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;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
59 Subscription, Task, WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
65 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
66 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
67 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
68 Toolchain, Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76 row_chunk::RowChunk,
77};
78use lsp::{
79 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
80 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
81 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
82 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
83 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
84 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
85 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
86 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
87};
88use node_runtime::read_package_installed_version;
89use parking_lot::Mutex;
90use postage::{mpsc, sink::Sink, stream::Stream, watch};
91use rand::prelude::*;
92use rpc::{
93 AnyProtoClient, ErrorCode, ErrorExt as _,
94 proto::{LspRequestId, LspRequestMessage as _},
95};
96use semver::Version;
97use serde::Serialize;
98use serde_json::Value;
99use settings::{Settings, SettingsLocation, SettingsStore};
100use sha2::{Digest, Sha256};
101use snippet::Snippet;
102use std::{
103 any::TypeId,
104 borrow::Cow,
105 cell::RefCell,
106 cmp::{Ordering, Reverse},
107 collections::hash_map,
108 convert::TryInto,
109 ffi::OsStr,
110 future::ready,
111 iter, mem,
112 ops::{ControlFlow, Range},
113 path::{self, Path, PathBuf},
114 pin::pin,
115 rc::Rc,
116 sync::{
117 Arc,
118 atomic::{self, AtomicUsize},
119 },
120 time::{Duration, Instant},
121 vec,
122};
123use sum_tree::Dimensions;
124use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
125
126use util::{
127 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
128 paths::{PathStyle, SanitizedPath},
129 post_inc,
130 redact::redact_command,
131 rel_path::RelPath,
132};
133
134pub use fs::*;
135pub use language::Location;
136pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
137#[cfg(any(test, feature = "test-support"))]
138pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
139pub use worktree::{
140 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
141 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
142};
143
144const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
145pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
146const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
147const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
148
149#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
150pub enum ProgressToken {
151 Number(i32),
152 String(SharedString),
153}
154
155impl std::fmt::Display for ProgressToken {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 match self {
158 Self::Number(number) => write!(f, "{number}"),
159 Self::String(string) => write!(f, "{string}"),
160 }
161 }
162}
163
164impl ProgressToken {
165 fn from_lsp(value: lsp::NumberOrString) -> Self {
166 match value {
167 lsp::NumberOrString::Number(number) => Self::Number(number),
168 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
169 }
170 }
171
172 fn to_lsp(&self) -> lsp::NumberOrString {
173 match self {
174 Self::Number(number) => lsp::NumberOrString::Number(*number),
175 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
176 }
177 }
178
179 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
180 Some(match value.value? {
181 proto::progress_token::Value::Number(number) => Self::Number(number),
182 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
183 })
184 }
185
186 fn to_proto(&self) -> proto::ProgressToken {
187 proto::ProgressToken {
188 value: Some(match self {
189 Self::Number(number) => proto::progress_token::Value::Number(*number),
190 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
191 }),
192 }
193 }
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197pub enum FormatTrigger {
198 Save,
199 Manual,
200}
201
202pub enum LspFormatTarget {
203 Buffers,
204 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
205}
206
207#[derive(Clone, PartialEq, Eq, Hash)]
208pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
209
210struct OpenLspBuffer(Entity<Buffer>);
211
212impl FormatTrigger {
213 fn from_proto(value: i32) -> FormatTrigger {
214 match value {
215 0 => FormatTrigger::Save,
216 1 => FormatTrigger::Manual,
217 _ => FormatTrigger::Save,
218 }
219 }
220}
221
222#[derive(Clone)]
223struct UnifiedLanguageServer {
224 id: LanguageServerId,
225 project_roots: HashSet<Arc<RelPath>>,
226}
227
228#[derive(Clone, Debug, Hash, PartialEq, Eq)]
229struct LanguageServerSeed {
230 worktree_id: WorktreeId,
231 name: LanguageServerName,
232 toolchain: Option<Toolchain>,
233 settings: Arc<LspSettings>,
234}
235
236#[derive(Debug)]
237pub struct DocumentDiagnosticsUpdate<'a, D> {
238 pub diagnostics: D,
239 pub result_id: Option<SharedString>,
240 pub registration_id: Option<SharedString>,
241 pub server_id: LanguageServerId,
242 pub disk_based_sources: Cow<'a, [String]>,
243}
244
245pub struct DocumentDiagnostics {
246 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
247 document_abs_path: PathBuf,
248 version: Option<i32>,
249}
250
251#[derive(Default, Debug)]
252struct DynamicRegistrations {
253 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
254 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
255}
256
257pub struct LocalLspStore {
258 weak: WeakEntity<LspStore>,
259 pub worktree_store: Entity<WorktreeStore>,
260 toolchain_store: Entity<LocalToolchainStore>,
261 http_client: Arc<dyn HttpClient>,
262 environment: Entity<ProjectEnvironment>,
263 fs: Arc<dyn Fs>,
264 languages: Arc<LanguageRegistry>,
265 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
266 yarn: Entity<YarnPathStore>,
267 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
268 buffers_being_formatted: HashSet<BufferId>,
269 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
270 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
271 watched_manifest_filenames: HashSet<ManifestName>,
272 language_server_paths_watched_for_rename:
273 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
274 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
275 supplementary_language_servers:
276 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
277 prettier_store: Entity<PrettierStore>,
278 next_diagnostic_group_id: usize,
279 diagnostics: HashMap<
280 WorktreeId,
281 HashMap<
282 Arc<RelPath>,
283 Vec<(
284 LanguageServerId,
285 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
286 )>,
287 >,
288 >,
289 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
290 _subscription: gpui::Subscription,
291 lsp_tree: LanguageServerTree,
292 registered_buffers: HashMap<BufferId, usize>,
293 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
294 buffer_pull_diagnostics_result_ids: HashMap<
295 LanguageServerId,
296 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
297 >,
298 workspace_pull_diagnostics_result_ids: HashMap<
299 LanguageServerId,
300 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
301 >,
302 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
303}
304
305impl LocalLspStore {
306 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
307 pub fn running_language_server_for_id(
308 &self,
309 id: LanguageServerId,
310 ) -> Option<&Arc<LanguageServer>> {
311 let language_server_state = self.language_servers.get(&id)?;
312
313 match language_server_state {
314 LanguageServerState::Running { server, .. } => Some(server),
315 LanguageServerState::Starting { .. } => None,
316 }
317 }
318
319 fn get_or_insert_language_server(
320 &mut self,
321 worktree_handle: &Entity<Worktree>,
322 delegate: Arc<LocalLspAdapterDelegate>,
323 disposition: &Arc<LaunchDisposition>,
324 language_name: &LanguageName,
325 cx: &mut App,
326 ) -> LanguageServerId {
327 let key = LanguageServerSeed {
328 worktree_id: worktree_handle.read(cx).id(),
329 name: disposition.server_name.clone(),
330 settings: disposition.settings.clone(),
331 toolchain: disposition.toolchain.clone(),
332 };
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 state.id
336 } else {
337 let adapter = self
338 .languages
339 .lsp_adapters(language_name)
340 .into_iter()
341 .find(|adapter| adapter.name() == disposition.server_name)
342 .expect("To find LSP adapter");
343 let new_language_server_id = self.start_language_server(
344 worktree_handle,
345 delegate,
346 adapter,
347 disposition.settings.clone(),
348 key.clone(),
349 cx,
350 );
351 if let Some(state) = self.language_server_ids.get_mut(&key) {
352 state.project_roots.insert(disposition.path.path.clone());
353 } else {
354 debug_assert!(
355 false,
356 "Expected `start_language_server` to ensure that `key` exists in a map"
357 );
358 }
359 new_language_server_id
360 }
361 }
362
363 fn start_language_server(
364 &mut self,
365 worktree_handle: &Entity<Worktree>,
366 delegate: Arc<LocalLspAdapterDelegate>,
367 adapter: Arc<CachedLspAdapter>,
368 settings: Arc<LspSettings>,
369 key: LanguageServerSeed,
370 cx: &mut App,
371 ) -> LanguageServerId {
372 let worktree = worktree_handle.read(cx);
373
374 let worktree_id = worktree.id();
375 let worktree_abs_path = worktree.abs_path();
376 let toolchain = key.toolchain.clone();
377 let override_options = settings.initialization_options.clone();
378
379 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
380
381 let server_id = self.languages.next_language_server_id();
382 log::trace!(
383 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
384 adapter.name.0
385 );
386
387 let wait_until_worktree_trust =
388 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
389 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
390 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
391 });
392 if can_trust {
393 self.restricted_worktrees_tasks.remove(&worktree_id);
394 None
395 } else {
396 match self.restricted_worktrees_tasks.entry(worktree_id) {
397 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
398 hash_map::Entry::Vacant(v) => {
399 let (mut tx, rx) = watch::channel::<bool>();
400 let lsp_store = self.weak.clone();
401 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
402 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
403 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
404 tx.blocking_send(true).ok();
405 lsp_store
406 .update(cx, |lsp_store, _| {
407 if let Some(local_lsp_store) =
408 lsp_store.as_local_mut()
409 {
410 local_lsp_store
411 .restricted_worktrees_tasks
412 .remove(&worktree_id);
413 }
414 })
415 .ok();
416 }
417 }
418 });
419 v.insert((subscription, rx.clone()));
420 Some(rx)
421 }
422 }
423 }
424 });
425 let update_binary_status = wait_until_worktree_trust.is_none();
426
427 let binary = self.get_language_server_binary(
428 worktree_abs_path.clone(),
429 adapter.clone(),
430 settings,
431 toolchain.clone(),
432 delegate.clone(),
433 true,
434 wait_until_worktree_trust,
435 cx,
436 );
437 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
438
439 let pending_server = cx.spawn({
440 let adapter = adapter.clone();
441 let server_name = adapter.name.clone();
442 let stderr_capture = stderr_capture.clone();
443 #[cfg(any(test, feature = "test-support"))]
444 let lsp_store = self.weak.clone();
445 let pending_workspace_folders = pending_workspace_folders.clone();
446 async move |cx| {
447 let binary = binary.await?;
448 #[cfg(any(test, feature = "test-support"))]
449 if let Some(server) = lsp_store
450 .update(&mut cx.clone(), |this, cx| {
451 this.languages.create_fake_language_server(
452 server_id,
453 &server_name,
454 binary.clone(),
455 &mut cx.to_async(),
456 )
457 })
458 .ok()
459 .flatten()
460 {
461 return Ok(server);
462 }
463
464 let code_action_kinds = adapter.code_action_kinds();
465 lsp::LanguageServer::new(
466 stderr_capture,
467 server_id,
468 server_name,
469 binary,
470 &worktree_abs_path,
471 code_action_kinds,
472 Some(pending_workspace_folders),
473 cx,
474 )
475 }
476 });
477
478 let startup = {
479 let server_name = adapter.name.0.clone();
480 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
481 let key = key.clone();
482 let adapter = adapter.clone();
483 let lsp_store = self.weak.clone();
484 let pending_workspace_folders = pending_workspace_folders.clone();
485
486 let pull_diagnostics = ProjectSettings::get_global(cx)
487 .diagnostics
488 .lsp_pull_diagnostics
489 .enabled;
490 cx.spawn(async move |cx| {
491 let result = async {
492 let language_server = pending_server.await?;
493
494 let workspace_config = Self::workspace_configuration_for_adapter(
495 adapter.adapter.clone(),
496 &delegate,
497 toolchain,
498 None,
499 cx,
500 )
501 .await?;
502
503 let mut initialization_options = Self::initialization_options_for_adapter(
504 adapter.adapter.clone(),
505 &delegate,
506 )
507 .await?;
508
509 match (&mut initialization_options, override_options) {
510 (Some(initialization_options), Some(override_options)) => {
511 merge_json_value_into(override_options, initialization_options);
512 }
513 (None, override_options) => initialization_options = override_options,
514 _ => {}
515 }
516
517 let initialization_params = cx.update(|cx| {
518 let mut params =
519 language_server.default_initialize_params(pull_diagnostics, cx);
520 params.initialization_options = initialization_options;
521 adapter.adapter.prepare_initialize_params(params, cx)
522 })?;
523
524 Self::setup_lsp_messages(
525 lsp_store.clone(),
526 &language_server,
527 delegate.clone(),
528 adapter.clone(),
529 );
530
531 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
532 settings: workspace_config,
533 };
534 let language_server = cx
535 .update(|cx| {
536 language_server.initialize(
537 initialization_params,
538 Arc::new(did_change_configuration_params.clone()),
539 cx,
540 )
541 })
542 .await
543 .inspect_err(|_| {
544 if let Some(lsp_store) = lsp_store.upgrade() {
545 lsp_store.update(cx, |lsp_store, cx| {
546 lsp_store.cleanup_lsp_data(server_id);
547 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
548 });
549 }
550 })?;
551
552 language_server.notify::<lsp::notification::DidChangeConfiguration>(
553 did_change_configuration_params,
554 )?;
555
556 anyhow::Ok(language_server)
557 }
558 .await;
559
560 match result {
561 Ok(server) => {
562 lsp_store
563 .update(cx, |lsp_store, cx| {
564 lsp_store.insert_newly_running_language_server(
565 adapter,
566 server.clone(),
567 server_id,
568 key,
569 pending_workspace_folders,
570 cx,
571 );
572 })
573 .ok();
574 stderr_capture.lock().take();
575 Some(server)
576 }
577
578 Err(err) => {
579 let log = stderr_capture.lock().take().unwrap_or_default();
580 delegate.update_status(
581 adapter.name(),
582 BinaryStatus::Failed {
583 error: if log.is_empty() {
584 format!("{err:#}")
585 } else {
586 format!("{err:#}\n-- stderr --\n{log}")
587 },
588 },
589 );
590 log::error!(
591 "Failed to start language server {server_name:?}: {}",
592 redact_command(&format!("{err:?}"))
593 );
594 if !log.is_empty() {
595 log::error!("server stderr: {}", redact_command(&log));
596 }
597 None
598 }
599 }
600 })
601 };
602 let state = LanguageServerState::Starting {
603 startup,
604 pending_workspace_folders,
605 };
606
607 if update_binary_status {
608 self.languages
609 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
610 }
611
612 self.language_servers.insert(server_id, state);
613 self.language_server_ids
614 .entry(key)
615 .or_insert(UnifiedLanguageServer {
616 id: server_id,
617 project_roots: Default::default(),
618 });
619 server_id
620 }
621
622 fn get_language_server_binary(
623 &self,
624 worktree_abs_path: Arc<Path>,
625 adapter: Arc<CachedLspAdapter>,
626 settings: Arc<LspSettings>,
627 toolchain: Option<Toolchain>,
628 delegate: Arc<dyn LspAdapterDelegate>,
629 allow_binary_download: bool,
630 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
631 cx: &mut App,
632 ) -> Task<Result<LanguageServerBinary>> {
633 if let Some(settings) = &settings.binary
634 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
635 {
636 let settings = settings.clone();
637 let languages = self.languages.clone();
638 return cx.background_spawn(async move {
639 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
640 let already_trusted = *wait_until_worktree_trust.borrow();
641 if !already_trusted {
642 log::info!(
643 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
644 adapter.name(),
645 );
646 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
647 if worktree_trusted {
648 break;
649 }
650 }
651 log::info!(
652 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
653 adapter.name(),
654 );
655 }
656 languages
657 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
658 }
659 let mut env = delegate.shell_env().await;
660 env.extend(settings.env.unwrap_or_default());
661
662 Ok(LanguageServerBinary {
663 path: delegate.resolve_executable_path(path),
664 env: Some(env),
665 arguments: settings
666 .arguments
667 .unwrap_or_default()
668 .iter()
669 .map(Into::into)
670 .collect(),
671 })
672 });
673 }
674 let lsp_binary_options = LanguageServerBinaryOptions {
675 allow_path_lookup: !settings
676 .binary
677 .as_ref()
678 .and_then(|b| b.ignore_system_version)
679 .unwrap_or_default(),
680 allow_binary_download,
681 pre_release: settings
682 .fetch
683 .as_ref()
684 .and_then(|f| f.pre_release)
685 .unwrap_or(false),
686 };
687
688 cx.spawn(async move |cx| {
689 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
690 let already_trusted = *wait_until_worktree_trust.borrow();
691 if !already_trusted {
692 log::info!(
693 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
694 adapter.name(),
695 );
696 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
697 if worktree_trusted {
698 break;
699 }
700 }
701 log::info!(
702 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
703 adapter.name(),
704 );
705 }
706 }
707
708 let (existing_binary, maybe_download_binary) = adapter
709 .clone()
710 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
711 .await
712 .await;
713
714 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
715
716 let mut binary = match (existing_binary, maybe_download_binary) {
717 (binary, None) => binary?,
718 (Err(_), Some(downloader)) => downloader.await?,
719 (Ok(existing_binary), Some(downloader)) => {
720 let mut download_timeout = cx
721 .background_executor()
722 .timer(SERVER_DOWNLOAD_TIMEOUT)
723 .fuse();
724 let mut downloader = downloader.fuse();
725 futures::select! {
726 _ = download_timeout => {
727 // Return existing binary and kick the existing work to the background.
728 cx.spawn(async move |_| downloader.await).detach();
729 Ok(existing_binary)
730 },
731 downloaded_or_existing_binary = downloader => {
732 // If download fails, this results in the existing binary.
733 downloaded_or_existing_binary
734 }
735 }?
736 }
737 };
738 let mut shell_env = delegate.shell_env().await;
739
740 shell_env.extend(binary.env.unwrap_or_default());
741
742 if let Some(settings) = settings.binary.as_ref() {
743 if let Some(arguments) = &settings.arguments {
744 binary.arguments = arguments.iter().map(Into::into).collect();
745 }
746 if let Some(env) = &settings.env {
747 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
748 }
749 }
750
751 binary.env = Some(shell_env);
752 Ok(binary)
753 })
754 }
755
756 fn setup_lsp_messages(
757 lsp_store: WeakEntity<LspStore>,
758 language_server: &LanguageServer,
759 delegate: Arc<dyn LspAdapterDelegate>,
760 adapter: Arc<CachedLspAdapter>,
761 ) {
762 let name = language_server.name();
763 let server_id = language_server.server_id();
764 language_server
765 .on_notification::<lsp::notification::PublishDiagnostics, _>({
766 let adapter = adapter.clone();
767 let this = lsp_store.clone();
768 move |mut params, cx| {
769 let adapter = adapter.clone();
770 if let Some(this) = this.upgrade() {
771 this.update(cx, |this, cx| {
772 {
773 let buffer = params
774 .uri
775 .to_file_path()
776 .map(|file_path| this.get_buffer(&file_path, cx))
777 .ok()
778 .flatten();
779 adapter.process_diagnostics(&mut params, server_id, buffer);
780 }
781
782 this.merge_lsp_diagnostics(
783 DiagnosticSourceKind::Pushed,
784 vec![DocumentDiagnosticsUpdate {
785 server_id,
786 diagnostics: params,
787 result_id: None,
788 disk_based_sources: Cow::Borrowed(
789 &adapter.disk_based_diagnostic_sources,
790 ),
791 registration_id: None,
792 }],
793 |_, diagnostic, cx| match diagnostic.source_kind {
794 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
795 adapter.retain_old_diagnostic(diagnostic, cx)
796 }
797 DiagnosticSourceKind::Pulled => true,
798 },
799 cx,
800 )
801 .log_err();
802 });
803 }
804 }
805 })
806 .detach();
807 language_server
808 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
809 let adapter = adapter.adapter.clone();
810 let delegate = delegate.clone();
811 let this = lsp_store.clone();
812 move |params, cx| {
813 let adapter = adapter.clone();
814 let delegate = delegate.clone();
815 let this = this.clone();
816 let mut cx = cx.clone();
817 async move {
818 let toolchain_for_id = this
819 .update(&mut cx, |this, _| {
820 this.as_local()?.language_server_ids.iter().find_map(
821 |(seed, value)| {
822 (value.id == server_id).then(|| seed.toolchain.clone())
823 },
824 )
825 })?
826 .context("Expected the LSP store to be in a local mode")?;
827
828 let mut scope_uri_to_workspace_config = BTreeMap::new();
829 for item in ¶ms.items {
830 let scope_uri = item.scope_uri.clone();
831 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
832 scope_uri_to_workspace_config.entry(scope_uri.clone())
833 else {
834 // We've already queried workspace configuration of this URI.
835 continue;
836 };
837 let workspace_config = Self::workspace_configuration_for_adapter(
838 adapter.clone(),
839 &delegate,
840 toolchain_for_id.clone(),
841 scope_uri,
842 &mut cx,
843 )
844 .await?;
845 new_scope_uri.insert(workspace_config);
846 }
847
848 Ok(params
849 .items
850 .into_iter()
851 .filter_map(|item| {
852 let workspace_config =
853 scope_uri_to_workspace_config.get(&item.scope_uri)?;
854 if let Some(section) = &item.section {
855 Some(
856 workspace_config
857 .get(section)
858 .cloned()
859 .unwrap_or(serde_json::Value::Null),
860 )
861 } else {
862 Some(workspace_config.clone())
863 }
864 })
865 .collect())
866 }
867 }
868 })
869 .detach();
870
871 language_server
872 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
873 let this = lsp_store.clone();
874 move |_, cx| {
875 let this = this.clone();
876 let cx = cx.clone();
877 async move {
878 let Some(server) =
879 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
880 else {
881 return Ok(None);
882 };
883 let root = server.workspace_folders();
884 Ok(Some(
885 root.into_iter()
886 .map(|uri| WorkspaceFolder {
887 uri,
888 name: Default::default(),
889 })
890 .collect(),
891 ))
892 }
893 }
894 })
895 .detach();
896 // Even though we don't have handling for these requests, respond to them to
897 // avoid stalling any language server like `gopls` which waits for a response
898 // to these requests when initializing.
899 language_server
900 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
901 let this = lsp_store.clone();
902 move |params, cx| {
903 let this = this.clone();
904 let mut cx = cx.clone();
905 async move {
906 this.update(&mut cx, |this, _| {
907 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
908 {
909 status
910 .progress_tokens
911 .insert(ProgressToken::from_lsp(params.token));
912 }
913 })?;
914
915 Ok(())
916 }
917 }
918 })
919 .detach();
920
921 language_server
922 .on_request::<lsp::request::RegisterCapability, _, _>({
923 let lsp_store = lsp_store.clone();
924 move |params, cx| {
925 let lsp_store = lsp_store.clone();
926 let mut cx = cx.clone();
927 async move {
928 lsp_store
929 .update(&mut cx, |lsp_store, cx| {
930 if lsp_store.as_local().is_some() {
931 match lsp_store
932 .register_server_capabilities(server_id, params, cx)
933 {
934 Ok(()) => {}
935 Err(e) => {
936 log::error!(
937 "Failed to register server capabilities: {e:#}"
938 );
939 }
940 };
941 }
942 })
943 .ok();
944 Ok(())
945 }
946 }
947 })
948 .detach();
949
950 language_server
951 .on_request::<lsp::request::UnregisterCapability, _, _>({
952 let lsp_store = lsp_store.clone();
953 move |params, cx| {
954 let lsp_store = lsp_store.clone();
955 let mut cx = cx.clone();
956 async move {
957 lsp_store
958 .update(&mut cx, |lsp_store, cx| {
959 if lsp_store.as_local().is_some() {
960 match lsp_store
961 .unregister_server_capabilities(server_id, params, cx)
962 {
963 Ok(()) => {}
964 Err(e) => {
965 log::error!(
966 "Failed to unregister server capabilities: {e:#}"
967 );
968 }
969 }
970 }
971 })
972 .ok();
973 Ok(())
974 }
975 }
976 })
977 .detach();
978
979 language_server
980 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
981 let this = lsp_store.clone();
982 move |params, cx| {
983 let mut cx = cx.clone();
984 let this = this.clone();
985 async move {
986 LocalLspStore::on_lsp_workspace_edit(
987 this.clone(),
988 params,
989 server_id,
990 &mut cx,
991 )
992 .await
993 }
994 }
995 })
996 .detach();
997
998 language_server
999 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1000 let lsp_store = lsp_store.clone();
1001 let request_id = Arc::new(AtomicUsize::new(0));
1002 move |(), cx| {
1003 let lsp_store = lsp_store.clone();
1004 let request_id = request_id.clone();
1005 let mut cx = cx.clone();
1006 async move {
1007 lsp_store
1008 .update(&mut cx, |lsp_store, cx| {
1009 let request_id =
1010 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1011 cx.emit(LspStoreEvent::RefreshInlayHints {
1012 server_id,
1013 request_id,
1014 });
1015 lsp_store
1016 .downstream_client
1017 .as_ref()
1018 .map(|(client, project_id)| {
1019 client.send(proto::RefreshInlayHints {
1020 project_id: *project_id,
1021 server_id: server_id.to_proto(),
1022 request_id: request_id.map(|id| id as u64),
1023 })
1024 })
1025 })?
1026 .transpose()?;
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1035 let this = lsp_store.clone();
1036 move |(), cx| {
1037 let this = this.clone();
1038 let mut cx = cx.clone();
1039 async move {
1040 this.update(&mut cx, |this, cx| {
1041 cx.emit(LspStoreEvent::RefreshCodeLens);
1042 this.downstream_client.as_ref().map(|(client, project_id)| {
1043 client.send(proto::RefreshCodeLens {
1044 project_id: *project_id,
1045 })
1046 })
1047 })?
1048 .transpose()?;
1049 Ok(())
1050 }
1051 }
1052 })
1053 .detach();
1054
1055 language_server
1056 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1057 let this = lsp_store.clone();
1058 move |(), cx| {
1059 let this = this.clone();
1060 let mut cx = cx.clone();
1061 async move {
1062 this.update(&mut cx, |lsp_store, cx| {
1063 lsp_store.pull_workspace_diagnostics(server_id);
1064 lsp_store
1065 .downstream_client
1066 .as_ref()
1067 .map(|(client, project_id)| {
1068 client.send(proto::PullWorkspaceDiagnostics {
1069 project_id: *project_id,
1070 server_id: server_id.to_proto(),
1071 })
1072 })
1073 .transpose()?;
1074 anyhow::Ok(
1075 lsp_store.pull_document_diagnostics_for_server(server_id, cx),
1076 )
1077 })??
1078 .await;
1079 Ok(())
1080 }
1081 }
1082 })
1083 .detach();
1084
1085 language_server
1086 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1087 let this = lsp_store.clone();
1088 let name = name.to_string();
1089 let adapter = adapter.clone();
1090 move |params, cx| {
1091 let this = this.clone();
1092 let name = name.to_string();
1093 let adapter = adapter.clone();
1094 let mut cx = cx.clone();
1095 async move {
1096 let actions = params.actions.unwrap_or_default();
1097 let message = params.message.clone();
1098 let (tx, rx) = smol::channel::bounded(1);
1099 let request = LanguageServerPromptRequest {
1100 level: match params.typ {
1101 lsp::MessageType::ERROR => PromptLevel::Critical,
1102 lsp::MessageType::WARNING => PromptLevel::Warning,
1103 _ => PromptLevel::Info,
1104 },
1105 message: params.message,
1106 actions,
1107 response_channel: tx,
1108 lsp_name: name.clone(),
1109 };
1110
1111 let did_update = this
1112 .update(&mut cx, |_, cx| {
1113 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1114 })
1115 .is_ok();
1116 if did_update {
1117 let response = rx.recv().await.ok();
1118 if let Some(ref selected_action) = response {
1119 let context = language::PromptResponseContext {
1120 message,
1121 selected_action: selected_action.clone(),
1122 };
1123 adapter.process_prompt_response(&context, &mut cx)
1124 }
1125
1126 Ok(response)
1127 } else {
1128 Ok(None)
1129 }
1130 }
1131 }
1132 })
1133 .detach();
1134 language_server
1135 .on_notification::<lsp::notification::ShowMessage, _>({
1136 let this = lsp_store.clone();
1137 let name = name.to_string();
1138 move |params, cx| {
1139 let this = this.clone();
1140 let name = name.to_string();
1141 let mut cx = cx.clone();
1142
1143 let (tx, _) = smol::channel::bounded(1);
1144 let request = LanguageServerPromptRequest {
1145 level: match params.typ {
1146 lsp::MessageType::ERROR => PromptLevel::Critical,
1147 lsp::MessageType::WARNING => PromptLevel::Warning,
1148 _ => PromptLevel::Info,
1149 },
1150 message: params.message,
1151 actions: vec![],
1152 response_channel: tx,
1153 lsp_name: name,
1154 };
1155
1156 let _ = this.update(&mut cx, |_, cx| {
1157 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1158 });
1159 }
1160 })
1161 .detach();
1162
1163 let disk_based_diagnostics_progress_token =
1164 adapter.disk_based_diagnostics_progress_token.clone();
1165
1166 language_server
1167 .on_notification::<lsp::notification::Progress, _>({
1168 let this = lsp_store.clone();
1169 move |params, cx| {
1170 if let Some(this) = this.upgrade() {
1171 this.update(cx, |this, cx| {
1172 this.on_lsp_progress(
1173 params,
1174 server_id,
1175 disk_based_diagnostics_progress_token.clone(),
1176 cx,
1177 );
1178 });
1179 }
1180 }
1181 })
1182 .detach();
1183
1184 language_server
1185 .on_notification::<lsp::notification::LogMessage, _>({
1186 let this = lsp_store.clone();
1187 move |params, cx| {
1188 if let Some(this) = this.upgrade() {
1189 this.update(cx, |_, cx| {
1190 cx.emit(LspStoreEvent::LanguageServerLog(
1191 server_id,
1192 LanguageServerLogType::Log(params.typ),
1193 params.message,
1194 ));
1195 });
1196 }
1197 }
1198 })
1199 .detach();
1200
1201 language_server
1202 .on_notification::<lsp::notification::LogTrace, _>({
1203 let this = lsp_store.clone();
1204 move |params, cx| {
1205 let mut cx = cx.clone();
1206 if let Some(this) = this.upgrade() {
1207 this.update(&mut cx, |_, cx| {
1208 cx.emit(LspStoreEvent::LanguageServerLog(
1209 server_id,
1210 LanguageServerLogType::Trace {
1211 verbose_info: params.verbose,
1212 },
1213 params.message,
1214 ));
1215 });
1216 }
1217 }
1218 })
1219 .detach();
1220
1221 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1222 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1223 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1224 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1225 }
1226
1227 fn shutdown_language_servers_on_quit(
1228 &mut self,
1229 _: &mut Context<LspStore>,
1230 ) -> impl Future<Output = ()> + use<> {
1231 let shutdown_futures = self
1232 .language_servers
1233 .drain()
1234 .map(|(_, server_state)| Self::shutdown_server(server_state))
1235 .collect::<Vec<_>>();
1236
1237 async move {
1238 join_all(shutdown_futures).await;
1239 }
1240 }
1241
1242 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1243 match server_state {
1244 LanguageServerState::Running { server, .. } => {
1245 if let Some(shutdown) = server.shutdown() {
1246 shutdown.await;
1247 }
1248 }
1249 LanguageServerState::Starting { startup, .. } => {
1250 if let Some(server) = startup.await
1251 && let Some(shutdown) = server.shutdown()
1252 {
1253 shutdown.await;
1254 }
1255 }
1256 }
1257 Ok(())
1258 }
1259
1260 fn language_servers_for_worktree(
1261 &self,
1262 worktree_id: WorktreeId,
1263 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1264 self.language_server_ids
1265 .iter()
1266 .filter_map(move |(seed, state)| {
1267 if seed.worktree_id != worktree_id {
1268 return None;
1269 }
1270
1271 if let Some(LanguageServerState::Running { server, .. }) =
1272 self.language_servers.get(&state.id)
1273 {
1274 Some(server)
1275 } else {
1276 None
1277 }
1278 })
1279 }
1280
1281 fn language_server_ids_for_project_path(
1282 &self,
1283 project_path: ProjectPath,
1284 language: &Language,
1285 cx: &mut App,
1286 ) -> Vec<LanguageServerId> {
1287 let Some(worktree) = self
1288 .worktree_store
1289 .read(cx)
1290 .worktree_for_id(project_path.worktree_id, cx)
1291 else {
1292 return Vec::new();
1293 };
1294 let delegate: Arc<dyn ManifestDelegate> =
1295 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1296
1297 self.lsp_tree
1298 .get(
1299 project_path,
1300 language.name(),
1301 language.manifest(),
1302 &delegate,
1303 cx,
1304 )
1305 .collect::<Vec<_>>()
1306 }
1307
1308 fn language_server_ids_for_buffer(
1309 &self,
1310 buffer: &Buffer,
1311 cx: &mut App,
1312 ) -> Vec<LanguageServerId> {
1313 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1314 let worktree_id = file.worktree_id(cx);
1315
1316 let path: Arc<RelPath> = file
1317 .path()
1318 .parent()
1319 .map(Arc::from)
1320 .unwrap_or_else(|| file.path().clone());
1321 let worktree_path = ProjectPath { worktree_id, path };
1322 self.language_server_ids_for_project_path(worktree_path, language, cx)
1323 } else {
1324 Vec::new()
1325 }
1326 }
1327
1328 fn language_servers_for_buffer<'a>(
1329 &'a self,
1330 buffer: &'a Buffer,
1331 cx: &'a mut App,
1332 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1333 self.language_server_ids_for_buffer(buffer, cx)
1334 .into_iter()
1335 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1336 LanguageServerState::Running {
1337 adapter, server, ..
1338 } => Some((adapter, server)),
1339 _ => None,
1340 })
1341 }
1342
1343 async fn execute_code_action_kind_locally(
1344 lsp_store: WeakEntity<LspStore>,
1345 mut buffers: Vec<Entity<Buffer>>,
1346 kind: CodeActionKind,
1347 push_to_history: bool,
1348 cx: &mut AsyncApp,
1349 ) -> anyhow::Result<ProjectTransaction> {
1350 // Do not allow multiple concurrent code actions requests for the
1351 // same buffer.
1352 lsp_store.update(cx, |this, cx| {
1353 let this = this.as_local_mut().unwrap();
1354 buffers.retain(|buffer| {
1355 this.buffers_being_formatted
1356 .insert(buffer.read(cx).remote_id())
1357 });
1358 })?;
1359 let _cleanup = defer({
1360 let this = lsp_store.clone();
1361 let mut cx = cx.clone();
1362 let buffers = &buffers;
1363 move || {
1364 this.update(&mut cx, |this, cx| {
1365 let this = this.as_local_mut().unwrap();
1366 for buffer in buffers {
1367 this.buffers_being_formatted
1368 .remove(&buffer.read(cx).remote_id());
1369 }
1370 })
1371 .ok();
1372 }
1373 });
1374 let mut project_transaction = ProjectTransaction::default();
1375
1376 for buffer in &buffers {
1377 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1378 buffer.update(cx, |buffer, cx| {
1379 lsp_store
1380 .as_local()
1381 .unwrap()
1382 .language_servers_for_buffer(buffer, cx)
1383 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1384 .collect::<Vec<_>>()
1385 })
1386 })?;
1387 for (_, language_server) in adapters_and_servers.iter() {
1388 let actions = Self::get_server_code_actions_from_action_kinds(
1389 &lsp_store,
1390 language_server.server_id(),
1391 vec![kind.clone()],
1392 buffer,
1393 cx,
1394 )
1395 .await?;
1396 Self::execute_code_actions_on_server(
1397 &lsp_store,
1398 language_server,
1399 actions,
1400 push_to_history,
1401 &mut project_transaction,
1402 cx,
1403 )
1404 .await?;
1405 }
1406 }
1407 Ok(project_transaction)
1408 }
1409
1410 async fn format_locally(
1411 lsp_store: WeakEntity<LspStore>,
1412 mut buffers: Vec<FormattableBuffer>,
1413 push_to_history: bool,
1414 trigger: FormatTrigger,
1415 logger: zlog::Logger,
1416 cx: &mut AsyncApp,
1417 ) -> anyhow::Result<ProjectTransaction> {
1418 // Do not allow multiple concurrent formatting requests for the
1419 // same buffer.
1420 lsp_store.update(cx, |this, cx| {
1421 let this = this.as_local_mut().unwrap();
1422 buffers.retain(|buffer| {
1423 this.buffers_being_formatted
1424 .insert(buffer.handle.read(cx).remote_id())
1425 });
1426 })?;
1427
1428 let _cleanup = defer({
1429 let this = lsp_store.clone();
1430 let mut cx = cx.clone();
1431 let buffers = &buffers;
1432 move || {
1433 this.update(&mut cx, |this, cx| {
1434 let this = this.as_local_mut().unwrap();
1435 for buffer in buffers {
1436 this.buffers_being_formatted
1437 .remove(&buffer.handle.read(cx).remote_id());
1438 }
1439 })
1440 .ok();
1441 }
1442 });
1443
1444 let mut project_transaction = ProjectTransaction::default();
1445
1446 for buffer in &buffers {
1447 zlog::debug!(
1448 logger =>
1449 "formatting buffer '{:?}'",
1450 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1451 );
1452 // Create an empty transaction to hold all of the formatting edits.
1453 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1454 // ensure no transactions created while formatting are
1455 // grouped with the previous transaction in the history
1456 // based on the transaction group interval
1457 buffer.finalize_last_transaction();
1458 buffer
1459 .start_transaction()
1460 .context("transaction already open")?;
1461 buffer.end_transaction(cx);
1462 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1463 buffer.finalize_last_transaction();
1464 anyhow::Ok(transaction_id)
1465 })?;
1466
1467 let result = Self::format_buffer_locally(
1468 lsp_store.clone(),
1469 buffer,
1470 formatting_transaction_id,
1471 trigger,
1472 logger,
1473 cx,
1474 )
1475 .await;
1476
1477 buffer.handle.update(cx, |buffer, cx| {
1478 let Some(formatting_transaction) =
1479 buffer.get_transaction(formatting_transaction_id).cloned()
1480 else {
1481 zlog::warn!(logger => "no formatting transaction");
1482 return;
1483 };
1484 if formatting_transaction.edit_ids.is_empty() {
1485 zlog::debug!(logger => "no changes made while formatting");
1486 buffer.forget_transaction(formatting_transaction_id);
1487 return;
1488 }
1489 if !push_to_history {
1490 zlog::trace!(logger => "forgetting format transaction");
1491 buffer.forget_transaction(formatting_transaction.id);
1492 }
1493 project_transaction
1494 .0
1495 .insert(cx.entity(), formatting_transaction);
1496 });
1497
1498 result?;
1499 }
1500
1501 Ok(project_transaction)
1502 }
1503
1504 async fn format_buffer_locally(
1505 lsp_store: WeakEntity<LspStore>,
1506 buffer: &FormattableBuffer,
1507 formatting_transaction_id: clock::Lamport,
1508 trigger: FormatTrigger,
1509 logger: zlog::Logger,
1510 cx: &mut AsyncApp,
1511 ) -> Result<()> {
1512 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1513 buffer.handle.update(cx, |buffer, cx| {
1514 let adapters_and_servers = lsp_store
1515 .as_local()
1516 .unwrap()
1517 .language_servers_for_buffer(buffer, cx)
1518 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1519 .collect::<Vec<_>>();
1520 let settings =
1521 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1522 .into_owned();
1523 (adapters_and_servers, settings)
1524 })
1525 })?;
1526
1527 /// Apply edits to the buffer that will become part of the formatting transaction.
1528 /// Fails if the buffer has been edited since the start of that transaction.
1529 fn extend_formatting_transaction(
1530 buffer: &FormattableBuffer,
1531 formatting_transaction_id: text::TransactionId,
1532 cx: &mut AsyncApp,
1533 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1534 ) -> anyhow::Result<()> {
1535 buffer.handle.update(cx, |buffer, cx| {
1536 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1537 if last_transaction_id != Some(formatting_transaction_id) {
1538 anyhow::bail!("Buffer edited while formatting. Aborting")
1539 }
1540 buffer.start_transaction();
1541 operation(buffer, cx);
1542 if let Some(transaction_id) = buffer.end_transaction(cx) {
1543 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1544 }
1545 Ok(())
1546 })
1547 }
1548
1549 // handle whitespace formatting
1550 if settings.remove_trailing_whitespace_on_save {
1551 zlog::trace!(logger => "removing trailing whitespace");
1552 let diff = buffer
1553 .handle
1554 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1555 .await;
1556 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1557 buffer.apply_diff(diff, cx);
1558 })?;
1559 }
1560
1561 if settings.ensure_final_newline_on_save {
1562 zlog::trace!(logger => "ensuring final newline");
1563 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1564 buffer.ensure_final_newline(cx);
1565 })?;
1566 }
1567
1568 // Formatter for `code_actions_on_format` that runs before
1569 // the rest of the formatters
1570 let mut code_actions_on_format_formatters = None;
1571 let should_run_code_actions_on_format = !matches!(
1572 (trigger, &settings.format_on_save),
1573 (FormatTrigger::Save, &FormatOnSave::Off)
1574 );
1575 if should_run_code_actions_on_format {
1576 let have_code_actions_to_run_on_format = settings
1577 .code_actions_on_format
1578 .values()
1579 .any(|enabled| *enabled);
1580 if have_code_actions_to_run_on_format {
1581 zlog::trace!(logger => "going to run code actions on format");
1582 code_actions_on_format_formatters = Some(
1583 settings
1584 .code_actions_on_format
1585 .iter()
1586 .filter_map(|(action, enabled)| enabled.then_some(action))
1587 .cloned()
1588 .map(Formatter::CodeAction)
1589 .collect::<Vec<_>>(),
1590 );
1591 }
1592 }
1593
1594 let formatters = match (trigger, &settings.format_on_save) {
1595 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1596 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1597 settings.formatter.as_ref()
1598 }
1599 };
1600
1601 let formatters = code_actions_on_format_formatters
1602 .iter()
1603 .flatten()
1604 .chain(formatters);
1605
1606 for formatter in formatters {
1607 let formatter = if formatter == &Formatter::Auto {
1608 if settings.prettier.allowed {
1609 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1610 &Formatter::Prettier
1611 } else {
1612 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1613 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1614 }
1615 } else {
1616 formatter
1617 };
1618 match formatter {
1619 Formatter::Auto => unreachable!("Auto resolved above"),
1620 Formatter::Prettier => {
1621 let logger = zlog::scoped!(logger => "prettier");
1622 zlog::trace!(logger => "formatting");
1623 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1624
1625 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1626 lsp_store.prettier_store().unwrap().downgrade()
1627 })?;
1628 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1629 .await
1630 .transpose()?;
1631 let Some(diff) = diff else {
1632 zlog::trace!(logger => "No changes");
1633 continue;
1634 };
1635
1636 extend_formatting_transaction(
1637 buffer,
1638 formatting_transaction_id,
1639 cx,
1640 |buffer, cx| {
1641 buffer.apply_diff(diff, cx);
1642 },
1643 )?;
1644 }
1645 Formatter::External { command, arguments } => {
1646 let logger = zlog::scoped!(logger => "command");
1647 zlog::trace!(logger => "formatting");
1648 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1649
1650 let diff = Self::format_via_external_command(
1651 buffer,
1652 command.as_ref(),
1653 arguments.as_deref(),
1654 cx,
1655 )
1656 .await
1657 .with_context(|| {
1658 format!("Failed to format buffer via external command: {}", command)
1659 })?;
1660 let Some(diff) = diff else {
1661 zlog::trace!(logger => "No changes");
1662 continue;
1663 };
1664
1665 extend_formatting_transaction(
1666 buffer,
1667 formatting_transaction_id,
1668 cx,
1669 |buffer, cx| {
1670 buffer.apply_diff(diff, cx);
1671 },
1672 )?;
1673 }
1674 Formatter::LanguageServer(specifier) => {
1675 let logger = zlog::scoped!(logger => "language-server");
1676 zlog::trace!(logger => "formatting");
1677 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1678
1679 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1680 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1681 continue;
1682 };
1683
1684 let language_server = match specifier {
1685 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1686 adapters_and_servers.iter().find_map(|(adapter, server)| {
1687 if adapter.name.0.as_ref() == name {
1688 Some(server.clone())
1689 } else {
1690 None
1691 }
1692 })
1693 }
1694 settings::LanguageServerFormatterSpecifier::Current => {
1695 adapters_and_servers.first().map(|e| e.1.clone())
1696 }
1697 };
1698
1699 let Some(language_server) = language_server else {
1700 log::debug!(
1701 "No language server found to format buffer '{:?}'. Skipping",
1702 buffer_path_abs.as_path().to_string_lossy()
1703 );
1704 continue;
1705 };
1706
1707 zlog::trace!(
1708 logger =>
1709 "Formatting buffer '{:?}' using language server '{:?}'",
1710 buffer_path_abs.as_path().to_string_lossy(),
1711 language_server.name()
1712 );
1713
1714 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1715 zlog::trace!(logger => "formatting ranges");
1716 Self::format_ranges_via_lsp(
1717 &lsp_store,
1718 &buffer.handle,
1719 ranges,
1720 buffer_path_abs,
1721 &language_server,
1722 &settings,
1723 cx,
1724 )
1725 .await
1726 .context("Failed to format ranges via language server")?
1727 } else {
1728 zlog::trace!(logger => "formatting full");
1729 Self::format_via_lsp(
1730 &lsp_store,
1731 &buffer.handle,
1732 buffer_path_abs,
1733 &language_server,
1734 &settings,
1735 cx,
1736 )
1737 .await
1738 .context("failed to format via language server")?
1739 };
1740
1741 if edits.is_empty() {
1742 zlog::trace!(logger => "No changes");
1743 continue;
1744 }
1745 extend_formatting_transaction(
1746 buffer,
1747 formatting_transaction_id,
1748 cx,
1749 |buffer, cx| {
1750 buffer.edit(edits, None, cx);
1751 },
1752 )?;
1753 }
1754 Formatter::CodeAction(code_action_name) => {
1755 let logger = zlog::scoped!(logger => "code-actions");
1756 zlog::trace!(logger => "formatting");
1757 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1758
1759 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1760 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1761 continue;
1762 };
1763
1764 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1765 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1766
1767 let mut actions_and_servers = Vec::new();
1768
1769 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1770 let actions_result = Self::get_server_code_actions_from_action_kinds(
1771 &lsp_store,
1772 language_server.server_id(),
1773 vec![code_action_kind.clone()],
1774 &buffer.handle,
1775 cx,
1776 )
1777 .await
1778 .with_context(|| {
1779 format!(
1780 "Failed to resolve code action {:?} with language server {}",
1781 code_action_kind,
1782 language_server.name()
1783 )
1784 });
1785 let Ok(actions) = actions_result else {
1786 // note: it may be better to set result to the error and break formatters here
1787 // but for now we try to execute the actions that we can resolve and skip the rest
1788 zlog::error!(
1789 logger =>
1790 "Failed to resolve code action {:?} with language server {}",
1791 code_action_kind,
1792 language_server.name()
1793 );
1794 continue;
1795 };
1796 for action in actions {
1797 actions_and_servers.push((action, index));
1798 }
1799 }
1800
1801 if actions_and_servers.is_empty() {
1802 zlog::warn!(logger => "No code actions were resolved, continuing");
1803 continue;
1804 }
1805
1806 'actions: for (mut action, server_index) in actions_and_servers {
1807 let server = &adapters_and_servers[server_index].1;
1808
1809 let describe_code_action = |action: &CodeAction| {
1810 format!(
1811 "code action '{}' with title \"{}\" on server {}",
1812 action
1813 .lsp_action
1814 .action_kind()
1815 .unwrap_or("unknown".into())
1816 .as_str(),
1817 action.lsp_action.title(),
1818 server.name(),
1819 )
1820 };
1821
1822 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1823
1824 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1825 zlog::error!(
1826 logger =>
1827 "Failed to resolve {}. Error: {}",
1828 describe_code_action(&action),
1829 err
1830 );
1831 continue;
1832 }
1833
1834 if let Some(edit) = action.lsp_action.edit().cloned() {
1835 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1836 // but filters out and logs warnings for code actions that require unreasonably
1837 // difficult handling on our part, such as:
1838 // - applying edits that call commands
1839 // which can result in arbitrary workspace edits being sent from the server that
1840 // have no way of being tied back to the command that initiated them (i.e. we
1841 // can't know which edits are part of the format request, or if the server is done sending
1842 // actions in response to the command)
1843 // - actions that create/delete/modify/rename files other than the one we are formatting
1844 // as we then would need to handle such changes correctly in the local history as well
1845 // as the remote history through the ProjectTransaction
1846 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1847 // Supporting these actions is not impossible, but not supported as of yet.
1848 if edit.changes.is_none() && edit.document_changes.is_none() {
1849 zlog::trace!(
1850 logger =>
1851 "No changes for code action. Skipping {}",
1852 describe_code_action(&action),
1853 );
1854 continue;
1855 }
1856
1857 let mut operations = Vec::new();
1858 if let Some(document_changes) = edit.document_changes {
1859 match document_changes {
1860 lsp::DocumentChanges::Edits(edits) => operations.extend(
1861 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1862 ),
1863 lsp::DocumentChanges::Operations(ops) => operations = ops,
1864 }
1865 } else if let Some(changes) = edit.changes {
1866 operations.extend(changes.into_iter().map(|(uri, edits)| {
1867 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1868 text_document:
1869 lsp::OptionalVersionedTextDocumentIdentifier {
1870 uri,
1871 version: None,
1872 },
1873 edits: edits.into_iter().map(Edit::Plain).collect(),
1874 })
1875 }));
1876 }
1877
1878 let mut edits = Vec::with_capacity(operations.len());
1879
1880 if operations.is_empty() {
1881 zlog::trace!(
1882 logger =>
1883 "No changes for code action. Skipping {}",
1884 describe_code_action(&action),
1885 );
1886 continue;
1887 }
1888 for operation in operations {
1889 let op = match operation {
1890 lsp::DocumentChangeOperation::Edit(op) => op,
1891 lsp::DocumentChangeOperation::Op(_) => {
1892 zlog::warn!(
1893 logger =>
1894 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1895 describe_code_action(&action),
1896 );
1897 continue 'actions;
1898 }
1899 };
1900 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1901 zlog::warn!(
1902 logger =>
1903 "Failed to convert URI '{:?}' to file path. Skipping {}",
1904 &op.text_document.uri,
1905 describe_code_action(&action),
1906 );
1907 continue 'actions;
1908 };
1909 if &file_path != buffer_path_abs {
1910 zlog::warn!(
1911 logger =>
1912 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1913 file_path,
1914 buffer_path_abs,
1915 describe_code_action(&action),
1916 );
1917 continue 'actions;
1918 }
1919
1920 let mut lsp_edits = Vec::new();
1921 for edit in op.edits {
1922 match edit {
1923 Edit::Plain(edit) => {
1924 if !lsp_edits.contains(&edit) {
1925 lsp_edits.push(edit);
1926 }
1927 }
1928 Edit::Annotated(edit) => {
1929 if !lsp_edits.contains(&edit.text_edit) {
1930 lsp_edits.push(edit.text_edit);
1931 }
1932 }
1933 Edit::Snippet(_) => {
1934 zlog::warn!(
1935 logger =>
1936 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1937 describe_code_action(&action),
1938 );
1939 continue 'actions;
1940 }
1941 }
1942 }
1943 let edits_result = lsp_store
1944 .update(cx, |lsp_store, cx| {
1945 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1946 &buffer.handle,
1947 lsp_edits,
1948 server.server_id(),
1949 op.text_document.version,
1950 cx,
1951 )
1952 })?
1953 .await;
1954 let Ok(resolved_edits) = edits_result else {
1955 zlog::warn!(
1956 logger =>
1957 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1958 buffer_path_abs.as_path(),
1959 describe_code_action(&action),
1960 );
1961 continue 'actions;
1962 };
1963 edits.extend(resolved_edits);
1964 }
1965
1966 if edits.is_empty() {
1967 zlog::warn!(logger => "No edits resolved from LSP");
1968 continue;
1969 }
1970
1971 extend_formatting_transaction(
1972 buffer,
1973 formatting_transaction_id,
1974 cx,
1975 |buffer, cx| {
1976 zlog::info!(
1977 "Applying edits {edits:?}. Content: {:?}",
1978 buffer.text()
1979 );
1980 buffer.edit(edits, None, cx);
1981 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1982 },
1983 )?;
1984 }
1985
1986 if let Some(command) = action.lsp_action.command() {
1987 zlog::warn!(
1988 logger =>
1989 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1990 &command.command,
1991 );
1992
1993 // bail early if command is invalid
1994 let server_capabilities = server.capabilities();
1995 let available_commands = server_capabilities
1996 .execute_command_provider
1997 .as_ref()
1998 .map(|options| options.commands.as_slice())
1999 .unwrap_or_default();
2000 if !available_commands.contains(&command.command) {
2001 zlog::warn!(
2002 logger =>
2003 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2004 command.command,
2005 server.name(),
2006 );
2007 continue;
2008 }
2009
2010 // noop so we just ensure buffer hasn't been edited since resolving code actions
2011 extend_formatting_transaction(
2012 buffer,
2013 formatting_transaction_id,
2014 cx,
2015 |_, _| {},
2016 )?;
2017 zlog::info!(logger => "Executing command {}", &command.command);
2018
2019 lsp_store.update(cx, |this, _| {
2020 this.as_local_mut()
2021 .unwrap()
2022 .last_workspace_edits_by_language_server
2023 .remove(&server.server_id());
2024 })?;
2025
2026 let execute_command_result = server
2027 .request::<lsp::request::ExecuteCommand>(
2028 lsp::ExecuteCommandParams {
2029 command: command.command.clone(),
2030 arguments: command.arguments.clone().unwrap_or_default(),
2031 ..Default::default()
2032 },
2033 )
2034 .await
2035 .into_response();
2036
2037 if execute_command_result.is_err() {
2038 zlog::error!(
2039 logger =>
2040 "Failed to execute command '{}' as part of {}",
2041 &command.command,
2042 describe_code_action(&action),
2043 );
2044 continue 'actions;
2045 }
2046
2047 let mut project_transaction_command =
2048 lsp_store.update(cx, |this, _| {
2049 this.as_local_mut()
2050 .unwrap()
2051 .last_workspace_edits_by_language_server
2052 .remove(&server.server_id())
2053 .unwrap_or_default()
2054 })?;
2055
2056 if let Some(transaction) =
2057 project_transaction_command.0.remove(&buffer.handle)
2058 {
2059 zlog::trace!(
2060 logger =>
2061 "Successfully captured {} edits that resulted from command {}",
2062 transaction.edit_ids.len(),
2063 &command.command,
2064 );
2065 let transaction_id_project_transaction = transaction.id;
2066 buffer.handle.update(cx, |buffer, _| {
2067 // it may have been removed from history if push_to_history was
2068 // false in deserialize_workspace_edit. If so push it so we
2069 // can merge it with the format transaction
2070 // and pop the combined transaction off the history stack
2071 // later if push_to_history is false
2072 if buffer.get_transaction(transaction.id).is_none() {
2073 buffer.push_transaction(transaction, Instant::now());
2074 }
2075 buffer.merge_transactions(
2076 transaction_id_project_transaction,
2077 formatting_transaction_id,
2078 );
2079 });
2080 }
2081
2082 if !project_transaction_command.0.is_empty() {
2083 let mut extra_buffers = String::new();
2084 for buffer in project_transaction_command.0.keys() {
2085 buffer.read_with(cx, |b, cx| {
2086 if let Some(path) = b.project_path(cx) {
2087 if !extra_buffers.is_empty() {
2088 extra_buffers.push_str(", ");
2089 }
2090 extra_buffers.push_str(path.path.as_unix_str());
2091 }
2092 });
2093 }
2094 zlog::warn!(
2095 logger =>
2096 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2097 &command.command,
2098 extra_buffers,
2099 );
2100 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2101 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2102 // add it so it's included, and merge it into the format transaction when its created later
2103 }
2104 }
2105 }
2106 }
2107 }
2108 }
2109
2110 Ok(())
2111 }
2112
2113 pub async fn format_ranges_via_lsp(
2114 this: &WeakEntity<LspStore>,
2115 buffer_handle: &Entity<Buffer>,
2116 ranges: &[Range<Anchor>],
2117 abs_path: &Path,
2118 language_server: &Arc<LanguageServer>,
2119 settings: &LanguageSettings,
2120 cx: &mut AsyncApp,
2121 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2122 let capabilities = &language_server.capabilities();
2123 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2124 if range_formatting_provider == Some(&OneOf::Left(false)) {
2125 anyhow::bail!(
2126 "{} language server does not support range formatting",
2127 language_server.name()
2128 );
2129 }
2130
2131 let uri = file_path_to_lsp_url(abs_path)?;
2132 let text_document = lsp::TextDocumentIdentifier::new(uri);
2133
2134 let lsp_edits = {
2135 let mut lsp_ranges = Vec::new();
2136 this.update(cx, |_this, cx| {
2137 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2138 // not have been sent to the language server. This seems like a fairly systemic
2139 // issue, though, the resolution probably is not specific to formatting.
2140 //
2141 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2142 // LSP.
2143 let snapshot = buffer_handle.read(cx).snapshot();
2144 for range in ranges {
2145 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2146 }
2147 anyhow::Ok(())
2148 })??;
2149
2150 let mut edits = None;
2151 for range in lsp_ranges {
2152 if let Some(mut edit) = language_server
2153 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2154 text_document: text_document.clone(),
2155 range,
2156 options: lsp_command::lsp_formatting_options(settings),
2157 work_done_progress_params: Default::default(),
2158 })
2159 .await
2160 .into_response()?
2161 {
2162 edits.get_or_insert_with(Vec::new).append(&mut edit);
2163 }
2164 }
2165 edits
2166 };
2167
2168 if let Some(lsp_edits) = lsp_edits {
2169 this.update(cx, |this, cx| {
2170 this.as_local_mut().unwrap().edits_from_lsp(
2171 buffer_handle,
2172 lsp_edits,
2173 language_server.server_id(),
2174 None,
2175 cx,
2176 )
2177 })?
2178 .await
2179 } else {
2180 Ok(Vec::with_capacity(0))
2181 }
2182 }
2183
2184 async fn format_via_lsp(
2185 this: &WeakEntity<LspStore>,
2186 buffer: &Entity<Buffer>,
2187 abs_path: &Path,
2188 language_server: &Arc<LanguageServer>,
2189 settings: &LanguageSettings,
2190 cx: &mut AsyncApp,
2191 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2192 let logger = zlog::scoped!("lsp_format");
2193 zlog::debug!(logger => "Formatting via LSP");
2194
2195 let uri = file_path_to_lsp_url(abs_path)?;
2196 let text_document = lsp::TextDocumentIdentifier::new(uri);
2197 let capabilities = &language_server.capabilities();
2198
2199 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2200 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2201
2202 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2203 let _timer = zlog::time!(logger => "format-full");
2204 language_server
2205 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2206 text_document,
2207 options: lsp_command::lsp_formatting_options(settings),
2208 work_done_progress_params: Default::default(),
2209 })
2210 .await
2211 .into_response()?
2212 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2213 let _timer = zlog::time!(logger => "format-range");
2214 let buffer_start = lsp::Position::new(0, 0);
2215 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2216 language_server
2217 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2218 text_document: text_document.clone(),
2219 range: lsp::Range::new(buffer_start, buffer_end),
2220 options: lsp_command::lsp_formatting_options(settings),
2221 work_done_progress_params: Default::default(),
2222 })
2223 .await
2224 .into_response()?
2225 } else {
2226 None
2227 };
2228
2229 if let Some(lsp_edits) = lsp_edits {
2230 this.update(cx, |this, cx| {
2231 this.as_local_mut().unwrap().edits_from_lsp(
2232 buffer,
2233 lsp_edits,
2234 language_server.server_id(),
2235 None,
2236 cx,
2237 )
2238 })?
2239 .await
2240 } else {
2241 Ok(Vec::with_capacity(0))
2242 }
2243 }
2244
2245 async fn format_via_external_command(
2246 buffer: &FormattableBuffer,
2247 command: &str,
2248 arguments: Option<&[String]>,
2249 cx: &mut AsyncApp,
2250 ) -> Result<Option<Diff>> {
2251 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2252 let file = File::from_dyn(buffer.file())?;
2253 let worktree = file.worktree.read(cx);
2254 let mut worktree_path = worktree.abs_path().to_path_buf();
2255 if worktree.root_entry()?.is_file() {
2256 worktree_path.pop();
2257 }
2258 Some(worktree_path)
2259 });
2260
2261 let mut child = util::command::new_smol_command(command);
2262
2263 if let Some(buffer_env) = buffer.env.as_ref() {
2264 child.envs(buffer_env);
2265 }
2266
2267 if let Some(working_dir_path) = working_dir_path {
2268 child.current_dir(working_dir_path);
2269 }
2270
2271 if let Some(arguments) = arguments {
2272 child.args(arguments.iter().map(|arg| {
2273 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2274 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2275 } else {
2276 arg.replace("{buffer_path}", "Untitled")
2277 }
2278 }));
2279 }
2280
2281 let mut child = child
2282 .stdin(smol::process::Stdio::piped())
2283 .stdout(smol::process::Stdio::piped())
2284 .stderr(smol::process::Stdio::piped())
2285 .spawn()?;
2286
2287 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2288 let text = buffer
2289 .handle
2290 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2291 for chunk in text.chunks() {
2292 stdin.write_all(chunk.as_bytes()).await?;
2293 }
2294 stdin.flush().await?;
2295
2296 let output = child.output().await?;
2297 anyhow::ensure!(
2298 output.status.success(),
2299 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2300 output.status.code(),
2301 String::from_utf8_lossy(&output.stdout),
2302 String::from_utf8_lossy(&output.stderr),
2303 );
2304
2305 let stdout = String::from_utf8(output.stdout)?;
2306 Ok(Some(
2307 buffer
2308 .handle
2309 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2310 .await,
2311 ))
2312 }
2313
2314 async fn try_resolve_code_action(
2315 lang_server: &LanguageServer,
2316 action: &mut CodeAction,
2317 ) -> anyhow::Result<()> {
2318 match &mut action.lsp_action {
2319 LspAction::Action(lsp_action) => {
2320 if !action.resolved
2321 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2322 && lsp_action.data.is_some()
2323 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2324 {
2325 **lsp_action = lang_server
2326 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2327 .await
2328 .into_response()?;
2329 }
2330 }
2331 LspAction::CodeLens(lens) => {
2332 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2333 *lens = lang_server
2334 .request::<lsp::request::CodeLensResolve>(lens.clone())
2335 .await
2336 .into_response()?;
2337 }
2338 }
2339 LspAction::Command(_) => {}
2340 }
2341
2342 action.resolved = true;
2343 anyhow::Ok(())
2344 }
2345
2346 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2347 let buffer = buffer_handle.read(cx);
2348
2349 let file = buffer.file().cloned();
2350
2351 let Some(file) = File::from_dyn(file.as_ref()) else {
2352 return;
2353 };
2354 if !file.is_local() {
2355 return;
2356 }
2357 let path = ProjectPath::from_file(file, cx);
2358 let worktree_id = file.worktree_id(cx);
2359 let language = buffer.language().cloned();
2360
2361 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2362 for (server_id, diagnostics) in
2363 diagnostics.get(file.path()).cloned().unwrap_or_default()
2364 {
2365 self.update_buffer_diagnostics(
2366 buffer_handle,
2367 server_id,
2368 None,
2369 None,
2370 None,
2371 Vec::new(),
2372 diagnostics,
2373 cx,
2374 )
2375 .log_err();
2376 }
2377 }
2378 let Some(language) = language else {
2379 return;
2380 };
2381 let Some(snapshot) = self
2382 .worktree_store
2383 .read(cx)
2384 .worktree_for_id(worktree_id, cx)
2385 .map(|worktree| worktree.read(cx).snapshot())
2386 else {
2387 return;
2388 };
2389 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2390
2391 for server_id in
2392 self.lsp_tree
2393 .get(path, language.name(), language.manifest(), &delegate, cx)
2394 {
2395 let server = self
2396 .language_servers
2397 .get(&server_id)
2398 .and_then(|server_state| {
2399 if let LanguageServerState::Running { server, .. } = server_state {
2400 Some(server.clone())
2401 } else {
2402 None
2403 }
2404 });
2405 let server = match server {
2406 Some(server) => server,
2407 None => continue,
2408 };
2409
2410 buffer_handle.update(cx, |buffer, cx| {
2411 buffer.set_completion_triggers(
2412 server.server_id(),
2413 server
2414 .capabilities()
2415 .completion_provider
2416 .as_ref()
2417 .and_then(|provider| {
2418 provider
2419 .trigger_characters
2420 .as_ref()
2421 .map(|characters| characters.iter().cloned().collect())
2422 })
2423 .unwrap_or_default(),
2424 cx,
2425 );
2426 });
2427 }
2428 }
2429
2430 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2431 buffer.update(cx, |buffer, cx| {
2432 let Some(language) = buffer.language() else {
2433 return;
2434 };
2435 let path = ProjectPath {
2436 worktree_id: old_file.worktree_id(cx),
2437 path: old_file.path.clone(),
2438 };
2439 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2440 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2441 buffer.set_completion_triggers(server_id, Default::default(), cx);
2442 }
2443 });
2444 }
2445
2446 fn update_buffer_diagnostics(
2447 &mut self,
2448 buffer: &Entity<Buffer>,
2449 server_id: LanguageServerId,
2450 registration_id: Option<Option<SharedString>>,
2451 result_id: Option<SharedString>,
2452 version: Option<i32>,
2453 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2454 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2455 cx: &mut Context<LspStore>,
2456 ) -> Result<()> {
2457 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2458 Ordering::Equal
2459 .then_with(|| b.is_primary.cmp(&a.is_primary))
2460 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2461 .then_with(|| a.severity.cmp(&b.severity))
2462 .then_with(|| a.message.cmp(&b.message))
2463 }
2464
2465 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2466 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2467 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2468
2469 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2470 Ordering::Equal
2471 .then_with(|| a.range.start.cmp(&b.range.start))
2472 .then_with(|| b.range.end.cmp(&a.range.end))
2473 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2474 });
2475
2476 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2477
2478 let edits_since_save = std::cell::LazyCell::new(|| {
2479 let saved_version = buffer.read(cx).saved_version();
2480 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2481 });
2482
2483 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2484
2485 for (new_diagnostic, entry) in diagnostics {
2486 let start;
2487 let end;
2488 if new_diagnostic && entry.diagnostic.is_disk_based {
2489 // Some diagnostics are based on files on disk instead of buffers'
2490 // current contents. Adjust these diagnostics' ranges to reflect
2491 // any unsaved edits.
2492 // Do not alter the reused ones though, as their coordinates were stored as anchors
2493 // and were properly adjusted on reuse.
2494 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2495 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2496 } else {
2497 start = entry.range.start;
2498 end = entry.range.end;
2499 }
2500
2501 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2502 ..snapshot.clip_point_utf16(end, Bias::Right);
2503
2504 // Expand empty ranges by one codepoint
2505 if range.start == range.end {
2506 // This will be go to the next boundary when being clipped
2507 range.end.column += 1;
2508 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2509 if range.start == range.end && range.end.column > 0 {
2510 range.start.column -= 1;
2511 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2512 }
2513 }
2514
2515 sanitized_diagnostics.push(DiagnosticEntry {
2516 range,
2517 diagnostic: entry.diagnostic,
2518 });
2519 }
2520 drop(edits_since_save);
2521
2522 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2523 buffer.update(cx, |buffer, cx| {
2524 if let Some(registration_id) = registration_id {
2525 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2526 self.buffer_pull_diagnostics_result_ids
2527 .entry(server_id)
2528 .or_default()
2529 .entry(registration_id)
2530 .or_default()
2531 .insert(abs_path, result_id);
2532 }
2533 }
2534
2535 buffer.update_diagnostics(server_id, set, cx)
2536 });
2537
2538 Ok(())
2539 }
2540
2541 fn register_language_server_for_invisible_worktree(
2542 &mut self,
2543 worktree: &Entity<Worktree>,
2544 language_server_id: LanguageServerId,
2545 cx: &mut App,
2546 ) {
2547 let worktree = worktree.read(cx);
2548 let worktree_id = worktree.id();
2549 debug_assert!(!worktree.is_visible());
2550 let Some(mut origin_seed) = self
2551 .language_server_ids
2552 .iter()
2553 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2554 else {
2555 return;
2556 };
2557 origin_seed.worktree_id = worktree_id;
2558 self.language_server_ids
2559 .entry(origin_seed)
2560 .or_insert_with(|| UnifiedLanguageServer {
2561 id: language_server_id,
2562 project_roots: Default::default(),
2563 });
2564 }
2565
2566 fn register_buffer_with_language_servers(
2567 &mut self,
2568 buffer_handle: &Entity<Buffer>,
2569 only_register_servers: HashSet<LanguageServerSelector>,
2570 cx: &mut Context<LspStore>,
2571 ) {
2572 let buffer = buffer_handle.read(cx);
2573 let buffer_id = buffer.remote_id();
2574
2575 let Some(file) = File::from_dyn(buffer.file()) else {
2576 return;
2577 };
2578 if !file.is_local() {
2579 return;
2580 }
2581
2582 let abs_path = file.abs_path(cx);
2583 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2584 return;
2585 };
2586 let initial_snapshot = buffer.text_snapshot();
2587 let worktree_id = file.worktree_id(cx);
2588
2589 let Some(language) = buffer.language().cloned() else {
2590 return;
2591 };
2592 let path: Arc<RelPath> = file
2593 .path()
2594 .parent()
2595 .map(Arc::from)
2596 .unwrap_or_else(|| file.path().clone());
2597 let Some(worktree) = self
2598 .worktree_store
2599 .read(cx)
2600 .worktree_for_id(worktree_id, cx)
2601 else {
2602 return;
2603 };
2604 let language_name = language.name();
2605 let (reused, delegate, servers) = self
2606 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2607 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2608 .unwrap_or_else(|| {
2609 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2610 let delegate: Arc<dyn ManifestDelegate> =
2611 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2612
2613 let servers = self
2614 .lsp_tree
2615 .walk(
2616 ProjectPath { worktree_id, path },
2617 language.name(),
2618 language.manifest(),
2619 &delegate,
2620 cx,
2621 )
2622 .collect::<Vec<_>>();
2623 (false, lsp_delegate, servers)
2624 });
2625 let servers_and_adapters = servers
2626 .into_iter()
2627 .filter_map(|server_node| {
2628 if reused && server_node.server_id().is_none() {
2629 return None;
2630 }
2631 if !only_register_servers.is_empty() {
2632 if let Some(server_id) = server_node.server_id()
2633 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2634 {
2635 return None;
2636 }
2637 if let Some(name) = server_node.name()
2638 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2639 {
2640 return None;
2641 }
2642 }
2643
2644 let server_id = server_node.server_id_or_init(|disposition| {
2645 let path = &disposition.path;
2646
2647 {
2648 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2649
2650 let server_id = self.get_or_insert_language_server(
2651 &worktree,
2652 delegate.clone(),
2653 disposition,
2654 &language_name,
2655 cx,
2656 );
2657
2658 if let Some(state) = self.language_servers.get(&server_id)
2659 && let Ok(uri) = uri
2660 {
2661 state.add_workspace_folder(uri);
2662 };
2663 server_id
2664 }
2665 })?;
2666 let server_state = self.language_servers.get(&server_id)?;
2667 if let LanguageServerState::Running {
2668 server, adapter, ..
2669 } = server_state
2670 {
2671 Some((server.clone(), adapter.clone()))
2672 } else {
2673 None
2674 }
2675 })
2676 .collect::<Vec<_>>();
2677 for (server, adapter) in servers_and_adapters {
2678 buffer_handle.update(cx, |buffer, cx| {
2679 buffer.set_completion_triggers(
2680 server.server_id(),
2681 server
2682 .capabilities()
2683 .completion_provider
2684 .as_ref()
2685 .and_then(|provider| {
2686 provider
2687 .trigger_characters
2688 .as_ref()
2689 .map(|characters| characters.iter().cloned().collect())
2690 })
2691 .unwrap_or_default(),
2692 cx,
2693 );
2694 });
2695
2696 let snapshot = LspBufferSnapshot {
2697 version: 0,
2698 snapshot: initial_snapshot.clone(),
2699 };
2700
2701 let mut registered = false;
2702 self.buffer_snapshots
2703 .entry(buffer_id)
2704 .or_default()
2705 .entry(server.server_id())
2706 .or_insert_with(|| {
2707 registered = true;
2708 server.register_buffer(
2709 uri.clone(),
2710 adapter.language_id(&language.name()),
2711 0,
2712 initial_snapshot.text(),
2713 );
2714
2715 vec![snapshot]
2716 });
2717
2718 self.buffers_opened_in_servers
2719 .entry(buffer_id)
2720 .or_default()
2721 .insert(server.server_id());
2722 if registered {
2723 cx.emit(LspStoreEvent::LanguageServerUpdate {
2724 language_server_id: server.server_id(),
2725 name: None,
2726 message: proto::update_language_server::Variant::RegisteredForBuffer(
2727 proto::RegisteredForBuffer {
2728 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2729 buffer_id: buffer_id.to_proto(),
2730 },
2731 ),
2732 });
2733 }
2734 }
2735 }
2736
2737 fn reuse_existing_language_server<'lang_name>(
2738 &self,
2739 server_tree: &LanguageServerTree,
2740 worktree: &Entity<Worktree>,
2741 language_name: &'lang_name LanguageName,
2742 cx: &mut App,
2743 ) -> Option<(
2744 Arc<LocalLspAdapterDelegate>,
2745 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2746 )> {
2747 if worktree.read(cx).is_visible() {
2748 return None;
2749 }
2750
2751 let worktree_store = self.worktree_store.read(cx);
2752 let servers = server_tree
2753 .instances
2754 .iter()
2755 .filter(|(worktree_id, _)| {
2756 worktree_store
2757 .worktree_for_id(**worktree_id, cx)
2758 .is_some_and(|worktree| worktree.read(cx).is_visible())
2759 })
2760 .flat_map(|(worktree_id, servers)| {
2761 servers
2762 .roots
2763 .iter()
2764 .flat_map(|(_, language_servers)| language_servers)
2765 .map(move |(_, (server_node, server_languages))| {
2766 (worktree_id, server_node, server_languages)
2767 })
2768 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2769 .map(|(worktree_id, server_node, _)| {
2770 (
2771 *worktree_id,
2772 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2773 )
2774 })
2775 })
2776 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2777 acc.entry(worktree_id)
2778 .or_insert_with(Vec::new)
2779 .push(server_node);
2780 acc
2781 })
2782 .into_values()
2783 .max_by_key(|servers| servers.len())?;
2784
2785 let worktree_id = worktree.read(cx).id();
2786 let apply = move |tree: &mut LanguageServerTree| {
2787 for server_node in &servers {
2788 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2789 }
2790 servers
2791 };
2792
2793 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2794 Some((delegate, apply))
2795 }
2796
2797 pub(crate) fn unregister_old_buffer_from_language_servers(
2798 &mut self,
2799 buffer: &Entity<Buffer>,
2800 old_file: &File,
2801 cx: &mut App,
2802 ) {
2803 let old_path = match old_file.as_local() {
2804 Some(local) => local.abs_path(cx),
2805 None => return,
2806 };
2807
2808 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2809 debug_panic!("{old_path:?} is not parseable as an URI");
2810 return;
2811 };
2812 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2813 }
2814
2815 pub(crate) fn unregister_buffer_from_language_servers(
2816 &mut self,
2817 buffer: &Entity<Buffer>,
2818 file_url: &lsp::Uri,
2819 cx: &mut App,
2820 ) {
2821 buffer.update(cx, |buffer, cx| {
2822 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2823
2824 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2825 if snapshots
2826 .as_mut()
2827 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2828 {
2829 language_server.unregister_buffer(file_url.clone());
2830 }
2831 }
2832 });
2833 }
2834
2835 fn buffer_snapshot_for_lsp_version(
2836 &mut self,
2837 buffer: &Entity<Buffer>,
2838 server_id: LanguageServerId,
2839 version: Option<i32>,
2840 cx: &App,
2841 ) -> Result<TextBufferSnapshot> {
2842 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2843
2844 if let Some(version) = version {
2845 let buffer_id = buffer.read(cx).remote_id();
2846 let snapshots = if let Some(snapshots) = self
2847 .buffer_snapshots
2848 .get_mut(&buffer_id)
2849 .and_then(|m| m.get_mut(&server_id))
2850 {
2851 snapshots
2852 } else if version == 0 {
2853 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2854 // We detect this case and treat it as if the version was `None`.
2855 return Ok(buffer.read(cx).text_snapshot());
2856 } else {
2857 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2858 };
2859
2860 let found_snapshot = snapshots
2861 .binary_search_by_key(&version, |e| e.version)
2862 .map(|ix| snapshots[ix].snapshot.clone())
2863 .map_err(|_| {
2864 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2865 })?;
2866
2867 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2868 Ok(found_snapshot)
2869 } else {
2870 Ok((buffer.read(cx)).text_snapshot())
2871 }
2872 }
2873
2874 async fn get_server_code_actions_from_action_kinds(
2875 lsp_store: &WeakEntity<LspStore>,
2876 language_server_id: LanguageServerId,
2877 code_action_kinds: Vec<lsp::CodeActionKind>,
2878 buffer: &Entity<Buffer>,
2879 cx: &mut AsyncApp,
2880 ) -> Result<Vec<CodeAction>> {
2881 let actions = lsp_store
2882 .update(cx, move |this, cx| {
2883 let request = GetCodeActions {
2884 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2885 kinds: Some(code_action_kinds),
2886 };
2887 let server = LanguageServerToQuery::Other(language_server_id);
2888 this.request_lsp(buffer.clone(), server, request, cx)
2889 })?
2890 .await?;
2891 Ok(actions)
2892 }
2893
2894 pub async fn execute_code_actions_on_server(
2895 lsp_store: &WeakEntity<LspStore>,
2896 language_server: &Arc<LanguageServer>,
2897
2898 actions: Vec<CodeAction>,
2899 push_to_history: bool,
2900 project_transaction: &mut ProjectTransaction,
2901 cx: &mut AsyncApp,
2902 ) -> anyhow::Result<()> {
2903 for mut action in actions {
2904 Self::try_resolve_code_action(language_server, &mut action)
2905 .await
2906 .context("resolving a formatting code action")?;
2907
2908 if let Some(edit) = action.lsp_action.edit() {
2909 if edit.changes.is_none() && edit.document_changes.is_none() {
2910 continue;
2911 }
2912
2913 let new = Self::deserialize_workspace_edit(
2914 lsp_store.upgrade().context("project dropped")?,
2915 edit.clone(),
2916 push_to_history,
2917 language_server.clone(),
2918 cx,
2919 )
2920 .await?;
2921 project_transaction.0.extend(new.0);
2922 }
2923
2924 if let Some(command) = action.lsp_action.command() {
2925 let server_capabilities = language_server.capabilities();
2926 let available_commands = server_capabilities
2927 .execute_command_provider
2928 .as_ref()
2929 .map(|options| options.commands.as_slice())
2930 .unwrap_or_default();
2931 if available_commands.contains(&command.command) {
2932 lsp_store.update(cx, |lsp_store, _| {
2933 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2934 mode.last_workspace_edits_by_language_server
2935 .remove(&language_server.server_id());
2936 }
2937 })?;
2938
2939 language_server
2940 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2941 command: command.command.clone(),
2942 arguments: command.arguments.clone().unwrap_or_default(),
2943 ..Default::default()
2944 })
2945 .await
2946 .into_response()
2947 .context("execute command")?;
2948
2949 lsp_store.update(cx, |this, _| {
2950 if let LspStoreMode::Local(mode) = &mut this.mode {
2951 project_transaction.0.extend(
2952 mode.last_workspace_edits_by_language_server
2953 .remove(&language_server.server_id())
2954 .unwrap_or_default()
2955 .0,
2956 )
2957 }
2958 })?;
2959 } else {
2960 log::warn!(
2961 "Cannot execute a command {} not listed in the language server capabilities",
2962 command.command
2963 )
2964 }
2965 }
2966 }
2967 Ok(())
2968 }
2969
2970 pub async fn deserialize_text_edits(
2971 this: Entity<LspStore>,
2972 buffer_to_edit: Entity<Buffer>,
2973 edits: Vec<lsp::TextEdit>,
2974 push_to_history: bool,
2975 _: Arc<CachedLspAdapter>,
2976 language_server: Arc<LanguageServer>,
2977 cx: &mut AsyncApp,
2978 ) -> Result<Option<Transaction>> {
2979 let edits = this
2980 .update(cx, |this, cx| {
2981 this.as_local_mut().unwrap().edits_from_lsp(
2982 &buffer_to_edit,
2983 edits,
2984 language_server.server_id(),
2985 None,
2986 cx,
2987 )
2988 })
2989 .await?;
2990
2991 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2992 buffer.finalize_last_transaction();
2993 buffer.start_transaction();
2994 for (range, text) in edits {
2995 buffer.edit([(range, text)], None, cx);
2996 }
2997
2998 if buffer.end_transaction(cx).is_some() {
2999 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3000 if !push_to_history {
3001 buffer.forget_transaction(transaction.id);
3002 }
3003 Some(transaction)
3004 } else {
3005 None
3006 }
3007 });
3008
3009 Ok(transaction)
3010 }
3011
3012 #[allow(clippy::type_complexity)]
3013 pub(crate) fn edits_from_lsp(
3014 &mut self,
3015 buffer: &Entity<Buffer>,
3016 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3017 server_id: LanguageServerId,
3018 version: Option<i32>,
3019 cx: &mut Context<LspStore>,
3020 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3021 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3022 cx.background_spawn(async move {
3023 let snapshot = snapshot?;
3024 let mut lsp_edits = lsp_edits
3025 .into_iter()
3026 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3027 .collect::<Vec<_>>();
3028
3029 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3030
3031 let mut lsp_edits = lsp_edits.into_iter().peekable();
3032 let mut edits = Vec::new();
3033 while let Some((range, mut new_text)) = lsp_edits.next() {
3034 // Clip invalid ranges provided by the language server.
3035 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3036 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3037
3038 // Combine any LSP edits that are adjacent.
3039 //
3040 // Also, combine LSP edits that are separated from each other by only
3041 // a newline. This is important because for some code actions,
3042 // Rust-analyzer rewrites the entire buffer via a series of edits that
3043 // are separated by unchanged newline characters.
3044 //
3045 // In order for the diffing logic below to work properly, any edits that
3046 // cancel each other out must be combined into one.
3047 while let Some((next_range, next_text)) = lsp_edits.peek() {
3048 if next_range.start.0 > range.end {
3049 if next_range.start.0.row > range.end.row + 1
3050 || next_range.start.0.column > 0
3051 || snapshot.clip_point_utf16(
3052 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3053 Bias::Left,
3054 ) > range.end
3055 {
3056 break;
3057 }
3058 new_text.push('\n');
3059 }
3060 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3061 new_text.push_str(next_text);
3062 lsp_edits.next();
3063 }
3064
3065 // For multiline edits, perform a diff of the old and new text so that
3066 // we can identify the changes more precisely, preserving the locations
3067 // of any anchors positioned in the unchanged regions.
3068 if range.end.row > range.start.row {
3069 let offset = range.start.to_offset(&snapshot);
3070 let old_text = snapshot.text_for_range(range).collect::<String>();
3071 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3072 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3073 (
3074 snapshot.anchor_after(offset + range.start)
3075 ..snapshot.anchor_before(offset + range.end),
3076 replacement,
3077 )
3078 }));
3079 } else if range.end == range.start {
3080 let anchor = snapshot.anchor_after(range.start);
3081 edits.push((anchor..anchor, new_text.into()));
3082 } else {
3083 let edit_start = snapshot.anchor_after(range.start);
3084 let edit_end = snapshot.anchor_before(range.end);
3085 edits.push((edit_start..edit_end, new_text.into()));
3086 }
3087 }
3088
3089 Ok(edits)
3090 })
3091 }
3092
3093 pub(crate) async fn deserialize_workspace_edit(
3094 this: Entity<LspStore>,
3095 edit: lsp::WorkspaceEdit,
3096 push_to_history: bool,
3097 language_server: Arc<LanguageServer>,
3098 cx: &mut AsyncApp,
3099 ) -> Result<ProjectTransaction> {
3100 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3101
3102 let mut operations = Vec::new();
3103 if let Some(document_changes) = edit.document_changes {
3104 match document_changes {
3105 lsp::DocumentChanges::Edits(edits) => {
3106 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3107 }
3108 lsp::DocumentChanges::Operations(ops) => operations = ops,
3109 }
3110 } else if let Some(changes) = edit.changes {
3111 operations.extend(changes.into_iter().map(|(uri, edits)| {
3112 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3113 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3114 uri,
3115 version: None,
3116 },
3117 edits: edits.into_iter().map(Edit::Plain).collect(),
3118 })
3119 }));
3120 }
3121
3122 let mut project_transaction = ProjectTransaction::default();
3123 for operation in operations {
3124 match operation {
3125 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3126 let abs_path = op
3127 .uri
3128 .to_file_path()
3129 .map_err(|()| anyhow!("can't convert URI to path"))?;
3130
3131 if let Some(parent_path) = abs_path.parent() {
3132 fs.create_dir(parent_path).await?;
3133 }
3134 if abs_path.ends_with("/") {
3135 fs.create_dir(&abs_path).await?;
3136 } else {
3137 fs.create_file(
3138 &abs_path,
3139 op.options
3140 .map(|options| fs::CreateOptions {
3141 overwrite: options.overwrite.unwrap_or(false),
3142 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3143 })
3144 .unwrap_or_default(),
3145 )
3146 .await?;
3147 }
3148 }
3149
3150 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3151 let source_abs_path = op
3152 .old_uri
3153 .to_file_path()
3154 .map_err(|()| anyhow!("can't convert URI to path"))?;
3155 let target_abs_path = op
3156 .new_uri
3157 .to_file_path()
3158 .map_err(|()| anyhow!("can't convert URI to path"))?;
3159
3160 let options = fs::RenameOptions {
3161 overwrite: op
3162 .options
3163 .as_ref()
3164 .and_then(|options| options.overwrite)
3165 .unwrap_or(false),
3166 ignore_if_exists: op
3167 .options
3168 .as_ref()
3169 .and_then(|options| options.ignore_if_exists)
3170 .unwrap_or(false),
3171 create_parents: true,
3172 };
3173
3174 fs.rename(&source_abs_path, &target_abs_path, options)
3175 .await?;
3176 }
3177
3178 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3179 let abs_path = op
3180 .uri
3181 .to_file_path()
3182 .map_err(|()| anyhow!("can't convert URI to path"))?;
3183 let options = op
3184 .options
3185 .map(|options| fs::RemoveOptions {
3186 recursive: options.recursive.unwrap_or(false),
3187 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3188 })
3189 .unwrap_or_default();
3190 if abs_path.ends_with("/") {
3191 fs.remove_dir(&abs_path, options).await?;
3192 } else {
3193 fs.remove_file(&abs_path, options).await?;
3194 }
3195 }
3196
3197 lsp::DocumentChangeOperation::Edit(op) => {
3198 let buffer_to_edit = this
3199 .update(cx, |this, cx| {
3200 this.open_local_buffer_via_lsp(
3201 op.text_document.uri.clone(),
3202 language_server.server_id(),
3203 cx,
3204 )
3205 })
3206 .await?;
3207
3208 let edits = this
3209 .update(cx, |this, cx| {
3210 let path = buffer_to_edit.read(cx).project_path(cx);
3211 let active_entry = this.active_entry;
3212 let is_active_entry = path.is_some_and(|project_path| {
3213 this.worktree_store
3214 .read(cx)
3215 .entry_for_path(&project_path, cx)
3216 .is_some_and(|entry| Some(entry.id) == active_entry)
3217 });
3218 let local = this.as_local_mut().unwrap();
3219
3220 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3221 for edit in op.edits {
3222 match edit {
3223 Edit::Plain(edit) => {
3224 if !edits.contains(&edit) {
3225 edits.push(edit)
3226 }
3227 }
3228 Edit::Annotated(edit) => {
3229 if !edits.contains(&edit.text_edit) {
3230 edits.push(edit.text_edit)
3231 }
3232 }
3233 Edit::Snippet(edit) => {
3234 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3235 else {
3236 continue;
3237 };
3238
3239 if is_active_entry {
3240 snippet_edits.push((edit.range, snippet));
3241 } else {
3242 // Since this buffer is not focused, apply a normal edit.
3243 let new_edit = TextEdit {
3244 range: edit.range,
3245 new_text: snippet.text,
3246 };
3247 if !edits.contains(&new_edit) {
3248 edits.push(new_edit);
3249 }
3250 }
3251 }
3252 }
3253 }
3254 if !snippet_edits.is_empty() {
3255 let buffer_id = buffer_to_edit.read(cx).remote_id();
3256 let version = if let Some(buffer_version) = op.text_document.version
3257 {
3258 local
3259 .buffer_snapshot_for_lsp_version(
3260 &buffer_to_edit,
3261 language_server.server_id(),
3262 Some(buffer_version),
3263 cx,
3264 )
3265 .ok()
3266 .map(|snapshot| snapshot.version)
3267 } else {
3268 Some(buffer_to_edit.read(cx).saved_version().clone())
3269 };
3270
3271 let most_recent_edit =
3272 version.and_then(|version| version.most_recent());
3273 // Check if the edit that triggered that edit has been made by this participant.
3274
3275 if let Some(most_recent_edit) = most_recent_edit {
3276 cx.emit(LspStoreEvent::SnippetEdit {
3277 buffer_id,
3278 edits: snippet_edits,
3279 most_recent_edit,
3280 });
3281 }
3282 }
3283
3284 local.edits_from_lsp(
3285 &buffer_to_edit,
3286 edits,
3287 language_server.server_id(),
3288 op.text_document.version,
3289 cx,
3290 )
3291 })
3292 .await?;
3293
3294 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3295 buffer.finalize_last_transaction();
3296 buffer.start_transaction();
3297 for (range, text) in edits {
3298 buffer.edit([(range, text)], None, cx);
3299 }
3300
3301 buffer.end_transaction(cx).and_then(|transaction_id| {
3302 if push_to_history {
3303 buffer.finalize_last_transaction();
3304 buffer.get_transaction(transaction_id).cloned()
3305 } else {
3306 buffer.forget_transaction(transaction_id)
3307 }
3308 })
3309 });
3310 if let Some(transaction) = transaction {
3311 project_transaction.0.insert(buffer_to_edit, transaction);
3312 }
3313 }
3314 }
3315 }
3316
3317 Ok(project_transaction)
3318 }
3319
3320 async fn on_lsp_workspace_edit(
3321 this: WeakEntity<LspStore>,
3322 params: lsp::ApplyWorkspaceEditParams,
3323 server_id: LanguageServerId,
3324 cx: &mut AsyncApp,
3325 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3326 let this = this.upgrade().context("project project closed")?;
3327 let language_server = this
3328 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3329 .context("language server not found")?;
3330 let transaction = Self::deserialize_workspace_edit(
3331 this.clone(),
3332 params.edit,
3333 true,
3334 language_server.clone(),
3335 cx,
3336 )
3337 .await
3338 .log_err();
3339 this.update(cx, |this, cx| {
3340 if let Some(transaction) = transaction {
3341 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3342
3343 this.as_local_mut()
3344 .unwrap()
3345 .last_workspace_edits_by_language_server
3346 .insert(server_id, transaction);
3347 }
3348 });
3349 Ok(lsp::ApplyWorkspaceEditResponse {
3350 applied: true,
3351 failed_change: None,
3352 failure_reason: None,
3353 })
3354 }
3355
3356 fn remove_worktree(
3357 &mut self,
3358 id_to_remove: WorktreeId,
3359 cx: &mut Context<LspStore>,
3360 ) -> Vec<LanguageServerId> {
3361 self.restricted_worktrees_tasks.remove(&id_to_remove);
3362 self.diagnostics.remove(&id_to_remove);
3363 self.prettier_store.update(cx, |prettier_store, cx| {
3364 prettier_store.remove_worktree(id_to_remove, cx);
3365 });
3366
3367 let mut servers_to_remove = BTreeSet::default();
3368 let mut servers_to_preserve = HashSet::default();
3369 for (seed, state) in &self.language_server_ids {
3370 if seed.worktree_id == id_to_remove {
3371 servers_to_remove.insert(state.id);
3372 } else {
3373 servers_to_preserve.insert(state.id);
3374 }
3375 }
3376 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3377 self.language_server_ids
3378 .retain(|_, state| !servers_to_remove.contains(&state.id));
3379 for server_id_to_remove in &servers_to_remove {
3380 self.language_server_watched_paths
3381 .remove(server_id_to_remove);
3382 self.language_server_paths_watched_for_rename
3383 .remove(server_id_to_remove);
3384 self.last_workspace_edits_by_language_server
3385 .remove(server_id_to_remove);
3386 self.language_servers.remove(server_id_to_remove);
3387 self.buffer_pull_diagnostics_result_ids
3388 .remove(server_id_to_remove);
3389 self.workspace_pull_diagnostics_result_ids
3390 .remove(server_id_to_remove);
3391 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3392 buffer_servers.remove(server_id_to_remove);
3393 }
3394 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3395 }
3396 servers_to_remove.into_iter().collect()
3397 }
3398
3399 fn rebuild_watched_paths_inner<'a>(
3400 &'a self,
3401 language_server_id: LanguageServerId,
3402 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3403 cx: &mut Context<LspStore>,
3404 ) -> LanguageServerWatchedPathsBuilder {
3405 let worktrees = self
3406 .worktree_store
3407 .read(cx)
3408 .worktrees()
3409 .filter_map(|worktree| {
3410 self.language_servers_for_worktree(worktree.read(cx).id())
3411 .find(|server| server.server_id() == language_server_id)
3412 .map(|_| worktree)
3413 })
3414 .collect::<Vec<_>>();
3415
3416 let mut worktree_globs = HashMap::default();
3417 let mut abs_globs = HashMap::default();
3418 log::trace!(
3419 "Processing new watcher paths for language server with id {}",
3420 language_server_id
3421 );
3422
3423 for watcher in watchers {
3424 if let Some((worktree, literal_prefix, pattern)) =
3425 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3426 {
3427 worktree.update(cx, |worktree, _| {
3428 if let Some((tree, glob)) =
3429 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3430 {
3431 tree.add_path_prefix_to_scan(literal_prefix);
3432 worktree_globs
3433 .entry(tree.id())
3434 .or_insert_with(GlobSetBuilder::new)
3435 .add(glob);
3436 }
3437 });
3438 } else {
3439 let (path, pattern) = match &watcher.glob_pattern {
3440 lsp::GlobPattern::String(s) => {
3441 let watcher_path = SanitizedPath::new(s);
3442 let path = glob_literal_prefix(watcher_path.as_path());
3443 let pattern = watcher_path
3444 .as_path()
3445 .strip_prefix(&path)
3446 .map(|p| p.to_string_lossy().into_owned())
3447 .unwrap_or_else(|e| {
3448 debug_panic!(
3449 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3450 s,
3451 path.display(),
3452 e
3453 );
3454 watcher_path.as_path().to_string_lossy().into_owned()
3455 });
3456 (path, pattern)
3457 }
3458 lsp::GlobPattern::Relative(rp) => {
3459 let Ok(mut base_uri) = match &rp.base_uri {
3460 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3461 lsp::OneOf::Right(base_uri) => base_uri,
3462 }
3463 .to_file_path() else {
3464 continue;
3465 };
3466
3467 let path = glob_literal_prefix(Path::new(&rp.pattern));
3468 let pattern = Path::new(&rp.pattern)
3469 .strip_prefix(&path)
3470 .map(|p| p.to_string_lossy().into_owned())
3471 .unwrap_or_else(|e| {
3472 debug_panic!(
3473 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3474 rp.pattern,
3475 path.display(),
3476 e
3477 );
3478 rp.pattern.clone()
3479 });
3480 base_uri.push(path);
3481 (base_uri, pattern)
3482 }
3483 };
3484
3485 if let Some(glob) = Glob::new(&pattern).log_err() {
3486 if !path
3487 .components()
3488 .any(|c| matches!(c, path::Component::Normal(_)))
3489 {
3490 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3491 // rather than adding a new watcher for `/`.
3492 for worktree in &worktrees {
3493 worktree_globs
3494 .entry(worktree.read(cx).id())
3495 .or_insert_with(GlobSetBuilder::new)
3496 .add(glob.clone());
3497 }
3498 } else {
3499 abs_globs
3500 .entry(path.into())
3501 .or_insert_with(GlobSetBuilder::new)
3502 .add(glob);
3503 }
3504 }
3505 }
3506 }
3507
3508 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3509 for (worktree_id, builder) in worktree_globs {
3510 if let Ok(globset) = builder.build() {
3511 watch_builder.watch_worktree(worktree_id, globset);
3512 }
3513 }
3514 for (abs_path, builder) in abs_globs {
3515 if let Ok(globset) = builder.build() {
3516 watch_builder.watch_abs_path(abs_path, globset);
3517 }
3518 }
3519 watch_builder
3520 }
3521
3522 fn worktree_and_path_for_file_watcher(
3523 worktrees: &[Entity<Worktree>],
3524 watcher: &FileSystemWatcher,
3525 cx: &App,
3526 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3527 worktrees.iter().find_map(|worktree| {
3528 let tree = worktree.read(cx);
3529 let worktree_root_path = tree.abs_path();
3530 let path_style = tree.path_style();
3531 match &watcher.glob_pattern {
3532 lsp::GlobPattern::String(s) => {
3533 let watcher_path = SanitizedPath::new(s);
3534 let relative = watcher_path
3535 .as_path()
3536 .strip_prefix(&worktree_root_path)
3537 .ok()?;
3538 let literal_prefix = glob_literal_prefix(relative);
3539 Some((
3540 worktree.clone(),
3541 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3542 relative.to_string_lossy().into_owned(),
3543 ))
3544 }
3545 lsp::GlobPattern::Relative(rp) => {
3546 let base_uri = match &rp.base_uri {
3547 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3548 lsp::OneOf::Right(base_uri) => base_uri,
3549 }
3550 .to_file_path()
3551 .ok()?;
3552 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3553 let mut literal_prefix = relative.to_owned();
3554 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3555 Some((
3556 worktree.clone(),
3557 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3558 rp.pattern.clone(),
3559 ))
3560 }
3561 }
3562 })
3563 }
3564
3565 fn rebuild_watched_paths(
3566 &mut self,
3567 language_server_id: LanguageServerId,
3568 cx: &mut Context<LspStore>,
3569 ) {
3570 let Some(registrations) = self
3571 .language_server_dynamic_registrations
3572 .get(&language_server_id)
3573 else {
3574 return;
3575 };
3576
3577 let watch_builder = self.rebuild_watched_paths_inner(
3578 language_server_id,
3579 registrations.did_change_watched_files.values().flatten(),
3580 cx,
3581 );
3582 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3583 self.language_server_watched_paths
3584 .insert(language_server_id, watcher);
3585
3586 cx.notify();
3587 }
3588
3589 fn on_lsp_did_change_watched_files(
3590 &mut self,
3591 language_server_id: LanguageServerId,
3592 registration_id: &str,
3593 params: DidChangeWatchedFilesRegistrationOptions,
3594 cx: &mut Context<LspStore>,
3595 ) {
3596 let registrations = self
3597 .language_server_dynamic_registrations
3598 .entry(language_server_id)
3599 .or_default();
3600
3601 registrations
3602 .did_change_watched_files
3603 .insert(registration_id.to_string(), params.watchers);
3604
3605 self.rebuild_watched_paths(language_server_id, cx);
3606 }
3607
3608 fn on_lsp_unregister_did_change_watched_files(
3609 &mut self,
3610 language_server_id: LanguageServerId,
3611 registration_id: &str,
3612 cx: &mut Context<LspStore>,
3613 ) {
3614 let registrations = self
3615 .language_server_dynamic_registrations
3616 .entry(language_server_id)
3617 .or_default();
3618
3619 if registrations
3620 .did_change_watched_files
3621 .remove(registration_id)
3622 .is_some()
3623 {
3624 log::info!(
3625 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3626 language_server_id,
3627 registration_id
3628 );
3629 } else {
3630 log::warn!(
3631 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3632 language_server_id,
3633 registration_id
3634 );
3635 }
3636
3637 self.rebuild_watched_paths(language_server_id, cx);
3638 }
3639
3640 async fn initialization_options_for_adapter(
3641 adapter: Arc<dyn LspAdapter>,
3642 delegate: &Arc<dyn LspAdapterDelegate>,
3643 ) -> Result<Option<serde_json::Value>> {
3644 let Some(mut initialization_config) =
3645 adapter.clone().initialization_options(delegate).await?
3646 else {
3647 return Ok(None);
3648 };
3649
3650 for other_adapter in delegate.registered_lsp_adapters() {
3651 if other_adapter.name() == adapter.name() {
3652 continue;
3653 }
3654 if let Ok(Some(target_config)) = other_adapter
3655 .clone()
3656 .additional_initialization_options(adapter.name(), delegate)
3657 .await
3658 {
3659 merge_json_value_into(target_config.clone(), &mut initialization_config);
3660 }
3661 }
3662
3663 Ok(Some(initialization_config))
3664 }
3665
3666 async fn workspace_configuration_for_adapter(
3667 adapter: Arc<dyn LspAdapter>,
3668 delegate: &Arc<dyn LspAdapterDelegate>,
3669 toolchain: Option<Toolchain>,
3670 requested_uri: Option<Uri>,
3671 cx: &mut AsyncApp,
3672 ) -> Result<serde_json::Value> {
3673 let mut workspace_config = adapter
3674 .clone()
3675 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3676 .await?;
3677
3678 for other_adapter in delegate.registered_lsp_adapters() {
3679 if other_adapter.name() == adapter.name() {
3680 continue;
3681 }
3682 if let Ok(Some(target_config)) = other_adapter
3683 .clone()
3684 .additional_workspace_configuration(adapter.name(), delegate, cx)
3685 .await
3686 {
3687 merge_json_value_into(target_config.clone(), &mut workspace_config);
3688 }
3689 }
3690
3691 Ok(workspace_config)
3692 }
3693
3694 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3695 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3696 Some(server.clone())
3697 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3698 Some(Arc::clone(server))
3699 } else {
3700 None
3701 }
3702 }
3703}
3704
3705fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3706 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3707 cx.emit(LspStoreEvent::LanguageServerUpdate {
3708 language_server_id: server.server_id(),
3709 name: Some(server.name()),
3710 message: proto::update_language_server::Variant::MetadataUpdated(
3711 proto::ServerMetadataUpdated {
3712 capabilities: Some(capabilities),
3713 binary: Some(proto::LanguageServerBinaryInfo {
3714 path: server.binary().path.to_string_lossy().into_owned(),
3715 arguments: server
3716 .binary()
3717 .arguments
3718 .iter()
3719 .map(|arg| arg.to_string_lossy().into_owned())
3720 .collect(),
3721 }),
3722 configuration: serde_json::to_string(server.configuration()).ok(),
3723 workspace_folders: server
3724 .workspace_folders()
3725 .iter()
3726 .map(|uri| uri.to_string())
3727 .collect(),
3728 },
3729 ),
3730 });
3731 }
3732}
3733
3734#[derive(Debug)]
3735pub struct FormattableBuffer {
3736 handle: Entity<Buffer>,
3737 abs_path: Option<PathBuf>,
3738 env: Option<HashMap<String, String>>,
3739 ranges: Option<Vec<Range<Anchor>>>,
3740}
3741
3742pub struct RemoteLspStore {
3743 upstream_client: Option<AnyProtoClient>,
3744 upstream_project_id: u64,
3745}
3746
3747pub(crate) enum LspStoreMode {
3748 Local(LocalLspStore), // ssh host and collab host
3749 Remote(RemoteLspStore), // collab guest
3750}
3751
3752impl LspStoreMode {
3753 fn is_local(&self) -> bool {
3754 matches!(self, LspStoreMode::Local(_))
3755 }
3756}
3757
3758pub struct LspStore {
3759 mode: LspStoreMode,
3760 last_formatting_failure: Option<String>,
3761 downstream_client: Option<(AnyProtoClient, u64)>,
3762 nonce: u128,
3763 buffer_store: Entity<BufferStore>,
3764 worktree_store: Entity<WorktreeStore>,
3765 pub languages: Arc<LanguageRegistry>,
3766 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3767 active_entry: Option<ProjectEntryId>,
3768 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3769 _maintain_buffer_languages: Task<()>,
3770 diagnostic_summaries:
3771 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3772 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3773 lsp_data: HashMap<BufferId, BufferLspData>,
3774 next_hint_id: Arc<AtomicUsize>,
3775}
3776
3777#[derive(Debug)]
3778pub struct BufferLspData {
3779 buffer_version: Global,
3780 document_colors: Option<DocumentColorData>,
3781 code_lens: Option<CodeLensData>,
3782 inlay_hints: BufferInlayHints,
3783 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3784 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3785}
3786
3787#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3788struct LspKey {
3789 request_type: TypeId,
3790 server_queried: Option<LanguageServerId>,
3791}
3792
3793impl BufferLspData {
3794 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3795 Self {
3796 buffer_version: buffer.read(cx).version(),
3797 document_colors: None,
3798 code_lens: None,
3799 inlay_hints: BufferInlayHints::new(buffer, cx),
3800 lsp_requests: HashMap::default(),
3801 chunk_lsp_requests: HashMap::default(),
3802 }
3803 }
3804
3805 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3806 if let Some(document_colors) = &mut self.document_colors {
3807 document_colors.colors.remove(&for_server);
3808 document_colors.cache_version += 1;
3809 }
3810
3811 if let Some(code_lens) = &mut self.code_lens {
3812 code_lens.lens.remove(&for_server);
3813 }
3814
3815 self.inlay_hints.remove_server_data(for_server);
3816 }
3817
3818 #[cfg(any(test, feature = "test-support"))]
3819 pub fn inlay_hints(&self) -> &BufferInlayHints {
3820 &self.inlay_hints
3821 }
3822}
3823
3824#[derive(Debug, Default, Clone)]
3825pub struct DocumentColors {
3826 pub colors: HashSet<DocumentColor>,
3827 pub cache_version: Option<usize>,
3828}
3829
3830type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3831type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3832
3833#[derive(Debug, Default)]
3834struct DocumentColorData {
3835 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3836 cache_version: usize,
3837 colors_update: Option<(Global, DocumentColorTask)>,
3838}
3839
3840#[derive(Debug, Default)]
3841struct CodeLensData {
3842 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3843 update: Option<(Global, CodeLensTask)>,
3844}
3845
3846#[derive(Debug)]
3847pub enum LspStoreEvent {
3848 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3849 LanguageServerRemoved(LanguageServerId),
3850 LanguageServerUpdate {
3851 language_server_id: LanguageServerId,
3852 name: Option<LanguageServerName>,
3853 message: proto::update_language_server::Variant,
3854 },
3855 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3856 LanguageServerPrompt(LanguageServerPromptRequest),
3857 LanguageDetected {
3858 buffer: Entity<Buffer>,
3859 new_language: Option<Arc<Language>>,
3860 },
3861 Notification(String),
3862 RefreshInlayHints {
3863 server_id: LanguageServerId,
3864 request_id: Option<usize>,
3865 },
3866 RefreshCodeLens,
3867 DiagnosticsUpdated {
3868 server_id: LanguageServerId,
3869 paths: Vec<ProjectPath>,
3870 },
3871 DiskBasedDiagnosticsStarted {
3872 language_server_id: LanguageServerId,
3873 },
3874 DiskBasedDiagnosticsFinished {
3875 language_server_id: LanguageServerId,
3876 },
3877 SnippetEdit {
3878 buffer_id: BufferId,
3879 edits: Vec<(lsp::Range, Snippet)>,
3880 most_recent_edit: clock::Lamport,
3881 },
3882 WorkspaceEditApplied(ProjectTransaction),
3883}
3884
3885#[derive(Clone, Debug, Serialize)]
3886pub struct LanguageServerStatus {
3887 pub name: LanguageServerName,
3888 pub server_version: Option<SharedString>,
3889 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3890 pub has_pending_diagnostic_updates: bool,
3891 pub progress_tokens: HashSet<ProgressToken>,
3892 pub worktree: Option<WorktreeId>,
3893 pub binary: Option<LanguageServerBinary>,
3894 pub configuration: Option<Value>,
3895 pub workspace_folders: BTreeSet<Uri>,
3896}
3897
3898#[derive(Clone, Debug)]
3899struct CoreSymbol {
3900 pub language_server_name: LanguageServerName,
3901 pub source_worktree_id: WorktreeId,
3902 pub source_language_server_id: LanguageServerId,
3903 pub path: SymbolLocation,
3904 pub name: String,
3905 pub kind: lsp::SymbolKind,
3906 pub range: Range<Unclipped<PointUtf16>>,
3907}
3908
3909#[derive(Clone, Debug, PartialEq, Eq)]
3910pub enum SymbolLocation {
3911 InProject(ProjectPath),
3912 OutsideProject {
3913 abs_path: Arc<Path>,
3914 signature: [u8; 32],
3915 },
3916}
3917
3918impl SymbolLocation {
3919 fn file_name(&self) -> Option<&str> {
3920 match self {
3921 Self::InProject(path) => path.path.file_name(),
3922 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3923 }
3924 }
3925}
3926
3927impl LspStore {
3928 pub fn init(client: &AnyProtoClient) {
3929 client.add_entity_request_handler(Self::handle_lsp_query);
3930 client.add_entity_message_handler(Self::handle_lsp_query_response);
3931 client.add_entity_request_handler(Self::handle_restart_language_servers);
3932 client.add_entity_request_handler(Self::handle_stop_language_servers);
3933 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3934 client.add_entity_message_handler(Self::handle_start_language_server);
3935 client.add_entity_message_handler(Self::handle_update_language_server);
3936 client.add_entity_message_handler(Self::handle_language_server_log);
3937 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3938 client.add_entity_request_handler(Self::handle_format_buffers);
3939 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3940 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3941 client.add_entity_request_handler(Self::handle_apply_code_action);
3942 client.add_entity_request_handler(Self::handle_get_project_symbols);
3943 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3944 client.add_entity_request_handler(Self::handle_get_color_presentation);
3945 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3946 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3947 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3948 client.add_entity_request_handler(Self::handle_on_type_formatting);
3949 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3950 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3951 client.add_entity_request_handler(Self::handle_rename_project_entry);
3952 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3953 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3954 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3955 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3956 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3957 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3958 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3959
3960 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3961 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3962 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3963 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3964 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3965 client.add_entity_request_handler(
3966 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3967 );
3968 client.add_entity_request_handler(
3969 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3970 );
3971 client.add_entity_request_handler(
3972 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3973 );
3974 }
3975
3976 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3977 match &self.mode {
3978 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3979 _ => None,
3980 }
3981 }
3982
3983 pub fn as_local(&self) -> Option<&LocalLspStore> {
3984 match &self.mode {
3985 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3986 _ => None,
3987 }
3988 }
3989
3990 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3991 match &mut self.mode {
3992 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3993 _ => None,
3994 }
3995 }
3996
3997 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3998 match &self.mode {
3999 LspStoreMode::Remote(RemoteLspStore {
4000 upstream_client: Some(upstream_client),
4001 upstream_project_id,
4002 ..
4003 }) => Some((upstream_client.clone(), *upstream_project_id)),
4004
4005 LspStoreMode::Remote(RemoteLspStore {
4006 upstream_client: None,
4007 ..
4008 }) => None,
4009 LspStoreMode::Local(_) => None,
4010 }
4011 }
4012
4013 pub fn new_local(
4014 buffer_store: Entity<BufferStore>,
4015 worktree_store: Entity<WorktreeStore>,
4016 prettier_store: Entity<PrettierStore>,
4017 toolchain_store: Entity<LocalToolchainStore>,
4018 environment: Entity<ProjectEnvironment>,
4019 manifest_tree: Entity<ManifestTree>,
4020 languages: Arc<LanguageRegistry>,
4021 http_client: Arc<dyn HttpClient>,
4022 fs: Arc<dyn Fs>,
4023 cx: &mut Context<Self>,
4024 ) -> Self {
4025 let yarn = YarnPathStore::new(fs.clone(), cx);
4026 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4027 .detach();
4028 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4029 .detach();
4030 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4031 .detach();
4032 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4033 .detach();
4034 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4035 .detach();
4036 subscribe_to_binary_statuses(&languages, cx).detach();
4037
4038 let _maintain_workspace_config = {
4039 let (sender, receiver) = watch::channel();
4040 (Self::maintain_workspace_config(receiver, cx), sender)
4041 };
4042
4043 Self {
4044 mode: LspStoreMode::Local(LocalLspStore {
4045 weak: cx.weak_entity(),
4046 worktree_store: worktree_store.clone(),
4047
4048 supplementary_language_servers: Default::default(),
4049 languages: languages.clone(),
4050 language_server_ids: Default::default(),
4051 language_servers: Default::default(),
4052 last_workspace_edits_by_language_server: Default::default(),
4053 language_server_watched_paths: Default::default(),
4054 language_server_paths_watched_for_rename: Default::default(),
4055 language_server_dynamic_registrations: Default::default(),
4056 buffers_being_formatted: Default::default(),
4057 buffer_snapshots: Default::default(),
4058 prettier_store,
4059 environment,
4060 http_client,
4061 fs,
4062 yarn,
4063 next_diagnostic_group_id: Default::default(),
4064 diagnostics: Default::default(),
4065 _subscription: cx.on_app_quit(|this, cx| {
4066 this.as_local_mut()
4067 .unwrap()
4068 .shutdown_language_servers_on_quit(cx)
4069 }),
4070 lsp_tree: LanguageServerTree::new(
4071 manifest_tree,
4072 languages.clone(),
4073 toolchain_store.clone(),
4074 ),
4075 toolchain_store,
4076 registered_buffers: HashMap::default(),
4077 buffers_opened_in_servers: HashMap::default(),
4078 buffer_pull_diagnostics_result_ids: HashMap::default(),
4079 workspace_pull_diagnostics_result_ids: HashMap::default(),
4080 restricted_worktrees_tasks: HashMap::default(),
4081 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4082 .manifest_file_names(),
4083 }),
4084 last_formatting_failure: None,
4085 downstream_client: None,
4086 buffer_store,
4087 worktree_store,
4088 languages: languages.clone(),
4089 language_server_statuses: Default::default(),
4090 nonce: StdRng::from_os_rng().random(),
4091 diagnostic_summaries: HashMap::default(),
4092 lsp_server_capabilities: HashMap::default(),
4093 lsp_data: HashMap::default(),
4094 next_hint_id: Arc::default(),
4095 active_entry: None,
4096 _maintain_workspace_config,
4097 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4098 }
4099 }
4100
4101 fn send_lsp_proto_request<R: LspCommand>(
4102 &self,
4103 buffer: Entity<Buffer>,
4104 client: AnyProtoClient,
4105 upstream_project_id: u64,
4106 request: R,
4107 cx: &mut Context<LspStore>,
4108 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4109 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4110 return Task::ready(Ok(R::Response::default()));
4111 }
4112 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4113 cx.spawn(async move |this, cx| {
4114 let response = client.request(message).await?;
4115 let this = this.upgrade().context("project dropped")?;
4116 request
4117 .response_from_proto(response, this, buffer, cx.clone())
4118 .await
4119 })
4120 }
4121
4122 pub(super) fn new_remote(
4123 buffer_store: Entity<BufferStore>,
4124 worktree_store: Entity<WorktreeStore>,
4125 languages: Arc<LanguageRegistry>,
4126 upstream_client: AnyProtoClient,
4127 project_id: u64,
4128 cx: &mut Context<Self>,
4129 ) -> Self {
4130 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4131 .detach();
4132 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4133 .detach();
4134 subscribe_to_binary_statuses(&languages, cx).detach();
4135 let _maintain_workspace_config = {
4136 let (sender, receiver) = watch::channel();
4137 (Self::maintain_workspace_config(receiver, cx), sender)
4138 };
4139 Self {
4140 mode: LspStoreMode::Remote(RemoteLspStore {
4141 upstream_client: Some(upstream_client),
4142 upstream_project_id: project_id,
4143 }),
4144 downstream_client: None,
4145 last_formatting_failure: None,
4146 buffer_store,
4147 worktree_store,
4148 languages: languages.clone(),
4149 language_server_statuses: Default::default(),
4150 nonce: StdRng::from_os_rng().random(),
4151 diagnostic_summaries: HashMap::default(),
4152 lsp_server_capabilities: HashMap::default(),
4153 next_hint_id: Arc::default(),
4154 lsp_data: HashMap::default(),
4155 active_entry: None,
4156
4157 _maintain_workspace_config,
4158 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4159 }
4160 }
4161
4162 fn on_buffer_store_event(
4163 &mut self,
4164 _: Entity<BufferStore>,
4165 event: &BufferStoreEvent,
4166 cx: &mut Context<Self>,
4167 ) {
4168 match event {
4169 BufferStoreEvent::BufferAdded(buffer) => {
4170 self.on_buffer_added(buffer, cx).log_err();
4171 }
4172 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4173 let buffer_id = buffer.read(cx).remote_id();
4174 if let Some(local) = self.as_local_mut()
4175 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4176 {
4177 local.reset_buffer(buffer, old_file, cx);
4178
4179 if local.registered_buffers.contains_key(&buffer_id) {
4180 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4181 }
4182 }
4183
4184 self.detect_language_for_buffer(buffer, cx);
4185 if let Some(local) = self.as_local_mut() {
4186 local.initialize_buffer(buffer, cx);
4187 if local.registered_buffers.contains_key(&buffer_id) {
4188 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4189 }
4190 }
4191 }
4192 _ => {}
4193 }
4194 }
4195
4196 fn on_worktree_store_event(
4197 &mut self,
4198 _: Entity<WorktreeStore>,
4199 event: &WorktreeStoreEvent,
4200 cx: &mut Context<Self>,
4201 ) {
4202 match event {
4203 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4204 if !worktree.read(cx).is_local() {
4205 return;
4206 }
4207 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4208 worktree::Event::UpdatedEntries(changes) => {
4209 this.update_local_worktree_language_servers(&worktree, changes, cx);
4210 }
4211 worktree::Event::UpdatedGitRepositories(_)
4212 | worktree::Event::DeletedEntry(_) => {}
4213 })
4214 .detach()
4215 }
4216 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4217 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4218 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4219 }
4220 WorktreeStoreEvent::WorktreeReleased(..)
4221 | WorktreeStoreEvent::WorktreeOrderChanged
4222 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4223 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4224 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4225 }
4226 }
4227
4228 fn on_prettier_store_event(
4229 &mut self,
4230 _: Entity<PrettierStore>,
4231 event: &PrettierStoreEvent,
4232 cx: &mut Context<Self>,
4233 ) {
4234 match event {
4235 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4236 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4237 }
4238 PrettierStoreEvent::LanguageServerAdded {
4239 new_server_id,
4240 name,
4241 prettier_server,
4242 } => {
4243 self.register_supplementary_language_server(
4244 *new_server_id,
4245 name.clone(),
4246 prettier_server.clone(),
4247 cx,
4248 );
4249 }
4250 }
4251 }
4252
4253 fn on_toolchain_store_event(
4254 &mut self,
4255 _: Entity<LocalToolchainStore>,
4256 event: &ToolchainStoreEvent,
4257 _: &mut Context<Self>,
4258 ) {
4259 if let ToolchainStoreEvent::ToolchainActivated = event {
4260 self.request_workspace_config_refresh()
4261 }
4262 }
4263
4264 fn request_workspace_config_refresh(&mut self) {
4265 *self._maintain_workspace_config.1.borrow_mut() = ();
4266 }
4267
4268 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4269 self.as_local().map(|local| local.prettier_store.clone())
4270 }
4271
4272 fn on_buffer_event(
4273 &mut self,
4274 buffer: Entity<Buffer>,
4275 event: &language::BufferEvent,
4276 cx: &mut Context<Self>,
4277 ) {
4278 match event {
4279 language::BufferEvent::Edited => {
4280 self.on_buffer_edited(buffer, cx);
4281 }
4282
4283 language::BufferEvent::Saved => {
4284 self.on_buffer_saved(buffer, cx);
4285 }
4286
4287 _ => {}
4288 }
4289 }
4290
4291 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4292 buffer
4293 .read(cx)
4294 .set_language_registry(self.languages.clone());
4295
4296 cx.subscribe(buffer, |this, buffer, event, cx| {
4297 this.on_buffer_event(buffer, event, cx);
4298 })
4299 .detach();
4300
4301 self.detect_language_for_buffer(buffer, cx);
4302 if let Some(local) = self.as_local_mut() {
4303 local.initialize_buffer(buffer, cx);
4304 }
4305
4306 Ok(())
4307 }
4308
4309 pub(crate) fn register_buffer_with_language_servers(
4310 &mut self,
4311 buffer: &Entity<Buffer>,
4312 only_register_servers: HashSet<LanguageServerSelector>,
4313 ignore_refcounts: bool,
4314 cx: &mut Context<Self>,
4315 ) -> OpenLspBufferHandle {
4316 let buffer_id = buffer.read(cx).remote_id();
4317 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4318 if let Some(local) = self.as_local_mut() {
4319 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4320 if !ignore_refcounts {
4321 *refcount += 1;
4322 }
4323
4324 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4325 // 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
4326 // 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
4327 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4328 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4329 return handle;
4330 };
4331 if !file.is_local() {
4332 return handle;
4333 }
4334
4335 if ignore_refcounts || *refcount == 1 {
4336 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4337 }
4338 if !ignore_refcounts {
4339 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4340 let refcount = {
4341 let local = lsp_store.as_local_mut().unwrap();
4342 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4343 debug_panic!("bad refcounting");
4344 return;
4345 };
4346
4347 *refcount -= 1;
4348 *refcount
4349 };
4350 if refcount == 0 {
4351 lsp_store.lsp_data.remove(&buffer_id);
4352 let local = lsp_store.as_local_mut().unwrap();
4353 local.registered_buffers.remove(&buffer_id);
4354
4355 local.buffers_opened_in_servers.remove(&buffer_id);
4356 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4357 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4358
4359 let buffer_abs_path = file.abs_path(cx);
4360 for (_, buffer_pull_diagnostics_result_ids) in
4361 &mut local.buffer_pull_diagnostics_result_ids
4362 {
4363 buffer_pull_diagnostics_result_ids.retain(
4364 |_, buffer_result_ids| {
4365 buffer_result_ids.remove(&buffer_abs_path);
4366 !buffer_result_ids.is_empty()
4367 },
4368 );
4369 }
4370
4371 let diagnostic_updates = local
4372 .language_servers
4373 .keys()
4374 .cloned()
4375 .map(|server_id| DocumentDiagnosticsUpdate {
4376 diagnostics: DocumentDiagnostics {
4377 document_abs_path: buffer_abs_path.clone(),
4378 version: None,
4379 diagnostics: Vec::new(),
4380 },
4381 result_id: None,
4382 registration_id: None,
4383 server_id: server_id,
4384 disk_based_sources: Cow::Borrowed(&[]),
4385 })
4386 .collect::<Vec<_>>();
4387
4388 lsp_store
4389 .merge_diagnostic_entries(
4390 diagnostic_updates,
4391 |_, diagnostic, _| {
4392 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4393 },
4394 cx,
4395 )
4396 .context("Clearing diagnostics for the closed buffer")
4397 .log_err();
4398 }
4399 }
4400 })
4401 .detach();
4402 }
4403 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4404 let buffer_id = buffer.read(cx).remote_id().to_proto();
4405 cx.background_spawn(async move {
4406 upstream_client
4407 .request(proto::RegisterBufferWithLanguageServers {
4408 project_id: upstream_project_id,
4409 buffer_id,
4410 only_servers: only_register_servers
4411 .into_iter()
4412 .map(|selector| {
4413 let selector = match selector {
4414 LanguageServerSelector::Id(language_server_id) => {
4415 proto::language_server_selector::Selector::ServerId(
4416 language_server_id.to_proto(),
4417 )
4418 }
4419 LanguageServerSelector::Name(language_server_name) => {
4420 proto::language_server_selector::Selector::Name(
4421 language_server_name.to_string(),
4422 )
4423 }
4424 };
4425 proto::LanguageServerSelector {
4426 selector: Some(selector),
4427 }
4428 })
4429 .collect(),
4430 })
4431 .await
4432 })
4433 .detach();
4434 } else {
4435 // Our remote connection got closed
4436 }
4437 handle
4438 }
4439
4440 fn maintain_buffer_languages(
4441 languages: Arc<LanguageRegistry>,
4442 cx: &mut Context<Self>,
4443 ) -> Task<()> {
4444 let mut subscription = languages.subscribe();
4445 let mut prev_reload_count = languages.reload_count();
4446 cx.spawn(async move |this, cx| {
4447 while let Some(()) = subscription.next().await {
4448 if let Some(this) = this.upgrade() {
4449 // If the language registry has been reloaded, then remove and
4450 // re-assign the languages on all open buffers.
4451 let reload_count = languages.reload_count();
4452 if reload_count > prev_reload_count {
4453 prev_reload_count = reload_count;
4454 this.update(cx, |this, cx| {
4455 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4456 for buffer in buffer_store.buffers() {
4457 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4458 {
4459 buffer.update(cx, |buffer, cx| {
4460 buffer.set_language_async(None, cx)
4461 });
4462 if let Some(local) = this.as_local_mut() {
4463 local.reset_buffer(&buffer, &f, cx);
4464
4465 if local
4466 .registered_buffers
4467 .contains_key(&buffer.read(cx).remote_id())
4468 && let Some(file_url) =
4469 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4470 {
4471 local.unregister_buffer_from_language_servers(
4472 &buffer, &file_url, cx,
4473 );
4474 }
4475 }
4476 }
4477 }
4478 });
4479 });
4480 }
4481
4482 this.update(cx, |this, cx| {
4483 let mut plain_text_buffers = Vec::new();
4484 let mut buffers_with_unknown_injections = Vec::new();
4485 for handle in this.buffer_store.read(cx).buffers() {
4486 let buffer = handle.read(cx);
4487 if buffer.language().is_none()
4488 || buffer.language() == Some(&*language::PLAIN_TEXT)
4489 {
4490 plain_text_buffers.push(handle);
4491 } else if buffer.contains_unknown_injections() {
4492 buffers_with_unknown_injections.push(handle);
4493 }
4494 }
4495
4496 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4497 // and reused later in the invisible worktrees.
4498 plain_text_buffers.sort_by_key(|buffer| {
4499 Reverse(
4500 File::from_dyn(buffer.read(cx).file())
4501 .map(|file| file.worktree.read(cx).is_visible()),
4502 )
4503 });
4504
4505 for buffer in plain_text_buffers {
4506 this.detect_language_for_buffer(&buffer, cx);
4507 if let Some(local) = this.as_local_mut() {
4508 local.initialize_buffer(&buffer, cx);
4509 if local
4510 .registered_buffers
4511 .contains_key(&buffer.read(cx).remote_id())
4512 {
4513 local.register_buffer_with_language_servers(
4514 &buffer,
4515 HashSet::default(),
4516 cx,
4517 );
4518 }
4519 }
4520 }
4521
4522 for buffer in buffers_with_unknown_injections {
4523 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4524 }
4525 });
4526 }
4527 }
4528 })
4529 }
4530
4531 fn detect_language_for_buffer(
4532 &mut self,
4533 buffer_handle: &Entity<Buffer>,
4534 cx: &mut Context<Self>,
4535 ) -> Option<language::AvailableLanguage> {
4536 // If the buffer has a language, set it and start the language server if we haven't already.
4537 let buffer = buffer_handle.read(cx);
4538 let file = buffer.file()?;
4539
4540 let content = buffer.as_rope();
4541 let available_language = self.languages.language_for_file(file, Some(content), cx);
4542 if let Some(available_language) = &available_language {
4543 if let Some(Ok(Ok(new_language))) = self
4544 .languages
4545 .load_language(available_language)
4546 .now_or_never()
4547 {
4548 self.set_language_for_buffer(buffer_handle, new_language, cx);
4549 }
4550 } else {
4551 cx.emit(LspStoreEvent::LanguageDetected {
4552 buffer: buffer_handle.clone(),
4553 new_language: None,
4554 });
4555 }
4556
4557 available_language
4558 }
4559
4560 pub(crate) fn set_language_for_buffer(
4561 &mut self,
4562 buffer_entity: &Entity<Buffer>,
4563 new_language: Arc<Language>,
4564 cx: &mut Context<Self>,
4565 ) {
4566 let buffer = buffer_entity.read(cx);
4567 let buffer_file = buffer.file().cloned();
4568 let buffer_id = buffer.remote_id();
4569 if let Some(local_store) = self.as_local_mut()
4570 && local_store.registered_buffers.contains_key(&buffer_id)
4571 && let Some(abs_path) =
4572 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4573 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4574 {
4575 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4576 }
4577 buffer_entity.update(cx, |buffer, cx| {
4578 if buffer
4579 .language()
4580 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4581 {
4582 buffer.set_language_async(Some(new_language.clone()), cx);
4583 }
4584 });
4585
4586 let settings =
4587 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4588 let buffer_file = File::from_dyn(buffer_file.as_ref());
4589
4590 let worktree_id = if let Some(file) = buffer_file {
4591 let worktree = file.worktree.clone();
4592
4593 if let Some(local) = self.as_local_mut()
4594 && local.registered_buffers.contains_key(&buffer_id)
4595 {
4596 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4597 }
4598 Some(worktree.read(cx).id())
4599 } else {
4600 None
4601 };
4602
4603 if settings.prettier.allowed
4604 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4605 {
4606 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4607 if let Some(prettier_store) = prettier_store {
4608 prettier_store.update(cx, |prettier_store, cx| {
4609 prettier_store.install_default_prettier(
4610 worktree_id,
4611 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4612 cx,
4613 )
4614 })
4615 }
4616 }
4617
4618 cx.emit(LspStoreEvent::LanguageDetected {
4619 buffer: buffer_entity.clone(),
4620 new_language: Some(new_language),
4621 })
4622 }
4623
4624 pub fn buffer_store(&self) -> Entity<BufferStore> {
4625 self.buffer_store.clone()
4626 }
4627
4628 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4629 self.active_entry = active_entry;
4630 }
4631
4632 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4633 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4634 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4635 {
4636 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4637 summaries
4638 .iter()
4639 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4640 });
4641 if let Some(summary) = summaries.next() {
4642 client
4643 .send(proto::UpdateDiagnosticSummary {
4644 project_id: downstream_project_id,
4645 worktree_id: worktree.id().to_proto(),
4646 summary: Some(summary),
4647 more_summaries: summaries.collect(),
4648 })
4649 .log_err();
4650 }
4651 }
4652 }
4653
4654 fn is_capable_for_proto_request<R>(
4655 &self,
4656 buffer: &Entity<Buffer>,
4657 request: &R,
4658 cx: &App,
4659 ) -> bool
4660 where
4661 R: LspCommand,
4662 {
4663 self.check_if_capable_for_proto_request(
4664 buffer,
4665 |capabilities| {
4666 request.check_capabilities(AdapterServerCapabilities {
4667 server_capabilities: capabilities.clone(),
4668 code_action_kinds: None,
4669 })
4670 },
4671 cx,
4672 )
4673 }
4674
4675 fn check_if_capable_for_proto_request<F>(
4676 &self,
4677 buffer: &Entity<Buffer>,
4678 check: F,
4679 cx: &App,
4680 ) -> bool
4681 where
4682 F: FnMut(&lsp::ServerCapabilities) -> bool,
4683 {
4684 let Some(language) = buffer.read(cx).language().cloned() else {
4685 return false;
4686 };
4687 let registered_language_servers = self
4688 .languages
4689 .lsp_adapters(&language.name())
4690 .into_iter()
4691 .map(|lsp_adapter| lsp_adapter.name())
4692 .collect::<HashSet<_>>();
4693 self.language_server_statuses
4694 .iter()
4695 .filter_map(|(server_id, server_status)| {
4696 // Include servers that are either registered for this language OR
4697 // available to be loaded (for SSH remote mode where adapters like
4698 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4699 // but only loaded on the server side)
4700 let is_relevant = registered_language_servers.contains(&server_status.name)
4701 || self.languages.is_lsp_adapter_available(&server_status.name);
4702 is_relevant.then_some(server_id)
4703 })
4704 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4705 .any(check)
4706 }
4707
4708 fn all_capable_for_proto_request<F>(
4709 &self,
4710 buffer: &Entity<Buffer>,
4711 mut check: F,
4712 cx: &App,
4713 ) -> Vec<lsp::LanguageServerId>
4714 where
4715 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4716 {
4717 let Some(language) = buffer.read(cx).language().cloned() else {
4718 return Vec::default();
4719 };
4720 let registered_language_servers = self
4721 .languages
4722 .lsp_adapters(&language.name())
4723 .into_iter()
4724 .map(|lsp_adapter| lsp_adapter.name())
4725 .collect::<HashSet<_>>();
4726 self.language_server_statuses
4727 .iter()
4728 .filter_map(|(server_id, server_status)| {
4729 // Include servers that are either registered for this language OR
4730 // available to be loaded (for SSH remote mode where adapters like
4731 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4732 // but only loaded on the server side)
4733 let is_relevant = registered_language_servers.contains(&server_status.name)
4734 || self.languages.is_lsp_adapter_available(&server_status.name);
4735 is_relevant.then_some((server_id, &server_status.name))
4736 })
4737 .filter_map(|(server_id, server_name)| {
4738 self.lsp_server_capabilities
4739 .get(server_id)
4740 .map(|c| (server_id, server_name, c))
4741 })
4742 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4743 .map(|(server_id, _, _)| *server_id)
4744 .collect()
4745 }
4746
4747 pub fn request_lsp<R>(
4748 &mut self,
4749 buffer: Entity<Buffer>,
4750 server: LanguageServerToQuery,
4751 request: R,
4752 cx: &mut Context<Self>,
4753 ) -> Task<Result<R::Response>>
4754 where
4755 R: LspCommand,
4756 <R::LspRequest as lsp::request::Request>::Result: Send,
4757 <R::LspRequest as lsp::request::Request>::Params: Send,
4758 {
4759 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4760 return self.send_lsp_proto_request(
4761 buffer,
4762 upstream_client,
4763 upstream_project_id,
4764 request,
4765 cx,
4766 );
4767 }
4768
4769 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4770 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4771 local
4772 .language_servers_for_buffer(buffer, cx)
4773 .find(|(_, server)| {
4774 request.check_capabilities(server.adapter_server_capabilities())
4775 })
4776 .map(|(_, server)| server.clone())
4777 }),
4778 LanguageServerToQuery::Other(id) => self
4779 .language_server_for_local_buffer(buffer, id, cx)
4780 .and_then(|(_, server)| {
4781 request
4782 .check_capabilities(server.adapter_server_capabilities())
4783 .then(|| Arc::clone(server))
4784 }),
4785 }) else {
4786 return Task::ready(Ok(Default::default()));
4787 };
4788
4789 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4790
4791 let Some(file) = file else {
4792 return Task::ready(Ok(Default::default()));
4793 };
4794
4795 let lsp_params = match request.to_lsp_params_or_response(
4796 &file.abs_path(cx),
4797 buffer.read(cx),
4798 &language_server,
4799 cx,
4800 ) {
4801 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4802 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4803 Err(err) => {
4804 let message = format!(
4805 "{} via {} failed: {}",
4806 request.display_name(),
4807 language_server.name(),
4808 err
4809 );
4810 // rust-analyzer likes to error with this when its still loading up
4811 if !message.ends_with("content modified") {
4812 log::warn!("{message}");
4813 }
4814 return Task::ready(Err(anyhow!(message)));
4815 }
4816 };
4817
4818 let status = request.status();
4819 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4820 return Task::ready(Ok(Default::default()));
4821 }
4822 cx.spawn(async move |this, cx| {
4823 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4824
4825 let id = lsp_request.id();
4826 let _cleanup = if status.is_some() {
4827 cx.update(|cx| {
4828 this.update(cx, |this, cx| {
4829 this.on_lsp_work_start(
4830 language_server.server_id(),
4831 ProgressToken::Number(id),
4832 LanguageServerProgress {
4833 is_disk_based_diagnostics_progress: false,
4834 is_cancellable: false,
4835 title: None,
4836 message: status.clone(),
4837 percentage: None,
4838 last_update_at: cx.background_executor().now(),
4839 },
4840 cx,
4841 );
4842 })
4843 })
4844 .log_err();
4845
4846 Some(defer(|| {
4847 cx.update(|cx| {
4848 this.update(cx, |this, cx| {
4849 this.on_lsp_work_end(
4850 language_server.server_id(),
4851 ProgressToken::Number(id),
4852 cx,
4853 );
4854 })
4855 })
4856 .log_err();
4857 }))
4858 } else {
4859 None
4860 };
4861
4862 let result = lsp_request.await.into_response();
4863
4864 let response = result.map_err(|err| {
4865 let message = format!(
4866 "{} via {} failed: {}",
4867 request.display_name(),
4868 language_server.name(),
4869 err
4870 );
4871 // rust-analyzer likes to error with this when its still loading up
4872 if !message.ends_with("content modified") {
4873 log::warn!("{message}");
4874 }
4875 anyhow::anyhow!(message)
4876 })?;
4877
4878 request
4879 .response_from_lsp(
4880 response,
4881 this.upgrade().context("no app context")?,
4882 buffer,
4883 language_server.server_id(),
4884 cx.clone(),
4885 )
4886 .await
4887 })
4888 }
4889
4890 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4891 let mut language_formatters_to_check = Vec::new();
4892 for buffer in self.buffer_store.read(cx).buffers() {
4893 let buffer = buffer.read(cx);
4894 let buffer_file = File::from_dyn(buffer.file());
4895 let buffer_language = buffer.language();
4896 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4897 if buffer_language.is_some() {
4898 language_formatters_to_check.push((
4899 buffer_file.map(|f| f.worktree_id(cx)),
4900 settings.into_owned(),
4901 ));
4902 }
4903 }
4904
4905 self.request_workspace_config_refresh();
4906
4907 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4908 prettier_store.update(cx, |prettier_store, cx| {
4909 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4910 })
4911 }
4912
4913 cx.notify();
4914 }
4915
4916 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4917 let buffer_store = self.buffer_store.clone();
4918 let Some(local) = self.as_local_mut() else {
4919 return;
4920 };
4921 let mut adapters = BTreeMap::default();
4922 let get_adapter = {
4923 let languages = local.languages.clone();
4924 let environment = local.environment.clone();
4925 let weak = local.weak.clone();
4926 let worktree_store = local.worktree_store.clone();
4927 let http_client = local.http_client.clone();
4928 let fs = local.fs.clone();
4929 move |worktree_id, cx: &mut App| {
4930 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4931 Some(LocalLspAdapterDelegate::new(
4932 languages.clone(),
4933 &environment,
4934 weak.clone(),
4935 &worktree,
4936 http_client.clone(),
4937 fs.clone(),
4938 cx,
4939 ))
4940 }
4941 };
4942
4943 let mut messages_to_report = Vec::new();
4944 let (new_tree, to_stop) = {
4945 let mut rebase = local.lsp_tree.rebase();
4946 let buffers = buffer_store
4947 .read(cx)
4948 .buffers()
4949 .filter_map(|buffer| {
4950 let raw_buffer = buffer.read(cx);
4951 if !local
4952 .registered_buffers
4953 .contains_key(&raw_buffer.remote_id())
4954 {
4955 return None;
4956 }
4957 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4958 let language = raw_buffer.language().cloned()?;
4959 Some((file, language, raw_buffer.remote_id()))
4960 })
4961 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4962 for (file, language, buffer_id) in buffers {
4963 let worktree_id = file.worktree_id(cx);
4964 let Some(worktree) = local
4965 .worktree_store
4966 .read(cx)
4967 .worktree_for_id(worktree_id, cx)
4968 else {
4969 continue;
4970 };
4971
4972 if let Some((_, apply)) = local.reuse_existing_language_server(
4973 rebase.server_tree(),
4974 &worktree,
4975 &language.name(),
4976 cx,
4977 ) {
4978 (apply)(rebase.server_tree());
4979 } else if let Some(lsp_delegate) = adapters
4980 .entry(worktree_id)
4981 .or_insert_with(|| get_adapter(worktree_id, cx))
4982 .clone()
4983 {
4984 let delegate =
4985 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4986 let path = file
4987 .path()
4988 .parent()
4989 .map(Arc::from)
4990 .unwrap_or_else(|| file.path().clone());
4991 let worktree_path = ProjectPath { worktree_id, path };
4992 let abs_path = file.abs_path(cx);
4993 let nodes = rebase
4994 .walk(
4995 worktree_path,
4996 language.name(),
4997 language.manifest(),
4998 delegate.clone(),
4999 cx,
5000 )
5001 .collect::<Vec<_>>();
5002 for node in nodes {
5003 let server_id = node.server_id_or_init(|disposition| {
5004 let path = &disposition.path;
5005 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5006 let key = LanguageServerSeed {
5007 worktree_id,
5008 name: disposition.server_name.clone(),
5009 settings: disposition.settings.clone(),
5010 toolchain: local.toolchain_store.read(cx).active_toolchain(
5011 path.worktree_id,
5012 &path.path,
5013 language.name(),
5014 ),
5015 };
5016 local.language_server_ids.remove(&key);
5017
5018 let server_id = local.get_or_insert_language_server(
5019 &worktree,
5020 lsp_delegate.clone(),
5021 disposition,
5022 &language.name(),
5023 cx,
5024 );
5025 if let Some(state) = local.language_servers.get(&server_id)
5026 && let Ok(uri) = uri
5027 {
5028 state.add_workspace_folder(uri);
5029 };
5030 server_id
5031 });
5032
5033 if let Some(language_server_id) = server_id {
5034 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5035 language_server_id,
5036 name: node.name(),
5037 message:
5038 proto::update_language_server::Variant::RegisteredForBuffer(
5039 proto::RegisteredForBuffer {
5040 buffer_abs_path: abs_path
5041 .to_string_lossy()
5042 .into_owned(),
5043 buffer_id: buffer_id.to_proto(),
5044 },
5045 ),
5046 });
5047 }
5048 }
5049 } else {
5050 continue;
5051 }
5052 }
5053 rebase.finish()
5054 };
5055 for message in messages_to_report {
5056 cx.emit(message);
5057 }
5058 local.lsp_tree = new_tree;
5059 for (id, _) in to_stop {
5060 self.stop_local_language_server(id, cx).detach();
5061 }
5062 }
5063
5064 pub fn apply_code_action(
5065 &self,
5066 buffer_handle: Entity<Buffer>,
5067 mut action: CodeAction,
5068 push_to_history: bool,
5069 cx: &mut Context<Self>,
5070 ) -> Task<Result<ProjectTransaction>> {
5071 if let Some((upstream_client, project_id)) = self.upstream_client() {
5072 let request = proto::ApplyCodeAction {
5073 project_id,
5074 buffer_id: buffer_handle.read(cx).remote_id().into(),
5075 action: Some(Self::serialize_code_action(&action)),
5076 };
5077 let buffer_store = self.buffer_store();
5078 cx.spawn(async move |_, cx| {
5079 let response = upstream_client
5080 .request(request)
5081 .await?
5082 .transaction
5083 .context("missing transaction")?;
5084
5085 buffer_store
5086 .update(cx, |buffer_store, cx| {
5087 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5088 })
5089 .await
5090 })
5091 } else if self.mode.is_local() {
5092 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5093 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5094 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5095 }) else {
5096 return Task::ready(Ok(ProjectTransaction::default()));
5097 };
5098 cx.spawn(async move |this, cx| {
5099 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5100 .await
5101 .context("resolving a code action")?;
5102 if let Some(edit) = action.lsp_action.edit()
5103 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5104 return LocalLspStore::deserialize_workspace_edit(
5105 this.upgrade().context("no app present")?,
5106 edit.clone(),
5107 push_to_history,
5108
5109 lang_server.clone(),
5110 cx,
5111 )
5112 .await;
5113 }
5114
5115 if let Some(command) = action.lsp_action.command() {
5116 let server_capabilities = lang_server.capabilities();
5117 let available_commands = server_capabilities
5118 .execute_command_provider
5119 .as_ref()
5120 .map(|options| options.commands.as_slice())
5121 .unwrap_or_default();
5122 if available_commands.contains(&command.command) {
5123 this.update(cx, |this, _| {
5124 this.as_local_mut()
5125 .unwrap()
5126 .last_workspace_edits_by_language_server
5127 .remove(&lang_server.server_id());
5128 })?;
5129
5130 let _result = lang_server
5131 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5132 command: command.command.clone(),
5133 arguments: command.arguments.clone().unwrap_or_default(),
5134 ..lsp::ExecuteCommandParams::default()
5135 })
5136 .await.into_response()
5137 .context("execute command")?;
5138
5139 return this.update(cx, |this, _| {
5140 this.as_local_mut()
5141 .unwrap()
5142 .last_workspace_edits_by_language_server
5143 .remove(&lang_server.server_id())
5144 .unwrap_or_default()
5145 });
5146 } else {
5147 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5148 }
5149 }
5150
5151 Ok(ProjectTransaction::default())
5152 })
5153 } else {
5154 Task::ready(Err(anyhow!("no upstream client and not local")))
5155 }
5156 }
5157
5158 pub fn apply_code_action_kind(
5159 &mut self,
5160 buffers: HashSet<Entity<Buffer>>,
5161 kind: CodeActionKind,
5162 push_to_history: bool,
5163 cx: &mut Context<Self>,
5164 ) -> Task<anyhow::Result<ProjectTransaction>> {
5165 if self.as_local().is_some() {
5166 cx.spawn(async move |lsp_store, cx| {
5167 let buffers = buffers.into_iter().collect::<Vec<_>>();
5168 let result = LocalLspStore::execute_code_action_kind_locally(
5169 lsp_store.clone(),
5170 buffers,
5171 kind,
5172 push_to_history,
5173 cx,
5174 )
5175 .await;
5176 lsp_store.update(cx, |lsp_store, _| {
5177 lsp_store.update_last_formatting_failure(&result);
5178 })?;
5179 result
5180 })
5181 } else if let Some((client, project_id)) = self.upstream_client() {
5182 let buffer_store = self.buffer_store();
5183 cx.spawn(async move |lsp_store, cx| {
5184 let result = client
5185 .request(proto::ApplyCodeActionKind {
5186 project_id,
5187 kind: kind.as_str().to_owned(),
5188 buffer_ids: buffers
5189 .iter()
5190 .map(|buffer| {
5191 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5192 })
5193 .collect(),
5194 })
5195 .await
5196 .and_then(|result| result.transaction.context("missing transaction"));
5197 lsp_store.update(cx, |lsp_store, _| {
5198 lsp_store.update_last_formatting_failure(&result);
5199 })?;
5200
5201 let transaction_response = result?;
5202 buffer_store
5203 .update(cx, |buffer_store, cx| {
5204 buffer_store.deserialize_project_transaction(
5205 transaction_response,
5206 push_to_history,
5207 cx,
5208 )
5209 })
5210 .await
5211 })
5212 } else {
5213 Task::ready(Ok(ProjectTransaction::default()))
5214 }
5215 }
5216
5217 pub fn resolved_hint(
5218 &mut self,
5219 buffer_id: BufferId,
5220 id: InlayId,
5221 cx: &mut Context<Self>,
5222 ) -> Option<ResolvedHint> {
5223 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5224
5225 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5226 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5227 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5228 let (server_id, resolve_data) = match &hint.resolve_state {
5229 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5230 ResolveState::Resolving => {
5231 return Some(ResolvedHint::Resolving(
5232 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5233 ));
5234 }
5235 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5236 };
5237
5238 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5239 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5240 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5241 id,
5242 cx.spawn(async move |lsp_store, cx| {
5243 let resolved_hint = resolve_task.await;
5244 lsp_store
5245 .update(cx, |lsp_store, _| {
5246 if let Some(old_inlay_hint) = lsp_store
5247 .lsp_data
5248 .get_mut(&buffer_id)
5249 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5250 {
5251 match resolved_hint {
5252 Ok(resolved_hint) => {
5253 *old_inlay_hint = resolved_hint;
5254 }
5255 Err(e) => {
5256 old_inlay_hint.resolve_state =
5257 ResolveState::CanResolve(server_id, resolve_data);
5258 log::error!("Inlay hint resolve failed: {e:#}");
5259 }
5260 }
5261 }
5262 })
5263 .ok();
5264 })
5265 .shared(),
5266 );
5267 debug_assert!(
5268 previous_task.is_none(),
5269 "Did not change hint's resolve state after spawning its resolve"
5270 );
5271 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5272 None
5273 }
5274
5275 fn resolve_inlay_hint(
5276 &self,
5277 mut hint: InlayHint,
5278 buffer: Entity<Buffer>,
5279 server_id: LanguageServerId,
5280 cx: &mut Context<Self>,
5281 ) -> Task<anyhow::Result<InlayHint>> {
5282 if let Some((upstream_client, project_id)) = self.upstream_client() {
5283 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5284 {
5285 hint.resolve_state = ResolveState::Resolved;
5286 return Task::ready(Ok(hint));
5287 }
5288 let request = proto::ResolveInlayHint {
5289 project_id,
5290 buffer_id: buffer.read(cx).remote_id().into(),
5291 language_server_id: server_id.0 as u64,
5292 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5293 };
5294 cx.background_spawn(async move {
5295 let response = upstream_client
5296 .request(request)
5297 .await
5298 .context("inlay hints proto request")?;
5299 match response.hint {
5300 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5301 .context("inlay hints proto resolve response conversion"),
5302 None => Ok(hint),
5303 }
5304 })
5305 } else {
5306 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5307 self.language_server_for_local_buffer(buffer, server_id, cx)
5308 .map(|(_, server)| server.clone())
5309 }) else {
5310 return Task::ready(Ok(hint));
5311 };
5312 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5313 return Task::ready(Ok(hint));
5314 }
5315 let buffer_snapshot = buffer.read(cx).snapshot();
5316 cx.spawn(async move |_, cx| {
5317 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5318 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5319 );
5320 let resolved_hint = resolve_task
5321 .await
5322 .into_response()
5323 .context("inlay hint resolve LSP request")?;
5324 let resolved_hint = InlayHints::lsp_to_project_hint(
5325 resolved_hint,
5326 &buffer,
5327 server_id,
5328 ResolveState::Resolved,
5329 false,
5330 cx,
5331 )
5332 .await?;
5333 Ok(resolved_hint)
5334 })
5335 }
5336 }
5337
5338 pub fn resolve_color_presentation(
5339 &mut self,
5340 mut color: DocumentColor,
5341 buffer: Entity<Buffer>,
5342 server_id: LanguageServerId,
5343 cx: &mut Context<Self>,
5344 ) -> Task<Result<DocumentColor>> {
5345 if color.resolved {
5346 return Task::ready(Ok(color));
5347 }
5348
5349 if let Some((upstream_client, project_id)) = self.upstream_client() {
5350 let start = color.lsp_range.start;
5351 let end = color.lsp_range.end;
5352 let request = proto::GetColorPresentation {
5353 project_id,
5354 server_id: server_id.to_proto(),
5355 buffer_id: buffer.read(cx).remote_id().into(),
5356 color: Some(proto::ColorInformation {
5357 red: color.color.red,
5358 green: color.color.green,
5359 blue: color.color.blue,
5360 alpha: color.color.alpha,
5361 lsp_range_start: Some(proto::PointUtf16 {
5362 row: start.line,
5363 column: start.character,
5364 }),
5365 lsp_range_end: Some(proto::PointUtf16 {
5366 row: end.line,
5367 column: end.character,
5368 }),
5369 }),
5370 };
5371 cx.background_spawn(async move {
5372 let response = upstream_client
5373 .request(request)
5374 .await
5375 .context("color presentation proto request")?;
5376 color.resolved = true;
5377 color.color_presentations = response
5378 .presentations
5379 .into_iter()
5380 .map(|presentation| ColorPresentation {
5381 label: SharedString::from(presentation.label),
5382 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5383 additional_text_edits: presentation
5384 .additional_text_edits
5385 .into_iter()
5386 .filter_map(deserialize_lsp_edit)
5387 .collect(),
5388 })
5389 .collect();
5390 Ok(color)
5391 })
5392 } else {
5393 let path = match buffer
5394 .update(cx, |buffer, cx| {
5395 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5396 })
5397 .context("buffer with the missing path")
5398 {
5399 Ok(path) => path,
5400 Err(e) => return Task::ready(Err(e)),
5401 };
5402 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5403 self.language_server_for_local_buffer(buffer, server_id, cx)
5404 .map(|(_, server)| server.clone())
5405 }) else {
5406 return Task::ready(Ok(color));
5407 };
5408 cx.background_spawn(async move {
5409 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5410 lsp::ColorPresentationParams {
5411 text_document: make_text_document_identifier(&path)?,
5412 color: color.color,
5413 range: color.lsp_range,
5414 work_done_progress_params: Default::default(),
5415 partial_result_params: Default::default(),
5416 },
5417 );
5418 color.color_presentations = resolve_task
5419 .await
5420 .into_response()
5421 .context("color presentation resolve LSP request")?
5422 .into_iter()
5423 .map(|presentation| ColorPresentation {
5424 label: SharedString::from(presentation.label),
5425 text_edit: presentation.text_edit,
5426 additional_text_edits: presentation
5427 .additional_text_edits
5428 .unwrap_or_default(),
5429 })
5430 .collect();
5431 color.resolved = true;
5432 Ok(color)
5433 })
5434 }
5435 }
5436
5437 pub(crate) fn linked_edits(
5438 &mut self,
5439 buffer: &Entity<Buffer>,
5440 position: Anchor,
5441 cx: &mut Context<Self>,
5442 ) -> Task<Result<Vec<Range<Anchor>>>> {
5443 let snapshot = buffer.read(cx).snapshot();
5444 let scope = snapshot.language_scope_at(position);
5445 let Some(server_id) = self
5446 .as_local()
5447 .and_then(|local| {
5448 buffer.update(cx, |buffer, cx| {
5449 local
5450 .language_servers_for_buffer(buffer, cx)
5451 .filter(|(_, server)| {
5452 LinkedEditingRange::check_server_capabilities(server.capabilities())
5453 })
5454 .filter(|(adapter, _)| {
5455 scope
5456 .as_ref()
5457 .map(|scope| scope.language_allowed(&adapter.name))
5458 .unwrap_or(true)
5459 })
5460 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5461 .next()
5462 })
5463 })
5464 .or_else(|| {
5465 self.upstream_client()
5466 .is_some()
5467 .then_some(LanguageServerToQuery::FirstCapable)
5468 })
5469 .filter(|_| {
5470 maybe!({
5471 let language = buffer.read(cx).language_at(position)?;
5472 Some(
5473 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5474 .linked_edits,
5475 )
5476 }) == Some(true)
5477 })
5478 else {
5479 return Task::ready(Ok(Vec::new()));
5480 };
5481
5482 self.request_lsp(
5483 buffer.clone(),
5484 server_id,
5485 LinkedEditingRange { position },
5486 cx,
5487 )
5488 }
5489
5490 fn apply_on_type_formatting(
5491 &mut self,
5492 buffer: Entity<Buffer>,
5493 position: Anchor,
5494 trigger: String,
5495 cx: &mut Context<Self>,
5496 ) -> Task<Result<Option<Transaction>>> {
5497 if let Some((client, project_id)) = self.upstream_client() {
5498 if !self.check_if_capable_for_proto_request(
5499 &buffer,
5500 |capabilities| {
5501 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5502 },
5503 cx,
5504 ) {
5505 return Task::ready(Ok(None));
5506 }
5507 let request = proto::OnTypeFormatting {
5508 project_id,
5509 buffer_id: buffer.read(cx).remote_id().into(),
5510 position: Some(serialize_anchor(&position)),
5511 trigger,
5512 version: serialize_version(&buffer.read(cx).version()),
5513 };
5514 cx.background_spawn(async move {
5515 client
5516 .request(request)
5517 .await?
5518 .transaction
5519 .map(language::proto::deserialize_transaction)
5520 .transpose()
5521 })
5522 } else if let Some(local) = self.as_local_mut() {
5523 let buffer_id = buffer.read(cx).remote_id();
5524 local.buffers_being_formatted.insert(buffer_id);
5525 cx.spawn(async move |this, cx| {
5526 let _cleanup = defer({
5527 let this = this.clone();
5528 let mut cx = cx.clone();
5529 move || {
5530 this.update(&mut cx, |this, _| {
5531 if let Some(local) = this.as_local_mut() {
5532 local.buffers_being_formatted.remove(&buffer_id);
5533 }
5534 })
5535 .ok();
5536 }
5537 });
5538
5539 buffer
5540 .update(cx, |buffer, _| {
5541 buffer.wait_for_edits(Some(position.timestamp))
5542 })
5543 .await?;
5544 this.update(cx, |this, cx| {
5545 let position = position.to_point_utf16(buffer.read(cx));
5546 this.on_type_format(buffer, position, trigger, false, cx)
5547 })?
5548 .await
5549 })
5550 } else {
5551 Task::ready(Err(anyhow!("No upstream client or local language server")))
5552 }
5553 }
5554
5555 pub fn on_type_format<T: ToPointUtf16>(
5556 &mut self,
5557 buffer: Entity<Buffer>,
5558 position: T,
5559 trigger: String,
5560 push_to_history: bool,
5561 cx: &mut Context<Self>,
5562 ) -> Task<Result<Option<Transaction>>> {
5563 let position = position.to_point_utf16(buffer.read(cx));
5564 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5565 }
5566
5567 fn on_type_format_impl(
5568 &mut self,
5569 buffer: Entity<Buffer>,
5570 position: PointUtf16,
5571 trigger: String,
5572 push_to_history: bool,
5573 cx: &mut Context<Self>,
5574 ) -> Task<Result<Option<Transaction>>> {
5575 let options = buffer.update(cx, |buffer, cx| {
5576 lsp_command::lsp_formatting_options(
5577 language_settings(
5578 buffer.language_at(position).map(|l| l.name()),
5579 buffer.file(),
5580 cx,
5581 )
5582 .as_ref(),
5583 )
5584 });
5585
5586 cx.spawn(async move |this, cx| {
5587 if let Some(waiter) =
5588 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5589 {
5590 waiter.await?;
5591 }
5592 cx.update(|cx| {
5593 this.update(cx, |this, cx| {
5594 this.request_lsp(
5595 buffer.clone(),
5596 LanguageServerToQuery::FirstCapable,
5597 OnTypeFormatting {
5598 position,
5599 trigger,
5600 options,
5601 push_to_history,
5602 },
5603 cx,
5604 )
5605 })
5606 })?
5607 .await
5608 })
5609 }
5610
5611 pub fn definitions(
5612 &mut self,
5613 buffer: &Entity<Buffer>,
5614 position: PointUtf16,
5615 cx: &mut Context<Self>,
5616 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5617 if let Some((upstream_client, project_id)) = self.upstream_client() {
5618 let request = GetDefinitions { position };
5619 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5620 return Task::ready(Ok(None));
5621 }
5622 let request_task = upstream_client.request_lsp(
5623 project_id,
5624 None,
5625 LSP_REQUEST_TIMEOUT,
5626 cx.background_executor().clone(),
5627 request.to_proto(project_id, buffer.read(cx)),
5628 );
5629 let buffer = buffer.clone();
5630 cx.spawn(async move |weak_lsp_store, cx| {
5631 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5632 return Ok(None);
5633 };
5634 let Some(responses) = request_task.await? else {
5635 return Ok(None);
5636 };
5637 let actions = join_all(responses.payload.into_iter().map(|response| {
5638 GetDefinitions { position }.response_from_proto(
5639 response.response,
5640 lsp_store.clone(),
5641 buffer.clone(),
5642 cx.clone(),
5643 )
5644 }))
5645 .await;
5646
5647 Ok(Some(
5648 actions
5649 .into_iter()
5650 .collect::<Result<Vec<Vec<_>>>>()?
5651 .into_iter()
5652 .flatten()
5653 .dedup()
5654 .collect(),
5655 ))
5656 })
5657 } else {
5658 let definitions_task = self.request_multiple_lsp_locally(
5659 buffer,
5660 Some(position),
5661 GetDefinitions { position },
5662 cx,
5663 );
5664 cx.background_spawn(async move {
5665 Ok(Some(
5666 definitions_task
5667 .await
5668 .into_iter()
5669 .flat_map(|(_, definitions)| definitions)
5670 .dedup()
5671 .collect(),
5672 ))
5673 })
5674 }
5675 }
5676
5677 pub fn declarations(
5678 &mut self,
5679 buffer: &Entity<Buffer>,
5680 position: PointUtf16,
5681 cx: &mut Context<Self>,
5682 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5683 if let Some((upstream_client, project_id)) = self.upstream_client() {
5684 let request = GetDeclarations { position };
5685 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5686 return Task::ready(Ok(None));
5687 }
5688 let request_task = upstream_client.request_lsp(
5689 project_id,
5690 None,
5691 LSP_REQUEST_TIMEOUT,
5692 cx.background_executor().clone(),
5693 request.to_proto(project_id, buffer.read(cx)),
5694 );
5695 let buffer = buffer.clone();
5696 cx.spawn(async move |weak_lsp_store, cx| {
5697 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5698 return Ok(None);
5699 };
5700 let Some(responses) = request_task.await? else {
5701 return Ok(None);
5702 };
5703 let actions = join_all(responses.payload.into_iter().map(|response| {
5704 GetDeclarations { position }.response_from_proto(
5705 response.response,
5706 lsp_store.clone(),
5707 buffer.clone(),
5708 cx.clone(),
5709 )
5710 }))
5711 .await;
5712
5713 Ok(Some(
5714 actions
5715 .into_iter()
5716 .collect::<Result<Vec<Vec<_>>>>()?
5717 .into_iter()
5718 .flatten()
5719 .dedup()
5720 .collect(),
5721 ))
5722 })
5723 } else {
5724 let declarations_task = self.request_multiple_lsp_locally(
5725 buffer,
5726 Some(position),
5727 GetDeclarations { position },
5728 cx,
5729 );
5730 cx.background_spawn(async move {
5731 Ok(Some(
5732 declarations_task
5733 .await
5734 .into_iter()
5735 .flat_map(|(_, declarations)| declarations)
5736 .dedup()
5737 .collect(),
5738 ))
5739 })
5740 }
5741 }
5742
5743 pub fn type_definitions(
5744 &mut self,
5745 buffer: &Entity<Buffer>,
5746 position: PointUtf16,
5747 cx: &mut Context<Self>,
5748 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5749 if let Some((upstream_client, project_id)) = self.upstream_client() {
5750 let request = GetTypeDefinitions { position };
5751 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5752 return Task::ready(Ok(None));
5753 }
5754 let request_task = upstream_client.request_lsp(
5755 project_id,
5756 None,
5757 LSP_REQUEST_TIMEOUT,
5758 cx.background_executor().clone(),
5759 request.to_proto(project_id, buffer.read(cx)),
5760 );
5761 let buffer = buffer.clone();
5762 cx.spawn(async move |weak_lsp_store, cx| {
5763 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5764 return Ok(None);
5765 };
5766 let Some(responses) = request_task.await? else {
5767 return Ok(None);
5768 };
5769 let actions = join_all(responses.payload.into_iter().map(|response| {
5770 GetTypeDefinitions { position }.response_from_proto(
5771 response.response,
5772 lsp_store.clone(),
5773 buffer.clone(),
5774 cx.clone(),
5775 )
5776 }))
5777 .await;
5778
5779 Ok(Some(
5780 actions
5781 .into_iter()
5782 .collect::<Result<Vec<Vec<_>>>>()?
5783 .into_iter()
5784 .flatten()
5785 .dedup()
5786 .collect(),
5787 ))
5788 })
5789 } else {
5790 let type_definitions_task = self.request_multiple_lsp_locally(
5791 buffer,
5792 Some(position),
5793 GetTypeDefinitions { position },
5794 cx,
5795 );
5796 cx.background_spawn(async move {
5797 Ok(Some(
5798 type_definitions_task
5799 .await
5800 .into_iter()
5801 .flat_map(|(_, type_definitions)| type_definitions)
5802 .dedup()
5803 .collect(),
5804 ))
5805 })
5806 }
5807 }
5808
5809 pub fn implementations(
5810 &mut self,
5811 buffer: &Entity<Buffer>,
5812 position: PointUtf16,
5813 cx: &mut Context<Self>,
5814 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5815 if let Some((upstream_client, project_id)) = self.upstream_client() {
5816 let request = GetImplementations { position };
5817 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5818 return Task::ready(Ok(None));
5819 }
5820 let request_task = upstream_client.request_lsp(
5821 project_id,
5822 None,
5823 LSP_REQUEST_TIMEOUT,
5824 cx.background_executor().clone(),
5825 request.to_proto(project_id, buffer.read(cx)),
5826 );
5827 let buffer = buffer.clone();
5828 cx.spawn(async move |weak_lsp_store, cx| {
5829 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5830 return Ok(None);
5831 };
5832 let Some(responses) = request_task.await? else {
5833 return Ok(None);
5834 };
5835 let actions = join_all(responses.payload.into_iter().map(|response| {
5836 GetImplementations { position }.response_from_proto(
5837 response.response,
5838 lsp_store.clone(),
5839 buffer.clone(),
5840 cx.clone(),
5841 )
5842 }))
5843 .await;
5844
5845 Ok(Some(
5846 actions
5847 .into_iter()
5848 .collect::<Result<Vec<Vec<_>>>>()?
5849 .into_iter()
5850 .flatten()
5851 .dedup()
5852 .collect(),
5853 ))
5854 })
5855 } else {
5856 let implementations_task = self.request_multiple_lsp_locally(
5857 buffer,
5858 Some(position),
5859 GetImplementations { position },
5860 cx,
5861 );
5862 cx.background_spawn(async move {
5863 Ok(Some(
5864 implementations_task
5865 .await
5866 .into_iter()
5867 .flat_map(|(_, implementations)| implementations)
5868 .dedup()
5869 .collect(),
5870 ))
5871 })
5872 }
5873 }
5874
5875 pub fn references(
5876 &mut self,
5877 buffer: &Entity<Buffer>,
5878 position: PointUtf16,
5879 cx: &mut Context<Self>,
5880 ) -> Task<Result<Option<Vec<Location>>>> {
5881 if let Some((upstream_client, project_id)) = self.upstream_client() {
5882 let request = GetReferences { position };
5883 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5884 return Task::ready(Ok(None));
5885 }
5886
5887 let request_task = upstream_client.request_lsp(
5888 project_id,
5889 None,
5890 LSP_REQUEST_TIMEOUT,
5891 cx.background_executor().clone(),
5892 request.to_proto(project_id, buffer.read(cx)),
5893 );
5894 let buffer = buffer.clone();
5895 cx.spawn(async move |weak_lsp_store, cx| {
5896 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5897 return Ok(None);
5898 };
5899 let Some(responses) = request_task.await? else {
5900 return Ok(None);
5901 };
5902
5903 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5904 GetReferences { position }.response_from_proto(
5905 lsp_response.response,
5906 lsp_store.clone(),
5907 buffer.clone(),
5908 cx.clone(),
5909 )
5910 }))
5911 .await
5912 .into_iter()
5913 .collect::<Result<Vec<Vec<_>>>>()?
5914 .into_iter()
5915 .flatten()
5916 .dedup()
5917 .collect();
5918 Ok(Some(locations))
5919 })
5920 } else {
5921 let references_task = self.request_multiple_lsp_locally(
5922 buffer,
5923 Some(position),
5924 GetReferences { position },
5925 cx,
5926 );
5927 cx.background_spawn(async move {
5928 Ok(Some(
5929 references_task
5930 .await
5931 .into_iter()
5932 .flat_map(|(_, references)| references)
5933 .dedup()
5934 .collect(),
5935 ))
5936 })
5937 }
5938 }
5939
5940 pub fn code_actions(
5941 &mut self,
5942 buffer: &Entity<Buffer>,
5943 range: Range<Anchor>,
5944 kinds: Option<Vec<CodeActionKind>>,
5945 cx: &mut Context<Self>,
5946 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5947 if let Some((upstream_client, project_id)) = self.upstream_client() {
5948 let request = GetCodeActions {
5949 range: range.clone(),
5950 kinds: kinds.clone(),
5951 };
5952 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5953 return Task::ready(Ok(None));
5954 }
5955 let request_task = upstream_client.request_lsp(
5956 project_id,
5957 None,
5958 LSP_REQUEST_TIMEOUT,
5959 cx.background_executor().clone(),
5960 request.to_proto(project_id, buffer.read(cx)),
5961 );
5962 let buffer = buffer.clone();
5963 cx.spawn(async move |weak_lsp_store, cx| {
5964 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5965 return Ok(None);
5966 };
5967 let Some(responses) = request_task.await? else {
5968 return Ok(None);
5969 };
5970 let actions = join_all(responses.payload.into_iter().map(|response| {
5971 GetCodeActions {
5972 range: range.clone(),
5973 kinds: kinds.clone(),
5974 }
5975 .response_from_proto(
5976 response.response,
5977 lsp_store.clone(),
5978 buffer.clone(),
5979 cx.clone(),
5980 )
5981 }))
5982 .await;
5983
5984 Ok(Some(
5985 actions
5986 .into_iter()
5987 .collect::<Result<Vec<Vec<_>>>>()?
5988 .into_iter()
5989 .flatten()
5990 .collect(),
5991 ))
5992 })
5993 } else {
5994 let all_actions_task = self.request_multiple_lsp_locally(
5995 buffer,
5996 Some(range.start),
5997 GetCodeActions { range, kinds },
5998 cx,
5999 );
6000 cx.background_spawn(async move {
6001 Ok(Some(
6002 all_actions_task
6003 .await
6004 .into_iter()
6005 .flat_map(|(_, actions)| actions)
6006 .collect(),
6007 ))
6008 })
6009 }
6010 }
6011
6012 pub fn code_lens_actions(
6013 &mut self,
6014 buffer: &Entity<Buffer>,
6015 cx: &mut Context<Self>,
6016 ) -> CodeLensTask {
6017 let version_queried_for = buffer.read(cx).version();
6018 let buffer_id = buffer.read(cx).remote_id();
6019 let existing_servers = self.as_local().map(|local| {
6020 local
6021 .buffers_opened_in_servers
6022 .get(&buffer_id)
6023 .cloned()
6024 .unwrap_or_default()
6025 });
6026
6027 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6028 if let Some(cached_lens) = &lsp_data.code_lens {
6029 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6030 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6031 existing_servers != cached_lens.lens.keys().copied().collect()
6032 });
6033 if !has_different_servers {
6034 return Task::ready(Ok(Some(
6035 cached_lens.lens.values().flatten().cloned().collect(),
6036 )))
6037 .shared();
6038 }
6039 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6040 if !version_queried_for.changed_since(updating_for) {
6041 return running_update.clone();
6042 }
6043 }
6044 }
6045 }
6046
6047 let lens_lsp_data = self
6048 .latest_lsp_data(buffer, cx)
6049 .code_lens
6050 .get_or_insert_default();
6051 let buffer = buffer.clone();
6052 let query_version_queried_for = version_queried_for.clone();
6053 let new_task = cx
6054 .spawn(async move |lsp_store, cx| {
6055 cx.background_executor()
6056 .timer(Duration::from_millis(30))
6057 .await;
6058 let fetched_lens = lsp_store
6059 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6060 .map_err(Arc::new)?
6061 .await
6062 .context("fetching code lens")
6063 .map_err(Arc::new);
6064 let fetched_lens = match fetched_lens {
6065 Ok(fetched_lens) => fetched_lens,
6066 Err(e) => {
6067 lsp_store
6068 .update(cx, |lsp_store, _| {
6069 if let Some(lens_lsp_data) = lsp_store
6070 .lsp_data
6071 .get_mut(&buffer_id)
6072 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6073 {
6074 lens_lsp_data.update = None;
6075 }
6076 })
6077 .ok();
6078 return Err(e);
6079 }
6080 };
6081
6082 lsp_store
6083 .update(cx, |lsp_store, _| {
6084 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6085 let code_lens = lsp_data.code_lens.as_mut()?;
6086 if let Some(fetched_lens) = fetched_lens {
6087 if lsp_data.buffer_version == query_version_queried_for {
6088 code_lens.lens.extend(fetched_lens);
6089 } else if !lsp_data
6090 .buffer_version
6091 .changed_since(&query_version_queried_for)
6092 {
6093 lsp_data.buffer_version = query_version_queried_for;
6094 code_lens.lens = fetched_lens;
6095 }
6096 }
6097 code_lens.update = None;
6098 Some(code_lens.lens.values().flatten().cloned().collect())
6099 })
6100 .map_err(Arc::new)
6101 })
6102 .shared();
6103 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6104 new_task
6105 }
6106
6107 fn fetch_code_lens(
6108 &mut self,
6109 buffer: &Entity<Buffer>,
6110 cx: &mut Context<Self>,
6111 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6112 if let Some((upstream_client, project_id)) = self.upstream_client() {
6113 let request = GetCodeLens;
6114 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6115 return Task::ready(Ok(None));
6116 }
6117 let request_task = upstream_client.request_lsp(
6118 project_id,
6119 None,
6120 LSP_REQUEST_TIMEOUT,
6121 cx.background_executor().clone(),
6122 request.to_proto(project_id, buffer.read(cx)),
6123 );
6124 let buffer = buffer.clone();
6125 cx.spawn(async move |weak_lsp_store, cx| {
6126 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6127 return Ok(None);
6128 };
6129 let Some(responses) = request_task.await? else {
6130 return Ok(None);
6131 };
6132
6133 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6134 let lsp_store = lsp_store.clone();
6135 let buffer = buffer.clone();
6136 let cx = cx.clone();
6137 async move {
6138 (
6139 LanguageServerId::from_proto(response.server_id),
6140 GetCodeLens
6141 .response_from_proto(response.response, lsp_store, buffer, cx)
6142 .await,
6143 )
6144 }
6145 }))
6146 .await;
6147
6148 let mut has_errors = false;
6149 let code_lens_actions = code_lens_actions
6150 .into_iter()
6151 .filter_map(|(server_id, code_lens)| match code_lens {
6152 Ok(code_lens) => Some((server_id, code_lens)),
6153 Err(e) => {
6154 has_errors = true;
6155 log::error!("{e:#}");
6156 None
6157 }
6158 })
6159 .collect::<HashMap<_, _>>();
6160 anyhow::ensure!(
6161 !has_errors || !code_lens_actions.is_empty(),
6162 "Failed to fetch code lens"
6163 );
6164 Ok(Some(code_lens_actions))
6165 })
6166 } else {
6167 let code_lens_actions_task =
6168 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6169 cx.background_spawn(async move {
6170 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6171 })
6172 }
6173 }
6174
6175 #[inline(never)]
6176 pub fn completions(
6177 &self,
6178 buffer: &Entity<Buffer>,
6179 position: PointUtf16,
6180 context: CompletionContext,
6181 cx: &mut Context<Self>,
6182 ) -> Task<Result<Vec<CompletionResponse>>> {
6183 let language_registry = self.languages.clone();
6184
6185 if let Some((upstream_client, project_id)) = self.upstream_client() {
6186 let snapshot = buffer.read(cx).snapshot();
6187 let offset = position.to_offset(&snapshot);
6188 let scope = snapshot.language_scope_at(offset);
6189 let capable_lsps = self.all_capable_for_proto_request(
6190 buffer,
6191 |server_name, capabilities| {
6192 capabilities.completion_provider.is_some()
6193 && scope
6194 .as_ref()
6195 .map(|scope| scope.language_allowed(server_name))
6196 .unwrap_or(true)
6197 },
6198 cx,
6199 );
6200 if capable_lsps.is_empty() {
6201 return Task::ready(Ok(Vec::new()));
6202 }
6203
6204 let language = buffer.read(cx).language().cloned();
6205
6206 // In the future, we should provide project guests with the names of LSP adapters,
6207 // so that they can use the correct LSP adapter when computing labels. For now,
6208 // guests just use the first LSP adapter associated with the buffer's language.
6209 let lsp_adapter = language.as_ref().and_then(|language| {
6210 language_registry
6211 .lsp_adapters(&language.name())
6212 .first()
6213 .cloned()
6214 });
6215
6216 let buffer = buffer.clone();
6217
6218 cx.spawn(async move |this, cx| {
6219 let requests = join_all(
6220 capable_lsps
6221 .into_iter()
6222 .map(|id| {
6223 let request = GetCompletions {
6224 position,
6225 context: context.clone(),
6226 server_id: Some(id),
6227 };
6228 let buffer = buffer.clone();
6229 let language = language.clone();
6230 let lsp_adapter = lsp_adapter.clone();
6231 let upstream_client = upstream_client.clone();
6232 let response = this
6233 .update(cx, |this, cx| {
6234 this.send_lsp_proto_request(
6235 buffer,
6236 upstream_client,
6237 project_id,
6238 request,
6239 cx,
6240 )
6241 })
6242 .log_err();
6243 async move {
6244 let response = response?.await.log_err()?;
6245
6246 let completions = populate_labels_for_completions(
6247 response.completions,
6248 language,
6249 lsp_adapter,
6250 )
6251 .await;
6252
6253 Some(CompletionResponse {
6254 completions,
6255 display_options: CompletionDisplayOptions::default(),
6256 is_incomplete: response.is_incomplete,
6257 })
6258 }
6259 })
6260 .collect::<Vec<_>>(),
6261 );
6262 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6263 })
6264 } else if let Some(local) = self.as_local() {
6265 let snapshot = buffer.read(cx).snapshot();
6266 let offset = position.to_offset(&snapshot);
6267 let scope = snapshot.language_scope_at(offset);
6268 let language = snapshot.language().cloned();
6269 let completion_settings = language_settings(
6270 language.as_ref().map(|language| language.name()),
6271 buffer.read(cx).file(),
6272 cx,
6273 )
6274 .completions
6275 .clone();
6276 if !completion_settings.lsp {
6277 return Task::ready(Ok(Vec::new()));
6278 }
6279
6280 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6281 local
6282 .language_servers_for_buffer(buffer, cx)
6283 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6284 .filter(|(adapter, _)| {
6285 scope
6286 .as_ref()
6287 .map(|scope| scope.language_allowed(&adapter.name))
6288 .unwrap_or(true)
6289 })
6290 .map(|(_, server)| server.server_id())
6291 .collect()
6292 });
6293
6294 let buffer = buffer.clone();
6295 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6296 let lsp_timeout = if lsp_timeout > 0 {
6297 Some(Duration::from_millis(lsp_timeout))
6298 } else {
6299 None
6300 };
6301 cx.spawn(async move |this, cx| {
6302 let mut tasks = Vec::with_capacity(server_ids.len());
6303 this.update(cx, |lsp_store, cx| {
6304 for server_id in server_ids {
6305 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6306 let lsp_timeout = lsp_timeout
6307 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6308 let mut timeout = cx.background_spawn(async move {
6309 match lsp_timeout {
6310 Some(lsp_timeout) => {
6311 lsp_timeout.await;
6312 true
6313 },
6314 None => false,
6315 }
6316 }).fuse();
6317 let mut lsp_request = lsp_store.request_lsp(
6318 buffer.clone(),
6319 LanguageServerToQuery::Other(server_id),
6320 GetCompletions {
6321 position,
6322 context: context.clone(),
6323 server_id: Some(server_id),
6324 },
6325 cx,
6326 ).fuse();
6327 let new_task = cx.background_spawn(async move {
6328 select_biased! {
6329 response = lsp_request => anyhow::Ok(Some(response?)),
6330 timeout_happened = timeout => {
6331 if timeout_happened {
6332 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6333 Ok(None)
6334 } else {
6335 let completions = lsp_request.await?;
6336 Ok(Some(completions))
6337 }
6338 },
6339 }
6340 });
6341 tasks.push((lsp_adapter, new_task));
6342 }
6343 })?;
6344
6345 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6346 let completion_response = task.await.ok()??;
6347 let completions = populate_labels_for_completions(
6348 completion_response.completions,
6349 language.clone(),
6350 lsp_adapter,
6351 )
6352 .await;
6353 Some(CompletionResponse {
6354 completions,
6355 display_options: CompletionDisplayOptions::default(),
6356 is_incomplete: completion_response.is_incomplete,
6357 })
6358 });
6359
6360 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6361
6362 Ok(responses.into_iter().flatten().collect())
6363 })
6364 } else {
6365 Task::ready(Err(anyhow!("No upstream client or local language server")))
6366 }
6367 }
6368
6369 pub fn resolve_completions(
6370 &self,
6371 buffer: Entity<Buffer>,
6372 completion_indices: Vec<usize>,
6373 completions: Rc<RefCell<Box<[Completion]>>>,
6374 cx: &mut Context<Self>,
6375 ) -> Task<Result<bool>> {
6376 let client = self.upstream_client();
6377 let buffer_id = buffer.read(cx).remote_id();
6378 let buffer_snapshot = buffer.read(cx).snapshot();
6379
6380 if !self.check_if_capable_for_proto_request(
6381 &buffer,
6382 GetCompletions::can_resolve_completions,
6383 cx,
6384 ) {
6385 return Task::ready(Ok(false));
6386 }
6387 cx.spawn(async move |lsp_store, cx| {
6388 let mut did_resolve = false;
6389 if let Some((client, project_id)) = client {
6390 for completion_index in completion_indices {
6391 let server_id = {
6392 let completion = &completions.borrow()[completion_index];
6393 completion.source.server_id()
6394 };
6395 if let Some(server_id) = server_id {
6396 if Self::resolve_completion_remote(
6397 project_id,
6398 server_id,
6399 buffer_id,
6400 completions.clone(),
6401 completion_index,
6402 client.clone(),
6403 )
6404 .await
6405 .log_err()
6406 .is_some()
6407 {
6408 did_resolve = true;
6409 }
6410 } else {
6411 resolve_word_completion(
6412 &buffer_snapshot,
6413 &mut completions.borrow_mut()[completion_index],
6414 );
6415 }
6416 }
6417 } else {
6418 for completion_index in completion_indices {
6419 let server_id = {
6420 let completion = &completions.borrow()[completion_index];
6421 completion.source.server_id()
6422 };
6423 if let Some(server_id) = server_id {
6424 let server_and_adapter = lsp_store
6425 .read_with(cx, |lsp_store, _| {
6426 let server = lsp_store.language_server_for_id(server_id)?;
6427 let adapter =
6428 lsp_store.language_server_adapter_for_id(server.server_id())?;
6429 Some((server, adapter))
6430 })
6431 .ok()
6432 .flatten();
6433 let Some((server, adapter)) = server_and_adapter else {
6434 continue;
6435 };
6436
6437 let resolved = Self::resolve_completion_local(
6438 server,
6439 completions.clone(),
6440 completion_index,
6441 )
6442 .await
6443 .log_err()
6444 .is_some();
6445 if resolved {
6446 Self::regenerate_completion_labels(
6447 adapter,
6448 &buffer_snapshot,
6449 completions.clone(),
6450 completion_index,
6451 )
6452 .await
6453 .log_err();
6454 did_resolve = true;
6455 }
6456 } else {
6457 resolve_word_completion(
6458 &buffer_snapshot,
6459 &mut completions.borrow_mut()[completion_index],
6460 );
6461 }
6462 }
6463 }
6464
6465 Ok(did_resolve)
6466 })
6467 }
6468
6469 async fn resolve_completion_local(
6470 server: Arc<lsp::LanguageServer>,
6471 completions: Rc<RefCell<Box<[Completion]>>>,
6472 completion_index: usize,
6473 ) -> Result<()> {
6474 let server_id = server.server_id();
6475 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6476 return Ok(());
6477 }
6478
6479 let request = {
6480 let completion = &completions.borrow()[completion_index];
6481 match &completion.source {
6482 CompletionSource::Lsp {
6483 lsp_completion,
6484 resolved,
6485 server_id: completion_server_id,
6486 ..
6487 } => {
6488 if *resolved {
6489 return Ok(());
6490 }
6491 anyhow::ensure!(
6492 server_id == *completion_server_id,
6493 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6494 );
6495 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6496 }
6497 CompletionSource::BufferWord { .. }
6498 | CompletionSource::Dap { .. }
6499 | CompletionSource::Custom => {
6500 return Ok(());
6501 }
6502 }
6503 };
6504 let resolved_completion = request
6505 .await
6506 .into_response()
6507 .context("resolve completion")?;
6508
6509 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6510 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6511
6512 let mut completions = completions.borrow_mut();
6513 let completion = &mut completions[completion_index];
6514 if let CompletionSource::Lsp {
6515 lsp_completion,
6516 resolved,
6517 server_id: completion_server_id,
6518 ..
6519 } = &mut completion.source
6520 {
6521 if *resolved {
6522 return Ok(());
6523 }
6524 anyhow::ensure!(
6525 server_id == *completion_server_id,
6526 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6527 );
6528 **lsp_completion = resolved_completion;
6529 *resolved = true;
6530 }
6531 Ok(())
6532 }
6533
6534 async fn regenerate_completion_labels(
6535 adapter: Arc<CachedLspAdapter>,
6536 snapshot: &BufferSnapshot,
6537 completions: Rc<RefCell<Box<[Completion]>>>,
6538 completion_index: usize,
6539 ) -> Result<()> {
6540 let completion_item = completions.borrow()[completion_index]
6541 .source
6542 .lsp_completion(true)
6543 .map(Cow::into_owned);
6544 if let Some(lsp_documentation) = completion_item
6545 .as_ref()
6546 .and_then(|completion_item| completion_item.documentation.clone())
6547 {
6548 let mut completions = completions.borrow_mut();
6549 let completion = &mut completions[completion_index];
6550 completion.documentation = Some(lsp_documentation.into());
6551 } else {
6552 let mut completions = completions.borrow_mut();
6553 let completion = &mut completions[completion_index];
6554 completion.documentation = Some(CompletionDocumentation::Undocumented);
6555 }
6556
6557 let mut new_label = match completion_item {
6558 Some(completion_item) => {
6559 // Some language servers always return `detail` lazily via resolve, regardless of
6560 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6561 // See: https://github.com/yioneko/vtsls/issues/213
6562 let language = snapshot.language();
6563 match language {
6564 Some(language) => {
6565 adapter
6566 .labels_for_completions(
6567 std::slice::from_ref(&completion_item),
6568 language,
6569 )
6570 .await?
6571 }
6572 None => Vec::new(),
6573 }
6574 .pop()
6575 .flatten()
6576 .unwrap_or_else(|| {
6577 CodeLabel::fallback_for_completion(
6578 &completion_item,
6579 language.map(|language| language.as_ref()),
6580 )
6581 })
6582 }
6583 None => CodeLabel::plain(
6584 completions.borrow()[completion_index].new_text.clone(),
6585 None,
6586 ),
6587 };
6588 ensure_uniform_list_compatible_label(&mut new_label);
6589
6590 let mut completions = completions.borrow_mut();
6591 let completion = &mut completions[completion_index];
6592 if completion.label.filter_text() == new_label.filter_text() {
6593 completion.label = new_label;
6594 } else {
6595 log::error!(
6596 "Resolved completion changed display label from {} to {}. \
6597 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6598 completion.label.text(),
6599 new_label.text(),
6600 completion.label.filter_text(),
6601 new_label.filter_text()
6602 );
6603 }
6604
6605 Ok(())
6606 }
6607
6608 async fn resolve_completion_remote(
6609 project_id: u64,
6610 server_id: LanguageServerId,
6611 buffer_id: BufferId,
6612 completions: Rc<RefCell<Box<[Completion]>>>,
6613 completion_index: usize,
6614 client: AnyProtoClient,
6615 ) -> Result<()> {
6616 let lsp_completion = {
6617 let completion = &completions.borrow()[completion_index];
6618 match &completion.source {
6619 CompletionSource::Lsp {
6620 lsp_completion,
6621 resolved,
6622 server_id: completion_server_id,
6623 ..
6624 } => {
6625 anyhow::ensure!(
6626 server_id == *completion_server_id,
6627 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6628 );
6629 if *resolved {
6630 return Ok(());
6631 }
6632 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6633 }
6634 CompletionSource::Custom
6635 | CompletionSource::Dap { .. }
6636 | CompletionSource::BufferWord { .. } => {
6637 return Ok(());
6638 }
6639 }
6640 };
6641 let request = proto::ResolveCompletionDocumentation {
6642 project_id,
6643 language_server_id: server_id.0 as u64,
6644 lsp_completion,
6645 buffer_id: buffer_id.into(),
6646 };
6647
6648 let response = client
6649 .request(request)
6650 .await
6651 .context("completion documentation resolve proto request")?;
6652 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6653
6654 let documentation = if response.documentation.is_empty() {
6655 CompletionDocumentation::Undocumented
6656 } else if response.documentation_is_markdown {
6657 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6658 } else if response.documentation.lines().count() <= 1 {
6659 CompletionDocumentation::SingleLine(response.documentation.into())
6660 } else {
6661 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6662 };
6663
6664 let mut completions = completions.borrow_mut();
6665 let completion = &mut completions[completion_index];
6666 completion.documentation = Some(documentation);
6667 if let CompletionSource::Lsp {
6668 insert_range,
6669 lsp_completion,
6670 resolved,
6671 server_id: completion_server_id,
6672 lsp_defaults: _,
6673 } = &mut completion.source
6674 {
6675 let completion_insert_range = response
6676 .old_insert_start
6677 .and_then(deserialize_anchor)
6678 .zip(response.old_insert_end.and_then(deserialize_anchor));
6679 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6680
6681 if *resolved {
6682 return Ok(());
6683 }
6684 anyhow::ensure!(
6685 server_id == *completion_server_id,
6686 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6687 );
6688 **lsp_completion = resolved_lsp_completion;
6689 *resolved = true;
6690 }
6691
6692 let replace_range = response
6693 .old_replace_start
6694 .and_then(deserialize_anchor)
6695 .zip(response.old_replace_end.and_then(deserialize_anchor));
6696 if let Some((old_replace_start, old_replace_end)) = replace_range
6697 && !response.new_text.is_empty()
6698 {
6699 completion.new_text = response.new_text;
6700 completion.replace_range = old_replace_start..old_replace_end;
6701 }
6702
6703 Ok(())
6704 }
6705
6706 pub fn apply_additional_edits_for_completion(
6707 &self,
6708 buffer_handle: Entity<Buffer>,
6709 completions: Rc<RefCell<Box<[Completion]>>>,
6710 completion_index: usize,
6711 push_to_history: bool,
6712 cx: &mut Context<Self>,
6713 ) -> Task<Result<Option<Transaction>>> {
6714 if let Some((client, project_id)) = self.upstream_client() {
6715 let buffer = buffer_handle.read(cx);
6716 let buffer_id = buffer.remote_id();
6717 cx.spawn(async move |_, cx| {
6718 let request = {
6719 let completion = completions.borrow()[completion_index].clone();
6720 proto::ApplyCompletionAdditionalEdits {
6721 project_id,
6722 buffer_id: buffer_id.into(),
6723 completion: Some(Self::serialize_completion(&CoreCompletion {
6724 replace_range: completion.replace_range,
6725 new_text: completion.new_text,
6726 source: completion.source,
6727 })),
6728 }
6729 };
6730
6731 if let Some(transaction) = client.request(request).await?.transaction {
6732 let transaction = language::proto::deserialize_transaction(transaction)?;
6733 buffer_handle
6734 .update(cx, |buffer, _| {
6735 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6736 })
6737 .await?;
6738 if push_to_history {
6739 buffer_handle.update(cx, |buffer, _| {
6740 buffer.push_transaction(transaction.clone(), Instant::now());
6741 buffer.finalize_last_transaction();
6742 });
6743 }
6744 Ok(Some(transaction))
6745 } else {
6746 Ok(None)
6747 }
6748 })
6749 } else {
6750 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6751 let completion = &completions.borrow()[completion_index];
6752 let server_id = completion.source.server_id()?;
6753 Some(
6754 self.language_server_for_local_buffer(buffer, server_id, cx)?
6755 .1
6756 .clone(),
6757 )
6758 }) else {
6759 return Task::ready(Ok(None));
6760 };
6761
6762 cx.spawn(async move |this, cx| {
6763 Self::resolve_completion_local(
6764 server.clone(),
6765 completions.clone(),
6766 completion_index,
6767 )
6768 .await
6769 .context("resolving completion")?;
6770 let completion = completions.borrow()[completion_index].clone();
6771 let additional_text_edits = completion
6772 .source
6773 .lsp_completion(true)
6774 .as_ref()
6775 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6776 if let Some(edits) = additional_text_edits {
6777 let edits = this
6778 .update(cx, |this, cx| {
6779 this.as_local_mut().unwrap().edits_from_lsp(
6780 &buffer_handle,
6781 edits,
6782 server.server_id(),
6783 None,
6784 cx,
6785 )
6786 })?
6787 .await?;
6788
6789 buffer_handle.update(cx, |buffer, cx| {
6790 buffer.finalize_last_transaction();
6791 buffer.start_transaction();
6792
6793 for (range, text) in edits {
6794 let primary = &completion.replace_range;
6795
6796 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6797 // and the primary completion is just an insertion (empty range), then this is likely
6798 // an auto-import scenario and should not be considered overlapping
6799 // https://github.com/zed-industries/zed/issues/26136
6800 let is_file_start_auto_import = {
6801 let snapshot = buffer.snapshot();
6802 let primary_start_point = primary.start.to_point(&snapshot);
6803 let range_start_point = range.start.to_point(&snapshot);
6804
6805 let result = primary_start_point.row == 0
6806 && primary_start_point.column == 0
6807 && range_start_point.row == 0
6808 && range_start_point.column == 0;
6809
6810 result
6811 };
6812
6813 let has_overlap = if is_file_start_auto_import {
6814 false
6815 } else {
6816 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6817 && primary.end.cmp(&range.start, buffer).is_ge();
6818 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6819 && range.end.cmp(&primary.end, buffer).is_ge();
6820 let result = start_within || end_within;
6821 result
6822 };
6823
6824 //Skip additional edits which overlap with the primary completion edit
6825 //https://github.com/zed-industries/zed/pull/1871
6826 if !has_overlap {
6827 buffer.edit([(range, text)], None, cx);
6828 }
6829 }
6830
6831 let transaction = if buffer.end_transaction(cx).is_some() {
6832 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6833 if !push_to_history {
6834 buffer.forget_transaction(transaction.id);
6835 }
6836 Some(transaction)
6837 } else {
6838 None
6839 };
6840 Ok(transaction)
6841 })
6842 } else {
6843 Ok(None)
6844 }
6845 })
6846 }
6847 }
6848
6849 pub fn pull_diagnostics(
6850 &mut self,
6851 buffer: Entity<Buffer>,
6852 cx: &mut Context<Self>,
6853 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6854 let buffer_id = buffer.read(cx).remote_id();
6855
6856 if let Some((client, upstream_project_id)) = self.upstream_client() {
6857 let mut suitable_capabilities = None;
6858 // Are we capable for proto request?
6859 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6860 &buffer,
6861 |capabilities| {
6862 if let Some(caps) = &capabilities.diagnostic_provider {
6863 suitable_capabilities = Some(caps.clone());
6864 true
6865 } else {
6866 false
6867 }
6868 },
6869 cx,
6870 );
6871 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6872 let Some(dynamic_caps) = suitable_capabilities else {
6873 return Task::ready(Ok(None));
6874 };
6875 assert!(any_server_has_diagnostics_provider);
6876
6877 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6878 let request = GetDocumentDiagnostics {
6879 previous_result_id: None,
6880 identifier,
6881 registration_id: None,
6882 };
6883 let request_task = client.request_lsp(
6884 upstream_project_id,
6885 None,
6886 LSP_REQUEST_TIMEOUT,
6887 cx.background_executor().clone(),
6888 request.to_proto(upstream_project_id, buffer.read(cx)),
6889 );
6890 cx.background_spawn(async move {
6891 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6892 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6893 // Do not attempt to further process the dummy responses here.
6894 let _response = request_task.await?;
6895 Ok(None)
6896 })
6897 } else {
6898 let servers = buffer.update(cx, |buffer, cx| {
6899 self.running_language_servers_for_local_buffer(buffer, cx)
6900 .map(|(_, server)| server.clone())
6901 .collect::<Vec<_>>()
6902 });
6903
6904 let pull_diagnostics = servers
6905 .into_iter()
6906 .flat_map(|server| {
6907 let result = maybe!({
6908 let local = self.as_local()?;
6909 let server_id = server.server_id();
6910 let providers_with_identifiers = local
6911 .language_server_dynamic_registrations
6912 .get(&server_id)
6913 .into_iter()
6914 .flat_map(|registrations| registrations.diagnostics.clone())
6915 .collect::<Vec<_>>();
6916 Some(
6917 providers_with_identifiers
6918 .into_iter()
6919 .map(|(registration_id, dynamic_caps)| {
6920 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6921 let registration_id = registration_id.map(SharedString::from);
6922 let result_id = self.result_id_for_buffer_pull(
6923 server_id,
6924 buffer_id,
6925 ®istration_id,
6926 cx,
6927 );
6928 self.request_lsp(
6929 buffer.clone(),
6930 LanguageServerToQuery::Other(server_id),
6931 GetDocumentDiagnostics {
6932 previous_result_id: result_id,
6933 registration_id,
6934 identifier,
6935 },
6936 cx,
6937 )
6938 })
6939 .collect::<Vec<_>>(),
6940 )
6941 });
6942
6943 result.unwrap_or_default()
6944 })
6945 .collect::<Vec<_>>();
6946
6947 cx.background_spawn(async move {
6948 let mut responses = Vec::new();
6949 for diagnostics in join_all(pull_diagnostics).await {
6950 responses.extend(diagnostics?);
6951 }
6952 Ok(Some(responses))
6953 })
6954 }
6955 }
6956
6957 pub fn applicable_inlay_chunks(
6958 &mut self,
6959 buffer: &Entity<Buffer>,
6960 ranges: &[Range<text::Anchor>],
6961 cx: &mut Context<Self>,
6962 ) -> Vec<Range<BufferRow>> {
6963 let buffer_snapshot = buffer.read(cx).snapshot();
6964 let ranges = ranges
6965 .iter()
6966 .map(|range| range.to_point(&buffer_snapshot))
6967 .collect::<Vec<_>>();
6968
6969 self.latest_lsp_data(buffer, cx)
6970 .inlay_hints
6971 .applicable_chunks(ranges.as_slice())
6972 .map(|chunk| chunk.row_range())
6973 .collect()
6974 }
6975
6976 pub fn invalidate_inlay_hints<'a>(
6977 &'a mut self,
6978 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6979 ) {
6980 for buffer_id in for_buffers {
6981 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6982 lsp_data.inlay_hints.clear();
6983 }
6984 }
6985 }
6986
6987 pub fn inlay_hints(
6988 &mut self,
6989 invalidate: InvalidationStrategy,
6990 buffer: Entity<Buffer>,
6991 ranges: Vec<Range<text::Anchor>>,
6992 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6993 cx: &mut Context<Self>,
6994 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6995 let next_hint_id = self.next_hint_id.clone();
6996 let lsp_data = self.latest_lsp_data(&buffer, cx);
6997 let query_version = lsp_data.buffer_version.clone();
6998 let mut lsp_refresh_requested = false;
6999 let for_server = if let InvalidationStrategy::RefreshRequested {
7000 server_id,
7001 request_id,
7002 } = invalidate
7003 {
7004 let invalidated = lsp_data
7005 .inlay_hints
7006 .invalidate_for_server_refresh(server_id, request_id);
7007 lsp_refresh_requested = invalidated;
7008 Some(server_id)
7009 } else {
7010 None
7011 };
7012 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7013 let known_chunks = known_chunks
7014 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7015 .map(|(_, known_chunks)| known_chunks)
7016 .unwrap_or_default();
7017
7018 let buffer_snapshot = buffer.read(cx).snapshot();
7019 let ranges = ranges
7020 .iter()
7021 .map(|range| range.to_point(&buffer_snapshot))
7022 .collect::<Vec<_>>();
7023
7024 let mut hint_fetch_tasks = Vec::new();
7025 let mut cached_inlay_hints = None;
7026 let mut ranges_to_query = None;
7027 let applicable_chunks = existing_inlay_hints
7028 .applicable_chunks(ranges.as_slice())
7029 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7030 .collect::<Vec<_>>();
7031 if applicable_chunks.is_empty() {
7032 return HashMap::default();
7033 }
7034
7035 for row_chunk in applicable_chunks {
7036 match (
7037 existing_inlay_hints
7038 .cached_hints(&row_chunk)
7039 .filter(|_| !lsp_refresh_requested)
7040 .cloned(),
7041 existing_inlay_hints
7042 .fetched_hints(&row_chunk)
7043 .as_ref()
7044 .filter(|_| !lsp_refresh_requested)
7045 .cloned(),
7046 ) {
7047 (None, None) => {
7048 let chunk_range = row_chunk.anchor_range();
7049 ranges_to_query
7050 .get_or_insert_with(Vec::new)
7051 .push((row_chunk, chunk_range));
7052 }
7053 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7054 (Some(cached_hints), None) => {
7055 for (server_id, cached_hints) in cached_hints {
7056 if for_server.is_none_or(|for_server| for_server == server_id) {
7057 cached_inlay_hints
7058 .get_or_insert_with(HashMap::default)
7059 .entry(row_chunk.row_range())
7060 .or_insert_with(HashMap::default)
7061 .entry(server_id)
7062 .or_insert_with(Vec::new)
7063 .extend(cached_hints);
7064 }
7065 }
7066 }
7067 (Some(cached_hints), Some(fetched_hints)) => {
7068 hint_fetch_tasks.push((row_chunk, fetched_hints));
7069 for (server_id, cached_hints) in cached_hints {
7070 if for_server.is_none_or(|for_server| for_server == server_id) {
7071 cached_inlay_hints
7072 .get_or_insert_with(HashMap::default)
7073 .entry(row_chunk.row_range())
7074 .or_insert_with(HashMap::default)
7075 .entry(server_id)
7076 .or_insert_with(Vec::new)
7077 .extend(cached_hints);
7078 }
7079 }
7080 }
7081 }
7082 }
7083
7084 if hint_fetch_tasks.is_empty()
7085 && ranges_to_query
7086 .as_ref()
7087 .is_none_or(|ranges| ranges.is_empty())
7088 && let Some(cached_inlay_hints) = cached_inlay_hints
7089 {
7090 cached_inlay_hints
7091 .into_iter()
7092 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7093 .collect()
7094 } else {
7095 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7096 let next_hint_id = next_hint_id.clone();
7097 let buffer = buffer.clone();
7098 let query_version = query_version.clone();
7099 let new_inlay_hints = cx
7100 .spawn(async move |lsp_store, cx| {
7101 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7102 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7103 })?;
7104 new_fetch_task
7105 .await
7106 .and_then(|new_hints_by_server| {
7107 lsp_store.update(cx, |lsp_store, cx| {
7108 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7109 let update_cache = lsp_data.buffer_version == query_version;
7110 if new_hints_by_server.is_empty() {
7111 if update_cache {
7112 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7113 }
7114 HashMap::default()
7115 } else {
7116 new_hints_by_server
7117 .into_iter()
7118 .map(|(server_id, new_hints)| {
7119 let new_hints = new_hints
7120 .into_iter()
7121 .map(|new_hint| {
7122 (
7123 InlayId::Hint(next_hint_id.fetch_add(
7124 1,
7125 atomic::Ordering::AcqRel,
7126 )),
7127 new_hint,
7128 )
7129 })
7130 .collect::<Vec<_>>();
7131 if update_cache {
7132 lsp_data.inlay_hints.insert_new_hints(
7133 chunk,
7134 server_id,
7135 new_hints.clone(),
7136 );
7137 }
7138 (server_id, new_hints)
7139 })
7140 .collect()
7141 }
7142 })
7143 })
7144 .map_err(Arc::new)
7145 })
7146 .shared();
7147
7148 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7149 *fetch_task = Some(new_inlay_hints.clone());
7150 hint_fetch_tasks.push((chunk, new_inlay_hints));
7151 }
7152
7153 cached_inlay_hints
7154 .unwrap_or_default()
7155 .into_iter()
7156 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7157 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7158 (
7159 chunk.row_range(),
7160 cx.spawn(async move |_, _| {
7161 hints_fetch.await.map_err(|e| {
7162 if e.error_code() != ErrorCode::Internal {
7163 anyhow!(e.error_code())
7164 } else {
7165 anyhow!("{e:#}")
7166 }
7167 })
7168 }),
7169 )
7170 }))
7171 .collect()
7172 }
7173 }
7174
7175 fn fetch_inlay_hints(
7176 &mut self,
7177 for_server: Option<LanguageServerId>,
7178 buffer: &Entity<Buffer>,
7179 range: Range<Anchor>,
7180 cx: &mut Context<Self>,
7181 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7182 let request = InlayHints {
7183 range: range.clone(),
7184 };
7185 if let Some((upstream_client, project_id)) = self.upstream_client() {
7186 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7187 return Task::ready(Ok(HashMap::default()));
7188 }
7189 let request_task = upstream_client.request_lsp(
7190 project_id,
7191 for_server.map(|id| id.to_proto()),
7192 LSP_REQUEST_TIMEOUT,
7193 cx.background_executor().clone(),
7194 request.to_proto(project_id, buffer.read(cx)),
7195 );
7196 let buffer = buffer.clone();
7197 cx.spawn(async move |weak_lsp_store, cx| {
7198 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7199 return Ok(HashMap::default());
7200 };
7201 let Some(responses) = request_task.await? else {
7202 return Ok(HashMap::default());
7203 };
7204
7205 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7206 let lsp_store = lsp_store.clone();
7207 let buffer = buffer.clone();
7208 let cx = cx.clone();
7209 let request = request.clone();
7210 async move {
7211 (
7212 LanguageServerId::from_proto(response.server_id),
7213 request
7214 .response_from_proto(response.response, lsp_store, buffer, cx)
7215 .await,
7216 )
7217 }
7218 }))
7219 .await;
7220
7221 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7222 let mut has_errors = false;
7223 let inlay_hints = inlay_hints
7224 .into_iter()
7225 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7226 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7227 Err(e) => {
7228 has_errors = true;
7229 log::error!("{e:#}");
7230 None
7231 }
7232 })
7233 .map(|(server_id, mut new_hints)| {
7234 new_hints.retain(|hint| {
7235 hint.position.is_valid(&buffer_snapshot)
7236 && range.start.is_valid(&buffer_snapshot)
7237 && range.end.is_valid(&buffer_snapshot)
7238 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7239 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7240 });
7241 (server_id, new_hints)
7242 })
7243 .collect::<HashMap<_, _>>();
7244 anyhow::ensure!(
7245 !has_errors || !inlay_hints.is_empty(),
7246 "Failed to fetch inlay hints"
7247 );
7248 Ok(inlay_hints)
7249 })
7250 } else {
7251 let inlay_hints_task = match for_server {
7252 Some(server_id) => {
7253 let server_task = self.request_lsp(
7254 buffer.clone(),
7255 LanguageServerToQuery::Other(server_id),
7256 request,
7257 cx,
7258 );
7259 cx.background_spawn(async move {
7260 let mut responses = Vec::new();
7261 match server_task.await {
7262 Ok(response) => responses.push((server_id, response)),
7263 // rust-analyzer likes to error with this when its still loading up
7264 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7265 Err(e) => log::error!(
7266 "Error handling response for inlay hints request: {e:#}"
7267 ),
7268 }
7269 responses
7270 })
7271 }
7272 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7273 };
7274 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7275 cx.background_spawn(async move {
7276 Ok(inlay_hints_task
7277 .await
7278 .into_iter()
7279 .map(|(server_id, mut new_hints)| {
7280 new_hints.retain(|hint| {
7281 hint.position.is_valid(&buffer_snapshot)
7282 && range.start.is_valid(&buffer_snapshot)
7283 && range.end.is_valid(&buffer_snapshot)
7284 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7285 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7286 });
7287 (server_id, new_hints)
7288 })
7289 .collect())
7290 })
7291 }
7292 }
7293
7294 fn diagnostic_registration_exists(
7295 &self,
7296 server_id: LanguageServerId,
7297 registration_id: &Option<SharedString>,
7298 ) -> bool {
7299 let Some(local) = self.as_local() else {
7300 return false;
7301 };
7302 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7303 else {
7304 return false;
7305 };
7306 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7307 registrations.diagnostics.contains_key(®istration_key)
7308 }
7309
7310 pub fn pull_diagnostics_for_buffer(
7311 &mut self,
7312 buffer: Entity<Buffer>,
7313 cx: &mut Context<Self>,
7314 ) -> Task<anyhow::Result<()>> {
7315 let diagnostics = self.pull_diagnostics(buffer, cx);
7316 cx.spawn(async move |lsp_store, cx| {
7317 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7318 return Ok(());
7319 };
7320 lsp_store.update(cx, |lsp_store, cx| {
7321 if lsp_store.as_local().is_none() {
7322 return;
7323 }
7324
7325 let mut unchanged_buffers = HashMap::default();
7326 let server_diagnostics_updates = diagnostics
7327 .into_iter()
7328 .filter_map(|diagnostics_set| match diagnostics_set {
7329 LspPullDiagnostics::Response {
7330 server_id,
7331 uri,
7332 diagnostics,
7333 registration_id,
7334 } => Some((server_id, uri, diagnostics, registration_id)),
7335 LspPullDiagnostics::Default => None,
7336 })
7337 .filter(|(server_id, _, _, registration_id)| {
7338 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7339 })
7340 .fold(
7341 HashMap::default(),
7342 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7343 let (result_id, diagnostics) = match diagnostics {
7344 PulledDiagnostics::Unchanged { result_id } => {
7345 unchanged_buffers
7346 .entry(new_registration_id.clone())
7347 .or_insert_with(HashSet::default)
7348 .insert(uri.clone());
7349 (Some(result_id), Vec::new())
7350 }
7351 PulledDiagnostics::Changed {
7352 result_id,
7353 diagnostics,
7354 } => (result_id, diagnostics),
7355 };
7356 let disk_based_sources = Cow::Owned(
7357 lsp_store
7358 .language_server_adapter_for_id(server_id)
7359 .as_ref()
7360 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7361 .unwrap_or(&[])
7362 .to_vec(),
7363 );
7364 acc.entry(server_id)
7365 .or_insert_with(HashMap::default)
7366 .entry(new_registration_id.clone())
7367 .or_insert_with(Vec::new)
7368 .push(DocumentDiagnosticsUpdate {
7369 server_id,
7370 diagnostics: lsp::PublishDiagnosticsParams {
7371 uri,
7372 diagnostics,
7373 version: None,
7374 },
7375 result_id,
7376 disk_based_sources,
7377 registration_id: new_registration_id,
7378 });
7379 acc
7380 },
7381 );
7382
7383 for diagnostic_updates in server_diagnostics_updates.into_values() {
7384 for (registration_id, diagnostic_updates) in diagnostic_updates {
7385 lsp_store
7386 .merge_lsp_diagnostics(
7387 DiagnosticSourceKind::Pulled,
7388 diagnostic_updates,
7389 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7390 DiagnosticSourceKind::Pulled => {
7391 old_diagnostic.registration_id != registration_id
7392 || unchanged_buffers
7393 .get(&old_diagnostic.registration_id)
7394 .is_some_and(|unchanged_buffers| {
7395 unchanged_buffers.contains(&document_uri)
7396 })
7397 }
7398 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7399 true
7400 }
7401 },
7402 cx,
7403 )
7404 .log_err();
7405 }
7406 }
7407 })
7408 })
7409 }
7410
7411 pub fn document_colors(
7412 &mut self,
7413 known_cache_version: Option<usize>,
7414 buffer: Entity<Buffer>,
7415 cx: &mut Context<Self>,
7416 ) -> Option<DocumentColorTask> {
7417 let version_queried_for = buffer.read(cx).version();
7418 let buffer_id = buffer.read(cx).remote_id();
7419
7420 let current_language_servers = self.as_local().map(|local| {
7421 local
7422 .buffers_opened_in_servers
7423 .get(&buffer_id)
7424 .cloned()
7425 .unwrap_or_default()
7426 });
7427
7428 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7429 if let Some(cached_colors) = &lsp_data.document_colors {
7430 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7431 let has_different_servers =
7432 current_language_servers.is_some_and(|current_language_servers| {
7433 current_language_servers
7434 != cached_colors.colors.keys().copied().collect()
7435 });
7436 if !has_different_servers {
7437 let cache_version = cached_colors.cache_version;
7438 if Some(cache_version) == known_cache_version {
7439 return None;
7440 } else {
7441 return Some(
7442 Task::ready(Ok(DocumentColors {
7443 colors: cached_colors
7444 .colors
7445 .values()
7446 .flatten()
7447 .cloned()
7448 .collect(),
7449 cache_version: Some(cache_version),
7450 }))
7451 .shared(),
7452 );
7453 }
7454 }
7455 }
7456 }
7457 }
7458
7459 let color_lsp_data = self
7460 .latest_lsp_data(&buffer, cx)
7461 .document_colors
7462 .get_or_insert_default();
7463 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7464 && !version_queried_for.changed_since(updating_for)
7465 {
7466 return Some(running_update.clone());
7467 }
7468 let buffer_version_queried_for = version_queried_for.clone();
7469 let new_task = cx
7470 .spawn(async move |lsp_store, cx| {
7471 cx.background_executor()
7472 .timer(Duration::from_millis(30))
7473 .await;
7474 let fetched_colors = lsp_store
7475 .update(cx, |lsp_store, cx| {
7476 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7477 })?
7478 .await
7479 .context("fetching document colors")
7480 .map_err(Arc::new);
7481 let fetched_colors = match fetched_colors {
7482 Ok(fetched_colors) => {
7483 if buffer.update(cx, |buffer, _| {
7484 buffer.version() != buffer_version_queried_for
7485 }) {
7486 return Ok(DocumentColors::default());
7487 }
7488 fetched_colors
7489 }
7490 Err(e) => {
7491 lsp_store
7492 .update(cx, |lsp_store, _| {
7493 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7494 if let Some(document_colors) = &mut lsp_data.document_colors {
7495 document_colors.colors_update = None;
7496 }
7497 }
7498 })
7499 .ok();
7500 return Err(e);
7501 }
7502 };
7503
7504 lsp_store
7505 .update(cx, |lsp_store, cx| {
7506 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7507 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7508
7509 if let Some(fetched_colors) = fetched_colors {
7510 if lsp_data.buffer_version == buffer_version_queried_for {
7511 lsp_colors.colors.extend(fetched_colors);
7512 lsp_colors.cache_version += 1;
7513 } else if !lsp_data
7514 .buffer_version
7515 .changed_since(&buffer_version_queried_for)
7516 {
7517 lsp_data.buffer_version = buffer_version_queried_for;
7518 lsp_colors.colors = fetched_colors;
7519 lsp_colors.cache_version += 1;
7520 }
7521 }
7522 lsp_colors.colors_update = None;
7523 let colors = lsp_colors
7524 .colors
7525 .values()
7526 .flatten()
7527 .cloned()
7528 .collect::<HashSet<_>>();
7529 DocumentColors {
7530 colors,
7531 cache_version: Some(lsp_colors.cache_version),
7532 }
7533 })
7534 .map_err(Arc::new)
7535 })
7536 .shared();
7537 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7538 Some(new_task)
7539 }
7540
7541 fn fetch_document_colors_for_buffer(
7542 &mut self,
7543 buffer: &Entity<Buffer>,
7544 cx: &mut Context<Self>,
7545 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7546 if let Some((client, project_id)) = self.upstream_client() {
7547 let request = GetDocumentColor {};
7548 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7549 return Task::ready(Ok(None));
7550 }
7551
7552 let request_task = client.request_lsp(
7553 project_id,
7554 None,
7555 LSP_REQUEST_TIMEOUT,
7556 cx.background_executor().clone(),
7557 request.to_proto(project_id, buffer.read(cx)),
7558 );
7559 let buffer = buffer.clone();
7560 cx.spawn(async move |lsp_store, cx| {
7561 let Some(lsp_store) = lsp_store.upgrade() else {
7562 return Ok(None);
7563 };
7564 let colors = join_all(
7565 request_task
7566 .await
7567 .log_err()
7568 .flatten()
7569 .map(|response| response.payload)
7570 .unwrap_or_default()
7571 .into_iter()
7572 .map(|color_response| {
7573 let response = request.response_from_proto(
7574 color_response.response,
7575 lsp_store.clone(),
7576 buffer.clone(),
7577 cx.clone(),
7578 );
7579 async move {
7580 (
7581 LanguageServerId::from_proto(color_response.server_id),
7582 response.await.log_err().unwrap_or_default(),
7583 )
7584 }
7585 }),
7586 )
7587 .await
7588 .into_iter()
7589 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7590 acc.entry(server_id)
7591 .or_insert_with(HashSet::default)
7592 .extend(colors);
7593 acc
7594 });
7595 Ok(Some(colors))
7596 })
7597 } else {
7598 let document_colors_task =
7599 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7600 cx.background_spawn(async move {
7601 Ok(Some(
7602 document_colors_task
7603 .await
7604 .into_iter()
7605 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7606 acc.entry(server_id)
7607 .or_insert_with(HashSet::default)
7608 .extend(colors);
7609 acc
7610 })
7611 .into_iter()
7612 .collect(),
7613 ))
7614 })
7615 }
7616 }
7617
7618 pub fn signature_help<T: ToPointUtf16>(
7619 &mut self,
7620 buffer: &Entity<Buffer>,
7621 position: T,
7622 cx: &mut Context<Self>,
7623 ) -> Task<Option<Vec<SignatureHelp>>> {
7624 let position = position.to_point_utf16(buffer.read(cx));
7625
7626 if let Some((client, upstream_project_id)) = self.upstream_client() {
7627 let request = GetSignatureHelp { position };
7628 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7629 return Task::ready(None);
7630 }
7631 let request_task = client.request_lsp(
7632 upstream_project_id,
7633 None,
7634 LSP_REQUEST_TIMEOUT,
7635 cx.background_executor().clone(),
7636 request.to_proto(upstream_project_id, buffer.read(cx)),
7637 );
7638 let buffer = buffer.clone();
7639 cx.spawn(async move |weak_lsp_store, cx| {
7640 let lsp_store = weak_lsp_store.upgrade()?;
7641 let signatures = join_all(
7642 request_task
7643 .await
7644 .log_err()
7645 .flatten()
7646 .map(|response| response.payload)
7647 .unwrap_or_default()
7648 .into_iter()
7649 .map(|response| {
7650 let response = GetSignatureHelp { position }.response_from_proto(
7651 response.response,
7652 lsp_store.clone(),
7653 buffer.clone(),
7654 cx.clone(),
7655 );
7656 async move { response.await.log_err().flatten() }
7657 }),
7658 )
7659 .await
7660 .into_iter()
7661 .flatten()
7662 .collect();
7663 Some(signatures)
7664 })
7665 } else {
7666 let all_actions_task = self.request_multiple_lsp_locally(
7667 buffer,
7668 Some(position),
7669 GetSignatureHelp { position },
7670 cx,
7671 );
7672 cx.background_spawn(async move {
7673 Some(
7674 all_actions_task
7675 .await
7676 .into_iter()
7677 .flat_map(|(_, actions)| actions)
7678 .collect::<Vec<_>>(),
7679 )
7680 })
7681 }
7682 }
7683
7684 pub fn hover(
7685 &mut self,
7686 buffer: &Entity<Buffer>,
7687 position: PointUtf16,
7688 cx: &mut Context<Self>,
7689 ) -> Task<Option<Vec<Hover>>> {
7690 if let Some((client, upstream_project_id)) = self.upstream_client() {
7691 let request = GetHover { position };
7692 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7693 return Task::ready(None);
7694 }
7695 let request_task = client.request_lsp(
7696 upstream_project_id,
7697 None,
7698 LSP_REQUEST_TIMEOUT,
7699 cx.background_executor().clone(),
7700 request.to_proto(upstream_project_id, buffer.read(cx)),
7701 );
7702 let buffer = buffer.clone();
7703 cx.spawn(async move |weak_lsp_store, cx| {
7704 let lsp_store = weak_lsp_store.upgrade()?;
7705 let hovers = join_all(
7706 request_task
7707 .await
7708 .log_err()
7709 .flatten()
7710 .map(|response| response.payload)
7711 .unwrap_or_default()
7712 .into_iter()
7713 .map(|response| {
7714 let response = GetHover { position }.response_from_proto(
7715 response.response,
7716 lsp_store.clone(),
7717 buffer.clone(),
7718 cx.clone(),
7719 );
7720 async move {
7721 response
7722 .await
7723 .log_err()
7724 .flatten()
7725 .and_then(remove_empty_hover_blocks)
7726 }
7727 }),
7728 )
7729 .await
7730 .into_iter()
7731 .flatten()
7732 .collect();
7733 Some(hovers)
7734 })
7735 } else {
7736 let all_actions_task = self.request_multiple_lsp_locally(
7737 buffer,
7738 Some(position),
7739 GetHover { position },
7740 cx,
7741 );
7742 cx.background_spawn(async move {
7743 Some(
7744 all_actions_task
7745 .await
7746 .into_iter()
7747 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7748 .collect::<Vec<Hover>>(),
7749 )
7750 })
7751 }
7752 }
7753
7754 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7755 let language_registry = self.languages.clone();
7756
7757 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7758 let request = upstream_client.request(proto::GetProjectSymbols {
7759 project_id: *project_id,
7760 query: query.to_string(),
7761 });
7762 cx.foreground_executor().spawn(async move {
7763 let response = request.await?;
7764 let mut symbols = Vec::new();
7765 let core_symbols = response
7766 .symbols
7767 .into_iter()
7768 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7769 .collect::<Vec<_>>();
7770 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7771 .await;
7772 Ok(symbols)
7773 })
7774 } else if let Some(local) = self.as_local() {
7775 struct WorkspaceSymbolsResult {
7776 server_id: LanguageServerId,
7777 lsp_adapter: Arc<CachedLspAdapter>,
7778 worktree: WeakEntity<Worktree>,
7779 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7780 }
7781
7782 let mut requests = Vec::new();
7783 let mut requested_servers = BTreeSet::new();
7784 for (seed, state) in local.language_server_ids.iter() {
7785 let Some(worktree_handle) = self
7786 .worktree_store
7787 .read(cx)
7788 .worktree_for_id(seed.worktree_id, cx)
7789 else {
7790 continue;
7791 };
7792 let worktree = worktree_handle.read(cx);
7793 if !worktree.is_visible() {
7794 continue;
7795 }
7796
7797 if !requested_servers.insert(state.id) {
7798 continue;
7799 }
7800
7801 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7802 Some(LanguageServerState::Running {
7803 adapter, server, ..
7804 }) => (adapter.clone(), server),
7805
7806 _ => continue,
7807 };
7808 let supports_workspace_symbol_request =
7809 match server.capabilities().workspace_symbol_provider {
7810 Some(OneOf::Left(supported)) => supported,
7811 Some(OneOf::Right(_)) => true,
7812 None => false,
7813 };
7814 if !supports_workspace_symbol_request {
7815 continue;
7816 }
7817 let worktree_handle = worktree_handle.clone();
7818 let server_id = server.server_id();
7819 requests.push(
7820 server
7821 .request::<lsp::request::WorkspaceSymbolRequest>(
7822 lsp::WorkspaceSymbolParams {
7823 query: query.to_string(),
7824 ..Default::default()
7825 },
7826 )
7827 .map(move |response| {
7828 let lsp_symbols = response
7829 .into_response()
7830 .context("workspace symbols request")
7831 .log_err()
7832 .flatten()
7833 .map(|symbol_response| match symbol_response {
7834 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7835 flat_responses
7836 .into_iter()
7837 .map(|lsp_symbol| {
7838 (
7839 lsp_symbol.name,
7840 lsp_symbol.kind,
7841 lsp_symbol.location,
7842 )
7843 })
7844 .collect::<Vec<_>>()
7845 }
7846 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7847 nested_responses
7848 .into_iter()
7849 .filter_map(|lsp_symbol| {
7850 let location = match lsp_symbol.location {
7851 OneOf::Left(location) => location,
7852 OneOf::Right(_) => {
7853 log::error!(
7854 "Unexpected: client capabilities \
7855 forbid symbol resolutions in \
7856 workspace.symbol.resolveSupport"
7857 );
7858 return None;
7859 }
7860 };
7861 Some((lsp_symbol.name, lsp_symbol.kind, location))
7862 })
7863 .collect::<Vec<_>>()
7864 }
7865 })
7866 .unwrap_or_default();
7867
7868 WorkspaceSymbolsResult {
7869 server_id,
7870 lsp_adapter,
7871 worktree: worktree_handle.downgrade(),
7872 lsp_symbols,
7873 }
7874 }),
7875 );
7876 }
7877
7878 cx.spawn(async move |this, cx| {
7879 let responses = futures::future::join_all(requests).await;
7880 let this = match this.upgrade() {
7881 Some(this) => this,
7882 None => return Ok(Vec::new()),
7883 };
7884
7885 let mut symbols = Vec::new();
7886 for result in responses {
7887 let core_symbols = this.update(cx, |this, cx| {
7888 result
7889 .lsp_symbols
7890 .into_iter()
7891 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7892 let abs_path = symbol_location.uri.to_file_path().ok()?;
7893 let source_worktree = result.worktree.upgrade()?;
7894 let source_worktree_id = source_worktree.read(cx).id();
7895
7896 let path = if let Some((tree, rel_path)) =
7897 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7898 {
7899 let worktree_id = tree.read(cx).id();
7900 SymbolLocation::InProject(ProjectPath {
7901 worktree_id,
7902 path: rel_path,
7903 })
7904 } else {
7905 SymbolLocation::OutsideProject {
7906 signature: this.symbol_signature(&abs_path),
7907 abs_path: abs_path.into(),
7908 }
7909 };
7910
7911 Some(CoreSymbol {
7912 source_language_server_id: result.server_id,
7913 language_server_name: result.lsp_adapter.name.clone(),
7914 source_worktree_id,
7915 path,
7916 kind: symbol_kind,
7917 name: symbol_name,
7918 range: range_from_lsp(symbol_location.range),
7919 })
7920 })
7921 .collect::<Vec<_>>()
7922 });
7923
7924 populate_labels_for_symbols(
7925 core_symbols,
7926 &language_registry,
7927 Some(result.lsp_adapter),
7928 &mut symbols,
7929 )
7930 .await;
7931 }
7932
7933 Ok(symbols)
7934 })
7935 } else {
7936 Task::ready(Err(anyhow!("No upstream client or local language server")))
7937 }
7938 }
7939
7940 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7941 let mut summary = DiagnosticSummary::default();
7942 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7943 summary.error_count += path_summary.error_count;
7944 summary.warning_count += path_summary.warning_count;
7945 }
7946 summary
7947 }
7948
7949 /// Returns the diagnostic summary for a specific project path.
7950 pub fn diagnostic_summary_for_path(
7951 &self,
7952 project_path: &ProjectPath,
7953 _: &App,
7954 ) -> DiagnosticSummary {
7955 if let Some(summaries) = self
7956 .diagnostic_summaries
7957 .get(&project_path.worktree_id)
7958 .and_then(|map| map.get(&project_path.path))
7959 {
7960 let (error_count, warning_count) = summaries.iter().fold(
7961 (0, 0),
7962 |(error_count, warning_count), (_language_server_id, summary)| {
7963 (
7964 error_count + summary.error_count,
7965 warning_count + summary.warning_count,
7966 )
7967 },
7968 );
7969
7970 DiagnosticSummary {
7971 error_count,
7972 warning_count,
7973 }
7974 } else {
7975 DiagnosticSummary::default()
7976 }
7977 }
7978
7979 pub fn diagnostic_summaries<'a>(
7980 &'a self,
7981 include_ignored: bool,
7982 cx: &'a App,
7983 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7984 self.worktree_store
7985 .read(cx)
7986 .visible_worktrees(cx)
7987 .filter_map(|worktree| {
7988 let worktree = worktree.read(cx);
7989 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7990 })
7991 .flat_map(move |(worktree, summaries)| {
7992 let worktree_id = worktree.id();
7993 summaries
7994 .iter()
7995 .filter(move |(path, _)| {
7996 include_ignored
7997 || worktree
7998 .entry_for_path(path.as_ref())
7999 .is_some_and(|entry| !entry.is_ignored)
8000 })
8001 .flat_map(move |(path, summaries)| {
8002 summaries.iter().map(move |(server_id, summary)| {
8003 (
8004 ProjectPath {
8005 worktree_id,
8006 path: path.clone(),
8007 },
8008 *server_id,
8009 *summary,
8010 )
8011 })
8012 })
8013 })
8014 }
8015
8016 pub fn on_buffer_edited(
8017 &mut self,
8018 buffer: Entity<Buffer>,
8019 cx: &mut Context<Self>,
8020 ) -> Option<()> {
8021 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8022 Some(
8023 self.as_local()?
8024 .language_servers_for_buffer(buffer, cx)
8025 .map(|i| i.1.clone())
8026 .collect(),
8027 )
8028 })?;
8029
8030 let buffer = buffer.read(cx);
8031 let file = File::from_dyn(buffer.file())?;
8032 let abs_path = file.as_local()?.abs_path(cx);
8033 let uri = lsp::Uri::from_file_path(&abs_path)
8034 .ok()
8035 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8036 .log_err()?;
8037 let next_snapshot = buffer.text_snapshot();
8038 for language_server in language_servers {
8039 let language_server = language_server.clone();
8040
8041 let buffer_snapshots = self
8042 .as_local_mut()?
8043 .buffer_snapshots
8044 .get_mut(&buffer.remote_id())
8045 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8046 let previous_snapshot = buffer_snapshots.last()?;
8047
8048 let build_incremental_change = || {
8049 buffer
8050 .edits_since::<Dimensions<PointUtf16, usize>>(
8051 previous_snapshot.snapshot.version(),
8052 )
8053 .map(|edit| {
8054 let edit_start = edit.new.start.0;
8055 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8056 let new_text = next_snapshot
8057 .text_for_range(edit.new.start.1..edit.new.end.1)
8058 .collect();
8059 lsp::TextDocumentContentChangeEvent {
8060 range: Some(lsp::Range::new(
8061 point_to_lsp(edit_start),
8062 point_to_lsp(edit_end),
8063 )),
8064 range_length: None,
8065 text: new_text,
8066 }
8067 })
8068 .collect()
8069 };
8070
8071 let document_sync_kind = language_server
8072 .capabilities()
8073 .text_document_sync
8074 .as_ref()
8075 .and_then(|sync| match sync {
8076 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8077 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8078 });
8079
8080 let content_changes: Vec<_> = match document_sync_kind {
8081 Some(lsp::TextDocumentSyncKind::FULL) => {
8082 vec![lsp::TextDocumentContentChangeEvent {
8083 range: None,
8084 range_length: None,
8085 text: next_snapshot.text(),
8086 }]
8087 }
8088 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8089 _ => {
8090 #[cfg(any(test, feature = "test-support"))]
8091 {
8092 build_incremental_change()
8093 }
8094
8095 #[cfg(not(any(test, feature = "test-support")))]
8096 {
8097 continue;
8098 }
8099 }
8100 };
8101
8102 let next_version = previous_snapshot.version + 1;
8103 buffer_snapshots.push(LspBufferSnapshot {
8104 version: next_version,
8105 snapshot: next_snapshot.clone(),
8106 });
8107
8108 language_server
8109 .notify::<lsp::notification::DidChangeTextDocument>(
8110 lsp::DidChangeTextDocumentParams {
8111 text_document: lsp::VersionedTextDocumentIdentifier::new(
8112 uri.clone(),
8113 next_version,
8114 ),
8115 content_changes,
8116 },
8117 )
8118 .ok();
8119 self.pull_workspace_diagnostics(language_server.server_id());
8120 }
8121
8122 None
8123 }
8124
8125 pub fn on_buffer_saved(
8126 &mut self,
8127 buffer: Entity<Buffer>,
8128 cx: &mut Context<Self>,
8129 ) -> Option<()> {
8130 let file = File::from_dyn(buffer.read(cx).file())?;
8131 let worktree_id = file.worktree_id(cx);
8132 let abs_path = file.as_local()?.abs_path(cx);
8133 let text_document = lsp::TextDocumentIdentifier {
8134 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8135 };
8136 let local = self.as_local()?;
8137
8138 for server in local.language_servers_for_worktree(worktree_id) {
8139 if let Some(include_text) = include_text(server.as_ref()) {
8140 let text = if include_text {
8141 Some(buffer.read(cx).text())
8142 } else {
8143 None
8144 };
8145 server
8146 .notify::<lsp::notification::DidSaveTextDocument>(
8147 lsp::DidSaveTextDocumentParams {
8148 text_document: text_document.clone(),
8149 text,
8150 },
8151 )
8152 .ok();
8153 }
8154 }
8155
8156 let language_servers = buffer.update(cx, |buffer, cx| {
8157 local.language_server_ids_for_buffer(buffer, cx)
8158 });
8159 for language_server_id in language_servers {
8160 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8161 }
8162
8163 None
8164 }
8165
8166 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8167 maybe!(async move {
8168 let mut refreshed_servers = HashSet::default();
8169 let servers = lsp_store
8170 .update(cx, |lsp_store, cx| {
8171 let local = lsp_store.as_local()?;
8172
8173 let servers = local
8174 .language_server_ids
8175 .iter()
8176 .filter_map(|(seed, state)| {
8177 let worktree = lsp_store
8178 .worktree_store
8179 .read(cx)
8180 .worktree_for_id(seed.worktree_id, cx);
8181 let delegate: Arc<dyn LspAdapterDelegate> =
8182 worktree.map(|worktree| {
8183 LocalLspAdapterDelegate::new(
8184 local.languages.clone(),
8185 &local.environment,
8186 cx.weak_entity(),
8187 &worktree,
8188 local.http_client.clone(),
8189 local.fs.clone(),
8190 cx,
8191 )
8192 })?;
8193 let server_id = state.id;
8194
8195 let states = local.language_servers.get(&server_id)?;
8196
8197 match states {
8198 LanguageServerState::Starting { .. } => None,
8199 LanguageServerState::Running {
8200 adapter, server, ..
8201 } => {
8202 let adapter = adapter.clone();
8203 let server = server.clone();
8204 refreshed_servers.insert(server.name());
8205 let toolchain = seed.toolchain.clone();
8206 Some(cx.spawn(async move |_, cx| {
8207 let settings =
8208 LocalLspStore::workspace_configuration_for_adapter(
8209 adapter.adapter.clone(),
8210 &delegate,
8211 toolchain,
8212 None,
8213 cx,
8214 )
8215 .await
8216 .ok()?;
8217 server
8218 .notify::<lsp::notification::DidChangeConfiguration>(
8219 lsp::DidChangeConfigurationParams { settings },
8220 )
8221 .ok()?;
8222 Some(())
8223 }))
8224 }
8225 }
8226 })
8227 .collect::<Vec<_>>();
8228
8229 Some(servers)
8230 })
8231 .ok()
8232 .flatten()?;
8233
8234 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8235 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8236 // to stop and unregister its language server wrapper.
8237 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8238 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8239 let _: Vec<Option<()>> = join_all(servers).await;
8240
8241 Some(())
8242 })
8243 .await;
8244 }
8245
8246 fn maintain_workspace_config(
8247 external_refresh_requests: watch::Receiver<()>,
8248 cx: &mut Context<Self>,
8249 ) -> Task<Result<()>> {
8250 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8251 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8252
8253 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8254 *settings_changed_tx.borrow_mut() = ();
8255 });
8256
8257 let mut joint_future =
8258 futures::stream::select(settings_changed_rx, external_refresh_requests);
8259 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8260 // - 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).
8261 // - 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.
8262 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8263 // - 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,
8264 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8265 cx.spawn(async move |this, cx| {
8266 while let Some(()) = joint_future.next().await {
8267 this.update(cx, |this, cx| {
8268 this.refresh_server_tree(cx);
8269 })
8270 .ok();
8271
8272 Self::refresh_workspace_configurations(&this, cx).await;
8273 }
8274
8275 drop(settings_observation);
8276 anyhow::Ok(())
8277 })
8278 }
8279
8280 pub fn running_language_servers_for_local_buffer<'a>(
8281 &'a self,
8282 buffer: &Buffer,
8283 cx: &mut App,
8284 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8285 let local = self.as_local();
8286 let language_server_ids = local
8287 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8288 .unwrap_or_default();
8289
8290 language_server_ids
8291 .into_iter()
8292 .filter_map(
8293 move |server_id| match local?.language_servers.get(&server_id)? {
8294 LanguageServerState::Running {
8295 adapter, server, ..
8296 } => Some((adapter, server)),
8297 _ => None,
8298 },
8299 )
8300 }
8301
8302 pub fn language_servers_for_local_buffer(
8303 &self,
8304 buffer: &Buffer,
8305 cx: &mut App,
8306 ) -> Vec<LanguageServerId> {
8307 let local = self.as_local();
8308 local
8309 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8310 .unwrap_or_default()
8311 }
8312
8313 pub fn language_server_for_local_buffer<'a>(
8314 &'a self,
8315 buffer: &'a Buffer,
8316 server_id: LanguageServerId,
8317 cx: &'a mut App,
8318 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8319 self.as_local()?
8320 .language_servers_for_buffer(buffer, cx)
8321 .find(|(_, s)| s.server_id() == server_id)
8322 }
8323
8324 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8325 self.diagnostic_summaries.remove(&id_to_remove);
8326 if let Some(local) = self.as_local_mut() {
8327 let to_remove = local.remove_worktree(id_to_remove, cx);
8328 for server in to_remove {
8329 self.language_server_statuses.remove(&server);
8330 }
8331 }
8332 }
8333
8334 pub fn shared(
8335 &mut self,
8336 project_id: u64,
8337 downstream_client: AnyProtoClient,
8338 _: &mut Context<Self>,
8339 ) {
8340 self.downstream_client = Some((downstream_client.clone(), project_id));
8341
8342 for (server_id, status) in &self.language_server_statuses {
8343 if let Some(server) = self.language_server_for_id(*server_id) {
8344 downstream_client
8345 .send(proto::StartLanguageServer {
8346 project_id,
8347 server: Some(proto::LanguageServer {
8348 id: server_id.to_proto(),
8349 name: status.name.to_string(),
8350 worktree_id: status.worktree.map(|id| id.to_proto()),
8351 }),
8352 capabilities: serde_json::to_string(&server.capabilities())
8353 .expect("serializing server LSP capabilities"),
8354 })
8355 .log_err();
8356 }
8357 }
8358 }
8359
8360 pub fn disconnected_from_host(&mut self) {
8361 self.downstream_client.take();
8362 }
8363
8364 pub fn disconnected_from_ssh_remote(&mut self) {
8365 if let LspStoreMode::Remote(RemoteLspStore {
8366 upstream_client, ..
8367 }) = &mut self.mode
8368 {
8369 upstream_client.take();
8370 }
8371 }
8372
8373 pub(crate) fn set_language_server_statuses_from_proto(
8374 &mut self,
8375 project: WeakEntity<Project>,
8376 language_servers: Vec<proto::LanguageServer>,
8377 server_capabilities: Vec<String>,
8378 cx: &mut Context<Self>,
8379 ) {
8380 let lsp_logs = cx
8381 .try_global::<GlobalLogStore>()
8382 .map(|lsp_store| lsp_store.0.clone());
8383
8384 self.language_server_statuses = language_servers
8385 .into_iter()
8386 .zip(server_capabilities)
8387 .map(|(server, server_capabilities)| {
8388 let server_id = LanguageServerId(server.id as usize);
8389 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8390 self.lsp_server_capabilities
8391 .insert(server_id, server_capabilities);
8392 }
8393
8394 let name = LanguageServerName::from_proto(server.name);
8395 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8396
8397 if let Some(lsp_logs) = &lsp_logs {
8398 lsp_logs.update(cx, |lsp_logs, cx| {
8399 lsp_logs.add_language_server(
8400 // Only remote clients get their language servers set from proto
8401 LanguageServerKind::Remote {
8402 project: project.clone(),
8403 },
8404 server_id,
8405 Some(name.clone()),
8406 worktree,
8407 None,
8408 cx,
8409 );
8410 });
8411 }
8412
8413 (
8414 server_id,
8415 LanguageServerStatus {
8416 name,
8417 server_version: None,
8418 pending_work: Default::default(),
8419 has_pending_diagnostic_updates: false,
8420 progress_tokens: Default::default(),
8421 worktree,
8422 binary: None,
8423 configuration: None,
8424 workspace_folders: BTreeSet::new(),
8425 },
8426 )
8427 })
8428 .collect();
8429 }
8430
8431 #[cfg(test)]
8432 pub fn update_diagnostic_entries(
8433 &mut self,
8434 server_id: LanguageServerId,
8435 abs_path: PathBuf,
8436 result_id: Option<SharedString>,
8437 version: Option<i32>,
8438 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8439 cx: &mut Context<Self>,
8440 ) -> anyhow::Result<()> {
8441 self.merge_diagnostic_entries(
8442 vec![DocumentDiagnosticsUpdate {
8443 diagnostics: DocumentDiagnostics {
8444 diagnostics,
8445 document_abs_path: abs_path,
8446 version,
8447 },
8448 result_id,
8449 server_id,
8450 disk_based_sources: Cow::Borrowed(&[]),
8451 registration_id: None,
8452 }],
8453 |_, _, _| false,
8454 cx,
8455 )?;
8456 Ok(())
8457 }
8458
8459 pub fn merge_diagnostic_entries<'a>(
8460 &mut self,
8461 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8462 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8463 cx: &mut Context<Self>,
8464 ) -> anyhow::Result<()> {
8465 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8466 let mut updated_diagnostics_paths = HashMap::default();
8467 for mut update in diagnostic_updates {
8468 let abs_path = &update.diagnostics.document_abs_path;
8469 let server_id = update.server_id;
8470 let Some((worktree, relative_path)) =
8471 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8472 else {
8473 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8474 return Ok(());
8475 };
8476
8477 let worktree_id = worktree.read(cx).id();
8478 let project_path = ProjectPath {
8479 worktree_id,
8480 path: relative_path,
8481 };
8482
8483 let document_uri = lsp::Uri::from_file_path(abs_path)
8484 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8485 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8486 let snapshot = buffer_handle.read(cx).snapshot();
8487 let buffer = buffer_handle.read(cx);
8488 let reused_diagnostics = buffer
8489 .buffer_diagnostics(Some(server_id))
8490 .iter()
8491 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8492 .map(|v| {
8493 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8494 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8495 DiagnosticEntry {
8496 range: start..end,
8497 diagnostic: v.diagnostic.clone(),
8498 }
8499 })
8500 .collect::<Vec<_>>();
8501
8502 self.as_local_mut()
8503 .context("cannot merge diagnostics on a remote LspStore")?
8504 .update_buffer_diagnostics(
8505 &buffer_handle,
8506 server_id,
8507 Some(update.registration_id),
8508 update.result_id,
8509 update.diagnostics.version,
8510 update.diagnostics.diagnostics.clone(),
8511 reused_diagnostics.clone(),
8512 cx,
8513 )?;
8514
8515 update.diagnostics.diagnostics.extend(reused_diagnostics);
8516 } else if let Some(local) = self.as_local() {
8517 let reused_diagnostics = local
8518 .diagnostics
8519 .get(&worktree_id)
8520 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8521 .and_then(|diagnostics_by_server_id| {
8522 diagnostics_by_server_id
8523 .binary_search_by_key(&server_id, |e| e.0)
8524 .ok()
8525 .map(|ix| &diagnostics_by_server_id[ix].1)
8526 })
8527 .into_iter()
8528 .flatten()
8529 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8530
8531 update
8532 .diagnostics
8533 .diagnostics
8534 .extend(reused_diagnostics.cloned());
8535 }
8536
8537 let updated = worktree.update(cx, |worktree, cx| {
8538 self.update_worktree_diagnostics(
8539 worktree.id(),
8540 server_id,
8541 project_path.path.clone(),
8542 update.diagnostics.diagnostics,
8543 cx,
8544 )
8545 })?;
8546 match updated {
8547 ControlFlow::Continue(new_summary) => {
8548 if let Some((project_id, new_summary)) = new_summary {
8549 match &mut diagnostics_summary {
8550 Some(diagnostics_summary) => {
8551 diagnostics_summary
8552 .more_summaries
8553 .push(proto::DiagnosticSummary {
8554 path: project_path.path.as_ref().to_proto(),
8555 language_server_id: server_id.0 as u64,
8556 error_count: new_summary.error_count,
8557 warning_count: new_summary.warning_count,
8558 })
8559 }
8560 None => {
8561 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8562 project_id,
8563 worktree_id: worktree_id.to_proto(),
8564 summary: Some(proto::DiagnosticSummary {
8565 path: project_path.path.as_ref().to_proto(),
8566 language_server_id: server_id.0 as u64,
8567 error_count: new_summary.error_count,
8568 warning_count: new_summary.warning_count,
8569 }),
8570 more_summaries: Vec::new(),
8571 })
8572 }
8573 }
8574 }
8575 updated_diagnostics_paths
8576 .entry(server_id)
8577 .or_insert_with(Vec::new)
8578 .push(project_path);
8579 }
8580 ControlFlow::Break(()) => {}
8581 }
8582 }
8583
8584 if let Some((diagnostics_summary, (downstream_client, _))) =
8585 diagnostics_summary.zip(self.downstream_client.as_ref())
8586 {
8587 downstream_client.send(diagnostics_summary).log_err();
8588 }
8589 for (server_id, paths) in updated_diagnostics_paths {
8590 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8591 }
8592 Ok(())
8593 }
8594
8595 fn update_worktree_diagnostics(
8596 &mut self,
8597 worktree_id: WorktreeId,
8598 server_id: LanguageServerId,
8599 path_in_worktree: Arc<RelPath>,
8600 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8601 _: &mut Context<Worktree>,
8602 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8603 let local = match &mut self.mode {
8604 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8605 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8606 };
8607
8608 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8609 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8610 let summaries_by_server_id = summaries_for_tree
8611 .entry(path_in_worktree.clone())
8612 .or_default();
8613
8614 let old_summary = summaries_by_server_id
8615 .remove(&server_id)
8616 .unwrap_or_default();
8617
8618 let new_summary = DiagnosticSummary::new(&diagnostics);
8619 if diagnostics.is_empty() {
8620 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8621 {
8622 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8623 diagnostics_by_server_id.remove(ix);
8624 }
8625 if diagnostics_by_server_id.is_empty() {
8626 diagnostics_for_tree.remove(&path_in_worktree);
8627 }
8628 }
8629 } else {
8630 summaries_by_server_id.insert(server_id, new_summary);
8631 let diagnostics_by_server_id = diagnostics_for_tree
8632 .entry(path_in_worktree.clone())
8633 .or_default();
8634 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8635 Ok(ix) => {
8636 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8637 }
8638 Err(ix) => {
8639 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8640 }
8641 }
8642 }
8643
8644 if !old_summary.is_empty() || !new_summary.is_empty() {
8645 if let Some((_, project_id)) = &self.downstream_client {
8646 Ok(ControlFlow::Continue(Some((
8647 *project_id,
8648 proto::DiagnosticSummary {
8649 path: path_in_worktree.to_proto(),
8650 language_server_id: server_id.0 as u64,
8651 error_count: new_summary.error_count as u32,
8652 warning_count: new_summary.warning_count as u32,
8653 },
8654 ))))
8655 } else {
8656 Ok(ControlFlow::Continue(None))
8657 }
8658 } else {
8659 Ok(ControlFlow::Break(()))
8660 }
8661 }
8662
8663 pub fn open_buffer_for_symbol(
8664 &mut self,
8665 symbol: &Symbol,
8666 cx: &mut Context<Self>,
8667 ) -> Task<Result<Entity<Buffer>>> {
8668 if let Some((client, project_id)) = self.upstream_client() {
8669 let request = client.request(proto::OpenBufferForSymbol {
8670 project_id,
8671 symbol: Some(Self::serialize_symbol(symbol)),
8672 });
8673 cx.spawn(async move |this, cx| {
8674 let response = request.await?;
8675 let buffer_id = BufferId::new(response.buffer_id)?;
8676 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8677 .await
8678 })
8679 } else if let Some(local) = self.as_local() {
8680 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8681 seed.worktree_id == symbol.source_worktree_id
8682 && state.id == symbol.source_language_server_id
8683 && symbol.language_server_name == seed.name
8684 });
8685 if !is_valid {
8686 return Task::ready(Err(anyhow!(
8687 "language server for worktree and language not found"
8688 )));
8689 };
8690
8691 let symbol_abs_path = match &symbol.path {
8692 SymbolLocation::InProject(project_path) => self
8693 .worktree_store
8694 .read(cx)
8695 .absolutize(&project_path, cx)
8696 .context("no such worktree"),
8697 SymbolLocation::OutsideProject {
8698 abs_path,
8699 signature: _,
8700 } => Ok(abs_path.to_path_buf()),
8701 };
8702 let symbol_abs_path = match symbol_abs_path {
8703 Ok(abs_path) => abs_path,
8704 Err(err) => return Task::ready(Err(err)),
8705 };
8706 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8707 uri
8708 } else {
8709 return Task::ready(Err(anyhow!("invalid symbol path")));
8710 };
8711
8712 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8713 } else {
8714 Task::ready(Err(anyhow!("no upstream client or local store")))
8715 }
8716 }
8717
8718 pub(crate) fn open_local_buffer_via_lsp(
8719 &mut self,
8720 abs_path: lsp::Uri,
8721 language_server_id: LanguageServerId,
8722 cx: &mut Context<Self>,
8723 ) -> Task<Result<Entity<Buffer>>> {
8724 cx.spawn(async move |lsp_store, cx| {
8725 // Escape percent-encoded string.
8726 let current_scheme = abs_path.scheme().to_owned();
8727 // Uri is immutable, so we can't modify the scheme
8728
8729 let abs_path = abs_path
8730 .to_file_path()
8731 .map_err(|()| anyhow!("can't convert URI to path"))?;
8732 let p = abs_path.clone();
8733 let yarn_worktree = lsp_store
8734 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8735 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8736 cx.spawn(async move |this, cx| {
8737 let t = this
8738 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8739 .ok()?;
8740 t.await
8741 })
8742 }),
8743 None => Task::ready(None),
8744 })?
8745 .await;
8746 let (worktree_root_target, known_relative_path) =
8747 if let Some((zip_root, relative_path)) = yarn_worktree {
8748 (zip_root, Some(relative_path))
8749 } else {
8750 (Arc::<Path>::from(abs_path.as_path()), None)
8751 };
8752 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8753 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8754 worktree_store.find_worktree(&worktree_root_target, cx)
8755 })
8756 })?;
8757 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8758 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8759 (result.0, relative_path, None)
8760 } else {
8761 let worktree = lsp_store
8762 .update(cx, |lsp_store, cx| {
8763 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8764 worktree_store.create_worktree(&worktree_root_target, false, cx)
8765 })
8766 })?
8767 .await?;
8768 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8769 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8770 lsp_store
8771 .update(cx, |lsp_store, cx| {
8772 if let Some(local) = lsp_store.as_local_mut() {
8773 local.register_language_server_for_invisible_worktree(
8774 &worktree,
8775 language_server_id,
8776 cx,
8777 )
8778 }
8779 match lsp_store.language_server_statuses.get(&language_server_id) {
8780 Some(status) => status.worktree,
8781 None => None,
8782 }
8783 })
8784 .ok()
8785 .flatten()
8786 .zip(Some(worktree_root.clone()))
8787 } else {
8788 None
8789 };
8790 let relative_path = if let Some(known_path) = known_relative_path {
8791 known_path
8792 } else {
8793 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8794 .into_arc()
8795 };
8796 (worktree, relative_path, source_ws)
8797 };
8798 let project_path = ProjectPath {
8799 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8800 path: relative_path,
8801 };
8802 let buffer = lsp_store
8803 .update(cx, |lsp_store, cx| {
8804 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8805 buffer_store.open_buffer(project_path, cx)
8806 })
8807 })?
8808 .await?;
8809 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8810 if let Some((source_ws, worktree_root)) = source_ws {
8811 buffer.update(cx, |buffer, cx| {
8812 let settings = WorktreeSettings::get(
8813 Some(
8814 (&ProjectPath {
8815 worktree_id: source_ws,
8816 path: Arc::from(RelPath::empty()),
8817 })
8818 .into(),
8819 ),
8820 cx,
8821 );
8822 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8823 if is_read_only {
8824 buffer.set_capability(Capability::ReadOnly, cx);
8825 }
8826 });
8827 }
8828 Ok(buffer)
8829 })
8830 }
8831
8832 fn request_multiple_lsp_locally<P, R>(
8833 &mut self,
8834 buffer: &Entity<Buffer>,
8835 position: Option<P>,
8836 request: R,
8837 cx: &mut Context<Self>,
8838 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8839 where
8840 P: ToOffset,
8841 R: LspCommand + Clone,
8842 <R::LspRequest as lsp::request::Request>::Result: Send,
8843 <R::LspRequest as lsp::request::Request>::Params: Send,
8844 {
8845 let Some(local) = self.as_local() else {
8846 return Task::ready(Vec::new());
8847 };
8848
8849 let snapshot = buffer.read(cx).snapshot();
8850 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8851
8852 let server_ids = buffer.update(cx, |buffer, cx| {
8853 local
8854 .language_servers_for_buffer(buffer, cx)
8855 .filter(|(adapter, _)| {
8856 scope
8857 .as_ref()
8858 .map(|scope| scope.language_allowed(&adapter.name))
8859 .unwrap_or(true)
8860 })
8861 .map(|(_, server)| server.server_id())
8862 .filter(|server_id| {
8863 self.as_local().is_none_or(|local| {
8864 local
8865 .buffers_opened_in_servers
8866 .get(&snapshot.remote_id())
8867 .is_some_and(|servers| servers.contains(server_id))
8868 })
8869 })
8870 .collect::<Vec<_>>()
8871 });
8872
8873 let mut response_results = server_ids
8874 .into_iter()
8875 .map(|server_id| {
8876 let task = self.request_lsp(
8877 buffer.clone(),
8878 LanguageServerToQuery::Other(server_id),
8879 request.clone(),
8880 cx,
8881 );
8882 async move { (server_id, task.await) }
8883 })
8884 .collect::<FuturesUnordered<_>>();
8885
8886 cx.background_spawn(async move {
8887 let mut responses = Vec::with_capacity(response_results.len());
8888 while let Some((server_id, response_result)) = response_results.next().await {
8889 match response_result {
8890 Ok(response) => responses.push((server_id, response)),
8891 // rust-analyzer likes to error with this when its still loading up
8892 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8893 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8894 }
8895 }
8896 responses
8897 })
8898 }
8899
8900 async fn handle_lsp_get_completions(
8901 this: Entity<Self>,
8902 envelope: TypedEnvelope<proto::GetCompletions>,
8903 mut cx: AsyncApp,
8904 ) -> Result<proto::GetCompletionsResponse> {
8905 let sender_id = envelope.original_sender_id().unwrap_or_default();
8906
8907 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8908 let buffer_handle = this.update(&mut cx, |this, cx| {
8909 this.buffer_store.read(cx).get_existing(buffer_id)
8910 })?;
8911 let request = GetCompletions::from_proto(
8912 envelope.payload,
8913 this.clone(),
8914 buffer_handle.clone(),
8915 cx.clone(),
8916 )
8917 .await?;
8918
8919 let server_to_query = match request.server_id {
8920 Some(server_id) => LanguageServerToQuery::Other(server_id),
8921 None => LanguageServerToQuery::FirstCapable,
8922 };
8923
8924 let response = this
8925 .update(&mut cx, |this, cx| {
8926 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8927 })
8928 .await?;
8929 this.update(&mut cx, |this, cx| {
8930 Ok(GetCompletions::response_to_proto(
8931 response,
8932 this,
8933 sender_id,
8934 &buffer_handle.read(cx).version(),
8935 cx,
8936 ))
8937 })
8938 }
8939
8940 async fn handle_lsp_command<T: LspCommand>(
8941 this: Entity<Self>,
8942 envelope: TypedEnvelope<T::ProtoRequest>,
8943 mut cx: AsyncApp,
8944 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8945 where
8946 <T::LspRequest as lsp::request::Request>::Params: Send,
8947 <T::LspRequest as lsp::request::Request>::Result: Send,
8948 {
8949 let sender_id = envelope.original_sender_id().unwrap_or_default();
8950 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8951 let buffer_handle = this.update(&mut cx, |this, cx| {
8952 this.buffer_store.read(cx).get_existing(buffer_id)
8953 })?;
8954 let request = T::from_proto(
8955 envelope.payload,
8956 this.clone(),
8957 buffer_handle.clone(),
8958 cx.clone(),
8959 )
8960 .await?;
8961 let response = this
8962 .update(&mut cx, |this, cx| {
8963 this.request_lsp(
8964 buffer_handle.clone(),
8965 LanguageServerToQuery::FirstCapable,
8966 request,
8967 cx,
8968 )
8969 })
8970 .await?;
8971 this.update(&mut cx, |this, cx| {
8972 Ok(T::response_to_proto(
8973 response,
8974 this,
8975 sender_id,
8976 &buffer_handle.read(cx).version(),
8977 cx,
8978 ))
8979 })
8980 }
8981
8982 async fn handle_lsp_query(
8983 lsp_store: Entity<Self>,
8984 envelope: TypedEnvelope<proto::LspQuery>,
8985 mut cx: AsyncApp,
8986 ) -> Result<proto::Ack> {
8987 use proto::lsp_query::Request;
8988 let sender_id = envelope.original_sender_id().unwrap_or_default();
8989 let lsp_query = envelope.payload;
8990 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8991 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8992 match lsp_query.request.context("invalid LSP query request")? {
8993 Request::GetReferences(get_references) => {
8994 let position = get_references.position.clone().and_then(deserialize_anchor);
8995 Self::query_lsp_locally::<GetReferences>(
8996 lsp_store,
8997 server_id,
8998 sender_id,
8999 lsp_request_id,
9000 get_references,
9001 position,
9002 &mut cx,
9003 )
9004 .await?;
9005 }
9006 Request::GetDocumentColor(get_document_color) => {
9007 Self::query_lsp_locally::<GetDocumentColor>(
9008 lsp_store,
9009 server_id,
9010 sender_id,
9011 lsp_request_id,
9012 get_document_color,
9013 None,
9014 &mut cx,
9015 )
9016 .await?;
9017 }
9018 Request::GetHover(get_hover) => {
9019 let position = get_hover.position.clone().and_then(deserialize_anchor);
9020 Self::query_lsp_locally::<GetHover>(
9021 lsp_store,
9022 server_id,
9023 sender_id,
9024 lsp_request_id,
9025 get_hover,
9026 position,
9027 &mut cx,
9028 )
9029 .await?;
9030 }
9031 Request::GetCodeActions(get_code_actions) => {
9032 Self::query_lsp_locally::<GetCodeActions>(
9033 lsp_store,
9034 server_id,
9035 sender_id,
9036 lsp_request_id,
9037 get_code_actions,
9038 None,
9039 &mut cx,
9040 )
9041 .await?;
9042 }
9043 Request::GetSignatureHelp(get_signature_help) => {
9044 let position = get_signature_help
9045 .position
9046 .clone()
9047 .and_then(deserialize_anchor);
9048 Self::query_lsp_locally::<GetSignatureHelp>(
9049 lsp_store,
9050 server_id,
9051 sender_id,
9052 lsp_request_id,
9053 get_signature_help,
9054 position,
9055 &mut cx,
9056 )
9057 .await?;
9058 }
9059 Request::GetCodeLens(get_code_lens) => {
9060 Self::query_lsp_locally::<GetCodeLens>(
9061 lsp_store,
9062 server_id,
9063 sender_id,
9064 lsp_request_id,
9065 get_code_lens,
9066 None,
9067 &mut cx,
9068 )
9069 .await?;
9070 }
9071 Request::GetDefinition(get_definition) => {
9072 let position = get_definition.position.clone().and_then(deserialize_anchor);
9073 Self::query_lsp_locally::<GetDefinitions>(
9074 lsp_store,
9075 server_id,
9076 sender_id,
9077 lsp_request_id,
9078 get_definition,
9079 position,
9080 &mut cx,
9081 )
9082 .await?;
9083 }
9084 Request::GetDeclaration(get_declaration) => {
9085 let position = get_declaration
9086 .position
9087 .clone()
9088 .and_then(deserialize_anchor);
9089 Self::query_lsp_locally::<GetDeclarations>(
9090 lsp_store,
9091 server_id,
9092 sender_id,
9093 lsp_request_id,
9094 get_declaration,
9095 position,
9096 &mut cx,
9097 )
9098 .await?;
9099 }
9100 Request::GetTypeDefinition(get_type_definition) => {
9101 let position = get_type_definition
9102 .position
9103 .clone()
9104 .and_then(deserialize_anchor);
9105 Self::query_lsp_locally::<GetTypeDefinitions>(
9106 lsp_store,
9107 server_id,
9108 sender_id,
9109 lsp_request_id,
9110 get_type_definition,
9111 position,
9112 &mut cx,
9113 )
9114 .await?;
9115 }
9116 Request::GetImplementation(get_implementation) => {
9117 let position = get_implementation
9118 .position
9119 .clone()
9120 .and_then(deserialize_anchor);
9121 Self::query_lsp_locally::<GetImplementations>(
9122 lsp_store,
9123 server_id,
9124 sender_id,
9125 lsp_request_id,
9126 get_implementation,
9127 position,
9128 &mut cx,
9129 )
9130 .await?;
9131 }
9132 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9133 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9134 let version = deserialize_version(get_document_diagnostics.buffer_version());
9135 let buffer = lsp_store.update(&mut cx, |this, cx| {
9136 this.buffer_store.read(cx).get_existing(buffer_id)
9137 })?;
9138 buffer
9139 .update(&mut cx, |buffer, _| {
9140 buffer.wait_for_version(version.clone())
9141 })
9142 .await?;
9143 lsp_store.update(&mut cx, |lsp_store, cx| {
9144 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9145 let key = LspKey {
9146 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9147 server_queried: server_id,
9148 };
9149 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9150 ) {
9151 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9152 lsp_requests.clear();
9153 };
9154 }
9155
9156 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9157 existing_queries.insert(
9158 lsp_request_id,
9159 cx.spawn(async move |lsp_store, cx| {
9160 let diagnostics_pull = lsp_store.update(cx, |lsp_store, cx| {
9161 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9162 });
9163 if let Ok(diagnostics_pull) = diagnostics_pull {
9164 match diagnostics_pull.await {
9165 Ok(()) => {}
9166 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9167 };
9168 }
9169 }),
9170 );
9171 });
9172 }
9173 Request::InlayHints(inlay_hints) => {
9174 let query_start = inlay_hints
9175 .start
9176 .clone()
9177 .and_then(deserialize_anchor)
9178 .context("invalid inlay hints range start")?;
9179 let query_end = inlay_hints
9180 .end
9181 .clone()
9182 .and_then(deserialize_anchor)
9183 .context("invalid inlay hints range end")?;
9184 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9185 &lsp_store,
9186 server_id,
9187 lsp_request_id,
9188 &inlay_hints,
9189 query_start..query_end,
9190 &mut cx,
9191 )
9192 .await
9193 .context("preparing inlay hints request")?;
9194 Self::query_lsp_locally::<InlayHints>(
9195 lsp_store,
9196 server_id,
9197 sender_id,
9198 lsp_request_id,
9199 inlay_hints,
9200 None,
9201 &mut cx,
9202 )
9203 .await
9204 .context("querying for inlay hints")?
9205 }
9206 }
9207 Ok(proto::Ack {})
9208 }
9209
9210 async fn handle_lsp_query_response(
9211 lsp_store: Entity<Self>,
9212 envelope: TypedEnvelope<proto::LspQueryResponse>,
9213 cx: AsyncApp,
9214 ) -> Result<()> {
9215 lsp_store.read_with(&cx, |lsp_store, _| {
9216 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9217 upstream_client.handle_lsp_response(envelope.clone());
9218 }
9219 });
9220 Ok(())
9221 }
9222
9223 async fn handle_apply_code_action(
9224 this: Entity<Self>,
9225 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9226 mut cx: AsyncApp,
9227 ) -> Result<proto::ApplyCodeActionResponse> {
9228 let sender_id = envelope.original_sender_id().unwrap_or_default();
9229 let action =
9230 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9231 let apply_code_action = this.update(&mut cx, |this, cx| {
9232 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9233 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9234 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9235 })?;
9236
9237 let project_transaction = apply_code_action.await?;
9238 let project_transaction = this.update(&mut cx, |this, cx| {
9239 this.buffer_store.update(cx, |buffer_store, cx| {
9240 buffer_store.serialize_project_transaction_for_peer(
9241 project_transaction,
9242 sender_id,
9243 cx,
9244 )
9245 })
9246 });
9247 Ok(proto::ApplyCodeActionResponse {
9248 transaction: Some(project_transaction),
9249 })
9250 }
9251
9252 async fn handle_register_buffer_with_language_servers(
9253 this: Entity<Self>,
9254 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9255 mut cx: AsyncApp,
9256 ) -> Result<proto::Ack> {
9257 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9258 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9259 this.update(&mut cx, |this, cx| {
9260 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9261 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9262 project_id: upstream_project_id,
9263 buffer_id: buffer_id.to_proto(),
9264 only_servers: envelope.payload.only_servers,
9265 });
9266 }
9267
9268 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9269 anyhow::bail!("buffer is not open");
9270 };
9271
9272 let handle = this.register_buffer_with_language_servers(
9273 &buffer,
9274 envelope
9275 .payload
9276 .only_servers
9277 .into_iter()
9278 .filter_map(|selector| {
9279 Some(match selector.selector? {
9280 proto::language_server_selector::Selector::ServerId(server_id) => {
9281 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9282 }
9283 proto::language_server_selector::Selector::Name(name) => {
9284 LanguageServerSelector::Name(LanguageServerName(
9285 SharedString::from(name),
9286 ))
9287 }
9288 })
9289 })
9290 .collect(),
9291 false,
9292 cx,
9293 );
9294 this.buffer_store().update(cx, |buffer_store, _| {
9295 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9296 });
9297
9298 Ok(())
9299 })?;
9300 Ok(proto::Ack {})
9301 }
9302
9303 async fn handle_rename_project_entry(
9304 this: Entity<Self>,
9305 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9306 mut cx: AsyncApp,
9307 ) -> Result<proto::ProjectEntryResponse> {
9308 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9309 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9310 let new_path =
9311 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9312
9313 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9314 .update(&mut cx, |this, cx| {
9315 let (worktree, entry) = this
9316 .worktree_store
9317 .read(cx)
9318 .worktree_and_entry_for_id(entry_id, cx)?;
9319 let new_worktree = this
9320 .worktree_store
9321 .read(cx)
9322 .worktree_for_id(new_worktree_id, cx)?;
9323 Some((
9324 this.worktree_store.clone(),
9325 worktree,
9326 new_worktree,
9327 entry.clone(),
9328 ))
9329 })
9330 .context("worktree not found")?;
9331 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9332 (worktree.absolutize(&old_entry.path), worktree.id())
9333 });
9334 let new_abs_path =
9335 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9336
9337 let _transaction = Self::will_rename_entry(
9338 this.downgrade(),
9339 old_worktree_id,
9340 &old_abs_path,
9341 &new_abs_path,
9342 old_entry.is_dir(),
9343 cx.clone(),
9344 )
9345 .await;
9346 let response = WorktreeStore::handle_rename_project_entry(
9347 worktree_store,
9348 envelope.payload,
9349 cx.clone(),
9350 )
9351 .await;
9352 this.read_with(&cx, |this, _| {
9353 this.did_rename_entry(
9354 old_worktree_id,
9355 &old_abs_path,
9356 &new_abs_path,
9357 old_entry.is_dir(),
9358 );
9359 });
9360 response
9361 }
9362
9363 async fn handle_update_diagnostic_summary(
9364 this: Entity<Self>,
9365 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9366 mut cx: AsyncApp,
9367 ) -> Result<()> {
9368 this.update(&mut cx, |lsp_store, cx| {
9369 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9370 let mut updated_diagnostics_paths = HashMap::default();
9371 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9372 for message_summary in envelope
9373 .payload
9374 .summary
9375 .into_iter()
9376 .chain(envelope.payload.more_summaries)
9377 {
9378 let project_path = ProjectPath {
9379 worktree_id,
9380 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9381 };
9382 let path = project_path.path.clone();
9383 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9384 let summary = DiagnosticSummary {
9385 error_count: message_summary.error_count as usize,
9386 warning_count: message_summary.warning_count as usize,
9387 };
9388
9389 if summary.is_empty() {
9390 if let Some(worktree_summaries) =
9391 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9392 && let Some(summaries) = worktree_summaries.get_mut(&path)
9393 {
9394 summaries.remove(&server_id);
9395 if summaries.is_empty() {
9396 worktree_summaries.remove(&path);
9397 }
9398 }
9399 } else {
9400 lsp_store
9401 .diagnostic_summaries
9402 .entry(worktree_id)
9403 .or_default()
9404 .entry(path)
9405 .or_default()
9406 .insert(server_id, summary);
9407 }
9408
9409 if let Some((_, project_id)) = &lsp_store.downstream_client {
9410 match &mut diagnostics_summary {
9411 Some(diagnostics_summary) => {
9412 diagnostics_summary
9413 .more_summaries
9414 .push(proto::DiagnosticSummary {
9415 path: project_path.path.as_ref().to_proto(),
9416 language_server_id: server_id.0 as u64,
9417 error_count: summary.error_count as u32,
9418 warning_count: summary.warning_count as u32,
9419 })
9420 }
9421 None => {
9422 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9423 project_id: *project_id,
9424 worktree_id: worktree_id.to_proto(),
9425 summary: Some(proto::DiagnosticSummary {
9426 path: project_path.path.as_ref().to_proto(),
9427 language_server_id: server_id.0 as u64,
9428 error_count: summary.error_count as u32,
9429 warning_count: summary.warning_count as u32,
9430 }),
9431 more_summaries: Vec::new(),
9432 })
9433 }
9434 }
9435 }
9436 updated_diagnostics_paths
9437 .entry(server_id)
9438 .or_insert_with(Vec::new)
9439 .push(project_path);
9440 }
9441
9442 if let Some((diagnostics_summary, (downstream_client, _))) =
9443 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9444 {
9445 downstream_client.send(diagnostics_summary).log_err();
9446 }
9447 for (server_id, paths) in updated_diagnostics_paths {
9448 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9449 }
9450 Ok(())
9451 })
9452 }
9453
9454 async fn handle_start_language_server(
9455 lsp_store: Entity<Self>,
9456 envelope: TypedEnvelope<proto::StartLanguageServer>,
9457 mut cx: AsyncApp,
9458 ) -> Result<()> {
9459 let server = envelope.payload.server.context("invalid server")?;
9460 let server_capabilities =
9461 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9462 .with_context(|| {
9463 format!(
9464 "incorrect server capabilities {}",
9465 envelope.payload.capabilities
9466 )
9467 })?;
9468 lsp_store.update(&mut cx, |lsp_store, cx| {
9469 let server_id = LanguageServerId(server.id as usize);
9470 let server_name = LanguageServerName::from_proto(server.name.clone());
9471 lsp_store
9472 .lsp_server_capabilities
9473 .insert(server_id, server_capabilities);
9474 lsp_store.language_server_statuses.insert(
9475 server_id,
9476 LanguageServerStatus {
9477 name: server_name.clone(),
9478 server_version: None,
9479 pending_work: Default::default(),
9480 has_pending_diagnostic_updates: false,
9481 progress_tokens: Default::default(),
9482 worktree: server.worktree_id.map(WorktreeId::from_proto),
9483 binary: None,
9484 configuration: None,
9485 workspace_folders: BTreeSet::new(),
9486 },
9487 );
9488 cx.emit(LspStoreEvent::LanguageServerAdded(
9489 server_id,
9490 server_name,
9491 server.worktree_id.map(WorktreeId::from_proto),
9492 ));
9493 cx.notify();
9494 });
9495 Ok(())
9496 }
9497
9498 async fn handle_update_language_server(
9499 lsp_store: Entity<Self>,
9500 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9501 mut cx: AsyncApp,
9502 ) -> Result<()> {
9503 lsp_store.update(&mut cx, |lsp_store, cx| {
9504 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9505
9506 match envelope.payload.variant.context("invalid variant")? {
9507 proto::update_language_server::Variant::WorkStart(payload) => {
9508 lsp_store.on_lsp_work_start(
9509 language_server_id,
9510 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9511 .context("invalid progress token value")?,
9512 LanguageServerProgress {
9513 title: payload.title,
9514 is_disk_based_diagnostics_progress: false,
9515 is_cancellable: payload.is_cancellable.unwrap_or(false),
9516 message: payload.message,
9517 percentage: payload.percentage.map(|p| p as usize),
9518 last_update_at: cx.background_executor().now(),
9519 },
9520 cx,
9521 );
9522 }
9523 proto::update_language_server::Variant::WorkProgress(payload) => {
9524 lsp_store.on_lsp_work_progress(
9525 language_server_id,
9526 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9527 .context("invalid progress token value")?,
9528 LanguageServerProgress {
9529 title: None,
9530 is_disk_based_diagnostics_progress: false,
9531 is_cancellable: payload.is_cancellable.unwrap_or(false),
9532 message: payload.message,
9533 percentage: payload.percentage.map(|p| p as usize),
9534 last_update_at: cx.background_executor().now(),
9535 },
9536 cx,
9537 );
9538 }
9539
9540 proto::update_language_server::Variant::WorkEnd(payload) => {
9541 lsp_store.on_lsp_work_end(
9542 language_server_id,
9543 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9544 .context("invalid progress token value")?,
9545 cx,
9546 );
9547 }
9548
9549 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9550 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9551 }
9552
9553 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9554 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9555 }
9556
9557 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9558 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9559 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9560 cx.emit(LspStoreEvent::LanguageServerUpdate {
9561 language_server_id,
9562 name: envelope
9563 .payload
9564 .server_name
9565 .map(SharedString::new)
9566 .map(LanguageServerName),
9567 message: non_lsp,
9568 });
9569 }
9570 }
9571
9572 Ok(())
9573 })
9574 }
9575
9576 async fn handle_language_server_log(
9577 this: Entity<Self>,
9578 envelope: TypedEnvelope<proto::LanguageServerLog>,
9579 mut cx: AsyncApp,
9580 ) -> Result<()> {
9581 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9582 let log_type = envelope
9583 .payload
9584 .log_type
9585 .map(LanguageServerLogType::from_proto)
9586 .context("invalid language server log type")?;
9587
9588 let message = envelope.payload.message;
9589
9590 this.update(&mut cx, |_, cx| {
9591 cx.emit(LspStoreEvent::LanguageServerLog(
9592 language_server_id,
9593 log_type,
9594 message,
9595 ));
9596 });
9597 Ok(())
9598 }
9599
9600 async fn handle_lsp_ext_cancel_flycheck(
9601 lsp_store: Entity<Self>,
9602 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9603 cx: AsyncApp,
9604 ) -> Result<proto::Ack> {
9605 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9606 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9607 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9608 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9609 } else {
9610 None
9611 }
9612 });
9613 if let Some(task) = task {
9614 task.context("handling lsp ext cancel flycheck")?;
9615 }
9616
9617 Ok(proto::Ack {})
9618 }
9619
9620 async fn handle_lsp_ext_run_flycheck(
9621 lsp_store: Entity<Self>,
9622 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9623 mut cx: AsyncApp,
9624 ) -> Result<proto::Ack> {
9625 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9626 lsp_store.update(&mut cx, |lsp_store, cx| {
9627 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9628 let text_document = if envelope.payload.current_file_only {
9629 let buffer_id = envelope
9630 .payload
9631 .buffer_id
9632 .map(|id| BufferId::new(id))
9633 .transpose()?;
9634 buffer_id
9635 .and_then(|buffer_id| {
9636 lsp_store
9637 .buffer_store()
9638 .read(cx)
9639 .get(buffer_id)
9640 .and_then(|buffer| {
9641 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9642 })
9643 .map(|path| make_text_document_identifier(&path))
9644 })
9645 .transpose()?
9646 } else {
9647 None
9648 };
9649 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9650 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9651 )?;
9652 }
9653 anyhow::Ok(())
9654 })?;
9655
9656 Ok(proto::Ack {})
9657 }
9658
9659 async fn handle_lsp_ext_clear_flycheck(
9660 lsp_store: Entity<Self>,
9661 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9662 cx: AsyncApp,
9663 ) -> Result<proto::Ack> {
9664 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9665 lsp_store.read_with(&cx, |lsp_store, _| {
9666 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9667 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9668 } else {
9669 None
9670 }
9671 });
9672
9673 Ok(proto::Ack {})
9674 }
9675
9676 pub fn disk_based_diagnostics_started(
9677 &mut self,
9678 language_server_id: LanguageServerId,
9679 cx: &mut Context<Self>,
9680 ) {
9681 if let Some(language_server_status) =
9682 self.language_server_statuses.get_mut(&language_server_id)
9683 {
9684 language_server_status.has_pending_diagnostic_updates = true;
9685 }
9686
9687 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9688 cx.emit(LspStoreEvent::LanguageServerUpdate {
9689 language_server_id,
9690 name: self
9691 .language_server_adapter_for_id(language_server_id)
9692 .map(|adapter| adapter.name()),
9693 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9694 Default::default(),
9695 ),
9696 })
9697 }
9698
9699 pub fn disk_based_diagnostics_finished(
9700 &mut self,
9701 language_server_id: LanguageServerId,
9702 cx: &mut Context<Self>,
9703 ) {
9704 if let Some(language_server_status) =
9705 self.language_server_statuses.get_mut(&language_server_id)
9706 {
9707 language_server_status.has_pending_diagnostic_updates = false;
9708 }
9709
9710 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9711 cx.emit(LspStoreEvent::LanguageServerUpdate {
9712 language_server_id,
9713 name: self
9714 .language_server_adapter_for_id(language_server_id)
9715 .map(|adapter| adapter.name()),
9716 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9717 Default::default(),
9718 ),
9719 })
9720 }
9721
9722 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9723 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9724 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9725 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9726 // the language server might take some time to publish diagnostics.
9727 fn simulate_disk_based_diagnostics_events_if_needed(
9728 &mut self,
9729 language_server_id: LanguageServerId,
9730 cx: &mut Context<Self>,
9731 ) {
9732 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9733
9734 let Some(LanguageServerState::Running {
9735 simulate_disk_based_diagnostics_completion,
9736 adapter,
9737 ..
9738 }) = self
9739 .as_local_mut()
9740 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9741 else {
9742 return;
9743 };
9744
9745 if adapter.disk_based_diagnostics_progress_token.is_some() {
9746 return;
9747 }
9748
9749 let prev_task =
9750 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9751 cx.background_executor()
9752 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9753 .await;
9754
9755 this.update(cx, |this, cx| {
9756 this.disk_based_diagnostics_finished(language_server_id, cx);
9757
9758 if let Some(LanguageServerState::Running {
9759 simulate_disk_based_diagnostics_completion,
9760 ..
9761 }) = this.as_local_mut().and_then(|local_store| {
9762 local_store.language_servers.get_mut(&language_server_id)
9763 }) {
9764 *simulate_disk_based_diagnostics_completion = None;
9765 }
9766 })
9767 .ok();
9768 }));
9769
9770 if prev_task.is_none() {
9771 self.disk_based_diagnostics_started(language_server_id, cx);
9772 }
9773 }
9774
9775 pub fn language_server_statuses(
9776 &self,
9777 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9778 self.language_server_statuses
9779 .iter()
9780 .map(|(key, value)| (*key, value))
9781 }
9782
9783 pub(super) fn did_rename_entry(
9784 &self,
9785 worktree_id: WorktreeId,
9786 old_path: &Path,
9787 new_path: &Path,
9788 is_dir: bool,
9789 ) {
9790 maybe!({
9791 let local_store = self.as_local()?;
9792
9793 let old_uri = lsp::Uri::from_file_path(old_path)
9794 .ok()
9795 .map(|uri| uri.to_string())?;
9796 let new_uri = lsp::Uri::from_file_path(new_path)
9797 .ok()
9798 .map(|uri| uri.to_string())?;
9799
9800 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9801 let Some(filter) = local_store
9802 .language_server_paths_watched_for_rename
9803 .get(&language_server.server_id())
9804 else {
9805 continue;
9806 };
9807
9808 if filter.should_send_did_rename(&old_uri, is_dir) {
9809 language_server
9810 .notify::<DidRenameFiles>(RenameFilesParams {
9811 files: vec![FileRename {
9812 old_uri: old_uri.clone(),
9813 new_uri: new_uri.clone(),
9814 }],
9815 })
9816 .ok();
9817 }
9818 }
9819 Some(())
9820 });
9821 }
9822
9823 pub(super) fn will_rename_entry(
9824 this: WeakEntity<Self>,
9825 worktree_id: WorktreeId,
9826 old_path: &Path,
9827 new_path: &Path,
9828 is_dir: bool,
9829 cx: AsyncApp,
9830 ) -> Task<ProjectTransaction> {
9831 let old_uri = lsp::Uri::from_file_path(old_path)
9832 .ok()
9833 .map(|uri| uri.to_string());
9834 let new_uri = lsp::Uri::from_file_path(new_path)
9835 .ok()
9836 .map(|uri| uri.to_string());
9837 cx.spawn(async move |cx| {
9838 let mut tasks = vec![];
9839 this.update(cx, |this, cx| {
9840 let local_store = this.as_local()?;
9841 let old_uri = old_uri?;
9842 let new_uri = new_uri?;
9843 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9844 let Some(filter) = local_store
9845 .language_server_paths_watched_for_rename
9846 .get(&language_server.server_id())
9847 else {
9848 continue;
9849 };
9850
9851 if filter.should_send_will_rename(&old_uri, is_dir) {
9852 let apply_edit = cx.spawn({
9853 let old_uri = old_uri.clone();
9854 let new_uri = new_uri.clone();
9855 let language_server = language_server.clone();
9856 async move |this, cx| {
9857 let edit = language_server
9858 .request::<WillRenameFiles>(RenameFilesParams {
9859 files: vec![FileRename { old_uri, new_uri }],
9860 })
9861 .await
9862 .into_response()
9863 .context("will rename files")
9864 .log_err()
9865 .flatten()?;
9866
9867 let transaction = LocalLspStore::deserialize_workspace_edit(
9868 this.upgrade()?,
9869 edit,
9870 false,
9871 language_server.clone(),
9872 cx,
9873 )
9874 .await
9875 .ok()?;
9876 Some(transaction)
9877 }
9878 });
9879 tasks.push(apply_edit);
9880 }
9881 }
9882 Some(())
9883 })
9884 .ok()
9885 .flatten();
9886 let mut merged_transaction = ProjectTransaction::default();
9887 for task in tasks {
9888 // Await on tasks sequentially so that the order of application of edits is deterministic
9889 // (at least with regards to the order of registration of language servers)
9890 if let Some(transaction) = task.await {
9891 for (buffer, buffer_transaction) in transaction.0 {
9892 merged_transaction.0.insert(buffer, buffer_transaction);
9893 }
9894 }
9895 }
9896 merged_transaction
9897 })
9898 }
9899
9900 fn lsp_notify_abs_paths_changed(
9901 &mut self,
9902 server_id: LanguageServerId,
9903 changes: Vec<PathEvent>,
9904 ) {
9905 maybe!({
9906 let server = self.language_server_for_id(server_id)?;
9907 let changes = changes
9908 .into_iter()
9909 .filter_map(|event| {
9910 let typ = match event.kind? {
9911 PathEventKind::Created => lsp::FileChangeType::CREATED,
9912 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9913 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9914 };
9915 Some(lsp::FileEvent {
9916 uri: file_path_to_lsp_url(&event.path).log_err()?,
9917 typ,
9918 })
9919 })
9920 .collect::<Vec<_>>();
9921 if !changes.is_empty() {
9922 server
9923 .notify::<lsp::notification::DidChangeWatchedFiles>(
9924 lsp::DidChangeWatchedFilesParams { changes },
9925 )
9926 .ok();
9927 }
9928 Some(())
9929 });
9930 }
9931
9932 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9933 self.as_local()?.language_server_for_id(id)
9934 }
9935
9936 fn on_lsp_progress(
9937 &mut self,
9938 progress_params: lsp::ProgressParams,
9939 language_server_id: LanguageServerId,
9940 disk_based_diagnostics_progress_token: Option<String>,
9941 cx: &mut Context<Self>,
9942 ) {
9943 match progress_params.value {
9944 lsp::ProgressParamsValue::WorkDone(progress) => {
9945 self.handle_work_done_progress(
9946 progress,
9947 language_server_id,
9948 disk_based_diagnostics_progress_token,
9949 ProgressToken::from_lsp(progress_params.token),
9950 cx,
9951 );
9952 }
9953 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9954 let registration_id = match progress_params.token {
9955 lsp::NumberOrString::Number(_) => None,
9956 lsp::NumberOrString::String(token) => token
9957 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9958 .map(|(_, id)| id.to_owned()),
9959 };
9960 if let Some(LanguageServerState::Running {
9961 workspace_diagnostics_refresh_tasks,
9962 ..
9963 }) = self
9964 .as_local_mut()
9965 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9966 && let Some(workspace_diagnostics) =
9967 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9968 {
9969 workspace_diagnostics.progress_tx.try_send(()).ok();
9970 self.apply_workspace_diagnostic_report(
9971 language_server_id,
9972 report,
9973 registration_id.map(SharedString::from),
9974 cx,
9975 )
9976 }
9977 }
9978 }
9979 }
9980
9981 fn handle_work_done_progress(
9982 &mut self,
9983 progress: lsp::WorkDoneProgress,
9984 language_server_id: LanguageServerId,
9985 disk_based_diagnostics_progress_token: Option<String>,
9986 token: ProgressToken,
9987 cx: &mut Context<Self>,
9988 ) {
9989 let language_server_status =
9990 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9991 status
9992 } else {
9993 return;
9994 };
9995
9996 if !language_server_status.progress_tokens.contains(&token) {
9997 return;
9998 }
9999
10000 let is_disk_based_diagnostics_progress =
10001 if let (Some(disk_based_token), ProgressToken::String(token)) =
10002 (&disk_based_diagnostics_progress_token, &token)
10003 {
10004 token.starts_with(disk_based_token)
10005 } else {
10006 false
10007 };
10008
10009 match progress {
10010 lsp::WorkDoneProgress::Begin(report) => {
10011 if is_disk_based_diagnostics_progress {
10012 self.disk_based_diagnostics_started(language_server_id, cx);
10013 }
10014 self.on_lsp_work_start(
10015 language_server_id,
10016 token.clone(),
10017 LanguageServerProgress {
10018 title: Some(report.title),
10019 is_disk_based_diagnostics_progress,
10020 is_cancellable: report.cancellable.unwrap_or(false),
10021 message: report.message.clone(),
10022 percentage: report.percentage.map(|p| p as usize),
10023 last_update_at: cx.background_executor().now(),
10024 },
10025 cx,
10026 );
10027 }
10028 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10029 language_server_id,
10030 token,
10031 LanguageServerProgress {
10032 title: None,
10033 is_disk_based_diagnostics_progress,
10034 is_cancellable: report.cancellable.unwrap_or(false),
10035 message: report.message,
10036 percentage: report.percentage.map(|p| p as usize),
10037 last_update_at: cx.background_executor().now(),
10038 },
10039 cx,
10040 ),
10041 lsp::WorkDoneProgress::End(_) => {
10042 language_server_status.progress_tokens.remove(&token);
10043 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10044 if is_disk_based_diagnostics_progress {
10045 self.disk_based_diagnostics_finished(language_server_id, cx);
10046 }
10047 }
10048 }
10049 }
10050
10051 fn on_lsp_work_start(
10052 &mut self,
10053 language_server_id: LanguageServerId,
10054 token: ProgressToken,
10055 progress: LanguageServerProgress,
10056 cx: &mut Context<Self>,
10057 ) {
10058 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10059 status.pending_work.insert(token.clone(), progress.clone());
10060 cx.notify();
10061 }
10062 cx.emit(LspStoreEvent::LanguageServerUpdate {
10063 language_server_id,
10064 name: self
10065 .language_server_adapter_for_id(language_server_id)
10066 .map(|adapter| adapter.name()),
10067 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10068 token: Some(token.to_proto()),
10069 title: progress.title,
10070 message: progress.message,
10071 percentage: progress.percentage.map(|p| p as u32),
10072 is_cancellable: Some(progress.is_cancellable),
10073 }),
10074 })
10075 }
10076
10077 fn on_lsp_work_progress(
10078 &mut self,
10079 language_server_id: LanguageServerId,
10080 token: ProgressToken,
10081 progress: LanguageServerProgress,
10082 cx: &mut Context<Self>,
10083 ) {
10084 let mut did_update = false;
10085 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10086 match status.pending_work.entry(token.clone()) {
10087 btree_map::Entry::Vacant(entry) => {
10088 entry.insert(progress.clone());
10089 did_update = true;
10090 }
10091 btree_map::Entry::Occupied(mut entry) => {
10092 let entry = entry.get_mut();
10093 if (progress.last_update_at - entry.last_update_at)
10094 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10095 {
10096 entry.last_update_at = progress.last_update_at;
10097 if progress.message.is_some() {
10098 entry.message = progress.message.clone();
10099 }
10100 if progress.percentage.is_some() {
10101 entry.percentage = progress.percentage;
10102 }
10103 if progress.is_cancellable != entry.is_cancellable {
10104 entry.is_cancellable = progress.is_cancellable;
10105 }
10106 did_update = true;
10107 }
10108 }
10109 }
10110 }
10111
10112 if did_update {
10113 cx.emit(LspStoreEvent::LanguageServerUpdate {
10114 language_server_id,
10115 name: self
10116 .language_server_adapter_for_id(language_server_id)
10117 .map(|adapter| adapter.name()),
10118 message: proto::update_language_server::Variant::WorkProgress(
10119 proto::LspWorkProgress {
10120 token: Some(token.to_proto()),
10121 message: progress.message,
10122 percentage: progress.percentage.map(|p| p as u32),
10123 is_cancellable: Some(progress.is_cancellable),
10124 },
10125 ),
10126 })
10127 }
10128 }
10129
10130 fn on_lsp_work_end(
10131 &mut self,
10132 language_server_id: LanguageServerId,
10133 token: ProgressToken,
10134 cx: &mut Context<Self>,
10135 ) {
10136 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10137 if let Some(work) = status.pending_work.remove(&token)
10138 && !work.is_disk_based_diagnostics_progress
10139 {
10140 cx.emit(LspStoreEvent::RefreshInlayHints {
10141 server_id: language_server_id,
10142 request_id: None,
10143 });
10144 }
10145 cx.notify();
10146 }
10147
10148 cx.emit(LspStoreEvent::LanguageServerUpdate {
10149 language_server_id,
10150 name: self
10151 .language_server_adapter_for_id(language_server_id)
10152 .map(|adapter| adapter.name()),
10153 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10154 token: Some(token.to_proto()),
10155 }),
10156 })
10157 }
10158
10159 pub async fn handle_resolve_completion_documentation(
10160 this: Entity<Self>,
10161 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10162 mut cx: AsyncApp,
10163 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10164 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10165
10166 let completion = this
10167 .read_with(&cx, |this, cx| {
10168 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10169 let server = this
10170 .language_server_for_id(id)
10171 .with_context(|| format!("No language server {id}"))?;
10172
10173 anyhow::Ok(cx.background_spawn(async move {
10174 let can_resolve = server
10175 .capabilities()
10176 .completion_provider
10177 .as_ref()
10178 .and_then(|options| options.resolve_provider)
10179 .unwrap_or(false);
10180 if can_resolve {
10181 server
10182 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10183 .await
10184 .into_response()
10185 .context("resolve completion item")
10186 } else {
10187 anyhow::Ok(lsp_completion)
10188 }
10189 }))
10190 })?
10191 .await?;
10192
10193 let mut documentation_is_markdown = false;
10194 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10195 let documentation = match completion.documentation {
10196 Some(lsp::Documentation::String(text)) => text,
10197
10198 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10199 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10200 value
10201 }
10202
10203 _ => String::new(),
10204 };
10205
10206 // If we have a new buffer_id, that means we're talking to a new client
10207 // and want to check for new text_edits in the completion too.
10208 let mut old_replace_start = None;
10209 let mut old_replace_end = None;
10210 let mut old_insert_start = None;
10211 let mut old_insert_end = None;
10212 let mut new_text = String::default();
10213 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10214 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10215 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10216 anyhow::Ok(buffer.read(cx).snapshot())
10217 })?;
10218
10219 if let Some(text_edit) = completion.text_edit.as_ref() {
10220 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10221
10222 if let Some(mut edit) = edit {
10223 LineEnding::normalize(&mut edit.new_text);
10224
10225 new_text = edit.new_text;
10226 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10227 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10228 if let Some(insert_range) = edit.insert_range {
10229 old_insert_start = Some(serialize_anchor(&insert_range.start));
10230 old_insert_end = Some(serialize_anchor(&insert_range.end));
10231 }
10232 }
10233 }
10234 }
10235
10236 Ok(proto::ResolveCompletionDocumentationResponse {
10237 documentation,
10238 documentation_is_markdown,
10239 old_replace_start,
10240 old_replace_end,
10241 new_text,
10242 lsp_completion,
10243 old_insert_start,
10244 old_insert_end,
10245 })
10246 }
10247
10248 async fn handle_on_type_formatting(
10249 this: Entity<Self>,
10250 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10251 mut cx: AsyncApp,
10252 ) -> Result<proto::OnTypeFormattingResponse> {
10253 let on_type_formatting = this.update(&mut cx, |this, cx| {
10254 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10255 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10256 let position = envelope
10257 .payload
10258 .position
10259 .and_then(deserialize_anchor)
10260 .context("invalid position")?;
10261 anyhow::Ok(this.apply_on_type_formatting(
10262 buffer,
10263 position,
10264 envelope.payload.trigger.clone(),
10265 cx,
10266 ))
10267 })?;
10268
10269 let transaction = on_type_formatting
10270 .await?
10271 .as_ref()
10272 .map(language::proto::serialize_transaction);
10273 Ok(proto::OnTypeFormattingResponse { transaction })
10274 }
10275
10276 async fn handle_refresh_inlay_hints(
10277 lsp_store: Entity<Self>,
10278 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10279 mut cx: AsyncApp,
10280 ) -> Result<proto::Ack> {
10281 lsp_store.update(&mut cx, |_, cx| {
10282 cx.emit(LspStoreEvent::RefreshInlayHints {
10283 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10284 request_id: envelope.payload.request_id.map(|id| id as usize),
10285 });
10286 });
10287 Ok(proto::Ack {})
10288 }
10289
10290 async fn handle_pull_workspace_diagnostics(
10291 lsp_store: Entity<Self>,
10292 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10293 mut cx: AsyncApp,
10294 ) -> Result<proto::Ack> {
10295 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10296 lsp_store.update(&mut cx, |lsp_store, _| {
10297 lsp_store.pull_workspace_diagnostics(server_id);
10298 });
10299 Ok(proto::Ack {})
10300 }
10301
10302 async fn handle_get_color_presentation(
10303 lsp_store: Entity<Self>,
10304 envelope: TypedEnvelope<proto::GetColorPresentation>,
10305 mut cx: AsyncApp,
10306 ) -> Result<proto::GetColorPresentationResponse> {
10307 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10308 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10309 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10310 })?;
10311
10312 let color = envelope
10313 .payload
10314 .color
10315 .context("invalid color resolve request")?;
10316 let start = color
10317 .lsp_range_start
10318 .context("invalid color resolve request")?;
10319 let end = color
10320 .lsp_range_end
10321 .context("invalid color resolve request")?;
10322
10323 let color = DocumentColor {
10324 lsp_range: lsp::Range {
10325 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10326 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10327 },
10328 color: lsp::Color {
10329 red: color.red,
10330 green: color.green,
10331 blue: color.blue,
10332 alpha: color.alpha,
10333 },
10334 resolved: false,
10335 color_presentations: Vec::new(),
10336 };
10337 let resolved_color = lsp_store
10338 .update(&mut cx, |lsp_store, cx| {
10339 lsp_store.resolve_color_presentation(
10340 color,
10341 buffer.clone(),
10342 LanguageServerId(envelope.payload.server_id as usize),
10343 cx,
10344 )
10345 })
10346 .await
10347 .context("resolving color presentation")?;
10348
10349 Ok(proto::GetColorPresentationResponse {
10350 presentations: resolved_color
10351 .color_presentations
10352 .into_iter()
10353 .map(|presentation| proto::ColorPresentation {
10354 label: presentation.label.to_string(),
10355 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10356 additional_text_edits: presentation
10357 .additional_text_edits
10358 .into_iter()
10359 .map(serialize_lsp_edit)
10360 .collect(),
10361 })
10362 .collect(),
10363 })
10364 }
10365
10366 async fn handle_resolve_inlay_hint(
10367 lsp_store: Entity<Self>,
10368 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10369 mut cx: AsyncApp,
10370 ) -> Result<proto::ResolveInlayHintResponse> {
10371 let proto_hint = envelope
10372 .payload
10373 .hint
10374 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10375 let hint = InlayHints::proto_to_project_hint(proto_hint)
10376 .context("resolved proto inlay hint conversion")?;
10377 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10378 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10379 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10380 })?;
10381 let response_hint = lsp_store
10382 .update(&mut cx, |lsp_store, cx| {
10383 lsp_store.resolve_inlay_hint(
10384 hint,
10385 buffer,
10386 LanguageServerId(envelope.payload.language_server_id as usize),
10387 cx,
10388 )
10389 })
10390 .await
10391 .context("inlay hints fetch")?;
10392 Ok(proto::ResolveInlayHintResponse {
10393 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10394 })
10395 }
10396
10397 async fn handle_refresh_code_lens(
10398 this: Entity<Self>,
10399 _: TypedEnvelope<proto::RefreshCodeLens>,
10400 mut cx: AsyncApp,
10401 ) -> Result<proto::Ack> {
10402 this.update(&mut cx, |_, cx| {
10403 cx.emit(LspStoreEvent::RefreshCodeLens);
10404 });
10405 Ok(proto::Ack {})
10406 }
10407
10408 async fn handle_open_buffer_for_symbol(
10409 this: Entity<Self>,
10410 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10411 mut cx: AsyncApp,
10412 ) -> Result<proto::OpenBufferForSymbolResponse> {
10413 let peer_id = envelope.original_sender_id().unwrap_or_default();
10414 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10415 let symbol = Self::deserialize_symbol(symbol)?;
10416 this.read_with(&cx, |this, _| {
10417 if let SymbolLocation::OutsideProject {
10418 abs_path,
10419 signature,
10420 } = &symbol.path
10421 {
10422 let new_signature = this.symbol_signature(&abs_path);
10423 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10424 }
10425 Ok(())
10426 })?;
10427 let buffer = this
10428 .update(&mut cx, |this, cx| {
10429 this.open_buffer_for_symbol(
10430 &Symbol {
10431 language_server_name: symbol.language_server_name,
10432 source_worktree_id: symbol.source_worktree_id,
10433 source_language_server_id: symbol.source_language_server_id,
10434 path: symbol.path,
10435 name: symbol.name,
10436 kind: symbol.kind,
10437 range: symbol.range,
10438 label: CodeLabel::default(),
10439 },
10440 cx,
10441 )
10442 })
10443 .await?;
10444
10445 this.update(&mut cx, |this, cx| {
10446 let is_private = buffer
10447 .read(cx)
10448 .file()
10449 .map(|f| f.is_private())
10450 .unwrap_or_default();
10451 if is_private {
10452 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10453 } else {
10454 this.buffer_store
10455 .update(cx, |buffer_store, cx| {
10456 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10457 })
10458 .detach_and_log_err(cx);
10459 let buffer_id = buffer.read(cx).remote_id().to_proto();
10460 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10461 }
10462 })
10463 }
10464
10465 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10466 let mut hasher = Sha256::new();
10467 hasher.update(abs_path.to_string_lossy().as_bytes());
10468 hasher.update(self.nonce.to_be_bytes());
10469 hasher.finalize().as_slice().try_into().unwrap()
10470 }
10471
10472 pub async fn handle_get_project_symbols(
10473 this: Entity<Self>,
10474 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10475 mut cx: AsyncApp,
10476 ) -> Result<proto::GetProjectSymbolsResponse> {
10477 let symbols = this
10478 .update(&mut cx, |this, cx| {
10479 this.symbols(&envelope.payload.query, cx)
10480 })
10481 .await?;
10482
10483 Ok(proto::GetProjectSymbolsResponse {
10484 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10485 })
10486 }
10487
10488 pub async fn handle_restart_language_servers(
10489 this: Entity<Self>,
10490 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10491 mut cx: AsyncApp,
10492 ) -> Result<proto::Ack> {
10493 this.update(&mut cx, |lsp_store, cx| {
10494 let buffers =
10495 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10496 lsp_store.restart_language_servers_for_buffers(
10497 buffers,
10498 envelope
10499 .payload
10500 .only_servers
10501 .into_iter()
10502 .filter_map(|selector| {
10503 Some(match selector.selector? {
10504 proto::language_server_selector::Selector::ServerId(server_id) => {
10505 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10506 }
10507 proto::language_server_selector::Selector::Name(name) => {
10508 LanguageServerSelector::Name(LanguageServerName(
10509 SharedString::from(name),
10510 ))
10511 }
10512 })
10513 })
10514 .collect(),
10515 cx,
10516 );
10517 });
10518
10519 Ok(proto::Ack {})
10520 }
10521
10522 pub async fn handle_stop_language_servers(
10523 lsp_store: Entity<Self>,
10524 envelope: TypedEnvelope<proto::StopLanguageServers>,
10525 mut cx: AsyncApp,
10526 ) -> Result<proto::Ack> {
10527 lsp_store.update(&mut cx, |lsp_store, cx| {
10528 if envelope.payload.all
10529 && envelope.payload.also_servers.is_empty()
10530 && envelope.payload.buffer_ids.is_empty()
10531 {
10532 lsp_store.stop_all_language_servers(cx);
10533 } else {
10534 let buffers =
10535 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10536 lsp_store
10537 .stop_language_servers_for_buffers(
10538 buffers,
10539 envelope
10540 .payload
10541 .also_servers
10542 .into_iter()
10543 .filter_map(|selector| {
10544 Some(match selector.selector? {
10545 proto::language_server_selector::Selector::ServerId(
10546 server_id,
10547 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10548 server_id,
10549 )),
10550 proto::language_server_selector::Selector::Name(name) => {
10551 LanguageServerSelector::Name(LanguageServerName(
10552 SharedString::from(name),
10553 ))
10554 }
10555 })
10556 })
10557 .collect(),
10558 cx,
10559 )
10560 .detach_and_log_err(cx);
10561 }
10562 });
10563
10564 Ok(proto::Ack {})
10565 }
10566
10567 pub async fn handle_cancel_language_server_work(
10568 lsp_store: Entity<Self>,
10569 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10570 mut cx: AsyncApp,
10571 ) -> Result<proto::Ack> {
10572 lsp_store.update(&mut cx, |lsp_store, cx| {
10573 if let Some(work) = envelope.payload.work {
10574 match work {
10575 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10576 let buffers =
10577 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10578 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10579 }
10580 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10581 let server_id = LanguageServerId::from_proto(work.language_server_id);
10582 let token = work
10583 .token
10584 .map(|token| {
10585 ProgressToken::from_proto(token)
10586 .context("invalid work progress token")
10587 })
10588 .transpose()?;
10589 lsp_store.cancel_language_server_work(server_id, token, cx);
10590 }
10591 }
10592 }
10593 anyhow::Ok(())
10594 })?;
10595
10596 Ok(proto::Ack {})
10597 }
10598
10599 fn buffer_ids_to_buffers(
10600 &mut self,
10601 buffer_ids: impl Iterator<Item = u64>,
10602 cx: &mut Context<Self>,
10603 ) -> Vec<Entity<Buffer>> {
10604 buffer_ids
10605 .into_iter()
10606 .flat_map(|buffer_id| {
10607 self.buffer_store
10608 .read(cx)
10609 .get(BufferId::new(buffer_id).log_err()?)
10610 })
10611 .collect::<Vec<_>>()
10612 }
10613
10614 async fn handle_apply_additional_edits_for_completion(
10615 this: Entity<Self>,
10616 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10617 mut cx: AsyncApp,
10618 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10619 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10620 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10621 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10622 let completion = Self::deserialize_completion(
10623 envelope.payload.completion.context("invalid completion")?,
10624 )?;
10625 anyhow::Ok((buffer, completion))
10626 })?;
10627
10628 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10629 this.apply_additional_edits_for_completion(
10630 buffer,
10631 Rc::new(RefCell::new(Box::new([Completion {
10632 replace_range: completion.replace_range,
10633 new_text: completion.new_text,
10634 source: completion.source,
10635 documentation: None,
10636 label: CodeLabel::default(),
10637 match_start: None,
10638 snippet_deduplication_key: None,
10639 insert_text_mode: None,
10640 icon_path: None,
10641 confirm: None,
10642 }]))),
10643 0,
10644 false,
10645 cx,
10646 )
10647 });
10648
10649 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10650 transaction: apply_additional_edits
10651 .await?
10652 .as_ref()
10653 .map(language::proto::serialize_transaction),
10654 })
10655 }
10656
10657 pub fn last_formatting_failure(&self) -> Option<&str> {
10658 self.last_formatting_failure.as_deref()
10659 }
10660
10661 pub fn reset_last_formatting_failure(&mut self) {
10662 self.last_formatting_failure = None;
10663 }
10664
10665 pub fn environment_for_buffer(
10666 &self,
10667 buffer: &Entity<Buffer>,
10668 cx: &mut Context<Self>,
10669 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10670 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10671 environment.update(cx, |env, cx| {
10672 env.buffer_environment(buffer, &self.worktree_store, cx)
10673 })
10674 } else {
10675 Task::ready(None).shared()
10676 }
10677 }
10678
10679 pub fn format(
10680 &mut self,
10681 buffers: HashSet<Entity<Buffer>>,
10682 target: LspFormatTarget,
10683 push_to_history: bool,
10684 trigger: FormatTrigger,
10685 cx: &mut Context<Self>,
10686 ) -> Task<anyhow::Result<ProjectTransaction>> {
10687 let logger = zlog::scoped!("format");
10688 if self.as_local().is_some() {
10689 zlog::trace!(logger => "Formatting locally");
10690 let logger = zlog::scoped!(logger => "local");
10691 let buffers = buffers
10692 .into_iter()
10693 .map(|buffer_handle| {
10694 let buffer = buffer_handle.read(cx);
10695 let buffer_abs_path = File::from_dyn(buffer.file())
10696 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10697
10698 (buffer_handle, buffer_abs_path, buffer.remote_id())
10699 })
10700 .collect::<Vec<_>>();
10701
10702 cx.spawn(async move |lsp_store, cx| {
10703 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10704
10705 for (handle, abs_path, id) in buffers {
10706 let env = lsp_store
10707 .update(cx, |lsp_store, cx| {
10708 lsp_store.environment_for_buffer(&handle, cx)
10709 })?
10710 .await;
10711
10712 let ranges = match &target {
10713 LspFormatTarget::Buffers => None,
10714 LspFormatTarget::Ranges(ranges) => {
10715 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10716 }
10717 };
10718
10719 formattable_buffers.push(FormattableBuffer {
10720 handle,
10721 abs_path,
10722 env,
10723 ranges,
10724 });
10725 }
10726 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10727
10728 let format_timer = zlog::time!(logger => "Formatting buffers");
10729 let result = LocalLspStore::format_locally(
10730 lsp_store.clone(),
10731 formattable_buffers,
10732 push_to_history,
10733 trigger,
10734 logger,
10735 cx,
10736 )
10737 .await;
10738 format_timer.end();
10739
10740 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10741
10742 lsp_store.update(cx, |lsp_store, _| {
10743 lsp_store.update_last_formatting_failure(&result);
10744 })?;
10745
10746 result
10747 })
10748 } else if let Some((client, project_id)) = self.upstream_client() {
10749 zlog::trace!(logger => "Formatting remotely");
10750 let logger = zlog::scoped!(logger => "remote");
10751 // Don't support formatting ranges via remote
10752 match target {
10753 LspFormatTarget::Buffers => {}
10754 LspFormatTarget::Ranges(_) => {
10755 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10756 return Task::ready(Ok(ProjectTransaction::default()));
10757 }
10758 }
10759
10760 let buffer_store = self.buffer_store();
10761 cx.spawn(async move |lsp_store, cx| {
10762 zlog::trace!(logger => "Sending remote format request");
10763 let request_timer = zlog::time!(logger => "remote format request");
10764 let result = client
10765 .request(proto::FormatBuffers {
10766 project_id,
10767 trigger: trigger as i32,
10768 buffer_ids: buffers
10769 .iter()
10770 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10771 .collect(),
10772 })
10773 .await
10774 .and_then(|result| result.transaction.context("missing transaction"));
10775 request_timer.end();
10776
10777 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10778
10779 lsp_store.update(cx, |lsp_store, _| {
10780 lsp_store.update_last_formatting_failure(&result);
10781 })?;
10782
10783 let transaction_response = result?;
10784 let _timer = zlog::time!(logger => "deserializing project transaction");
10785 buffer_store
10786 .update(cx, |buffer_store, cx| {
10787 buffer_store.deserialize_project_transaction(
10788 transaction_response,
10789 push_to_history,
10790 cx,
10791 )
10792 })
10793 .await
10794 })
10795 } else {
10796 zlog::trace!(logger => "Not formatting");
10797 Task::ready(Ok(ProjectTransaction::default()))
10798 }
10799 }
10800
10801 async fn handle_format_buffers(
10802 this: Entity<Self>,
10803 envelope: TypedEnvelope<proto::FormatBuffers>,
10804 mut cx: AsyncApp,
10805 ) -> Result<proto::FormatBuffersResponse> {
10806 let sender_id = envelope.original_sender_id().unwrap_or_default();
10807 let format = this.update(&mut cx, |this, cx| {
10808 let mut buffers = HashSet::default();
10809 for buffer_id in &envelope.payload.buffer_ids {
10810 let buffer_id = BufferId::new(*buffer_id)?;
10811 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10812 }
10813 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10814 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10815 })?;
10816
10817 let project_transaction = format.await?;
10818 let project_transaction = this.update(&mut cx, |this, cx| {
10819 this.buffer_store.update(cx, |buffer_store, cx| {
10820 buffer_store.serialize_project_transaction_for_peer(
10821 project_transaction,
10822 sender_id,
10823 cx,
10824 )
10825 })
10826 });
10827 Ok(proto::FormatBuffersResponse {
10828 transaction: Some(project_transaction),
10829 })
10830 }
10831
10832 async fn handle_apply_code_action_kind(
10833 this: Entity<Self>,
10834 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10835 mut cx: AsyncApp,
10836 ) -> Result<proto::ApplyCodeActionKindResponse> {
10837 let sender_id = envelope.original_sender_id().unwrap_or_default();
10838 let format = this.update(&mut cx, |this, cx| {
10839 let mut buffers = HashSet::default();
10840 for buffer_id in &envelope.payload.buffer_ids {
10841 let buffer_id = BufferId::new(*buffer_id)?;
10842 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10843 }
10844 let kind = match envelope.payload.kind.as_str() {
10845 "" => CodeActionKind::EMPTY,
10846 "quickfix" => CodeActionKind::QUICKFIX,
10847 "refactor" => CodeActionKind::REFACTOR,
10848 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10849 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10850 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10851 "source" => CodeActionKind::SOURCE,
10852 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10853 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10854 _ => anyhow::bail!(
10855 "Invalid code action kind {}",
10856 envelope.payload.kind.as_str()
10857 ),
10858 };
10859 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10860 })?;
10861
10862 let project_transaction = format.await?;
10863 let project_transaction = this.update(&mut cx, |this, cx| {
10864 this.buffer_store.update(cx, |buffer_store, cx| {
10865 buffer_store.serialize_project_transaction_for_peer(
10866 project_transaction,
10867 sender_id,
10868 cx,
10869 )
10870 })
10871 });
10872 Ok(proto::ApplyCodeActionKindResponse {
10873 transaction: Some(project_transaction),
10874 })
10875 }
10876
10877 async fn shutdown_language_server(
10878 server_state: Option<LanguageServerState>,
10879 name: LanguageServerName,
10880 cx: &mut AsyncApp,
10881 ) {
10882 let server = match server_state {
10883 Some(LanguageServerState::Starting { startup, .. }) => {
10884 let mut timer = cx
10885 .background_executor()
10886 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10887 .fuse();
10888
10889 select! {
10890 server = startup.fuse() => server,
10891 () = timer => {
10892 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10893 None
10894 },
10895 }
10896 }
10897
10898 Some(LanguageServerState::Running { server, .. }) => Some(server),
10899
10900 None => None,
10901 };
10902
10903 if let Some(server) = server
10904 && let Some(shutdown) = server.shutdown()
10905 {
10906 shutdown.await;
10907 }
10908 }
10909
10910 // Returns a list of all of the worktrees which no longer have a language server and the root path
10911 // for the stopped server
10912 fn stop_local_language_server(
10913 &mut self,
10914 server_id: LanguageServerId,
10915 cx: &mut Context<Self>,
10916 ) -> Task<()> {
10917 let local = match &mut self.mode {
10918 LspStoreMode::Local(local) => local,
10919 _ => {
10920 return Task::ready(());
10921 }
10922 };
10923
10924 // Remove this server ID from all entries in the given worktree.
10925 local
10926 .language_server_ids
10927 .retain(|_, state| state.id != server_id);
10928 self.buffer_store.update(cx, |buffer_store, cx| {
10929 for buffer in buffer_store.buffers() {
10930 buffer.update(cx, |buffer, cx| {
10931 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10932 buffer.set_completion_triggers(server_id, Default::default(), cx);
10933 });
10934 }
10935 });
10936
10937 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10938 summaries.retain(|path, summaries_by_server_id| {
10939 if summaries_by_server_id.remove(&server_id).is_some() {
10940 if let Some((client, project_id)) = self.downstream_client.clone() {
10941 client
10942 .send(proto::UpdateDiagnosticSummary {
10943 project_id,
10944 worktree_id: worktree_id.to_proto(),
10945 summary: Some(proto::DiagnosticSummary {
10946 path: path.as_ref().to_proto(),
10947 language_server_id: server_id.0 as u64,
10948 error_count: 0,
10949 warning_count: 0,
10950 }),
10951 more_summaries: Vec::new(),
10952 })
10953 .log_err();
10954 }
10955 !summaries_by_server_id.is_empty()
10956 } else {
10957 true
10958 }
10959 });
10960 }
10961
10962 let local = self.as_local_mut().unwrap();
10963 for diagnostics in local.diagnostics.values_mut() {
10964 diagnostics.retain(|_, diagnostics_by_server_id| {
10965 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10966 diagnostics_by_server_id.remove(ix);
10967 !diagnostics_by_server_id.is_empty()
10968 } else {
10969 true
10970 }
10971 });
10972 }
10973 local.language_server_watched_paths.remove(&server_id);
10974
10975 let server_state = local.language_servers.remove(&server_id);
10976 self.cleanup_lsp_data(server_id);
10977 let name = self
10978 .language_server_statuses
10979 .remove(&server_id)
10980 .map(|status| status.name)
10981 .or_else(|| {
10982 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10983 Some(adapter.name())
10984 } else {
10985 None
10986 }
10987 });
10988
10989 if let Some(name) = name {
10990 log::info!("stopping language server {name}");
10991 self.languages
10992 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10993 cx.notify();
10994
10995 return cx.spawn(async move |lsp_store, cx| {
10996 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10997 lsp_store
10998 .update(cx, |lsp_store, cx| {
10999 lsp_store
11000 .languages
11001 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11002 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11003 cx.notify();
11004 })
11005 .ok();
11006 });
11007 }
11008
11009 if server_state.is_some() {
11010 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11011 }
11012 Task::ready(())
11013 }
11014
11015 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11016 if let Some((client, project_id)) = self.upstream_client() {
11017 let request = client.request(proto::StopLanguageServers {
11018 project_id,
11019 buffer_ids: Vec::new(),
11020 also_servers: Vec::new(),
11021 all: true,
11022 });
11023 cx.background_spawn(request).detach_and_log_err(cx);
11024 } else {
11025 let Some(local) = self.as_local_mut() else {
11026 return;
11027 };
11028 let language_servers_to_stop = local
11029 .language_server_ids
11030 .values()
11031 .map(|state| state.id)
11032 .collect();
11033 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11034 let tasks = language_servers_to_stop
11035 .into_iter()
11036 .map(|server| self.stop_local_language_server(server, cx))
11037 .collect::<Vec<_>>();
11038 cx.background_spawn(async move {
11039 futures::future::join_all(tasks).await;
11040 })
11041 .detach();
11042 }
11043 }
11044
11045 pub fn restart_language_servers_for_buffers(
11046 &mut self,
11047 buffers: Vec<Entity<Buffer>>,
11048 only_restart_servers: HashSet<LanguageServerSelector>,
11049 cx: &mut Context<Self>,
11050 ) {
11051 if let Some((client, project_id)) = self.upstream_client() {
11052 let request = client.request(proto::RestartLanguageServers {
11053 project_id,
11054 buffer_ids: buffers
11055 .into_iter()
11056 .map(|b| b.read(cx).remote_id().to_proto())
11057 .collect(),
11058 only_servers: only_restart_servers
11059 .into_iter()
11060 .map(|selector| {
11061 let selector = match selector {
11062 LanguageServerSelector::Id(language_server_id) => {
11063 proto::language_server_selector::Selector::ServerId(
11064 language_server_id.to_proto(),
11065 )
11066 }
11067 LanguageServerSelector::Name(language_server_name) => {
11068 proto::language_server_selector::Selector::Name(
11069 language_server_name.to_string(),
11070 )
11071 }
11072 };
11073 proto::LanguageServerSelector {
11074 selector: Some(selector),
11075 }
11076 })
11077 .collect(),
11078 all: false,
11079 });
11080 cx.background_spawn(request).detach_and_log_err(cx);
11081 } else {
11082 let stop_task = if only_restart_servers.is_empty() {
11083 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11084 } else {
11085 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11086 };
11087 cx.spawn(async move |lsp_store, cx| {
11088 stop_task.await;
11089 lsp_store.update(cx, |lsp_store, cx| {
11090 for buffer in buffers {
11091 lsp_store.register_buffer_with_language_servers(
11092 &buffer,
11093 only_restart_servers.clone(),
11094 true,
11095 cx,
11096 );
11097 }
11098 })
11099 })
11100 .detach();
11101 }
11102 }
11103
11104 pub fn stop_language_servers_for_buffers(
11105 &mut self,
11106 buffers: Vec<Entity<Buffer>>,
11107 also_stop_servers: HashSet<LanguageServerSelector>,
11108 cx: &mut Context<Self>,
11109 ) -> Task<Result<()>> {
11110 if let Some((client, project_id)) = self.upstream_client() {
11111 let request = client.request(proto::StopLanguageServers {
11112 project_id,
11113 buffer_ids: buffers
11114 .into_iter()
11115 .map(|b| b.read(cx).remote_id().to_proto())
11116 .collect(),
11117 also_servers: also_stop_servers
11118 .into_iter()
11119 .map(|selector| {
11120 let selector = match selector {
11121 LanguageServerSelector::Id(language_server_id) => {
11122 proto::language_server_selector::Selector::ServerId(
11123 language_server_id.to_proto(),
11124 )
11125 }
11126 LanguageServerSelector::Name(language_server_name) => {
11127 proto::language_server_selector::Selector::Name(
11128 language_server_name.to_string(),
11129 )
11130 }
11131 };
11132 proto::LanguageServerSelector {
11133 selector: Some(selector),
11134 }
11135 })
11136 .collect(),
11137 all: false,
11138 });
11139 cx.background_spawn(async move {
11140 let _ = request.await?;
11141 Ok(())
11142 })
11143 } else {
11144 let task =
11145 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11146 cx.background_spawn(async move {
11147 task.await;
11148 Ok(())
11149 })
11150 }
11151 }
11152
11153 fn stop_local_language_servers_for_buffers(
11154 &mut self,
11155 buffers: &[Entity<Buffer>],
11156 also_stop_servers: HashSet<LanguageServerSelector>,
11157 cx: &mut Context<Self>,
11158 ) -> Task<()> {
11159 let Some(local) = self.as_local_mut() else {
11160 return Task::ready(());
11161 };
11162 let mut language_server_names_to_stop = BTreeSet::default();
11163 let mut language_servers_to_stop = also_stop_servers
11164 .into_iter()
11165 .flat_map(|selector| match selector {
11166 LanguageServerSelector::Id(id) => Some(id),
11167 LanguageServerSelector::Name(name) => {
11168 language_server_names_to_stop.insert(name);
11169 None
11170 }
11171 })
11172 .collect::<BTreeSet<_>>();
11173
11174 let mut covered_worktrees = HashSet::default();
11175 for buffer in buffers {
11176 buffer.update(cx, |buffer, cx| {
11177 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11178 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11179 && covered_worktrees.insert(worktree_id)
11180 {
11181 language_server_names_to_stop.retain(|name| {
11182 let old_ids_count = language_servers_to_stop.len();
11183 let all_language_servers_with_this_name = local
11184 .language_server_ids
11185 .iter()
11186 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11187 language_servers_to_stop.extend(all_language_servers_with_this_name);
11188 old_ids_count == language_servers_to_stop.len()
11189 });
11190 }
11191 });
11192 }
11193 for name in language_server_names_to_stop {
11194 language_servers_to_stop.extend(
11195 local
11196 .language_server_ids
11197 .iter()
11198 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11199 );
11200 }
11201
11202 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11203 let tasks = language_servers_to_stop
11204 .into_iter()
11205 .map(|server| self.stop_local_language_server(server, cx))
11206 .collect::<Vec<_>>();
11207
11208 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11209 }
11210
11211 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11212 let (worktree, relative_path) =
11213 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11214
11215 let project_path = ProjectPath {
11216 worktree_id: worktree.read(cx).id(),
11217 path: relative_path,
11218 };
11219
11220 Some(
11221 self.buffer_store()
11222 .read(cx)
11223 .get_by_path(&project_path)?
11224 .read(cx),
11225 )
11226 }
11227
11228 #[cfg(any(test, feature = "test-support"))]
11229 pub fn update_diagnostics(
11230 &mut self,
11231 server_id: LanguageServerId,
11232 diagnostics: lsp::PublishDiagnosticsParams,
11233 result_id: Option<SharedString>,
11234 source_kind: DiagnosticSourceKind,
11235 disk_based_sources: &[String],
11236 cx: &mut Context<Self>,
11237 ) -> Result<()> {
11238 self.merge_lsp_diagnostics(
11239 source_kind,
11240 vec![DocumentDiagnosticsUpdate {
11241 diagnostics,
11242 result_id,
11243 server_id,
11244 disk_based_sources: Cow::Borrowed(disk_based_sources),
11245 registration_id: None,
11246 }],
11247 |_, _, _| false,
11248 cx,
11249 )
11250 }
11251
11252 pub fn merge_lsp_diagnostics(
11253 &mut self,
11254 source_kind: DiagnosticSourceKind,
11255 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11256 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11257 cx: &mut Context<Self>,
11258 ) -> Result<()> {
11259 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11260 let updates = lsp_diagnostics
11261 .into_iter()
11262 .filter_map(|update| {
11263 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11264 Some(DocumentDiagnosticsUpdate {
11265 diagnostics: self.lsp_to_document_diagnostics(
11266 abs_path,
11267 source_kind,
11268 update.server_id,
11269 update.diagnostics,
11270 &update.disk_based_sources,
11271 update.registration_id.clone(),
11272 ),
11273 result_id: update.result_id,
11274 server_id: update.server_id,
11275 disk_based_sources: update.disk_based_sources,
11276 registration_id: update.registration_id,
11277 })
11278 })
11279 .collect();
11280 self.merge_diagnostic_entries(updates, merge, cx)?;
11281 Ok(())
11282 }
11283
11284 fn lsp_to_document_diagnostics(
11285 &mut self,
11286 document_abs_path: PathBuf,
11287 source_kind: DiagnosticSourceKind,
11288 server_id: LanguageServerId,
11289 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11290 disk_based_sources: &[String],
11291 registration_id: Option<SharedString>,
11292 ) -> DocumentDiagnostics {
11293 let mut diagnostics = Vec::default();
11294 let mut primary_diagnostic_group_ids = HashMap::default();
11295 let mut sources_by_group_id = HashMap::default();
11296 let mut supporting_diagnostics = HashMap::default();
11297
11298 let adapter = self.language_server_adapter_for_id(server_id);
11299
11300 // Ensure that primary diagnostics are always the most severe
11301 lsp_diagnostics
11302 .diagnostics
11303 .sort_by_key(|item| item.severity);
11304
11305 for diagnostic in &lsp_diagnostics.diagnostics {
11306 let source = diagnostic.source.as_ref();
11307 let range = range_from_lsp(diagnostic.range);
11308 let is_supporting = diagnostic
11309 .related_information
11310 .as_ref()
11311 .is_some_and(|infos| {
11312 infos.iter().any(|info| {
11313 primary_diagnostic_group_ids.contains_key(&(
11314 source,
11315 diagnostic.code.clone(),
11316 range_from_lsp(info.location.range),
11317 ))
11318 })
11319 });
11320
11321 let is_unnecessary = diagnostic
11322 .tags
11323 .as_ref()
11324 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11325
11326 let underline = self
11327 .language_server_adapter_for_id(server_id)
11328 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11329
11330 if is_supporting {
11331 supporting_diagnostics.insert(
11332 (source, diagnostic.code.clone(), range),
11333 (diagnostic.severity, is_unnecessary),
11334 );
11335 } else {
11336 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11337 let is_disk_based =
11338 source.is_some_and(|source| disk_based_sources.contains(source));
11339
11340 sources_by_group_id.insert(group_id, source);
11341 primary_diagnostic_group_ids
11342 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11343
11344 diagnostics.push(DiagnosticEntry {
11345 range,
11346 diagnostic: Diagnostic {
11347 source: diagnostic.source.clone(),
11348 source_kind,
11349 code: diagnostic.code.clone(),
11350 code_description: diagnostic
11351 .code_description
11352 .as_ref()
11353 .and_then(|d| d.href.clone()),
11354 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11355 markdown: adapter.as_ref().and_then(|adapter| {
11356 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11357 }),
11358 message: diagnostic.message.trim().to_string(),
11359 group_id,
11360 is_primary: true,
11361 is_disk_based,
11362 is_unnecessary,
11363 underline,
11364 data: diagnostic.data.clone(),
11365 registration_id: registration_id.clone(),
11366 },
11367 });
11368 if let Some(infos) = &diagnostic.related_information {
11369 for info in infos {
11370 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11371 let range = range_from_lsp(info.location.range);
11372 diagnostics.push(DiagnosticEntry {
11373 range,
11374 diagnostic: Diagnostic {
11375 source: diagnostic.source.clone(),
11376 source_kind,
11377 code: diagnostic.code.clone(),
11378 code_description: diagnostic
11379 .code_description
11380 .as_ref()
11381 .and_then(|d| d.href.clone()),
11382 severity: DiagnosticSeverity::INFORMATION,
11383 markdown: adapter.as_ref().and_then(|adapter| {
11384 adapter.diagnostic_message_to_markdown(&info.message)
11385 }),
11386 message: info.message.trim().to_string(),
11387 group_id,
11388 is_primary: false,
11389 is_disk_based,
11390 is_unnecessary: false,
11391 underline,
11392 data: diagnostic.data.clone(),
11393 registration_id: registration_id.clone(),
11394 },
11395 });
11396 }
11397 }
11398 }
11399 }
11400 }
11401
11402 for entry in &mut diagnostics {
11403 let diagnostic = &mut entry.diagnostic;
11404 if !diagnostic.is_primary {
11405 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11406 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11407 source,
11408 diagnostic.code.clone(),
11409 entry.range.clone(),
11410 )) {
11411 if let Some(severity) = severity {
11412 diagnostic.severity = severity;
11413 }
11414 diagnostic.is_unnecessary = is_unnecessary;
11415 }
11416 }
11417 }
11418
11419 DocumentDiagnostics {
11420 diagnostics,
11421 document_abs_path,
11422 version: lsp_diagnostics.version,
11423 }
11424 }
11425
11426 fn insert_newly_running_language_server(
11427 &mut self,
11428 adapter: Arc<CachedLspAdapter>,
11429 language_server: Arc<LanguageServer>,
11430 server_id: LanguageServerId,
11431 key: LanguageServerSeed,
11432 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11433 cx: &mut Context<Self>,
11434 ) {
11435 let Some(local) = self.as_local_mut() else {
11436 return;
11437 };
11438 // If the language server for this key doesn't match the server id, don't store the
11439 // server. Which will cause it to be dropped, killing the process
11440 if local
11441 .language_server_ids
11442 .get(&key)
11443 .map(|state| state.id != server_id)
11444 .unwrap_or(false)
11445 {
11446 return;
11447 }
11448
11449 // Update language_servers collection with Running variant of LanguageServerState
11450 // indicating that the server is up and running and ready
11451 let workspace_folders = workspace_folders.lock().clone();
11452 language_server.set_workspace_folders(workspace_folders);
11453
11454 let workspace_diagnostics_refresh_tasks = language_server
11455 .capabilities()
11456 .diagnostic_provider
11457 .and_then(|provider| {
11458 local
11459 .language_server_dynamic_registrations
11460 .entry(server_id)
11461 .or_default()
11462 .diagnostics
11463 .entry(None)
11464 .or_insert(provider.clone());
11465 let workspace_refresher =
11466 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11467
11468 Some((None, workspace_refresher))
11469 })
11470 .into_iter()
11471 .collect();
11472 local.language_servers.insert(
11473 server_id,
11474 LanguageServerState::Running {
11475 workspace_diagnostics_refresh_tasks,
11476 adapter: adapter.clone(),
11477 server: language_server.clone(),
11478 simulate_disk_based_diagnostics_completion: None,
11479 },
11480 );
11481 local
11482 .languages
11483 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11484 if let Some(file_ops_caps) = language_server
11485 .capabilities()
11486 .workspace
11487 .as_ref()
11488 .and_then(|ws| ws.file_operations.as_ref())
11489 {
11490 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11491 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11492 if did_rename_caps.or(will_rename_caps).is_some() {
11493 let watcher = RenamePathsWatchedForServer::default()
11494 .with_did_rename_patterns(did_rename_caps)
11495 .with_will_rename_patterns(will_rename_caps);
11496 local
11497 .language_server_paths_watched_for_rename
11498 .insert(server_id, watcher);
11499 }
11500 }
11501
11502 self.language_server_statuses.insert(
11503 server_id,
11504 LanguageServerStatus {
11505 name: language_server.name(),
11506 server_version: language_server.version(),
11507 pending_work: Default::default(),
11508 has_pending_diagnostic_updates: false,
11509 progress_tokens: Default::default(),
11510 worktree: Some(key.worktree_id),
11511 binary: Some(language_server.binary().clone()),
11512 configuration: Some(language_server.configuration().clone()),
11513 workspace_folders: language_server.workspace_folders(),
11514 },
11515 );
11516
11517 cx.emit(LspStoreEvent::LanguageServerAdded(
11518 server_id,
11519 language_server.name(),
11520 Some(key.worktree_id),
11521 ));
11522
11523 let server_capabilities = language_server.capabilities();
11524 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11525 downstream_client
11526 .send(proto::StartLanguageServer {
11527 project_id: *project_id,
11528 server: Some(proto::LanguageServer {
11529 id: server_id.to_proto(),
11530 name: language_server.name().to_string(),
11531 worktree_id: Some(key.worktree_id.to_proto()),
11532 }),
11533 capabilities: serde_json::to_string(&server_capabilities)
11534 .expect("serializing server LSP capabilities"),
11535 })
11536 .log_err();
11537 }
11538 self.lsp_server_capabilities
11539 .insert(server_id, server_capabilities);
11540
11541 // Tell the language server about every open buffer in the worktree that matches the language.
11542 // Also check for buffers in worktrees that reused this server
11543 let mut worktrees_using_server = vec![key.worktree_id];
11544 if let Some(local) = self.as_local() {
11545 // Find all worktrees that have this server in their language server tree
11546 for (worktree_id, servers) in &local.lsp_tree.instances {
11547 if *worktree_id != key.worktree_id {
11548 for server_map in servers.roots.values() {
11549 if server_map
11550 .values()
11551 .any(|(node, _)| node.id() == Some(server_id))
11552 {
11553 worktrees_using_server.push(*worktree_id);
11554 }
11555 }
11556 }
11557 }
11558 }
11559
11560 let mut buffer_paths_registered = Vec::new();
11561 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11562 let mut lsp_adapters = HashMap::default();
11563 for buffer_handle in buffer_store.buffers() {
11564 let buffer = buffer_handle.read(cx);
11565 let file = match File::from_dyn(buffer.file()) {
11566 Some(file) => file,
11567 None => continue,
11568 };
11569 let language = match buffer.language() {
11570 Some(language) => language,
11571 None => continue,
11572 };
11573
11574 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11575 || !lsp_adapters
11576 .entry(language.name())
11577 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11578 .iter()
11579 .any(|a| a.name == key.name)
11580 {
11581 continue;
11582 }
11583 // didOpen
11584 let file = match file.as_local() {
11585 Some(file) => file,
11586 None => continue,
11587 };
11588
11589 let local = self.as_local_mut().unwrap();
11590
11591 let buffer_id = buffer.remote_id();
11592 if local.registered_buffers.contains_key(&buffer_id) {
11593 let versions = local
11594 .buffer_snapshots
11595 .entry(buffer_id)
11596 .or_default()
11597 .entry(server_id)
11598 .and_modify(|_| {
11599 assert!(
11600 false,
11601 "There should not be an existing snapshot for a newly inserted buffer"
11602 )
11603 })
11604 .or_insert_with(|| {
11605 vec![LspBufferSnapshot {
11606 version: 0,
11607 snapshot: buffer.text_snapshot(),
11608 }]
11609 });
11610
11611 let snapshot = versions.last().unwrap();
11612 let version = snapshot.version;
11613 let initial_snapshot = &snapshot.snapshot;
11614 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11615 language_server.register_buffer(
11616 uri,
11617 adapter.language_id(&language.name()),
11618 version,
11619 initial_snapshot.text(),
11620 );
11621 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11622 local
11623 .buffers_opened_in_servers
11624 .entry(buffer_id)
11625 .or_default()
11626 .insert(server_id);
11627 }
11628 buffer_handle.update(cx, |buffer, cx| {
11629 buffer.set_completion_triggers(
11630 server_id,
11631 language_server
11632 .capabilities()
11633 .completion_provider
11634 .as_ref()
11635 .and_then(|provider| {
11636 provider
11637 .trigger_characters
11638 .as_ref()
11639 .map(|characters| characters.iter().cloned().collect())
11640 })
11641 .unwrap_or_default(),
11642 cx,
11643 )
11644 });
11645 }
11646 });
11647
11648 for (buffer_id, abs_path) in buffer_paths_registered {
11649 cx.emit(LspStoreEvent::LanguageServerUpdate {
11650 language_server_id: server_id,
11651 name: Some(adapter.name()),
11652 message: proto::update_language_server::Variant::RegisteredForBuffer(
11653 proto::RegisteredForBuffer {
11654 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11655 buffer_id: buffer_id.to_proto(),
11656 },
11657 ),
11658 });
11659 }
11660
11661 cx.notify();
11662 }
11663
11664 pub fn language_servers_running_disk_based_diagnostics(
11665 &self,
11666 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11667 self.language_server_statuses
11668 .iter()
11669 .filter_map(|(id, status)| {
11670 if status.has_pending_diagnostic_updates {
11671 Some(*id)
11672 } else {
11673 None
11674 }
11675 })
11676 }
11677
11678 pub(crate) fn cancel_language_server_work_for_buffers(
11679 &mut self,
11680 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11681 cx: &mut Context<Self>,
11682 ) {
11683 if let Some((client, project_id)) = self.upstream_client() {
11684 let request = client.request(proto::CancelLanguageServerWork {
11685 project_id,
11686 work: Some(proto::cancel_language_server_work::Work::Buffers(
11687 proto::cancel_language_server_work::Buffers {
11688 buffer_ids: buffers
11689 .into_iter()
11690 .map(|b| b.read(cx).remote_id().to_proto())
11691 .collect(),
11692 },
11693 )),
11694 });
11695 cx.background_spawn(request).detach_and_log_err(cx);
11696 } else if let Some(local) = self.as_local() {
11697 let servers = buffers
11698 .into_iter()
11699 .flat_map(|buffer| {
11700 buffer.update(cx, |buffer, cx| {
11701 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11702 })
11703 })
11704 .collect::<HashSet<_>>();
11705 for server_id in servers {
11706 self.cancel_language_server_work(server_id, None, cx);
11707 }
11708 }
11709 }
11710
11711 pub(crate) fn cancel_language_server_work(
11712 &mut self,
11713 server_id: LanguageServerId,
11714 token_to_cancel: Option<ProgressToken>,
11715 cx: &mut Context<Self>,
11716 ) {
11717 if let Some(local) = self.as_local() {
11718 let status = self.language_server_statuses.get(&server_id);
11719 let server = local.language_servers.get(&server_id);
11720 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11721 {
11722 for (token, progress) in &status.pending_work {
11723 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11724 && token != token_to_cancel
11725 {
11726 continue;
11727 }
11728 if progress.is_cancellable {
11729 server
11730 .notify::<lsp::notification::WorkDoneProgressCancel>(
11731 WorkDoneProgressCancelParams {
11732 token: token.to_lsp(),
11733 },
11734 )
11735 .ok();
11736 }
11737 }
11738 }
11739 } else if let Some((client, project_id)) = self.upstream_client() {
11740 let request = client.request(proto::CancelLanguageServerWork {
11741 project_id,
11742 work: Some(
11743 proto::cancel_language_server_work::Work::LanguageServerWork(
11744 proto::cancel_language_server_work::LanguageServerWork {
11745 language_server_id: server_id.to_proto(),
11746 token: token_to_cancel.map(|token| token.to_proto()),
11747 },
11748 ),
11749 ),
11750 });
11751 cx.background_spawn(request).detach_and_log_err(cx);
11752 }
11753 }
11754
11755 fn register_supplementary_language_server(
11756 &mut self,
11757 id: LanguageServerId,
11758 name: LanguageServerName,
11759 server: Arc<LanguageServer>,
11760 cx: &mut Context<Self>,
11761 ) {
11762 if let Some(local) = self.as_local_mut() {
11763 local
11764 .supplementary_language_servers
11765 .insert(id, (name.clone(), server));
11766 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11767 }
11768 }
11769
11770 fn unregister_supplementary_language_server(
11771 &mut self,
11772 id: LanguageServerId,
11773 cx: &mut Context<Self>,
11774 ) {
11775 if let Some(local) = self.as_local_mut() {
11776 local.supplementary_language_servers.remove(&id);
11777 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11778 }
11779 }
11780
11781 pub(crate) fn supplementary_language_servers(
11782 &self,
11783 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11784 self.as_local().into_iter().flat_map(|local| {
11785 local
11786 .supplementary_language_servers
11787 .iter()
11788 .map(|(id, (name, _))| (*id, name.clone()))
11789 })
11790 }
11791
11792 pub fn language_server_adapter_for_id(
11793 &self,
11794 id: LanguageServerId,
11795 ) -> Option<Arc<CachedLspAdapter>> {
11796 self.as_local()
11797 .and_then(|local| local.language_servers.get(&id))
11798 .and_then(|language_server_state| match language_server_state {
11799 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11800 _ => None,
11801 })
11802 }
11803
11804 pub(super) fn update_local_worktree_language_servers(
11805 &mut self,
11806 worktree_handle: &Entity<Worktree>,
11807 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11808 cx: &mut Context<Self>,
11809 ) {
11810 if changes.is_empty() {
11811 return;
11812 }
11813
11814 let Some(local) = self.as_local() else { return };
11815
11816 local.prettier_store.update(cx, |prettier_store, cx| {
11817 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11818 });
11819
11820 let worktree_id = worktree_handle.read(cx).id();
11821 let mut language_server_ids = local
11822 .language_server_ids
11823 .iter()
11824 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11825 .collect::<Vec<_>>();
11826 language_server_ids.sort();
11827 language_server_ids.dedup();
11828
11829 // let abs_path = worktree_handle.read(cx).abs_path();
11830 for server_id in &language_server_ids {
11831 if let Some(LanguageServerState::Running { server, .. }) =
11832 local.language_servers.get(server_id)
11833 && let Some(watched_paths) = local
11834 .language_server_watched_paths
11835 .get(server_id)
11836 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11837 {
11838 let params = lsp::DidChangeWatchedFilesParams {
11839 changes: changes
11840 .iter()
11841 .filter_map(|(path, _, change)| {
11842 if !watched_paths.is_match(path.as_std_path()) {
11843 return None;
11844 }
11845 let typ = match change {
11846 PathChange::Loaded => return None,
11847 PathChange::Added => lsp::FileChangeType::CREATED,
11848 PathChange::Removed => lsp::FileChangeType::DELETED,
11849 PathChange::Updated => lsp::FileChangeType::CHANGED,
11850 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11851 };
11852 let uri = lsp::Uri::from_file_path(
11853 worktree_handle.read(cx).absolutize(&path),
11854 )
11855 .ok()?;
11856 Some(lsp::FileEvent { uri, typ })
11857 })
11858 .collect(),
11859 };
11860 if !params.changes.is_empty() {
11861 server
11862 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11863 .ok();
11864 }
11865 }
11866 }
11867 for (path, _, _) in changes {
11868 if let Some(file_name) = path.file_name()
11869 && local.watched_manifest_filenames.contains(file_name)
11870 {
11871 self.request_workspace_config_refresh();
11872 break;
11873 }
11874 }
11875 }
11876
11877 pub fn wait_for_remote_buffer(
11878 &mut self,
11879 id: BufferId,
11880 cx: &mut Context<Self>,
11881 ) -> Task<Result<Entity<Buffer>>> {
11882 self.buffer_store.update(cx, |buffer_store, cx| {
11883 buffer_store.wait_for_remote_buffer(id, cx)
11884 })
11885 }
11886
11887 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11888 let mut result = proto::Symbol {
11889 language_server_name: symbol.language_server_name.0.to_string(),
11890 source_worktree_id: symbol.source_worktree_id.to_proto(),
11891 language_server_id: symbol.source_language_server_id.to_proto(),
11892 name: symbol.name.clone(),
11893 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11894 start: Some(proto::PointUtf16 {
11895 row: symbol.range.start.0.row,
11896 column: symbol.range.start.0.column,
11897 }),
11898 end: Some(proto::PointUtf16 {
11899 row: symbol.range.end.0.row,
11900 column: symbol.range.end.0.column,
11901 }),
11902 worktree_id: Default::default(),
11903 path: Default::default(),
11904 signature: Default::default(),
11905 };
11906 match &symbol.path {
11907 SymbolLocation::InProject(path) => {
11908 result.worktree_id = path.worktree_id.to_proto();
11909 result.path = path.path.to_proto();
11910 }
11911 SymbolLocation::OutsideProject {
11912 abs_path,
11913 signature,
11914 } => {
11915 result.path = abs_path.to_string_lossy().into_owned();
11916 result.signature = signature.to_vec();
11917 }
11918 }
11919 result
11920 }
11921
11922 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11923 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11924 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11925 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11926
11927 let path = if serialized_symbol.signature.is_empty() {
11928 SymbolLocation::InProject(ProjectPath {
11929 worktree_id,
11930 path: RelPath::from_proto(&serialized_symbol.path)
11931 .context("invalid symbol path")?,
11932 })
11933 } else {
11934 SymbolLocation::OutsideProject {
11935 abs_path: Path::new(&serialized_symbol.path).into(),
11936 signature: serialized_symbol
11937 .signature
11938 .try_into()
11939 .map_err(|_| anyhow!("invalid signature"))?,
11940 }
11941 };
11942
11943 let start = serialized_symbol.start.context("invalid start")?;
11944 let end = serialized_symbol.end.context("invalid end")?;
11945 Ok(CoreSymbol {
11946 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11947 source_worktree_id,
11948 source_language_server_id: LanguageServerId::from_proto(
11949 serialized_symbol.language_server_id,
11950 ),
11951 path,
11952 name: serialized_symbol.name,
11953 range: Unclipped(PointUtf16::new(start.row, start.column))
11954 ..Unclipped(PointUtf16::new(end.row, end.column)),
11955 kind,
11956 })
11957 }
11958
11959 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11960 let mut serialized_completion = proto::Completion {
11961 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11962 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11963 new_text: completion.new_text.clone(),
11964 ..proto::Completion::default()
11965 };
11966 match &completion.source {
11967 CompletionSource::Lsp {
11968 insert_range,
11969 server_id,
11970 lsp_completion,
11971 lsp_defaults,
11972 resolved,
11973 } => {
11974 let (old_insert_start, old_insert_end) = insert_range
11975 .as_ref()
11976 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11977 .unzip();
11978
11979 serialized_completion.old_insert_start = old_insert_start;
11980 serialized_completion.old_insert_end = old_insert_end;
11981 serialized_completion.source = proto::completion::Source::Lsp as i32;
11982 serialized_completion.server_id = server_id.0 as u64;
11983 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11984 serialized_completion.lsp_defaults = lsp_defaults
11985 .as_deref()
11986 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11987 serialized_completion.resolved = *resolved;
11988 }
11989 CompletionSource::BufferWord {
11990 word_range,
11991 resolved,
11992 } => {
11993 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11994 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11995 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11996 serialized_completion.resolved = *resolved;
11997 }
11998 CompletionSource::Custom => {
11999 serialized_completion.source = proto::completion::Source::Custom as i32;
12000 serialized_completion.resolved = true;
12001 }
12002 CompletionSource::Dap { sort_text } => {
12003 serialized_completion.source = proto::completion::Source::Dap as i32;
12004 serialized_completion.sort_text = Some(sort_text.clone());
12005 }
12006 }
12007
12008 serialized_completion
12009 }
12010
12011 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12012 let old_replace_start = completion
12013 .old_replace_start
12014 .and_then(deserialize_anchor)
12015 .context("invalid old start")?;
12016 let old_replace_end = completion
12017 .old_replace_end
12018 .and_then(deserialize_anchor)
12019 .context("invalid old end")?;
12020 let insert_range = {
12021 match completion.old_insert_start.zip(completion.old_insert_end) {
12022 Some((start, end)) => {
12023 let start = deserialize_anchor(start).context("invalid insert old start")?;
12024 let end = deserialize_anchor(end).context("invalid insert old end")?;
12025 Some(start..end)
12026 }
12027 None => None,
12028 }
12029 };
12030 Ok(CoreCompletion {
12031 replace_range: old_replace_start..old_replace_end,
12032 new_text: completion.new_text,
12033 source: match proto::completion::Source::from_i32(completion.source) {
12034 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12035 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12036 insert_range,
12037 server_id: LanguageServerId::from_proto(completion.server_id),
12038 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12039 lsp_defaults: completion
12040 .lsp_defaults
12041 .as_deref()
12042 .map(serde_json::from_slice)
12043 .transpose()?,
12044 resolved: completion.resolved,
12045 },
12046 Some(proto::completion::Source::BufferWord) => {
12047 let word_range = completion
12048 .buffer_word_start
12049 .and_then(deserialize_anchor)
12050 .context("invalid buffer word start")?
12051 ..completion
12052 .buffer_word_end
12053 .and_then(deserialize_anchor)
12054 .context("invalid buffer word end")?;
12055 CompletionSource::BufferWord {
12056 word_range,
12057 resolved: completion.resolved,
12058 }
12059 }
12060 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12061 sort_text: completion
12062 .sort_text
12063 .context("expected sort text to exist")?,
12064 },
12065 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12066 },
12067 })
12068 }
12069
12070 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12071 let (kind, lsp_action) = match &action.lsp_action {
12072 LspAction::Action(code_action) => (
12073 proto::code_action::Kind::Action as i32,
12074 serde_json::to_vec(code_action).unwrap(),
12075 ),
12076 LspAction::Command(command) => (
12077 proto::code_action::Kind::Command as i32,
12078 serde_json::to_vec(command).unwrap(),
12079 ),
12080 LspAction::CodeLens(code_lens) => (
12081 proto::code_action::Kind::CodeLens as i32,
12082 serde_json::to_vec(code_lens).unwrap(),
12083 ),
12084 };
12085
12086 proto::CodeAction {
12087 server_id: action.server_id.0 as u64,
12088 start: Some(serialize_anchor(&action.range.start)),
12089 end: Some(serialize_anchor(&action.range.end)),
12090 lsp_action,
12091 kind,
12092 resolved: action.resolved,
12093 }
12094 }
12095
12096 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12097 let start = action
12098 .start
12099 .and_then(deserialize_anchor)
12100 .context("invalid start")?;
12101 let end = action
12102 .end
12103 .and_then(deserialize_anchor)
12104 .context("invalid end")?;
12105 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12106 Some(proto::code_action::Kind::Action) => {
12107 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12108 }
12109 Some(proto::code_action::Kind::Command) => {
12110 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12111 }
12112 Some(proto::code_action::Kind::CodeLens) => {
12113 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12114 }
12115 None => anyhow::bail!("Unknown action kind {}", action.kind),
12116 };
12117 Ok(CodeAction {
12118 server_id: LanguageServerId(action.server_id as usize),
12119 range: start..end,
12120 resolved: action.resolved,
12121 lsp_action,
12122 })
12123 }
12124
12125 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12126 match &formatting_result {
12127 Ok(_) => self.last_formatting_failure = None,
12128 Err(error) => {
12129 let error_string = format!("{error:#}");
12130 log::error!("Formatting failed: {error_string}");
12131 self.last_formatting_failure
12132 .replace(error_string.lines().join(" "));
12133 }
12134 }
12135 }
12136
12137 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12138 self.lsp_server_capabilities.remove(&for_server);
12139 for lsp_data in self.lsp_data.values_mut() {
12140 lsp_data.remove_server_data(for_server);
12141 }
12142 if let Some(local) = self.as_local_mut() {
12143 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12144 local
12145 .workspace_pull_diagnostics_result_ids
12146 .remove(&for_server);
12147 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12148 buffer_servers.remove(&for_server);
12149 }
12150 }
12151 }
12152
12153 pub fn result_id_for_buffer_pull(
12154 &self,
12155 server_id: LanguageServerId,
12156 buffer_id: BufferId,
12157 registration_id: &Option<SharedString>,
12158 cx: &App,
12159 ) -> Option<SharedString> {
12160 let abs_path = self
12161 .buffer_store
12162 .read(cx)
12163 .get(buffer_id)
12164 .and_then(|b| File::from_dyn(b.read(cx).file()))
12165 .map(|f| f.abs_path(cx))?;
12166 self.as_local()?
12167 .buffer_pull_diagnostics_result_ids
12168 .get(&server_id)?
12169 .get(registration_id)?
12170 .get(&abs_path)?
12171 .clone()
12172 }
12173
12174 /// Gets all result_ids for a workspace diagnostics pull request.
12175 /// 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.
12176 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12177 pub fn result_ids_for_workspace_refresh(
12178 &self,
12179 server_id: LanguageServerId,
12180 registration_id: &Option<SharedString>,
12181 ) -> HashMap<PathBuf, SharedString> {
12182 let Some(local) = self.as_local() else {
12183 return HashMap::default();
12184 };
12185 local
12186 .workspace_pull_diagnostics_result_ids
12187 .get(&server_id)
12188 .into_iter()
12189 .filter_map(|diagnostics| diagnostics.get(registration_id))
12190 .flatten()
12191 .filter_map(|(abs_path, result_id)| {
12192 let result_id = local
12193 .buffer_pull_diagnostics_result_ids
12194 .get(&server_id)
12195 .and_then(|buffer_ids_result_ids| {
12196 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12197 })
12198 .cloned()
12199 .flatten()
12200 .or_else(|| result_id.clone())?;
12201 Some((abs_path.clone(), result_id))
12202 })
12203 .collect()
12204 }
12205
12206 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12207 if let Some(LanguageServerState::Running {
12208 workspace_diagnostics_refresh_tasks,
12209 ..
12210 }) = self
12211 .as_local_mut()
12212 .and_then(|local| local.language_servers.get_mut(&server_id))
12213 {
12214 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12215 diagnostics.refresh_tx.try_send(()).ok();
12216 }
12217 }
12218 }
12219
12220 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12221 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12222 /// which requires refreshing both workspace and document diagnostics.
12223 pub fn pull_document_diagnostics_for_server(
12224 &mut self,
12225 server_id: LanguageServerId,
12226 cx: &mut Context<Self>,
12227 ) -> Task<()> {
12228 let buffers_to_pull = self
12229 .as_local()
12230 .into_iter()
12231 .flat_map(|local| {
12232 self.buffer_store.read(cx).buffers().filter(|buffer| {
12233 let buffer_id = buffer.read(cx).remote_id();
12234 local
12235 .buffers_opened_in_servers
12236 .get(&buffer_id)
12237 .is_some_and(|servers| servers.contains(&server_id))
12238 })
12239 })
12240 .collect::<Vec<_>>();
12241
12242 let pulls = join_all(buffers_to_pull.into_iter().map(|buffer| {
12243 let buffer_path = buffer.read(cx).file().map(|f| f.full_path(cx));
12244 let pull_task = self.pull_diagnostics_for_buffer(buffer, cx);
12245 async move { (buffer_path, pull_task.await) }
12246 }));
12247 cx.background_spawn(async move {
12248 for (pull_task_path, pull_task_result) in pulls.await {
12249 if let Err(e) = pull_task_result {
12250 match pull_task_path {
12251 Some(path) => {
12252 log::error!("Failed to pull diagnostics for buffer {path:?}: {e:#}");
12253 }
12254 None => log::error!("Failed to pull diagnostics: {e:#}"),
12255 }
12256 }
12257 }
12258 })
12259 }
12260
12261 fn apply_workspace_diagnostic_report(
12262 &mut self,
12263 server_id: LanguageServerId,
12264 report: lsp::WorkspaceDiagnosticReportResult,
12265 registration_id: Option<SharedString>,
12266 cx: &mut Context<Self>,
12267 ) {
12268 let mut workspace_diagnostics =
12269 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12270 report,
12271 server_id,
12272 registration_id,
12273 );
12274 workspace_diagnostics.retain(|d| match &d.diagnostics {
12275 LspPullDiagnostics::Response {
12276 server_id,
12277 registration_id,
12278 ..
12279 } => self.diagnostic_registration_exists(*server_id, registration_id),
12280 LspPullDiagnostics::Default => false,
12281 });
12282 let mut unchanged_buffers = HashMap::default();
12283 let workspace_diagnostics_updates = workspace_diagnostics
12284 .into_iter()
12285 .filter_map(
12286 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12287 LspPullDiagnostics::Response {
12288 server_id,
12289 uri,
12290 diagnostics,
12291 registration_id,
12292 } => Some((
12293 server_id,
12294 uri,
12295 diagnostics,
12296 workspace_diagnostics.version,
12297 registration_id,
12298 )),
12299 LspPullDiagnostics::Default => None,
12300 },
12301 )
12302 .fold(
12303 HashMap::default(),
12304 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12305 let (result_id, diagnostics) = match diagnostics {
12306 PulledDiagnostics::Unchanged { result_id } => {
12307 unchanged_buffers
12308 .entry(new_registration_id.clone())
12309 .or_insert_with(HashSet::default)
12310 .insert(uri.clone());
12311 (Some(result_id), Vec::new())
12312 }
12313 PulledDiagnostics::Changed {
12314 result_id,
12315 diagnostics,
12316 } => (result_id, diagnostics),
12317 };
12318 let disk_based_sources = Cow::Owned(
12319 self.language_server_adapter_for_id(server_id)
12320 .as_ref()
12321 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12322 .unwrap_or(&[])
12323 .to_vec(),
12324 );
12325
12326 let Some(abs_path) = uri.to_file_path().ok() else {
12327 return acc;
12328 };
12329 let Some((worktree, relative_path)) =
12330 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12331 else {
12332 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12333 return acc;
12334 };
12335 let worktree_id = worktree.read(cx).id();
12336 let project_path = ProjectPath {
12337 worktree_id,
12338 path: relative_path,
12339 };
12340 if let Some(local_lsp_store) = self.as_local_mut() {
12341 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12342 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12343 }
12344 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12345 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12346 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12347 acc.entry(server_id)
12348 .or_insert_with(HashMap::default)
12349 .entry(new_registration_id.clone())
12350 .or_insert_with(Vec::new)
12351 .push(DocumentDiagnosticsUpdate {
12352 server_id,
12353 diagnostics: lsp::PublishDiagnosticsParams {
12354 uri,
12355 diagnostics,
12356 version,
12357 },
12358 result_id,
12359 disk_based_sources,
12360 registration_id: new_registration_id,
12361 });
12362 }
12363 acc
12364 },
12365 );
12366
12367 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12368 for (registration_id, diagnostic_updates) in diagnostic_updates {
12369 self.merge_lsp_diagnostics(
12370 DiagnosticSourceKind::Pulled,
12371 diagnostic_updates,
12372 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12373 DiagnosticSourceKind::Pulled => {
12374 old_diagnostic.registration_id != registration_id
12375 || unchanged_buffers
12376 .get(&old_diagnostic.registration_id)
12377 .is_some_and(|unchanged_buffers| {
12378 unchanged_buffers.contains(&document_uri)
12379 })
12380 }
12381 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12382 },
12383 cx,
12384 )
12385 .log_err();
12386 }
12387 }
12388 }
12389
12390 fn register_server_capabilities(
12391 &mut self,
12392 server_id: LanguageServerId,
12393 params: lsp::RegistrationParams,
12394 cx: &mut Context<Self>,
12395 ) -> anyhow::Result<()> {
12396 let server = self
12397 .language_server_for_id(server_id)
12398 .with_context(|| format!("no server {server_id} found"))?;
12399 for reg in params.registrations {
12400 match reg.method.as_str() {
12401 "workspace/didChangeWatchedFiles" => {
12402 if let Some(options) = reg.register_options {
12403 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12404 let caps = serde_json::from_value(options)?;
12405 local_lsp_store
12406 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12407 true
12408 } else {
12409 false
12410 };
12411 if notify {
12412 notify_server_capabilities_updated(&server, cx);
12413 }
12414 }
12415 }
12416 "workspace/didChangeConfiguration" => {
12417 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12418 }
12419 "workspace/didChangeWorkspaceFolders" => {
12420 // In this case register options is an empty object, we can ignore it
12421 let caps = lsp::WorkspaceFoldersServerCapabilities {
12422 supported: Some(true),
12423 change_notifications: Some(OneOf::Right(reg.id)),
12424 };
12425 server.update_capabilities(|capabilities| {
12426 capabilities
12427 .workspace
12428 .get_or_insert_default()
12429 .workspace_folders = Some(caps);
12430 });
12431 notify_server_capabilities_updated(&server, cx);
12432 }
12433 "workspace/symbol" => {
12434 let options = parse_register_capabilities(reg)?;
12435 server.update_capabilities(|capabilities| {
12436 capabilities.workspace_symbol_provider = Some(options);
12437 });
12438 notify_server_capabilities_updated(&server, cx);
12439 }
12440 "workspace/fileOperations" => {
12441 if let Some(options) = reg.register_options {
12442 let caps = serde_json::from_value(options)?;
12443 server.update_capabilities(|capabilities| {
12444 capabilities
12445 .workspace
12446 .get_or_insert_default()
12447 .file_operations = Some(caps);
12448 });
12449 notify_server_capabilities_updated(&server, cx);
12450 }
12451 }
12452 "workspace/executeCommand" => {
12453 if let Some(options) = reg.register_options {
12454 let options = serde_json::from_value(options)?;
12455 server.update_capabilities(|capabilities| {
12456 capabilities.execute_command_provider = Some(options);
12457 });
12458 notify_server_capabilities_updated(&server, cx);
12459 }
12460 }
12461 "textDocument/rangeFormatting" => {
12462 let options = parse_register_capabilities(reg)?;
12463 server.update_capabilities(|capabilities| {
12464 capabilities.document_range_formatting_provider = Some(options);
12465 });
12466 notify_server_capabilities_updated(&server, cx);
12467 }
12468 "textDocument/onTypeFormatting" => {
12469 if let Some(options) = reg
12470 .register_options
12471 .map(serde_json::from_value)
12472 .transpose()?
12473 {
12474 server.update_capabilities(|capabilities| {
12475 capabilities.document_on_type_formatting_provider = Some(options);
12476 });
12477 notify_server_capabilities_updated(&server, cx);
12478 }
12479 }
12480 "textDocument/formatting" => {
12481 let options = parse_register_capabilities(reg)?;
12482 server.update_capabilities(|capabilities| {
12483 capabilities.document_formatting_provider = Some(options);
12484 });
12485 notify_server_capabilities_updated(&server, cx);
12486 }
12487 "textDocument/rename" => {
12488 let options = parse_register_capabilities(reg)?;
12489 server.update_capabilities(|capabilities| {
12490 capabilities.rename_provider = Some(options);
12491 });
12492 notify_server_capabilities_updated(&server, cx);
12493 }
12494 "textDocument/inlayHint" => {
12495 let options = parse_register_capabilities(reg)?;
12496 server.update_capabilities(|capabilities| {
12497 capabilities.inlay_hint_provider = Some(options);
12498 });
12499 notify_server_capabilities_updated(&server, cx);
12500 }
12501 "textDocument/documentSymbol" => {
12502 let options = parse_register_capabilities(reg)?;
12503 server.update_capabilities(|capabilities| {
12504 capabilities.document_symbol_provider = Some(options);
12505 });
12506 notify_server_capabilities_updated(&server, cx);
12507 }
12508 "textDocument/codeAction" => {
12509 let options = parse_register_capabilities(reg)?;
12510 let provider = match options {
12511 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12512 OneOf::Right(caps) => caps,
12513 };
12514 server.update_capabilities(|capabilities| {
12515 capabilities.code_action_provider = Some(provider);
12516 });
12517 notify_server_capabilities_updated(&server, cx);
12518 }
12519 "textDocument/definition" => {
12520 let options = parse_register_capabilities(reg)?;
12521 server.update_capabilities(|capabilities| {
12522 capabilities.definition_provider = Some(options);
12523 });
12524 notify_server_capabilities_updated(&server, cx);
12525 }
12526 "textDocument/completion" => {
12527 if let Some(caps) = reg
12528 .register_options
12529 .map(serde_json::from_value::<CompletionOptions>)
12530 .transpose()?
12531 {
12532 server.update_capabilities(|capabilities| {
12533 capabilities.completion_provider = Some(caps.clone());
12534 });
12535
12536 if let Some(local) = self.as_local() {
12537 let mut buffers_with_language_server = Vec::new();
12538 for handle in self.buffer_store.read(cx).buffers() {
12539 let buffer_id = handle.read(cx).remote_id();
12540 if local
12541 .buffers_opened_in_servers
12542 .get(&buffer_id)
12543 .filter(|s| s.contains(&server_id))
12544 .is_some()
12545 {
12546 buffers_with_language_server.push(handle);
12547 }
12548 }
12549 let triggers = caps
12550 .trigger_characters
12551 .unwrap_or_default()
12552 .into_iter()
12553 .collect::<BTreeSet<_>>();
12554 for handle in buffers_with_language_server {
12555 let triggers = triggers.clone();
12556 let _ = handle.update(cx, move |buffer, cx| {
12557 buffer.set_completion_triggers(server_id, triggers, cx);
12558 });
12559 }
12560 }
12561 notify_server_capabilities_updated(&server, cx);
12562 }
12563 }
12564 "textDocument/hover" => {
12565 let options = parse_register_capabilities(reg)?;
12566 let provider = match options {
12567 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12568 OneOf::Right(caps) => caps,
12569 };
12570 server.update_capabilities(|capabilities| {
12571 capabilities.hover_provider = Some(provider);
12572 });
12573 notify_server_capabilities_updated(&server, cx);
12574 }
12575 "textDocument/signatureHelp" => {
12576 if let Some(caps) = reg
12577 .register_options
12578 .map(serde_json::from_value)
12579 .transpose()?
12580 {
12581 server.update_capabilities(|capabilities| {
12582 capabilities.signature_help_provider = Some(caps);
12583 });
12584 notify_server_capabilities_updated(&server, cx);
12585 }
12586 }
12587 "textDocument/didChange" => {
12588 if let Some(sync_kind) = reg
12589 .register_options
12590 .and_then(|opts| opts.get("syncKind").cloned())
12591 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12592 .transpose()?
12593 {
12594 server.update_capabilities(|capabilities| {
12595 let mut sync_options =
12596 Self::take_text_document_sync_options(capabilities);
12597 sync_options.change = Some(sync_kind);
12598 capabilities.text_document_sync =
12599 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12600 });
12601 notify_server_capabilities_updated(&server, cx);
12602 }
12603 }
12604 "textDocument/didSave" => {
12605 if let Some(include_text) = reg
12606 .register_options
12607 .map(|opts| {
12608 let transpose = opts
12609 .get("includeText")
12610 .cloned()
12611 .map(serde_json::from_value::<Option<bool>>)
12612 .transpose();
12613 match transpose {
12614 Ok(value) => Ok(value.flatten()),
12615 Err(e) => Err(e),
12616 }
12617 })
12618 .transpose()?
12619 {
12620 server.update_capabilities(|capabilities| {
12621 let mut sync_options =
12622 Self::take_text_document_sync_options(capabilities);
12623 sync_options.save =
12624 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12625 include_text,
12626 }));
12627 capabilities.text_document_sync =
12628 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12629 });
12630 notify_server_capabilities_updated(&server, cx);
12631 }
12632 }
12633 "textDocument/codeLens" => {
12634 if let Some(caps) = reg
12635 .register_options
12636 .map(serde_json::from_value)
12637 .transpose()?
12638 {
12639 server.update_capabilities(|capabilities| {
12640 capabilities.code_lens_provider = Some(caps);
12641 });
12642 notify_server_capabilities_updated(&server, cx);
12643 }
12644 }
12645 "textDocument/diagnostic" => {
12646 if let Some(caps) = reg
12647 .register_options
12648 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12649 .transpose()?
12650 {
12651 let local = self
12652 .as_local_mut()
12653 .context("Expected LSP Store to be local")?;
12654 let state = local
12655 .language_servers
12656 .get_mut(&server_id)
12657 .context("Could not obtain Language Servers state")?;
12658 local
12659 .language_server_dynamic_registrations
12660 .entry(server_id)
12661 .or_default()
12662 .diagnostics
12663 .insert(Some(reg.id.clone()), caps.clone());
12664
12665 let supports_workspace_diagnostics =
12666 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12667 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12668 diagnostic_options.workspace_diagnostics
12669 }
12670 DiagnosticServerCapabilities::RegistrationOptions(
12671 diagnostic_registration_options,
12672 ) => {
12673 diagnostic_registration_options
12674 .diagnostic_options
12675 .workspace_diagnostics
12676 }
12677 };
12678
12679 if supports_workspace_diagnostics(&caps) {
12680 if let LanguageServerState::Running {
12681 workspace_diagnostics_refresh_tasks,
12682 ..
12683 } = state
12684 && let Some(task) = lsp_workspace_diagnostics_refresh(
12685 Some(reg.id.clone()),
12686 caps.clone(),
12687 server.clone(),
12688 cx,
12689 )
12690 {
12691 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12692 }
12693 }
12694
12695 server.update_capabilities(|capabilities| {
12696 capabilities.diagnostic_provider = Some(caps);
12697 });
12698
12699 notify_server_capabilities_updated(&server, cx);
12700
12701 self.pull_document_diagnostics_for_server(server_id, cx)
12702 .detach();
12703 }
12704 }
12705 "textDocument/documentColor" => {
12706 let options = parse_register_capabilities(reg)?;
12707 let provider = match options {
12708 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12709 OneOf::Right(caps) => caps,
12710 };
12711 server.update_capabilities(|capabilities| {
12712 capabilities.color_provider = Some(provider);
12713 });
12714 notify_server_capabilities_updated(&server, cx);
12715 }
12716 _ => log::warn!("unhandled capability registration: {reg:?}"),
12717 }
12718 }
12719
12720 Ok(())
12721 }
12722
12723 fn unregister_server_capabilities(
12724 &mut self,
12725 server_id: LanguageServerId,
12726 params: lsp::UnregistrationParams,
12727 cx: &mut Context<Self>,
12728 ) -> anyhow::Result<()> {
12729 let server = self
12730 .language_server_for_id(server_id)
12731 .with_context(|| format!("no server {server_id} found"))?;
12732 for unreg in params.unregisterations.iter() {
12733 match unreg.method.as_str() {
12734 "workspace/didChangeWatchedFiles" => {
12735 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12736 local_lsp_store
12737 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12738 true
12739 } else {
12740 false
12741 };
12742 if notify {
12743 notify_server_capabilities_updated(&server, cx);
12744 }
12745 }
12746 "workspace/didChangeConfiguration" => {
12747 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12748 }
12749 "workspace/didChangeWorkspaceFolders" => {
12750 server.update_capabilities(|capabilities| {
12751 capabilities
12752 .workspace
12753 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12754 workspace_folders: None,
12755 file_operations: None,
12756 })
12757 .workspace_folders = None;
12758 });
12759 notify_server_capabilities_updated(&server, cx);
12760 }
12761 "workspace/symbol" => {
12762 server.update_capabilities(|capabilities| {
12763 capabilities.workspace_symbol_provider = None
12764 });
12765 notify_server_capabilities_updated(&server, cx);
12766 }
12767 "workspace/fileOperations" => {
12768 server.update_capabilities(|capabilities| {
12769 capabilities
12770 .workspace
12771 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12772 workspace_folders: None,
12773 file_operations: None,
12774 })
12775 .file_operations = None;
12776 });
12777 notify_server_capabilities_updated(&server, cx);
12778 }
12779 "workspace/executeCommand" => {
12780 server.update_capabilities(|capabilities| {
12781 capabilities.execute_command_provider = None;
12782 });
12783 notify_server_capabilities_updated(&server, cx);
12784 }
12785 "textDocument/rangeFormatting" => {
12786 server.update_capabilities(|capabilities| {
12787 capabilities.document_range_formatting_provider = None
12788 });
12789 notify_server_capabilities_updated(&server, cx);
12790 }
12791 "textDocument/onTypeFormatting" => {
12792 server.update_capabilities(|capabilities| {
12793 capabilities.document_on_type_formatting_provider = None;
12794 });
12795 notify_server_capabilities_updated(&server, cx);
12796 }
12797 "textDocument/formatting" => {
12798 server.update_capabilities(|capabilities| {
12799 capabilities.document_formatting_provider = None;
12800 });
12801 notify_server_capabilities_updated(&server, cx);
12802 }
12803 "textDocument/rename" => {
12804 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12805 notify_server_capabilities_updated(&server, cx);
12806 }
12807 "textDocument/codeAction" => {
12808 server.update_capabilities(|capabilities| {
12809 capabilities.code_action_provider = None;
12810 });
12811 notify_server_capabilities_updated(&server, cx);
12812 }
12813 "textDocument/definition" => {
12814 server.update_capabilities(|capabilities| {
12815 capabilities.definition_provider = None;
12816 });
12817 notify_server_capabilities_updated(&server, cx);
12818 }
12819 "textDocument/completion" => {
12820 server.update_capabilities(|capabilities| {
12821 capabilities.completion_provider = None;
12822 });
12823 notify_server_capabilities_updated(&server, cx);
12824 }
12825 "textDocument/hover" => {
12826 server.update_capabilities(|capabilities| {
12827 capabilities.hover_provider = None;
12828 });
12829 notify_server_capabilities_updated(&server, cx);
12830 }
12831 "textDocument/signatureHelp" => {
12832 server.update_capabilities(|capabilities| {
12833 capabilities.signature_help_provider = None;
12834 });
12835 notify_server_capabilities_updated(&server, cx);
12836 }
12837 "textDocument/didChange" => {
12838 server.update_capabilities(|capabilities| {
12839 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12840 sync_options.change = None;
12841 capabilities.text_document_sync =
12842 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12843 });
12844 notify_server_capabilities_updated(&server, cx);
12845 }
12846 "textDocument/didSave" => {
12847 server.update_capabilities(|capabilities| {
12848 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12849 sync_options.save = None;
12850 capabilities.text_document_sync =
12851 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12852 });
12853 notify_server_capabilities_updated(&server, cx);
12854 }
12855 "textDocument/codeLens" => {
12856 server.update_capabilities(|capabilities| {
12857 capabilities.code_lens_provider = None;
12858 });
12859 notify_server_capabilities_updated(&server, cx);
12860 }
12861 "textDocument/diagnostic" => {
12862 let local = self
12863 .as_local_mut()
12864 .context("Expected LSP Store to be local")?;
12865
12866 let state = local
12867 .language_servers
12868 .get_mut(&server_id)
12869 .context("Could not obtain Language Servers state")?;
12870 let registrations = local
12871 .language_server_dynamic_registrations
12872 .get_mut(&server_id)
12873 .with_context(|| {
12874 format!("Expected dynamic registration to exist for server {server_id}")
12875 })?;
12876 registrations.diagnostics
12877 .remove(&Some(unreg.id.clone()))
12878 .with_context(|| format!(
12879 "Attempted to unregister non-existent diagnostic registration with ID {}",
12880 unreg.id)
12881 )?;
12882 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12883
12884 if let LanguageServerState::Running {
12885 workspace_diagnostics_refresh_tasks,
12886 ..
12887 } = state
12888 {
12889 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12890 }
12891
12892 self.clear_unregistered_diagnostics(
12893 server_id,
12894 SharedString::from(unreg.id.clone()),
12895 cx,
12896 )?;
12897
12898 if removed_last_diagnostic_provider {
12899 server.update_capabilities(|capabilities| {
12900 debug_assert!(capabilities.diagnostic_provider.is_some());
12901 capabilities.diagnostic_provider = None;
12902 });
12903 }
12904
12905 notify_server_capabilities_updated(&server, cx);
12906 }
12907 "textDocument/documentColor" => {
12908 server.update_capabilities(|capabilities| {
12909 capabilities.color_provider = None;
12910 });
12911 notify_server_capabilities_updated(&server, cx);
12912 }
12913 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12914 }
12915 }
12916
12917 Ok(())
12918 }
12919
12920 fn clear_unregistered_diagnostics(
12921 &mut self,
12922 server_id: LanguageServerId,
12923 cleared_registration_id: SharedString,
12924 cx: &mut Context<Self>,
12925 ) -> anyhow::Result<()> {
12926 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12927
12928 self.buffer_store.update(cx, |buffer_store, cx| {
12929 for buffer_handle in buffer_store.buffers() {
12930 let buffer = buffer_handle.read(cx);
12931 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12932 let Some(abs_path) = abs_path else {
12933 continue;
12934 };
12935 affected_abs_paths.insert(abs_path);
12936 }
12937 });
12938
12939 let local = self.as_local().context("Expected LSP Store to be local")?;
12940 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12941 let Some(worktree) = self
12942 .worktree_store
12943 .read(cx)
12944 .worktree_for_id(*worktree_id, cx)
12945 else {
12946 continue;
12947 };
12948
12949 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12950 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12951 let has_matching_registration =
12952 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12953 entry.diagnostic.registration_id.as_ref()
12954 == Some(&cleared_registration_id)
12955 });
12956 if has_matching_registration {
12957 let abs_path = worktree.read(cx).absolutize(rel_path);
12958 affected_abs_paths.insert(abs_path);
12959 }
12960 }
12961 }
12962 }
12963
12964 if affected_abs_paths.is_empty() {
12965 return Ok(());
12966 }
12967
12968 // Send a fake diagnostic update which clears the state for the registration ID
12969 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12970 affected_abs_paths
12971 .into_iter()
12972 .map(|abs_path| DocumentDiagnosticsUpdate {
12973 diagnostics: DocumentDiagnostics {
12974 diagnostics: Vec::new(),
12975 document_abs_path: abs_path,
12976 version: None,
12977 },
12978 result_id: None,
12979 registration_id: Some(cleared_registration_id.clone()),
12980 server_id,
12981 disk_based_sources: Cow::Borrowed(&[]),
12982 })
12983 .collect();
12984
12985 let merge_registration_id = cleared_registration_id.clone();
12986 self.merge_diagnostic_entries(
12987 clears,
12988 move |_, diagnostic, _| {
12989 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12990 diagnostic.registration_id != Some(merge_registration_id.clone())
12991 } else {
12992 true
12993 }
12994 },
12995 cx,
12996 )?;
12997
12998 Ok(())
12999 }
13000
13001 async fn deduplicate_range_based_lsp_requests<T>(
13002 lsp_store: &Entity<Self>,
13003 server_id: Option<LanguageServerId>,
13004 lsp_request_id: LspRequestId,
13005 proto_request: &T::ProtoRequest,
13006 range: Range<Anchor>,
13007 cx: &mut AsyncApp,
13008 ) -> Result<()>
13009 where
13010 T: LspCommand,
13011 T::ProtoRequest: proto::LspRequestMessage,
13012 {
13013 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13014 let version = deserialize_version(proto_request.buffer_version());
13015 let buffer = lsp_store.update(cx, |this, cx| {
13016 this.buffer_store.read(cx).get_existing(buffer_id)
13017 })?;
13018 buffer
13019 .update(cx, |buffer, _| buffer.wait_for_version(version))
13020 .await?;
13021 lsp_store.update(cx, |lsp_store, cx| {
13022 let buffer_snapshot = buffer.read(cx).snapshot();
13023 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13024 let chunks_queried_for = lsp_data
13025 .inlay_hints
13026 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13027 .collect::<Vec<_>>();
13028 match chunks_queried_for.as_slice() {
13029 &[chunk] => {
13030 let key = LspKey {
13031 request_type: TypeId::of::<T>(),
13032 server_queried: server_id,
13033 };
13034 let previous_request = lsp_data
13035 .chunk_lsp_requests
13036 .entry(key)
13037 .or_default()
13038 .insert(chunk, lsp_request_id);
13039 if let Some((previous_request, running_requests)) =
13040 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13041 {
13042 running_requests.remove(&previous_request);
13043 }
13044 }
13045 _ambiguous_chunks => {
13046 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13047 // there, a buffer version-based check will be performed and outdated requests discarded.
13048 }
13049 }
13050 anyhow::Ok(())
13051 })?;
13052
13053 Ok(())
13054 }
13055
13056 async fn query_lsp_locally<T>(
13057 lsp_store: Entity<Self>,
13058 for_server_id: Option<LanguageServerId>,
13059 sender_id: proto::PeerId,
13060 lsp_request_id: LspRequestId,
13061 proto_request: T::ProtoRequest,
13062 position: Option<Anchor>,
13063 cx: &mut AsyncApp,
13064 ) -> Result<()>
13065 where
13066 T: LspCommand + Clone,
13067 T::ProtoRequest: proto::LspRequestMessage,
13068 <T::ProtoRequest as proto::RequestMessage>::Response:
13069 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13070 {
13071 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13072 let version = deserialize_version(proto_request.buffer_version());
13073 let buffer = lsp_store.update(cx, |this, cx| {
13074 this.buffer_store.read(cx).get_existing(buffer_id)
13075 })?;
13076 buffer
13077 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13078 .await?;
13079 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13080 let request =
13081 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13082 let key = LspKey {
13083 request_type: TypeId::of::<T>(),
13084 server_queried: for_server_id,
13085 };
13086 lsp_store.update(cx, |lsp_store, cx| {
13087 let request_task = match for_server_id {
13088 Some(server_id) => {
13089 let server_task = lsp_store.request_lsp(
13090 buffer.clone(),
13091 LanguageServerToQuery::Other(server_id),
13092 request.clone(),
13093 cx,
13094 );
13095 cx.background_spawn(async move {
13096 let mut responses = Vec::new();
13097 match server_task.await {
13098 Ok(response) => responses.push((server_id, response)),
13099 // rust-analyzer likes to error with this when its still loading up
13100 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13101 Err(e) => log::error!(
13102 "Error handling response for request {request:?}: {e:#}"
13103 ),
13104 }
13105 responses
13106 })
13107 }
13108 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13109 };
13110 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13111 if T::ProtoRequest::stop_previous_requests() {
13112 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13113 lsp_requests.clear();
13114 }
13115 }
13116 lsp_data.lsp_requests.entry(key).or_default().insert(
13117 lsp_request_id,
13118 cx.spawn(async move |lsp_store, cx| {
13119 let response = request_task.await;
13120 lsp_store
13121 .update(cx, |lsp_store, cx| {
13122 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13123 {
13124 let response = response
13125 .into_iter()
13126 .map(|(server_id, response)| {
13127 (
13128 server_id.to_proto(),
13129 T::response_to_proto(
13130 response,
13131 lsp_store,
13132 sender_id,
13133 &buffer_version,
13134 cx,
13135 )
13136 .into(),
13137 )
13138 })
13139 .collect::<HashMap<_, _>>();
13140 match client.send_lsp_response::<T::ProtoRequest>(
13141 project_id,
13142 lsp_request_id,
13143 response,
13144 ) {
13145 Ok(()) => {}
13146 Err(e) => {
13147 log::error!("Failed to send LSP response: {e:#}",)
13148 }
13149 }
13150 }
13151 })
13152 .ok();
13153 }),
13154 );
13155 });
13156 Ok(())
13157 }
13158
13159 fn take_text_document_sync_options(
13160 capabilities: &mut lsp::ServerCapabilities,
13161 ) -> lsp::TextDocumentSyncOptions {
13162 match capabilities.text_document_sync.take() {
13163 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13164 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13165 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13166 sync_options.change = Some(sync_kind);
13167 sync_options
13168 }
13169 None => lsp::TextDocumentSyncOptions::default(),
13170 }
13171 }
13172
13173 #[cfg(any(test, feature = "test-support"))]
13174 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13175 Some(
13176 self.lsp_data
13177 .get_mut(&buffer_id)?
13178 .code_lens
13179 .take()?
13180 .update
13181 .take()?
13182 .1,
13183 )
13184 }
13185
13186 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13187 self.downstream_client.clone()
13188 }
13189
13190 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13191 self.worktree_store.clone()
13192 }
13193
13194 /// Gets what's stored in the LSP data for the given buffer.
13195 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13196 self.lsp_data.get_mut(&buffer_id)
13197 }
13198
13199 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13200 /// new [`BufferLspData`] will be created to replace the previous state.
13201 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13202 let (buffer_id, buffer_version) =
13203 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13204 let lsp_data = self
13205 .lsp_data
13206 .entry(buffer_id)
13207 .or_insert_with(|| BufferLspData::new(buffer, cx));
13208 if buffer_version.changed_since(&lsp_data.buffer_version) {
13209 *lsp_data = BufferLspData::new(buffer, cx);
13210 }
13211 lsp_data
13212 }
13213}
13214
13215// Registration with registerOptions as null, should fallback to true.
13216// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13217fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13218 reg: lsp::Registration,
13219) -> Result<OneOf<bool, T>> {
13220 Ok(match reg.register_options {
13221 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13222 None => OneOf::Left(true),
13223 })
13224}
13225
13226fn subscribe_to_binary_statuses(
13227 languages: &Arc<LanguageRegistry>,
13228 cx: &mut Context<'_, LspStore>,
13229) -> Task<()> {
13230 let mut server_statuses = languages.language_server_binary_statuses();
13231 cx.spawn(async move |lsp_store, cx| {
13232 while let Some((server_name, binary_status)) = server_statuses.next().await {
13233 if lsp_store
13234 .update(cx, |_, cx| {
13235 let mut message = None;
13236 let binary_status = match binary_status {
13237 BinaryStatus::None => proto::ServerBinaryStatus::None,
13238 BinaryStatus::CheckingForUpdate => {
13239 proto::ServerBinaryStatus::CheckingForUpdate
13240 }
13241 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13242 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13243 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13244 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13245 BinaryStatus::Failed { error } => {
13246 message = Some(error);
13247 proto::ServerBinaryStatus::Failed
13248 }
13249 };
13250 cx.emit(LspStoreEvent::LanguageServerUpdate {
13251 // Binary updates are about the binary that might not have any language server id at that point.
13252 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13253 language_server_id: LanguageServerId(0),
13254 name: Some(server_name),
13255 message: proto::update_language_server::Variant::StatusUpdate(
13256 proto::StatusUpdate {
13257 message,
13258 status: Some(proto::status_update::Status::Binary(
13259 binary_status as i32,
13260 )),
13261 },
13262 ),
13263 });
13264 })
13265 .is_err()
13266 {
13267 break;
13268 }
13269 }
13270 })
13271}
13272
13273fn lsp_workspace_diagnostics_refresh(
13274 registration_id: Option<String>,
13275 options: DiagnosticServerCapabilities,
13276 server: Arc<LanguageServer>,
13277 cx: &mut Context<'_, LspStore>,
13278) -> Option<WorkspaceRefreshTask> {
13279 let identifier = workspace_diagnostic_identifier(&options)?;
13280 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13281
13282 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13283 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13284 refresh_tx.try_send(()).ok();
13285
13286 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13287 let mut attempts = 0;
13288 let max_attempts = 50;
13289 let mut requests = 0;
13290
13291 loop {
13292 let Some(()) = refresh_rx.recv().await else {
13293 return;
13294 };
13295
13296 'request: loop {
13297 requests += 1;
13298 if attempts > max_attempts {
13299 log::error!(
13300 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13301 );
13302 return;
13303 }
13304 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13305 cx.background_executor()
13306 .timer(Duration::from_millis(backoff_millis))
13307 .await;
13308 attempts += 1;
13309
13310 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13311 lsp_store
13312 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13313 .into_iter()
13314 .filter_map(|(abs_path, result_id)| {
13315 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13316 Some(lsp::PreviousResultId {
13317 uri,
13318 value: result_id.to_string(),
13319 })
13320 })
13321 .collect()
13322 }) else {
13323 return;
13324 };
13325
13326 let token = if let Some(registration_id) = ®istration_id {
13327 format!(
13328 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13329 server.server_id(),
13330 )
13331 } else {
13332 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13333 };
13334
13335 progress_rx.try_recv().ok();
13336 let timer =
13337 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13338 let progress = pin!(progress_rx.recv().fuse());
13339 let response_result = server
13340 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13341 lsp::WorkspaceDiagnosticParams {
13342 previous_result_ids,
13343 identifier: identifier.clone(),
13344 work_done_progress_params: Default::default(),
13345 partial_result_params: lsp::PartialResultParams {
13346 partial_result_token: Some(lsp::ProgressToken::String(token)),
13347 },
13348 },
13349 select(timer, progress).then(|either| match either {
13350 Either::Left((message, ..)) => ready(message).left_future(),
13351 Either::Right(..) => pending::<String>().right_future(),
13352 }),
13353 )
13354 .await;
13355
13356 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13357 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13358 match response_result {
13359 ConnectionResult::Timeout => {
13360 log::error!("Timeout during workspace diagnostics pull");
13361 continue 'request;
13362 }
13363 ConnectionResult::ConnectionReset => {
13364 log::error!("Server closed a workspace diagnostics pull request");
13365 continue 'request;
13366 }
13367 ConnectionResult::Result(Err(e)) => {
13368 log::error!("Error during workspace diagnostics pull: {e:#}");
13369 break 'request;
13370 }
13371 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13372 attempts = 0;
13373 if lsp_store
13374 .update(cx, |lsp_store, cx| {
13375 lsp_store.apply_workspace_diagnostic_report(
13376 server.server_id(),
13377 pulled_diagnostics,
13378 registration_id_shared.clone(),
13379 cx,
13380 )
13381 })
13382 .is_err()
13383 {
13384 return;
13385 }
13386 break 'request;
13387 }
13388 }
13389 }
13390 }
13391 });
13392
13393 Some(WorkspaceRefreshTask {
13394 refresh_tx,
13395 progress_tx,
13396 task: workspace_query_language_server,
13397 })
13398}
13399
13400fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13401 match &options {
13402 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13403 diagnostic_options.identifier.clone()
13404 }
13405 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13406 let diagnostic_options = ®istration_options.diagnostic_options;
13407 diagnostic_options.identifier.clone()
13408 }
13409 }
13410}
13411
13412fn workspace_diagnostic_identifier(
13413 options: &DiagnosticServerCapabilities,
13414) -> Option<Option<String>> {
13415 match &options {
13416 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13417 if !diagnostic_options.workspace_diagnostics {
13418 return None;
13419 }
13420 Some(diagnostic_options.identifier.clone())
13421 }
13422 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13423 let diagnostic_options = ®istration_options.diagnostic_options;
13424 if !diagnostic_options.workspace_diagnostics {
13425 return None;
13426 }
13427 Some(diagnostic_options.identifier.clone())
13428 }
13429 }
13430}
13431
13432fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13433 let CompletionSource::BufferWord {
13434 word_range,
13435 resolved,
13436 } = &mut completion.source
13437 else {
13438 return;
13439 };
13440 if *resolved {
13441 return;
13442 }
13443
13444 if completion.new_text
13445 != snapshot
13446 .text_for_range(word_range.clone())
13447 .collect::<String>()
13448 {
13449 return;
13450 }
13451
13452 let mut offset = 0;
13453 for chunk in snapshot.chunks(word_range.clone(), true) {
13454 let end_offset = offset + chunk.text.len();
13455 if let Some(highlight_id) = chunk.syntax_highlight_id {
13456 completion
13457 .label
13458 .runs
13459 .push((offset..end_offset, highlight_id));
13460 }
13461 offset = end_offset;
13462 }
13463 *resolved = true;
13464}
13465
13466impl EventEmitter<LspStoreEvent> for LspStore {}
13467
13468fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13469 hover
13470 .contents
13471 .retain(|hover_block| !hover_block.text.trim().is_empty());
13472 if hover.contents.is_empty() {
13473 None
13474 } else {
13475 Some(hover)
13476 }
13477}
13478
13479async fn populate_labels_for_completions(
13480 new_completions: Vec<CoreCompletion>,
13481 language: Option<Arc<Language>>,
13482 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13483) -> Vec<Completion> {
13484 let lsp_completions = new_completions
13485 .iter()
13486 .filter_map(|new_completion| {
13487 new_completion
13488 .source
13489 .lsp_completion(true)
13490 .map(|lsp_completion| lsp_completion.into_owned())
13491 })
13492 .collect::<Vec<_>>();
13493
13494 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13495 lsp_adapter
13496 .labels_for_completions(&lsp_completions, language)
13497 .await
13498 .log_err()
13499 .unwrap_or_default()
13500 } else {
13501 Vec::new()
13502 }
13503 .into_iter()
13504 .fuse();
13505
13506 let mut completions = Vec::new();
13507 for completion in new_completions {
13508 match completion.source.lsp_completion(true) {
13509 Some(lsp_completion) => {
13510 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13511
13512 let mut label = labels.next().flatten().unwrap_or_else(|| {
13513 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13514 });
13515 ensure_uniform_list_compatible_label(&mut label);
13516 completions.push(Completion {
13517 label,
13518 documentation,
13519 replace_range: completion.replace_range,
13520 new_text: completion.new_text,
13521 insert_text_mode: lsp_completion.insert_text_mode,
13522 source: completion.source,
13523 icon_path: None,
13524 confirm: None,
13525 match_start: None,
13526 snippet_deduplication_key: None,
13527 });
13528 }
13529 None => {
13530 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13531 ensure_uniform_list_compatible_label(&mut label);
13532 completions.push(Completion {
13533 label,
13534 documentation: None,
13535 replace_range: completion.replace_range,
13536 new_text: completion.new_text,
13537 source: completion.source,
13538 insert_text_mode: None,
13539 icon_path: None,
13540 confirm: None,
13541 match_start: None,
13542 snippet_deduplication_key: None,
13543 });
13544 }
13545 }
13546 }
13547 completions
13548}
13549
13550#[derive(Debug)]
13551pub enum LanguageServerToQuery {
13552 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13553 FirstCapable,
13554 /// Query a specific language server.
13555 Other(LanguageServerId),
13556}
13557
13558#[derive(Default)]
13559struct RenamePathsWatchedForServer {
13560 did_rename: Vec<RenameActionPredicate>,
13561 will_rename: Vec<RenameActionPredicate>,
13562}
13563
13564impl RenamePathsWatchedForServer {
13565 fn with_did_rename_patterns(
13566 mut self,
13567 did_rename: Option<&FileOperationRegistrationOptions>,
13568 ) -> Self {
13569 if let Some(did_rename) = did_rename {
13570 self.did_rename = did_rename
13571 .filters
13572 .iter()
13573 .filter_map(|filter| filter.try_into().log_err())
13574 .collect();
13575 }
13576 self
13577 }
13578 fn with_will_rename_patterns(
13579 mut self,
13580 will_rename: Option<&FileOperationRegistrationOptions>,
13581 ) -> Self {
13582 if let Some(will_rename) = will_rename {
13583 self.will_rename = will_rename
13584 .filters
13585 .iter()
13586 .filter_map(|filter| filter.try_into().log_err())
13587 .collect();
13588 }
13589 self
13590 }
13591
13592 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13593 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13594 }
13595 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13596 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13597 }
13598}
13599
13600impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13601 type Error = globset::Error;
13602 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13603 Ok(Self {
13604 kind: ops.pattern.matches.clone(),
13605 glob: GlobBuilder::new(&ops.pattern.glob)
13606 .case_insensitive(
13607 ops.pattern
13608 .options
13609 .as_ref()
13610 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13611 )
13612 .build()?
13613 .compile_matcher(),
13614 })
13615 }
13616}
13617struct RenameActionPredicate {
13618 glob: GlobMatcher,
13619 kind: Option<FileOperationPatternKind>,
13620}
13621
13622impl RenameActionPredicate {
13623 // Returns true if language server should be notified
13624 fn eval(&self, path: &str, is_dir: bool) -> bool {
13625 self.kind.as_ref().is_none_or(|kind| {
13626 let expected_kind = if is_dir {
13627 FileOperationPatternKind::Folder
13628 } else {
13629 FileOperationPatternKind::File
13630 };
13631 kind == &expected_kind
13632 }) && self.glob.is_match(path)
13633 }
13634}
13635
13636#[derive(Default)]
13637struct LanguageServerWatchedPaths {
13638 worktree_paths: HashMap<WorktreeId, GlobSet>,
13639 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13640}
13641
13642#[derive(Default)]
13643struct LanguageServerWatchedPathsBuilder {
13644 worktree_paths: HashMap<WorktreeId, GlobSet>,
13645 abs_paths: HashMap<Arc<Path>, GlobSet>,
13646}
13647
13648impl LanguageServerWatchedPathsBuilder {
13649 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13650 self.worktree_paths.insert(worktree_id, glob_set);
13651 }
13652 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13653 self.abs_paths.insert(path, glob_set);
13654 }
13655 fn build(
13656 self,
13657 fs: Arc<dyn Fs>,
13658 language_server_id: LanguageServerId,
13659 cx: &mut Context<LspStore>,
13660 ) -> LanguageServerWatchedPaths {
13661 let lsp_store = cx.weak_entity();
13662
13663 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13664 let abs_paths = self
13665 .abs_paths
13666 .into_iter()
13667 .map(|(abs_path, globset)| {
13668 let task = cx.spawn({
13669 let abs_path = abs_path.clone();
13670 let fs = fs.clone();
13671
13672 let lsp_store = lsp_store.clone();
13673 async move |_, cx| {
13674 maybe!(async move {
13675 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13676 while let Some(update) = push_updates.0.next().await {
13677 let action = lsp_store
13678 .update(cx, |this, _| {
13679 let Some(local) = this.as_local() else {
13680 return ControlFlow::Break(());
13681 };
13682 let Some(watcher) = local
13683 .language_server_watched_paths
13684 .get(&language_server_id)
13685 else {
13686 return ControlFlow::Break(());
13687 };
13688 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13689 "Watched abs path is not registered with a watcher",
13690 );
13691 let matching_entries = update
13692 .into_iter()
13693 .filter(|event| globs.is_match(&event.path))
13694 .collect::<Vec<_>>();
13695 this.lsp_notify_abs_paths_changed(
13696 language_server_id,
13697 matching_entries,
13698 );
13699 ControlFlow::Continue(())
13700 })
13701 .ok()?;
13702
13703 if action.is_break() {
13704 break;
13705 }
13706 }
13707 Some(())
13708 })
13709 .await;
13710 }
13711 });
13712 (abs_path, (globset, task))
13713 })
13714 .collect();
13715 LanguageServerWatchedPaths {
13716 worktree_paths: self.worktree_paths,
13717 abs_paths,
13718 }
13719 }
13720}
13721
13722struct LspBufferSnapshot {
13723 version: i32,
13724 snapshot: TextBufferSnapshot,
13725}
13726
13727/// A prompt requested by LSP server.
13728#[derive(Clone, Debug)]
13729pub struct LanguageServerPromptRequest {
13730 pub level: PromptLevel,
13731 pub message: String,
13732 pub actions: Vec<MessageActionItem>,
13733 pub lsp_name: String,
13734 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13735}
13736
13737impl LanguageServerPromptRequest {
13738 pub async fn respond(self, index: usize) -> Option<()> {
13739 if let Some(response) = self.actions.into_iter().nth(index) {
13740 self.response_channel.send(response).await.ok()
13741 } else {
13742 None
13743 }
13744 }
13745}
13746impl PartialEq for LanguageServerPromptRequest {
13747 fn eq(&self, other: &Self) -> bool {
13748 self.message == other.message && self.actions == other.actions
13749 }
13750}
13751
13752#[derive(Clone, Debug, PartialEq)]
13753pub enum LanguageServerLogType {
13754 Log(MessageType),
13755 Trace { verbose_info: Option<String> },
13756 Rpc { received: bool },
13757}
13758
13759impl LanguageServerLogType {
13760 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13761 match self {
13762 Self::Log(log_type) => {
13763 use proto::log_message::LogLevel;
13764 let level = match *log_type {
13765 MessageType::ERROR => LogLevel::Error,
13766 MessageType::WARNING => LogLevel::Warning,
13767 MessageType::INFO => LogLevel::Info,
13768 MessageType::LOG => LogLevel::Log,
13769 other => {
13770 log::warn!("Unknown lsp log message type: {other:?}");
13771 LogLevel::Log
13772 }
13773 };
13774 proto::language_server_log::LogType::Log(proto::LogMessage {
13775 level: level as i32,
13776 })
13777 }
13778 Self::Trace { verbose_info } => {
13779 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13780 verbose_info: verbose_info.to_owned(),
13781 })
13782 }
13783 Self::Rpc { received } => {
13784 let kind = if *received {
13785 proto::rpc_message::Kind::Received
13786 } else {
13787 proto::rpc_message::Kind::Sent
13788 };
13789 let kind = kind as i32;
13790 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13791 }
13792 }
13793 }
13794
13795 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13796 use proto::log_message::LogLevel;
13797 use proto::rpc_message;
13798 match log_type {
13799 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13800 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13801 LogLevel::Error => MessageType::ERROR,
13802 LogLevel::Warning => MessageType::WARNING,
13803 LogLevel::Info => MessageType::INFO,
13804 LogLevel::Log => MessageType::LOG,
13805 },
13806 ),
13807 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13808 verbose_info: trace_message.verbose_info,
13809 },
13810 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13811 received: match rpc_message::Kind::from_i32(message.kind)
13812 .unwrap_or(rpc_message::Kind::Received)
13813 {
13814 rpc_message::Kind::Received => true,
13815 rpc_message::Kind::Sent => false,
13816 },
13817 },
13818 }
13819 }
13820}
13821
13822pub struct WorkspaceRefreshTask {
13823 refresh_tx: mpsc::Sender<()>,
13824 progress_tx: mpsc::Sender<()>,
13825 #[allow(dead_code)]
13826 task: Task<()>,
13827}
13828
13829pub enum LanguageServerState {
13830 Starting {
13831 startup: Task<Option<Arc<LanguageServer>>>,
13832 /// List of language servers that will be added to the workspace once it's initialization completes.
13833 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13834 },
13835
13836 Running {
13837 adapter: Arc<CachedLspAdapter>,
13838 server: Arc<LanguageServer>,
13839 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13840 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13841 },
13842}
13843
13844impl LanguageServerState {
13845 fn add_workspace_folder(&self, uri: Uri) {
13846 match self {
13847 LanguageServerState::Starting {
13848 pending_workspace_folders,
13849 ..
13850 } => {
13851 pending_workspace_folders.lock().insert(uri);
13852 }
13853 LanguageServerState::Running { server, .. } => {
13854 server.add_workspace_folder(uri);
13855 }
13856 }
13857 }
13858 fn _remove_workspace_folder(&self, uri: Uri) {
13859 match self {
13860 LanguageServerState::Starting {
13861 pending_workspace_folders,
13862 ..
13863 } => {
13864 pending_workspace_folders.lock().remove(&uri);
13865 }
13866 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13867 }
13868 }
13869}
13870
13871impl std::fmt::Debug for LanguageServerState {
13872 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13873 match self {
13874 LanguageServerState::Starting { .. } => {
13875 f.debug_struct("LanguageServerState::Starting").finish()
13876 }
13877 LanguageServerState::Running { .. } => {
13878 f.debug_struct("LanguageServerState::Running").finish()
13879 }
13880 }
13881 }
13882}
13883
13884#[derive(Clone, Debug, Serialize)]
13885pub struct LanguageServerProgress {
13886 pub is_disk_based_diagnostics_progress: bool,
13887 pub is_cancellable: bool,
13888 pub title: Option<String>,
13889 pub message: Option<String>,
13890 pub percentage: Option<usize>,
13891 #[serde(skip_serializing)]
13892 pub last_update_at: Instant,
13893}
13894
13895#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13896pub struct DiagnosticSummary {
13897 pub error_count: usize,
13898 pub warning_count: usize,
13899}
13900
13901impl DiagnosticSummary {
13902 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13903 let mut this = Self {
13904 error_count: 0,
13905 warning_count: 0,
13906 };
13907
13908 for entry in diagnostics {
13909 if entry.diagnostic.is_primary {
13910 match entry.diagnostic.severity {
13911 DiagnosticSeverity::ERROR => this.error_count += 1,
13912 DiagnosticSeverity::WARNING => this.warning_count += 1,
13913 _ => {}
13914 }
13915 }
13916 }
13917
13918 this
13919 }
13920
13921 pub fn is_empty(&self) -> bool {
13922 self.error_count == 0 && self.warning_count == 0
13923 }
13924
13925 pub fn to_proto(
13926 self,
13927 language_server_id: LanguageServerId,
13928 path: &RelPath,
13929 ) -> proto::DiagnosticSummary {
13930 proto::DiagnosticSummary {
13931 path: path.to_proto(),
13932 language_server_id: language_server_id.0 as u64,
13933 error_count: self.error_count as u32,
13934 warning_count: self.warning_count as u32,
13935 }
13936 }
13937}
13938
13939#[derive(Clone, Debug)]
13940pub enum CompletionDocumentation {
13941 /// There is no documentation for this completion.
13942 Undocumented,
13943 /// A single line of documentation.
13944 SingleLine(SharedString),
13945 /// Multiple lines of plain text documentation.
13946 MultiLinePlainText(SharedString),
13947 /// Markdown documentation.
13948 MultiLineMarkdown(SharedString),
13949 /// Both single line and multiple lines of plain text documentation.
13950 SingleLineAndMultiLinePlainText {
13951 single_line: SharedString,
13952 plain_text: Option<SharedString>,
13953 },
13954}
13955
13956impl CompletionDocumentation {
13957 #[cfg(any(test, feature = "test-support"))]
13958 pub fn text(&self) -> SharedString {
13959 match self {
13960 CompletionDocumentation::Undocumented => "".into(),
13961 CompletionDocumentation::SingleLine(s) => s.clone(),
13962 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13963 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13964 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13965 single_line.clone()
13966 }
13967 }
13968 }
13969}
13970
13971impl From<lsp::Documentation> for CompletionDocumentation {
13972 fn from(docs: lsp::Documentation) -> Self {
13973 match docs {
13974 lsp::Documentation::String(text) => {
13975 if text.lines().count() <= 1 {
13976 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13977 } else {
13978 CompletionDocumentation::MultiLinePlainText(text.into())
13979 }
13980 }
13981
13982 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13983 lsp::MarkupKind::PlainText => {
13984 if value.lines().count() <= 1 {
13985 CompletionDocumentation::SingleLine(value.into())
13986 } else {
13987 CompletionDocumentation::MultiLinePlainText(value.into())
13988 }
13989 }
13990
13991 lsp::MarkupKind::Markdown => {
13992 CompletionDocumentation::MultiLineMarkdown(value.into())
13993 }
13994 },
13995 }
13996 }
13997}
13998
13999pub enum ResolvedHint {
14000 Resolved(InlayHint),
14001 Resolving(Shared<Task<()>>),
14002}
14003
14004fn glob_literal_prefix(glob: &Path) -> PathBuf {
14005 glob.components()
14006 .take_while(|component| match component {
14007 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14008 _ => true,
14009 })
14010 .collect()
14011}
14012
14013pub struct SshLspAdapter {
14014 name: LanguageServerName,
14015 binary: LanguageServerBinary,
14016 initialization_options: Option<String>,
14017 code_action_kinds: Option<Vec<CodeActionKind>>,
14018}
14019
14020impl SshLspAdapter {
14021 pub fn new(
14022 name: LanguageServerName,
14023 binary: LanguageServerBinary,
14024 initialization_options: Option<String>,
14025 code_action_kinds: Option<String>,
14026 ) -> Self {
14027 Self {
14028 name,
14029 binary,
14030 initialization_options,
14031 code_action_kinds: code_action_kinds
14032 .as_ref()
14033 .and_then(|c| serde_json::from_str(c).ok()),
14034 }
14035 }
14036}
14037
14038impl LspInstaller for SshLspAdapter {
14039 type BinaryVersion = ();
14040 async fn check_if_user_installed(
14041 &self,
14042 _: &dyn LspAdapterDelegate,
14043 _: Option<Toolchain>,
14044 _: &AsyncApp,
14045 ) -> Option<LanguageServerBinary> {
14046 Some(self.binary.clone())
14047 }
14048
14049 async fn cached_server_binary(
14050 &self,
14051 _: PathBuf,
14052 _: &dyn LspAdapterDelegate,
14053 ) -> Option<LanguageServerBinary> {
14054 None
14055 }
14056
14057 async fn fetch_latest_server_version(
14058 &self,
14059 _: &dyn LspAdapterDelegate,
14060 _: bool,
14061 _: &mut AsyncApp,
14062 ) -> Result<()> {
14063 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14064 }
14065
14066 async fn fetch_server_binary(
14067 &self,
14068 _: (),
14069 _: PathBuf,
14070 _: &dyn LspAdapterDelegate,
14071 ) -> Result<LanguageServerBinary> {
14072 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14073 }
14074}
14075
14076#[async_trait(?Send)]
14077impl LspAdapter for SshLspAdapter {
14078 fn name(&self) -> LanguageServerName {
14079 self.name.clone()
14080 }
14081
14082 async fn initialization_options(
14083 self: Arc<Self>,
14084 _: &Arc<dyn LspAdapterDelegate>,
14085 ) -> Result<Option<serde_json::Value>> {
14086 let Some(options) = &self.initialization_options else {
14087 return Ok(None);
14088 };
14089 let result = serde_json::from_str(options)?;
14090 Ok(result)
14091 }
14092
14093 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14094 self.code_action_kinds.clone()
14095 }
14096}
14097
14098pub fn language_server_settings<'a>(
14099 delegate: &'a dyn LspAdapterDelegate,
14100 language: &LanguageServerName,
14101 cx: &'a App,
14102) -> Option<&'a LspSettings> {
14103 language_server_settings_for(
14104 SettingsLocation {
14105 worktree_id: delegate.worktree_id(),
14106 path: RelPath::empty(),
14107 },
14108 language,
14109 cx,
14110 )
14111}
14112
14113pub fn language_server_settings_for<'a>(
14114 location: SettingsLocation<'a>,
14115 language: &LanguageServerName,
14116 cx: &'a App,
14117) -> Option<&'a LspSettings> {
14118 ProjectSettings::get(Some(location), cx).lsp.get(language)
14119}
14120
14121pub struct LocalLspAdapterDelegate {
14122 lsp_store: WeakEntity<LspStore>,
14123 worktree: worktree::Snapshot,
14124 fs: Arc<dyn Fs>,
14125 http_client: Arc<dyn HttpClient>,
14126 language_registry: Arc<LanguageRegistry>,
14127 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14128}
14129
14130impl LocalLspAdapterDelegate {
14131 pub fn new(
14132 language_registry: Arc<LanguageRegistry>,
14133 environment: &Entity<ProjectEnvironment>,
14134 lsp_store: WeakEntity<LspStore>,
14135 worktree: &Entity<Worktree>,
14136 http_client: Arc<dyn HttpClient>,
14137 fs: Arc<dyn Fs>,
14138 cx: &mut App,
14139 ) -> Arc<Self> {
14140 let load_shell_env_task =
14141 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14142
14143 Arc::new(Self {
14144 lsp_store,
14145 worktree: worktree.read(cx).snapshot(),
14146 fs,
14147 http_client,
14148 language_registry,
14149 load_shell_env_task,
14150 })
14151 }
14152
14153 pub fn from_local_lsp(
14154 local: &LocalLspStore,
14155 worktree: &Entity<Worktree>,
14156 cx: &mut App,
14157 ) -> Arc<Self> {
14158 Self::new(
14159 local.languages.clone(),
14160 &local.environment,
14161 local.weak.clone(),
14162 worktree,
14163 local.http_client.clone(),
14164 local.fs.clone(),
14165 cx,
14166 )
14167 }
14168}
14169
14170#[async_trait]
14171impl LspAdapterDelegate for LocalLspAdapterDelegate {
14172 fn show_notification(&self, message: &str, cx: &mut App) {
14173 self.lsp_store
14174 .update(cx, |_, cx| {
14175 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14176 })
14177 .ok();
14178 }
14179
14180 fn http_client(&self) -> Arc<dyn HttpClient> {
14181 self.http_client.clone()
14182 }
14183
14184 fn worktree_id(&self) -> WorktreeId {
14185 self.worktree.id()
14186 }
14187
14188 fn worktree_root_path(&self) -> &Path {
14189 self.worktree.abs_path().as_ref()
14190 }
14191
14192 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14193 self.worktree.resolve_executable_path(path)
14194 }
14195
14196 async fn shell_env(&self) -> HashMap<String, String> {
14197 let task = self.load_shell_env_task.clone();
14198 task.await.unwrap_or_default()
14199 }
14200
14201 async fn npm_package_installed_version(
14202 &self,
14203 package_name: &str,
14204 ) -> Result<Option<(PathBuf, Version)>> {
14205 let local_package_directory = self.worktree_root_path();
14206 let node_modules_directory = local_package_directory.join("node_modules");
14207
14208 if let Some(version) =
14209 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14210 {
14211 return Ok(Some((node_modules_directory, version)));
14212 }
14213 let Some(npm) = self.which("npm".as_ref()).await else {
14214 log::warn!(
14215 "Failed to find npm executable for {:?}",
14216 local_package_directory
14217 );
14218 return Ok(None);
14219 };
14220
14221 let env = self.shell_env().await;
14222 let output = util::command::new_smol_command(&npm)
14223 .args(["root", "-g"])
14224 .envs(env)
14225 .current_dir(local_package_directory)
14226 .output()
14227 .await?;
14228 let global_node_modules =
14229 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14230
14231 if let Some(version) =
14232 read_package_installed_version(global_node_modules.clone(), package_name).await?
14233 {
14234 return Ok(Some((global_node_modules, version)));
14235 }
14236 return Ok(None);
14237 }
14238
14239 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14240 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14241 if self.fs.is_file(&worktree_abs_path).await {
14242 worktree_abs_path.pop();
14243 }
14244
14245 let env = self.shell_env().await;
14246
14247 let shell_path = env.get("PATH").cloned();
14248
14249 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14250 }
14251
14252 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14253 let mut working_dir = self.worktree_root_path().to_path_buf();
14254 if self.fs.is_file(&working_dir).await {
14255 working_dir.pop();
14256 }
14257 let output = util::command::new_smol_command(&command.path)
14258 .args(command.arguments)
14259 .envs(command.env.clone().unwrap_or_default())
14260 .current_dir(working_dir)
14261 .output()
14262 .await?;
14263
14264 anyhow::ensure!(
14265 output.status.success(),
14266 "{}, stdout: {:?}, stderr: {:?}",
14267 output.status,
14268 String::from_utf8_lossy(&output.stdout),
14269 String::from_utf8_lossy(&output.stderr)
14270 );
14271 Ok(())
14272 }
14273
14274 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14275 self.language_registry
14276 .update_lsp_binary_status(server_name, status);
14277 }
14278
14279 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14280 self.language_registry
14281 .all_lsp_adapters()
14282 .into_iter()
14283 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14284 .collect()
14285 }
14286
14287 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14288 let dir = self.language_registry.language_server_download_dir(name)?;
14289
14290 if !dir.exists() {
14291 smol::fs::create_dir_all(&dir)
14292 .await
14293 .context("failed to create container directory")
14294 .log_err()?;
14295 }
14296
14297 Some(dir)
14298 }
14299
14300 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14301 let entry = self
14302 .worktree
14303 .entry_for_path(path)
14304 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14305 let abs_path = self.worktree.absolutize(&entry.path);
14306 self.fs.load(&abs_path).await
14307 }
14308}
14309
14310async fn populate_labels_for_symbols(
14311 symbols: Vec<CoreSymbol>,
14312 language_registry: &Arc<LanguageRegistry>,
14313 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14314 output: &mut Vec<Symbol>,
14315) {
14316 #[allow(clippy::mutable_key_type)]
14317 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14318
14319 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14320 for symbol in symbols {
14321 let Some(file_name) = symbol.path.file_name() else {
14322 continue;
14323 };
14324 let language = language_registry
14325 .load_language_for_file_path(Path::new(file_name))
14326 .await
14327 .ok()
14328 .or_else(|| {
14329 unknown_paths.insert(file_name.into());
14330 None
14331 });
14332 symbols_by_language
14333 .entry(language)
14334 .or_default()
14335 .push(symbol);
14336 }
14337
14338 for unknown_path in unknown_paths {
14339 log::info!("no language found for symbol in file {unknown_path:?}");
14340 }
14341
14342 let mut label_params = Vec::new();
14343 for (language, mut symbols) in symbols_by_language {
14344 label_params.clear();
14345 label_params.extend(
14346 symbols
14347 .iter_mut()
14348 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14349 );
14350
14351 let mut labels = Vec::new();
14352 if let Some(language) = language {
14353 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14354 language_registry
14355 .lsp_adapters(&language.name())
14356 .first()
14357 .cloned()
14358 });
14359 if let Some(lsp_adapter) = lsp_adapter {
14360 labels = lsp_adapter
14361 .labels_for_symbols(&label_params, &language)
14362 .await
14363 .log_err()
14364 .unwrap_or_default();
14365 }
14366 }
14367
14368 for ((symbol, (name, _)), label) in symbols
14369 .into_iter()
14370 .zip(label_params.drain(..))
14371 .zip(labels.into_iter().chain(iter::repeat(None)))
14372 {
14373 output.push(Symbol {
14374 language_server_name: symbol.language_server_name,
14375 source_worktree_id: symbol.source_worktree_id,
14376 source_language_server_id: symbol.source_language_server_id,
14377 path: symbol.path,
14378 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14379 name,
14380 kind: symbol.kind,
14381 range: symbol.range,
14382 });
14383 }
14384 }
14385}
14386
14387fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14388 match server.capabilities().text_document_sync.as_ref()? {
14389 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14390 // Server wants didSave but didn't specify includeText.
14391 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14392 // Server doesn't want didSave at all.
14393 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14394 // Server provided SaveOptions.
14395 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14396 Some(save_options.include_text.unwrap_or(false))
14397 }
14398 },
14399 // We do not have any save info. Kind affects didChange only.
14400 lsp::TextDocumentSyncCapability::Kind(_) => None,
14401 }
14402}
14403
14404/// Completion items are displayed in a `UniformList`.
14405/// Usually, those items are single-line strings, but in LSP responses,
14406/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14407/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14408/// 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,
14409/// breaking the completions menu presentation.
14410///
14411/// 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.
14412fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14413 let mut new_text = String::with_capacity(label.text.len());
14414 let mut offset_map = vec![0; label.text.len() + 1];
14415 let mut last_char_was_space = false;
14416 let mut new_idx = 0;
14417 let chars = label.text.char_indices().fuse();
14418 let mut newlines_removed = false;
14419
14420 for (idx, c) in chars {
14421 offset_map[idx] = new_idx;
14422
14423 match c {
14424 '\n' if last_char_was_space => {
14425 newlines_removed = true;
14426 }
14427 '\t' | ' ' if last_char_was_space => {}
14428 '\n' if !last_char_was_space => {
14429 new_text.push(' ');
14430 new_idx += 1;
14431 last_char_was_space = true;
14432 newlines_removed = true;
14433 }
14434 ' ' | '\t' => {
14435 new_text.push(' ');
14436 new_idx += 1;
14437 last_char_was_space = true;
14438 }
14439 _ => {
14440 new_text.push(c);
14441 new_idx += c.len_utf8();
14442 last_char_was_space = false;
14443 }
14444 }
14445 }
14446 offset_map[label.text.len()] = new_idx;
14447
14448 // Only modify the label if newlines were removed.
14449 if !newlines_removed {
14450 return;
14451 }
14452
14453 let last_index = new_idx;
14454 let mut run_ranges_errors = Vec::new();
14455 label.runs.retain_mut(|(range, _)| {
14456 match offset_map.get(range.start) {
14457 Some(&start) => range.start = start,
14458 None => {
14459 run_ranges_errors.push(range.clone());
14460 return false;
14461 }
14462 }
14463
14464 match offset_map.get(range.end) {
14465 Some(&end) => range.end = end,
14466 None => {
14467 run_ranges_errors.push(range.clone());
14468 range.end = last_index;
14469 }
14470 }
14471 true
14472 });
14473 if !run_ranges_errors.is_empty() {
14474 log::error!(
14475 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14476 label.text
14477 );
14478 }
14479
14480 let mut wrong_filter_range = None;
14481 if label.filter_range == (0..label.text.len()) {
14482 label.filter_range = 0..new_text.len();
14483 } else {
14484 let mut original_filter_range = Some(label.filter_range.clone());
14485 match offset_map.get(label.filter_range.start) {
14486 Some(&start) => label.filter_range.start = start,
14487 None => {
14488 wrong_filter_range = original_filter_range.take();
14489 label.filter_range.start = last_index;
14490 }
14491 }
14492
14493 match offset_map.get(label.filter_range.end) {
14494 Some(&end) => label.filter_range.end = end,
14495 None => {
14496 wrong_filter_range = original_filter_range.take();
14497 label.filter_range.end = last_index;
14498 }
14499 }
14500 }
14501 if let Some(wrong_filter_range) = wrong_filter_range {
14502 log::error!(
14503 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14504 label.text
14505 );
14506 }
14507
14508 label.text = new_text;
14509}
14510
14511#[cfg(test)]
14512mod tests {
14513 use language::HighlightId;
14514
14515 use super::*;
14516
14517 #[test]
14518 fn test_glob_literal_prefix() {
14519 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14520 assert_eq!(
14521 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14522 Path::new("node_modules")
14523 );
14524 assert_eq!(
14525 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14526 Path::new("foo")
14527 );
14528 assert_eq!(
14529 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14530 Path::new("foo/bar/baz.js")
14531 );
14532
14533 #[cfg(target_os = "windows")]
14534 {
14535 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14536 assert_eq!(
14537 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14538 Path::new("node_modules")
14539 );
14540 assert_eq!(
14541 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14542 Path::new("foo")
14543 );
14544 assert_eq!(
14545 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14546 Path::new("foo/bar/baz.js")
14547 );
14548 }
14549 }
14550
14551 #[test]
14552 fn test_multi_len_chars_normalization() {
14553 let mut label = CodeLabel::new(
14554 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14555 0..6,
14556 vec![(0..6, HighlightId(1))],
14557 );
14558 ensure_uniform_list_compatible_label(&mut label);
14559 assert_eq!(
14560 label,
14561 CodeLabel::new(
14562 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14563 0..6,
14564 vec![(0..6, HighlightId(1))],
14565 )
14566 );
14567 }
14568
14569 #[test]
14570 fn test_trailing_newline_in_completion_documentation() {
14571 let doc = lsp::Documentation::String(
14572 "Inappropriate argument value (of correct type).\n".to_string(),
14573 );
14574 let completion_doc: CompletionDocumentation = doc.into();
14575 assert!(
14576 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
14577 );
14578
14579 let doc = lsp::Documentation::String(" some value \n".to_string());
14580 let completion_doc: CompletionDocumentation = doc.into();
14581 assert!(matches!(
14582 completion_doc,
14583 CompletionDocumentation::SingleLine(s) if s == "some value"
14584 ));
14585 }
14586}