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 smol::channel::{Receiver, Sender};
102use snippet::Snippet;
103use std::{
104 any::TypeId,
105 borrow::Cow,
106 cell::RefCell,
107 cmp::{Ordering, Reverse},
108 collections::hash_map,
109 convert::TryInto,
110 ffi::OsStr,
111 future::ready,
112 iter, mem,
113 ops::{ControlFlow, Range},
114 path::{self, Path, PathBuf},
115 pin::pin,
116 rc::Rc,
117 sync::{
118 Arc,
119 atomic::{self, AtomicUsize},
120 },
121 time::{Duration, Instant},
122 vec,
123};
124use sum_tree::Dimensions;
125use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
126
127use util::{
128 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
129 paths::{PathStyle, SanitizedPath},
130 post_inc,
131 redact::redact_command,
132 rel_path::RelPath,
133};
134
135pub use fs::*;
136pub use language::Location;
137pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
138#[cfg(any(test, feature = "test-support"))]
139pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
140pub use worktree::{
141 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
142 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
143};
144
145const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
146pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
147const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
148const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
149
150#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
151pub enum ProgressToken {
152 Number(i32),
153 String(SharedString),
154}
155
156impl std::fmt::Display for ProgressToken {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 match self {
159 Self::Number(number) => write!(f, "{number}"),
160 Self::String(string) => write!(f, "{string}"),
161 }
162 }
163}
164
165impl ProgressToken {
166 fn from_lsp(value: lsp::NumberOrString) -> Self {
167 match value {
168 lsp::NumberOrString::Number(number) => Self::Number(number),
169 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
170 }
171 }
172
173 fn to_lsp(&self) -> lsp::NumberOrString {
174 match self {
175 Self::Number(number) => lsp::NumberOrString::Number(*number),
176 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
177 }
178 }
179
180 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
181 Some(match value.value? {
182 proto::progress_token::Value::Number(number) => Self::Number(number),
183 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
184 })
185 }
186
187 fn to_proto(&self) -> proto::ProgressToken {
188 proto::ProgressToken {
189 value: Some(match self {
190 Self::Number(number) => proto::progress_token::Value::Number(*number),
191 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
192 }),
193 }
194 }
195}
196
197#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198pub enum FormatTrigger {
199 Save,
200 Manual,
201}
202
203pub enum LspFormatTarget {
204 Buffers,
205 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
206}
207
208#[derive(Clone, PartialEq, Eq, Hash)]
209pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
210
211struct OpenLspBuffer(Entity<Buffer>);
212
213impl FormatTrigger {
214 fn from_proto(value: i32) -> FormatTrigger {
215 match value {
216 0 => FormatTrigger::Save,
217 1 => FormatTrigger::Manual,
218 _ => FormatTrigger::Save,
219 }
220 }
221}
222
223#[derive(Clone)]
224struct UnifiedLanguageServer {
225 id: LanguageServerId,
226 project_roots: HashSet<Arc<RelPath>>,
227}
228
229#[derive(Clone, Debug, Hash, PartialEq, Eq)]
230struct LanguageServerSeed {
231 worktree_id: WorktreeId,
232 name: LanguageServerName,
233 toolchain: Option<Toolchain>,
234 settings: Arc<LspSettings>,
235}
236
237#[derive(Debug)]
238pub struct DocumentDiagnosticsUpdate<'a, D> {
239 pub diagnostics: D,
240 pub result_id: Option<SharedString>,
241 pub registration_id: Option<SharedString>,
242 pub server_id: LanguageServerId,
243 pub disk_based_sources: Cow<'a, [String]>,
244}
245
246pub struct DocumentDiagnostics {
247 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
248 document_abs_path: PathBuf,
249 version: Option<i32>,
250}
251
252#[cfg(test)]
253impl DocumentDiagnostics {
254 pub fn new(
255 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
256 document_abs_path: PathBuf,
257 version: Option<i32>,
258 ) -> Self {
259 Self {
260 diagnostics,
261 document_abs_path,
262 version,
263 }
264 }
265}
266
267#[derive(Default, Debug)]
268struct DynamicRegistrations {
269 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
270 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
271}
272
273pub struct LocalLspStore {
274 weak: WeakEntity<LspStore>,
275 pub worktree_store: Entity<WorktreeStore>,
276 toolchain_store: Entity<LocalToolchainStore>,
277 http_client: Arc<dyn HttpClient>,
278 environment: Entity<ProjectEnvironment>,
279 fs: Arc<dyn Fs>,
280 languages: Arc<LanguageRegistry>,
281 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
282 yarn: Entity<YarnPathStore>,
283 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
284 buffers_being_formatted: HashSet<BufferId>,
285 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
286 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
287 watched_manifest_filenames: HashSet<ManifestName>,
288 language_server_paths_watched_for_rename:
289 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
290 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
291 supplementary_language_servers:
292 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
293 prettier_store: Entity<PrettierStore>,
294 next_diagnostic_group_id: usize,
295 diagnostics: HashMap<
296 WorktreeId,
297 HashMap<
298 Arc<RelPath>,
299 Vec<(
300 LanguageServerId,
301 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
302 )>,
303 >,
304 >,
305 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
306 _subscription: gpui::Subscription,
307 lsp_tree: LanguageServerTree,
308 registered_buffers: HashMap<BufferId, usize>,
309 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
310 buffer_pull_diagnostics_result_ids: HashMap<
311 LanguageServerId,
312 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
313 >,
314 workspace_pull_diagnostics_result_ids: HashMap<
315 LanguageServerId,
316 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
317 >,
318 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, Receiver<()>)>,
319}
320
321impl LocalLspStore {
322 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
323 pub fn running_language_server_for_id(
324 &self,
325 id: LanguageServerId,
326 ) -> Option<&Arc<LanguageServer>> {
327 let language_server_state = self.language_servers.get(&id)?;
328
329 match language_server_state {
330 LanguageServerState::Running { server, .. } => Some(server),
331 LanguageServerState::Starting { .. } => None,
332 }
333 }
334
335 fn get_or_insert_language_server(
336 &mut self,
337 worktree_handle: &Entity<Worktree>,
338 delegate: Arc<LocalLspAdapterDelegate>,
339 disposition: &Arc<LaunchDisposition>,
340 language_name: &LanguageName,
341 cx: &mut App,
342 ) -> LanguageServerId {
343 let key = LanguageServerSeed {
344 worktree_id: worktree_handle.read(cx).id(),
345 name: disposition.server_name.clone(),
346 settings: disposition.settings.clone(),
347 toolchain: disposition.toolchain.clone(),
348 };
349 if let Some(state) = self.language_server_ids.get_mut(&key) {
350 state.project_roots.insert(disposition.path.path.clone());
351 state.id
352 } else {
353 let adapter = self
354 .languages
355 .lsp_adapters(language_name)
356 .into_iter()
357 .find(|adapter| adapter.name() == disposition.server_name)
358 .expect("To find LSP adapter");
359 let new_language_server_id = self.start_language_server(
360 worktree_handle,
361 delegate,
362 adapter,
363 disposition.settings.clone(),
364 key.clone(),
365 cx,
366 );
367 if let Some(state) = self.language_server_ids.get_mut(&key) {
368 state.project_roots.insert(disposition.path.path.clone());
369 } else {
370 debug_assert!(
371 false,
372 "Expected `start_language_server` to ensure that `key` exists in a map"
373 );
374 }
375 new_language_server_id
376 }
377 }
378
379 fn start_language_server(
380 &mut self,
381 worktree_handle: &Entity<Worktree>,
382 delegate: Arc<LocalLspAdapterDelegate>,
383 adapter: Arc<CachedLspAdapter>,
384 settings: Arc<LspSettings>,
385 key: LanguageServerSeed,
386 cx: &mut App,
387 ) -> LanguageServerId {
388 let worktree = worktree_handle.read(cx);
389
390 let worktree_id = worktree.id();
391 let worktree_abs_path = worktree.abs_path();
392 let toolchain = key.toolchain.clone();
393 let override_options = settings.initialization_options.clone();
394
395 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
396
397 let server_id = self.languages.next_language_server_id();
398 log::trace!(
399 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
400 adapter.name.0
401 );
402
403 let untrusted_worktree_task =
404 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
405 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
406 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
407 });
408 if can_trust {
409 self.restricted_worktrees_tasks.remove(&worktree_id);
410 None
411 } else {
412 match self.restricted_worktrees_tasks.entry(worktree_id) {
413 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
414 hash_map::Entry::Vacant(v) => {
415 let (tx, rx) = smol::channel::bounded::<()>(1);
416 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, _| {
417 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
418 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
419 tx.send_blocking(()).ok();
420 }
421 }
422 });
423 v.insert((subscription, rx.clone()));
424 Some(rx)
425 }
426 }
427 }
428 });
429 let update_binary_status = untrusted_worktree_task.is_none();
430
431 let binary = self.get_language_server_binary(
432 worktree_abs_path.clone(),
433 adapter.clone(),
434 settings,
435 toolchain.clone(),
436 delegate.clone(),
437 true,
438 untrusted_worktree_task,
439 cx,
440 );
441 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
442
443 let pending_server = cx.spawn({
444 let adapter = adapter.clone();
445 let server_name = adapter.name.clone();
446 let stderr_capture = stderr_capture.clone();
447 #[cfg(any(test, feature = "test-support"))]
448 let lsp_store = self.weak.clone();
449 let pending_workspace_folders = pending_workspace_folders.clone();
450 async move |cx| {
451 let binary = binary.await?;
452 #[cfg(any(test, feature = "test-support"))]
453 if let Some(server) = lsp_store
454 .update(&mut cx.clone(), |this, cx| {
455 this.languages.create_fake_language_server(
456 server_id,
457 &server_name,
458 binary.clone(),
459 &mut cx.to_async(),
460 )
461 })
462 .ok()
463 .flatten()
464 {
465 return Ok(server);
466 }
467
468 let code_action_kinds = adapter.code_action_kinds();
469 lsp::LanguageServer::new(
470 stderr_capture,
471 server_id,
472 server_name,
473 binary,
474 &worktree_abs_path,
475 code_action_kinds,
476 Some(pending_workspace_folders),
477 cx,
478 )
479 }
480 });
481
482 let startup = {
483 let server_name = adapter.name.0.clone();
484 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
485 let key = key.clone();
486 let adapter = adapter.clone();
487 let lsp_store = self.weak.clone();
488 let pending_workspace_folders = pending_workspace_folders.clone();
489
490 let pull_diagnostics = ProjectSettings::get_global(cx)
491 .diagnostics
492 .lsp_pull_diagnostics
493 .enabled;
494 cx.spawn(async move |cx| {
495 let result = async {
496 let language_server = pending_server.await?;
497
498 let workspace_config = Self::workspace_configuration_for_adapter(
499 adapter.adapter.clone(),
500 &delegate,
501 toolchain,
502 None,
503 cx,
504 )
505 .await?;
506
507 let mut initialization_options = Self::initialization_options_for_adapter(
508 adapter.adapter.clone(),
509 &delegate,
510 )
511 .await?;
512
513 match (&mut initialization_options, override_options) {
514 (Some(initialization_options), Some(override_options)) => {
515 merge_json_value_into(override_options, initialization_options);
516 }
517 (None, override_options) => initialization_options = override_options,
518 _ => {}
519 }
520
521 let initialization_params = cx.update(|cx| {
522 let mut params =
523 language_server.default_initialize_params(pull_diagnostics, cx);
524 params.initialization_options = initialization_options;
525 adapter.adapter.prepare_initialize_params(params, cx)
526 })?;
527
528 Self::setup_lsp_messages(
529 lsp_store.clone(),
530 &language_server,
531 delegate.clone(),
532 adapter.clone(),
533 );
534
535 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
536 settings: workspace_config,
537 };
538 let language_server = cx
539 .update(|cx| {
540 language_server.initialize(
541 initialization_params,
542 Arc::new(did_change_configuration_params.clone()),
543 cx,
544 )
545 })
546 .await
547 .inspect_err(|_| {
548 if let Some(lsp_store) = lsp_store.upgrade() {
549 lsp_store.update(cx, |lsp_store, cx| {
550 lsp_store.cleanup_lsp_data(server_id);
551 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
552 });
553 }
554 })?;
555
556 language_server.notify::<lsp::notification::DidChangeConfiguration>(
557 did_change_configuration_params,
558 )?;
559
560 anyhow::Ok(language_server)
561 }
562 .await;
563
564 match result {
565 Ok(server) => {
566 lsp_store
567 .update(cx, |lsp_store, cx| {
568 lsp_store.insert_newly_running_language_server(
569 adapter,
570 server.clone(),
571 server_id,
572 key,
573 pending_workspace_folders,
574 cx,
575 );
576 })
577 .ok();
578 stderr_capture.lock().take();
579 Some(server)
580 }
581
582 Err(err) => {
583 let log = stderr_capture.lock().take().unwrap_or_default();
584 delegate.update_status(
585 adapter.name(),
586 BinaryStatus::Failed {
587 error: if log.is_empty() {
588 format!("{err:#}")
589 } else {
590 format!("{err:#}\n-- stderr --\n{log}")
591 },
592 },
593 );
594 log::error!(
595 "Failed to start language server {server_name:?}: {}",
596 redact_command(&format!("{err:?}"))
597 );
598 if !log.is_empty() {
599 log::error!("server stderr: {}", redact_command(&log));
600 }
601 None
602 }
603 }
604 })
605 };
606 let state = LanguageServerState::Starting {
607 startup,
608 pending_workspace_folders,
609 };
610
611 if update_binary_status {
612 self.languages
613 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
614 }
615
616 self.language_servers.insert(server_id, state);
617 self.language_server_ids
618 .entry(key)
619 .or_insert(UnifiedLanguageServer {
620 id: server_id,
621 project_roots: Default::default(),
622 });
623 server_id
624 }
625
626 fn get_language_server_binary(
627 &self,
628 worktree_abs_path: Arc<Path>,
629 adapter: Arc<CachedLspAdapter>,
630 settings: Arc<LspSettings>,
631 toolchain: Option<Toolchain>,
632 delegate: Arc<dyn LspAdapterDelegate>,
633 allow_binary_download: bool,
634 untrusted_worktree_task: Option<Receiver<()>>,
635 cx: &mut App,
636 ) -> Task<Result<LanguageServerBinary>> {
637 if let Some(settings) = &settings.binary
638 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
639 {
640 let settings = settings.clone();
641 let languages = self.languages.clone();
642 return cx.background_spawn(async move {
643 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
644 log::info!(
645 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
646 adapter.name(),
647 );
648 untrusted_worktree_task.recv().await.ok();
649 log::info!(
650 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
651 adapter.name(),
652 );
653 languages
654 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
655 }
656 let mut env = delegate.shell_env().await;
657 env.extend(settings.env.unwrap_or_default());
658
659 Ok(LanguageServerBinary {
660 path: delegate.resolve_executable_path(path),
661 env: Some(env),
662 arguments: settings
663 .arguments
664 .unwrap_or_default()
665 .iter()
666 .map(Into::into)
667 .collect(),
668 })
669 });
670 }
671 let lsp_binary_options = LanguageServerBinaryOptions {
672 allow_path_lookup: !settings
673 .binary
674 .as_ref()
675 .and_then(|b| b.ignore_system_version)
676 .unwrap_or_default(),
677 allow_binary_download,
678 pre_release: settings
679 .fetch
680 .as_ref()
681 .and_then(|f| f.pre_release)
682 .unwrap_or(false),
683 };
684
685 cx.spawn(async move |cx| {
686 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
687 log::info!(
688 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
689 adapter.name(),
690 );
691 untrusted_worktree_task.recv().await.ok();
692 log::info!(
693 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
694 adapter.name(),
695 );
696 }
697
698 let (existing_binary, maybe_download_binary) = adapter
699 .clone()
700 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
701 .await
702 .await;
703
704 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
705
706 let mut binary = match (existing_binary, maybe_download_binary) {
707 (binary, None) => binary?,
708 (Err(_), Some(downloader)) => downloader.await?,
709 (Ok(existing_binary), Some(downloader)) => {
710 let mut download_timeout = cx
711 .background_executor()
712 .timer(SERVER_DOWNLOAD_TIMEOUT)
713 .fuse();
714 let mut downloader = downloader.fuse();
715 futures::select! {
716 _ = download_timeout => {
717 // Return existing binary and kick the existing work to the background.
718 cx.spawn(async move |_| downloader.await).detach();
719 Ok(existing_binary)
720 },
721 downloaded_or_existing_binary = downloader => {
722 // If download fails, this results in the existing binary.
723 downloaded_or_existing_binary
724 }
725 }?
726 }
727 };
728 let mut shell_env = delegate.shell_env().await;
729
730 shell_env.extend(binary.env.unwrap_or_default());
731
732 if let Some(settings) = settings.binary.as_ref() {
733 if let Some(arguments) = &settings.arguments {
734 binary.arguments = arguments.iter().map(Into::into).collect();
735 }
736 if let Some(env) = &settings.env {
737 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
738 }
739 }
740
741 binary.env = Some(shell_env);
742 Ok(binary)
743 })
744 }
745
746 fn setup_lsp_messages(
747 lsp_store: WeakEntity<LspStore>,
748 language_server: &LanguageServer,
749 delegate: Arc<dyn LspAdapterDelegate>,
750 adapter: Arc<CachedLspAdapter>,
751 ) {
752 let name = language_server.name();
753 let server_id = language_server.server_id();
754 language_server
755 .on_notification::<lsp::notification::PublishDiagnostics, _>({
756 let adapter = adapter.clone();
757 let this = lsp_store.clone();
758 move |mut params, cx| {
759 let adapter = adapter.clone();
760 if let Some(this) = this.upgrade() {
761 this.update(cx, |this, cx| {
762 {
763 let buffer = params
764 .uri
765 .to_file_path()
766 .map(|file_path| this.get_buffer(&file_path, cx))
767 .ok()
768 .flatten();
769 adapter.process_diagnostics(&mut params, server_id, buffer);
770 }
771
772 this.merge_lsp_diagnostics(
773 DiagnosticSourceKind::Pushed,
774 vec![DocumentDiagnosticsUpdate {
775 server_id,
776 diagnostics: params,
777 result_id: None,
778 disk_based_sources: Cow::Borrowed(
779 &adapter.disk_based_diagnostic_sources,
780 ),
781 registration_id: None,
782 }],
783 |_, diagnostic, cx| match diagnostic.source_kind {
784 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
785 adapter.retain_old_diagnostic(diagnostic, cx)
786 }
787 DiagnosticSourceKind::Pulled => true,
788 },
789 cx,
790 )
791 .log_err();
792 });
793 }
794 }
795 })
796 .detach();
797 language_server
798 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
799 let adapter = adapter.adapter.clone();
800 let delegate = delegate.clone();
801 let this = lsp_store.clone();
802 move |params, cx| {
803 let adapter = adapter.clone();
804 let delegate = delegate.clone();
805 let this = this.clone();
806 let mut cx = cx.clone();
807 async move {
808 let toolchain_for_id = this
809 .update(&mut cx, |this, _| {
810 this.as_local()?.language_server_ids.iter().find_map(
811 |(seed, value)| {
812 (value.id == server_id).then(|| seed.toolchain.clone())
813 },
814 )
815 })?
816 .context("Expected the LSP store to be in a local mode")?;
817
818 let mut scope_uri_to_workspace_config = BTreeMap::new();
819 for item in ¶ms.items {
820 let scope_uri = item.scope_uri.clone();
821 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
822 scope_uri_to_workspace_config.entry(scope_uri.clone())
823 else {
824 // We've already queried workspace configuration of this URI.
825 continue;
826 };
827 let workspace_config = Self::workspace_configuration_for_adapter(
828 adapter.clone(),
829 &delegate,
830 toolchain_for_id.clone(),
831 scope_uri,
832 &mut cx,
833 )
834 .await?;
835 new_scope_uri.insert(workspace_config);
836 }
837
838 Ok(params
839 .items
840 .into_iter()
841 .filter_map(|item| {
842 let workspace_config =
843 scope_uri_to_workspace_config.get(&item.scope_uri)?;
844 if let Some(section) = &item.section {
845 Some(
846 workspace_config
847 .get(section)
848 .cloned()
849 .unwrap_or(serde_json::Value::Null),
850 )
851 } else {
852 Some(workspace_config.clone())
853 }
854 })
855 .collect())
856 }
857 }
858 })
859 .detach();
860
861 language_server
862 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
863 let this = lsp_store.clone();
864 move |_, cx| {
865 let this = this.clone();
866 let cx = cx.clone();
867 async move {
868 let Some(server) =
869 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
870 else {
871 return Ok(None);
872 };
873 let root = server.workspace_folders();
874 Ok(Some(
875 root.into_iter()
876 .map(|uri| WorkspaceFolder {
877 uri,
878 name: Default::default(),
879 })
880 .collect(),
881 ))
882 }
883 }
884 })
885 .detach();
886 // Even though we don't have handling for these requests, respond to them to
887 // avoid stalling any language server like `gopls` which waits for a response
888 // to these requests when initializing.
889 language_server
890 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
891 let this = lsp_store.clone();
892 move |params, cx| {
893 let this = this.clone();
894 let mut cx = cx.clone();
895 async move {
896 this.update(&mut cx, |this, _| {
897 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
898 {
899 status
900 .progress_tokens
901 .insert(ProgressToken::from_lsp(params.token));
902 }
903 })?;
904
905 Ok(())
906 }
907 }
908 })
909 .detach();
910
911 language_server
912 .on_request::<lsp::request::RegisterCapability, _, _>({
913 let lsp_store = lsp_store.clone();
914 move |params, cx| {
915 let lsp_store = lsp_store.clone();
916 let mut cx = cx.clone();
917 async move {
918 lsp_store
919 .update(&mut cx, |lsp_store, cx| {
920 if lsp_store.as_local().is_some() {
921 match lsp_store
922 .register_server_capabilities(server_id, params, cx)
923 {
924 Ok(()) => {}
925 Err(e) => {
926 log::error!(
927 "Failed to register server capabilities: {e:#}"
928 );
929 }
930 };
931 }
932 })
933 .ok();
934 Ok(())
935 }
936 }
937 })
938 .detach();
939
940 language_server
941 .on_request::<lsp::request::UnregisterCapability, _, _>({
942 let lsp_store = lsp_store.clone();
943 move |params, cx| {
944 let lsp_store = lsp_store.clone();
945 let mut cx = cx.clone();
946 async move {
947 lsp_store
948 .update(&mut cx, |lsp_store, cx| {
949 if lsp_store.as_local().is_some() {
950 match lsp_store
951 .unregister_server_capabilities(server_id, params, cx)
952 {
953 Ok(()) => {}
954 Err(e) => {
955 log::error!(
956 "Failed to unregister server capabilities: {e:#}"
957 );
958 }
959 }
960 }
961 })
962 .ok();
963 Ok(())
964 }
965 }
966 })
967 .detach();
968
969 language_server
970 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
971 let this = lsp_store.clone();
972 move |params, cx| {
973 let mut cx = cx.clone();
974 let this = this.clone();
975 async move {
976 LocalLspStore::on_lsp_workspace_edit(
977 this.clone(),
978 params,
979 server_id,
980 &mut cx,
981 )
982 .await
983 }
984 }
985 })
986 .detach();
987
988 language_server
989 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
990 let lsp_store = lsp_store.clone();
991 let request_id = Arc::new(AtomicUsize::new(0));
992 move |(), cx| {
993 let lsp_store = lsp_store.clone();
994 let request_id = request_id.clone();
995 let mut cx = cx.clone();
996 async move {
997 lsp_store
998 .update(&mut cx, |lsp_store, cx| {
999 let request_id =
1000 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1001 cx.emit(LspStoreEvent::RefreshInlayHints {
1002 server_id,
1003 request_id,
1004 });
1005 lsp_store
1006 .downstream_client
1007 .as_ref()
1008 .map(|(client, project_id)| {
1009 client.send(proto::RefreshInlayHints {
1010 project_id: *project_id,
1011 server_id: server_id.to_proto(),
1012 request_id: request_id.map(|id| id as u64),
1013 })
1014 })
1015 })?
1016 .transpose()?;
1017 Ok(())
1018 }
1019 }
1020 })
1021 .detach();
1022
1023 language_server
1024 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1025 let this = lsp_store.clone();
1026 move |(), cx| {
1027 let this = this.clone();
1028 let mut cx = cx.clone();
1029 async move {
1030 this.update(&mut cx, |this, cx| {
1031 cx.emit(LspStoreEvent::RefreshCodeLens);
1032 this.downstream_client.as_ref().map(|(client, project_id)| {
1033 client.send(proto::RefreshCodeLens {
1034 project_id: *project_id,
1035 })
1036 })
1037 })?
1038 .transpose()?;
1039 Ok(())
1040 }
1041 }
1042 })
1043 .detach();
1044
1045 language_server
1046 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1047 let this = lsp_store.clone();
1048 move |(), cx| {
1049 let this = this.clone();
1050 let mut cx = cx.clone();
1051 async move {
1052 this.update(&mut cx, |lsp_store, cx| {
1053 lsp_store.pull_workspace_diagnostics(server_id);
1054 lsp_store
1055 .downstream_client
1056 .as_ref()
1057 .map(|(client, project_id)| {
1058 client.send(proto::PullWorkspaceDiagnostics {
1059 project_id: *project_id,
1060 server_id: server_id.to_proto(),
1061 })
1062 })
1063 .transpose()?;
1064 anyhow::Ok(
1065 lsp_store.pull_document_diagnostics_for_server(server_id, cx),
1066 )
1067 })??
1068 .await;
1069 Ok(())
1070 }
1071 }
1072 })
1073 .detach();
1074
1075 language_server
1076 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1077 let this = lsp_store.clone();
1078 let name = name.to_string();
1079 let adapter = adapter.clone();
1080 move |params, cx| {
1081 let this = this.clone();
1082 let name = name.to_string();
1083 let adapter = adapter.clone();
1084 let mut cx = cx.clone();
1085 async move {
1086 let actions = params.actions.unwrap_or_default();
1087 let message = params.message.clone();
1088 let (tx, rx) = smol::channel::bounded(1);
1089 let request = LanguageServerPromptRequest {
1090 level: match params.typ {
1091 lsp::MessageType::ERROR => PromptLevel::Critical,
1092 lsp::MessageType::WARNING => PromptLevel::Warning,
1093 _ => PromptLevel::Info,
1094 },
1095 message: params.message,
1096 actions,
1097 response_channel: tx,
1098 lsp_name: name.clone(),
1099 };
1100
1101 let did_update = this
1102 .update(&mut cx, |_, cx| {
1103 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1104 })
1105 .is_ok();
1106 if did_update {
1107 let response = rx.recv().await.ok();
1108 if let Some(ref selected_action) = response {
1109 let context = language::PromptResponseContext {
1110 message,
1111 selected_action: selected_action.clone(),
1112 };
1113 adapter.process_prompt_response(&context, &mut cx)
1114 }
1115
1116 Ok(response)
1117 } else {
1118 Ok(None)
1119 }
1120 }
1121 }
1122 })
1123 .detach();
1124 language_server
1125 .on_notification::<lsp::notification::ShowMessage, _>({
1126 let this = lsp_store.clone();
1127 let name = name.to_string();
1128 move |params, cx| {
1129 let this = this.clone();
1130 let name = name.to_string();
1131 let mut cx = cx.clone();
1132
1133 let (tx, _) = smol::channel::bounded(1);
1134 let request = LanguageServerPromptRequest {
1135 level: match params.typ {
1136 lsp::MessageType::ERROR => PromptLevel::Critical,
1137 lsp::MessageType::WARNING => PromptLevel::Warning,
1138 _ => PromptLevel::Info,
1139 },
1140 message: params.message,
1141 actions: vec![],
1142 response_channel: tx,
1143 lsp_name: name,
1144 };
1145
1146 let _ = this.update(&mut cx, |_, cx| {
1147 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1148 });
1149 }
1150 })
1151 .detach();
1152
1153 let disk_based_diagnostics_progress_token =
1154 adapter.disk_based_diagnostics_progress_token.clone();
1155
1156 language_server
1157 .on_notification::<lsp::notification::Progress, _>({
1158 let this = lsp_store.clone();
1159 move |params, cx| {
1160 if let Some(this) = this.upgrade() {
1161 this.update(cx, |this, cx| {
1162 this.on_lsp_progress(
1163 params,
1164 server_id,
1165 disk_based_diagnostics_progress_token.clone(),
1166 cx,
1167 );
1168 });
1169 }
1170 }
1171 })
1172 .detach();
1173
1174 language_server
1175 .on_notification::<lsp::notification::LogMessage, _>({
1176 let this = lsp_store.clone();
1177 move |params, cx| {
1178 if let Some(this) = this.upgrade() {
1179 this.update(cx, |_, cx| {
1180 cx.emit(LspStoreEvent::LanguageServerLog(
1181 server_id,
1182 LanguageServerLogType::Log(params.typ),
1183 params.message,
1184 ));
1185 });
1186 }
1187 }
1188 })
1189 .detach();
1190
1191 language_server
1192 .on_notification::<lsp::notification::LogTrace, _>({
1193 let this = lsp_store.clone();
1194 move |params, cx| {
1195 let mut cx = cx.clone();
1196 if let Some(this) = this.upgrade() {
1197 this.update(&mut cx, |_, cx| {
1198 cx.emit(LspStoreEvent::LanguageServerLog(
1199 server_id,
1200 LanguageServerLogType::Trace {
1201 verbose_info: params.verbose,
1202 },
1203 params.message,
1204 ));
1205 });
1206 }
1207 }
1208 })
1209 .detach();
1210
1211 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1212 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1213 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1214 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1215 }
1216
1217 fn shutdown_language_servers_on_quit(
1218 &mut self,
1219 _: &mut Context<LspStore>,
1220 ) -> impl Future<Output = ()> + use<> {
1221 let shutdown_futures = self
1222 .language_servers
1223 .drain()
1224 .map(|(_, server_state)| Self::shutdown_server(server_state))
1225 .collect::<Vec<_>>();
1226
1227 async move {
1228 join_all(shutdown_futures).await;
1229 }
1230 }
1231
1232 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1233 match server_state {
1234 LanguageServerState::Running { server, .. } => {
1235 if let Some(shutdown) = server.shutdown() {
1236 shutdown.await;
1237 }
1238 }
1239 LanguageServerState::Starting { startup, .. } => {
1240 if let Some(server) = startup.await
1241 && let Some(shutdown) = server.shutdown()
1242 {
1243 shutdown.await;
1244 }
1245 }
1246 }
1247 Ok(())
1248 }
1249
1250 fn language_servers_for_worktree(
1251 &self,
1252 worktree_id: WorktreeId,
1253 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1254 self.language_server_ids
1255 .iter()
1256 .filter_map(move |(seed, state)| {
1257 if seed.worktree_id != worktree_id {
1258 return None;
1259 }
1260
1261 if let Some(LanguageServerState::Running { server, .. }) =
1262 self.language_servers.get(&state.id)
1263 {
1264 Some(server)
1265 } else {
1266 None
1267 }
1268 })
1269 }
1270
1271 fn language_server_ids_for_project_path(
1272 &self,
1273 project_path: ProjectPath,
1274 language: &Language,
1275 cx: &mut App,
1276 ) -> Vec<LanguageServerId> {
1277 let Some(worktree) = self
1278 .worktree_store
1279 .read(cx)
1280 .worktree_for_id(project_path.worktree_id, cx)
1281 else {
1282 return Vec::new();
1283 };
1284 let delegate: Arc<dyn ManifestDelegate> =
1285 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1286
1287 self.lsp_tree
1288 .get(
1289 project_path,
1290 language.name(),
1291 language.manifest(),
1292 &delegate,
1293 cx,
1294 )
1295 .collect::<Vec<_>>()
1296 }
1297
1298 fn language_server_ids_for_buffer(
1299 &self,
1300 buffer: &Buffer,
1301 cx: &mut App,
1302 ) -> Vec<LanguageServerId> {
1303 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1304 let worktree_id = file.worktree_id(cx);
1305
1306 let path: Arc<RelPath> = file
1307 .path()
1308 .parent()
1309 .map(Arc::from)
1310 .unwrap_or_else(|| file.path().clone());
1311 let worktree_path = ProjectPath { worktree_id, path };
1312 self.language_server_ids_for_project_path(worktree_path, language, cx)
1313 } else {
1314 Vec::new()
1315 }
1316 }
1317
1318 fn language_servers_for_buffer<'a>(
1319 &'a self,
1320 buffer: &'a Buffer,
1321 cx: &'a mut App,
1322 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1323 self.language_server_ids_for_buffer(buffer, cx)
1324 .into_iter()
1325 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1326 LanguageServerState::Running {
1327 adapter, server, ..
1328 } => Some((adapter, server)),
1329 _ => None,
1330 })
1331 }
1332
1333 async fn execute_code_action_kind_locally(
1334 lsp_store: WeakEntity<LspStore>,
1335 mut buffers: Vec<Entity<Buffer>>,
1336 kind: CodeActionKind,
1337 push_to_history: bool,
1338 cx: &mut AsyncApp,
1339 ) -> anyhow::Result<ProjectTransaction> {
1340 // Do not allow multiple concurrent code actions requests for the
1341 // same buffer.
1342 lsp_store.update(cx, |this, cx| {
1343 let this = this.as_local_mut().unwrap();
1344 buffers.retain(|buffer| {
1345 this.buffers_being_formatted
1346 .insert(buffer.read(cx).remote_id())
1347 });
1348 })?;
1349 let _cleanup = defer({
1350 let this = lsp_store.clone();
1351 let mut cx = cx.clone();
1352 let buffers = &buffers;
1353 move || {
1354 this.update(&mut cx, |this, cx| {
1355 let this = this.as_local_mut().unwrap();
1356 for buffer in buffers {
1357 this.buffers_being_formatted
1358 .remove(&buffer.read(cx).remote_id());
1359 }
1360 })
1361 .ok();
1362 }
1363 });
1364 let mut project_transaction = ProjectTransaction::default();
1365
1366 for buffer in &buffers {
1367 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1368 buffer.update(cx, |buffer, cx| {
1369 lsp_store
1370 .as_local()
1371 .unwrap()
1372 .language_servers_for_buffer(buffer, cx)
1373 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1374 .collect::<Vec<_>>()
1375 })
1376 })?;
1377 for (_, language_server) in adapters_and_servers.iter() {
1378 let actions = Self::get_server_code_actions_from_action_kinds(
1379 &lsp_store,
1380 language_server.server_id(),
1381 vec![kind.clone()],
1382 buffer,
1383 cx,
1384 )
1385 .await?;
1386 Self::execute_code_actions_on_server(
1387 &lsp_store,
1388 language_server,
1389 actions,
1390 push_to_history,
1391 &mut project_transaction,
1392 cx,
1393 )
1394 .await?;
1395 }
1396 }
1397 Ok(project_transaction)
1398 }
1399
1400 async fn format_locally(
1401 lsp_store: WeakEntity<LspStore>,
1402 mut buffers: Vec<FormattableBuffer>,
1403 push_to_history: bool,
1404 trigger: FormatTrigger,
1405 logger: zlog::Logger,
1406 cx: &mut AsyncApp,
1407 ) -> anyhow::Result<ProjectTransaction> {
1408 // Do not allow multiple concurrent formatting requests for the
1409 // same buffer.
1410 lsp_store.update(cx, |this, cx| {
1411 let this = this.as_local_mut().unwrap();
1412 buffers.retain(|buffer| {
1413 this.buffers_being_formatted
1414 .insert(buffer.handle.read(cx).remote_id())
1415 });
1416 })?;
1417
1418 let _cleanup = defer({
1419 let this = lsp_store.clone();
1420 let mut cx = cx.clone();
1421 let buffers = &buffers;
1422 move || {
1423 this.update(&mut cx, |this, cx| {
1424 let this = this.as_local_mut().unwrap();
1425 for buffer in buffers {
1426 this.buffers_being_formatted
1427 .remove(&buffer.handle.read(cx).remote_id());
1428 }
1429 })
1430 .ok();
1431 }
1432 });
1433
1434 let mut project_transaction = ProjectTransaction::default();
1435
1436 for buffer in &buffers {
1437 zlog::debug!(
1438 logger =>
1439 "formatting buffer '{:?}'",
1440 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1441 );
1442 // Create an empty transaction to hold all of the formatting edits.
1443 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1444 // ensure no transactions created while formatting are
1445 // grouped with the previous transaction in the history
1446 // based on the transaction group interval
1447 buffer.finalize_last_transaction();
1448 buffer
1449 .start_transaction()
1450 .context("transaction already open")?;
1451 buffer.end_transaction(cx);
1452 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1453 buffer.finalize_last_transaction();
1454 anyhow::Ok(transaction_id)
1455 })?;
1456
1457 let result = Self::format_buffer_locally(
1458 lsp_store.clone(),
1459 buffer,
1460 formatting_transaction_id,
1461 trigger,
1462 logger,
1463 cx,
1464 )
1465 .await;
1466
1467 buffer.handle.update(cx, |buffer, cx| {
1468 let Some(formatting_transaction) =
1469 buffer.get_transaction(formatting_transaction_id).cloned()
1470 else {
1471 zlog::warn!(logger => "no formatting transaction");
1472 return;
1473 };
1474 if formatting_transaction.edit_ids.is_empty() {
1475 zlog::debug!(logger => "no changes made while formatting");
1476 buffer.forget_transaction(formatting_transaction_id);
1477 return;
1478 }
1479 if !push_to_history {
1480 zlog::trace!(logger => "forgetting format transaction");
1481 buffer.forget_transaction(formatting_transaction.id);
1482 }
1483 project_transaction
1484 .0
1485 .insert(cx.entity(), formatting_transaction);
1486 });
1487
1488 result?;
1489 }
1490
1491 Ok(project_transaction)
1492 }
1493
1494 async fn format_buffer_locally(
1495 lsp_store: WeakEntity<LspStore>,
1496 buffer: &FormattableBuffer,
1497 formatting_transaction_id: clock::Lamport,
1498 trigger: FormatTrigger,
1499 logger: zlog::Logger,
1500 cx: &mut AsyncApp,
1501 ) -> Result<()> {
1502 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1503 buffer.handle.update(cx, |buffer, cx| {
1504 let adapters_and_servers = lsp_store
1505 .as_local()
1506 .unwrap()
1507 .language_servers_for_buffer(buffer, cx)
1508 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1509 .collect::<Vec<_>>();
1510 let settings =
1511 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1512 .into_owned();
1513 (adapters_and_servers, settings)
1514 })
1515 })?;
1516
1517 /// Apply edits to the buffer that will become part of the formatting transaction.
1518 /// Fails if the buffer has been edited since the start of that transaction.
1519 fn extend_formatting_transaction(
1520 buffer: &FormattableBuffer,
1521 formatting_transaction_id: text::TransactionId,
1522 cx: &mut AsyncApp,
1523 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1524 ) -> anyhow::Result<()> {
1525 buffer.handle.update(cx, |buffer, cx| {
1526 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1527 if last_transaction_id != Some(formatting_transaction_id) {
1528 anyhow::bail!("Buffer edited while formatting. Aborting")
1529 }
1530 buffer.start_transaction();
1531 operation(buffer, cx);
1532 if let Some(transaction_id) = buffer.end_transaction(cx) {
1533 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1534 }
1535 Ok(())
1536 })
1537 }
1538
1539 // handle whitespace formatting
1540 if settings.remove_trailing_whitespace_on_save {
1541 zlog::trace!(logger => "removing trailing whitespace");
1542 let diff = buffer
1543 .handle
1544 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1545 .await;
1546 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1547 buffer.apply_diff(diff, cx);
1548 })?;
1549 }
1550
1551 if settings.ensure_final_newline_on_save {
1552 zlog::trace!(logger => "ensuring final newline");
1553 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1554 buffer.ensure_final_newline(cx);
1555 })?;
1556 }
1557
1558 // Formatter for `code_actions_on_format` that runs before
1559 // the rest of the formatters
1560 let mut code_actions_on_format_formatters = None;
1561 let should_run_code_actions_on_format = !matches!(
1562 (trigger, &settings.format_on_save),
1563 (FormatTrigger::Save, &FormatOnSave::Off)
1564 );
1565 if should_run_code_actions_on_format {
1566 let have_code_actions_to_run_on_format = settings
1567 .code_actions_on_format
1568 .values()
1569 .any(|enabled| *enabled);
1570 if have_code_actions_to_run_on_format {
1571 zlog::trace!(logger => "going to run code actions on format");
1572 code_actions_on_format_formatters = Some(
1573 settings
1574 .code_actions_on_format
1575 .iter()
1576 .filter_map(|(action, enabled)| enabled.then_some(action))
1577 .cloned()
1578 .map(Formatter::CodeAction)
1579 .collect::<Vec<_>>(),
1580 );
1581 }
1582 }
1583
1584 let formatters = match (trigger, &settings.format_on_save) {
1585 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1586 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1587 settings.formatter.as_ref()
1588 }
1589 };
1590
1591 let formatters = code_actions_on_format_formatters
1592 .iter()
1593 .flatten()
1594 .chain(formatters);
1595
1596 for formatter in formatters {
1597 let formatter = if formatter == &Formatter::Auto {
1598 if settings.prettier.allowed {
1599 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1600 &Formatter::Prettier
1601 } else {
1602 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1603 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1604 }
1605 } else {
1606 formatter
1607 };
1608 match formatter {
1609 Formatter::Auto => unreachable!("Auto resolved above"),
1610 Formatter::Prettier => {
1611 let logger = zlog::scoped!(logger => "prettier");
1612 zlog::trace!(logger => "formatting");
1613 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1614
1615 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1616 lsp_store.prettier_store().unwrap().downgrade()
1617 })?;
1618 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1619 .await
1620 .transpose()?;
1621 let Some(diff) = diff else {
1622 zlog::trace!(logger => "No changes");
1623 continue;
1624 };
1625
1626 extend_formatting_transaction(
1627 buffer,
1628 formatting_transaction_id,
1629 cx,
1630 |buffer, cx| {
1631 buffer.apply_diff(diff, cx);
1632 },
1633 )?;
1634 }
1635 Formatter::External { command, arguments } => {
1636 let logger = zlog::scoped!(logger => "command");
1637 zlog::trace!(logger => "formatting");
1638 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1639
1640 let diff = Self::format_via_external_command(
1641 buffer,
1642 command.as_ref(),
1643 arguments.as_deref(),
1644 cx,
1645 )
1646 .await
1647 .with_context(|| {
1648 format!("Failed to format buffer via external command: {}", command)
1649 })?;
1650 let Some(diff) = diff else {
1651 zlog::trace!(logger => "No changes");
1652 continue;
1653 };
1654
1655 extend_formatting_transaction(
1656 buffer,
1657 formatting_transaction_id,
1658 cx,
1659 |buffer, cx| {
1660 buffer.apply_diff(diff, cx);
1661 },
1662 )?;
1663 }
1664 Formatter::LanguageServer(specifier) => {
1665 let logger = zlog::scoped!(logger => "language-server");
1666 zlog::trace!(logger => "formatting");
1667 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1668
1669 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1670 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1671 continue;
1672 };
1673
1674 let language_server = match specifier {
1675 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1676 adapters_and_servers.iter().find_map(|(adapter, server)| {
1677 if adapter.name.0.as_ref() == name {
1678 Some(server.clone())
1679 } else {
1680 None
1681 }
1682 })
1683 }
1684 settings::LanguageServerFormatterSpecifier::Current => {
1685 adapters_and_servers.first().map(|e| e.1.clone())
1686 }
1687 };
1688
1689 let Some(language_server) = language_server else {
1690 log::debug!(
1691 "No language server found to format buffer '{:?}'. Skipping",
1692 buffer_path_abs.as_path().to_string_lossy()
1693 );
1694 continue;
1695 };
1696
1697 zlog::trace!(
1698 logger =>
1699 "Formatting buffer '{:?}' using language server '{:?}'",
1700 buffer_path_abs.as_path().to_string_lossy(),
1701 language_server.name()
1702 );
1703
1704 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1705 zlog::trace!(logger => "formatting ranges");
1706 Self::format_ranges_via_lsp(
1707 &lsp_store,
1708 &buffer.handle,
1709 ranges,
1710 buffer_path_abs,
1711 &language_server,
1712 &settings,
1713 cx,
1714 )
1715 .await
1716 .context("Failed to format ranges via language server")?
1717 } else {
1718 zlog::trace!(logger => "formatting full");
1719 Self::format_via_lsp(
1720 &lsp_store,
1721 &buffer.handle,
1722 buffer_path_abs,
1723 &language_server,
1724 &settings,
1725 cx,
1726 )
1727 .await
1728 .context("failed to format via language server")?
1729 };
1730
1731 if edits.is_empty() {
1732 zlog::trace!(logger => "No changes");
1733 continue;
1734 }
1735 extend_formatting_transaction(
1736 buffer,
1737 formatting_transaction_id,
1738 cx,
1739 |buffer, cx| {
1740 buffer.edit(edits, None, cx);
1741 },
1742 )?;
1743 }
1744 Formatter::CodeAction(code_action_name) => {
1745 let logger = zlog::scoped!(logger => "code-actions");
1746 zlog::trace!(logger => "formatting");
1747 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1748
1749 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1750 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1751 continue;
1752 };
1753
1754 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1755 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1756
1757 let mut actions_and_servers = Vec::new();
1758
1759 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1760 let actions_result = Self::get_server_code_actions_from_action_kinds(
1761 &lsp_store,
1762 language_server.server_id(),
1763 vec![code_action_kind.clone()],
1764 &buffer.handle,
1765 cx,
1766 )
1767 .await
1768 .with_context(|| {
1769 format!(
1770 "Failed to resolve code action {:?} with language server {}",
1771 code_action_kind,
1772 language_server.name()
1773 )
1774 });
1775 let Ok(actions) = actions_result else {
1776 // note: it may be better to set result to the error and break formatters here
1777 // but for now we try to execute the actions that we can resolve and skip the rest
1778 zlog::error!(
1779 logger =>
1780 "Failed to resolve code action {:?} with language server {}",
1781 code_action_kind,
1782 language_server.name()
1783 );
1784 continue;
1785 };
1786 for action in actions {
1787 actions_and_servers.push((action, index));
1788 }
1789 }
1790
1791 if actions_and_servers.is_empty() {
1792 zlog::warn!(logger => "No code actions were resolved, continuing");
1793 continue;
1794 }
1795
1796 'actions: for (mut action, server_index) in actions_and_servers {
1797 let server = &adapters_and_servers[server_index].1;
1798
1799 let describe_code_action = |action: &CodeAction| {
1800 format!(
1801 "code action '{}' with title \"{}\" on server {}",
1802 action
1803 .lsp_action
1804 .action_kind()
1805 .unwrap_or("unknown".into())
1806 .as_str(),
1807 action.lsp_action.title(),
1808 server.name(),
1809 )
1810 };
1811
1812 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1813
1814 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1815 zlog::error!(
1816 logger =>
1817 "Failed to resolve {}. Error: {}",
1818 describe_code_action(&action),
1819 err
1820 );
1821 continue;
1822 }
1823
1824 if let Some(edit) = action.lsp_action.edit().cloned() {
1825 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1826 // but filters out and logs warnings for code actions that require unreasonably
1827 // difficult handling on our part, such as:
1828 // - applying edits that call commands
1829 // which can result in arbitrary workspace edits being sent from the server that
1830 // have no way of being tied back to the command that initiated them (i.e. we
1831 // can't know which edits are part of the format request, or if the server is done sending
1832 // actions in response to the command)
1833 // - actions that create/delete/modify/rename files other than the one we are formatting
1834 // as we then would need to handle such changes correctly in the local history as well
1835 // as the remote history through the ProjectTransaction
1836 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1837 // Supporting these actions is not impossible, but not supported as of yet.
1838 if edit.changes.is_none() && edit.document_changes.is_none() {
1839 zlog::trace!(
1840 logger =>
1841 "No changes for code action. Skipping {}",
1842 describe_code_action(&action),
1843 );
1844 continue;
1845 }
1846
1847 let mut operations = Vec::new();
1848 if let Some(document_changes) = edit.document_changes {
1849 match document_changes {
1850 lsp::DocumentChanges::Edits(edits) => operations.extend(
1851 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1852 ),
1853 lsp::DocumentChanges::Operations(ops) => operations = ops,
1854 }
1855 } else if let Some(changes) = edit.changes {
1856 operations.extend(changes.into_iter().map(|(uri, edits)| {
1857 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1858 text_document:
1859 lsp::OptionalVersionedTextDocumentIdentifier {
1860 uri,
1861 version: None,
1862 },
1863 edits: edits.into_iter().map(Edit::Plain).collect(),
1864 })
1865 }));
1866 }
1867
1868 let mut edits = Vec::with_capacity(operations.len());
1869
1870 if operations.is_empty() {
1871 zlog::trace!(
1872 logger =>
1873 "No changes for code action. Skipping {}",
1874 describe_code_action(&action),
1875 );
1876 continue;
1877 }
1878 for operation in operations {
1879 let op = match operation {
1880 lsp::DocumentChangeOperation::Edit(op) => op,
1881 lsp::DocumentChangeOperation::Op(_) => {
1882 zlog::warn!(
1883 logger =>
1884 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1885 describe_code_action(&action),
1886 );
1887 continue 'actions;
1888 }
1889 };
1890 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1891 zlog::warn!(
1892 logger =>
1893 "Failed to convert URI '{:?}' to file path. Skipping {}",
1894 &op.text_document.uri,
1895 describe_code_action(&action),
1896 );
1897 continue 'actions;
1898 };
1899 if &file_path != buffer_path_abs {
1900 zlog::warn!(
1901 logger =>
1902 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1903 file_path,
1904 buffer_path_abs,
1905 describe_code_action(&action),
1906 );
1907 continue 'actions;
1908 }
1909
1910 let mut lsp_edits = Vec::new();
1911 for edit in op.edits {
1912 match edit {
1913 Edit::Plain(edit) => {
1914 if !lsp_edits.contains(&edit) {
1915 lsp_edits.push(edit);
1916 }
1917 }
1918 Edit::Annotated(edit) => {
1919 if !lsp_edits.contains(&edit.text_edit) {
1920 lsp_edits.push(edit.text_edit);
1921 }
1922 }
1923 Edit::Snippet(_) => {
1924 zlog::warn!(
1925 logger =>
1926 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1927 describe_code_action(&action),
1928 );
1929 continue 'actions;
1930 }
1931 }
1932 }
1933 let edits_result = lsp_store
1934 .update(cx, |lsp_store, cx| {
1935 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1936 &buffer.handle,
1937 lsp_edits,
1938 server.server_id(),
1939 op.text_document.version,
1940 cx,
1941 )
1942 })?
1943 .await;
1944 let Ok(resolved_edits) = edits_result else {
1945 zlog::warn!(
1946 logger =>
1947 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1948 buffer_path_abs.as_path(),
1949 describe_code_action(&action),
1950 );
1951 continue 'actions;
1952 };
1953 edits.extend(resolved_edits);
1954 }
1955
1956 if edits.is_empty() {
1957 zlog::warn!(logger => "No edits resolved from LSP");
1958 continue;
1959 }
1960
1961 extend_formatting_transaction(
1962 buffer,
1963 formatting_transaction_id,
1964 cx,
1965 |buffer, cx| {
1966 zlog::info!(
1967 "Applying edits {edits:?}. Content: {:?}",
1968 buffer.text()
1969 );
1970 buffer.edit(edits, None, cx);
1971 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1972 },
1973 )?;
1974 }
1975
1976 if let Some(command) = action.lsp_action.command() {
1977 zlog::warn!(
1978 logger =>
1979 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1980 &command.command,
1981 );
1982
1983 // bail early if command is invalid
1984 let server_capabilities = server.capabilities();
1985 let available_commands = server_capabilities
1986 .execute_command_provider
1987 .as_ref()
1988 .map(|options| options.commands.as_slice())
1989 .unwrap_or_default();
1990 if !available_commands.contains(&command.command) {
1991 zlog::warn!(
1992 logger =>
1993 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1994 command.command,
1995 server.name(),
1996 );
1997 continue;
1998 }
1999
2000 // noop so we just ensure buffer hasn't been edited since resolving code actions
2001 extend_formatting_transaction(
2002 buffer,
2003 formatting_transaction_id,
2004 cx,
2005 |_, _| {},
2006 )?;
2007 zlog::info!(logger => "Executing command {}", &command.command);
2008
2009 lsp_store.update(cx, |this, _| {
2010 this.as_local_mut()
2011 .unwrap()
2012 .last_workspace_edits_by_language_server
2013 .remove(&server.server_id());
2014 })?;
2015
2016 let execute_command_result = server
2017 .request::<lsp::request::ExecuteCommand>(
2018 lsp::ExecuteCommandParams {
2019 command: command.command.clone(),
2020 arguments: command.arguments.clone().unwrap_or_default(),
2021 ..Default::default()
2022 },
2023 )
2024 .await
2025 .into_response();
2026
2027 if execute_command_result.is_err() {
2028 zlog::error!(
2029 logger =>
2030 "Failed to execute command '{}' as part of {}",
2031 &command.command,
2032 describe_code_action(&action),
2033 );
2034 continue 'actions;
2035 }
2036
2037 let mut project_transaction_command =
2038 lsp_store.update(cx, |this, _| {
2039 this.as_local_mut()
2040 .unwrap()
2041 .last_workspace_edits_by_language_server
2042 .remove(&server.server_id())
2043 .unwrap_or_default()
2044 })?;
2045
2046 if let Some(transaction) =
2047 project_transaction_command.0.remove(&buffer.handle)
2048 {
2049 zlog::trace!(
2050 logger =>
2051 "Successfully captured {} edits that resulted from command {}",
2052 transaction.edit_ids.len(),
2053 &command.command,
2054 );
2055 let transaction_id_project_transaction = transaction.id;
2056 buffer.handle.update(cx, |buffer, _| {
2057 // it may have been removed from history if push_to_history was
2058 // false in deserialize_workspace_edit. If so push it so we
2059 // can merge it with the format transaction
2060 // and pop the combined transaction off the history stack
2061 // later if push_to_history is false
2062 if buffer.get_transaction(transaction.id).is_none() {
2063 buffer.push_transaction(transaction, Instant::now());
2064 }
2065 buffer.merge_transactions(
2066 transaction_id_project_transaction,
2067 formatting_transaction_id,
2068 );
2069 });
2070 }
2071
2072 if !project_transaction_command.0.is_empty() {
2073 let mut extra_buffers = String::new();
2074 for buffer in project_transaction_command.0.keys() {
2075 buffer.read_with(cx, |b, cx| {
2076 if let Some(path) = b.project_path(cx) {
2077 if !extra_buffers.is_empty() {
2078 extra_buffers.push_str(", ");
2079 }
2080 extra_buffers.push_str(path.path.as_unix_str());
2081 }
2082 });
2083 }
2084 zlog::warn!(
2085 logger =>
2086 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2087 &command.command,
2088 extra_buffers,
2089 );
2090 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2091 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2092 // add it so it's included, and merge it into the format transaction when its created later
2093 }
2094 }
2095 }
2096 }
2097 }
2098 }
2099
2100 Ok(())
2101 }
2102
2103 pub async fn format_ranges_via_lsp(
2104 this: &WeakEntity<LspStore>,
2105 buffer_handle: &Entity<Buffer>,
2106 ranges: &[Range<Anchor>],
2107 abs_path: &Path,
2108 language_server: &Arc<LanguageServer>,
2109 settings: &LanguageSettings,
2110 cx: &mut AsyncApp,
2111 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2112 let capabilities = &language_server.capabilities();
2113 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2114 if range_formatting_provider == Some(&OneOf::Left(false)) {
2115 anyhow::bail!(
2116 "{} language server does not support range formatting",
2117 language_server.name()
2118 );
2119 }
2120
2121 let uri = file_path_to_lsp_url(abs_path)?;
2122 let text_document = lsp::TextDocumentIdentifier::new(uri);
2123
2124 let lsp_edits = {
2125 let mut lsp_ranges = Vec::new();
2126 this.update(cx, |_this, cx| {
2127 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2128 // not have been sent to the language server. This seems like a fairly systemic
2129 // issue, though, the resolution probably is not specific to formatting.
2130 //
2131 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2132 // LSP.
2133 let snapshot = buffer_handle.read(cx).snapshot();
2134 for range in ranges {
2135 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2136 }
2137 anyhow::Ok(())
2138 })??;
2139
2140 let mut edits = None;
2141 for range in lsp_ranges {
2142 if let Some(mut edit) = language_server
2143 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2144 text_document: text_document.clone(),
2145 range,
2146 options: lsp_command::lsp_formatting_options(settings),
2147 work_done_progress_params: Default::default(),
2148 })
2149 .await
2150 .into_response()?
2151 {
2152 edits.get_or_insert_with(Vec::new).append(&mut edit);
2153 }
2154 }
2155 edits
2156 };
2157
2158 if let Some(lsp_edits) = lsp_edits {
2159 this.update(cx, |this, cx| {
2160 this.as_local_mut().unwrap().edits_from_lsp(
2161 buffer_handle,
2162 lsp_edits,
2163 language_server.server_id(),
2164 None,
2165 cx,
2166 )
2167 })?
2168 .await
2169 } else {
2170 Ok(Vec::with_capacity(0))
2171 }
2172 }
2173
2174 async fn format_via_lsp(
2175 this: &WeakEntity<LspStore>,
2176 buffer: &Entity<Buffer>,
2177 abs_path: &Path,
2178 language_server: &Arc<LanguageServer>,
2179 settings: &LanguageSettings,
2180 cx: &mut AsyncApp,
2181 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2182 let logger = zlog::scoped!("lsp_format");
2183 zlog::debug!(logger => "Formatting via LSP");
2184
2185 let uri = file_path_to_lsp_url(abs_path)?;
2186 let text_document = lsp::TextDocumentIdentifier::new(uri);
2187 let capabilities = &language_server.capabilities();
2188
2189 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2190 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2191
2192 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2193 let _timer = zlog::time!(logger => "format-full");
2194 language_server
2195 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2196 text_document,
2197 options: lsp_command::lsp_formatting_options(settings),
2198 work_done_progress_params: Default::default(),
2199 })
2200 .await
2201 .into_response()?
2202 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2203 let _timer = zlog::time!(logger => "format-range");
2204 let buffer_start = lsp::Position::new(0, 0);
2205 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2206 language_server
2207 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2208 text_document: text_document.clone(),
2209 range: lsp::Range::new(buffer_start, buffer_end),
2210 options: lsp_command::lsp_formatting_options(settings),
2211 work_done_progress_params: Default::default(),
2212 })
2213 .await
2214 .into_response()?
2215 } else {
2216 None
2217 };
2218
2219 if let Some(lsp_edits) = lsp_edits {
2220 this.update(cx, |this, cx| {
2221 this.as_local_mut().unwrap().edits_from_lsp(
2222 buffer,
2223 lsp_edits,
2224 language_server.server_id(),
2225 None,
2226 cx,
2227 )
2228 })?
2229 .await
2230 } else {
2231 Ok(Vec::with_capacity(0))
2232 }
2233 }
2234
2235 async fn format_via_external_command(
2236 buffer: &FormattableBuffer,
2237 command: &str,
2238 arguments: Option<&[String]>,
2239 cx: &mut AsyncApp,
2240 ) -> Result<Option<Diff>> {
2241 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2242 let file = File::from_dyn(buffer.file())?;
2243 let worktree = file.worktree.read(cx);
2244 let mut worktree_path = worktree.abs_path().to_path_buf();
2245 if worktree.root_entry()?.is_file() {
2246 worktree_path.pop();
2247 }
2248 Some(worktree_path)
2249 });
2250
2251 let mut child = util::command::new_smol_command(command);
2252
2253 if let Some(buffer_env) = buffer.env.as_ref() {
2254 child.envs(buffer_env);
2255 }
2256
2257 if let Some(working_dir_path) = working_dir_path {
2258 child.current_dir(working_dir_path);
2259 }
2260
2261 if let Some(arguments) = arguments {
2262 child.args(arguments.iter().map(|arg| {
2263 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2264 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2265 } else {
2266 arg.replace("{buffer_path}", "Untitled")
2267 }
2268 }));
2269 }
2270
2271 let mut child = child
2272 .stdin(smol::process::Stdio::piped())
2273 .stdout(smol::process::Stdio::piped())
2274 .stderr(smol::process::Stdio::piped())
2275 .spawn()?;
2276
2277 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2278 let text = buffer
2279 .handle
2280 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2281 for chunk in text.chunks() {
2282 stdin.write_all(chunk.as_bytes()).await?;
2283 }
2284 stdin.flush().await?;
2285
2286 let output = child.output().await?;
2287 anyhow::ensure!(
2288 output.status.success(),
2289 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2290 output.status.code(),
2291 String::from_utf8_lossy(&output.stdout),
2292 String::from_utf8_lossy(&output.stderr),
2293 );
2294
2295 let stdout = String::from_utf8(output.stdout)?;
2296 Ok(Some(
2297 buffer
2298 .handle
2299 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2300 .await,
2301 ))
2302 }
2303
2304 async fn try_resolve_code_action(
2305 lang_server: &LanguageServer,
2306 action: &mut CodeAction,
2307 ) -> anyhow::Result<()> {
2308 match &mut action.lsp_action {
2309 LspAction::Action(lsp_action) => {
2310 if !action.resolved
2311 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2312 && lsp_action.data.is_some()
2313 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2314 {
2315 **lsp_action = lang_server
2316 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2317 .await
2318 .into_response()?;
2319 }
2320 }
2321 LspAction::CodeLens(lens) => {
2322 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2323 *lens = lang_server
2324 .request::<lsp::request::CodeLensResolve>(lens.clone())
2325 .await
2326 .into_response()?;
2327 }
2328 }
2329 LspAction::Command(_) => {}
2330 }
2331
2332 action.resolved = true;
2333 anyhow::Ok(())
2334 }
2335
2336 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2337 let buffer = buffer_handle.read(cx);
2338
2339 let file = buffer.file().cloned();
2340
2341 let Some(file) = File::from_dyn(file.as_ref()) else {
2342 return;
2343 };
2344 if !file.is_local() {
2345 return;
2346 }
2347 let path = ProjectPath::from_file(file, cx);
2348 let worktree_id = file.worktree_id(cx);
2349 let language = buffer.language().cloned();
2350
2351 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2352 for (server_id, diagnostics) in
2353 diagnostics.get(file.path()).cloned().unwrap_or_default()
2354 {
2355 self.update_buffer_diagnostics(
2356 buffer_handle,
2357 server_id,
2358 None,
2359 None,
2360 None,
2361 Vec::new(),
2362 diagnostics,
2363 cx,
2364 )
2365 .log_err();
2366 }
2367 }
2368 let Some(language) = language else {
2369 return;
2370 };
2371 let Some(snapshot) = self
2372 .worktree_store
2373 .read(cx)
2374 .worktree_for_id(worktree_id, cx)
2375 .map(|worktree| worktree.read(cx).snapshot())
2376 else {
2377 return;
2378 };
2379 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2380
2381 for server_id in
2382 self.lsp_tree
2383 .get(path, language.name(), language.manifest(), &delegate, cx)
2384 {
2385 let server = self
2386 .language_servers
2387 .get(&server_id)
2388 .and_then(|server_state| {
2389 if let LanguageServerState::Running { server, .. } = server_state {
2390 Some(server.clone())
2391 } else {
2392 None
2393 }
2394 });
2395 let server = match server {
2396 Some(server) => server,
2397 None => continue,
2398 };
2399
2400 buffer_handle.update(cx, |buffer, cx| {
2401 buffer.set_completion_triggers(
2402 server.server_id(),
2403 server
2404 .capabilities()
2405 .completion_provider
2406 .as_ref()
2407 .and_then(|provider| {
2408 provider
2409 .trigger_characters
2410 .as_ref()
2411 .map(|characters| characters.iter().cloned().collect())
2412 })
2413 .unwrap_or_default(),
2414 cx,
2415 );
2416 });
2417 }
2418 }
2419
2420 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2421 buffer.update(cx, |buffer, cx| {
2422 let Some(language) = buffer.language() else {
2423 return;
2424 };
2425 let path = ProjectPath {
2426 worktree_id: old_file.worktree_id(cx),
2427 path: old_file.path.clone(),
2428 };
2429 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2430 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2431 buffer.set_completion_triggers(server_id, Default::default(), cx);
2432 }
2433 });
2434 }
2435
2436 fn update_buffer_diagnostics(
2437 &mut self,
2438 buffer: &Entity<Buffer>,
2439 server_id: LanguageServerId,
2440 registration_id: Option<Option<SharedString>>,
2441 result_id: Option<SharedString>,
2442 version: Option<i32>,
2443 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2444 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2445 cx: &mut Context<LspStore>,
2446 ) -> Result<()> {
2447 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2448 Ordering::Equal
2449 .then_with(|| b.is_primary.cmp(&a.is_primary))
2450 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2451 .then_with(|| a.severity.cmp(&b.severity))
2452 .then_with(|| a.message.cmp(&b.message))
2453 }
2454
2455 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2456 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2457 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2458
2459 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2460 Ordering::Equal
2461 .then_with(|| a.range.start.cmp(&b.range.start))
2462 .then_with(|| b.range.end.cmp(&a.range.end))
2463 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2464 });
2465
2466 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2467
2468 let edits_since_save = std::cell::LazyCell::new(|| {
2469 let saved_version = buffer.read(cx).saved_version();
2470 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2471 });
2472
2473 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2474
2475 for (new_diagnostic, entry) in diagnostics {
2476 let start;
2477 let end;
2478 if entry.diagnostic.is_disk_based {
2479 if !new_diagnostic {
2480 continue;
2481 }
2482 // Some diagnostics are based on files on disk instead of buffers'
2483 // current contents. Adjust these diagnostics' ranges to reflect
2484 // any unsaved edits.
2485 // Do not alter the reused ones though, as their coordinates were stored as anchors
2486 // and were properly adjusted on reuse.
2487 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2488 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2489 } else {
2490 start = entry.range.start;
2491 end = entry.range.end;
2492 }
2493
2494 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2495 ..snapshot.clip_point_utf16(end, Bias::Right);
2496
2497 // Expand empty ranges by one codepoint
2498 if range.start == range.end {
2499 // This will be go to the next boundary when being clipped
2500 range.end.column += 1;
2501 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2502 if range.start == range.end && range.end.column > 0 {
2503 range.start.column -= 1;
2504 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2505 }
2506 }
2507
2508 sanitized_diagnostics.push(DiagnosticEntry {
2509 range,
2510 diagnostic: entry.diagnostic,
2511 });
2512 }
2513 drop(edits_since_save);
2514
2515 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2516 buffer.update(cx, |buffer, cx| {
2517 if let Some(registration_id) = registration_id {
2518 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2519 self.buffer_pull_diagnostics_result_ids
2520 .entry(server_id)
2521 .or_default()
2522 .entry(registration_id)
2523 .or_default()
2524 .insert(abs_path, result_id);
2525 }
2526 }
2527
2528 buffer.update_diagnostics(server_id, set, cx)
2529 });
2530
2531 Ok(())
2532 }
2533
2534 fn register_language_server_for_invisible_worktree(
2535 &mut self,
2536 worktree: &Entity<Worktree>,
2537 language_server_id: LanguageServerId,
2538 cx: &mut App,
2539 ) {
2540 let worktree = worktree.read(cx);
2541 let worktree_id = worktree.id();
2542 debug_assert!(!worktree.is_visible());
2543 let Some(mut origin_seed) = self
2544 .language_server_ids
2545 .iter()
2546 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2547 else {
2548 return;
2549 };
2550 origin_seed.worktree_id = worktree_id;
2551 self.language_server_ids
2552 .entry(origin_seed)
2553 .or_insert_with(|| UnifiedLanguageServer {
2554 id: language_server_id,
2555 project_roots: Default::default(),
2556 });
2557 }
2558
2559 fn register_buffer_with_language_servers(
2560 &mut self,
2561 buffer_handle: &Entity<Buffer>,
2562 only_register_servers: HashSet<LanguageServerSelector>,
2563 cx: &mut Context<LspStore>,
2564 ) {
2565 let buffer = buffer_handle.read(cx);
2566 let buffer_id = buffer.remote_id();
2567
2568 let Some(file) = File::from_dyn(buffer.file()) else {
2569 return;
2570 };
2571 if !file.is_local() {
2572 return;
2573 }
2574
2575 let abs_path = file.abs_path(cx);
2576 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2577 return;
2578 };
2579 let initial_snapshot = buffer.text_snapshot();
2580 let worktree_id = file.worktree_id(cx);
2581
2582 let Some(language) = buffer.language().cloned() else {
2583 return;
2584 };
2585 let path: Arc<RelPath> = file
2586 .path()
2587 .parent()
2588 .map(Arc::from)
2589 .unwrap_or_else(|| file.path().clone());
2590 let Some(worktree) = self
2591 .worktree_store
2592 .read(cx)
2593 .worktree_for_id(worktree_id, cx)
2594 else {
2595 return;
2596 };
2597 let language_name = language.name();
2598 let (reused, delegate, servers) = self
2599 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2600 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2601 .unwrap_or_else(|| {
2602 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2603 let delegate: Arc<dyn ManifestDelegate> =
2604 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2605
2606 let servers = self
2607 .lsp_tree
2608 .walk(
2609 ProjectPath { worktree_id, path },
2610 language.name(),
2611 language.manifest(),
2612 &delegate,
2613 cx,
2614 )
2615 .collect::<Vec<_>>();
2616 (false, lsp_delegate, servers)
2617 });
2618 let servers_and_adapters = servers
2619 .into_iter()
2620 .filter_map(|server_node| {
2621 if reused && server_node.server_id().is_none() {
2622 return None;
2623 }
2624 if !only_register_servers.is_empty() {
2625 if let Some(server_id) = server_node.server_id()
2626 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2627 {
2628 return None;
2629 }
2630 if let Some(name) = server_node.name()
2631 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2632 {
2633 return None;
2634 }
2635 }
2636
2637 let server_id = server_node.server_id_or_init(|disposition| {
2638 let path = &disposition.path;
2639
2640 {
2641 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2642
2643 let server_id = self.get_or_insert_language_server(
2644 &worktree,
2645 delegate.clone(),
2646 disposition,
2647 &language_name,
2648 cx,
2649 );
2650
2651 if let Some(state) = self.language_servers.get(&server_id)
2652 && let Ok(uri) = uri
2653 {
2654 state.add_workspace_folder(uri);
2655 };
2656 server_id
2657 }
2658 })?;
2659 let server_state = self.language_servers.get(&server_id)?;
2660 if let LanguageServerState::Running {
2661 server, adapter, ..
2662 } = server_state
2663 {
2664 Some((server.clone(), adapter.clone()))
2665 } else {
2666 None
2667 }
2668 })
2669 .collect::<Vec<_>>();
2670 for (server, adapter) in servers_and_adapters {
2671 buffer_handle.update(cx, |buffer, cx| {
2672 buffer.set_completion_triggers(
2673 server.server_id(),
2674 server
2675 .capabilities()
2676 .completion_provider
2677 .as_ref()
2678 .and_then(|provider| {
2679 provider
2680 .trigger_characters
2681 .as_ref()
2682 .map(|characters| characters.iter().cloned().collect())
2683 })
2684 .unwrap_or_default(),
2685 cx,
2686 );
2687 });
2688
2689 let snapshot = LspBufferSnapshot {
2690 version: 0,
2691 snapshot: initial_snapshot.clone(),
2692 };
2693
2694 let mut registered = false;
2695 self.buffer_snapshots
2696 .entry(buffer_id)
2697 .or_default()
2698 .entry(server.server_id())
2699 .or_insert_with(|| {
2700 registered = true;
2701 server.register_buffer(
2702 uri.clone(),
2703 adapter.language_id(&language.name()),
2704 0,
2705 initial_snapshot.text(),
2706 );
2707
2708 vec![snapshot]
2709 });
2710
2711 self.buffers_opened_in_servers
2712 .entry(buffer_id)
2713 .or_default()
2714 .insert(server.server_id());
2715 if registered {
2716 cx.emit(LspStoreEvent::LanguageServerUpdate {
2717 language_server_id: server.server_id(),
2718 name: None,
2719 message: proto::update_language_server::Variant::RegisteredForBuffer(
2720 proto::RegisteredForBuffer {
2721 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2722 buffer_id: buffer_id.to_proto(),
2723 },
2724 ),
2725 });
2726 }
2727 }
2728 }
2729
2730 fn reuse_existing_language_server<'lang_name>(
2731 &self,
2732 server_tree: &LanguageServerTree,
2733 worktree: &Entity<Worktree>,
2734 language_name: &'lang_name LanguageName,
2735 cx: &mut App,
2736 ) -> Option<(
2737 Arc<LocalLspAdapterDelegate>,
2738 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2739 )> {
2740 if worktree.read(cx).is_visible() {
2741 return None;
2742 }
2743
2744 let worktree_store = self.worktree_store.read(cx);
2745 let servers = server_tree
2746 .instances
2747 .iter()
2748 .filter(|(worktree_id, _)| {
2749 worktree_store
2750 .worktree_for_id(**worktree_id, cx)
2751 .is_some_and(|worktree| worktree.read(cx).is_visible())
2752 })
2753 .flat_map(|(worktree_id, servers)| {
2754 servers
2755 .roots
2756 .iter()
2757 .flat_map(|(_, language_servers)| language_servers)
2758 .map(move |(_, (server_node, server_languages))| {
2759 (worktree_id, server_node, server_languages)
2760 })
2761 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2762 .map(|(worktree_id, server_node, _)| {
2763 (
2764 *worktree_id,
2765 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2766 )
2767 })
2768 })
2769 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2770 acc.entry(worktree_id)
2771 .or_insert_with(Vec::new)
2772 .push(server_node);
2773 acc
2774 })
2775 .into_values()
2776 .max_by_key(|servers| servers.len())?;
2777
2778 let worktree_id = worktree.read(cx).id();
2779 let apply = move |tree: &mut LanguageServerTree| {
2780 for server_node in &servers {
2781 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2782 }
2783 servers
2784 };
2785
2786 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2787 Some((delegate, apply))
2788 }
2789
2790 pub(crate) fn unregister_old_buffer_from_language_servers(
2791 &mut self,
2792 buffer: &Entity<Buffer>,
2793 old_file: &File,
2794 cx: &mut App,
2795 ) {
2796 let old_path = match old_file.as_local() {
2797 Some(local) => local.abs_path(cx),
2798 None => return,
2799 };
2800
2801 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2802 debug_panic!("{old_path:?} is not parseable as an URI");
2803 return;
2804 };
2805 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2806 }
2807
2808 pub(crate) fn unregister_buffer_from_language_servers(
2809 &mut self,
2810 buffer: &Entity<Buffer>,
2811 file_url: &lsp::Uri,
2812 cx: &mut App,
2813 ) {
2814 buffer.update(cx, |buffer, cx| {
2815 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2816
2817 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2818 if snapshots
2819 .as_mut()
2820 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2821 {
2822 language_server.unregister_buffer(file_url.clone());
2823 }
2824 }
2825 });
2826 }
2827
2828 fn buffer_snapshot_for_lsp_version(
2829 &mut self,
2830 buffer: &Entity<Buffer>,
2831 server_id: LanguageServerId,
2832 version: Option<i32>,
2833 cx: &App,
2834 ) -> Result<TextBufferSnapshot> {
2835 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2836
2837 if let Some(version) = version {
2838 let buffer_id = buffer.read(cx).remote_id();
2839 let snapshots = if let Some(snapshots) = self
2840 .buffer_snapshots
2841 .get_mut(&buffer_id)
2842 .and_then(|m| m.get_mut(&server_id))
2843 {
2844 snapshots
2845 } else if version == 0 {
2846 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2847 // We detect this case and treat it as if the version was `None`.
2848 return Ok(buffer.read(cx).text_snapshot());
2849 } else {
2850 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2851 };
2852
2853 let found_snapshot = snapshots
2854 .binary_search_by_key(&version, |e| e.version)
2855 .map(|ix| snapshots[ix].snapshot.clone())
2856 .map_err(|_| {
2857 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2858 })?;
2859
2860 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2861 Ok(found_snapshot)
2862 } else {
2863 Ok((buffer.read(cx)).text_snapshot())
2864 }
2865 }
2866
2867 async fn get_server_code_actions_from_action_kinds(
2868 lsp_store: &WeakEntity<LspStore>,
2869 language_server_id: LanguageServerId,
2870 code_action_kinds: Vec<lsp::CodeActionKind>,
2871 buffer: &Entity<Buffer>,
2872 cx: &mut AsyncApp,
2873 ) -> Result<Vec<CodeAction>> {
2874 let actions = lsp_store
2875 .update(cx, move |this, cx| {
2876 let request = GetCodeActions {
2877 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2878 kinds: Some(code_action_kinds),
2879 };
2880 let server = LanguageServerToQuery::Other(language_server_id);
2881 this.request_lsp(buffer.clone(), server, request, cx)
2882 })?
2883 .await?;
2884 Ok(actions)
2885 }
2886
2887 pub async fn execute_code_actions_on_server(
2888 lsp_store: &WeakEntity<LspStore>,
2889 language_server: &Arc<LanguageServer>,
2890
2891 actions: Vec<CodeAction>,
2892 push_to_history: bool,
2893 project_transaction: &mut ProjectTransaction,
2894 cx: &mut AsyncApp,
2895 ) -> anyhow::Result<()> {
2896 for mut action in actions {
2897 Self::try_resolve_code_action(language_server, &mut action)
2898 .await
2899 .context("resolving a formatting code action")?;
2900
2901 if let Some(edit) = action.lsp_action.edit() {
2902 if edit.changes.is_none() && edit.document_changes.is_none() {
2903 continue;
2904 }
2905
2906 let new = Self::deserialize_workspace_edit(
2907 lsp_store.upgrade().context("project dropped")?,
2908 edit.clone(),
2909 push_to_history,
2910 language_server.clone(),
2911 cx,
2912 )
2913 .await?;
2914 project_transaction.0.extend(new.0);
2915 }
2916
2917 if let Some(command) = action.lsp_action.command() {
2918 let server_capabilities = language_server.capabilities();
2919 let available_commands = server_capabilities
2920 .execute_command_provider
2921 .as_ref()
2922 .map(|options| options.commands.as_slice())
2923 .unwrap_or_default();
2924 if available_commands.contains(&command.command) {
2925 lsp_store.update(cx, |lsp_store, _| {
2926 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2927 mode.last_workspace_edits_by_language_server
2928 .remove(&language_server.server_id());
2929 }
2930 })?;
2931
2932 language_server
2933 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2934 command: command.command.clone(),
2935 arguments: command.arguments.clone().unwrap_or_default(),
2936 ..Default::default()
2937 })
2938 .await
2939 .into_response()
2940 .context("execute command")?;
2941
2942 lsp_store.update(cx, |this, _| {
2943 if let LspStoreMode::Local(mode) = &mut this.mode {
2944 project_transaction.0.extend(
2945 mode.last_workspace_edits_by_language_server
2946 .remove(&language_server.server_id())
2947 .unwrap_or_default()
2948 .0,
2949 )
2950 }
2951 })?;
2952 } else {
2953 log::warn!(
2954 "Cannot execute a command {} not listed in the language server capabilities",
2955 command.command
2956 )
2957 }
2958 }
2959 }
2960 Ok(())
2961 }
2962
2963 pub async fn deserialize_text_edits(
2964 this: Entity<LspStore>,
2965 buffer_to_edit: Entity<Buffer>,
2966 edits: Vec<lsp::TextEdit>,
2967 push_to_history: bool,
2968 _: Arc<CachedLspAdapter>,
2969 language_server: Arc<LanguageServer>,
2970 cx: &mut AsyncApp,
2971 ) -> Result<Option<Transaction>> {
2972 let edits = this
2973 .update(cx, |this, cx| {
2974 this.as_local_mut().unwrap().edits_from_lsp(
2975 &buffer_to_edit,
2976 edits,
2977 language_server.server_id(),
2978 None,
2979 cx,
2980 )
2981 })
2982 .await?;
2983
2984 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2985 buffer.finalize_last_transaction();
2986 buffer.start_transaction();
2987 for (range, text) in edits {
2988 buffer.edit([(range, text)], None, cx);
2989 }
2990
2991 if buffer.end_transaction(cx).is_some() {
2992 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2993 if !push_to_history {
2994 buffer.forget_transaction(transaction.id);
2995 }
2996 Some(transaction)
2997 } else {
2998 None
2999 }
3000 });
3001
3002 Ok(transaction)
3003 }
3004
3005 #[allow(clippy::type_complexity)]
3006 pub(crate) fn edits_from_lsp(
3007 &mut self,
3008 buffer: &Entity<Buffer>,
3009 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3010 server_id: LanguageServerId,
3011 version: Option<i32>,
3012 cx: &mut Context<LspStore>,
3013 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3014 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3015 cx.background_spawn(async move {
3016 let snapshot = snapshot?;
3017 let mut lsp_edits = lsp_edits
3018 .into_iter()
3019 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3020 .collect::<Vec<_>>();
3021
3022 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3023
3024 let mut lsp_edits = lsp_edits.into_iter().peekable();
3025 let mut edits = Vec::new();
3026 while let Some((range, mut new_text)) = lsp_edits.next() {
3027 // Clip invalid ranges provided by the language server.
3028 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3029 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3030
3031 // Combine any LSP edits that are adjacent.
3032 //
3033 // Also, combine LSP edits that are separated from each other by only
3034 // a newline. This is important because for some code actions,
3035 // Rust-analyzer rewrites the entire buffer via a series of edits that
3036 // are separated by unchanged newline characters.
3037 //
3038 // In order for the diffing logic below to work properly, any edits that
3039 // cancel each other out must be combined into one.
3040 while let Some((next_range, next_text)) = lsp_edits.peek() {
3041 if next_range.start.0 > range.end {
3042 if next_range.start.0.row > range.end.row + 1
3043 || next_range.start.0.column > 0
3044 || snapshot.clip_point_utf16(
3045 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3046 Bias::Left,
3047 ) > range.end
3048 {
3049 break;
3050 }
3051 new_text.push('\n');
3052 }
3053 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3054 new_text.push_str(next_text);
3055 lsp_edits.next();
3056 }
3057
3058 // For multiline edits, perform a diff of the old and new text so that
3059 // we can identify the changes more precisely, preserving the locations
3060 // of any anchors positioned in the unchanged regions.
3061 if range.end.row > range.start.row {
3062 let offset = range.start.to_offset(&snapshot);
3063 let old_text = snapshot.text_for_range(range).collect::<String>();
3064 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3065 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3066 (
3067 snapshot.anchor_after(offset + range.start)
3068 ..snapshot.anchor_before(offset + range.end),
3069 replacement,
3070 )
3071 }));
3072 } else if range.end == range.start {
3073 let anchor = snapshot.anchor_after(range.start);
3074 edits.push((anchor..anchor, new_text.into()));
3075 } else {
3076 let edit_start = snapshot.anchor_after(range.start);
3077 let edit_end = snapshot.anchor_before(range.end);
3078 edits.push((edit_start..edit_end, new_text.into()));
3079 }
3080 }
3081
3082 Ok(edits)
3083 })
3084 }
3085
3086 pub(crate) async fn deserialize_workspace_edit(
3087 this: Entity<LspStore>,
3088 edit: lsp::WorkspaceEdit,
3089 push_to_history: bool,
3090 language_server: Arc<LanguageServer>,
3091 cx: &mut AsyncApp,
3092 ) -> Result<ProjectTransaction> {
3093 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3094
3095 let mut operations = Vec::new();
3096 if let Some(document_changes) = edit.document_changes {
3097 match document_changes {
3098 lsp::DocumentChanges::Edits(edits) => {
3099 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3100 }
3101 lsp::DocumentChanges::Operations(ops) => operations = ops,
3102 }
3103 } else if let Some(changes) = edit.changes {
3104 operations.extend(changes.into_iter().map(|(uri, edits)| {
3105 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3106 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3107 uri,
3108 version: None,
3109 },
3110 edits: edits.into_iter().map(Edit::Plain).collect(),
3111 })
3112 }));
3113 }
3114
3115 let mut project_transaction = ProjectTransaction::default();
3116 for operation in operations {
3117 match operation {
3118 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3119 let abs_path = op
3120 .uri
3121 .to_file_path()
3122 .map_err(|()| anyhow!("can't convert URI to path"))?;
3123
3124 if let Some(parent_path) = abs_path.parent() {
3125 fs.create_dir(parent_path).await?;
3126 }
3127 if abs_path.ends_with("/") {
3128 fs.create_dir(&abs_path).await?;
3129 } else {
3130 fs.create_file(
3131 &abs_path,
3132 op.options
3133 .map(|options| fs::CreateOptions {
3134 overwrite: options.overwrite.unwrap_or(false),
3135 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3136 })
3137 .unwrap_or_default(),
3138 )
3139 .await?;
3140 }
3141 }
3142
3143 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3144 let source_abs_path = op
3145 .old_uri
3146 .to_file_path()
3147 .map_err(|()| anyhow!("can't convert URI to path"))?;
3148 let target_abs_path = op
3149 .new_uri
3150 .to_file_path()
3151 .map_err(|()| anyhow!("can't convert URI to path"))?;
3152
3153 let options = fs::RenameOptions {
3154 overwrite: op
3155 .options
3156 .as_ref()
3157 .and_then(|options| options.overwrite)
3158 .unwrap_or(false),
3159 ignore_if_exists: op
3160 .options
3161 .as_ref()
3162 .and_then(|options| options.ignore_if_exists)
3163 .unwrap_or(false),
3164 create_parents: true,
3165 };
3166
3167 fs.rename(&source_abs_path, &target_abs_path, options)
3168 .await?;
3169 }
3170
3171 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3172 let abs_path = op
3173 .uri
3174 .to_file_path()
3175 .map_err(|()| anyhow!("can't convert URI to path"))?;
3176 let options = op
3177 .options
3178 .map(|options| fs::RemoveOptions {
3179 recursive: options.recursive.unwrap_or(false),
3180 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3181 })
3182 .unwrap_or_default();
3183 if abs_path.ends_with("/") {
3184 fs.remove_dir(&abs_path, options).await?;
3185 } else {
3186 fs.remove_file(&abs_path, options).await?;
3187 }
3188 }
3189
3190 lsp::DocumentChangeOperation::Edit(op) => {
3191 let buffer_to_edit = this
3192 .update(cx, |this, cx| {
3193 this.open_local_buffer_via_lsp(
3194 op.text_document.uri.clone(),
3195 language_server.server_id(),
3196 cx,
3197 )
3198 })
3199 .await?;
3200
3201 let edits = this
3202 .update(cx, |this, cx| {
3203 let path = buffer_to_edit.read(cx).project_path(cx);
3204 let active_entry = this.active_entry;
3205 let is_active_entry = path.is_some_and(|project_path| {
3206 this.worktree_store
3207 .read(cx)
3208 .entry_for_path(&project_path, cx)
3209 .is_some_and(|entry| Some(entry.id) == active_entry)
3210 });
3211 let local = this.as_local_mut().unwrap();
3212
3213 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3214 for edit in op.edits {
3215 match edit {
3216 Edit::Plain(edit) => {
3217 if !edits.contains(&edit) {
3218 edits.push(edit)
3219 }
3220 }
3221 Edit::Annotated(edit) => {
3222 if !edits.contains(&edit.text_edit) {
3223 edits.push(edit.text_edit)
3224 }
3225 }
3226 Edit::Snippet(edit) => {
3227 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3228 else {
3229 continue;
3230 };
3231
3232 if is_active_entry {
3233 snippet_edits.push((edit.range, snippet));
3234 } else {
3235 // Since this buffer is not focused, apply a normal edit.
3236 let new_edit = TextEdit {
3237 range: edit.range,
3238 new_text: snippet.text,
3239 };
3240 if !edits.contains(&new_edit) {
3241 edits.push(new_edit);
3242 }
3243 }
3244 }
3245 }
3246 }
3247 if !snippet_edits.is_empty() {
3248 let buffer_id = buffer_to_edit.read(cx).remote_id();
3249 let version = if let Some(buffer_version) = op.text_document.version
3250 {
3251 local
3252 .buffer_snapshot_for_lsp_version(
3253 &buffer_to_edit,
3254 language_server.server_id(),
3255 Some(buffer_version),
3256 cx,
3257 )
3258 .ok()
3259 .map(|snapshot| snapshot.version)
3260 } else {
3261 Some(buffer_to_edit.read(cx).saved_version().clone())
3262 };
3263
3264 let most_recent_edit =
3265 version.and_then(|version| version.most_recent());
3266 // Check if the edit that triggered that edit has been made by this participant.
3267
3268 if let Some(most_recent_edit) = most_recent_edit {
3269 cx.emit(LspStoreEvent::SnippetEdit {
3270 buffer_id,
3271 edits: snippet_edits,
3272 most_recent_edit,
3273 });
3274 }
3275 }
3276
3277 local.edits_from_lsp(
3278 &buffer_to_edit,
3279 edits,
3280 language_server.server_id(),
3281 op.text_document.version,
3282 cx,
3283 )
3284 })
3285 .await?;
3286
3287 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3288 buffer.finalize_last_transaction();
3289 buffer.start_transaction();
3290 for (range, text) in edits {
3291 buffer.edit([(range, text)], None, cx);
3292 }
3293
3294 buffer.end_transaction(cx).and_then(|transaction_id| {
3295 if push_to_history {
3296 buffer.finalize_last_transaction();
3297 buffer.get_transaction(transaction_id).cloned()
3298 } else {
3299 buffer.forget_transaction(transaction_id)
3300 }
3301 })
3302 });
3303 if let Some(transaction) = transaction {
3304 project_transaction.0.insert(buffer_to_edit, transaction);
3305 }
3306 }
3307 }
3308 }
3309
3310 Ok(project_transaction)
3311 }
3312
3313 async fn on_lsp_workspace_edit(
3314 this: WeakEntity<LspStore>,
3315 params: lsp::ApplyWorkspaceEditParams,
3316 server_id: LanguageServerId,
3317 cx: &mut AsyncApp,
3318 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3319 let this = this.upgrade().context("project project closed")?;
3320 let language_server = this
3321 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3322 .context("language server not found")?;
3323 let transaction = Self::deserialize_workspace_edit(
3324 this.clone(),
3325 params.edit,
3326 true,
3327 language_server.clone(),
3328 cx,
3329 )
3330 .await
3331 .log_err();
3332 this.update(cx, |this, cx| {
3333 if let Some(transaction) = transaction {
3334 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3335
3336 this.as_local_mut()
3337 .unwrap()
3338 .last_workspace_edits_by_language_server
3339 .insert(server_id, transaction);
3340 }
3341 });
3342 Ok(lsp::ApplyWorkspaceEditResponse {
3343 applied: true,
3344 failed_change: None,
3345 failure_reason: None,
3346 })
3347 }
3348
3349 fn remove_worktree(
3350 &mut self,
3351 id_to_remove: WorktreeId,
3352 cx: &mut Context<LspStore>,
3353 ) -> Vec<LanguageServerId> {
3354 self.restricted_worktrees_tasks.remove(&id_to_remove);
3355 self.diagnostics.remove(&id_to_remove);
3356 self.prettier_store.update(cx, |prettier_store, cx| {
3357 prettier_store.remove_worktree(id_to_remove, cx);
3358 });
3359
3360 let mut servers_to_remove = BTreeSet::default();
3361 let mut servers_to_preserve = HashSet::default();
3362 for (seed, state) in &self.language_server_ids {
3363 if seed.worktree_id == id_to_remove {
3364 servers_to_remove.insert(state.id);
3365 } else {
3366 servers_to_preserve.insert(state.id);
3367 }
3368 }
3369 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3370 self.language_server_ids
3371 .retain(|_, state| !servers_to_remove.contains(&state.id));
3372 for server_id_to_remove in &servers_to_remove {
3373 self.language_server_watched_paths
3374 .remove(server_id_to_remove);
3375 self.language_server_paths_watched_for_rename
3376 .remove(server_id_to_remove);
3377 self.last_workspace_edits_by_language_server
3378 .remove(server_id_to_remove);
3379 self.language_servers.remove(server_id_to_remove);
3380 self.buffer_pull_diagnostics_result_ids
3381 .remove(server_id_to_remove);
3382 self.workspace_pull_diagnostics_result_ids
3383 .remove(server_id_to_remove);
3384 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3385 buffer_servers.remove(server_id_to_remove);
3386 }
3387 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3388 }
3389 servers_to_remove.into_iter().collect()
3390 }
3391
3392 fn rebuild_watched_paths_inner<'a>(
3393 &'a self,
3394 language_server_id: LanguageServerId,
3395 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3396 cx: &mut Context<LspStore>,
3397 ) -> LanguageServerWatchedPathsBuilder {
3398 let worktrees = self
3399 .worktree_store
3400 .read(cx)
3401 .worktrees()
3402 .filter_map(|worktree| {
3403 self.language_servers_for_worktree(worktree.read(cx).id())
3404 .find(|server| server.server_id() == language_server_id)
3405 .map(|_| worktree)
3406 })
3407 .collect::<Vec<_>>();
3408
3409 let mut worktree_globs = HashMap::default();
3410 let mut abs_globs = HashMap::default();
3411 log::trace!(
3412 "Processing new watcher paths for language server with id {}",
3413 language_server_id
3414 );
3415
3416 for watcher in watchers {
3417 if let Some((worktree, literal_prefix, pattern)) =
3418 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3419 {
3420 worktree.update(cx, |worktree, _| {
3421 if let Some((tree, glob)) =
3422 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3423 {
3424 tree.add_path_prefix_to_scan(literal_prefix);
3425 worktree_globs
3426 .entry(tree.id())
3427 .or_insert_with(GlobSetBuilder::new)
3428 .add(glob);
3429 }
3430 });
3431 } else {
3432 let (path, pattern) = match &watcher.glob_pattern {
3433 lsp::GlobPattern::String(s) => {
3434 let watcher_path = SanitizedPath::new(s);
3435 let path = glob_literal_prefix(watcher_path.as_path());
3436 let pattern = watcher_path
3437 .as_path()
3438 .strip_prefix(&path)
3439 .map(|p| p.to_string_lossy().into_owned())
3440 .unwrap_or_else(|e| {
3441 debug_panic!(
3442 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3443 s,
3444 path.display(),
3445 e
3446 );
3447 watcher_path.as_path().to_string_lossy().into_owned()
3448 });
3449 (path, pattern)
3450 }
3451 lsp::GlobPattern::Relative(rp) => {
3452 let Ok(mut base_uri) = match &rp.base_uri {
3453 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3454 lsp::OneOf::Right(base_uri) => base_uri,
3455 }
3456 .to_file_path() else {
3457 continue;
3458 };
3459
3460 let path = glob_literal_prefix(Path::new(&rp.pattern));
3461 let pattern = Path::new(&rp.pattern)
3462 .strip_prefix(&path)
3463 .map(|p| p.to_string_lossy().into_owned())
3464 .unwrap_or_else(|e| {
3465 debug_panic!(
3466 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3467 rp.pattern,
3468 path.display(),
3469 e
3470 );
3471 rp.pattern.clone()
3472 });
3473 base_uri.push(path);
3474 (base_uri, pattern)
3475 }
3476 };
3477
3478 if let Some(glob) = Glob::new(&pattern).log_err() {
3479 if !path
3480 .components()
3481 .any(|c| matches!(c, path::Component::Normal(_)))
3482 {
3483 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3484 // rather than adding a new watcher for `/`.
3485 for worktree in &worktrees {
3486 worktree_globs
3487 .entry(worktree.read(cx).id())
3488 .or_insert_with(GlobSetBuilder::new)
3489 .add(glob.clone());
3490 }
3491 } else {
3492 abs_globs
3493 .entry(path.into())
3494 .or_insert_with(GlobSetBuilder::new)
3495 .add(glob);
3496 }
3497 }
3498 }
3499 }
3500
3501 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3502 for (worktree_id, builder) in worktree_globs {
3503 if let Ok(globset) = builder.build() {
3504 watch_builder.watch_worktree(worktree_id, globset);
3505 }
3506 }
3507 for (abs_path, builder) in abs_globs {
3508 if let Ok(globset) = builder.build() {
3509 watch_builder.watch_abs_path(abs_path, globset);
3510 }
3511 }
3512 watch_builder
3513 }
3514
3515 fn worktree_and_path_for_file_watcher(
3516 worktrees: &[Entity<Worktree>],
3517 watcher: &FileSystemWatcher,
3518 cx: &App,
3519 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3520 worktrees.iter().find_map(|worktree| {
3521 let tree = worktree.read(cx);
3522 let worktree_root_path = tree.abs_path();
3523 let path_style = tree.path_style();
3524 match &watcher.glob_pattern {
3525 lsp::GlobPattern::String(s) => {
3526 let watcher_path = SanitizedPath::new(s);
3527 let relative = watcher_path
3528 .as_path()
3529 .strip_prefix(&worktree_root_path)
3530 .ok()?;
3531 let literal_prefix = glob_literal_prefix(relative);
3532 Some((
3533 worktree.clone(),
3534 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3535 relative.to_string_lossy().into_owned(),
3536 ))
3537 }
3538 lsp::GlobPattern::Relative(rp) => {
3539 let base_uri = match &rp.base_uri {
3540 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3541 lsp::OneOf::Right(base_uri) => base_uri,
3542 }
3543 .to_file_path()
3544 .ok()?;
3545 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3546 let mut literal_prefix = relative.to_owned();
3547 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3548 Some((
3549 worktree.clone(),
3550 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3551 rp.pattern.clone(),
3552 ))
3553 }
3554 }
3555 })
3556 }
3557
3558 fn rebuild_watched_paths(
3559 &mut self,
3560 language_server_id: LanguageServerId,
3561 cx: &mut Context<LspStore>,
3562 ) {
3563 let Some(registrations) = self
3564 .language_server_dynamic_registrations
3565 .get(&language_server_id)
3566 else {
3567 return;
3568 };
3569
3570 let watch_builder = self.rebuild_watched_paths_inner(
3571 language_server_id,
3572 registrations.did_change_watched_files.values().flatten(),
3573 cx,
3574 );
3575 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3576 self.language_server_watched_paths
3577 .insert(language_server_id, watcher);
3578
3579 cx.notify();
3580 }
3581
3582 fn on_lsp_did_change_watched_files(
3583 &mut self,
3584 language_server_id: LanguageServerId,
3585 registration_id: &str,
3586 params: DidChangeWatchedFilesRegistrationOptions,
3587 cx: &mut Context<LspStore>,
3588 ) {
3589 let registrations = self
3590 .language_server_dynamic_registrations
3591 .entry(language_server_id)
3592 .or_default();
3593
3594 registrations
3595 .did_change_watched_files
3596 .insert(registration_id.to_string(), params.watchers);
3597
3598 self.rebuild_watched_paths(language_server_id, cx);
3599 }
3600
3601 fn on_lsp_unregister_did_change_watched_files(
3602 &mut self,
3603 language_server_id: LanguageServerId,
3604 registration_id: &str,
3605 cx: &mut Context<LspStore>,
3606 ) {
3607 let registrations = self
3608 .language_server_dynamic_registrations
3609 .entry(language_server_id)
3610 .or_default();
3611
3612 if registrations
3613 .did_change_watched_files
3614 .remove(registration_id)
3615 .is_some()
3616 {
3617 log::info!(
3618 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3619 language_server_id,
3620 registration_id
3621 );
3622 } else {
3623 log::warn!(
3624 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3625 language_server_id,
3626 registration_id
3627 );
3628 }
3629
3630 self.rebuild_watched_paths(language_server_id, cx);
3631 }
3632
3633 async fn initialization_options_for_adapter(
3634 adapter: Arc<dyn LspAdapter>,
3635 delegate: &Arc<dyn LspAdapterDelegate>,
3636 ) -> Result<Option<serde_json::Value>> {
3637 let Some(mut initialization_config) =
3638 adapter.clone().initialization_options(delegate).await?
3639 else {
3640 return Ok(None);
3641 };
3642
3643 for other_adapter in delegate.registered_lsp_adapters() {
3644 if other_adapter.name() == adapter.name() {
3645 continue;
3646 }
3647 if let Ok(Some(target_config)) = other_adapter
3648 .clone()
3649 .additional_initialization_options(adapter.name(), delegate)
3650 .await
3651 {
3652 merge_json_value_into(target_config.clone(), &mut initialization_config);
3653 }
3654 }
3655
3656 Ok(Some(initialization_config))
3657 }
3658
3659 async fn workspace_configuration_for_adapter(
3660 adapter: Arc<dyn LspAdapter>,
3661 delegate: &Arc<dyn LspAdapterDelegate>,
3662 toolchain: Option<Toolchain>,
3663 requested_uri: Option<Uri>,
3664 cx: &mut AsyncApp,
3665 ) -> Result<serde_json::Value> {
3666 let mut workspace_config = adapter
3667 .clone()
3668 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3669 .await?;
3670
3671 for other_adapter in delegate.registered_lsp_adapters() {
3672 if other_adapter.name() == adapter.name() {
3673 continue;
3674 }
3675 if let Ok(Some(target_config)) = other_adapter
3676 .clone()
3677 .additional_workspace_configuration(adapter.name(), delegate, cx)
3678 .await
3679 {
3680 merge_json_value_into(target_config.clone(), &mut workspace_config);
3681 }
3682 }
3683
3684 Ok(workspace_config)
3685 }
3686
3687 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3688 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3689 Some(server.clone())
3690 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3691 Some(Arc::clone(server))
3692 } else {
3693 None
3694 }
3695 }
3696}
3697
3698fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3699 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3700 cx.emit(LspStoreEvent::LanguageServerUpdate {
3701 language_server_id: server.server_id(),
3702 name: Some(server.name()),
3703 message: proto::update_language_server::Variant::MetadataUpdated(
3704 proto::ServerMetadataUpdated {
3705 capabilities: Some(capabilities),
3706 binary: Some(proto::LanguageServerBinaryInfo {
3707 path: server.binary().path.to_string_lossy().into_owned(),
3708 arguments: server
3709 .binary()
3710 .arguments
3711 .iter()
3712 .map(|arg| arg.to_string_lossy().into_owned())
3713 .collect(),
3714 }),
3715 configuration: serde_json::to_string(server.configuration()).ok(),
3716 workspace_folders: server
3717 .workspace_folders()
3718 .iter()
3719 .map(|uri| uri.to_string())
3720 .collect(),
3721 },
3722 ),
3723 });
3724 }
3725}
3726
3727#[derive(Debug)]
3728pub struct FormattableBuffer {
3729 handle: Entity<Buffer>,
3730 abs_path: Option<PathBuf>,
3731 env: Option<HashMap<String, String>>,
3732 ranges: Option<Vec<Range<Anchor>>>,
3733}
3734
3735pub struct RemoteLspStore {
3736 upstream_client: Option<AnyProtoClient>,
3737 upstream_project_id: u64,
3738}
3739
3740pub(crate) enum LspStoreMode {
3741 Local(LocalLspStore), // ssh host and collab host
3742 Remote(RemoteLspStore), // collab guest
3743}
3744
3745impl LspStoreMode {
3746 fn is_local(&self) -> bool {
3747 matches!(self, LspStoreMode::Local(_))
3748 }
3749}
3750
3751pub struct LspStore {
3752 mode: LspStoreMode,
3753 last_formatting_failure: Option<String>,
3754 downstream_client: Option<(AnyProtoClient, u64)>,
3755 nonce: u128,
3756 buffer_store: Entity<BufferStore>,
3757 worktree_store: Entity<WorktreeStore>,
3758 pub languages: Arc<LanguageRegistry>,
3759 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3760 active_entry: Option<ProjectEntryId>,
3761 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3762 _maintain_buffer_languages: Task<()>,
3763 diagnostic_summaries:
3764 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3765 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3766 lsp_data: HashMap<BufferId, BufferLspData>,
3767 next_hint_id: Arc<AtomicUsize>,
3768}
3769
3770#[derive(Debug)]
3771pub struct BufferLspData {
3772 buffer_version: Global,
3773 document_colors: Option<DocumentColorData>,
3774 code_lens: Option<CodeLensData>,
3775 inlay_hints: BufferInlayHints,
3776 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3777 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3778}
3779
3780#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3781struct LspKey {
3782 request_type: TypeId,
3783 server_queried: Option<LanguageServerId>,
3784}
3785
3786impl BufferLspData {
3787 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3788 Self {
3789 buffer_version: buffer.read(cx).version(),
3790 document_colors: None,
3791 code_lens: None,
3792 inlay_hints: BufferInlayHints::new(buffer, cx),
3793 lsp_requests: HashMap::default(),
3794 chunk_lsp_requests: HashMap::default(),
3795 }
3796 }
3797
3798 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3799 if let Some(document_colors) = &mut self.document_colors {
3800 document_colors.colors.remove(&for_server);
3801 document_colors.cache_version += 1;
3802 }
3803
3804 if let Some(code_lens) = &mut self.code_lens {
3805 code_lens.lens.remove(&for_server);
3806 }
3807
3808 self.inlay_hints.remove_server_data(for_server);
3809 }
3810
3811 #[cfg(any(test, feature = "test-support"))]
3812 pub fn inlay_hints(&self) -> &BufferInlayHints {
3813 &self.inlay_hints
3814 }
3815}
3816
3817#[derive(Debug, Default, Clone)]
3818pub struct DocumentColors {
3819 pub colors: HashSet<DocumentColor>,
3820 pub cache_version: Option<usize>,
3821}
3822
3823type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3824type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3825
3826#[derive(Debug, Default)]
3827struct DocumentColorData {
3828 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3829 cache_version: usize,
3830 colors_update: Option<(Global, DocumentColorTask)>,
3831}
3832
3833#[derive(Debug, Default)]
3834struct CodeLensData {
3835 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3836 update: Option<(Global, CodeLensTask)>,
3837}
3838
3839#[derive(Debug)]
3840pub enum LspStoreEvent {
3841 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3842 LanguageServerRemoved(LanguageServerId),
3843 LanguageServerUpdate {
3844 language_server_id: LanguageServerId,
3845 name: Option<LanguageServerName>,
3846 message: proto::update_language_server::Variant,
3847 },
3848 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3849 LanguageServerPrompt(LanguageServerPromptRequest),
3850 LanguageDetected {
3851 buffer: Entity<Buffer>,
3852 new_language: Option<Arc<Language>>,
3853 },
3854 Notification(String),
3855 RefreshInlayHints {
3856 server_id: LanguageServerId,
3857 request_id: Option<usize>,
3858 },
3859 RefreshCodeLens,
3860 DiagnosticsUpdated {
3861 server_id: LanguageServerId,
3862 paths: Vec<ProjectPath>,
3863 },
3864 DiskBasedDiagnosticsStarted {
3865 language_server_id: LanguageServerId,
3866 },
3867 DiskBasedDiagnosticsFinished {
3868 language_server_id: LanguageServerId,
3869 },
3870 SnippetEdit {
3871 buffer_id: BufferId,
3872 edits: Vec<(lsp::Range, Snippet)>,
3873 most_recent_edit: clock::Lamport,
3874 },
3875 WorkspaceEditApplied(ProjectTransaction),
3876}
3877
3878#[derive(Clone, Debug, Serialize)]
3879pub struct LanguageServerStatus {
3880 pub name: LanguageServerName,
3881 pub server_version: Option<SharedString>,
3882 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3883 pub has_pending_diagnostic_updates: bool,
3884 pub progress_tokens: HashSet<ProgressToken>,
3885 pub worktree: Option<WorktreeId>,
3886 pub binary: Option<LanguageServerBinary>,
3887 pub configuration: Option<Value>,
3888 pub workspace_folders: BTreeSet<Uri>,
3889}
3890
3891#[derive(Clone, Debug)]
3892struct CoreSymbol {
3893 pub language_server_name: LanguageServerName,
3894 pub source_worktree_id: WorktreeId,
3895 pub source_language_server_id: LanguageServerId,
3896 pub path: SymbolLocation,
3897 pub name: String,
3898 pub kind: lsp::SymbolKind,
3899 pub range: Range<Unclipped<PointUtf16>>,
3900}
3901
3902#[derive(Clone, Debug, PartialEq, Eq)]
3903pub enum SymbolLocation {
3904 InProject(ProjectPath),
3905 OutsideProject {
3906 abs_path: Arc<Path>,
3907 signature: [u8; 32],
3908 },
3909}
3910
3911impl SymbolLocation {
3912 fn file_name(&self) -> Option<&str> {
3913 match self {
3914 Self::InProject(path) => path.path.file_name(),
3915 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3916 }
3917 }
3918}
3919
3920impl LspStore {
3921 pub fn init(client: &AnyProtoClient) {
3922 client.add_entity_request_handler(Self::handle_lsp_query);
3923 client.add_entity_message_handler(Self::handle_lsp_query_response);
3924 client.add_entity_request_handler(Self::handle_restart_language_servers);
3925 client.add_entity_request_handler(Self::handle_stop_language_servers);
3926 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3927 client.add_entity_message_handler(Self::handle_start_language_server);
3928 client.add_entity_message_handler(Self::handle_update_language_server);
3929 client.add_entity_message_handler(Self::handle_language_server_log);
3930 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3931 client.add_entity_request_handler(Self::handle_format_buffers);
3932 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3933 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3934 client.add_entity_request_handler(Self::handle_apply_code_action);
3935 client.add_entity_request_handler(Self::handle_get_project_symbols);
3936 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3937 client.add_entity_request_handler(Self::handle_get_color_presentation);
3938 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3939 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3940 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3941 client.add_entity_request_handler(Self::handle_on_type_formatting);
3942 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3943 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3944 client.add_entity_request_handler(Self::handle_rename_project_entry);
3945 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3946 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3947 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3948 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3949 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3950 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3951 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3952
3953 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3954 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3955 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3956 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3957 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3958 client.add_entity_request_handler(
3959 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3960 );
3961 client.add_entity_request_handler(
3962 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3963 );
3964 client.add_entity_request_handler(
3965 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3966 );
3967 }
3968
3969 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3970 match &self.mode {
3971 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3972 _ => None,
3973 }
3974 }
3975
3976 pub fn as_local(&self) -> Option<&LocalLspStore> {
3977 match &self.mode {
3978 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3979 _ => None,
3980 }
3981 }
3982
3983 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3984 match &mut self.mode {
3985 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3986 _ => None,
3987 }
3988 }
3989
3990 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3991 match &self.mode {
3992 LspStoreMode::Remote(RemoteLspStore {
3993 upstream_client: Some(upstream_client),
3994 upstream_project_id,
3995 ..
3996 }) => Some((upstream_client.clone(), *upstream_project_id)),
3997
3998 LspStoreMode::Remote(RemoteLspStore {
3999 upstream_client: None,
4000 ..
4001 }) => None,
4002 LspStoreMode::Local(_) => None,
4003 }
4004 }
4005
4006 pub fn new_local(
4007 buffer_store: Entity<BufferStore>,
4008 worktree_store: Entity<WorktreeStore>,
4009 prettier_store: Entity<PrettierStore>,
4010 toolchain_store: Entity<LocalToolchainStore>,
4011 environment: Entity<ProjectEnvironment>,
4012 manifest_tree: Entity<ManifestTree>,
4013 languages: Arc<LanguageRegistry>,
4014 http_client: Arc<dyn HttpClient>,
4015 fs: Arc<dyn Fs>,
4016 cx: &mut Context<Self>,
4017 ) -> Self {
4018 let yarn = YarnPathStore::new(fs.clone(), cx);
4019 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4020 .detach();
4021 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4022 .detach();
4023 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4024 .detach();
4025 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4026 .detach();
4027 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4028 .detach();
4029 subscribe_to_binary_statuses(&languages, cx).detach();
4030
4031 let _maintain_workspace_config = {
4032 let (sender, receiver) = watch::channel();
4033 (Self::maintain_workspace_config(receiver, cx), sender)
4034 };
4035
4036 Self {
4037 mode: LspStoreMode::Local(LocalLspStore {
4038 weak: cx.weak_entity(),
4039 worktree_store: worktree_store.clone(),
4040
4041 supplementary_language_servers: Default::default(),
4042 languages: languages.clone(),
4043 language_server_ids: Default::default(),
4044 language_servers: Default::default(),
4045 last_workspace_edits_by_language_server: Default::default(),
4046 language_server_watched_paths: Default::default(),
4047 language_server_paths_watched_for_rename: Default::default(),
4048 language_server_dynamic_registrations: Default::default(),
4049 buffers_being_formatted: Default::default(),
4050 buffer_snapshots: Default::default(),
4051 prettier_store,
4052 environment,
4053 http_client,
4054 fs,
4055 yarn,
4056 next_diagnostic_group_id: Default::default(),
4057 diagnostics: Default::default(),
4058 _subscription: cx.on_app_quit(|this, cx| {
4059 this.as_local_mut()
4060 .unwrap()
4061 .shutdown_language_servers_on_quit(cx)
4062 }),
4063 lsp_tree: LanguageServerTree::new(
4064 manifest_tree,
4065 languages.clone(),
4066 toolchain_store.clone(),
4067 ),
4068 toolchain_store,
4069 registered_buffers: HashMap::default(),
4070 buffers_opened_in_servers: HashMap::default(),
4071 buffer_pull_diagnostics_result_ids: HashMap::default(),
4072 workspace_pull_diagnostics_result_ids: HashMap::default(),
4073 restricted_worktrees_tasks: HashMap::default(),
4074 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4075 .manifest_file_names(),
4076 }),
4077 last_formatting_failure: None,
4078 downstream_client: None,
4079 buffer_store,
4080 worktree_store,
4081 languages: languages.clone(),
4082 language_server_statuses: Default::default(),
4083 nonce: StdRng::from_os_rng().random(),
4084 diagnostic_summaries: HashMap::default(),
4085 lsp_server_capabilities: HashMap::default(),
4086 lsp_data: HashMap::default(),
4087 next_hint_id: Arc::default(),
4088 active_entry: None,
4089 _maintain_workspace_config,
4090 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4091 }
4092 }
4093
4094 fn send_lsp_proto_request<R: LspCommand>(
4095 &self,
4096 buffer: Entity<Buffer>,
4097 client: AnyProtoClient,
4098 upstream_project_id: u64,
4099 request: R,
4100 cx: &mut Context<LspStore>,
4101 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4102 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4103 return Task::ready(Ok(R::Response::default()));
4104 }
4105 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4106 cx.spawn(async move |this, cx| {
4107 let response = client.request(message).await?;
4108 let this = this.upgrade().context("project dropped")?;
4109 request
4110 .response_from_proto(response, this, buffer, cx.clone())
4111 .await
4112 })
4113 }
4114
4115 pub(super) fn new_remote(
4116 buffer_store: Entity<BufferStore>,
4117 worktree_store: Entity<WorktreeStore>,
4118 languages: Arc<LanguageRegistry>,
4119 upstream_client: AnyProtoClient,
4120 project_id: u64,
4121 cx: &mut Context<Self>,
4122 ) -> Self {
4123 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4124 .detach();
4125 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4126 .detach();
4127 subscribe_to_binary_statuses(&languages, cx).detach();
4128 let _maintain_workspace_config = {
4129 let (sender, receiver) = watch::channel();
4130 (Self::maintain_workspace_config(receiver, cx), sender)
4131 };
4132 Self {
4133 mode: LspStoreMode::Remote(RemoteLspStore {
4134 upstream_client: Some(upstream_client),
4135 upstream_project_id: project_id,
4136 }),
4137 downstream_client: None,
4138 last_formatting_failure: None,
4139 buffer_store,
4140 worktree_store,
4141 languages: languages.clone(),
4142 language_server_statuses: Default::default(),
4143 nonce: StdRng::from_os_rng().random(),
4144 diagnostic_summaries: HashMap::default(),
4145 lsp_server_capabilities: HashMap::default(),
4146 next_hint_id: Arc::default(),
4147 lsp_data: HashMap::default(),
4148 active_entry: None,
4149
4150 _maintain_workspace_config,
4151 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4152 }
4153 }
4154
4155 fn on_buffer_store_event(
4156 &mut self,
4157 _: Entity<BufferStore>,
4158 event: &BufferStoreEvent,
4159 cx: &mut Context<Self>,
4160 ) {
4161 match event {
4162 BufferStoreEvent::BufferAdded(buffer) => {
4163 self.on_buffer_added(buffer, cx).log_err();
4164 }
4165 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4166 let buffer_id = buffer.read(cx).remote_id();
4167 if let Some(local) = self.as_local_mut()
4168 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4169 {
4170 local.reset_buffer(buffer, old_file, cx);
4171
4172 if local.registered_buffers.contains_key(&buffer_id) {
4173 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4174 }
4175 }
4176
4177 self.detect_language_for_buffer(buffer, cx);
4178 if let Some(local) = self.as_local_mut() {
4179 local.initialize_buffer(buffer, cx);
4180 if local.registered_buffers.contains_key(&buffer_id) {
4181 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4182 }
4183 }
4184 }
4185 _ => {}
4186 }
4187 }
4188
4189 fn on_worktree_store_event(
4190 &mut self,
4191 _: Entity<WorktreeStore>,
4192 event: &WorktreeStoreEvent,
4193 cx: &mut Context<Self>,
4194 ) {
4195 match event {
4196 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4197 if !worktree.read(cx).is_local() {
4198 return;
4199 }
4200 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4201 worktree::Event::UpdatedEntries(changes) => {
4202 this.update_local_worktree_language_servers(&worktree, changes, cx);
4203 }
4204 worktree::Event::UpdatedGitRepositories(_)
4205 | worktree::Event::DeletedEntry(_) => {}
4206 })
4207 .detach()
4208 }
4209 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4210 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4211 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4212 }
4213 WorktreeStoreEvent::WorktreeReleased(..)
4214 | WorktreeStoreEvent::WorktreeOrderChanged
4215 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4216 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4217 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4218 }
4219 }
4220
4221 fn on_prettier_store_event(
4222 &mut self,
4223 _: Entity<PrettierStore>,
4224 event: &PrettierStoreEvent,
4225 cx: &mut Context<Self>,
4226 ) {
4227 match event {
4228 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4229 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4230 }
4231 PrettierStoreEvent::LanguageServerAdded {
4232 new_server_id,
4233 name,
4234 prettier_server,
4235 } => {
4236 self.register_supplementary_language_server(
4237 *new_server_id,
4238 name.clone(),
4239 prettier_server.clone(),
4240 cx,
4241 );
4242 }
4243 }
4244 }
4245
4246 fn on_toolchain_store_event(
4247 &mut self,
4248 _: Entity<LocalToolchainStore>,
4249 event: &ToolchainStoreEvent,
4250 _: &mut Context<Self>,
4251 ) {
4252 if let ToolchainStoreEvent::ToolchainActivated = event {
4253 self.request_workspace_config_refresh()
4254 }
4255 }
4256
4257 fn request_workspace_config_refresh(&mut self) {
4258 *self._maintain_workspace_config.1.borrow_mut() = ();
4259 }
4260
4261 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4262 self.as_local().map(|local| local.prettier_store.clone())
4263 }
4264
4265 fn on_buffer_event(
4266 &mut self,
4267 buffer: Entity<Buffer>,
4268 event: &language::BufferEvent,
4269 cx: &mut Context<Self>,
4270 ) {
4271 match event {
4272 language::BufferEvent::Edited => {
4273 self.on_buffer_edited(buffer, cx);
4274 }
4275
4276 language::BufferEvent::Saved => {
4277 self.on_buffer_saved(buffer, cx);
4278 }
4279
4280 _ => {}
4281 }
4282 }
4283
4284 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4285 buffer
4286 .read(cx)
4287 .set_language_registry(self.languages.clone());
4288
4289 cx.subscribe(buffer, |this, buffer, event, cx| {
4290 this.on_buffer_event(buffer, event, cx);
4291 })
4292 .detach();
4293
4294 self.detect_language_for_buffer(buffer, cx);
4295 if let Some(local) = self.as_local_mut() {
4296 local.initialize_buffer(buffer, cx);
4297 }
4298
4299 Ok(())
4300 }
4301
4302 pub(crate) fn register_buffer_with_language_servers(
4303 &mut self,
4304 buffer: &Entity<Buffer>,
4305 only_register_servers: HashSet<LanguageServerSelector>,
4306 ignore_refcounts: bool,
4307 cx: &mut Context<Self>,
4308 ) -> OpenLspBufferHandle {
4309 let buffer_id = buffer.read(cx).remote_id();
4310 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4311 if let Some(local) = self.as_local_mut() {
4312 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4313 if !ignore_refcounts {
4314 *refcount += 1;
4315 }
4316
4317 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4318 // 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
4319 // 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
4320 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4321 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4322 return handle;
4323 };
4324 if !file.is_local() {
4325 return handle;
4326 }
4327
4328 if ignore_refcounts || *refcount == 1 {
4329 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4330 }
4331 if !ignore_refcounts {
4332 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4333 let refcount = {
4334 let local = lsp_store.as_local_mut().unwrap();
4335 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4336 debug_panic!("bad refcounting");
4337 return;
4338 };
4339
4340 *refcount -= 1;
4341 *refcount
4342 };
4343 if refcount == 0 {
4344 lsp_store.lsp_data.remove(&buffer_id);
4345 let local = lsp_store.as_local_mut().unwrap();
4346 local.registered_buffers.remove(&buffer_id);
4347
4348 local.buffers_opened_in_servers.remove(&buffer_id);
4349 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4350 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4351
4352 let buffer_abs_path = file.abs_path(cx);
4353 for (_, buffer_pull_diagnostics_result_ids) in
4354 &mut local.buffer_pull_diagnostics_result_ids
4355 {
4356 buffer_pull_diagnostics_result_ids.retain(
4357 |_, buffer_result_ids| {
4358 buffer_result_ids.remove(&buffer_abs_path);
4359 !buffer_result_ids.is_empty()
4360 },
4361 );
4362 }
4363
4364 let diagnostic_updates = local
4365 .language_servers
4366 .keys()
4367 .cloned()
4368 .map(|server_id| DocumentDiagnosticsUpdate {
4369 diagnostics: DocumentDiagnostics {
4370 document_abs_path: buffer_abs_path.clone(),
4371 version: None,
4372 diagnostics: Vec::new(),
4373 },
4374 result_id: None,
4375 registration_id: None,
4376 server_id: server_id,
4377 disk_based_sources: Cow::Borrowed(&[]),
4378 })
4379 .collect::<Vec<_>>();
4380
4381 lsp_store
4382 .merge_diagnostic_entries(
4383 diagnostic_updates,
4384 |_, diagnostic, _| {
4385 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4386 },
4387 cx,
4388 )
4389 .context("Clearing diagnostics for the closed buffer")
4390 .log_err();
4391 }
4392 }
4393 })
4394 .detach();
4395 }
4396 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4397 let buffer_id = buffer.read(cx).remote_id().to_proto();
4398 cx.background_spawn(async move {
4399 upstream_client
4400 .request(proto::RegisterBufferWithLanguageServers {
4401 project_id: upstream_project_id,
4402 buffer_id,
4403 only_servers: only_register_servers
4404 .into_iter()
4405 .map(|selector| {
4406 let selector = match selector {
4407 LanguageServerSelector::Id(language_server_id) => {
4408 proto::language_server_selector::Selector::ServerId(
4409 language_server_id.to_proto(),
4410 )
4411 }
4412 LanguageServerSelector::Name(language_server_name) => {
4413 proto::language_server_selector::Selector::Name(
4414 language_server_name.to_string(),
4415 )
4416 }
4417 };
4418 proto::LanguageServerSelector {
4419 selector: Some(selector),
4420 }
4421 })
4422 .collect(),
4423 })
4424 .await
4425 })
4426 .detach();
4427 } else {
4428 // Our remote connection got closed
4429 }
4430 handle
4431 }
4432
4433 fn maintain_buffer_languages(
4434 languages: Arc<LanguageRegistry>,
4435 cx: &mut Context<Self>,
4436 ) -> Task<()> {
4437 let mut subscription = languages.subscribe();
4438 let mut prev_reload_count = languages.reload_count();
4439 cx.spawn(async move |this, cx| {
4440 while let Some(()) = subscription.next().await {
4441 if let Some(this) = this.upgrade() {
4442 // If the language registry has been reloaded, then remove and
4443 // re-assign the languages on all open buffers.
4444 let reload_count = languages.reload_count();
4445 if reload_count > prev_reload_count {
4446 prev_reload_count = reload_count;
4447 this.update(cx, |this, cx| {
4448 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4449 for buffer in buffer_store.buffers() {
4450 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4451 {
4452 buffer.update(cx, |buffer, cx| {
4453 buffer.set_language_async(None, cx)
4454 });
4455 if let Some(local) = this.as_local_mut() {
4456 local.reset_buffer(&buffer, &f, cx);
4457
4458 if local
4459 .registered_buffers
4460 .contains_key(&buffer.read(cx).remote_id())
4461 && let Some(file_url) =
4462 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4463 {
4464 local.unregister_buffer_from_language_servers(
4465 &buffer, &file_url, cx,
4466 );
4467 }
4468 }
4469 }
4470 }
4471 });
4472 });
4473 }
4474
4475 this.update(cx, |this, cx| {
4476 let mut plain_text_buffers = Vec::new();
4477 let mut buffers_with_unknown_injections = Vec::new();
4478 for handle in this.buffer_store.read(cx).buffers() {
4479 let buffer = handle.read(cx);
4480 if buffer.language().is_none()
4481 || buffer.language() == Some(&*language::PLAIN_TEXT)
4482 {
4483 plain_text_buffers.push(handle);
4484 } else if buffer.contains_unknown_injections() {
4485 buffers_with_unknown_injections.push(handle);
4486 }
4487 }
4488
4489 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4490 // and reused later in the invisible worktrees.
4491 plain_text_buffers.sort_by_key(|buffer| {
4492 Reverse(
4493 File::from_dyn(buffer.read(cx).file())
4494 .map(|file| file.worktree.read(cx).is_visible()),
4495 )
4496 });
4497
4498 for buffer in plain_text_buffers {
4499 this.detect_language_for_buffer(&buffer, cx);
4500 if let Some(local) = this.as_local_mut() {
4501 local.initialize_buffer(&buffer, cx);
4502 if local
4503 .registered_buffers
4504 .contains_key(&buffer.read(cx).remote_id())
4505 {
4506 local.register_buffer_with_language_servers(
4507 &buffer,
4508 HashSet::default(),
4509 cx,
4510 );
4511 }
4512 }
4513 }
4514
4515 for buffer in buffers_with_unknown_injections {
4516 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4517 }
4518 });
4519 }
4520 }
4521 })
4522 }
4523
4524 fn detect_language_for_buffer(
4525 &mut self,
4526 buffer_handle: &Entity<Buffer>,
4527 cx: &mut Context<Self>,
4528 ) -> Option<language::AvailableLanguage> {
4529 // If the buffer has a language, set it and start the language server if we haven't already.
4530 let buffer = buffer_handle.read(cx);
4531 let file = buffer.file()?;
4532
4533 let content = buffer.as_rope();
4534 let available_language = self.languages.language_for_file(file, Some(content), cx);
4535 if let Some(available_language) = &available_language {
4536 if let Some(Ok(Ok(new_language))) = self
4537 .languages
4538 .load_language(available_language)
4539 .now_or_never()
4540 {
4541 self.set_language_for_buffer(buffer_handle, new_language, cx);
4542 }
4543 } else {
4544 cx.emit(LspStoreEvent::LanguageDetected {
4545 buffer: buffer_handle.clone(),
4546 new_language: None,
4547 });
4548 }
4549
4550 available_language
4551 }
4552
4553 pub(crate) fn set_language_for_buffer(
4554 &mut self,
4555 buffer_entity: &Entity<Buffer>,
4556 new_language: Arc<Language>,
4557 cx: &mut Context<Self>,
4558 ) {
4559 let buffer = buffer_entity.read(cx);
4560 let buffer_file = buffer.file().cloned();
4561 let buffer_id = buffer.remote_id();
4562 if let Some(local_store) = self.as_local_mut()
4563 && local_store.registered_buffers.contains_key(&buffer_id)
4564 && let Some(abs_path) =
4565 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4566 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4567 {
4568 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4569 }
4570 buffer_entity.update(cx, |buffer, cx| {
4571 if buffer
4572 .language()
4573 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4574 {
4575 buffer.set_language_async(Some(new_language.clone()), cx);
4576 }
4577 });
4578
4579 let settings =
4580 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4581 let buffer_file = File::from_dyn(buffer_file.as_ref());
4582
4583 let worktree_id = if let Some(file) = buffer_file {
4584 let worktree = file.worktree.clone();
4585
4586 if let Some(local) = self.as_local_mut()
4587 && local.registered_buffers.contains_key(&buffer_id)
4588 {
4589 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4590 }
4591 Some(worktree.read(cx).id())
4592 } else {
4593 None
4594 };
4595
4596 if settings.prettier.allowed
4597 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4598 {
4599 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4600 if let Some(prettier_store) = prettier_store {
4601 prettier_store.update(cx, |prettier_store, cx| {
4602 prettier_store.install_default_prettier(
4603 worktree_id,
4604 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4605 cx,
4606 )
4607 })
4608 }
4609 }
4610
4611 cx.emit(LspStoreEvent::LanguageDetected {
4612 buffer: buffer_entity.clone(),
4613 new_language: Some(new_language),
4614 })
4615 }
4616
4617 pub fn buffer_store(&self) -> Entity<BufferStore> {
4618 self.buffer_store.clone()
4619 }
4620
4621 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4622 self.active_entry = active_entry;
4623 }
4624
4625 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4626 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4627 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4628 {
4629 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4630 summaries
4631 .iter()
4632 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4633 });
4634 if let Some(summary) = summaries.next() {
4635 client
4636 .send(proto::UpdateDiagnosticSummary {
4637 project_id: downstream_project_id,
4638 worktree_id: worktree.id().to_proto(),
4639 summary: Some(summary),
4640 more_summaries: summaries.collect(),
4641 })
4642 .log_err();
4643 }
4644 }
4645 }
4646
4647 fn is_capable_for_proto_request<R>(
4648 &self,
4649 buffer: &Entity<Buffer>,
4650 request: &R,
4651 cx: &App,
4652 ) -> bool
4653 where
4654 R: LspCommand,
4655 {
4656 self.check_if_capable_for_proto_request(
4657 buffer,
4658 |capabilities| {
4659 request.check_capabilities(AdapterServerCapabilities {
4660 server_capabilities: capabilities.clone(),
4661 code_action_kinds: None,
4662 })
4663 },
4664 cx,
4665 )
4666 }
4667
4668 fn check_if_capable_for_proto_request<F>(
4669 &self,
4670 buffer: &Entity<Buffer>,
4671 check: F,
4672 cx: &App,
4673 ) -> bool
4674 where
4675 F: FnMut(&lsp::ServerCapabilities) -> bool,
4676 {
4677 let Some(language) = buffer.read(cx).language().cloned() else {
4678 return false;
4679 };
4680 let registered_language_servers = self
4681 .languages
4682 .lsp_adapters(&language.name())
4683 .into_iter()
4684 .map(|lsp_adapter| lsp_adapter.name())
4685 .collect::<HashSet<_>>();
4686 self.language_server_statuses
4687 .iter()
4688 .filter_map(|(server_id, server_status)| {
4689 // Include servers that are either registered for this language OR
4690 // available to be loaded (for SSH remote mode where adapters like
4691 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4692 // but only loaded on the server side)
4693 let is_relevant = registered_language_servers.contains(&server_status.name)
4694 || self.languages.is_lsp_adapter_available(&server_status.name);
4695 is_relevant.then_some(server_id)
4696 })
4697 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4698 .any(check)
4699 }
4700
4701 fn all_capable_for_proto_request<F>(
4702 &self,
4703 buffer: &Entity<Buffer>,
4704 mut check: F,
4705 cx: &App,
4706 ) -> Vec<lsp::LanguageServerId>
4707 where
4708 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4709 {
4710 let Some(language) = buffer.read(cx).language().cloned() else {
4711 return Vec::default();
4712 };
4713 let registered_language_servers = self
4714 .languages
4715 .lsp_adapters(&language.name())
4716 .into_iter()
4717 .map(|lsp_adapter| lsp_adapter.name())
4718 .collect::<HashSet<_>>();
4719 self.language_server_statuses
4720 .iter()
4721 .filter_map(|(server_id, server_status)| {
4722 // Include servers that are either registered for this language OR
4723 // available to be loaded (for SSH remote mode where adapters like
4724 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4725 // but only loaded on the server side)
4726 let is_relevant = registered_language_servers.contains(&server_status.name)
4727 || self.languages.is_lsp_adapter_available(&server_status.name);
4728 is_relevant.then_some((server_id, &server_status.name))
4729 })
4730 .filter_map(|(server_id, server_name)| {
4731 self.lsp_server_capabilities
4732 .get(server_id)
4733 .map(|c| (server_id, server_name, c))
4734 })
4735 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4736 .map(|(server_id, _, _)| *server_id)
4737 .collect()
4738 }
4739
4740 pub fn request_lsp<R>(
4741 &mut self,
4742 buffer: Entity<Buffer>,
4743 server: LanguageServerToQuery,
4744 request: R,
4745 cx: &mut Context<Self>,
4746 ) -> Task<Result<R::Response>>
4747 where
4748 R: LspCommand,
4749 <R::LspRequest as lsp::request::Request>::Result: Send,
4750 <R::LspRequest as lsp::request::Request>::Params: Send,
4751 {
4752 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4753 return self.send_lsp_proto_request(
4754 buffer,
4755 upstream_client,
4756 upstream_project_id,
4757 request,
4758 cx,
4759 );
4760 }
4761
4762 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4763 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4764 local
4765 .language_servers_for_buffer(buffer, cx)
4766 .find(|(_, server)| {
4767 request.check_capabilities(server.adapter_server_capabilities())
4768 })
4769 .map(|(_, server)| server.clone())
4770 }),
4771 LanguageServerToQuery::Other(id) => self
4772 .language_server_for_local_buffer(buffer, id, cx)
4773 .and_then(|(_, server)| {
4774 request
4775 .check_capabilities(server.adapter_server_capabilities())
4776 .then(|| Arc::clone(server))
4777 }),
4778 }) else {
4779 return Task::ready(Ok(Default::default()));
4780 };
4781
4782 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4783
4784 let Some(file) = file else {
4785 return Task::ready(Ok(Default::default()));
4786 };
4787
4788 let lsp_params = match request.to_lsp_params_or_response(
4789 &file.abs_path(cx),
4790 buffer.read(cx),
4791 &language_server,
4792 cx,
4793 ) {
4794 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4795 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4796 Err(err) => {
4797 let message = format!(
4798 "{} via {} failed: {}",
4799 request.display_name(),
4800 language_server.name(),
4801 err
4802 );
4803 // rust-analyzer likes to error with this when its still loading up
4804 if !message.ends_with("content modified") {
4805 log::warn!("{message}");
4806 }
4807 return Task::ready(Err(anyhow!(message)));
4808 }
4809 };
4810
4811 let status = request.status();
4812 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4813 return Task::ready(Ok(Default::default()));
4814 }
4815 cx.spawn(async move |this, cx| {
4816 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4817
4818 let id = lsp_request.id();
4819 let _cleanup = if status.is_some() {
4820 cx.update(|cx| {
4821 this.update(cx, |this, cx| {
4822 this.on_lsp_work_start(
4823 language_server.server_id(),
4824 ProgressToken::Number(id),
4825 LanguageServerProgress {
4826 is_disk_based_diagnostics_progress: false,
4827 is_cancellable: false,
4828 title: None,
4829 message: status.clone(),
4830 percentage: None,
4831 last_update_at: cx.background_executor().now(),
4832 },
4833 cx,
4834 );
4835 })
4836 })
4837 .log_err();
4838
4839 Some(defer(|| {
4840 cx.update(|cx| {
4841 this.update(cx, |this, cx| {
4842 this.on_lsp_work_end(
4843 language_server.server_id(),
4844 ProgressToken::Number(id),
4845 cx,
4846 );
4847 })
4848 })
4849 .log_err();
4850 }))
4851 } else {
4852 None
4853 };
4854
4855 let result = lsp_request.await.into_response();
4856
4857 let response = result.map_err(|err| {
4858 let message = format!(
4859 "{} via {} failed: {}",
4860 request.display_name(),
4861 language_server.name(),
4862 err
4863 );
4864 // rust-analyzer likes to error with this when its still loading up
4865 if !message.ends_with("content modified") {
4866 log::warn!("{message}");
4867 }
4868 anyhow::anyhow!(message)
4869 })?;
4870
4871 request
4872 .response_from_lsp(
4873 response,
4874 this.upgrade().context("no app context")?,
4875 buffer,
4876 language_server.server_id(),
4877 cx.clone(),
4878 )
4879 .await
4880 })
4881 }
4882
4883 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4884 let mut language_formatters_to_check = Vec::new();
4885 for buffer in self.buffer_store.read(cx).buffers() {
4886 let buffer = buffer.read(cx);
4887 let buffer_file = File::from_dyn(buffer.file());
4888 let buffer_language = buffer.language();
4889 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4890 if buffer_language.is_some() {
4891 language_formatters_to_check.push((
4892 buffer_file.map(|f| f.worktree_id(cx)),
4893 settings.into_owned(),
4894 ));
4895 }
4896 }
4897
4898 self.request_workspace_config_refresh();
4899
4900 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4901 prettier_store.update(cx, |prettier_store, cx| {
4902 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4903 })
4904 }
4905
4906 cx.notify();
4907 }
4908
4909 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4910 let buffer_store = self.buffer_store.clone();
4911 let Some(local) = self.as_local_mut() else {
4912 return;
4913 };
4914 let mut adapters = BTreeMap::default();
4915 let get_adapter = {
4916 let languages = local.languages.clone();
4917 let environment = local.environment.clone();
4918 let weak = local.weak.clone();
4919 let worktree_store = local.worktree_store.clone();
4920 let http_client = local.http_client.clone();
4921 let fs = local.fs.clone();
4922 move |worktree_id, cx: &mut App| {
4923 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4924 Some(LocalLspAdapterDelegate::new(
4925 languages.clone(),
4926 &environment,
4927 weak.clone(),
4928 &worktree,
4929 http_client.clone(),
4930 fs.clone(),
4931 cx,
4932 ))
4933 }
4934 };
4935
4936 let mut messages_to_report = Vec::new();
4937 let (new_tree, to_stop) = {
4938 let mut rebase = local.lsp_tree.rebase();
4939 let buffers = buffer_store
4940 .read(cx)
4941 .buffers()
4942 .filter_map(|buffer| {
4943 let raw_buffer = buffer.read(cx);
4944 if !local
4945 .registered_buffers
4946 .contains_key(&raw_buffer.remote_id())
4947 {
4948 return None;
4949 }
4950 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4951 let language = raw_buffer.language().cloned()?;
4952 Some((file, language, raw_buffer.remote_id()))
4953 })
4954 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4955 for (file, language, buffer_id) in buffers {
4956 let worktree_id = file.worktree_id(cx);
4957 let Some(worktree) = local
4958 .worktree_store
4959 .read(cx)
4960 .worktree_for_id(worktree_id, cx)
4961 else {
4962 continue;
4963 };
4964
4965 if let Some((_, apply)) = local.reuse_existing_language_server(
4966 rebase.server_tree(),
4967 &worktree,
4968 &language.name(),
4969 cx,
4970 ) {
4971 (apply)(rebase.server_tree());
4972 } else if let Some(lsp_delegate) = adapters
4973 .entry(worktree_id)
4974 .or_insert_with(|| get_adapter(worktree_id, cx))
4975 .clone()
4976 {
4977 let delegate =
4978 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4979 let path = file
4980 .path()
4981 .parent()
4982 .map(Arc::from)
4983 .unwrap_or_else(|| file.path().clone());
4984 let worktree_path = ProjectPath { worktree_id, path };
4985 let abs_path = file.abs_path(cx);
4986 let nodes = rebase
4987 .walk(
4988 worktree_path,
4989 language.name(),
4990 language.manifest(),
4991 delegate.clone(),
4992 cx,
4993 )
4994 .collect::<Vec<_>>();
4995 for node in nodes {
4996 let server_id = node.server_id_or_init(|disposition| {
4997 let path = &disposition.path;
4998 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4999 let key = LanguageServerSeed {
5000 worktree_id,
5001 name: disposition.server_name.clone(),
5002 settings: disposition.settings.clone(),
5003 toolchain: local.toolchain_store.read(cx).active_toolchain(
5004 path.worktree_id,
5005 &path.path,
5006 language.name(),
5007 ),
5008 };
5009 local.language_server_ids.remove(&key);
5010
5011 let server_id = local.get_or_insert_language_server(
5012 &worktree,
5013 lsp_delegate.clone(),
5014 disposition,
5015 &language.name(),
5016 cx,
5017 );
5018 if let Some(state) = local.language_servers.get(&server_id)
5019 && let Ok(uri) = uri
5020 {
5021 state.add_workspace_folder(uri);
5022 };
5023 server_id
5024 });
5025
5026 if let Some(language_server_id) = server_id {
5027 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5028 language_server_id,
5029 name: node.name(),
5030 message:
5031 proto::update_language_server::Variant::RegisteredForBuffer(
5032 proto::RegisteredForBuffer {
5033 buffer_abs_path: abs_path
5034 .to_string_lossy()
5035 .into_owned(),
5036 buffer_id: buffer_id.to_proto(),
5037 },
5038 ),
5039 });
5040 }
5041 }
5042 } else {
5043 continue;
5044 }
5045 }
5046 rebase.finish()
5047 };
5048 for message in messages_to_report {
5049 cx.emit(message);
5050 }
5051 local.lsp_tree = new_tree;
5052 for (id, _) in to_stop {
5053 self.stop_local_language_server(id, cx).detach();
5054 }
5055 }
5056
5057 pub fn apply_code_action(
5058 &self,
5059 buffer_handle: Entity<Buffer>,
5060 mut action: CodeAction,
5061 push_to_history: bool,
5062 cx: &mut Context<Self>,
5063 ) -> Task<Result<ProjectTransaction>> {
5064 if let Some((upstream_client, project_id)) = self.upstream_client() {
5065 let request = proto::ApplyCodeAction {
5066 project_id,
5067 buffer_id: buffer_handle.read(cx).remote_id().into(),
5068 action: Some(Self::serialize_code_action(&action)),
5069 };
5070 let buffer_store = self.buffer_store();
5071 cx.spawn(async move |_, cx| {
5072 let response = upstream_client
5073 .request(request)
5074 .await?
5075 .transaction
5076 .context("missing transaction")?;
5077
5078 buffer_store
5079 .update(cx, |buffer_store, cx| {
5080 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5081 })
5082 .await
5083 })
5084 } else if self.mode.is_local() {
5085 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5086 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5087 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5088 }) else {
5089 return Task::ready(Ok(ProjectTransaction::default()));
5090 };
5091 cx.spawn(async move |this, cx| {
5092 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5093 .await
5094 .context("resolving a code action")?;
5095 if let Some(edit) = action.lsp_action.edit()
5096 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5097 return LocalLspStore::deserialize_workspace_edit(
5098 this.upgrade().context("no app present")?,
5099 edit.clone(),
5100 push_to_history,
5101
5102 lang_server.clone(),
5103 cx,
5104 )
5105 .await;
5106 }
5107
5108 if let Some(command) = action.lsp_action.command() {
5109 let server_capabilities = lang_server.capabilities();
5110 let available_commands = server_capabilities
5111 .execute_command_provider
5112 .as_ref()
5113 .map(|options| options.commands.as_slice())
5114 .unwrap_or_default();
5115 if available_commands.contains(&command.command) {
5116 this.update(cx, |this, _| {
5117 this.as_local_mut()
5118 .unwrap()
5119 .last_workspace_edits_by_language_server
5120 .remove(&lang_server.server_id());
5121 })?;
5122
5123 let _result = lang_server
5124 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5125 command: command.command.clone(),
5126 arguments: command.arguments.clone().unwrap_or_default(),
5127 ..lsp::ExecuteCommandParams::default()
5128 })
5129 .await.into_response()
5130 .context("execute command")?;
5131
5132 return this.update(cx, |this, _| {
5133 this.as_local_mut()
5134 .unwrap()
5135 .last_workspace_edits_by_language_server
5136 .remove(&lang_server.server_id())
5137 .unwrap_or_default()
5138 });
5139 } else {
5140 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5141 }
5142 }
5143
5144 Ok(ProjectTransaction::default())
5145 })
5146 } else {
5147 Task::ready(Err(anyhow!("no upstream client and not local")))
5148 }
5149 }
5150
5151 pub fn apply_code_action_kind(
5152 &mut self,
5153 buffers: HashSet<Entity<Buffer>>,
5154 kind: CodeActionKind,
5155 push_to_history: bool,
5156 cx: &mut Context<Self>,
5157 ) -> Task<anyhow::Result<ProjectTransaction>> {
5158 if self.as_local().is_some() {
5159 cx.spawn(async move |lsp_store, cx| {
5160 let buffers = buffers.into_iter().collect::<Vec<_>>();
5161 let result = LocalLspStore::execute_code_action_kind_locally(
5162 lsp_store.clone(),
5163 buffers,
5164 kind,
5165 push_to_history,
5166 cx,
5167 )
5168 .await;
5169 lsp_store.update(cx, |lsp_store, _| {
5170 lsp_store.update_last_formatting_failure(&result);
5171 })?;
5172 result
5173 })
5174 } else if let Some((client, project_id)) = self.upstream_client() {
5175 let buffer_store = self.buffer_store();
5176 cx.spawn(async move |lsp_store, cx| {
5177 let result = client
5178 .request(proto::ApplyCodeActionKind {
5179 project_id,
5180 kind: kind.as_str().to_owned(),
5181 buffer_ids: buffers
5182 .iter()
5183 .map(|buffer| {
5184 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5185 })
5186 .collect(),
5187 })
5188 .await
5189 .and_then(|result| result.transaction.context("missing transaction"));
5190 lsp_store.update(cx, |lsp_store, _| {
5191 lsp_store.update_last_formatting_failure(&result);
5192 })?;
5193
5194 let transaction_response = result?;
5195 buffer_store
5196 .update(cx, |buffer_store, cx| {
5197 buffer_store.deserialize_project_transaction(
5198 transaction_response,
5199 push_to_history,
5200 cx,
5201 )
5202 })
5203 .await
5204 })
5205 } else {
5206 Task::ready(Ok(ProjectTransaction::default()))
5207 }
5208 }
5209
5210 pub fn resolved_hint(
5211 &mut self,
5212 buffer_id: BufferId,
5213 id: InlayId,
5214 cx: &mut Context<Self>,
5215 ) -> Option<ResolvedHint> {
5216 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5217
5218 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5219 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5220 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5221 let (server_id, resolve_data) = match &hint.resolve_state {
5222 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5223 ResolveState::Resolving => {
5224 return Some(ResolvedHint::Resolving(
5225 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5226 ));
5227 }
5228 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5229 };
5230
5231 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5232 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5233 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5234 id,
5235 cx.spawn(async move |lsp_store, cx| {
5236 let resolved_hint = resolve_task.await;
5237 lsp_store
5238 .update(cx, |lsp_store, _| {
5239 if let Some(old_inlay_hint) = lsp_store
5240 .lsp_data
5241 .get_mut(&buffer_id)
5242 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5243 {
5244 match resolved_hint {
5245 Ok(resolved_hint) => {
5246 *old_inlay_hint = resolved_hint;
5247 }
5248 Err(e) => {
5249 old_inlay_hint.resolve_state =
5250 ResolveState::CanResolve(server_id, resolve_data);
5251 log::error!("Inlay hint resolve failed: {e:#}");
5252 }
5253 }
5254 }
5255 })
5256 .ok();
5257 })
5258 .shared(),
5259 );
5260 debug_assert!(
5261 previous_task.is_none(),
5262 "Did not change hint's resolve state after spawning its resolve"
5263 );
5264 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5265 None
5266 }
5267
5268 fn resolve_inlay_hint(
5269 &self,
5270 mut hint: InlayHint,
5271 buffer: Entity<Buffer>,
5272 server_id: LanguageServerId,
5273 cx: &mut Context<Self>,
5274 ) -> Task<anyhow::Result<InlayHint>> {
5275 if let Some((upstream_client, project_id)) = self.upstream_client() {
5276 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5277 {
5278 hint.resolve_state = ResolveState::Resolved;
5279 return Task::ready(Ok(hint));
5280 }
5281 let request = proto::ResolveInlayHint {
5282 project_id,
5283 buffer_id: buffer.read(cx).remote_id().into(),
5284 language_server_id: server_id.0 as u64,
5285 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5286 };
5287 cx.background_spawn(async move {
5288 let response = upstream_client
5289 .request(request)
5290 .await
5291 .context("inlay hints proto request")?;
5292 match response.hint {
5293 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5294 .context("inlay hints proto resolve response conversion"),
5295 None => Ok(hint),
5296 }
5297 })
5298 } else {
5299 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5300 self.language_server_for_local_buffer(buffer, server_id, cx)
5301 .map(|(_, server)| server.clone())
5302 }) else {
5303 return Task::ready(Ok(hint));
5304 };
5305 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5306 return Task::ready(Ok(hint));
5307 }
5308 let buffer_snapshot = buffer.read(cx).snapshot();
5309 cx.spawn(async move |_, cx| {
5310 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5311 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5312 );
5313 let resolved_hint = resolve_task
5314 .await
5315 .into_response()
5316 .context("inlay hint resolve LSP request")?;
5317 let resolved_hint = InlayHints::lsp_to_project_hint(
5318 resolved_hint,
5319 &buffer,
5320 server_id,
5321 ResolveState::Resolved,
5322 false,
5323 cx,
5324 )
5325 .await?;
5326 Ok(resolved_hint)
5327 })
5328 }
5329 }
5330
5331 pub fn resolve_color_presentation(
5332 &mut self,
5333 mut color: DocumentColor,
5334 buffer: Entity<Buffer>,
5335 server_id: LanguageServerId,
5336 cx: &mut Context<Self>,
5337 ) -> Task<Result<DocumentColor>> {
5338 if color.resolved {
5339 return Task::ready(Ok(color));
5340 }
5341
5342 if let Some((upstream_client, project_id)) = self.upstream_client() {
5343 let start = color.lsp_range.start;
5344 let end = color.lsp_range.end;
5345 let request = proto::GetColorPresentation {
5346 project_id,
5347 server_id: server_id.to_proto(),
5348 buffer_id: buffer.read(cx).remote_id().into(),
5349 color: Some(proto::ColorInformation {
5350 red: color.color.red,
5351 green: color.color.green,
5352 blue: color.color.blue,
5353 alpha: color.color.alpha,
5354 lsp_range_start: Some(proto::PointUtf16 {
5355 row: start.line,
5356 column: start.character,
5357 }),
5358 lsp_range_end: Some(proto::PointUtf16 {
5359 row: end.line,
5360 column: end.character,
5361 }),
5362 }),
5363 };
5364 cx.background_spawn(async move {
5365 let response = upstream_client
5366 .request(request)
5367 .await
5368 .context("color presentation proto request")?;
5369 color.resolved = true;
5370 color.color_presentations = response
5371 .presentations
5372 .into_iter()
5373 .map(|presentation| ColorPresentation {
5374 label: SharedString::from(presentation.label),
5375 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5376 additional_text_edits: presentation
5377 .additional_text_edits
5378 .into_iter()
5379 .filter_map(deserialize_lsp_edit)
5380 .collect(),
5381 })
5382 .collect();
5383 Ok(color)
5384 })
5385 } else {
5386 let path = match buffer
5387 .update(cx, |buffer, cx| {
5388 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5389 })
5390 .context("buffer with the missing path")
5391 {
5392 Ok(path) => path,
5393 Err(e) => return Task::ready(Err(e)),
5394 };
5395 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5396 self.language_server_for_local_buffer(buffer, server_id, cx)
5397 .map(|(_, server)| server.clone())
5398 }) else {
5399 return Task::ready(Ok(color));
5400 };
5401 cx.background_spawn(async move {
5402 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5403 lsp::ColorPresentationParams {
5404 text_document: make_text_document_identifier(&path)?,
5405 color: color.color,
5406 range: color.lsp_range,
5407 work_done_progress_params: Default::default(),
5408 partial_result_params: Default::default(),
5409 },
5410 );
5411 color.color_presentations = resolve_task
5412 .await
5413 .into_response()
5414 .context("color presentation resolve LSP request")?
5415 .into_iter()
5416 .map(|presentation| ColorPresentation {
5417 label: SharedString::from(presentation.label),
5418 text_edit: presentation.text_edit,
5419 additional_text_edits: presentation
5420 .additional_text_edits
5421 .unwrap_or_default(),
5422 })
5423 .collect();
5424 color.resolved = true;
5425 Ok(color)
5426 })
5427 }
5428 }
5429
5430 pub(crate) fn linked_edits(
5431 &mut self,
5432 buffer: &Entity<Buffer>,
5433 position: Anchor,
5434 cx: &mut Context<Self>,
5435 ) -> Task<Result<Vec<Range<Anchor>>>> {
5436 let snapshot = buffer.read(cx).snapshot();
5437 let scope = snapshot.language_scope_at(position);
5438 let Some(server_id) = self
5439 .as_local()
5440 .and_then(|local| {
5441 buffer.update(cx, |buffer, cx| {
5442 local
5443 .language_servers_for_buffer(buffer, cx)
5444 .filter(|(_, server)| {
5445 LinkedEditingRange::check_server_capabilities(server.capabilities())
5446 })
5447 .filter(|(adapter, _)| {
5448 scope
5449 .as_ref()
5450 .map(|scope| scope.language_allowed(&adapter.name))
5451 .unwrap_or(true)
5452 })
5453 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5454 .next()
5455 })
5456 })
5457 .or_else(|| {
5458 self.upstream_client()
5459 .is_some()
5460 .then_some(LanguageServerToQuery::FirstCapable)
5461 })
5462 .filter(|_| {
5463 maybe!({
5464 let language = buffer.read(cx).language_at(position)?;
5465 Some(
5466 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5467 .linked_edits,
5468 )
5469 }) == Some(true)
5470 })
5471 else {
5472 return Task::ready(Ok(Vec::new()));
5473 };
5474
5475 self.request_lsp(
5476 buffer.clone(),
5477 server_id,
5478 LinkedEditingRange { position },
5479 cx,
5480 )
5481 }
5482
5483 fn apply_on_type_formatting(
5484 &mut self,
5485 buffer: Entity<Buffer>,
5486 position: Anchor,
5487 trigger: String,
5488 cx: &mut Context<Self>,
5489 ) -> Task<Result<Option<Transaction>>> {
5490 if let Some((client, project_id)) = self.upstream_client() {
5491 if !self.check_if_capable_for_proto_request(
5492 &buffer,
5493 |capabilities| {
5494 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5495 },
5496 cx,
5497 ) {
5498 return Task::ready(Ok(None));
5499 }
5500 let request = proto::OnTypeFormatting {
5501 project_id,
5502 buffer_id: buffer.read(cx).remote_id().into(),
5503 position: Some(serialize_anchor(&position)),
5504 trigger,
5505 version: serialize_version(&buffer.read(cx).version()),
5506 };
5507 cx.background_spawn(async move {
5508 client
5509 .request(request)
5510 .await?
5511 .transaction
5512 .map(language::proto::deserialize_transaction)
5513 .transpose()
5514 })
5515 } else if let Some(local) = self.as_local_mut() {
5516 let buffer_id = buffer.read(cx).remote_id();
5517 local.buffers_being_formatted.insert(buffer_id);
5518 cx.spawn(async move |this, cx| {
5519 let _cleanup = defer({
5520 let this = this.clone();
5521 let mut cx = cx.clone();
5522 move || {
5523 this.update(&mut cx, |this, _| {
5524 if let Some(local) = this.as_local_mut() {
5525 local.buffers_being_formatted.remove(&buffer_id);
5526 }
5527 })
5528 .ok();
5529 }
5530 });
5531
5532 buffer
5533 .update(cx, |buffer, _| {
5534 buffer.wait_for_edits(Some(position.timestamp))
5535 })
5536 .await?;
5537 this.update(cx, |this, cx| {
5538 let position = position.to_point_utf16(buffer.read(cx));
5539 this.on_type_format(buffer, position, trigger, false, cx)
5540 })?
5541 .await
5542 })
5543 } else {
5544 Task::ready(Err(anyhow!("No upstream client or local language server")))
5545 }
5546 }
5547
5548 pub fn on_type_format<T: ToPointUtf16>(
5549 &mut self,
5550 buffer: Entity<Buffer>,
5551 position: T,
5552 trigger: String,
5553 push_to_history: bool,
5554 cx: &mut Context<Self>,
5555 ) -> Task<Result<Option<Transaction>>> {
5556 let position = position.to_point_utf16(buffer.read(cx));
5557 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5558 }
5559
5560 fn on_type_format_impl(
5561 &mut self,
5562 buffer: Entity<Buffer>,
5563 position: PointUtf16,
5564 trigger: String,
5565 push_to_history: bool,
5566 cx: &mut Context<Self>,
5567 ) -> Task<Result<Option<Transaction>>> {
5568 let options = buffer.update(cx, |buffer, cx| {
5569 lsp_command::lsp_formatting_options(
5570 language_settings(
5571 buffer.language_at(position).map(|l| l.name()),
5572 buffer.file(),
5573 cx,
5574 )
5575 .as_ref(),
5576 )
5577 });
5578
5579 cx.spawn(async move |this, cx| {
5580 if let Some(waiter) =
5581 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5582 {
5583 waiter.await?;
5584 }
5585 cx.update(|cx| {
5586 this.update(cx, |this, cx| {
5587 this.request_lsp(
5588 buffer.clone(),
5589 LanguageServerToQuery::FirstCapable,
5590 OnTypeFormatting {
5591 position,
5592 trigger,
5593 options,
5594 push_to_history,
5595 },
5596 cx,
5597 )
5598 })
5599 })?
5600 .await
5601 })
5602 }
5603
5604 pub fn definitions(
5605 &mut self,
5606 buffer: &Entity<Buffer>,
5607 position: PointUtf16,
5608 cx: &mut Context<Self>,
5609 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5610 if let Some((upstream_client, project_id)) = self.upstream_client() {
5611 let request = GetDefinitions { position };
5612 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5613 return Task::ready(Ok(None));
5614 }
5615 let request_task = upstream_client.request_lsp(
5616 project_id,
5617 None,
5618 LSP_REQUEST_TIMEOUT,
5619 cx.background_executor().clone(),
5620 request.to_proto(project_id, buffer.read(cx)),
5621 );
5622 let buffer = buffer.clone();
5623 cx.spawn(async move |weak_lsp_store, cx| {
5624 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5625 return Ok(None);
5626 };
5627 let Some(responses) = request_task.await? else {
5628 return Ok(None);
5629 };
5630 let actions = join_all(responses.payload.into_iter().map(|response| {
5631 GetDefinitions { position }.response_from_proto(
5632 response.response,
5633 lsp_store.clone(),
5634 buffer.clone(),
5635 cx.clone(),
5636 )
5637 }))
5638 .await;
5639
5640 Ok(Some(
5641 actions
5642 .into_iter()
5643 .collect::<Result<Vec<Vec<_>>>>()?
5644 .into_iter()
5645 .flatten()
5646 .dedup()
5647 .collect(),
5648 ))
5649 })
5650 } else {
5651 let definitions_task = self.request_multiple_lsp_locally(
5652 buffer,
5653 Some(position),
5654 GetDefinitions { position },
5655 cx,
5656 );
5657 cx.background_spawn(async move {
5658 Ok(Some(
5659 definitions_task
5660 .await
5661 .into_iter()
5662 .flat_map(|(_, definitions)| definitions)
5663 .dedup()
5664 .collect(),
5665 ))
5666 })
5667 }
5668 }
5669
5670 pub fn declarations(
5671 &mut self,
5672 buffer: &Entity<Buffer>,
5673 position: PointUtf16,
5674 cx: &mut Context<Self>,
5675 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5676 if let Some((upstream_client, project_id)) = self.upstream_client() {
5677 let request = GetDeclarations { position };
5678 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5679 return Task::ready(Ok(None));
5680 }
5681 let request_task = upstream_client.request_lsp(
5682 project_id,
5683 None,
5684 LSP_REQUEST_TIMEOUT,
5685 cx.background_executor().clone(),
5686 request.to_proto(project_id, buffer.read(cx)),
5687 );
5688 let buffer = buffer.clone();
5689 cx.spawn(async move |weak_lsp_store, cx| {
5690 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5691 return Ok(None);
5692 };
5693 let Some(responses) = request_task.await? else {
5694 return Ok(None);
5695 };
5696 let actions = join_all(responses.payload.into_iter().map(|response| {
5697 GetDeclarations { position }.response_from_proto(
5698 response.response,
5699 lsp_store.clone(),
5700 buffer.clone(),
5701 cx.clone(),
5702 )
5703 }))
5704 .await;
5705
5706 Ok(Some(
5707 actions
5708 .into_iter()
5709 .collect::<Result<Vec<Vec<_>>>>()?
5710 .into_iter()
5711 .flatten()
5712 .dedup()
5713 .collect(),
5714 ))
5715 })
5716 } else {
5717 let declarations_task = self.request_multiple_lsp_locally(
5718 buffer,
5719 Some(position),
5720 GetDeclarations { position },
5721 cx,
5722 );
5723 cx.background_spawn(async move {
5724 Ok(Some(
5725 declarations_task
5726 .await
5727 .into_iter()
5728 .flat_map(|(_, declarations)| declarations)
5729 .dedup()
5730 .collect(),
5731 ))
5732 })
5733 }
5734 }
5735
5736 pub fn type_definitions(
5737 &mut self,
5738 buffer: &Entity<Buffer>,
5739 position: PointUtf16,
5740 cx: &mut Context<Self>,
5741 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5742 if let Some((upstream_client, project_id)) = self.upstream_client() {
5743 let request = GetTypeDefinitions { position };
5744 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5745 return Task::ready(Ok(None));
5746 }
5747 let request_task = upstream_client.request_lsp(
5748 project_id,
5749 None,
5750 LSP_REQUEST_TIMEOUT,
5751 cx.background_executor().clone(),
5752 request.to_proto(project_id, buffer.read(cx)),
5753 );
5754 let buffer = buffer.clone();
5755 cx.spawn(async move |weak_lsp_store, cx| {
5756 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5757 return Ok(None);
5758 };
5759 let Some(responses) = request_task.await? else {
5760 return Ok(None);
5761 };
5762 let actions = join_all(responses.payload.into_iter().map(|response| {
5763 GetTypeDefinitions { position }.response_from_proto(
5764 response.response,
5765 lsp_store.clone(),
5766 buffer.clone(),
5767 cx.clone(),
5768 )
5769 }))
5770 .await;
5771
5772 Ok(Some(
5773 actions
5774 .into_iter()
5775 .collect::<Result<Vec<Vec<_>>>>()?
5776 .into_iter()
5777 .flatten()
5778 .dedup()
5779 .collect(),
5780 ))
5781 })
5782 } else {
5783 let type_definitions_task = self.request_multiple_lsp_locally(
5784 buffer,
5785 Some(position),
5786 GetTypeDefinitions { position },
5787 cx,
5788 );
5789 cx.background_spawn(async move {
5790 Ok(Some(
5791 type_definitions_task
5792 .await
5793 .into_iter()
5794 .flat_map(|(_, type_definitions)| type_definitions)
5795 .dedup()
5796 .collect(),
5797 ))
5798 })
5799 }
5800 }
5801
5802 pub fn implementations(
5803 &mut self,
5804 buffer: &Entity<Buffer>,
5805 position: PointUtf16,
5806 cx: &mut Context<Self>,
5807 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5808 if let Some((upstream_client, project_id)) = self.upstream_client() {
5809 let request = GetImplementations { position };
5810 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5811 return Task::ready(Ok(None));
5812 }
5813 let request_task = upstream_client.request_lsp(
5814 project_id,
5815 None,
5816 LSP_REQUEST_TIMEOUT,
5817 cx.background_executor().clone(),
5818 request.to_proto(project_id, buffer.read(cx)),
5819 );
5820 let buffer = buffer.clone();
5821 cx.spawn(async move |weak_lsp_store, cx| {
5822 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5823 return Ok(None);
5824 };
5825 let Some(responses) = request_task.await? else {
5826 return Ok(None);
5827 };
5828 let actions = join_all(responses.payload.into_iter().map(|response| {
5829 GetImplementations { position }.response_from_proto(
5830 response.response,
5831 lsp_store.clone(),
5832 buffer.clone(),
5833 cx.clone(),
5834 )
5835 }))
5836 .await;
5837
5838 Ok(Some(
5839 actions
5840 .into_iter()
5841 .collect::<Result<Vec<Vec<_>>>>()?
5842 .into_iter()
5843 .flatten()
5844 .dedup()
5845 .collect(),
5846 ))
5847 })
5848 } else {
5849 let implementations_task = self.request_multiple_lsp_locally(
5850 buffer,
5851 Some(position),
5852 GetImplementations { position },
5853 cx,
5854 );
5855 cx.background_spawn(async move {
5856 Ok(Some(
5857 implementations_task
5858 .await
5859 .into_iter()
5860 .flat_map(|(_, implementations)| implementations)
5861 .dedup()
5862 .collect(),
5863 ))
5864 })
5865 }
5866 }
5867
5868 pub fn references(
5869 &mut self,
5870 buffer: &Entity<Buffer>,
5871 position: PointUtf16,
5872 cx: &mut Context<Self>,
5873 ) -> Task<Result<Option<Vec<Location>>>> {
5874 if let Some((upstream_client, project_id)) = self.upstream_client() {
5875 let request = GetReferences { position };
5876 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5877 return Task::ready(Ok(None));
5878 }
5879
5880 let request_task = upstream_client.request_lsp(
5881 project_id,
5882 None,
5883 LSP_REQUEST_TIMEOUT,
5884 cx.background_executor().clone(),
5885 request.to_proto(project_id, buffer.read(cx)),
5886 );
5887 let buffer = buffer.clone();
5888 cx.spawn(async move |weak_lsp_store, cx| {
5889 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5890 return Ok(None);
5891 };
5892 let Some(responses) = request_task.await? else {
5893 return Ok(None);
5894 };
5895
5896 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5897 GetReferences { position }.response_from_proto(
5898 lsp_response.response,
5899 lsp_store.clone(),
5900 buffer.clone(),
5901 cx.clone(),
5902 )
5903 }))
5904 .await
5905 .into_iter()
5906 .collect::<Result<Vec<Vec<_>>>>()?
5907 .into_iter()
5908 .flatten()
5909 .dedup()
5910 .collect();
5911 Ok(Some(locations))
5912 })
5913 } else {
5914 let references_task = self.request_multiple_lsp_locally(
5915 buffer,
5916 Some(position),
5917 GetReferences { position },
5918 cx,
5919 );
5920 cx.background_spawn(async move {
5921 Ok(Some(
5922 references_task
5923 .await
5924 .into_iter()
5925 .flat_map(|(_, references)| references)
5926 .dedup()
5927 .collect(),
5928 ))
5929 })
5930 }
5931 }
5932
5933 pub fn code_actions(
5934 &mut self,
5935 buffer: &Entity<Buffer>,
5936 range: Range<Anchor>,
5937 kinds: Option<Vec<CodeActionKind>>,
5938 cx: &mut Context<Self>,
5939 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5940 if let Some((upstream_client, project_id)) = self.upstream_client() {
5941 let request = GetCodeActions {
5942 range: range.clone(),
5943 kinds: kinds.clone(),
5944 };
5945 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5946 return Task::ready(Ok(None));
5947 }
5948 let request_task = upstream_client.request_lsp(
5949 project_id,
5950 None,
5951 LSP_REQUEST_TIMEOUT,
5952 cx.background_executor().clone(),
5953 request.to_proto(project_id, buffer.read(cx)),
5954 );
5955 let buffer = buffer.clone();
5956 cx.spawn(async move |weak_lsp_store, cx| {
5957 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5958 return Ok(None);
5959 };
5960 let Some(responses) = request_task.await? else {
5961 return Ok(None);
5962 };
5963 let actions = join_all(responses.payload.into_iter().map(|response| {
5964 GetCodeActions {
5965 range: range.clone(),
5966 kinds: kinds.clone(),
5967 }
5968 .response_from_proto(
5969 response.response,
5970 lsp_store.clone(),
5971 buffer.clone(),
5972 cx.clone(),
5973 )
5974 }))
5975 .await;
5976
5977 Ok(Some(
5978 actions
5979 .into_iter()
5980 .collect::<Result<Vec<Vec<_>>>>()?
5981 .into_iter()
5982 .flatten()
5983 .collect(),
5984 ))
5985 })
5986 } else {
5987 let all_actions_task = self.request_multiple_lsp_locally(
5988 buffer,
5989 Some(range.start),
5990 GetCodeActions { range, kinds },
5991 cx,
5992 );
5993 cx.background_spawn(async move {
5994 Ok(Some(
5995 all_actions_task
5996 .await
5997 .into_iter()
5998 .flat_map(|(_, actions)| actions)
5999 .collect(),
6000 ))
6001 })
6002 }
6003 }
6004
6005 pub fn code_lens_actions(
6006 &mut self,
6007 buffer: &Entity<Buffer>,
6008 cx: &mut Context<Self>,
6009 ) -> CodeLensTask {
6010 let version_queried_for = buffer.read(cx).version();
6011 let buffer_id = buffer.read(cx).remote_id();
6012 let existing_servers = self.as_local().map(|local| {
6013 local
6014 .buffers_opened_in_servers
6015 .get(&buffer_id)
6016 .cloned()
6017 .unwrap_or_default()
6018 });
6019
6020 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6021 if let Some(cached_lens) = &lsp_data.code_lens {
6022 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6023 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6024 existing_servers != cached_lens.lens.keys().copied().collect()
6025 });
6026 if !has_different_servers {
6027 return Task::ready(Ok(Some(
6028 cached_lens.lens.values().flatten().cloned().collect(),
6029 )))
6030 .shared();
6031 }
6032 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6033 if !version_queried_for.changed_since(updating_for) {
6034 return running_update.clone();
6035 }
6036 }
6037 }
6038 }
6039
6040 let lens_lsp_data = self
6041 .latest_lsp_data(buffer, cx)
6042 .code_lens
6043 .get_or_insert_default();
6044 let buffer = buffer.clone();
6045 let query_version_queried_for = version_queried_for.clone();
6046 let new_task = cx
6047 .spawn(async move |lsp_store, cx| {
6048 cx.background_executor()
6049 .timer(Duration::from_millis(30))
6050 .await;
6051 let fetched_lens = lsp_store
6052 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6053 .map_err(Arc::new)?
6054 .await
6055 .context("fetching code lens")
6056 .map_err(Arc::new);
6057 let fetched_lens = match fetched_lens {
6058 Ok(fetched_lens) => fetched_lens,
6059 Err(e) => {
6060 lsp_store
6061 .update(cx, |lsp_store, _| {
6062 if let Some(lens_lsp_data) = lsp_store
6063 .lsp_data
6064 .get_mut(&buffer_id)
6065 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6066 {
6067 lens_lsp_data.update = None;
6068 }
6069 })
6070 .ok();
6071 return Err(e);
6072 }
6073 };
6074
6075 lsp_store
6076 .update(cx, |lsp_store, _| {
6077 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6078 let code_lens = lsp_data.code_lens.as_mut()?;
6079 if let Some(fetched_lens) = fetched_lens {
6080 if lsp_data.buffer_version == query_version_queried_for {
6081 code_lens.lens.extend(fetched_lens);
6082 } else if !lsp_data
6083 .buffer_version
6084 .changed_since(&query_version_queried_for)
6085 {
6086 lsp_data.buffer_version = query_version_queried_for;
6087 code_lens.lens = fetched_lens;
6088 }
6089 }
6090 code_lens.update = None;
6091 Some(code_lens.lens.values().flatten().cloned().collect())
6092 })
6093 .map_err(Arc::new)
6094 })
6095 .shared();
6096 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6097 new_task
6098 }
6099
6100 fn fetch_code_lens(
6101 &mut self,
6102 buffer: &Entity<Buffer>,
6103 cx: &mut Context<Self>,
6104 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6105 if let Some((upstream_client, project_id)) = self.upstream_client() {
6106 let request = GetCodeLens;
6107 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6108 return Task::ready(Ok(None));
6109 }
6110 let request_task = upstream_client.request_lsp(
6111 project_id,
6112 None,
6113 LSP_REQUEST_TIMEOUT,
6114 cx.background_executor().clone(),
6115 request.to_proto(project_id, buffer.read(cx)),
6116 );
6117 let buffer = buffer.clone();
6118 cx.spawn(async move |weak_lsp_store, cx| {
6119 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6120 return Ok(None);
6121 };
6122 let Some(responses) = request_task.await? else {
6123 return Ok(None);
6124 };
6125
6126 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6127 let lsp_store = lsp_store.clone();
6128 let buffer = buffer.clone();
6129 let cx = cx.clone();
6130 async move {
6131 (
6132 LanguageServerId::from_proto(response.server_id),
6133 GetCodeLens
6134 .response_from_proto(response.response, lsp_store, buffer, cx)
6135 .await,
6136 )
6137 }
6138 }))
6139 .await;
6140
6141 let mut has_errors = false;
6142 let code_lens_actions = code_lens_actions
6143 .into_iter()
6144 .filter_map(|(server_id, code_lens)| match code_lens {
6145 Ok(code_lens) => Some((server_id, code_lens)),
6146 Err(e) => {
6147 has_errors = true;
6148 log::error!("{e:#}");
6149 None
6150 }
6151 })
6152 .collect::<HashMap<_, _>>();
6153 anyhow::ensure!(
6154 !has_errors || !code_lens_actions.is_empty(),
6155 "Failed to fetch code lens"
6156 );
6157 Ok(Some(code_lens_actions))
6158 })
6159 } else {
6160 let code_lens_actions_task =
6161 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6162 cx.background_spawn(async move {
6163 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6164 })
6165 }
6166 }
6167
6168 #[inline(never)]
6169 pub fn completions(
6170 &self,
6171 buffer: &Entity<Buffer>,
6172 position: PointUtf16,
6173 context: CompletionContext,
6174 cx: &mut Context<Self>,
6175 ) -> Task<Result<Vec<CompletionResponse>>> {
6176 let language_registry = self.languages.clone();
6177
6178 if let Some((upstream_client, project_id)) = self.upstream_client() {
6179 let snapshot = buffer.read(cx).snapshot();
6180 let offset = position.to_offset(&snapshot);
6181 let scope = snapshot.language_scope_at(offset);
6182 let capable_lsps = self.all_capable_for_proto_request(
6183 buffer,
6184 |server_name, capabilities| {
6185 capabilities.completion_provider.is_some()
6186 && scope
6187 .as_ref()
6188 .map(|scope| scope.language_allowed(server_name))
6189 .unwrap_or(true)
6190 },
6191 cx,
6192 );
6193 if capable_lsps.is_empty() {
6194 return Task::ready(Ok(Vec::new()));
6195 }
6196
6197 let language = buffer.read(cx).language().cloned();
6198
6199 // In the future, we should provide project guests with the names of LSP adapters,
6200 // so that they can use the correct LSP adapter when computing labels. For now,
6201 // guests just use the first LSP adapter associated with the buffer's language.
6202 let lsp_adapter = language.as_ref().and_then(|language| {
6203 language_registry
6204 .lsp_adapters(&language.name())
6205 .first()
6206 .cloned()
6207 });
6208
6209 let buffer = buffer.clone();
6210
6211 cx.spawn(async move |this, cx| {
6212 let requests = join_all(
6213 capable_lsps
6214 .into_iter()
6215 .map(|id| {
6216 let request = GetCompletions {
6217 position,
6218 context: context.clone(),
6219 server_id: Some(id),
6220 };
6221 let buffer = buffer.clone();
6222 let language = language.clone();
6223 let lsp_adapter = lsp_adapter.clone();
6224 let upstream_client = upstream_client.clone();
6225 let response = this
6226 .update(cx, |this, cx| {
6227 this.send_lsp_proto_request(
6228 buffer,
6229 upstream_client,
6230 project_id,
6231 request,
6232 cx,
6233 )
6234 })
6235 .log_err();
6236 async move {
6237 let response = response?.await.log_err()?;
6238
6239 let completions = populate_labels_for_completions(
6240 response.completions,
6241 language,
6242 lsp_adapter,
6243 )
6244 .await;
6245
6246 Some(CompletionResponse {
6247 completions,
6248 display_options: CompletionDisplayOptions::default(),
6249 is_incomplete: response.is_incomplete,
6250 })
6251 }
6252 })
6253 .collect::<Vec<_>>(),
6254 );
6255 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6256 })
6257 } else if let Some(local) = self.as_local() {
6258 let snapshot = buffer.read(cx).snapshot();
6259 let offset = position.to_offset(&snapshot);
6260 let scope = snapshot.language_scope_at(offset);
6261 let language = snapshot.language().cloned();
6262 let completion_settings = language_settings(
6263 language.as_ref().map(|language| language.name()),
6264 buffer.read(cx).file(),
6265 cx,
6266 )
6267 .completions
6268 .clone();
6269 if !completion_settings.lsp {
6270 return Task::ready(Ok(Vec::new()));
6271 }
6272
6273 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6274 local
6275 .language_servers_for_buffer(buffer, cx)
6276 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6277 .filter(|(adapter, _)| {
6278 scope
6279 .as_ref()
6280 .map(|scope| scope.language_allowed(&adapter.name))
6281 .unwrap_or(true)
6282 })
6283 .map(|(_, server)| server.server_id())
6284 .collect()
6285 });
6286
6287 let buffer = buffer.clone();
6288 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6289 let lsp_timeout = if lsp_timeout > 0 {
6290 Some(Duration::from_millis(lsp_timeout))
6291 } else {
6292 None
6293 };
6294 cx.spawn(async move |this, cx| {
6295 let mut tasks = Vec::with_capacity(server_ids.len());
6296 this.update(cx, |lsp_store, cx| {
6297 for server_id in server_ids {
6298 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6299 let lsp_timeout = lsp_timeout
6300 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6301 let mut timeout = cx.background_spawn(async move {
6302 match lsp_timeout {
6303 Some(lsp_timeout) => {
6304 lsp_timeout.await;
6305 true
6306 },
6307 None => false,
6308 }
6309 }).fuse();
6310 let mut lsp_request = lsp_store.request_lsp(
6311 buffer.clone(),
6312 LanguageServerToQuery::Other(server_id),
6313 GetCompletions {
6314 position,
6315 context: context.clone(),
6316 server_id: Some(server_id),
6317 },
6318 cx,
6319 ).fuse();
6320 let new_task = cx.background_spawn(async move {
6321 select_biased! {
6322 response = lsp_request => anyhow::Ok(Some(response?)),
6323 timeout_happened = timeout => {
6324 if timeout_happened {
6325 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6326 Ok(None)
6327 } else {
6328 let completions = lsp_request.await?;
6329 Ok(Some(completions))
6330 }
6331 },
6332 }
6333 });
6334 tasks.push((lsp_adapter, new_task));
6335 }
6336 })?;
6337
6338 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6339 let completion_response = task.await.ok()??;
6340 let completions = populate_labels_for_completions(
6341 completion_response.completions,
6342 language.clone(),
6343 lsp_adapter,
6344 )
6345 .await;
6346 Some(CompletionResponse {
6347 completions,
6348 display_options: CompletionDisplayOptions::default(),
6349 is_incomplete: completion_response.is_incomplete,
6350 })
6351 });
6352
6353 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6354
6355 Ok(responses.into_iter().flatten().collect())
6356 })
6357 } else {
6358 Task::ready(Err(anyhow!("No upstream client or local language server")))
6359 }
6360 }
6361
6362 pub fn resolve_completions(
6363 &self,
6364 buffer: Entity<Buffer>,
6365 completion_indices: Vec<usize>,
6366 completions: Rc<RefCell<Box<[Completion]>>>,
6367 cx: &mut Context<Self>,
6368 ) -> Task<Result<bool>> {
6369 let client = self.upstream_client();
6370 let buffer_id = buffer.read(cx).remote_id();
6371 let buffer_snapshot = buffer.read(cx).snapshot();
6372
6373 if !self.check_if_capable_for_proto_request(
6374 &buffer,
6375 GetCompletions::can_resolve_completions,
6376 cx,
6377 ) {
6378 return Task::ready(Ok(false));
6379 }
6380 cx.spawn(async move |lsp_store, cx| {
6381 let mut did_resolve = false;
6382 if let Some((client, project_id)) = client {
6383 for completion_index in completion_indices {
6384 let server_id = {
6385 let completion = &completions.borrow()[completion_index];
6386 completion.source.server_id()
6387 };
6388 if let Some(server_id) = server_id {
6389 if Self::resolve_completion_remote(
6390 project_id,
6391 server_id,
6392 buffer_id,
6393 completions.clone(),
6394 completion_index,
6395 client.clone(),
6396 )
6397 .await
6398 .log_err()
6399 .is_some()
6400 {
6401 did_resolve = true;
6402 }
6403 } else {
6404 resolve_word_completion(
6405 &buffer_snapshot,
6406 &mut completions.borrow_mut()[completion_index],
6407 );
6408 }
6409 }
6410 } else {
6411 for completion_index in completion_indices {
6412 let server_id = {
6413 let completion = &completions.borrow()[completion_index];
6414 completion.source.server_id()
6415 };
6416 if let Some(server_id) = server_id {
6417 let server_and_adapter = lsp_store
6418 .read_with(cx, |lsp_store, _| {
6419 let server = lsp_store.language_server_for_id(server_id)?;
6420 let adapter =
6421 lsp_store.language_server_adapter_for_id(server.server_id())?;
6422 Some((server, adapter))
6423 })
6424 .ok()
6425 .flatten();
6426 let Some((server, adapter)) = server_and_adapter else {
6427 continue;
6428 };
6429
6430 let resolved = Self::resolve_completion_local(
6431 server,
6432 completions.clone(),
6433 completion_index,
6434 )
6435 .await
6436 .log_err()
6437 .is_some();
6438 if resolved {
6439 Self::regenerate_completion_labels(
6440 adapter,
6441 &buffer_snapshot,
6442 completions.clone(),
6443 completion_index,
6444 )
6445 .await
6446 .log_err();
6447 did_resolve = true;
6448 }
6449 } else {
6450 resolve_word_completion(
6451 &buffer_snapshot,
6452 &mut completions.borrow_mut()[completion_index],
6453 );
6454 }
6455 }
6456 }
6457
6458 Ok(did_resolve)
6459 })
6460 }
6461
6462 async fn resolve_completion_local(
6463 server: Arc<lsp::LanguageServer>,
6464 completions: Rc<RefCell<Box<[Completion]>>>,
6465 completion_index: usize,
6466 ) -> Result<()> {
6467 let server_id = server.server_id();
6468 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6469 return Ok(());
6470 }
6471
6472 let request = {
6473 let completion = &completions.borrow()[completion_index];
6474 match &completion.source {
6475 CompletionSource::Lsp {
6476 lsp_completion,
6477 resolved,
6478 server_id: completion_server_id,
6479 ..
6480 } => {
6481 if *resolved {
6482 return Ok(());
6483 }
6484 anyhow::ensure!(
6485 server_id == *completion_server_id,
6486 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6487 );
6488 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6489 }
6490 CompletionSource::BufferWord { .. }
6491 | CompletionSource::Dap { .. }
6492 | CompletionSource::Custom => {
6493 return Ok(());
6494 }
6495 }
6496 };
6497 let resolved_completion = request
6498 .await
6499 .into_response()
6500 .context("resolve completion")?;
6501
6502 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6503 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6504
6505 let mut completions = completions.borrow_mut();
6506 let completion = &mut completions[completion_index];
6507 if let CompletionSource::Lsp {
6508 lsp_completion,
6509 resolved,
6510 server_id: completion_server_id,
6511 ..
6512 } = &mut completion.source
6513 {
6514 if *resolved {
6515 return Ok(());
6516 }
6517 anyhow::ensure!(
6518 server_id == *completion_server_id,
6519 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6520 );
6521 **lsp_completion = resolved_completion;
6522 *resolved = true;
6523 }
6524 Ok(())
6525 }
6526
6527 async fn regenerate_completion_labels(
6528 adapter: Arc<CachedLspAdapter>,
6529 snapshot: &BufferSnapshot,
6530 completions: Rc<RefCell<Box<[Completion]>>>,
6531 completion_index: usize,
6532 ) -> Result<()> {
6533 let completion_item = completions.borrow()[completion_index]
6534 .source
6535 .lsp_completion(true)
6536 .map(Cow::into_owned);
6537 if let Some(lsp_documentation) = completion_item
6538 .as_ref()
6539 .and_then(|completion_item| completion_item.documentation.clone())
6540 {
6541 let mut completions = completions.borrow_mut();
6542 let completion = &mut completions[completion_index];
6543 completion.documentation = Some(lsp_documentation.into());
6544 } else {
6545 let mut completions = completions.borrow_mut();
6546 let completion = &mut completions[completion_index];
6547 completion.documentation = Some(CompletionDocumentation::Undocumented);
6548 }
6549
6550 let mut new_label = match completion_item {
6551 Some(completion_item) => {
6552 // Some language servers always return `detail` lazily via resolve, regardless of
6553 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6554 // See: https://github.com/yioneko/vtsls/issues/213
6555 let language = snapshot.language();
6556 match language {
6557 Some(language) => {
6558 adapter
6559 .labels_for_completions(
6560 std::slice::from_ref(&completion_item),
6561 language,
6562 )
6563 .await?
6564 }
6565 None => Vec::new(),
6566 }
6567 .pop()
6568 .flatten()
6569 .unwrap_or_else(|| {
6570 CodeLabel::fallback_for_completion(
6571 &completion_item,
6572 language.map(|language| language.as_ref()),
6573 )
6574 })
6575 }
6576 None => CodeLabel::plain(
6577 completions.borrow()[completion_index].new_text.clone(),
6578 None,
6579 ),
6580 };
6581 ensure_uniform_list_compatible_label(&mut new_label);
6582
6583 let mut completions = completions.borrow_mut();
6584 let completion = &mut completions[completion_index];
6585 if completion.label.filter_text() == new_label.filter_text() {
6586 completion.label = new_label;
6587 } else {
6588 log::error!(
6589 "Resolved completion changed display label from {} to {}. \
6590 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6591 completion.label.text(),
6592 new_label.text(),
6593 completion.label.filter_text(),
6594 new_label.filter_text()
6595 );
6596 }
6597
6598 Ok(())
6599 }
6600
6601 async fn resolve_completion_remote(
6602 project_id: u64,
6603 server_id: LanguageServerId,
6604 buffer_id: BufferId,
6605 completions: Rc<RefCell<Box<[Completion]>>>,
6606 completion_index: usize,
6607 client: AnyProtoClient,
6608 ) -> Result<()> {
6609 let lsp_completion = {
6610 let completion = &completions.borrow()[completion_index];
6611 match &completion.source {
6612 CompletionSource::Lsp {
6613 lsp_completion,
6614 resolved,
6615 server_id: completion_server_id,
6616 ..
6617 } => {
6618 anyhow::ensure!(
6619 server_id == *completion_server_id,
6620 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6621 );
6622 if *resolved {
6623 return Ok(());
6624 }
6625 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6626 }
6627 CompletionSource::Custom
6628 | CompletionSource::Dap { .. }
6629 | CompletionSource::BufferWord { .. } => {
6630 return Ok(());
6631 }
6632 }
6633 };
6634 let request = proto::ResolveCompletionDocumentation {
6635 project_id,
6636 language_server_id: server_id.0 as u64,
6637 lsp_completion,
6638 buffer_id: buffer_id.into(),
6639 };
6640
6641 let response = client
6642 .request(request)
6643 .await
6644 .context("completion documentation resolve proto request")?;
6645 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6646
6647 let documentation = if response.documentation.is_empty() {
6648 CompletionDocumentation::Undocumented
6649 } else if response.documentation_is_markdown {
6650 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6651 } else if response.documentation.lines().count() <= 1 {
6652 CompletionDocumentation::SingleLine(response.documentation.into())
6653 } else {
6654 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6655 };
6656
6657 let mut completions = completions.borrow_mut();
6658 let completion = &mut completions[completion_index];
6659 completion.documentation = Some(documentation);
6660 if let CompletionSource::Lsp {
6661 insert_range,
6662 lsp_completion,
6663 resolved,
6664 server_id: completion_server_id,
6665 lsp_defaults: _,
6666 } = &mut completion.source
6667 {
6668 let completion_insert_range = response
6669 .old_insert_start
6670 .and_then(deserialize_anchor)
6671 .zip(response.old_insert_end.and_then(deserialize_anchor));
6672 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6673
6674 if *resolved {
6675 return Ok(());
6676 }
6677 anyhow::ensure!(
6678 server_id == *completion_server_id,
6679 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6680 );
6681 **lsp_completion = resolved_lsp_completion;
6682 *resolved = true;
6683 }
6684
6685 let replace_range = response
6686 .old_replace_start
6687 .and_then(deserialize_anchor)
6688 .zip(response.old_replace_end.and_then(deserialize_anchor));
6689 if let Some((old_replace_start, old_replace_end)) = replace_range
6690 && !response.new_text.is_empty()
6691 {
6692 completion.new_text = response.new_text;
6693 completion.replace_range = old_replace_start..old_replace_end;
6694 }
6695
6696 Ok(())
6697 }
6698
6699 pub fn apply_additional_edits_for_completion(
6700 &self,
6701 buffer_handle: Entity<Buffer>,
6702 completions: Rc<RefCell<Box<[Completion]>>>,
6703 completion_index: usize,
6704 push_to_history: bool,
6705 cx: &mut Context<Self>,
6706 ) -> Task<Result<Option<Transaction>>> {
6707 if let Some((client, project_id)) = self.upstream_client() {
6708 let buffer = buffer_handle.read(cx);
6709 let buffer_id = buffer.remote_id();
6710 cx.spawn(async move |_, cx| {
6711 let request = {
6712 let completion = completions.borrow()[completion_index].clone();
6713 proto::ApplyCompletionAdditionalEdits {
6714 project_id,
6715 buffer_id: buffer_id.into(),
6716 completion: Some(Self::serialize_completion(&CoreCompletion {
6717 replace_range: completion.replace_range,
6718 new_text: completion.new_text,
6719 source: completion.source,
6720 })),
6721 }
6722 };
6723
6724 if let Some(transaction) = client.request(request).await?.transaction {
6725 let transaction = language::proto::deserialize_transaction(transaction)?;
6726 buffer_handle
6727 .update(cx, |buffer, _| {
6728 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6729 })
6730 .await?;
6731 if push_to_history {
6732 buffer_handle.update(cx, |buffer, _| {
6733 buffer.push_transaction(transaction.clone(), Instant::now());
6734 buffer.finalize_last_transaction();
6735 });
6736 }
6737 Ok(Some(transaction))
6738 } else {
6739 Ok(None)
6740 }
6741 })
6742 } else {
6743 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6744 let completion = &completions.borrow()[completion_index];
6745 let server_id = completion.source.server_id()?;
6746 Some(
6747 self.language_server_for_local_buffer(buffer, server_id, cx)?
6748 .1
6749 .clone(),
6750 )
6751 }) else {
6752 return Task::ready(Ok(None));
6753 };
6754
6755 cx.spawn(async move |this, cx| {
6756 Self::resolve_completion_local(
6757 server.clone(),
6758 completions.clone(),
6759 completion_index,
6760 )
6761 .await
6762 .context("resolving completion")?;
6763 let completion = completions.borrow()[completion_index].clone();
6764 let additional_text_edits = completion
6765 .source
6766 .lsp_completion(true)
6767 .as_ref()
6768 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6769 if let Some(edits) = additional_text_edits {
6770 let edits = this
6771 .update(cx, |this, cx| {
6772 this.as_local_mut().unwrap().edits_from_lsp(
6773 &buffer_handle,
6774 edits,
6775 server.server_id(),
6776 None,
6777 cx,
6778 )
6779 })?
6780 .await?;
6781
6782 buffer_handle.update(cx, |buffer, cx| {
6783 buffer.finalize_last_transaction();
6784 buffer.start_transaction();
6785
6786 for (range, text) in edits {
6787 let primary = &completion.replace_range;
6788
6789 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6790 // and the primary completion is just an insertion (empty range), then this is likely
6791 // an auto-import scenario and should not be considered overlapping
6792 // https://github.com/zed-industries/zed/issues/26136
6793 let is_file_start_auto_import = {
6794 let snapshot = buffer.snapshot();
6795 let primary_start_point = primary.start.to_point(&snapshot);
6796 let range_start_point = range.start.to_point(&snapshot);
6797
6798 let result = primary_start_point.row == 0
6799 && primary_start_point.column == 0
6800 && range_start_point.row == 0
6801 && range_start_point.column == 0;
6802
6803 result
6804 };
6805
6806 let has_overlap = if is_file_start_auto_import {
6807 false
6808 } else {
6809 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6810 && primary.end.cmp(&range.start, buffer).is_ge();
6811 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6812 && range.end.cmp(&primary.end, buffer).is_ge();
6813 let result = start_within || end_within;
6814 result
6815 };
6816
6817 //Skip additional edits which overlap with the primary completion edit
6818 //https://github.com/zed-industries/zed/pull/1871
6819 if !has_overlap {
6820 buffer.edit([(range, text)], None, cx);
6821 }
6822 }
6823
6824 let transaction = if buffer.end_transaction(cx).is_some() {
6825 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6826 if !push_to_history {
6827 buffer.forget_transaction(transaction.id);
6828 }
6829 Some(transaction)
6830 } else {
6831 None
6832 };
6833 Ok(transaction)
6834 })
6835 } else {
6836 Ok(None)
6837 }
6838 })
6839 }
6840 }
6841
6842 pub fn pull_diagnostics(
6843 &mut self,
6844 buffer: Entity<Buffer>,
6845 cx: &mut Context<Self>,
6846 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6847 let buffer_id = buffer.read(cx).remote_id();
6848
6849 if let Some((client, upstream_project_id)) = self.upstream_client() {
6850 let mut suitable_capabilities = None;
6851 // Are we capable for proto request?
6852 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6853 &buffer,
6854 |capabilities| {
6855 if let Some(caps) = &capabilities.diagnostic_provider {
6856 suitable_capabilities = Some(caps.clone());
6857 true
6858 } else {
6859 false
6860 }
6861 },
6862 cx,
6863 );
6864 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6865 let Some(dynamic_caps) = suitable_capabilities else {
6866 return Task::ready(Ok(None));
6867 };
6868 assert!(any_server_has_diagnostics_provider);
6869
6870 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6871 let request = GetDocumentDiagnostics {
6872 previous_result_id: None,
6873 identifier,
6874 registration_id: None,
6875 };
6876 let request_task = client.request_lsp(
6877 upstream_project_id,
6878 None,
6879 LSP_REQUEST_TIMEOUT,
6880 cx.background_executor().clone(),
6881 request.to_proto(upstream_project_id, buffer.read(cx)),
6882 );
6883 cx.background_spawn(async move {
6884 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6885 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6886 // Do not attempt to further process the dummy responses here.
6887 let _response = request_task.await?;
6888 Ok(None)
6889 })
6890 } else {
6891 let servers = buffer.update(cx, |buffer, cx| {
6892 self.running_language_servers_for_local_buffer(buffer, cx)
6893 .map(|(_, server)| server.clone())
6894 .collect::<Vec<_>>()
6895 });
6896
6897 let pull_diagnostics = servers
6898 .into_iter()
6899 .flat_map(|server| {
6900 let result = maybe!({
6901 let local = self.as_local()?;
6902 let server_id = server.server_id();
6903 let providers_with_identifiers = local
6904 .language_server_dynamic_registrations
6905 .get(&server_id)
6906 .into_iter()
6907 .flat_map(|registrations| registrations.diagnostics.clone())
6908 .collect::<Vec<_>>();
6909 Some(
6910 providers_with_identifiers
6911 .into_iter()
6912 .map(|(registration_id, dynamic_caps)| {
6913 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6914 let registration_id = registration_id.map(SharedString::from);
6915 let result_id = self.result_id_for_buffer_pull(
6916 server_id,
6917 buffer_id,
6918 ®istration_id,
6919 cx,
6920 );
6921 self.request_lsp(
6922 buffer.clone(),
6923 LanguageServerToQuery::Other(server_id),
6924 GetDocumentDiagnostics {
6925 previous_result_id: result_id,
6926 registration_id,
6927 identifier,
6928 },
6929 cx,
6930 )
6931 })
6932 .collect::<Vec<_>>(),
6933 )
6934 });
6935
6936 result.unwrap_or_default()
6937 })
6938 .collect::<Vec<_>>();
6939
6940 cx.background_spawn(async move {
6941 let mut responses = Vec::new();
6942 for diagnostics in join_all(pull_diagnostics).await {
6943 responses.extend(diagnostics?);
6944 }
6945 Ok(Some(responses))
6946 })
6947 }
6948 }
6949
6950 pub fn applicable_inlay_chunks(
6951 &mut self,
6952 buffer: &Entity<Buffer>,
6953 ranges: &[Range<text::Anchor>],
6954 cx: &mut Context<Self>,
6955 ) -> Vec<Range<BufferRow>> {
6956 let buffer_snapshot = buffer.read(cx).snapshot();
6957 let ranges = ranges
6958 .iter()
6959 .map(|range| range.to_point(&buffer_snapshot))
6960 .collect::<Vec<_>>();
6961
6962 self.latest_lsp_data(buffer, cx)
6963 .inlay_hints
6964 .applicable_chunks(ranges.as_slice())
6965 .map(|chunk| chunk.row_range())
6966 .collect()
6967 }
6968
6969 pub fn invalidate_inlay_hints<'a>(
6970 &'a mut self,
6971 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6972 ) {
6973 for buffer_id in for_buffers {
6974 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6975 lsp_data.inlay_hints.clear();
6976 }
6977 }
6978 }
6979
6980 pub fn inlay_hints(
6981 &mut self,
6982 invalidate: InvalidationStrategy,
6983 buffer: Entity<Buffer>,
6984 ranges: Vec<Range<text::Anchor>>,
6985 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6986 cx: &mut Context<Self>,
6987 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6988 let next_hint_id = self.next_hint_id.clone();
6989 let lsp_data = self.latest_lsp_data(&buffer, cx);
6990 let query_version = lsp_data.buffer_version.clone();
6991 let mut lsp_refresh_requested = false;
6992 let for_server = if let InvalidationStrategy::RefreshRequested {
6993 server_id,
6994 request_id,
6995 } = invalidate
6996 {
6997 let invalidated = lsp_data
6998 .inlay_hints
6999 .invalidate_for_server_refresh(server_id, request_id);
7000 lsp_refresh_requested = invalidated;
7001 Some(server_id)
7002 } else {
7003 None
7004 };
7005 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7006 let known_chunks = known_chunks
7007 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7008 .map(|(_, known_chunks)| known_chunks)
7009 .unwrap_or_default();
7010
7011 let buffer_snapshot = buffer.read(cx).snapshot();
7012 let ranges = ranges
7013 .iter()
7014 .map(|range| range.to_point(&buffer_snapshot))
7015 .collect::<Vec<_>>();
7016
7017 let mut hint_fetch_tasks = Vec::new();
7018 let mut cached_inlay_hints = None;
7019 let mut ranges_to_query = None;
7020 let applicable_chunks = existing_inlay_hints
7021 .applicable_chunks(ranges.as_slice())
7022 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7023 .collect::<Vec<_>>();
7024 if applicable_chunks.is_empty() {
7025 return HashMap::default();
7026 }
7027
7028 for row_chunk in applicable_chunks {
7029 match (
7030 existing_inlay_hints
7031 .cached_hints(&row_chunk)
7032 .filter(|_| !lsp_refresh_requested)
7033 .cloned(),
7034 existing_inlay_hints
7035 .fetched_hints(&row_chunk)
7036 .as_ref()
7037 .filter(|_| !lsp_refresh_requested)
7038 .cloned(),
7039 ) {
7040 (None, None) => {
7041 let chunk_range = row_chunk.anchor_range();
7042 ranges_to_query
7043 .get_or_insert_with(Vec::new)
7044 .push((row_chunk, chunk_range));
7045 }
7046 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7047 (Some(cached_hints), None) => {
7048 for (server_id, cached_hints) in cached_hints {
7049 if for_server.is_none_or(|for_server| for_server == server_id) {
7050 cached_inlay_hints
7051 .get_or_insert_with(HashMap::default)
7052 .entry(row_chunk.row_range())
7053 .or_insert_with(HashMap::default)
7054 .entry(server_id)
7055 .or_insert_with(Vec::new)
7056 .extend(cached_hints);
7057 }
7058 }
7059 }
7060 (Some(cached_hints), Some(fetched_hints)) => {
7061 hint_fetch_tasks.push((row_chunk, fetched_hints));
7062 for (server_id, cached_hints) in cached_hints {
7063 if for_server.is_none_or(|for_server| for_server == server_id) {
7064 cached_inlay_hints
7065 .get_or_insert_with(HashMap::default)
7066 .entry(row_chunk.row_range())
7067 .or_insert_with(HashMap::default)
7068 .entry(server_id)
7069 .or_insert_with(Vec::new)
7070 .extend(cached_hints);
7071 }
7072 }
7073 }
7074 }
7075 }
7076
7077 if hint_fetch_tasks.is_empty()
7078 && ranges_to_query
7079 .as_ref()
7080 .is_none_or(|ranges| ranges.is_empty())
7081 && let Some(cached_inlay_hints) = cached_inlay_hints
7082 {
7083 cached_inlay_hints
7084 .into_iter()
7085 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7086 .collect()
7087 } else {
7088 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7089 let next_hint_id = next_hint_id.clone();
7090 let buffer = buffer.clone();
7091 let query_version = query_version.clone();
7092 let new_inlay_hints = cx
7093 .spawn(async move |lsp_store, cx| {
7094 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7095 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7096 })?;
7097 new_fetch_task
7098 .await
7099 .and_then(|new_hints_by_server| {
7100 lsp_store.update(cx, |lsp_store, cx| {
7101 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7102 let update_cache = lsp_data.buffer_version == query_version;
7103 if new_hints_by_server.is_empty() {
7104 if update_cache {
7105 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7106 }
7107 HashMap::default()
7108 } else {
7109 new_hints_by_server
7110 .into_iter()
7111 .map(|(server_id, new_hints)| {
7112 let new_hints = new_hints
7113 .into_iter()
7114 .map(|new_hint| {
7115 (
7116 InlayId::Hint(next_hint_id.fetch_add(
7117 1,
7118 atomic::Ordering::AcqRel,
7119 )),
7120 new_hint,
7121 )
7122 })
7123 .collect::<Vec<_>>();
7124 if update_cache {
7125 lsp_data.inlay_hints.insert_new_hints(
7126 chunk,
7127 server_id,
7128 new_hints.clone(),
7129 );
7130 }
7131 (server_id, new_hints)
7132 })
7133 .collect()
7134 }
7135 })
7136 })
7137 .map_err(Arc::new)
7138 })
7139 .shared();
7140
7141 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7142 *fetch_task = Some(new_inlay_hints.clone());
7143 hint_fetch_tasks.push((chunk, new_inlay_hints));
7144 }
7145
7146 cached_inlay_hints
7147 .unwrap_or_default()
7148 .into_iter()
7149 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7150 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7151 (
7152 chunk.row_range(),
7153 cx.spawn(async move |_, _| {
7154 hints_fetch.await.map_err(|e| {
7155 if e.error_code() != ErrorCode::Internal {
7156 anyhow!(e.error_code())
7157 } else {
7158 anyhow!("{e:#}")
7159 }
7160 })
7161 }),
7162 )
7163 }))
7164 .collect()
7165 }
7166 }
7167
7168 fn fetch_inlay_hints(
7169 &mut self,
7170 for_server: Option<LanguageServerId>,
7171 buffer: &Entity<Buffer>,
7172 range: Range<Anchor>,
7173 cx: &mut Context<Self>,
7174 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7175 let request = InlayHints {
7176 range: range.clone(),
7177 };
7178 if let Some((upstream_client, project_id)) = self.upstream_client() {
7179 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7180 return Task::ready(Ok(HashMap::default()));
7181 }
7182 let request_task = upstream_client.request_lsp(
7183 project_id,
7184 for_server.map(|id| id.to_proto()),
7185 LSP_REQUEST_TIMEOUT,
7186 cx.background_executor().clone(),
7187 request.to_proto(project_id, buffer.read(cx)),
7188 );
7189 let buffer = buffer.clone();
7190 cx.spawn(async move |weak_lsp_store, cx| {
7191 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7192 return Ok(HashMap::default());
7193 };
7194 let Some(responses) = request_task.await? else {
7195 return Ok(HashMap::default());
7196 };
7197
7198 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7199 let lsp_store = lsp_store.clone();
7200 let buffer = buffer.clone();
7201 let cx = cx.clone();
7202 let request = request.clone();
7203 async move {
7204 (
7205 LanguageServerId::from_proto(response.server_id),
7206 request
7207 .response_from_proto(response.response, lsp_store, buffer, cx)
7208 .await,
7209 )
7210 }
7211 }))
7212 .await;
7213
7214 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7215 let mut has_errors = false;
7216 let inlay_hints = inlay_hints
7217 .into_iter()
7218 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7219 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7220 Err(e) => {
7221 has_errors = true;
7222 log::error!("{e:#}");
7223 None
7224 }
7225 })
7226 .map(|(server_id, mut new_hints)| {
7227 new_hints.retain(|hint| {
7228 hint.position.is_valid(&buffer_snapshot)
7229 && range.start.is_valid(&buffer_snapshot)
7230 && range.end.is_valid(&buffer_snapshot)
7231 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7232 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7233 });
7234 (server_id, new_hints)
7235 })
7236 .collect::<HashMap<_, _>>();
7237 anyhow::ensure!(
7238 !has_errors || !inlay_hints.is_empty(),
7239 "Failed to fetch inlay hints"
7240 );
7241 Ok(inlay_hints)
7242 })
7243 } else {
7244 let inlay_hints_task = match for_server {
7245 Some(server_id) => {
7246 let server_task = self.request_lsp(
7247 buffer.clone(),
7248 LanguageServerToQuery::Other(server_id),
7249 request,
7250 cx,
7251 );
7252 cx.background_spawn(async move {
7253 let mut responses = Vec::new();
7254 match server_task.await {
7255 Ok(response) => responses.push((server_id, response)),
7256 // rust-analyzer likes to error with this when its still loading up
7257 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7258 Err(e) => log::error!(
7259 "Error handling response for inlay hints request: {e:#}"
7260 ),
7261 }
7262 responses
7263 })
7264 }
7265 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7266 };
7267 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7268 cx.background_spawn(async move {
7269 Ok(inlay_hints_task
7270 .await
7271 .into_iter()
7272 .map(|(server_id, mut new_hints)| {
7273 new_hints.retain(|hint| {
7274 hint.position.is_valid(&buffer_snapshot)
7275 && range.start.is_valid(&buffer_snapshot)
7276 && range.end.is_valid(&buffer_snapshot)
7277 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7278 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7279 });
7280 (server_id, new_hints)
7281 })
7282 .collect())
7283 })
7284 }
7285 }
7286
7287 fn diagnostic_registration_exists(
7288 &self,
7289 server_id: LanguageServerId,
7290 registration_id: &Option<SharedString>,
7291 ) -> bool {
7292 let Some(local) = self.as_local() else {
7293 return false;
7294 };
7295 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7296 else {
7297 return false;
7298 };
7299 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7300 registrations.diagnostics.contains_key(®istration_key)
7301 }
7302
7303 pub fn pull_diagnostics_for_buffer(
7304 &mut self,
7305 buffer: Entity<Buffer>,
7306 cx: &mut Context<Self>,
7307 ) -> Task<anyhow::Result<()>> {
7308 let diagnostics = self.pull_diagnostics(buffer, cx);
7309 cx.spawn(async move |lsp_store, cx| {
7310 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7311 return Ok(());
7312 };
7313 lsp_store.update(cx, |lsp_store, cx| {
7314 if lsp_store.as_local().is_none() {
7315 return;
7316 }
7317
7318 let mut unchanged_buffers = HashMap::default();
7319 let server_diagnostics_updates = diagnostics
7320 .into_iter()
7321 .filter_map(|diagnostics_set| match diagnostics_set {
7322 LspPullDiagnostics::Response {
7323 server_id,
7324 uri,
7325 diagnostics,
7326 registration_id,
7327 } => Some((server_id, uri, diagnostics, registration_id)),
7328 LspPullDiagnostics::Default => None,
7329 })
7330 .filter(|(server_id, _, _, registration_id)| {
7331 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7332 })
7333 .fold(
7334 HashMap::default(),
7335 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7336 let (result_id, diagnostics) = match diagnostics {
7337 PulledDiagnostics::Unchanged { result_id } => {
7338 unchanged_buffers
7339 .entry(new_registration_id.clone())
7340 .or_insert_with(HashSet::default)
7341 .insert(uri.clone());
7342 (Some(result_id), Vec::new())
7343 }
7344 PulledDiagnostics::Changed {
7345 result_id,
7346 diagnostics,
7347 } => (result_id, diagnostics),
7348 };
7349 let disk_based_sources = Cow::Owned(
7350 lsp_store
7351 .language_server_adapter_for_id(server_id)
7352 .as_ref()
7353 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7354 .unwrap_or(&[])
7355 .to_vec(),
7356 );
7357 acc.entry(server_id)
7358 .or_insert_with(HashMap::default)
7359 .entry(new_registration_id.clone())
7360 .or_insert_with(Vec::new)
7361 .push(DocumentDiagnosticsUpdate {
7362 server_id,
7363 diagnostics: lsp::PublishDiagnosticsParams {
7364 uri,
7365 diagnostics,
7366 version: None,
7367 },
7368 result_id,
7369 disk_based_sources,
7370 registration_id: new_registration_id,
7371 });
7372 acc
7373 },
7374 );
7375
7376 for diagnostic_updates in server_diagnostics_updates.into_values() {
7377 for (registration_id, diagnostic_updates) in diagnostic_updates {
7378 lsp_store
7379 .merge_lsp_diagnostics(
7380 DiagnosticSourceKind::Pulled,
7381 diagnostic_updates,
7382 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7383 DiagnosticSourceKind::Pulled => {
7384 old_diagnostic.registration_id != registration_id
7385 || unchanged_buffers
7386 .get(&old_diagnostic.registration_id)
7387 .is_some_and(|unchanged_buffers| {
7388 unchanged_buffers.contains(&document_uri)
7389 })
7390 }
7391 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7392 true
7393 }
7394 },
7395 cx,
7396 )
7397 .log_err();
7398 }
7399 }
7400 })
7401 })
7402 }
7403
7404 pub fn document_colors(
7405 &mut self,
7406 known_cache_version: Option<usize>,
7407 buffer: Entity<Buffer>,
7408 cx: &mut Context<Self>,
7409 ) -> Option<DocumentColorTask> {
7410 let version_queried_for = buffer.read(cx).version();
7411 let buffer_id = buffer.read(cx).remote_id();
7412
7413 let current_language_servers = self.as_local().map(|local| {
7414 local
7415 .buffers_opened_in_servers
7416 .get(&buffer_id)
7417 .cloned()
7418 .unwrap_or_default()
7419 });
7420
7421 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7422 if let Some(cached_colors) = &lsp_data.document_colors {
7423 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7424 let has_different_servers =
7425 current_language_servers.is_some_and(|current_language_servers| {
7426 current_language_servers
7427 != cached_colors.colors.keys().copied().collect()
7428 });
7429 if !has_different_servers {
7430 let cache_version = cached_colors.cache_version;
7431 if Some(cache_version) == known_cache_version {
7432 return None;
7433 } else {
7434 return Some(
7435 Task::ready(Ok(DocumentColors {
7436 colors: cached_colors
7437 .colors
7438 .values()
7439 .flatten()
7440 .cloned()
7441 .collect(),
7442 cache_version: Some(cache_version),
7443 }))
7444 .shared(),
7445 );
7446 }
7447 }
7448 }
7449 }
7450 }
7451
7452 let color_lsp_data = self
7453 .latest_lsp_data(&buffer, cx)
7454 .document_colors
7455 .get_or_insert_default();
7456 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7457 && !version_queried_for.changed_since(updating_for)
7458 {
7459 return Some(running_update.clone());
7460 }
7461 let buffer_version_queried_for = version_queried_for.clone();
7462 let new_task = cx
7463 .spawn(async move |lsp_store, cx| {
7464 cx.background_executor()
7465 .timer(Duration::from_millis(30))
7466 .await;
7467 let fetched_colors = lsp_store
7468 .update(cx, |lsp_store, cx| {
7469 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7470 })?
7471 .await
7472 .context("fetching document colors")
7473 .map_err(Arc::new);
7474 let fetched_colors = match fetched_colors {
7475 Ok(fetched_colors) => {
7476 if buffer.update(cx, |buffer, _| {
7477 buffer.version() != buffer_version_queried_for
7478 }) {
7479 return Ok(DocumentColors::default());
7480 }
7481 fetched_colors
7482 }
7483 Err(e) => {
7484 lsp_store
7485 .update(cx, |lsp_store, _| {
7486 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7487 if let Some(document_colors) = &mut lsp_data.document_colors {
7488 document_colors.colors_update = None;
7489 }
7490 }
7491 })
7492 .ok();
7493 return Err(e);
7494 }
7495 };
7496
7497 lsp_store
7498 .update(cx, |lsp_store, cx| {
7499 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7500 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7501
7502 if let Some(fetched_colors) = fetched_colors {
7503 if lsp_data.buffer_version == buffer_version_queried_for {
7504 lsp_colors.colors.extend(fetched_colors);
7505 lsp_colors.cache_version += 1;
7506 } else if !lsp_data
7507 .buffer_version
7508 .changed_since(&buffer_version_queried_for)
7509 {
7510 lsp_data.buffer_version = buffer_version_queried_for;
7511 lsp_colors.colors = fetched_colors;
7512 lsp_colors.cache_version += 1;
7513 }
7514 }
7515 lsp_colors.colors_update = None;
7516 let colors = lsp_colors
7517 .colors
7518 .values()
7519 .flatten()
7520 .cloned()
7521 .collect::<HashSet<_>>();
7522 DocumentColors {
7523 colors,
7524 cache_version: Some(lsp_colors.cache_version),
7525 }
7526 })
7527 .map_err(Arc::new)
7528 })
7529 .shared();
7530 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7531 Some(new_task)
7532 }
7533
7534 fn fetch_document_colors_for_buffer(
7535 &mut self,
7536 buffer: &Entity<Buffer>,
7537 cx: &mut Context<Self>,
7538 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7539 if let Some((client, project_id)) = self.upstream_client() {
7540 let request = GetDocumentColor {};
7541 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7542 return Task::ready(Ok(None));
7543 }
7544
7545 let request_task = client.request_lsp(
7546 project_id,
7547 None,
7548 LSP_REQUEST_TIMEOUT,
7549 cx.background_executor().clone(),
7550 request.to_proto(project_id, buffer.read(cx)),
7551 );
7552 let buffer = buffer.clone();
7553 cx.spawn(async move |lsp_store, cx| {
7554 let Some(lsp_store) = lsp_store.upgrade() else {
7555 return Ok(None);
7556 };
7557 let colors = join_all(
7558 request_task
7559 .await
7560 .log_err()
7561 .flatten()
7562 .map(|response| response.payload)
7563 .unwrap_or_default()
7564 .into_iter()
7565 .map(|color_response| {
7566 let response = request.response_from_proto(
7567 color_response.response,
7568 lsp_store.clone(),
7569 buffer.clone(),
7570 cx.clone(),
7571 );
7572 async move {
7573 (
7574 LanguageServerId::from_proto(color_response.server_id),
7575 response.await.log_err().unwrap_or_default(),
7576 )
7577 }
7578 }),
7579 )
7580 .await
7581 .into_iter()
7582 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7583 acc.entry(server_id)
7584 .or_insert_with(HashSet::default)
7585 .extend(colors);
7586 acc
7587 });
7588 Ok(Some(colors))
7589 })
7590 } else {
7591 let document_colors_task =
7592 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7593 cx.background_spawn(async move {
7594 Ok(Some(
7595 document_colors_task
7596 .await
7597 .into_iter()
7598 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7599 acc.entry(server_id)
7600 .or_insert_with(HashSet::default)
7601 .extend(colors);
7602 acc
7603 })
7604 .into_iter()
7605 .collect(),
7606 ))
7607 })
7608 }
7609 }
7610
7611 pub fn signature_help<T: ToPointUtf16>(
7612 &mut self,
7613 buffer: &Entity<Buffer>,
7614 position: T,
7615 cx: &mut Context<Self>,
7616 ) -> Task<Option<Vec<SignatureHelp>>> {
7617 let position = position.to_point_utf16(buffer.read(cx));
7618
7619 if let Some((client, upstream_project_id)) = self.upstream_client() {
7620 let request = GetSignatureHelp { position };
7621 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7622 return Task::ready(None);
7623 }
7624 let request_task = client.request_lsp(
7625 upstream_project_id,
7626 None,
7627 LSP_REQUEST_TIMEOUT,
7628 cx.background_executor().clone(),
7629 request.to_proto(upstream_project_id, buffer.read(cx)),
7630 );
7631 let buffer = buffer.clone();
7632 cx.spawn(async move |weak_lsp_store, cx| {
7633 let lsp_store = weak_lsp_store.upgrade()?;
7634 let signatures = join_all(
7635 request_task
7636 .await
7637 .log_err()
7638 .flatten()
7639 .map(|response| response.payload)
7640 .unwrap_or_default()
7641 .into_iter()
7642 .map(|response| {
7643 let response = GetSignatureHelp { position }.response_from_proto(
7644 response.response,
7645 lsp_store.clone(),
7646 buffer.clone(),
7647 cx.clone(),
7648 );
7649 async move { response.await.log_err().flatten() }
7650 }),
7651 )
7652 .await
7653 .into_iter()
7654 .flatten()
7655 .collect();
7656 Some(signatures)
7657 })
7658 } else {
7659 let all_actions_task = self.request_multiple_lsp_locally(
7660 buffer,
7661 Some(position),
7662 GetSignatureHelp { position },
7663 cx,
7664 );
7665 cx.background_spawn(async move {
7666 Some(
7667 all_actions_task
7668 .await
7669 .into_iter()
7670 .flat_map(|(_, actions)| actions)
7671 .collect::<Vec<_>>(),
7672 )
7673 })
7674 }
7675 }
7676
7677 pub fn hover(
7678 &mut self,
7679 buffer: &Entity<Buffer>,
7680 position: PointUtf16,
7681 cx: &mut Context<Self>,
7682 ) -> Task<Option<Vec<Hover>>> {
7683 if let Some((client, upstream_project_id)) = self.upstream_client() {
7684 let request = GetHover { position };
7685 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7686 return Task::ready(None);
7687 }
7688 let request_task = client.request_lsp(
7689 upstream_project_id,
7690 None,
7691 LSP_REQUEST_TIMEOUT,
7692 cx.background_executor().clone(),
7693 request.to_proto(upstream_project_id, buffer.read(cx)),
7694 );
7695 let buffer = buffer.clone();
7696 cx.spawn(async move |weak_lsp_store, cx| {
7697 let lsp_store = weak_lsp_store.upgrade()?;
7698 let hovers = join_all(
7699 request_task
7700 .await
7701 .log_err()
7702 .flatten()
7703 .map(|response| response.payload)
7704 .unwrap_or_default()
7705 .into_iter()
7706 .map(|response| {
7707 let response = GetHover { position }.response_from_proto(
7708 response.response,
7709 lsp_store.clone(),
7710 buffer.clone(),
7711 cx.clone(),
7712 );
7713 async move {
7714 response
7715 .await
7716 .log_err()
7717 .flatten()
7718 .and_then(remove_empty_hover_blocks)
7719 }
7720 }),
7721 )
7722 .await
7723 .into_iter()
7724 .flatten()
7725 .collect();
7726 Some(hovers)
7727 })
7728 } else {
7729 let all_actions_task = self.request_multiple_lsp_locally(
7730 buffer,
7731 Some(position),
7732 GetHover { position },
7733 cx,
7734 );
7735 cx.background_spawn(async move {
7736 Some(
7737 all_actions_task
7738 .await
7739 .into_iter()
7740 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7741 .collect::<Vec<Hover>>(),
7742 )
7743 })
7744 }
7745 }
7746
7747 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7748 let language_registry = self.languages.clone();
7749
7750 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7751 let request = upstream_client.request(proto::GetProjectSymbols {
7752 project_id: *project_id,
7753 query: query.to_string(),
7754 });
7755 cx.foreground_executor().spawn(async move {
7756 let response = request.await?;
7757 let mut symbols = Vec::new();
7758 let core_symbols = response
7759 .symbols
7760 .into_iter()
7761 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7762 .collect::<Vec<_>>();
7763 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7764 .await;
7765 Ok(symbols)
7766 })
7767 } else if let Some(local) = self.as_local() {
7768 struct WorkspaceSymbolsResult {
7769 server_id: LanguageServerId,
7770 lsp_adapter: Arc<CachedLspAdapter>,
7771 worktree: WeakEntity<Worktree>,
7772 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7773 }
7774
7775 let mut requests = Vec::new();
7776 let mut requested_servers = BTreeSet::new();
7777 for (seed, state) in local.language_server_ids.iter() {
7778 let Some(worktree_handle) = self
7779 .worktree_store
7780 .read(cx)
7781 .worktree_for_id(seed.worktree_id, cx)
7782 else {
7783 continue;
7784 };
7785 let worktree = worktree_handle.read(cx);
7786 if !worktree.is_visible() {
7787 continue;
7788 }
7789
7790 if !requested_servers.insert(state.id) {
7791 continue;
7792 }
7793
7794 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7795 Some(LanguageServerState::Running {
7796 adapter, server, ..
7797 }) => (adapter.clone(), server),
7798
7799 _ => continue,
7800 };
7801 let supports_workspace_symbol_request =
7802 match server.capabilities().workspace_symbol_provider {
7803 Some(OneOf::Left(supported)) => supported,
7804 Some(OneOf::Right(_)) => true,
7805 None => false,
7806 };
7807 if !supports_workspace_symbol_request {
7808 continue;
7809 }
7810 let worktree_handle = worktree_handle.clone();
7811 let server_id = server.server_id();
7812 requests.push(
7813 server
7814 .request::<lsp::request::WorkspaceSymbolRequest>(
7815 lsp::WorkspaceSymbolParams {
7816 query: query.to_string(),
7817 ..Default::default()
7818 },
7819 )
7820 .map(move |response| {
7821 let lsp_symbols = response.into_response()
7822 .context("workspace symbols request")
7823 .log_err()
7824 .flatten()
7825 .map(|symbol_response| match symbol_response {
7826 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7827 flat_responses.into_iter().map(|lsp_symbol| {
7828 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7829 }).collect::<Vec<_>>()
7830 }
7831 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7832 nested_responses.into_iter().filter_map(|lsp_symbol| {
7833 let location = match lsp_symbol.location {
7834 OneOf::Left(location) => location,
7835 OneOf::Right(_) => {
7836 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7837 return None
7838 }
7839 };
7840 Some((lsp_symbol.name, lsp_symbol.kind, location))
7841 }).collect::<Vec<_>>()
7842 }
7843 }).unwrap_or_default();
7844
7845 WorkspaceSymbolsResult {
7846 server_id,
7847 lsp_adapter,
7848 worktree: worktree_handle.downgrade(),
7849 lsp_symbols,
7850 }
7851 }),
7852 );
7853 }
7854
7855 cx.spawn(async move |this, cx| {
7856 let responses = futures::future::join_all(requests).await;
7857 let this = match this.upgrade() {
7858 Some(this) => this,
7859 None => return Ok(Vec::new()),
7860 };
7861
7862 let mut symbols = Vec::new();
7863 for result in responses {
7864 let core_symbols = this.update(cx, |this, cx| {
7865 result
7866 .lsp_symbols
7867 .into_iter()
7868 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7869 let abs_path = symbol_location.uri.to_file_path().ok()?;
7870 let source_worktree = result.worktree.upgrade()?;
7871 let source_worktree_id = source_worktree.read(cx).id();
7872
7873 let path = if let Some((tree, rel_path)) =
7874 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7875 {
7876 let worktree_id = tree.read(cx).id();
7877 SymbolLocation::InProject(ProjectPath {
7878 worktree_id,
7879 path: rel_path,
7880 })
7881 } else {
7882 SymbolLocation::OutsideProject {
7883 signature: this.symbol_signature(&abs_path),
7884 abs_path: abs_path.into(),
7885 }
7886 };
7887
7888 Some(CoreSymbol {
7889 source_language_server_id: result.server_id,
7890 language_server_name: result.lsp_adapter.name.clone(),
7891 source_worktree_id,
7892 path,
7893 kind: symbol_kind,
7894 name: symbol_name,
7895 range: range_from_lsp(symbol_location.range),
7896 })
7897 })
7898 .collect::<Vec<_>>()
7899 });
7900
7901 populate_labels_for_symbols(
7902 core_symbols,
7903 &language_registry,
7904 Some(result.lsp_adapter),
7905 &mut symbols,
7906 )
7907 .await;
7908 }
7909
7910 Ok(symbols)
7911 })
7912 } else {
7913 Task::ready(Err(anyhow!("No upstream client or local language server")))
7914 }
7915 }
7916
7917 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7918 let mut summary = DiagnosticSummary::default();
7919 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7920 summary.error_count += path_summary.error_count;
7921 summary.warning_count += path_summary.warning_count;
7922 }
7923 summary
7924 }
7925
7926 /// Returns the diagnostic summary for a specific project path.
7927 pub fn diagnostic_summary_for_path(
7928 &self,
7929 project_path: &ProjectPath,
7930 _: &App,
7931 ) -> DiagnosticSummary {
7932 if let Some(summaries) = self
7933 .diagnostic_summaries
7934 .get(&project_path.worktree_id)
7935 .and_then(|map| map.get(&project_path.path))
7936 {
7937 let (error_count, warning_count) = summaries.iter().fold(
7938 (0, 0),
7939 |(error_count, warning_count), (_language_server_id, summary)| {
7940 (
7941 error_count + summary.error_count,
7942 warning_count + summary.warning_count,
7943 )
7944 },
7945 );
7946
7947 DiagnosticSummary {
7948 error_count,
7949 warning_count,
7950 }
7951 } else {
7952 DiagnosticSummary::default()
7953 }
7954 }
7955
7956 pub fn diagnostic_summaries<'a>(
7957 &'a self,
7958 include_ignored: bool,
7959 cx: &'a App,
7960 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7961 self.worktree_store
7962 .read(cx)
7963 .visible_worktrees(cx)
7964 .filter_map(|worktree| {
7965 let worktree = worktree.read(cx);
7966 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7967 })
7968 .flat_map(move |(worktree, summaries)| {
7969 let worktree_id = worktree.id();
7970 summaries
7971 .iter()
7972 .filter(move |(path, _)| {
7973 include_ignored
7974 || worktree
7975 .entry_for_path(path.as_ref())
7976 .is_some_and(|entry| !entry.is_ignored)
7977 })
7978 .flat_map(move |(path, summaries)| {
7979 summaries.iter().map(move |(server_id, summary)| {
7980 (
7981 ProjectPath {
7982 worktree_id,
7983 path: path.clone(),
7984 },
7985 *server_id,
7986 *summary,
7987 )
7988 })
7989 })
7990 })
7991 }
7992
7993 pub fn on_buffer_edited(
7994 &mut self,
7995 buffer: Entity<Buffer>,
7996 cx: &mut Context<Self>,
7997 ) -> Option<()> {
7998 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7999 Some(
8000 self.as_local()?
8001 .language_servers_for_buffer(buffer, cx)
8002 .map(|i| i.1.clone())
8003 .collect(),
8004 )
8005 })?;
8006
8007 let buffer = buffer.read(cx);
8008 let file = File::from_dyn(buffer.file())?;
8009 let abs_path = file.as_local()?.abs_path(cx);
8010 let uri = lsp::Uri::from_file_path(&abs_path)
8011 .ok()
8012 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8013 .log_err()?;
8014 let next_snapshot = buffer.text_snapshot();
8015 for language_server in language_servers {
8016 let language_server = language_server.clone();
8017
8018 let buffer_snapshots = self
8019 .as_local_mut()?
8020 .buffer_snapshots
8021 .get_mut(&buffer.remote_id())
8022 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8023 let previous_snapshot = buffer_snapshots.last()?;
8024
8025 let build_incremental_change = || {
8026 buffer
8027 .edits_since::<Dimensions<PointUtf16, usize>>(
8028 previous_snapshot.snapshot.version(),
8029 )
8030 .map(|edit| {
8031 let edit_start = edit.new.start.0;
8032 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8033 let new_text = next_snapshot
8034 .text_for_range(edit.new.start.1..edit.new.end.1)
8035 .collect();
8036 lsp::TextDocumentContentChangeEvent {
8037 range: Some(lsp::Range::new(
8038 point_to_lsp(edit_start),
8039 point_to_lsp(edit_end),
8040 )),
8041 range_length: None,
8042 text: new_text,
8043 }
8044 })
8045 .collect()
8046 };
8047
8048 let document_sync_kind = language_server
8049 .capabilities()
8050 .text_document_sync
8051 .as_ref()
8052 .and_then(|sync| match sync {
8053 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8054 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8055 });
8056
8057 let content_changes: Vec<_> = match document_sync_kind {
8058 Some(lsp::TextDocumentSyncKind::FULL) => {
8059 vec![lsp::TextDocumentContentChangeEvent {
8060 range: None,
8061 range_length: None,
8062 text: next_snapshot.text(),
8063 }]
8064 }
8065 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8066 _ => {
8067 #[cfg(any(test, feature = "test-support"))]
8068 {
8069 build_incremental_change()
8070 }
8071
8072 #[cfg(not(any(test, feature = "test-support")))]
8073 {
8074 continue;
8075 }
8076 }
8077 };
8078
8079 let next_version = previous_snapshot.version + 1;
8080 buffer_snapshots.push(LspBufferSnapshot {
8081 version: next_version,
8082 snapshot: next_snapshot.clone(),
8083 });
8084
8085 language_server
8086 .notify::<lsp::notification::DidChangeTextDocument>(
8087 lsp::DidChangeTextDocumentParams {
8088 text_document: lsp::VersionedTextDocumentIdentifier::new(
8089 uri.clone(),
8090 next_version,
8091 ),
8092 content_changes,
8093 },
8094 )
8095 .ok();
8096 self.pull_workspace_diagnostics(language_server.server_id());
8097 }
8098
8099 None
8100 }
8101
8102 pub fn on_buffer_saved(
8103 &mut self,
8104 buffer: Entity<Buffer>,
8105 cx: &mut Context<Self>,
8106 ) -> Option<()> {
8107 let file = File::from_dyn(buffer.read(cx).file())?;
8108 let worktree_id = file.worktree_id(cx);
8109 let abs_path = file.as_local()?.abs_path(cx);
8110 let text_document = lsp::TextDocumentIdentifier {
8111 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8112 };
8113 let local = self.as_local()?;
8114
8115 for server in local.language_servers_for_worktree(worktree_id) {
8116 if let Some(include_text) = include_text(server.as_ref()) {
8117 let text = if include_text {
8118 Some(buffer.read(cx).text())
8119 } else {
8120 None
8121 };
8122 server
8123 .notify::<lsp::notification::DidSaveTextDocument>(
8124 lsp::DidSaveTextDocumentParams {
8125 text_document: text_document.clone(),
8126 text,
8127 },
8128 )
8129 .ok();
8130 }
8131 }
8132
8133 let language_servers = buffer.update(cx, |buffer, cx| {
8134 local.language_server_ids_for_buffer(buffer, cx)
8135 });
8136 for language_server_id in language_servers {
8137 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8138 }
8139
8140 None
8141 }
8142
8143 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8144 maybe!(async move {
8145 let mut refreshed_servers = HashSet::default();
8146 let servers = lsp_store
8147 .update(cx, |lsp_store, cx| {
8148 let local = lsp_store.as_local()?;
8149
8150 let servers = local
8151 .language_server_ids
8152 .iter()
8153 .filter_map(|(seed, state)| {
8154 let worktree = lsp_store
8155 .worktree_store
8156 .read(cx)
8157 .worktree_for_id(seed.worktree_id, cx);
8158 let delegate: Arc<dyn LspAdapterDelegate> =
8159 worktree.map(|worktree| {
8160 LocalLspAdapterDelegate::new(
8161 local.languages.clone(),
8162 &local.environment,
8163 cx.weak_entity(),
8164 &worktree,
8165 local.http_client.clone(),
8166 local.fs.clone(),
8167 cx,
8168 )
8169 })?;
8170 let server_id = state.id;
8171
8172 let states = local.language_servers.get(&server_id)?;
8173
8174 match states {
8175 LanguageServerState::Starting { .. } => None,
8176 LanguageServerState::Running {
8177 adapter, server, ..
8178 } => {
8179 let adapter = adapter.clone();
8180 let server = server.clone();
8181 refreshed_servers.insert(server.name());
8182 let toolchain = seed.toolchain.clone();
8183 Some(cx.spawn(async move |_, cx| {
8184 let settings =
8185 LocalLspStore::workspace_configuration_for_adapter(
8186 adapter.adapter.clone(),
8187 &delegate,
8188 toolchain,
8189 None,
8190 cx,
8191 )
8192 .await
8193 .ok()?;
8194 server
8195 .notify::<lsp::notification::DidChangeConfiguration>(
8196 lsp::DidChangeConfigurationParams { settings },
8197 )
8198 .ok()?;
8199 Some(())
8200 }))
8201 }
8202 }
8203 })
8204 .collect::<Vec<_>>();
8205
8206 Some(servers)
8207 })
8208 .ok()
8209 .flatten()?;
8210
8211 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8212 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8213 // to stop and unregister its language server wrapper.
8214 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8215 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8216 let _: Vec<Option<()>> = join_all(servers).await;
8217
8218 Some(())
8219 })
8220 .await;
8221 }
8222
8223 fn maintain_workspace_config(
8224 external_refresh_requests: watch::Receiver<()>,
8225 cx: &mut Context<Self>,
8226 ) -> Task<Result<()>> {
8227 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8228 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8229
8230 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8231 *settings_changed_tx.borrow_mut() = ();
8232 });
8233
8234 let mut joint_future =
8235 futures::stream::select(settings_changed_rx, external_refresh_requests);
8236 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8237 // - 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).
8238 // - 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.
8239 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8240 // - 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,
8241 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8242 cx.spawn(async move |this, cx| {
8243 while let Some(()) = joint_future.next().await {
8244 this.update(cx, |this, cx| {
8245 this.refresh_server_tree(cx);
8246 })
8247 .ok();
8248
8249 Self::refresh_workspace_configurations(&this, cx).await;
8250 }
8251
8252 drop(settings_observation);
8253 anyhow::Ok(())
8254 })
8255 }
8256
8257 pub fn running_language_servers_for_local_buffer<'a>(
8258 &'a self,
8259 buffer: &Buffer,
8260 cx: &mut App,
8261 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8262 let local = self.as_local();
8263 let language_server_ids = local
8264 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8265 .unwrap_or_default();
8266
8267 language_server_ids
8268 .into_iter()
8269 .filter_map(
8270 move |server_id| match local?.language_servers.get(&server_id)? {
8271 LanguageServerState::Running {
8272 adapter, server, ..
8273 } => Some((adapter, server)),
8274 _ => None,
8275 },
8276 )
8277 }
8278
8279 pub fn language_servers_for_local_buffer(
8280 &self,
8281 buffer: &Buffer,
8282 cx: &mut App,
8283 ) -> Vec<LanguageServerId> {
8284 let local = self.as_local();
8285 local
8286 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8287 .unwrap_or_default()
8288 }
8289
8290 pub fn language_server_for_local_buffer<'a>(
8291 &'a self,
8292 buffer: &'a Buffer,
8293 server_id: LanguageServerId,
8294 cx: &'a mut App,
8295 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8296 self.as_local()?
8297 .language_servers_for_buffer(buffer, cx)
8298 .find(|(_, s)| s.server_id() == server_id)
8299 }
8300
8301 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8302 self.diagnostic_summaries.remove(&id_to_remove);
8303 if let Some(local) = self.as_local_mut() {
8304 let to_remove = local.remove_worktree(id_to_remove, cx);
8305 for server in to_remove {
8306 self.language_server_statuses.remove(&server);
8307 }
8308 }
8309 }
8310
8311 pub fn shared(
8312 &mut self,
8313 project_id: u64,
8314 downstream_client: AnyProtoClient,
8315 _: &mut Context<Self>,
8316 ) {
8317 self.downstream_client = Some((downstream_client.clone(), project_id));
8318
8319 for (server_id, status) in &self.language_server_statuses {
8320 if let Some(server) = self.language_server_for_id(*server_id) {
8321 downstream_client
8322 .send(proto::StartLanguageServer {
8323 project_id,
8324 server: Some(proto::LanguageServer {
8325 id: server_id.to_proto(),
8326 name: status.name.to_string(),
8327 worktree_id: status.worktree.map(|id| id.to_proto()),
8328 }),
8329 capabilities: serde_json::to_string(&server.capabilities())
8330 .expect("serializing server LSP capabilities"),
8331 })
8332 .log_err();
8333 }
8334 }
8335 }
8336
8337 pub fn disconnected_from_host(&mut self) {
8338 self.downstream_client.take();
8339 }
8340
8341 pub fn disconnected_from_ssh_remote(&mut self) {
8342 if let LspStoreMode::Remote(RemoteLspStore {
8343 upstream_client, ..
8344 }) = &mut self.mode
8345 {
8346 upstream_client.take();
8347 }
8348 }
8349
8350 pub(crate) fn set_language_server_statuses_from_proto(
8351 &mut self,
8352 project: WeakEntity<Project>,
8353 language_servers: Vec<proto::LanguageServer>,
8354 server_capabilities: Vec<String>,
8355 cx: &mut Context<Self>,
8356 ) {
8357 let lsp_logs = cx
8358 .try_global::<GlobalLogStore>()
8359 .map(|lsp_store| lsp_store.0.clone());
8360
8361 self.language_server_statuses = language_servers
8362 .into_iter()
8363 .zip(server_capabilities)
8364 .map(|(server, server_capabilities)| {
8365 let server_id = LanguageServerId(server.id as usize);
8366 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8367 self.lsp_server_capabilities
8368 .insert(server_id, server_capabilities);
8369 }
8370
8371 let name = LanguageServerName::from_proto(server.name);
8372 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8373
8374 if let Some(lsp_logs) = &lsp_logs {
8375 lsp_logs.update(cx, |lsp_logs, cx| {
8376 lsp_logs.add_language_server(
8377 // Only remote clients get their language servers set from proto
8378 LanguageServerKind::Remote {
8379 project: project.clone(),
8380 },
8381 server_id,
8382 Some(name.clone()),
8383 worktree,
8384 None,
8385 cx,
8386 );
8387 });
8388 }
8389
8390 (
8391 server_id,
8392 LanguageServerStatus {
8393 name,
8394 server_version: None,
8395 pending_work: Default::default(),
8396 has_pending_diagnostic_updates: false,
8397 progress_tokens: Default::default(),
8398 worktree,
8399 binary: None,
8400 configuration: None,
8401 workspace_folders: BTreeSet::new(),
8402 },
8403 )
8404 })
8405 .collect();
8406 }
8407
8408 #[cfg(test)]
8409 pub fn update_diagnostic_entries(
8410 &mut self,
8411 server_id: LanguageServerId,
8412 abs_path: PathBuf,
8413 result_id: Option<SharedString>,
8414 version: Option<i32>,
8415 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8416 cx: &mut Context<Self>,
8417 ) -> anyhow::Result<()> {
8418 self.merge_diagnostic_entries(
8419 vec![DocumentDiagnosticsUpdate {
8420 diagnostics: DocumentDiagnostics {
8421 diagnostics,
8422 document_abs_path: abs_path,
8423 version,
8424 },
8425 result_id,
8426 server_id,
8427 disk_based_sources: Cow::Borrowed(&[]),
8428 registration_id: None,
8429 }],
8430 |_, _, _| false,
8431 cx,
8432 )?;
8433 Ok(())
8434 }
8435
8436 pub fn merge_diagnostic_entries<'a>(
8437 &mut self,
8438 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8439 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8440 cx: &mut Context<Self>,
8441 ) -> anyhow::Result<()> {
8442 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8443 let mut updated_diagnostics_paths = HashMap::default();
8444 for mut update in diagnostic_updates {
8445 let abs_path = &update.diagnostics.document_abs_path;
8446 let server_id = update.server_id;
8447 let Some((worktree, relative_path)) =
8448 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8449 else {
8450 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8451 return Ok(());
8452 };
8453
8454 let worktree_id = worktree.read(cx).id();
8455 let project_path = ProjectPath {
8456 worktree_id,
8457 path: relative_path,
8458 };
8459
8460 let document_uri = lsp::Uri::from_file_path(abs_path)
8461 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8462 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8463 let snapshot = buffer_handle.read(cx).snapshot();
8464 let buffer = buffer_handle.read(cx);
8465 let reused_diagnostics = buffer
8466 .buffer_diagnostics(Some(server_id))
8467 .iter()
8468 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8469 .map(|v| {
8470 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8471 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8472 DiagnosticEntry {
8473 range: start..end,
8474 diagnostic: v.diagnostic.clone(),
8475 }
8476 })
8477 .collect::<Vec<_>>();
8478
8479 self.as_local_mut()
8480 .context("cannot merge diagnostics on a remote LspStore")?
8481 .update_buffer_diagnostics(
8482 &buffer_handle,
8483 server_id,
8484 Some(update.registration_id),
8485 update.result_id,
8486 update.diagnostics.version,
8487 update.diagnostics.diagnostics.clone(),
8488 reused_diagnostics.clone(),
8489 cx,
8490 )?;
8491
8492 update.diagnostics.diagnostics.extend(reused_diagnostics);
8493 } else if let Some(local) = self.as_local() {
8494 let reused_diagnostics = local
8495 .diagnostics
8496 .get(&worktree_id)
8497 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8498 .and_then(|diagnostics_by_server_id| {
8499 diagnostics_by_server_id
8500 .binary_search_by_key(&server_id, |e| e.0)
8501 .ok()
8502 .map(|ix| &diagnostics_by_server_id[ix].1)
8503 })
8504 .into_iter()
8505 .flatten()
8506 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8507
8508 update
8509 .diagnostics
8510 .diagnostics
8511 .extend(reused_diagnostics.cloned());
8512 }
8513
8514 let updated = worktree.update(cx, |worktree, cx| {
8515 self.update_worktree_diagnostics(
8516 worktree.id(),
8517 server_id,
8518 project_path.path.clone(),
8519 update.diagnostics.diagnostics,
8520 cx,
8521 )
8522 })?;
8523 match updated {
8524 ControlFlow::Continue(new_summary) => {
8525 if let Some((project_id, new_summary)) = new_summary {
8526 match &mut diagnostics_summary {
8527 Some(diagnostics_summary) => {
8528 diagnostics_summary
8529 .more_summaries
8530 .push(proto::DiagnosticSummary {
8531 path: project_path.path.as_ref().to_proto(),
8532 language_server_id: server_id.0 as u64,
8533 error_count: new_summary.error_count,
8534 warning_count: new_summary.warning_count,
8535 })
8536 }
8537 None => {
8538 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8539 project_id,
8540 worktree_id: worktree_id.to_proto(),
8541 summary: Some(proto::DiagnosticSummary {
8542 path: project_path.path.as_ref().to_proto(),
8543 language_server_id: server_id.0 as u64,
8544 error_count: new_summary.error_count,
8545 warning_count: new_summary.warning_count,
8546 }),
8547 more_summaries: Vec::new(),
8548 })
8549 }
8550 }
8551 }
8552 updated_diagnostics_paths
8553 .entry(server_id)
8554 .or_insert_with(Vec::new)
8555 .push(project_path);
8556 }
8557 ControlFlow::Break(()) => {}
8558 }
8559 }
8560
8561 if let Some((diagnostics_summary, (downstream_client, _))) =
8562 diagnostics_summary.zip(self.downstream_client.as_ref())
8563 {
8564 downstream_client.send(diagnostics_summary).log_err();
8565 }
8566 for (server_id, paths) in updated_diagnostics_paths {
8567 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8568 }
8569 Ok(())
8570 }
8571
8572 fn update_worktree_diagnostics(
8573 &mut self,
8574 worktree_id: WorktreeId,
8575 server_id: LanguageServerId,
8576 path_in_worktree: Arc<RelPath>,
8577 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8578 _: &mut Context<Worktree>,
8579 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8580 let local = match &mut self.mode {
8581 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8582 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8583 };
8584
8585 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8586 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8587 let summaries_by_server_id = summaries_for_tree
8588 .entry(path_in_worktree.clone())
8589 .or_default();
8590
8591 let old_summary = summaries_by_server_id
8592 .remove(&server_id)
8593 .unwrap_or_default();
8594
8595 let new_summary = DiagnosticSummary::new(&diagnostics);
8596 if diagnostics.is_empty() {
8597 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8598 {
8599 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8600 diagnostics_by_server_id.remove(ix);
8601 }
8602 if diagnostics_by_server_id.is_empty() {
8603 diagnostics_for_tree.remove(&path_in_worktree);
8604 }
8605 }
8606 } else {
8607 summaries_by_server_id.insert(server_id, new_summary);
8608 let diagnostics_by_server_id = diagnostics_for_tree
8609 .entry(path_in_worktree.clone())
8610 .or_default();
8611 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8612 Ok(ix) => {
8613 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8614 }
8615 Err(ix) => {
8616 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8617 }
8618 }
8619 }
8620
8621 if !old_summary.is_empty() || !new_summary.is_empty() {
8622 if let Some((_, project_id)) = &self.downstream_client {
8623 Ok(ControlFlow::Continue(Some((
8624 *project_id,
8625 proto::DiagnosticSummary {
8626 path: path_in_worktree.to_proto(),
8627 language_server_id: server_id.0 as u64,
8628 error_count: new_summary.error_count as u32,
8629 warning_count: new_summary.warning_count as u32,
8630 },
8631 ))))
8632 } else {
8633 Ok(ControlFlow::Continue(None))
8634 }
8635 } else {
8636 Ok(ControlFlow::Break(()))
8637 }
8638 }
8639
8640 pub fn open_buffer_for_symbol(
8641 &mut self,
8642 symbol: &Symbol,
8643 cx: &mut Context<Self>,
8644 ) -> Task<Result<Entity<Buffer>>> {
8645 if let Some((client, project_id)) = self.upstream_client() {
8646 let request = client.request(proto::OpenBufferForSymbol {
8647 project_id,
8648 symbol: Some(Self::serialize_symbol(symbol)),
8649 });
8650 cx.spawn(async move |this, cx| {
8651 let response = request.await?;
8652 let buffer_id = BufferId::new(response.buffer_id)?;
8653 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8654 .await
8655 })
8656 } else if let Some(local) = self.as_local() {
8657 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8658 seed.worktree_id == symbol.source_worktree_id
8659 && state.id == symbol.source_language_server_id
8660 && symbol.language_server_name == seed.name
8661 });
8662 if !is_valid {
8663 return Task::ready(Err(anyhow!(
8664 "language server for worktree and language not found"
8665 )));
8666 };
8667
8668 let symbol_abs_path = match &symbol.path {
8669 SymbolLocation::InProject(project_path) => self
8670 .worktree_store
8671 .read(cx)
8672 .absolutize(&project_path, cx)
8673 .context("no such worktree"),
8674 SymbolLocation::OutsideProject {
8675 abs_path,
8676 signature: _,
8677 } => Ok(abs_path.to_path_buf()),
8678 };
8679 let symbol_abs_path = match symbol_abs_path {
8680 Ok(abs_path) => abs_path,
8681 Err(err) => return Task::ready(Err(err)),
8682 };
8683 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8684 uri
8685 } else {
8686 return Task::ready(Err(anyhow!("invalid symbol path")));
8687 };
8688
8689 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8690 } else {
8691 Task::ready(Err(anyhow!("no upstream client or local store")))
8692 }
8693 }
8694
8695 pub(crate) fn open_local_buffer_via_lsp(
8696 &mut self,
8697 abs_path: lsp::Uri,
8698 language_server_id: LanguageServerId,
8699 cx: &mut Context<Self>,
8700 ) -> Task<Result<Entity<Buffer>>> {
8701 cx.spawn(async move |lsp_store, cx| {
8702 // Escape percent-encoded string.
8703 let current_scheme = abs_path.scheme().to_owned();
8704 // Uri is immutable, so we can't modify the scheme
8705
8706 let abs_path = abs_path
8707 .to_file_path()
8708 .map_err(|()| anyhow!("can't convert URI to path"))?;
8709 let p = abs_path.clone();
8710 let yarn_worktree = lsp_store
8711 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8712 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8713 cx.spawn(async move |this, cx| {
8714 let t = this
8715 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8716 .ok()?;
8717 t.await
8718 })
8719 }),
8720 None => Task::ready(None),
8721 })?
8722 .await;
8723 let (worktree_root_target, known_relative_path) =
8724 if let Some((zip_root, relative_path)) = yarn_worktree {
8725 (zip_root, Some(relative_path))
8726 } else {
8727 (Arc::<Path>::from(abs_path.as_path()), None)
8728 };
8729 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8730 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8731 worktree_store.find_worktree(&worktree_root_target, cx)
8732 })
8733 })?;
8734 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8735 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8736 (result.0, relative_path, None)
8737 } else {
8738 let worktree = lsp_store
8739 .update(cx, |lsp_store, cx| {
8740 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8741 worktree_store.create_worktree(&worktree_root_target, false, cx)
8742 })
8743 })?
8744 .await?;
8745 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8746 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8747 lsp_store
8748 .update(cx, |lsp_store, cx| {
8749 if let Some(local) = lsp_store.as_local_mut() {
8750 local.register_language_server_for_invisible_worktree(
8751 &worktree,
8752 language_server_id,
8753 cx,
8754 )
8755 }
8756 match lsp_store.language_server_statuses.get(&language_server_id) {
8757 Some(status) => status.worktree,
8758 None => None,
8759 }
8760 })
8761 .ok()
8762 .flatten()
8763 .zip(Some(worktree_root.clone()))
8764 } else {
8765 None
8766 };
8767 let relative_path = if let Some(known_path) = known_relative_path {
8768 known_path
8769 } else {
8770 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8771 .into_arc()
8772 };
8773 (worktree, relative_path, source_ws)
8774 };
8775 let project_path = ProjectPath {
8776 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8777 path: relative_path,
8778 };
8779 let buffer = lsp_store
8780 .update(cx, |lsp_store, cx| {
8781 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8782 buffer_store.open_buffer(project_path, cx)
8783 })
8784 })?
8785 .await?;
8786 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8787 if let Some((source_ws, worktree_root)) = source_ws {
8788 buffer.update(cx, |buffer, cx| {
8789 let settings = WorktreeSettings::get(
8790 Some(
8791 (&ProjectPath {
8792 worktree_id: source_ws,
8793 path: Arc::from(RelPath::empty()),
8794 })
8795 .into(),
8796 ),
8797 cx,
8798 );
8799 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8800 if is_read_only {
8801 buffer.set_capability(Capability::ReadOnly, cx);
8802 }
8803 });
8804 }
8805 Ok(buffer)
8806 })
8807 }
8808
8809 fn request_multiple_lsp_locally<P, R>(
8810 &mut self,
8811 buffer: &Entity<Buffer>,
8812 position: Option<P>,
8813 request: R,
8814 cx: &mut Context<Self>,
8815 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8816 where
8817 P: ToOffset,
8818 R: LspCommand + Clone,
8819 <R::LspRequest as lsp::request::Request>::Result: Send,
8820 <R::LspRequest as lsp::request::Request>::Params: Send,
8821 {
8822 let Some(local) = self.as_local() else {
8823 return Task::ready(Vec::new());
8824 };
8825
8826 let snapshot = buffer.read(cx).snapshot();
8827 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8828
8829 let server_ids = buffer.update(cx, |buffer, cx| {
8830 local
8831 .language_servers_for_buffer(buffer, cx)
8832 .filter(|(adapter, _)| {
8833 scope
8834 .as_ref()
8835 .map(|scope| scope.language_allowed(&adapter.name))
8836 .unwrap_or(true)
8837 })
8838 .map(|(_, server)| server.server_id())
8839 .filter(|server_id| {
8840 self.as_local().is_none_or(|local| {
8841 local
8842 .buffers_opened_in_servers
8843 .get(&snapshot.remote_id())
8844 .is_some_and(|servers| servers.contains(server_id))
8845 })
8846 })
8847 .collect::<Vec<_>>()
8848 });
8849
8850 let mut response_results = server_ids
8851 .into_iter()
8852 .map(|server_id| {
8853 let task = self.request_lsp(
8854 buffer.clone(),
8855 LanguageServerToQuery::Other(server_id),
8856 request.clone(),
8857 cx,
8858 );
8859 async move { (server_id, task.await) }
8860 })
8861 .collect::<FuturesUnordered<_>>();
8862
8863 cx.background_spawn(async move {
8864 let mut responses = Vec::with_capacity(response_results.len());
8865 while let Some((server_id, response_result)) = response_results.next().await {
8866 match response_result {
8867 Ok(response) => responses.push((server_id, response)),
8868 // rust-analyzer likes to error with this when its still loading up
8869 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8870 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8871 }
8872 }
8873 responses
8874 })
8875 }
8876
8877 async fn handle_lsp_get_completions(
8878 this: Entity<Self>,
8879 envelope: TypedEnvelope<proto::GetCompletions>,
8880 mut cx: AsyncApp,
8881 ) -> Result<proto::GetCompletionsResponse> {
8882 let sender_id = envelope.original_sender_id().unwrap_or_default();
8883
8884 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8885 let buffer_handle = this.update(&mut cx, |this, cx| {
8886 this.buffer_store.read(cx).get_existing(buffer_id)
8887 })?;
8888 let request = GetCompletions::from_proto(
8889 envelope.payload,
8890 this.clone(),
8891 buffer_handle.clone(),
8892 cx.clone(),
8893 )
8894 .await?;
8895
8896 let server_to_query = match request.server_id {
8897 Some(server_id) => LanguageServerToQuery::Other(server_id),
8898 None => LanguageServerToQuery::FirstCapable,
8899 };
8900
8901 let response = this
8902 .update(&mut cx, |this, cx| {
8903 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8904 })
8905 .await?;
8906 this.update(&mut cx, |this, cx| {
8907 Ok(GetCompletions::response_to_proto(
8908 response,
8909 this,
8910 sender_id,
8911 &buffer_handle.read(cx).version(),
8912 cx,
8913 ))
8914 })
8915 }
8916
8917 async fn handle_lsp_command<T: LspCommand>(
8918 this: Entity<Self>,
8919 envelope: TypedEnvelope<T::ProtoRequest>,
8920 mut cx: AsyncApp,
8921 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8922 where
8923 <T::LspRequest as lsp::request::Request>::Params: Send,
8924 <T::LspRequest as lsp::request::Request>::Result: Send,
8925 {
8926 let sender_id = envelope.original_sender_id().unwrap_or_default();
8927 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8928 let buffer_handle = this.update(&mut cx, |this, cx| {
8929 this.buffer_store.read(cx).get_existing(buffer_id)
8930 })?;
8931 let request = T::from_proto(
8932 envelope.payload,
8933 this.clone(),
8934 buffer_handle.clone(),
8935 cx.clone(),
8936 )
8937 .await?;
8938 let response = this
8939 .update(&mut cx, |this, cx| {
8940 this.request_lsp(
8941 buffer_handle.clone(),
8942 LanguageServerToQuery::FirstCapable,
8943 request,
8944 cx,
8945 )
8946 })
8947 .await?;
8948 this.update(&mut cx, |this, cx| {
8949 Ok(T::response_to_proto(
8950 response,
8951 this,
8952 sender_id,
8953 &buffer_handle.read(cx).version(),
8954 cx,
8955 ))
8956 })
8957 }
8958
8959 async fn handle_lsp_query(
8960 lsp_store: Entity<Self>,
8961 envelope: TypedEnvelope<proto::LspQuery>,
8962 mut cx: AsyncApp,
8963 ) -> Result<proto::Ack> {
8964 use proto::lsp_query::Request;
8965 let sender_id = envelope.original_sender_id().unwrap_or_default();
8966 let lsp_query = envelope.payload;
8967 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8968 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8969 match lsp_query.request.context("invalid LSP query request")? {
8970 Request::GetReferences(get_references) => {
8971 let position = get_references.position.clone().and_then(deserialize_anchor);
8972 Self::query_lsp_locally::<GetReferences>(
8973 lsp_store,
8974 server_id,
8975 sender_id,
8976 lsp_request_id,
8977 get_references,
8978 position,
8979 &mut cx,
8980 )
8981 .await?;
8982 }
8983 Request::GetDocumentColor(get_document_color) => {
8984 Self::query_lsp_locally::<GetDocumentColor>(
8985 lsp_store,
8986 server_id,
8987 sender_id,
8988 lsp_request_id,
8989 get_document_color,
8990 None,
8991 &mut cx,
8992 )
8993 .await?;
8994 }
8995 Request::GetHover(get_hover) => {
8996 let position = get_hover.position.clone().and_then(deserialize_anchor);
8997 Self::query_lsp_locally::<GetHover>(
8998 lsp_store,
8999 server_id,
9000 sender_id,
9001 lsp_request_id,
9002 get_hover,
9003 position,
9004 &mut cx,
9005 )
9006 .await?;
9007 }
9008 Request::GetCodeActions(get_code_actions) => {
9009 Self::query_lsp_locally::<GetCodeActions>(
9010 lsp_store,
9011 server_id,
9012 sender_id,
9013 lsp_request_id,
9014 get_code_actions,
9015 None,
9016 &mut cx,
9017 )
9018 .await?;
9019 }
9020 Request::GetSignatureHelp(get_signature_help) => {
9021 let position = get_signature_help
9022 .position
9023 .clone()
9024 .and_then(deserialize_anchor);
9025 Self::query_lsp_locally::<GetSignatureHelp>(
9026 lsp_store,
9027 server_id,
9028 sender_id,
9029 lsp_request_id,
9030 get_signature_help,
9031 position,
9032 &mut cx,
9033 )
9034 .await?;
9035 }
9036 Request::GetCodeLens(get_code_lens) => {
9037 Self::query_lsp_locally::<GetCodeLens>(
9038 lsp_store,
9039 server_id,
9040 sender_id,
9041 lsp_request_id,
9042 get_code_lens,
9043 None,
9044 &mut cx,
9045 )
9046 .await?;
9047 }
9048 Request::GetDefinition(get_definition) => {
9049 let position = get_definition.position.clone().and_then(deserialize_anchor);
9050 Self::query_lsp_locally::<GetDefinitions>(
9051 lsp_store,
9052 server_id,
9053 sender_id,
9054 lsp_request_id,
9055 get_definition,
9056 position,
9057 &mut cx,
9058 )
9059 .await?;
9060 }
9061 Request::GetDeclaration(get_declaration) => {
9062 let position = get_declaration
9063 .position
9064 .clone()
9065 .and_then(deserialize_anchor);
9066 Self::query_lsp_locally::<GetDeclarations>(
9067 lsp_store,
9068 server_id,
9069 sender_id,
9070 lsp_request_id,
9071 get_declaration,
9072 position,
9073 &mut cx,
9074 )
9075 .await?;
9076 }
9077 Request::GetTypeDefinition(get_type_definition) => {
9078 let position = get_type_definition
9079 .position
9080 .clone()
9081 .and_then(deserialize_anchor);
9082 Self::query_lsp_locally::<GetTypeDefinitions>(
9083 lsp_store,
9084 server_id,
9085 sender_id,
9086 lsp_request_id,
9087 get_type_definition,
9088 position,
9089 &mut cx,
9090 )
9091 .await?;
9092 }
9093 Request::GetImplementation(get_implementation) => {
9094 let position = get_implementation
9095 .position
9096 .clone()
9097 .and_then(deserialize_anchor);
9098 Self::query_lsp_locally::<GetImplementations>(
9099 lsp_store,
9100 server_id,
9101 sender_id,
9102 lsp_request_id,
9103 get_implementation,
9104 position,
9105 &mut cx,
9106 )
9107 .await?;
9108 }
9109 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9110 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9111 let version = deserialize_version(get_document_diagnostics.buffer_version());
9112 let buffer = lsp_store.update(&mut cx, |this, cx| {
9113 this.buffer_store.read(cx).get_existing(buffer_id)
9114 })?;
9115 buffer
9116 .update(&mut cx, |buffer, _| {
9117 buffer.wait_for_version(version.clone())
9118 })
9119 .await?;
9120 lsp_store.update(&mut cx, |lsp_store, cx| {
9121 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9122 let key = LspKey {
9123 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9124 server_queried: server_id,
9125 };
9126 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9127 ) {
9128 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9129 lsp_requests.clear();
9130 };
9131 }
9132
9133 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9134 existing_queries.insert(
9135 lsp_request_id,
9136 cx.spawn(async move |lsp_store, cx| {
9137 let diagnostics_pull = lsp_store.update(cx, |lsp_store, cx| {
9138 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9139 });
9140 if let Ok(diagnostics_pull) = diagnostics_pull {
9141 match diagnostics_pull.await {
9142 Ok(()) => {}
9143 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9144 };
9145 }
9146 }),
9147 );
9148 });
9149 }
9150 Request::InlayHints(inlay_hints) => {
9151 let query_start = inlay_hints
9152 .start
9153 .clone()
9154 .and_then(deserialize_anchor)
9155 .context("invalid inlay hints range start")?;
9156 let query_end = inlay_hints
9157 .end
9158 .clone()
9159 .and_then(deserialize_anchor)
9160 .context("invalid inlay hints range end")?;
9161 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9162 &lsp_store,
9163 server_id,
9164 lsp_request_id,
9165 &inlay_hints,
9166 query_start..query_end,
9167 &mut cx,
9168 )
9169 .await
9170 .context("preparing inlay hints request")?;
9171 Self::query_lsp_locally::<InlayHints>(
9172 lsp_store,
9173 server_id,
9174 sender_id,
9175 lsp_request_id,
9176 inlay_hints,
9177 None,
9178 &mut cx,
9179 )
9180 .await
9181 .context("querying for inlay hints")?
9182 }
9183 }
9184 Ok(proto::Ack {})
9185 }
9186
9187 async fn handle_lsp_query_response(
9188 lsp_store: Entity<Self>,
9189 envelope: TypedEnvelope<proto::LspQueryResponse>,
9190 cx: AsyncApp,
9191 ) -> Result<()> {
9192 lsp_store.read_with(&cx, |lsp_store, _| {
9193 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9194 upstream_client.handle_lsp_response(envelope.clone());
9195 }
9196 });
9197 Ok(())
9198 }
9199
9200 async fn handle_apply_code_action(
9201 this: Entity<Self>,
9202 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9203 mut cx: AsyncApp,
9204 ) -> Result<proto::ApplyCodeActionResponse> {
9205 let sender_id = envelope.original_sender_id().unwrap_or_default();
9206 let action =
9207 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9208 let apply_code_action = this.update(&mut cx, |this, cx| {
9209 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9210 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9211 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9212 })?;
9213
9214 let project_transaction = apply_code_action.await?;
9215 let project_transaction = this.update(&mut cx, |this, cx| {
9216 this.buffer_store.update(cx, |buffer_store, cx| {
9217 buffer_store.serialize_project_transaction_for_peer(
9218 project_transaction,
9219 sender_id,
9220 cx,
9221 )
9222 })
9223 });
9224 Ok(proto::ApplyCodeActionResponse {
9225 transaction: Some(project_transaction),
9226 })
9227 }
9228
9229 async fn handle_register_buffer_with_language_servers(
9230 this: Entity<Self>,
9231 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9232 mut cx: AsyncApp,
9233 ) -> Result<proto::Ack> {
9234 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9235 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9236 this.update(&mut cx, |this, cx| {
9237 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9238 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9239 project_id: upstream_project_id,
9240 buffer_id: buffer_id.to_proto(),
9241 only_servers: envelope.payload.only_servers,
9242 });
9243 }
9244
9245 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9246 anyhow::bail!("buffer is not open");
9247 };
9248
9249 let handle = this.register_buffer_with_language_servers(
9250 &buffer,
9251 envelope
9252 .payload
9253 .only_servers
9254 .into_iter()
9255 .filter_map(|selector| {
9256 Some(match selector.selector? {
9257 proto::language_server_selector::Selector::ServerId(server_id) => {
9258 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9259 }
9260 proto::language_server_selector::Selector::Name(name) => {
9261 LanguageServerSelector::Name(LanguageServerName(
9262 SharedString::from(name),
9263 ))
9264 }
9265 })
9266 })
9267 .collect(),
9268 false,
9269 cx,
9270 );
9271 this.buffer_store().update(cx, |buffer_store, _| {
9272 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9273 });
9274
9275 Ok(())
9276 })?;
9277 Ok(proto::Ack {})
9278 }
9279
9280 async fn handle_rename_project_entry(
9281 this: Entity<Self>,
9282 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9283 mut cx: AsyncApp,
9284 ) -> Result<proto::ProjectEntryResponse> {
9285 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9286 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9287 let new_path =
9288 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9289
9290 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9291 .update(&mut cx, |this, cx| {
9292 let (worktree, entry) = this
9293 .worktree_store
9294 .read(cx)
9295 .worktree_and_entry_for_id(entry_id, cx)?;
9296 let new_worktree = this
9297 .worktree_store
9298 .read(cx)
9299 .worktree_for_id(new_worktree_id, cx)?;
9300 Some((
9301 this.worktree_store.clone(),
9302 worktree,
9303 new_worktree,
9304 entry.clone(),
9305 ))
9306 })
9307 .context("worktree not found")?;
9308 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9309 (worktree.absolutize(&old_entry.path), worktree.id())
9310 });
9311 let new_abs_path =
9312 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9313
9314 let _transaction = Self::will_rename_entry(
9315 this.downgrade(),
9316 old_worktree_id,
9317 &old_abs_path,
9318 &new_abs_path,
9319 old_entry.is_dir(),
9320 cx.clone(),
9321 )
9322 .await;
9323 let response = WorktreeStore::handle_rename_project_entry(
9324 worktree_store,
9325 envelope.payload,
9326 cx.clone(),
9327 )
9328 .await;
9329 this.read_with(&cx, |this, _| {
9330 this.did_rename_entry(
9331 old_worktree_id,
9332 &old_abs_path,
9333 &new_abs_path,
9334 old_entry.is_dir(),
9335 );
9336 });
9337 response
9338 }
9339
9340 async fn handle_update_diagnostic_summary(
9341 this: Entity<Self>,
9342 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9343 mut cx: AsyncApp,
9344 ) -> Result<()> {
9345 this.update(&mut cx, |lsp_store, cx| {
9346 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9347 let mut updated_diagnostics_paths = HashMap::default();
9348 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9349 for message_summary in envelope
9350 .payload
9351 .summary
9352 .into_iter()
9353 .chain(envelope.payload.more_summaries)
9354 {
9355 let project_path = ProjectPath {
9356 worktree_id,
9357 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9358 };
9359 let path = project_path.path.clone();
9360 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9361 let summary = DiagnosticSummary {
9362 error_count: message_summary.error_count as usize,
9363 warning_count: message_summary.warning_count as usize,
9364 };
9365
9366 if summary.is_empty() {
9367 if let Some(worktree_summaries) =
9368 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9369 && let Some(summaries) = worktree_summaries.get_mut(&path)
9370 {
9371 summaries.remove(&server_id);
9372 if summaries.is_empty() {
9373 worktree_summaries.remove(&path);
9374 }
9375 }
9376 } else {
9377 lsp_store
9378 .diagnostic_summaries
9379 .entry(worktree_id)
9380 .or_default()
9381 .entry(path)
9382 .or_default()
9383 .insert(server_id, summary);
9384 }
9385
9386 if let Some((_, project_id)) = &lsp_store.downstream_client {
9387 match &mut diagnostics_summary {
9388 Some(diagnostics_summary) => {
9389 diagnostics_summary
9390 .more_summaries
9391 .push(proto::DiagnosticSummary {
9392 path: project_path.path.as_ref().to_proto(),
9393 language_server_id: server_id.0 as u64,
9394 error_count: summary.error_count as u32,
9395 warning_count: summary.warning_count as u32,
9396 })
9397 }
9398 None => {
9399 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9400 project_id: *project_id,
9401 worktree_id: worktree_id.to_proto(),
9402 summary: Some(proto::DiagnosticSummary {
9403 path: project_path.path.as_ref().to_proto(),
9404 language_server_id: server_id.0 as u64,
9405 error_count: summary.error_count as u32,
9406 warning_count: summary.warning_count as u32,
9407 }),
9408 more_summaries: Vec::new(),
9409 })
9410 }
9411 }
9412 }
9413 updated_diagnostics_paths
9414 .entry(server_id)
9415 .or_insert_with(Vec::new)
9416 .push(project_path);
9417 }
9418
9419 if let Some((diagnostics_summary, (downstream_client, _))) =
9420 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9421 {
9422 downstream_client.send(diagnostics_summary).log_err();
9423 }
9424 for (server_id, paths) in updated_diagnostics_paths {
9425 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9426 }
9427 Ok(())
9428 })
9429 }
9430
9431 async fn handle_start_language_server(
9432 lsp_store: Entity<Self>,
9433 envelope: TypedEnvelope<proto::StartLanguageServer>,
9434 mut cx: AsyncApp,
9435 ) -> Result<()> {
9436 let server = envelope.payload.server.context("invalid server")?;
9437 let server_capabilities =
9438 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9439 .with_context(|| {
9440 format!(
9441 "incorrect server capabilities {}",
9442 envelope.payload.capabilities
9443 )
9444 })?;
9445 lsp_store.update(&mut cx, |lsp_store, cx| {
9446 let server_id = LanguageServerId(server.id as usize);
9447 let server_name = LanguageServerName::from_proto(server.name.clone());
9448 lsp_store
9449 .lsp_server_capabilities
9450 .insert(server_id, server_capabilities);
9451 lsp_store.language_server_statuses.insert(
9452 server_id,
9453 LanguageServerStatus {
9454 name: server_name.clone(),
9455 server_version: None,
9456 pending_work: Default::default(),
9457 has_pending_diagnostic_updates: false,
9458 progress_tokens: Default::default(),
9459 worktree: server.worktree_id.map(WorktreeId::from_proto),
9460 binary: None,
9461 configuration: None,
9462 workspace_folders: BTreeSet::new(),
9463 },
9464 );
9465 cx.emit(LspStoreEvent::LanguageServerAdded(
9466 server_id,
9467 server_name,
9468 server.worktree_id.map(WorktreeId::from_proto),
9469 ));
9470 cx.notify();
9471 });
9472 Ok(())
9473 }
9474
9475 async fn handle_update_language_server(
9476 lsp_store: Entity<Self>,
9477 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9478 mut cx: AsyncApp,
9479 ) -> Result<()> {
9480 lsp_store.update(&mut cx, |lsp_store, cx| {
9481 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9482
9483 match envelope.payload.variant.context("invalid variant")? {
9484 proto::update_language_server::Variant::WorkStart(payload) => {
9485 lsp_store.on_lsp_work_start(
9486 language_server_id,
9487 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9488 .context("invalid progress token value")?,
9489 LanguageServerProgress {
9490 title: payload.title,
9491 is_disk_based_diagnostics_progress: false,
9492 is_cancellable: payload.is_cancellable.unwrap_or(false),
9493 message: payload.message,
9494 percentage: payload.percentage.map(|p| p as usize),
9495 last_update_at: cx.background_executor().now(),
9496 },
9497 cx,
9498 );
9499 }
9500 proto::update_language_server::Variant::WorkProgress(payload) => {
9501 lsp_store.on_lsp_work_progress(
9502 language_server_id,
9503 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9504 .context("invalid progress token value")?,
9505 LanguageServerProgress {
9506 title: None,
9507 is_disk_based_diagnostics_progress: false,
9508 is_cancellable: payload.is_cancellable.unwrap_or(false),
9509 message: payload.message,
9510 percentage: payload.percentage.map(|p| p as usize),
9511 last_update_at: cx.background_executor().now(),
9512 },
9513 cx,
9514 );
9515 }
9516
9517 proto::update_language_server::Variant::WorkEnd(payload) => {
9518 lsp_store.on_lsp_work_end(
9519 language_server_id,
9520 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9521 .context("invalid progress token value")?,
9522 cx,
9523 );
9524 }
9525
9526 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9527 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9528 }
9529
9530 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9531 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9532 }
9533
9534 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9535 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9536 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9537 cx.emit(LspStoreEvent::LanguageServerUpdate {
9538 language_server_id,
9539 name: envelope
9540 .payload
9541 .server_name
9542 .map(SharedString::new)
9543 .map(LanguageServerName),
9544 message: non_lsp,
9545 });
9546 }
9547 }
9548
9549 Ok(())
9550 })
9551 }
9552
9553 async fn handle_language_server_log(
9554 this: Entity<Self>,
9555 envelope: TypedEnvelope<proto::LanguageServerLog>,
9556 mut cx: AsyncApp,
9557 ) -> Result<()> {
9558 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9559 let log_type = envelope
9560 .payload
9561 .log_type
9562 .map(LanguageServerLogType::from_proto)
9563 .context("invalid language server log type")?;
9564
9565 let message = envelope.payload.message;
9566
9567 this.update(&mut cx, |_, cx| {
9568 cx.emit(LspStoreEvent::LanguageServerLog(
9569 language_server_id,
9570 log_type,
9571 message,
9572 ));
9573 });
9574 Ok(())
9575 }
9576
9577 async fn handle_lsp_ext_cancel_flycheck(
9578 lsp_store: Entity<Self>,
9579 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9580 cx: AsyncApp,
9581 ) -> Result<proto::Ack> {
9582 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9583 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9584 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9585 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9586 } else {
9587 None
9588 }
9589 });
9590 if let Some(task) = task {
9591 task.context("handling lsp ext cancel flycheck")?;
9592 }
9593
9594 Ok(proto::Ack {})
9595 }
9596
9597 async fn handle_lsp_ext_run_flycheck(
9598 lsp_store: Entity<Self>,
9599 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9600 mut cx: AsyncApp,
9601 ) -> Result<proto::Ack> {
9602 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9603 lsp_store.update(&mut cx, |lsp_store, cx| {
9604 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9605 let text_document = if envelope.payload.current_file_only {
9606 let buffer_id = envelope
9607 .payload
9608 .buffer_id
9609 .map(|id| BufferId::new(id))
9610 .transpose()?;
9611 buffer_id
9612 .and_then(|buffer_id| {
9613 lsp_store
9614 .buffer_store()
9615 .read(cx)
9616 .get(buffer_id)
9617 .and_then(|buffer| {
9618 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9619 })
9620 .map(|path| make_text_document_identifier(&path))
9621 })
9622 .transpose()?
9623 } else {
9624 None
9625 };
9626 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9627 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9628 )?;
9629 }
9630 anyhow::Ok(())
9631 })?;
9632
9633 Ok(proto::Ack {})
9634 }
9635
9636 async fn handle_lsp_ext_clear_flycheck(
9637 lsp_store: Entity<Self>,
9638 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9639 cx: AsyncApp,
9640 ) -> Result<proto::Ack> {
9641 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9642 lsp_store.read_with(&cx, |lsp_store, _| {
9643 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9644 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9645 } else {
9646 None
9647 }
9648 });
9649
9650 Ok(proto::Ack {})
9651 }
9652
9653 pub fn disk_based_diagnostics_started(
9654 &mut self,
9655 language_server_id: LanguageServerId,
9656 cx: &mut Context<Self>,
9657 ) {
9658 if let Some(language_server_status) =
9659 self.language_server_statuses.get_mut(&language_server_id)
9660 {
9661 language_server_status.has_pending_diagnostic_updates = true;
9662 }
9663
9664 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9665 cx.emit(LspStoreEvent::LanguageServerUpdate {
9666 language_server_id,
9667 name: self
9668 .language_server_adapter_for_id(language_server_id)
9669 .map(|adapter| adapter.name()),
9670 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9671 Default::default(),
9672 ),
9673 })
9674 }
9675
9676 pub fn disk_based_diagnostics_finished(
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 = false;
9685 }
9686
9687 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { 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::DiskBasedDiagnosticsUpdated(
9694 Default::default(),
9695 ),
9696 })
9697 }
9698
9699 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9700 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9701 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9702 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9703 // the language server might take some time to publish diagnostics.
9704 fn simulate_disk_based_diagnostics_events_if_needed(
9705 &mut self,
9706 language_server_id: LanguageServerId,
9707 cx: &mut Context<Self>,
9708 ) {
9709 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9710
9711 let Some(LanguageServerState::Running {
9712 simulate_disk_based_diagnostics_completion,
9713 adapter,
9714 ..
9715 }) = self
9716 .as_local_mut()
9717 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9718 else {
9719 return;
9720 };
9721
9722 if adapter.disk_based_diagnostics_progress_token.is_some() {
9723 return;
9724 }
9725
9726 let prev_task =
9727 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9728 cx.background_executor()
9729 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9730 .await;
9731
9732 this.update(cx, |this, cx| {
9733 this.disk_based_diagnostics_finished(language_server_id, cx);
9734
9735 if let Some(LanguageServerState::Running {
9736 simulate_disk_based_diagnostics_completion,
9737 ..
9738 }) = this.as_local_mut().and_then(|local_store| {
9739 local_store.language_servers.get_mut(&language_server_id)
9740 }) {
9741 *simulate_disk_based_diagnostics_completion = None;
9742 }
9743 })
9744 .ok();
9745 }));
9746
9747 if prev_task.is_none() {
9748 self.disk_based_diagnostics_started(language_server_id, cx);
9749 }
9750 }
9751
9752 pub fn language_server_statuses(
9753 &self,
9754 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9755 self.language_server_statuses
9756 .iter()
9757 .map(|(key, value)| (*key, value))
9758 }
9759
9760 pub(super) fn did_rename_entry(
9761 &self,
9762 worktree_id: WorktreeId,
9763 old_path: &Path,
9764 new_path: &Path,
9765 is_dir: bool,
9766 ) {
9767 maybe!({
9768 let local_store = self.as_local()?;
9769
9770 let old_uri = lsp::Uri::from_file_path(old_path)
9771 .ok()
9772 .map(|uri| uri.to_string())?;
9773 let new_uri = lsp::Uri::from_file_path(new_path)
9774 .ok()
9775 .map(|uri| uri.to_string())?;
9776
9777 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9778 let Some(filter) = local_store
9779 .language_server_paths_watched_for_rename
9780 .get(&language_server.server_id())
9781 else {
9782 continue;
9783 };
9784
9785 if filter.should_send_did_rename(&old_uri, is_dir) {
9786 language_server
9787 .notify::<DidRenameFiles>(RenameFilesParams {
9788 files: vec![FileRename {
9789 old_uri: old_uri.clone(),
9790 new_uri: new_uri.clone(),
9791 }],
9792 })
9793 .ok();
9794 }
9795 }
9796 Some(())
9797 });
9798 }
9799
9800 pub(super) fn will_rename_entry(
9801 this: WeakEntity<Self>,
9802 worktree_id: WorktreeId,
9803 old_path: &Path,
9804 new_path: &Path,
9805 is_dir: bool,
9806 cx: AsyncApp,
9807 ) -> Task<ProjectTransaction> {
9808 let old_uri = lsp::Uri::from_file_path(old_path)
9809 .ok()
9810 .map(|uri| uri.to_string());
9811 let new_uri = lsp::Uri::from_file_path(new_path)
9812 .ok()
9813 .map(|uri| uri.to_string());
9814 cx.spawn(async move |cx| {
9815 let mut tasks = vec![];
9816 this.update(cx, |this, cx| {
9817 let local_store = this.as_local()?;
9818 let old_uri = old_uri?;
9819 let new_uri = new_uri?;
9820 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9821 let Some(filter) = local_store
9822 .language_server_paths_watched_for_rename
9823 .get(&language_server.server_id())
9824 else {
9825 continue;
9826 };
9827
9828 if filter.should_send_will_rename(&old_uri, is_dir) {
9829 let apply_edit = cx.spawn({
9830 let old_uri = old_uri.clone();
9831 let new_uri = new_uri.clone();
9832 let language_server = language_server.clone();
9833 async move |this, cx| {
9834 let edit = language_server
9835 .request::<WillRenameFiles>(RenameFilesParams {
9836 files: vec![FileRename { old_uri, new_uri }],
9837 })
9838 .await
9839 .into_response()
9840 .context("will rename files")
9841 .log_err()
9842 .flatten()?;
9843
9844 let transaction = LocalLspStore::deserialize_workspace_edit(
9845 this.upgrade()?,
9846 edit,
9847 false,
9848 language_server.clone(),
9849 cx,
9850 )
9851 .await
9852 .ok()?;
9853 Some(transaction)
9854 }
9855 });
9856 tasks.push(apply_edit);
9857 }
9858 }
9859 Some(())
9860 })
9861 .ok()
9862 .flatten();
9863 let mut merged_transaction = ProjectTransaction::default();
9864 for task in tasks {
9865 // Await on tasks sequentially so that the order of application of edits is deterministic
9866 // (at least with regards to the order of registration of language servers)
9867 if let Some(transaction) = task.await {
9868 for (buffer, buffer_transaction) in transaction.0 {
9869 merged_transaction.0.insert(buffer, buffer_transaction);
9870 }
9871 }
9872 }
9873 merged_transaction
9874 })
9875 }
9876
9877 fn lsp_notify_abs_paths_changed(
9878 &mut self,
9879 server_id: LanguageServerId,
9880 changes: Vec<PathEvent>,
9881 ) {
9882 maybe!({
9883 let server = self.language_server_for_id(server_id)?;
9884 let changes = changes
9885 .into_iter()
9886 .filter_map(|event| {
9887 let typ = match event.kind? {
9888 PathEventKind::Created => lsp::FileChangeType::CREATED,
9889 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9890 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9891 };
9892 Some(lsp::FileEvent {
9893 uri: file_path_to_lsp_url(&event.path).log_err()?,
9894 typ,
9895 })
9896 })
9897 .collect::<Vec<_>>();
9898 if !changes.is_empty() {
9899 server
9900 .notify::<lsp::notification::DidChangeWatchedFiles>(
9901 lsp::DidChangeWatchedFilesParams { changes },
9902 )
9903 .ok();
9904 }
9905 Some(())
9906 });
9907 }
9908
9909 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9910 self.as_local()?.language_server_for_id(id)
9911 }
9912
9913 fn on_lsp_progress(
9914 &mut self,
9915 progress_params: lsp::ProgressParams,
9916 language_server_id: LanguageServerId,
9917 disk_based_diagnostics_progress_token: Option<String>,
9918 cx: &mut Context<Self>,
9919 ) {
9920 match progress_params.value {
9921 lsp::ProgressParamsValue::WorkDone(progress) => {
9922 self.handle_work_done_progress(
9923 progress,
9924 language_server_id,
9925 disk_based_diagnostics_progress_token,
9926 ProgressToken::from_lsp(progress_params.token),
9927 cx,
9928 );
9929 }
9930 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9931 let registration_id = match progress_params.token {
9932 lsp::NumberOrString::Number(_) => None,
9933 lsp::NumberOrString::String(token) => token
9934 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9935 .map(|(_, id)| id.to_owned()),
9936 };
9937 if let Some(LanguageServerState::Running {
9938 workspace_diagnostics_refresh_tasks,
9939 ..
9940 }) = self
9941 .as_local_mut()
9942 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9943 && let Some(workspace_diagnostics) =
9944 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9945 {
9946 workspace_diagnostics.progress_tx.try_send(()).ok();
9947 self.apply_workspace_diagnostic_report(
9948 language_server_id,
9949 report,
9950 registration_id.map(SharedString::from),
9951 cx,
9952 )
9953 }
9954 }
9955 }
9956 }
9957
9958 fn handle_work_done_progress(
9959 &mut self,
9960 progress: lsp::WorkDoneProgress,
9961 language_server_id: LanguageServerId,
9962 disk_based_diagnostics_progress_token: Option<String>,
9963 token: ProgressToken,
9964 cx: &mut Context<Self>,
9965 ) {
9966 let language_server_status =
9967 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9968 status
9969 } else {
9970 return;
9971 };
9972
9973 if !language_server_status.progress_tokens.contains(&token) {
9974 return;
9975 }
9976
9977 let is_disk_based_diagnostics_progress =
9978 if let (Some(disk_based_token), ProgressToken::String(token)) =
9979 (&disk_based_diagnostics_progress_token, &token)
9980 {
9981 token.starts_with(disk_based_token)
9982 } else {
9983 false
9984 };
9985
9986 match progress {
9987 lsp::WorkDoneProgress::Begin(report) => {
9988 if is_disk_based_diagnostics_progress {
9989 self.disk_based_diagnostics_started(language_server_id, cx);
9990 }
9991 self.on_lsp_work_start(
9992 language_server_id,
9993 token.clone(),
9994 LanguageServerProgress {
9995 title: Some(report.title),
9996 is_disk_based_diagnostics_progress,
9997 is_cancellable: report.cancellable.unwrap_or(false),
9998 message: report.message.clone(),
9999 percentage: report.percentage.map(|p| p as usize),
10000 last_update_at: cx.background_executor().now(),
10001 },
10002 cx,
10003 );
10004 }
10005 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10006 language_server_id,
10007 token,
10008 LanguageServerProgress {
10009 title: None,
10010 is_disk_based_diagnostics_progress,
10011 is_cancellable: report.cancellable.unwrap_or(false),
10012 message: report.message,
10013 percentage: report.percentage.map(|p| p as usize),
10014 last_update_at: cx.background_executor().now(),
10015 },
10016 cx,
10017 ),
10018 lsp::WorkDoneProgress::End(_) => {
10019 language_server_status.progress_tokens.remove(&token);
10020 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10021 if is_disk_based_diagnostics_progress {
10022 self.disk_based_diagnostics_finished(language_server_id, cx);
10023 }
10024 }
10025 }
10026 }
10027
10028 fn on_lsp_work_start(
10029 &mut self,
10030 language_server_id: LanguageServerId,
10031 token: ProgressToken,
10032 progress: LanguageServerProgress,
10033 cx: &mut Context<Self>,
10034 ) {
10035 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10036 status.pending_work.insert(token.clone(), progress.clone());
10037 cx.notify();
10038 }
10039 cx.emit(LspStoreEvent::LanguageServerUpdate {
10040 language_server_id,
10041 name: self
10042 .language_server_adapter_for_id(language_server_id)
10043 .map(|adapter| adapter.name()),
10044 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10045 token: Some(token.to_proto()),
10046 title: progress.title,
10047 message: progress.message,
10048 percentage: progress.percentage.map(|p| p as u32),
10049 is_cancellable: Some(progress.is_cancellable),
10050 }),
10051 })
10052 }
10053
10054 fn on_lsp_work_progress(
10055 &mut self,
10056 language_server_id: LanguageServerId,
10057 token: ProgressToken,
10058 progress: LanguageServerProgress,
10059 cx: &mut Context<Self>,
10060 ) {
10061 let mut did_update = false;
10062 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10063 match status.pending_work.entry(token.clone()) {
10064 btree_map::Entry::Vacant(entry) => {
10065 entry.insert(progress.clone());
10066 did_update = true;
10067 }
10068 btree_map::Entry::Occupied(mut entry) => {
10069 let entry = entry.get_mut();
10070 if (progress.last_update_at - entry.last_update_at)
10071 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10072 {
10073 entry.last_update_at = progress.last_update_at;
10074 if progress.message.is_some() {
10075 entry.message = progress.message.clone();
10076 }
10077 if progress.percentage.is_some() {
10078 entry.percentage = progress.percentage;
10079 }
10080 if progress.is_cancellable != entry.is_cancellable {
10081 entry.is_cancellable = progress.is_cancellable;
10082 }
10083 did_update = true;
10084 }
10085 }
10086 }
10087 }
10088
10089 if did_update {
10090 cx.emit(LspStoreEvent::LanguageServerUpdate {
10091 language_server_id,
10092 name: self
10093 .language_server_adapter_for_id(language_server_id)
10094 .map(|adapter| adapter.name()),
10095 message: proto::update_language_server::Variant::WorkProgress(
10096 proto::LspWorkProgress {
10097 token: Some(token.to_proto()),
10098 message: progress.message,
10099 percentage: progress.percentage.map(|p| p as u32),
10100 is_cancellable: Some(progress.is_cancellable),
10101 },
10102 ),
10103 })
10104 }
10105 }
10106
10107 fn on_lsp_work_end(
10108 &mut self,
10109 language_server_id: LanguageServerId,
10110 token: ProgressToken,
10111 cx: &mut Context<Self>,
10112 ) {
10113 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10114 if let Some(work) = status.pending_work.remove(&token)
10115 && !work.is_disk_based_diagnostics_progress
10116 {
10117 cx.emit(LspStoreEvent::RefreshInlayHints {
10118 server_id: language_server_id,
10119 request_id: None,
10120 });
10121 }
10122 cx.notify();
10123 }
10124
10125 cx.emit(LspStoreEvent::LanguageServerUpdate {
10126 language_server_id,
10127 name: self
10128 .language_server_adapter_for_id(language_server_id)
10129 .map(|adapter| adapter.name()),
10130 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10131 token: Some(token.to_proto()),
10132 }),
10133 })
10134 }
10135
10136 pub async fn handle_resolve_completion_documentation(
10137 this: Entity<Self>,
10138 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10139 mut cx: AsyncApp,
10140 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10141 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10142
10143 let completion = this
10144 .read_with(&cx, |this, cx| {
10145 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10146 let server = this
10147 .language_server_for_id(id)
10148 .with_context(|| format!("No language server {id}"))?;
10149
10150 anyhow::Ok(cx.background_spawn(async move {
10151 let can_resolve = server
10152 .capabilities()
10153 .completion_provider
10154 .as_ref()
10155 .and_then(|options| options.resolve_provider)
10156 .unwrap_or(false);
10157 if can_resolve {
10158 server
10159 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10160 .await
10161 .into_response()
10162 .context("resolve completion item")
10163 } else {
10164 anyhow::Ok(lsp_completion)
10165 }
10166 }))
10167 })?
10168 .await?;
10169
10170 let mut documentation_is_markdown = false;
10171 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10172 let documentation = match completion.documentation {
10173 Some(lsp::Documentation::String(text)) => text,
10174
10175 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10176 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10177 value
10178 }
10179
10180 _ => String::new(),
10181 };
10182
10183 // If we have a new buffer_id, that means we're talking to a new client
10184 // and want to check for new text_edits in the completion too.
10185 let mut old_replace_start = None;
10186 let mut old_replace_end = None;
10187 let mut old_insert_start = None;
10188 let mut old_insert_end = None;
10189 let mut new_text = String::default();
10190 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10191 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10192 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10193 anyhow::Ok(buffer.read(cx).snapshot())
10194 })?;
10195
10196 if let Some(text_edit) = completion.text_edit.as_ref() {
10197 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10198
10199 if let Some(mut edit) = edit {
10200 LineEnding::normalize(&mut edit.new_text);
10201
10202 new_text = edit.new_text;
10203 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10204 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10205 if let Some(insert_range) = edit.insert_range {
10206 old_insert_start = Some(serialize_anchor(&insert_range.start));
10207 old_insert_end = Some(serialize_anchor(&insert_range.end));
10208 }
10209 }
10210 }
10211 }
10212
10213 Ok(proto::ResolveCompletionDocumentationResponse {
10214 documentation,
10215 documentation_is_markdown,
10216 old_replace_start,
10217 old_replace_end,
10218 new_text,
10219 lsp_completion,
10220 old_insert_start,
10221 old_insert_end,
10222 })
10223 }
10224
10225 async fn handle_on_type_formatting(
10226 this: Entity<Self>,
10227 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10228 mut cx: AsyncApp,
10229 ) -> Result<proto::OnTypeFormattingResponse> {
10230 let on_type_formatting = this.update(&mut cx, |this, cx| {
10231 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10232 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10233 let position = envelope
10234 .payload
10235 .position
10236 .and_then(deserialize_anchor)
10237 .context("invalid position")?;
10238 anyhow::Ok(this.apply_on_type_formatting(
10239 buffer,
10240 position,
10241 envelope.payload.trigger.clone(),
10242 cx,
10243 ))
10244 })?;
10245
10246 let transaction = on_type_formatting
10247 .await?
10248 .as_ref()
10249 .map(language::proto::serialize_transaction);
10250 Ok(proto::OnTypeFormattingResponse { transaction })
10251 }
10252
10253 async fn handle_refresh_inlay_hints(
10254 lsp_store: Entity<Self>,
10255 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10256 mut cx: AsyncApp,
10257 ) -> Result<proto::Ack> {
10258 lsp_store.update(&mut cx, |_, cx| {
10259 cx.emit(LspStoreEvent::RefreshInlayHints {
10260 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10261 request_id: envelope.payload.request_id.map(|id| id as usize),
10262 });
10263 });
10264 Ok(proto::Ack {})
10265 }
10266
10267 async fn handle_pull_workspace_diagnostics(
10268 lsp_store: Entity<Self>,
10269 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10270 mut cx: AsyncApp,
10271 ) -> Result<proto::Ack> {
10272 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10273 lsp_store.update(&mut cx, |lsp_store, _| {
10274 lsp_store.pull_workspace_diagnostics(server_id);
10275 });
10276 Ok(proto::Ack {})
10277 }
10278
10279 async fn handle_get_color_presentation(
10280 lsp_store: Entity<Self>,
10281 envelope: TypedEnvelope<proto::GetColorPresentation>,
10282 mut cx: AsyncApp,
10283 ) -> Result<proto::GetColorPresentationResponse> {
10284 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10285 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10286 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10287 })?;
10288
10289 let color = envelope
10290 .payload
10291 .color
10292 .context("invalid color resolve request")?;
10293 let start = color
10294 .lsp_range_start
10295 .context("invalid color resolve request")?;
10296 let end = color
10297 .lsp_range_end
10298 .context("invalid color resolve request")?;
10299
10300 let color = DocumentColor {
10301 lsp_range: lsp::Range {
10302 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10303 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10304 },
10305 color: lsp::Color {
10306 red: color.red,
10307 green: color.green,
10308 blue: color.blue,
10309 alpha: color.alpha,
10310 },
10311 resolved: false,
10312 color_presentations: Vec::new(),
10313 };
10314 let resolved_color = lsp_store
10315 .update(&mut cx, |lsp_store, cx| {
10316 lsp_store.resolve_color_presentation(
10317 color,
10318 buffer.clone(),
10319 LanguageServerId(envelope.payload.server_id as usize),
10320 cx,
10321 )
10322 })
10323 .await
10324 .context("resolving color presentation")?;
10325
10326 Ok(proto::GetColorPresentationResponse {
10327 presentations: resolved_color
10328 .color_presentations
10329 .into_iter()
10330 .map(|presentation| proto::ColorPresentation {
10331 label: presentation.label.to_string(),
10332 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10333 additional_text_edits: presentation
10334 .additional_text_edits
10335 .into_iter()
10336 .map(serialize_lsp_edit)
10337 .collect(),
10338 })
10339 .collect(),
10340 })
10341 }
10342
10343 async fn handle_resolve_inlay_hint(
10344 lsp_store: Entity<Self>,
10345 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10346 mut cx: AsyncApp,
10347 ) -> Result<proto::ResolveInlayHintResponse> {
10348 let proto_hint = envelope
10349 .payload
10350 .hint
10351 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10352 let hint = InlayHints::proto_to_project_hint(proto_hint)
10353 .context("resolved proto inlay hint conversion")?;
10354 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10355 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10356 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10357 })?;
10358 let response_hint = lsp_store
10359 .update(&mut cx, |lsp_store, cx| {
10360 lsp_store.resolve_inlay_hint(
10361 hint,
10362 buffer,
10363 LanguageServerId(envelope.payload.language_server_id as usize),
10364 cx,
10365 )
10366 })
10367 .await
10368 .context("inlay hints fetch")?;
10369 Ok(proto::ResolveInlayHintResponse {
10370 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10371 })
10372 }
10373
10374 async fn handle_refresh_code_lens(
10375 this: Entity<Self>,
10376 _: TypedEnvelope<proto::RefreshCodeLens>,
10377 mut cx: AsyncApp,
10378 ) -> Result<proto::Ack> {
10379 this.update(&mut cx, |_, cx| {
10380 cx.emit(LspStoreEvent::RefreshCodeLens);
10381 });
10382 Ok(proto::Ack {})
10383 }
10384
10385 async fn handle_open_buffer_for_symbol(
10386 this: Entity<Self>,
10387 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10388 mut cx: AsyncApp,
10389 ) -> Result<proto::OpenBufferForSymbolResponse> {
10390 let peer_id = envelope.original_sender_id().unwrap_or_default();
10391 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10392 let symbol = Self::deserialize_symbol(symbol)?;
10393 this.read_with(&cx, |this, _| {
10394 if let SymbolLocation::OutsideProject {
10395 abs_path,
10396 signature,
10397 } = &symbol.path
10398 {
10399 let new_signature = this.symbol_signature(&abs_path);
10400 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10401 }
10402 Ok(())
10403 })?;
10404 let buffer = this
10405 .update(&mut cx, |this, cx| {
10406 this.open_buffer_for_symbol(
10407 &Symbol {
10408 language_server_name: symbol.language_server_name,
10409 source_worktree_id: symbol.source_worktree_id,
10410 source_language_server_id: symbol.source_language_server_id,
10411 path: symbol.path,
10412 name: symbol.name,
10413 kind: symbol.kind,
10414 range: symbol.range,
10415 label: CodeLabel::default(),
10416 },
10417 cx,
10418 )
10419 })
10420 .await?;
10421
10422 this.update(&mut cx, |this, cx| {
10423 let is_private = buffer
10424 .read(cx)
10425 .file()
10426 .map(|f| f.is_private())
10427 .unwrap_or_default();
10428 if is_private {
10429 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10430 } else {
10431 this.buffer_store
10432 .update(cx, |buffer_store, cx| {
10433 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10434 })
10435 .detach_and_log_err(cx);
10436 let buffer_id = buffer.read(cx).remote_id().to_proto();
10437 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10438 }
10439 })
10440 }
10441
10442 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10443 let mut hasher = Sha256::new();
10444 hasher.update(abs_path.to_string_lossy().as_bytes());
10445 hasher.update(self.nonce.to_be_bytes());
10446 hasher.finalize().as_slice().try_into().unwrap()
10447 }
10448
10449 pub async fn handle_get_project_symbols(
10450 this: Entity<Self>,
10451 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10452 mut cx: AsyncApp,
10453 ) -> Result<proto::GetProjectSymbolsResponse> {
10454 let symbols = this
10455 .update(&mut cx, |this, cx| {
10456 this.symbols(&envelope.payload.query, cx)
10457 })
10458 .await?;
10459
10460 Ok(proto::GetProjectSymbolsResponse {
10461 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10462 })
10463 }
10464
10465 pub async fn handle_restart_language_servers(
10466 this: Entity<Self>,
10467 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10468 mut cx: AsyncApp,
10469 ) -> Result<proto::Ack> {
10470 this.update(&mut cx, |lsp_store, cx| {
10471 let buffers =
10472 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10473 lsp_store.restart_language_servers_for_buffers(
10474 buffers,
10475 envelope
10476 .payload
10477 .only_servers
10478 .into_iter()
10479 .filter_map(|selector| {
10480 Some(match selector.selector? {
10481 proto::language_server_selector::Selector::ServerId(server_id) => {
10482 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10483 }
10484 proto::language_server_selector::Selector::Name(name) => {
10485 LanguageServerSelector::Name(LanguageServerName(
10486 SharedString::from(name),
10487 ))
10488 }
10489 })
10490 })
10491 .collect(),
10492 cx,
10493 );
10494 });
10495
10496 Ok(proto::Ack {})
10497 }
10498
10499 pub async fn handle_stop_language_servers(
10500 lsp_store: Entity<Self>,
10501 envelope: TypedEnvelope<proto::StopLanguageServers>,
10502 mut cx: AsyncApp,
10503 ) -> Result<proto::Ack> {
10504 lsp_store.update(&mut cx, |lsp_store, cx| {
10505 if envelope.payload.all
10506 && envelope.payload.also_servers.is_empty()
10507 && envelope.payload.buffer_ids.is_empty()
10508 {
10509 lsp_store.stop_all_language_servers(cx);
10510 } else {
10511 let buffers =
10512 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10513 lsp_store
10514 .stop_language_servers_for_buffers(
10515 buffers,
10516 envelope
10517 .payload
10518 .also_servers
10519 .into_iter()
10520 .filter_map(|selector| {
10521 Some(match selector.selector? {
10522 proto::language_server_selector::Selector::ServerId(
10523 server_id,
10524 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10525 server_id,
10526 )),
10527 proto::language_server_selector::Selector::Name(name) => {
10528 LanguageServerSelector::Name(LanguageServerName(
10529 SharedString::from(name),
10530 ))
10531 }
10532 })
10533 })
10534 .collect(),
10535 cx,
10536 )
10537 .detach_and_log_err(cx);
10538 }
10539 });
10540
10541 Ok(proto::Ack {})
10542 }
10543
10544 pub async fn handle_cancel_language_server_work(
10545 lsp_store: Entity<Self>,
10546 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10547 mut cx: AsyncApp,
10548 ) -> Result<proto::Ack> {
10549 lsp_store.update(&mut cx, |lsp_store, cx| {
10550 if let Some(work) = envelope.payload.work {
10551 match work {
10552 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10553 let buffers =
10554 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10555 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10556 }
10557 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10558 let server_id = LanguageServerId::from_proto(work.language_server_id);
10559 let token = work
10560 .token
10561 .map(|token| {
10562 ProgressToken::from_proto(token)
10563 .context("invalid work progress token")
10564 })
10565 .transpose()?;
10566 lsp_store.cancel_language_server_work(server_id, token, cx);
10567 }
10568 }
10569 }
10570 anyhow::Ok(())
10571 })?;
10572
10573 Ok(proto::Ack {})
10574 }
10575
10576 fn buffer_ids_to_buffers(
10577 &mut self,
10578 buffer_ids: impl Iterator<Item = u64>,
10579 cx: &mut Context<Self>,
10580 ) -> Vec<Entity<Buffer>> {
10581 buffer_ids
10582 .into_iter()
10583 .flat_map(|buffer_id| {
10584 self.buffer_store
10585 .read(cx)
10586 .get(BufferId::new(buffer_id).log_err()?)
10587 })
10588 .collect::<Vec<_>>()
10589 }
10590
10591 async fn handle_apply_additional_edits_for_completion(
10592 this: Entity<Self>,
10593 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10594 mut cx: AsyncApp,
10595 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10596 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10597 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10598 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10599 let completion = Self::deserialize_completion(
10600 envelope.payload.completion.context("invalid completion")?,
10601 )?;
10602 anyhow::Ok((buffer, completion))
10603 })?;
10604
10605 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10606 this.apply_additional_edits_for_completion(
10607 buffer,
10608 Rc::new(RefCell::new(Box::new([Completion {
10609 replace_range: completion.replace_range,
10610 new_text: completion.new_text,
10611 source: completion.source,
10612 documentation: None,
10613 label: CodeLabel::default(),
10614 match_start: None,
10615 snippet_deduplication_key: None,
10616 insert_text_mode: None,
10617 icon_path: None,
10618 confirm: None,
10619 }]))),
10620 0,
10621 false,
10622 cx,
10623 )
10624 });
10625
10626 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10627 transaction: apply_additional_edits
10628 .await?
10629 .as_ref()
10630 .map(language::proto::serialize_transaction),
10631 })
10632 }
10633
10634 pub fn last_formatting_failure(&self) -> Option<&str> {
10635 self.last_formatting_failure.as_deref()
10636 }
10637
10638 pub fn reset_last_formatting_failure(&mut self) {
10639 self.last_formatting_failure = None;
10640 }
10641
10642 pub fn environment_for_buffer(
10643 &self,
10644 buffer: &Entity<Buffer>,
10645 cx: &mut Context<Self>,
10646 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10647 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10648 environment.update(cx, |env, cx| {
10649 env.buffer_environment(buffer, &self.worktree_store, cx)
10650 })
10651 } else {
10652 Task::ready(None).shared()
10653 }
10654 }
10655
10656 pub fn format(
10657 &mut self,
10658 buffers: HashSet<Entity<Buffer>>,
10659 target: LspFormatTarget,
10660 push_to_history: bool,
10661 trigger: FormatTrigger,
10662 cx: &mut Context<Self>,
10663 ) -> Task<anyhow::Result<ProjectTransaction>> {
10664 let logger = zlog::scoped!("format");
10665 if self.as_local().is_some() {
10666 zlog::trace!(logger => "Formatting locally");
10667 let logger = zlog::scoped!(logger => "local");
10668 let buffers = buffers
10669 .into_iter()
10670 .map(|buffer_handle| {
10671 let buffer = buffer_handle.read(cx);
10672 let buffer_abs_path = File::from_dyn(buffer.file())
10673 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10674
10675 (buffer_handle, buffer_abs_path, buffer.remote_id())
10676 })
10677 .collect::<Vec<_>>();
10678
10679 cx.spawn(async move |lsp_store, cx| {
10680 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10681
10682 for (handle, abs_path, id) in buffers {
10683 let env = lsp_store
10684 .update(cx, |lsp_store, cx| {
10685 lsp_store.environment_for_buffer(&handle, cx)
10686 })?
10687 .await;
10688
10689 let ranges = match &target {
10690 LspFormatTarget::Buffers => None,
10691 LspFormatTarget::Ranges(ranges) => {
10692 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10693 }
10694 };
10695
10696 formattable_buffers.push(FormattableBuffer {
10697 handle,
10698 abs_path,
10699 env,
10700 ranges,
10701 });
10702 }
10703 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10704
10705 let format_timer = zlog::time!(logger => "Formatting buffers");
10706 let result = LocalLspStore::format_locally(
10707 lsp_store.clone(),
10708 formattable_buffers,
10709 push_to_history,
10710 trigger,
10711 logger,
10712 cx,
10713 )
10714 .await;
10715 format_timer.end();
10716
10717 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10718
10719 lsp_store.update(cx, |lsp_store, _| {
10720 lsp_store.update_last_formatting_failure(&result);
10721 })?;
10722
10723 result
10724 })
10725 } else if let Some((client, project_id)) = self.upstream_client() {
10726 zlog::trace!(logger => "Formatting remotely");
10727 let logger = zlog::scoped!(logger => "remote");
10728 // Don't support formatting ranges via remote
10729 match target {
10730 LspFormatTarget::Buffers => {}
10731 LspFormatTarget::Ranges(_) => {
10732 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10733 return Task::ready(Ok(ProjectTransaction::default()));
10734 }
10735 }
10736
10737 let buffer_store = self.buffer_store();
10738 cx.spawn(async move |lsp_store, cx| {
10739 zlog::trace!(logger => "Sending remote format request");
10740 let request_timer = zlog::time!(logger => "remote format request");
10741 let result = client
10742 .request(proto::FormatBuffers {
10743 project_id,
10744 trigger: trigger as i32,
10745 buffer_ids: buffers
10746 .iter()
10747 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10748 .collect(),
10749 })
10750 .await
10751 .and_then(|result| result.transaction.context("missing transaction"));
10752 request_timer.end();
10753
10754 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10755
10756 lsp_store.update(cx, |lsp_store, _| {
10757 lsp_store.update_last_formatting_failure(&result);
10758 })?;
10759
10760 let transaction_response = result?;
10761 let _timer = zlog::time!(logger => "deserializing project transaction");
10762 buffer_store
10763 .update(cx, |buffer_store, cx| {
10764 buffer_store.deserialize_project_transaction(
10765 transaction_response,
10766 push_to_history,
10767 cx,
10768 )
10769 })
10770 .await
10771 })
10772 } else {
10773 zlog::trace!(logger => "Not formatting");
10774 Task::ready(Ok(ProjectTransaction::default()))
10775 }
10776 }
10777
10778 async fn handle_format_buffers(
10779 this: Entity<Self>,
10780 envelope: TypedEnvelope<proto::FormatBuffers>,
10781 mut cx: AsyncApp,
10782 ) -> Result<proto::FormatBuffersResponse> {
10783 let sender_id = envelope.original_sender_id().unwrap_or_default();
10784 let format = this.update(&mut cx, |this, cx| {
10785 let mut buffers = HashSet::default();
10786 for buffer_id in &envelope.payload.buffer_ids {
10787 let buffer_id = BufferId::new(*buffer_id)?;
10788 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10789 }
10790 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10791 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10792 })?;
10793
10794 let project_transaction = format.await?;
10795 let project_transaction = this.update(&mut cx, |this, cx| {
10796 this.buffer_store.update(cx, |buffer_store, cx| {
10797 buffer_store.serialize_project_transaction_for_peer(
10798 project_transaction,
10799 sender_id,
10800 cx,
10801 )
10802 })
10803 });
10804 Ok(proto::FormatBuffersResponse {
10805 transaction: Some(project_transaction),
10806 })
10807 }
10808
10809 async fn handle_apply_code_action_kind(
10810 this: Entity<Self>,
10811 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10812 mut cx: AsyncApp,
10813 ) -> Result<proto::ApplyCodeActionKindResponse> {
10814 let sender_id = envelope.original_sender_id().unwrap_or_default();
10815 let format = this.update(&mut cx, |this, cx| {
10816 let mut buffers = HashSet::default();
10817 for buffer_id in &envelope.payload.buffer_ids {
10818 let buffer_id = BufferId::new(*buffer_id)?;
10819 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10820 }
10821 let kind = match envelope.payload.kind.as_str() {
10822 "" => CodeActionKind::EMPTY,
10823 "quickfix" => CodeActionKind::QUICKFIX,
10824 "refactor" => CodeActionKind::REFACTOR,
10825 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10826 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10827 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10828 "source" => CodeActionKind::SOURCE,
10829 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10830 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10831 _ => anyhow::bail!(
10832 "Invalid code action kind {}",
10833 envelope.payload.kind.as_str()
10834 ),
10835 };
10836 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10837 })?;
10838
10839 let project_transaction = format.await?;
10840 let project_transaction = this.update(&mut cx, |this, cx| {
10841 this.buffer_store.update(cx, |buffer_store, cx| {
10842 buffer_store.serialize_project_transaction_for_peer(
10843 project_transaction,
10844 sender_id,
10845 cx,
10846 )
10847 })
10848 });
10849 Ok(proto::ApplyCodeActionKindResponse {
10850 transaction: Some(project_transaction),
10851 })
10852 }
10853
10854 async fn shutdown_language_server(
10855 server_state: Option<LanguageServerState>,
10856 name: LanguageServerName,
10857 cx: &mut AsyncApp,
10858 ) {
10859 let server = match server_state {
10860 Some(LanguageServerState::Starting { startup, .. }) => {
10861 let mut timer = cx
10862 .background_executor()
10863 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10864 .fuse();
10865
10866 select! {
10867 server = startup.fuse() => server,
10868 () = timer => {
10869 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10870 None
10871 },
10872 }
10873 }
10874
10875 Some(LanguageServerState::Running { server, .. }) => Some(server),
10876
10877 None => None,
10878 };
10879
10880 if let Some(server) = server
10881 && let Some(shutdown) = server.shutdown()
10882 {
10883 shutdown.await;
10884 }
10885 }
10886
10887 // Returns a list of all of the worktrees which no longer have a language server and the root path
10888 // for the stopped server
10889 fn stop_local_language_server(
10890 &mut self,
10891 server_id: LanguageServerId,
10892 cx: &mut Context<Self>,
10893 ) -> Task<()> {
10894 let local = match &mut self.mode {
10895 LspStoreMode::Local(local) => local,
10896 _ => {
10897 return Task::ready(());
10898 }
10899 };
10900
10901 // Remove this server ID from all entries in the given worktree.
10902 local
10903 .language_server_ids
10904 .retain(|_, state| state.id != server_id);
10905 self.buffer_store.update(cx, |buffer_store, cx| {
10906 for buffer in buffer_store.buffers() {
10907 buffer.update(cx, |buffer, cx| {
10908 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10909 buffer.set_completion_triggers(server_id, Default::default(), cx);
10910 });
10911 }
10912 });
10913
10914 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10915 summaries.retain(|path, summaries_by_server_id| {
10916 if summaries_by_server_id.remove(&server_id).is_some() {
10917 if let Some((client, project_id)) = self.downstream_client.clone() {
10918 client
10919 .send(proto::UpdateDiagnosticSummary {
10920 project_id,
10921 worktree_id: worktree_id.to_proto(),
10922 summary: Some(proto::DiagnosticSummary {
10923 path: path.as_ref().to_proto(),
10924 language_server_id: server_id.0 as u64,
10925 error_count: 0,
10926 warning_count: 0,
10927 }),
10928 more_summaries: Vec::new(),
10929 })
10930 .log_err();
10931 }
10932 !summaries_by_server_id.is_empty()
10933 } else {
10934 true
10935 }
10936 });
10937 }
10938
10939 let local = self.as_local_mut().unwrap();
10940 for diagnostics in local.diagnostics.values_mut() {
10941 diagnostics.retain(|_, diagnostics_by_server_id| {
10942 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10943 diagnostics_by_server_id.remove(ix);
10944 !diagnostics_by_server_id.is_empty()
10945 } else {
10946 true
10947 }
10948 });
10949 }
10950 local.language_server_watched_paths.remove(&server_id);
10951
10952 let server_state = local.language_servers.remove(&server_id);
10953 self.cleanup_lsp_data(server_id);
10954 let name = self
10955 .language_server_statuses
10956 .remove(&server_id)
10957 .map(|status| status.name)
10958 .or_else(|| {
10959 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10960 Some(adapter.name())
10961 } else {
10962 None
10963 }
10964 });
10965
10966 if let Some(name) = name {
10967 log::info!("stopping language server {name}");
10968 self.languages
10969 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10970 cx.notify();
10971
10972 return cx.spawn(async move |lsp_store, cx| {
10973 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10974 lsp_store
10975 .update(cx, |lsp_store, cx| {
10976 lsp_store
10977 .languages
10978 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10979 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10980 cx.notify();
10981 })
10982 .ok();
10983 });
10984 }
10985
10986 if server_state.is_some() {
10987 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10988 }
10989 Task::ready(())
10990 }
10991
10992 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10993 if let Some((client, project_id)) = self.upstream_client() {
10994 let request = client.request(proto::StopLanguageServers {
10995 project_id,
10996 buffer_ids: Vec::new(),
10997 also_servers: Vec::new(),
10998 all: true,
10999 });
11000 cx.background_spawn(request).detach_and_log_err(cx);
11001 } else {
11002 let Some(local) = self.as_local_mut() else {
11003 return;
11004 };
11005 let language_servers_to_stop = local
11006 .language_server_ids
11007 .values()
11008 .map(|state| state.id)
11009 .collect();
11010 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11011 let tasks = language_servers_to_stop
11012 .into_iter()
11013 .map(|server| self.stop_local_language_server(server, cx))
11014 .collect::<Vec<_>>();
11015 cx.background_spawn(async move {
11016 futures::future::join_all(tasks).await;
11017 })
11018 .detach();
11019 }
11020 }
11021
11022 pub fn restart_language_servers_for_buffers(
11023 &mut self,
11024 buffers: Vec<Entity<Buffer>>,
11025 only_restart_servers: HashSet<LanguageServerSelector>,
11026 cx: &mut Context<Self>,
11027 ) {
11028 if let Some((client, project_id)) = self.upstream_client() {
11029 let request = client.request(proto::RestartLanguageServers {
11030 project_id,
11031 buffer_ids: buffers
11032 .into_iter()
11033 .map(|b| b.read(cx).remote_id().to_proto())
11034 .collect(),
11035 only_servers: only_restart_servers
11036 .into_iter()
11037 .map(|selector| {
11038 let selector = match selector {
11039 LanguageServerSelector::Id(language_server_id) => {
11040 proto::language_server_selector::Selector::ServerId(
11041 language_server_id.to_proto(),
11042 )
11043 }
11044 LanguageServerSelector::Name(language_server_name) => {
11045 proto::language_server_selector::Selector::Name(
11046 language_server_name.to_string(),
11047 )
11048 }
11049 };
11050 proto::LanguageServerSelector {
11051 selector: Some(selector),
11052 }
11053 })
11054 .collect(),
11055 all: false,
11056 });
11057 cx.background_spawn(request).detach_and_log_err(cx);
11058 } else {
11059 let stop_task = if only_restart_servers.is_empty() {
11060 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11061 } else {
11062 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11063 };
11064 cx.spawn(async move |lsp_store, cx| {
11065 stop_task.await;
11066 lsp_store.update(cx, |lsp_store, cx| {
11067 for buffer in buffers {
11068 lsp_store.register_buffer_with_language_servers(
11069 &buffer,
11070 only_restart_servers.clone(),
11071 true,
11072 cx,
11073 );
11074 }
11075 })
11076 })
11077 .detach();
11078 }
11079 }
11080
11081 pub fn stop_language_servers_for_buffers(
11082 &mut self,
11083 buffers: Vec<Entity<Buffer>>,
11084 also_stop_servers: HashSet<LanguageServerSelector>,
11085 cx: &mut Context<Self>,
11086 ) -> Task<Result<()>> {
11087 if let Some((client, project_id)) = self.upstream_client() {
11088 let request = client.request(proto::StopLanguageServers {
11089 project_id,
11090 buffer_ids: buffers
11091 .into_iter()
11092 .map(|b| b.read(cx).remote_id().to_proto())
11093 .collect(),
11094 also_servers: also_stop_servers
11095 .into_iter()
11096 .map(|selector| {
11097 let selector = match selector {
11098 LanguageServerSelector::Id(language_server_id) => {
11099 proto::language_server_selector::Selector::ServerId(
11100 language_server_id.to_proto(),
11101 )
11102 }
11103 LanguageServerSelector::Name(language_server_name) => {
11104 proto::language_server_selector::Selector::Name(
11105 language_server_name.to_string(),
11106 )
11107 }
11108 };
11109 proto::LanguageServerSelector {
11110 selector: Some(selector),
11111 }
11112 })
11113 .collect(),
11114 all: false,
11115 });
11116 cx.background_spawn(async move {
11117 let _ = request.await?;
11118 Ok(())
11119 })
11120 } else {
11121 let task =
11122 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11123 cx.background_spawn(async move {
11124 task.await;
11125 Ok(())
11126 })
11127 }
11128 }
11129
11130 fn stop_local_language_servers_for_buffers(
11131 &mut self,
11132 buffers: &[Entity<Buffer>],
11133 also_stop_servers: HashSet<LanguageServerSelector>,
11134 cx: &mut Context<Self>,
11135 ) -> Task<()> {
11136 let Some(local) = self.as_local_mut() else {
11137 return Task::ready(());
11138 };
11139 let mut language_server_names_to_stop = BTreeSet::default();
11140 let mut language_servers_to_stop = also_stop_servers
11141 .into_iter()
11142 .flat_map(|selector| match selector {
11143 LanguageServerSelector::Id(id) => Some(id),
11144 LanguageServerSelector::Name(name) => {
11145 language_server_names_to_stop.insert(name);
11146 None
11147 }
11148 })
11149 .collect::<BTreeSet<_>>();
11150
11151 let mut covered_worktrees = HashSet::default();
11152 for buffer in buffers {
11153 buffer.update(cx, |buffer, cx| {
11154 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11155 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11156 && covered_worktrees.insert(worktree_id)
11157 {
11158 language_server_names_to_stop.retain(|name| {
11159 let old_ids_count = language_servers_to_stop.len();
11160 let all_language_servers_with_this_name = local
11161 .language_server_ids
11162 .iter()
11163 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11164 language_servers_to_stop.extend(all_language_servers_with_this_name);
11165 old_ids_count == language_servers_to_stop.len()
11166 });
11167 }
11168 });
11169 }
11170 for name in language_server_names_to_stop {
11171 language_servers_to_stop.extend(
11172 local
11173 .language_server_ids
11174 .iter()
11175 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11176 );
11177 }
11178
11179 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11180 let tasks = language_servers_to_stop
11181 .into_iter()
11182 .map(|server| self.stop_local_language_server(server, cx))
11183 .collect::<Vec<_>>();
11184
11185 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11186 }
11187
11188 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11189 let (worktree, relative_path) =
11190 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11191
11192 let project_path = ProjectPath {
11193 worktree_id: worktree.read(cx).id(),
11194 path: relative_path,
11195 };
11196
11197 Some(
11198 self.buffer_store()
11199 .read(cx)
11200 .get_by_path(&project_path)?
11201 .read(cx),
11202 )
11203 }
11204
11205 #[cfg(any(test, feature = "test-support"))]
11206 pub fn update_diagnostics(
11207 &mut self,
11208 server_id: LanguageServerId,
11209 diagnostics: lsp::PublishDiagnosticsParams,
11210 result_id: Option<SharedString>,
11211 source_kind: DiagnosticSourceKind,
11212 disk_based_sources: &[String],
11213 cx: &mut Context<Self>,
11214 ) -> Result<()> {
11215 self.merge_lsp_diagnostics(
11216 source_kind,
11217 vec![DocumentDiagnosticsUpdate {
11218 diagnostics,
11219 result_id,
11220 server_id,
11221 disk_based_sources: Cow::Borrowed(disk_based_sources),
11222 registration_id: None,
11223 }],
11224 |_, _, _| false,
11225 cx,
11226 )
11227 }
11228
11229 pub fn merge_lsp_diagnostics(
11230 &mut self,
11231 source_kind: DiagnosticSourceKind,
11232 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11233 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11234 cx: &mut Context<Self>,
11235 ) -> Result<()> {
11236 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11237 let updates = lsp_diagnostics
11238 .into_iter()
11239 .filter_map(|update| {
11240 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11241 Some(DocumentDiagnosticsUpdate {
11242 diagnostics: self.lsp_to_document_diagnostics(
11243 abs_path,
11244 source_kind,
11245 update.server_id,
11246 update.diagnostics,
11247 &update.disk_based_sources,
11248 update.registration_id.clone(),
11249 ),
11250 result_id: update.result_id,
11251 server_id: update.server_id,
11252 disk_based_sources: update.disk_based_sources,
11253 registration_id: update.registration_id,
11254 })
11255 })
11256 .collect();
11257 self.merge_diagnostic_entries(updates, merge, cx)?;
11258 Ok(())
11259 }
11260
11261 fn lsp_to_document_diagnostics(
11262 &mut self,
11263 document_abs_path: PathBuf,
11264 source_kind: DiagnosticSourceKind,
11265 server_id: LanguageServerId,
11266 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11267 disk_based_sources: &[String],
11268 registration_id: Option<SharedString>,
11269 ) -> DocumentDiagnostics {
11270 let mut diagnostics = Vec::default();
11271 let mut primary_diagnostic_group_ids = HashMap::default();
11272 let mut sources_by_group_id = HashMap::default();
11273 let mut supporting_diagnostics = HashMap::default();
11274
11275 let adapter = self.language_server_adapter_for_id(server_id);
11276
11277 // Ensure that primary diagnostics are always the most severe
11278 lsp_diagnostics
11279 .diagnostics
11280 .sort_by_key(|item| item.severity);
11281
11282 for diagnostic in &lsp_diagnostics.diagnostics {
11283 let source = diagnostic.source.as_ref();
11284 let range = range_from_lsp(diagnostic.range);
11285 let is_supporting = diagnostic
11286 .related_information
11287 .as_ref()
11288 .is_some_and(|infos| {
11289 infos.iter().any(|info| {
11290 primary_diagnostic_group_ids.contains_key(&(
11291 source,
11292 diagnostic.code.clone(),
11293 range_from_lsp(info.location.range),
11294 ))
11295 })
11296 });
11297
11298 let is_unnecessary = diagnostic
11299 .tags
11300 .as_ref()
11301 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11302
11303 let underline = self
11304 .language_server_adapter_for_id(server_id)
11305 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11306
11307 if is_supporting {
11308 supporting_diagnostics.insert(
11309 (source, diagnostic.code.clone(), range),
11310 (diagnostic.severity, is_unnecessary),
11311 );
11312 } else {
11313 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11314 let is_disk_based =
11315 source.is_some_and(|source| disk_based_sources.contains(source));
11316
11317 sources_by_group_id.insert(group_id, source);
11318 primary_diagnostic_group_ids
11319 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11320
11321 diagnostics.push(DiagnosticEntry {
11322 range,
11323 diagnostic: Diagnostic {
11324 source: diagnostic.source.clone(),
11325 source_kind,
11326 code: diagnostic.code.clone(),
11327 code_description: diagnostic
11328 .code_description
11329 .as_ref()
11330 .and_then(|d| d.href.clone()),
11331 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11332 markdown: adapter.as_ref().and_then(|adapter| {
11333 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11334 }),
11335 message: diagnostic.message.trim().to_string(),
11336 group_id,
11337 is_primary: true,
11338 is_disk_based,
11339 is_unnecessary,
11340 underline,
11341 data: diagnostic.data.clone(),
11342 registration_id: registration_id.clone(),
11343 },
11344 });
11345 if let Some(infos) = &diagnostic.related_information {
11346 for info in infos {
11347 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11348 let range = range_from_lsp(info.location.range);
11349 diagnostics.push(DiagnosticEntry {
11350 range,
11351 diagnostic: Diagnostic {
11352 source: diagnostic.source.clone(),
11353 source_kind,
11354 code: diagnostic.code.clone(),
11355 code_description: diagnostic
11356 .code_description
11357 .as_ref()
11358 .and_then(|d| d.href.clone()),
11359 severity: DiagnosticSeverity::INFORMATION,
11360 markdown: adapter.as_ref().and_then(|adapter| {
11361 adapter.diagnostic_message_to_markdown(&info.message)
11362 }),
11363 message: info.message.trim().to_string(),
11364 group_id,
11365 is_primary: false,
11366 is_disk_based,
11367 is_unnecessary: false,
11368 underline,
11369 data: diagnostic.data.clone(),
11370 registration_id: registration_id.clone(),
11371 },
11372 });
11373 }
11374 }
11375 }
11376 }
11377 }
11378
11379 for entry in &mut diagnostics {
11380 let diagnostic = &mut entry.diagnostic;
11381 if !diagnostic.is_primary {
11382 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11383 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11384 source,
11385 diagnostic.code.clone(),
11386 entry.range.clone(),
11387 )) {
11388 if let Some(severity) = severity {
11389 diagnostic.severity = severity;
11390 }
11391 diagnostic.is_unnecessary = is_unnecessary;
11392 }
11393 }
11394 }
11395
11396 DocumentDiagnostics {
11397 diagnostics,
11398 document_abs_path,
11399 version: lsp_diagnostics.version,
11400 }
11401 }
11402
11403 fn insert_newly_running_language_server(
11404 &mut self,
11405 adapter: Arc<CachedLspAdapter>,
11406 language_server: Arc<LanguageServer>,
11407 server_id: LanguageServerId,
11408 key: LanguageServerSeed,
11409 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11410 cx: &mut Context<Self>,
11411 ) {
11412 let Some(local) = self.as_local_mut() else {
11413 return;
11414 };
11415 // If the language server for this key doesn't match the server id, don't store the
11416 // server. Which will cause it to be dropped, killing the process
11417 if local
11418 .language_server_ids
11419 .get(&key)
11420 .map(|state| state.id != server_id)
11421 .unwrap_or(false)
11422 {
11423 return;
11424 }
11425
11426 // Update language_servers collection with Running variant of LanguageServerState
11427 // indicating that the server is up and running and ready
11428 let workspace_folders = workspace_folders.lock().clone();
11429 language_server.set_workspace_folders(workspace_folders);
11430
11431 let workspace_diagnostics_refresh_tasks = language_server
11432 .capabilities()
11433 .diagnostic_provider
11434 .and_then(|provider| {
11435 local
11436 .language_server_dynamic_registrations
11437 .entry(server_id)
11438 .or_default()
11439 .diagnostics
11440 .entry(None)
11441 .or_insert(provider.clone());
11442 let workspace_refresher =
11443 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11444
11445 Some((None, workspace_refresher))
11446 })
11447 .into_iter()
11448 .collect();
11449 local.language_servers.insert(
11450 server_id,
11451 LanguageServerState::Running {
11452 workspace_diagnostics_refresh_tasks,
11453 adapter: adapter.clone(),
11454 server: language_server.clone(),
11455 simulate_disk_based_diagnostics_completion: None,
11456 },
11457 );
11458 local
11459 .languages
11460 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11461 if let Some(file_ops_caps) = language_server
11462 .capabilities()
11463 .workspace
11464 .as_ref()
11465 .and_then(|ws| ws.file_operations.as_ref())
11466 {
11467 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11468 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11469 if did_rename_caps.or(will_rename_caps).is_some() {
11470 let watcher = RenamePathsWatchedForServer::default()
11471 .with_did_rename_patterns(did_rename_caps)
11472 .with_will_rename_patterns(will_rename_caps);
11473 local
11474 .language_server_paths_watched_for_rename
11475 .insert(server_id, watcher);
11476 }
11477 }
11478
11479 self.language_server_statuses.insert(
11480 server_id,
11481 LanguageServerStatus {
11482 name: language_server.name(),
11483 server_version: language_server.version(),
11484 pending_work: Default::default(),
11485 has_pending_diagnostic_updates: false,
11486 progress_tokens: Default::default(),
11487 worktree: Some(key.worktree_id),
11488 binary: Some(language_server.binary().clone()),
11489 configuration: Some(language_server.configuration().clone()),
11490 workspace_folders: language_server.workspace_folders(),
11491 },
11492 );
11493
11494 cx.emit(LspStoreEvent::LanguageServerAdded(
11495 server_id,
11496 language_server.name(),
11497 Some(key.worktree_id),
11498 ));
11499
11500 let server_capabilities = language_server.capabilities();
11501 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11502 downstream_client
11503 .send(proto::StartLanguageServer {
11504 project_id: *project_id,
11505 server: Some(proto::LanguageServer {
11506 id: server_id.to_proto(),
11507 name: language_server.name().to_string(),
11508 worktree_id: Some(key.worktree_id.to_proto()),
11509 }),
11510 capabilities: serde_json::to_string(&server_capabilities)
11511 .expect("serializing server LSP capabilities"),
11512 })
11513 .log_err();
11514 }
11515 self.lsp_server_capabilities
11516 .insert(server_id, server_capabilities);
11517
11518 // Tell the language server about every open buffer in the worktree that matches the language.
11519 // Also check for buffers in worktrees that reused this server
11520 let mut worktrees_using_server = vec![key.worktree_id];
11521 if let Some(local) = self.as_local() {
11522 // Find all worktrees that have this server in their language server tree
11523 for (worktree_id, servers) in &local.lsp_tree.instances {
11524 if *worktree_id != key.worktree_id {
11525 for server_map in servers.roots.values() {
11526 if server_map
11527 .values()
11528 .any(|(node, _)| node.id() == Some(server_id))
11529 {
11530 worktrees_using_server.push(*worktree_id);
11531 }
11532 }
11533 }
11534 }
11535 }
11536
11537 let mut buffer_paths_registered = Vec::new();
11538 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11539 let mut lsp_adapters = HashMap::default();
11540 for buffer_handle in buffer_store.buffers() {
11541 let buffer = buffer_handle.read(cx);
11542 let file = match File::from_dyn(buffer.file()) {
11543 Some(file) => file,
11544 None => continue,
11545 };
11546 let language = match buffer.language() {
11547 Some(language) => language,
11548 None => continue,
11549 };
11550
11551 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11552 || !lsp_adapters
11553 .entry(language.name())
11554 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11555 .iter()
11556 .any(|a| a.name == key.name)
11557 {
11558 continue;
11559 }
11560 // didOpen
11561 let file = match file.as_local() {
11562 Some(file) => file,
11563 None => continue,
11564 };
11565
11566 let local = self.as_local_mut().unwrap();
11567
11568 let buffer_id = buffer.remote_id();
11569 if local.registered_buffers.contains_key(&buffer_id) {
11570 let versions = local
11571 .buffer_snapshots
11572 .entry(buffer_id)
11573 .or_default()
11574 .entry(server_id)
11575 .and_modify(|_| {
11576 assert!(
11577 false,
11578 "There should not be an existing snapshot for a newly inserted buffer"
11579 )
11580 })
11581 .or_insert_with(|| {
11582 vec![LspBufferSnapshot {
11583 version: 0,
11584 snapshot: buffer.text_snapshot(),
11585 }]
11586 });
11587
11588 let snapshot = versions.last().unwrap();
11589 let version = snapshot.version;
11590 let initial_snapshot = &snapshot.snapshot;
11591 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11592 language_server.register_buffer(
11593 uri,
11594 adapter.language_id(&language.name()),
11595 version,
11596 initial_snapshot.text(),
11597 );
11598 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11599 local
11600 .buffers_opened_in_servers
11601 .entry(buffer_id)
11602 .or_default()
11603 .insert(server_id);
11604 }
11605 buffer_handle.update(cx, |buffer, cx| {
11606 buffer.set_completion_triggers(
11607 server_id,
11608 language_server
11609 .capabilities()
11610 .completion_provider
11611 .as_ref()
11612 .and_then(|provider| {
11613 provider
11614 .trigger_characters
11615 .as_ref()
11616 .map(|characters| characters.iter().cloned().collect())
11617 })
11618 .unwrap_or_default(),
11619 cx,
11620 )
11621 });
11622 }
11623 });
11624
11625 for (buffer_id, abs_path) in buffer_paths_registered {
11626 cx.emit(LspStoreEvent::LanguageServerUpdate {
11627 language_server_id: server_id,
11628 name: Some(adapter.name()),
11629 message: proto::update_language_server::Variant::RegisteredForBuffer(
11630 proto::RegisteredForBuffer {
11631 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11632 buffer_id: buffer_id.to_proto(),
11633 },
11634 ),
11635 });
11636 }
11637
11638 cx.notify();
11639 }
11640
11641 pub fn language_servers_running_disk_based_diagnostics(
11642 &self,
11643 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11644 self.language_server_statuses
11645 .iter()
11646 .filter_map(|(id, status)| {
11647 if status.has_pending_diagnostic_updates {
11648 Some(*id)
11649 } else {
11650 None
11651 }
11652 })
11653 }
11654
11655 pub(crate) fn cancel_language_server_work_for_buffers(
11656 &mut self,
11657 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11658 cx: &mut Context<Self>,
11659 ) {
11660 if let Some((client, project_id)) = self.upstream_client() {
11661 let request = client.request(proto::CancelLanguageServerWork {
11662 project_id,
11663 work: Some(proto::cancel_language_server_work::Work::Buffers(
11664 proto::cancel_language_server_work::Buffers {
11665 buffer_ids: buffers
11666 .into_iter()
11667 .map(|b| b.read(cx).remote_id().to_proto())
11668 .collect(),
11669 },
11670 )),
11671 });
11672 cx.background_spawn(request).detach_and_log_err(cx);
11673 } else if let Some(local) = self.as_local() {
11674 let servers = buffers
11675 .into_iter()
11676 .flat_map(|buffer| {
11677 buffer.update(cx, |buffer, cx| {
11678 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11679 })
11680 })
11681 .collect::<HashSet<_>>();
11682 for server_id in servers {
11683 self.cancel_language_server_work(server_id, None, cx);
11684 }
11685 }
11686 }
11687
11688 pub(crate) fn cancel_language_server_work(
11689 &mut self,
11690 server_id: LanguageServerId,
11691 token_to_cancel: Option<ProgressToken>,
11692 cx: &mut Context<Self>,
11693 ) {
11694 if let Some(local) = self.as_local() {
11695 let status = self.language_server_statuses.get(&server_id);
11696 let server = local.language_servers.get(&server_id);
11697 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11698 {
11699 for (token, progress) in &status.pending_work {
11700 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11701 && token != token_to_cancel
11702 {
11703 continue;
11704 }
11705 if progress.is_cancellable {
11706 server
11707 .notify::<lsp::notification::WorkDoneProgressCancel>(
11708 WorkDoneProgressCancelParams {
11709 token: token.to_lsp(),
11710 },
11711 )
11712 .ok();
11713 }
11714 }
11715 }
11716 } else if let Some((client, project_id)) = self.upstream_client() {
11717 let request = client.request(proto::CancelLanguageServerWork {
11718 project_id,
11719 work: Some(
11720 proto::cancel_language_server_work::Work::LanguageServerWork(
11721 proto::cancel_language_server_work::LanguageServerWork {
11722 language_server_id: server_id.to_proto(),
11723 token: token_to_cancel.map(|token| token.to_proto()),
11724 },
11725 ),
11726 ),
11727 });
11728 cx.background_spawn(request).detach_and_log_err(cx);
11729 }
11730 }
11731
11732 fn register_supplementary_language_server(
11733 &mut self,
11734 id: LanguageServerId,
11735 name: LanguageServerName,
11736 server: Arc<LanguageServer>,
11737 cx: &mut Context<Self>,
11738 ) {
11739 if let Some(local) = self.as_local_mut() {
11740 local
11741 .supplementary_language_servers
11742 .insert(id, (name.clone(), server));
11743 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11744 }
11745 }
11746
11747 fn unregister_supplementary_language_server(
11748 &mut self,
11749 id: LanguageServerId,
11750 cx: &mut Context<Self>,
11751 ) {
11752 if let Some(local) = self.as_local_mut() {
11753 local.supplementary_language_servers.remove(&id);
11754 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11755 }
11756 }
11757
11758 pub(crate) fn supplementary_language_servers(
11759 &self,
11760 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11761 self.as_local().into_iter().flat_map(|local| {
11762 local
11763 .supplementary_language_servers
11764 .iter()
11765 .map(|(id, (name, _))| (*id, name.clone()))
11766 })
11767 }
11768
11769 pub fn language_server_adapter_for_id(
11770 &self,
11771 id: LanguageServerId,
11772 ) -> Option<Arc<CachedLspAdapter>> {
11773 self.as_local()
11774 .and_then(|local| local.language_servers.get(&id))
11775 .and_then(|language_server_state| match language_server_state {
11776 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11777 _ => None,
11778 })
11779 }
11780
11781 pub(super) fn update_local_worktree_language_servers(
11782 &mut self,
11783 worktree_handle: &Entity<Worktree>,
11784 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11785 cx: &mut Context<Self>,
11786 ) {
11787 if changes.is_empty() {
11788 return;
11789 }
11790
11791 let Some(local) = self.as_local() else { return };
11792
11793 local.prettier_store.update(cx, |prettier_store, cx| {
11794 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11795 });
11796
11797 let worktree_id = worktree_handle.read(cx).id();
11798 let mut language_server_ids = local
11799 .language_server_ids
11800 .iter()
11801 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11802 .collect::<Vec<_>>();
11803 language_server_ids.sort();
11804 language_server_ids.dedup();
11805
11806 // let abs_path = worktree_handle.read(cx).abs_path();
11807 for server_id in &language_server_ids {
11808 if let Some(LanguageServerState::Running { server, .. }) =
11809 local.language_servers.get(server_id)
11810 && let Some(watched_paths) = local
11811 .language_server_watched_paths
11812 .get(server_id)
11813 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11814 {
11815 let params = lsp::DidChangeWatchedFilesParams {
11816 changes: changes
11817 .iter()
11818 .filter_map(|(path, _, change)| {
11819 if !watched_paths.is_match(path.as_std_path()) {
11820 return None;
11821 }
11822 let typ = match change {
11823 PathChange::Loaded => return None,
11824 PathChange::Added => lsp::FileChangeType::CREATED,
11825 PathChange::Removed => lsp::FileChangeType::DELETED,
11826 PathChange::Updated => lsp::FileChangeType::CHANGED,
11827 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11828 };
11829 let uri = lsp::Uri::from_file_path(
11830 worktree_handle.read(cx).absolutize(&path),
11831 )
11832 .ok()?;
11833 Some(lsp::FileEvent { uri, typ })
11834 })
11835 .collect(),
11836 };
11837 if !params.changes.is_empty() {
11838 server
11839 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11840 .ok();
11841 }
11842 }
11843 }
11844 for (path, _, _) in changes {
11845 if let Some(file_name) = path.file_name()
11846 && local.watched_manifest_filenames.contains(file_name)
11847 {
11848 self.request_workspace_config_refresh();
11849 break;
11850 }
11851 }
11852 }
11853
11854 pub fn wait_for_remote_buffer(
11855 &mut self,
11856 id: BufferId,
11857 cx: &mut Context<Self>,
11858 ) -> Task<Result<Entity<Buffer>>> {
11859 self.buffer_store.update(cx, |buffer_store, cx| {
11860 buffer_store.wait_for_remote_buffer(id, cx)
11861 })
11862 }
11863
11864 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11865 let mut result = proto::Symbol {
11866 language_server_name: symbol.language_server_name.0.to_string(),
11867 source_worktree_id: symbol.source_worktree_id.to_proto(),
11868 language_server_id: symbol.source_language_server_id.to_proto(),
11869 name: symbol.name.clone(),
11870 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11871 start: Some(proto::PointUtf16 {
11872 row: symbol.range.start.0.row,
11873 column: symbol.range.start.0.column,
11874 }),
11875 end: Some(proto::PointUtf16 {
11876 row: symbol.range.end.0.row,
11877 column: symbol.range.end.0.column,
11878 }),
11879 worktree_id: Default::default(),
11880 path: Default::default(),
11881 signature: Default::default(),
11882 };
11883 match &symbol.path {
11884 SymbolLocation::InProject(path) => {
11885 result.worktree_id = path.worktree_id.to_proto();
11886 result.path = path.path.to_proto();
11887 }
11888 SymbolLocation::OutsideProject {
11889 abs_path,
11890 signature,
11891 } => {
11892 result.path = abs_path.to_string_lossy().into_owned();
11893 result.signature = signature.to_vec();
11894 }
11895 }
11896 result
11897 }
11898
11899 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11900 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11901 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11902 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11903
11904 let path = if serialized_symbol.signature.is_empty() {
11905 SymbolLocation::InProject(ProjectPath {
11906 worktree_id,
11907 path: RelPath::from_proto(&serialized_symbol.path)
11908 .context("invalid symbol path")?,
11909 })
11910 } else {
11911 SymbolLocation::OutsideProject {
11912 abs_path: Path::new(&serialized_symbol.path).into(),
11913 signature: serialized_symbol
11914 .signature
11915 .try_into()
11916 .map_err(|_| anyhow!("invalid signature"))?,
11917 }
11918 };
11919
11920 let start = serialized_symbol.start.context("invalid start")?;
11921 let end = serialized_symbol.end.context("invalid end")?;
11922 Ok(CoreSymbol {
11923 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11924 source_worktree_id,
11925 source_language_server_id: LanguageServerId::from_proto(
11926 serialized_symbol.language_server_id,
11927 ),
11928 path,
11929 name: serialized_symbol.name,
11930 range: Unclipped(PointUtf16::new(start.row, start.column))
11931 ..Unclipped(PointUtf16::new(end.row, end.column)),
11932 kind,
11933 })
11934 }
11935
11936 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11937 let mut serialized_completion = proto::Completion {
11938 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11939 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11940 new_text: completion.new_text.clone(),
11941 ..proto::Completion::default()
11942 };
11943 match &completion.source {
11944 CompletionSource::Lsp {
11945 insert_range,
11946 server_id,
11947 lsp_completion,
11948 lsp_defaults,
11949 resolved,
11950 } => {
11951 let (old_insert_start, old_insert_end) = insert_range
11952 .as_ref()
11953 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11954 .unzip();
11955
11956 serialized_completion.old_insert_start = old_insert_start;
11957 serialized_completion.old_insert_end = old_insert_end;
11958 serialized_completion.source = proto::completion::Source::Lsp as i32;
11959 serialized_completion.server_id = server_id.0 as u64;
11960 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11961 serialized_completion.lsp_defaults = lsp_defaults
11962 .as_deref()
11963 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11964 serialized_completion.resolved = *resolved;
11965 }
11966 CompletionSource::BufferWord {
11967 word_range,
11968 resolved,
11969 } => {
11970 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11971 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11972 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11973 serialized_completion.resolved = *resolved;
11974 }
11975 CompletionSource::Custom => {
11976 serialized_completion.source = proto::completion::Source::Custom as i32;
11977 serialized_completion.resolved = true;
11978 }
11979 CompletionSource::Dap { sort_text } => {
11980 serialized_completion.source = proto::completion::Source::Dap as i32;
11981 serialized_completion.sort_text = Some(sort_text.clone());
11982 }
11983 }
11984
11985 serialized_completion
11986 }
11987
11988 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11989 let old_replace_start = completion
11990 .old_replace_start
11991 .and_then(deserialize_anchor)
11992 .context("invalid old start")?;
11993 let old_replace_end = completion
11994 .old_replace_end
11995 .and_then(deserialize_anchor)
11996 .context("invalid old end")?;
11997 let insert_range = {
11998 match completion.old_insert_start.zip(completion.old_insert_end) {
11999 Some((start, end)) => {
12000 let start = deserialize_anchor(start).context("invalid insert old start")?;
12001 let end = deserialize_anchor(end).context("invalid insert old end")?;
12002 Some(start..end)
12003 }
12004 None => None,
12005 }
12006 };
12007 Ok(CoreCompletion {
12008 replace_range: old_replace_start..old_replace_end,
12009 new_text: completion.new_text,
12010 source: match proto::completion::Source::from_i32(completion.source) {
12011 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12012 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12013 insert_range,
12014 server_id: LanguageServerId::from_proto(completion.server_id),
12015 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12016 lsp_defaults: completion
12017 .lsp_defaults
12018 .as_deref()
12019 .map(serde_json::from_slice)
12020 .transpose()?,
12021 resolved: completion.resolved,
12022 },
12023 Some(proto::completion::Source::BufferWord) => {
12024 let word_range = completion
12025 .buffer_word_start
12026 .and_then(deserialize_anchor)
12027 .context("invalid buffer word start")?
12028 ..completion
12029 .buffer_word_end
12030 .and_then(deserialize_anchor)
12031 .context("invalid buffer word end")?;
12032 CompletionSource::BufferWord {
12033 word_range,
12034 resolved: completion.resolved,
12035 }
12036 }
12037 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12038 sort_text: completion
12039 .sort_text
12040 .context("expected sort text to exist")?,
12041 },
12042 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12043 },
12044 })
12045 }
12046
12047 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12048 let (kind, lsp_action) = match &action.lsp_action {
12049 LspAction::Action(code_action) => (
12050 proto::code_action::Kind::Action as i32,
12051 serde_json::to_vec(code_action).unwrap(),
12052 ),
12053 LspAction::Command(command) => (
12054 proto::code_action::Kind::Command as i32,
12055 serde_json::to_vec(command).unwrap(),
12056 ),
12057 LspAction::CodeLens(code_lens) => (
12058 proto::code_action::Kind::CodeLens as i32,
12059 serde_json::to_vec(code_lens).unwrap(),
12060 ),
12061 };
12062
12063 proto::CodeAction {
12064 server_id: action.server_id.0 as u64,
12065 start: Some(serialize_anchor(&action.range.start)),
12066 end: Some(serialize_anchor(&action.range.end)),
12067 lsp_action,
12068 kind,
12069 resolved: action.resolved,
12070 }
12071 }
12072
12073 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12074 let start = action
12075 .start
12076 .and_then(deserialize_anchor)
12077 .context("invalid start")?;
12078 let end = action
12079 .end
12080 .and_then(deserialize_anchor)
12081 .context("invalid end")?;
12082 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12083 Some(proto::code_action::Kind::Action) => {
12084 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12085 }
12086 Some(proto::code_action::Kind::Command) => {
12087 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12088 }
12089 Some(proto::code_action::Kind::CodeLens) => {
12090 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12091 }
12092 None => anyhow::bail!("Unknown action kind {}", action.kind),
12093 };
12094 Ok(CodeAction {
12095 server_id: LanguageServerId(action.server_id as usize),
12096 range: start..end,
12097 resolved: action.resolved,
12098 lsp_action,
12099 })
12100 }
12101
12102 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12103 match &formatting_result {
12104 Ok(_) => self.last_formatting_failure = None,
12105 Err(error) => {
12106 let error_string = format!("{error:#}");
12107 log::error!("Formatting failed: {error_string}");
12108 self.last_formatting_failure
12109 .replace(error_string.lines().join(" "));
12110 }
12111 }
12112 }
12113
12114 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12115 self.lsp_server_capabilities.remove(&for_server);
12116 for lsp_data in self.lsp_data.values_mut() {
12117 lsp_data.remove_server_data(for_server);
12118 }
12119 if let Some(local) = self.as_local_mut() {
12120 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12121 local
12122 .workspace_pull_diagnostics_result_ids
12123 .remove(&for_server);
12124 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12125 buffer_servers.remove(&for_server);
12126 }
12127 }
12128 }
12129
12130 pub fn result_id_for_buffer_pull(
12131 &self,
12132 server_id: LanguageServerId,
12133 buffer_id: BufferId,
12134 registration_id: &Option<SharedString>,
12135 cx: &App,
12136 ) -> Option<SharedString> {
12137 let abs_path = self
12138 .buffer_store
12139 .read(cx)
12140 .get(buffer_id)
12141 .and_then(|b| File::from_dyn(b.read(cx).file()))
12142 .map(|f| f.abs_path(cx))?;
12143 self.as_local()?
12144 .buffer_pull_diagnostics_result_ids
12145 .get(&server_id)?
12146 .get(registration_id)?
12147 .get(&abs_path)?
12148 .clone()
12149 }
12150
12151 /// Gets all result_ids for a workspace diagnostics pull request.
12152 /// 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.
12153 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12154 pub fn result_ids_for_workspace_refresh(
12155 &self,
12156 server_id: LanguageServerId,
12157 registration_id: &Option<SharedString>,
12158 ) -> HashMap<PathBuf, SharedString> {
12159 let Some(local) = self.as_local() else {
12160 return HashMap::default();
12161 };
12162 local
12163 .workspace_pull_diagnostics_result_ids
12164 .get(&server_id)
12165 .into_iter()
12166 .filter_map(|diagnostics| diagnostics.get(registration_id))
12167 .flatten()
12168 .filter_map(|(abs_path, result_id)| {
12169 let result_id = local
12170 .buffer_pull_diagnostics_result_ids
12171 .get(&server_id)
12172 .and_then(|buffer_ids_result_ids| {
12173 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12174 })
12175 .cloned()
12176 .flatten()
12177 .or_else(|| result_id.clone())?;
12178 Some((abs_path.clone(), result_id))
12179 })
12180 .collect()
12181 }
12182
12183 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12184 if let Some(LanguageServerState::Running {
12185 workspace_diagnostics_refresh_tasks,
12186 ..
12187 }) = self
12188 .as_local_mut()
12189 .and_then(|local| local.language_servers.get_mut(&server_id))
12190 {
12191 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12192 diagnostics.refresh_tx.try_send(()).ok();
12193 }
12194 }
12195 }
12196
12197 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12198 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12199 /// which requires refreshing both workspace and document diagnostics.
12200 pub fn pull_document_diagnostics_for_server(
12201 &mut self,
12202 server_id: LanguageServerId,
12203 cx: &mut Context<Self>,
12204 ) -> Task<()> {
12205 let buffers_to_pull = self
12206 .as_local()
12207 .into_iter()
12208 .flat_map(|local| {
12209 self.buffer_store.read(cx).buffers().filter(|buffer| {
12210 let buffer_id = buffer.read(cx).remote_id();
12211 local
12212 .buffers_opened_in_servers
12213 .get(&buffer_id)
12214 .is_some_and(|servers| servers.contains(&server_id))
12215 })
12216 })
12217 .collect::<Vec<_>>();
12218
12219 let pulls = join_all(buffers_to_pull.into_iter().map(|buffer| {
12220 let buffer_path = buffer.read(cx).file().map(|f| f.full_path(cx));
12221 let pull_task = self.pull_diagnostics_for_buffer(buffer, cx);
12222 async move { (buffer_path, pull_task.await) }
12223 }));
12224 cx.background_spawn(async move {
12225 for (pull_task_path, pull_task_result) in pulls.await {
12226 if let Err(e) = pull_task_result {
12227 match pull_task_path {
12228 Some(path) => {
12229 log::error!("Failed to pull diagnostics for buffer {path:?}: {e:#}");
12230 }
12231 None => log::error!("Failed to pull diagnostics: {e:#}"),
12232 }
12233 }
12234 }
12235 })
12236 }
12237
12238 fn apply_workspace_diagnostic_report(
12239 &mut self,
12240 server_id: LanguageServerId,
12241 report: lsp::WorkspaceDiagnosticReportResult,
12242 registration_id: Option<SharedString>,
12243 cx: &mut Context<Self>,
12244 ) {
12245 let mut workspace_diagnostics =
12246 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12247 report,
12248 server_id,
12249 registration_id,
12250 );
12251 workspace_diagnostics.retain(|d| match &d.diagnostics {
12252 LspPullDiagnostics::Response {
12253 server_id,
12254 registration_id,
12255 ..
12256 } => self.diagnostic_registration_exists(*server_id, registration_id),
12257 LspPullDiagnostics::Default => false,
12258 });
12259 let mut unchanged_buffers = HashMap::default();
12260 let workspace_diagnostics_updates = workspace_diagnostics
12261 .into_iter()
12262 .filter_map(
12263 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12264 LspPullDiagnostics::Response {
12265 server_id,
12266 uri,
12267 diagnostics,
12268 registration_id,
12269 } => Some((
12270 server_id,
12271 uri,
12272 diagnostics,
12273 workspace_diagnostics.version,
12274 registration_id,
12275 )),
12276 LspPullDiagnostics::Default => None,
12277 },
12278 )
12279 .fold(
12280 HashMap::default(),
12281 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12282 let (result_id, diagnostics) = match diagnostics {
12283 PulledDiagnostics::Unchanged { result_id } => {
12284 unchanged_buffers
12285 .entry(new_registration_id.clone())
12286 .or_insert_with(HashSet::default)
12287 .insert(uri.clone());
12288 (Some(result_id), Vec::new())
12289 }
12290 PulledDiagnostics::Changed {
12291 result_id,
12292 diagnostics,
12293 } => (result_id, diagnostics),
12294 };
12295 let disk_based_sources = Cow::Owned(
12296 self.language_server_adapter_for_id(server_id)
12297 .as_ref()
12298 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12299 .unwrap_or(&[])
12300 .to_vec(),
12301 );
12302
12303 let Some(abs_path) = uri.to_file_path().ok() else {
12304 return acc;
12305 };
12306 let Some((worktree, relative_path)) =
12307 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12308 else {
12309 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12310 return acc;
12311 };
12312 let worktree_id = worktree.read(cx).id();
12313 let project_path = ProjectPath {
12314 worktree_id,
12315 path: relative_path,
12316 };
12317 if let Some(local_lsp_store) = self.as_local_mut() {
12318 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12319 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12320 }
12321 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12322 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12323 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12324 acc.entry(server_id)
12325 .or_insert_with(HashMap::default)
12326 .entry(new_registration_id.clone())
12327 .or_insert_with(Vec::new)
12328 .push(DocumentDiagnosticsUpdate {
12329 server_id,
12330 diagnostics: lsp::PublishDiagnosticsParams {
12331 uri,
12332 diagnostics,
12333 version,
12334 },
12335 result_id,
12336 disk_based_sources,
12337 registration_id: new_registration_id,
12338 });
12339 }
12340 acc
12341 },
12342 );
12343
12344 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12345 for (registration_id, diagnostic_updates) in diagnostic_updates {
12346 self.merge_lsp_diagnostics(
12347 DiagnosticSourceKind::Pulled,
12348 diagnostic_updates,
12349 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12350 DiagnosticSourceKind::Pulled => {
12351 old_diagnostic.registration_id != registration_id
12352 || unchanged_buffers
12353 .get(&old_diagnostic.registration_id)
12354 .is_some_and(|unchanged_buffers| {
12355 unchanged_buffers.contains(&document_uri)
12356 })
12357 }
12358 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12359 },
12360 cx,
12361 )
12362 .log_err();
12363 }
12364 }
12365 }
12366
12367 fn register_server_capabilities(
12368 &mut self,
12369 server_id: LanguageServerId,
12370 params: lsp::RegistrationParams,
12371 cx: &mut Context<Self>,
12372 ) -> anyhow::Result<()> {
12373 let server = self
12374 .language_server_for_id(server_id)
12375 .with_context(|| format!("no server {server_id} found"))?;
12376 for reg in params.registrations {
12377 match reg.method.as_str() {
12378 "workspace/didChangeWatchedFiles" => {
12379 if let Some(options) = reg.register_options {
12380 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12381 let caps = serde_json::from_value(options)?;
12382 local_lsp_store
12383 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12384 true
12385 } else {
12386 false
12387 };
12388 if notify {
12389 notify_server_capabilities_updated(&server, cx);
12390 }
12391 }
12392 }
12393 "workspace/didChangeConfiguration" => {
12394 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12395 }
12396 "workspace/didChangeWorkspaceFolders" => {
12397 // In this case register options is an empty object, we can ignore it
12398 let caps = lsp::WorkspaceFoldersServerCapabilities {
12399 supported: Some(true),
12400 change_notifications: Some(OneOf::Right(reg.id)),
12401 };
12402 server.update_capabilities(|capabilities| {
12403 capabilities
12404 .workspace
12405 .get_or_insert_default()
12406 .workspace_folders = Some(caps);
12407 });
12408 notify_server_capabilities_updated(&server, cx);
12409 }
12410 "workspace/symbol" => {
12411 let options = parse_register_capabilities(reg)?;
12412 server.update_capabilities(|capabilities| {
12413 capabilities.workspace_symbol_provider = Some(options);
12414 });
12415 notify_server_capabilities_updated(&server, cx);
12416 }
12417 "workspace/fileOperations" => {
12418 if let Some(options) = reg.register_options {
12419 let caps = serde_json::from_value(options)?;
12420 server.update_capabilities(|capabilities| {
12421 capabilities
12422 .workspace
12423 .get_or_insert_default()
12424 .file_operations = Some(caps);
12425 });
12426 notify_server_capabilities_updated(&server, cx);
12427 }
12428 }
12429 "workspace/executeCommand" => {
12430 if let Some(options) = reg.register_options {
12431 let options = serde_json::from_value(options)?;
12432 server.update_capabilities(|capabilities| {
12433 capabilities.execute_command_provider = Some(options);
12434 });
12435 notify_server_capabilities_updated(&server, cx);
12436 }
12437 }
12438 "textDocument/rangeFormatting" => {
12439 let options = parse_register_capabilities(reg)?;
12440 server.update_capabilities(|capabilities| {
12441 capabilities.document_range_formatting_provider = Some(options);
12442 });
12443 notify_server_capabilities_updated(&server, cx);
12444 }
12445 "textDocument/onTypeFormatting" => {
12446 if let Some(options) = reg
12447 .register_options
12448 .map(serde_json::from_value)
12449 .transpose()?
12450 {
12451 server.update_capabilities(|capabilities| {
12452 capabilities.document_on_type_formatting_provider = Some(options);
12453 });
12454 notify_server_capabilities_updated(&server, cx);
12455 }
12456 }
12457 "textDocument/formatting" => {
12458 let options = parse_register_capabilities(reg)?;
12459 server.update_capabilities(|capabilities| {
12460 capabilities.document_formatting_provider = Some(options);
12461 });
12462 notify_server_capabilities_updated(&server, cx);
12463 }
12464 "textDocument/rename" => {
12465 let options = parse_register_capabilities(reg)?;
12466 server.update_capabilities(|capabilities| {
12467 capabilities.rename_provider = Some(options);
12468 });
12469 notify_server_capabilities_updated(&server, cx);
12470 }
12471 "textDocument/inlayHint" => {
12472 let options = parse_register_capabilities(reg)?;
12473 server.update_capabilities(|capabilities| {
12474 capabilities.inlay_hint_provider = Some(options);
12475 });
12476 notify_server_capabilities_updated(&server, cx);
12477 }
12478 "textDocument/documentSymbol" => {
12479 let options = parse_register_capabilities(reg)?;
12480 server.update_capabilities(|capabilities| {
12481 capabilities.document_symbol_provider = Some(options);
12482 });
12483 notify_server_capabilities_updated(&server, cx);
12484 }
12485 "textDocument/codeAction" => {
12486 let options = parse_register_capabilities(reg)?;
12487 let provider = match options {
12488 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12489 OneOf::Right(caps) => caps,
12490 };
12491 server.update_capabilities(|capabilities| {
12492 capabilities.code_action_provider = Some(provider);
12493 });
12494 notify_server_capabilities_updated(&server, cx);
12495 }
12496 "textDocument/definition" => {
12497 let options = parse_register_capabilities(reg)?;
12498 server.update_capabilities(|capabilities| {
12499 capabilities.definition_provider = Some(options);
12500 });
12501 notify_server_capabilities_updated(&server, cx);
12502 }
12503 "textDocument/completion" => {
12504 if let Some(caps) = reg
12505 .register_options
12506 .map(serde_json::from_value::<CompletionOptions>)
12507 .transpose()?
12508 {
12509 server.update_capabilities(|capabilities| {
12510 capabilities.completion_provider = Some(caps.clone());
12511 });
12512
12513 if let Some(local) = self.as_local() {
12514 let mut buffers_with_language_server = Vec::new();
12515 for handle in self.buffer_store.read(cx).buffers() {
12516 let buffer_id = handle.read(cx).remote_id();
12517 if local
12518 .buffers_opened_in_servers
12519 .get(&buffer_id)
12520 .filter(|s| s.contains(&server_id))
12521 .is_some()
12522 {
12523 buffers_with_language_server.push(handle);
12524 }
12525 }
12526 let triggers = caps
12527 .trigger_characters
12528 .unwrap_or_default()
12529 .into_iter()
12530 .collect::<BTreeSet<_>>();
12531 for handle in buffers_with_language_server {
12532 let triggers = triggers.clone();
12533 let _ = handle.update(cx, move |buffer, cx| {
12534 buffer.set_completion_triggers(server_id, triggers, cx);
12535 });
12536 }
12537 }
12538 notify_server_capabilities_updated(&server, cx);
12539 }
12540 }
12541 "textDocument/hover" => {
12542 let options = parse_register_capabilities(reg)?;
12543 let provider = match options {
12544 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12545 OneOf::Right(caps) => caps,
12546 };
12547 server.update_capabilities(|capabilities| {
12548 capabilities.hover_provider = Some(provider);
12549 });
12550 notify_server_capabilities_updated(&server, cx);
12551 }
12552 "textDocument/signatureHelp" => {
12553 if let Some(caps) = reg
12554 .register_options
12555 .map(serde_json::from_value)
12556 .transpose()?
12557 {
12558 server.update_capabilities(|capabilities| {
12559 capabilities.signature_help_provider = Some(caps);
12560 });
12561 notify_server_capabilities_updated(&server, cx);
12562 }
12563 }
12564 "textDocument/didChange" => {
12565 if let Some(sync_kind) = reg
12566 .register_options
12567 .and_then(|opts| opts.get("syncKind").cloned())
12568 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12569 .transpose()?
12570 {
12571 server.update_capabilities(|capabilities| {
12572 let mut sync_options =
12573 Self::take_text_document_sync_options(capabilities);
12574 sync_options.change = Some(sync_kind);
12575 capabilities.text_document_sync =
12576 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12577 });
12578 notify_server_capabilities_updated(&server, cx);
12579 }
12580 }
12581 "textDocument/didSave" => {
12582 if let Some(include_text) = reg
12583 .register_options
12584 .map(|opts| {
12585 let transpose = opts
12586 .get("includeText")
12587 .cloned()
12588 .map(serde_json::from_value::<Option<bool>>)
12589 .transpose();
12590 match transpose {
12591 Ok(value) => Ok(value.flatten()),
12592 Err(e) => Err(e),
12593 }
12594 })
12595 .transpose()?
12596 {
12597 server.update_capabilities(|capabilities| {
12598 let mut sync_options =
12599 Self::take_text_document_sync_options(capabilities);
12600 sync_options.save =
12601 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12602 include_text,
12603 }));
12604 capabilities.text_document_sync =
12605 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12606 });
12607 notify_server_capabilities_updated(&server, cx);
12608 }
12609 }
12610 "textDocument/codeLens" => {
12611 if let Some(caps) = reg
12612 .register_options
12613 .map(serde_json::from_value)
12614 .transpose()?
12615 {
12616 server.update_capabilities(|capabilities| {
12617 capabilities.code_lens_provider = Some(caps);
12618 });
12619 notify_server_capabilities_updated(&server, cx);
12620 }
12621 }
12622 "textDocument/diagnostic" => {
12623 if let Some(caps) = reg
12624 .register_options
12625 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12626 .transpose()?
12627 {
12628 let local = self
12629 .as_local_mut()
12630 .context("Expected LSP Store to be local")?;
12631 let state = local
12632 .language_servers
12633 .get_mut(&server_id)
12634 .context("Could not obtain Language Servers state")?;
12635 local
12636 .language_server_dynamic_registrations
12637 .entry(server_id)
12638 .or_default()
12639 .diagnostics
12640 .insert(Some(reg.id.clone()), caps.clone());
12641
12642 let supports_workspace_diagnostics =
12643 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12644 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12645 diagnostic_options.workspace_diagnostics
12646 }
12647 DiagnosticServerCapabilities::RegistrationOptions(
12648 diagnostic_registration_options,
12649 ) => {
12650 diagnostic_registration_options
12651 .diagnostic_options
12652 .workspace_diagnostics
12653 }
12654 };
12655
12656 if supports_workspace_diagnostics(&caps) {
12657 if let LanguageServerState::Running {
12658 workspace_diagnostics_refresh_tasks,
12659 ..
12660 } = state
12661 && let Some(task) = lsp_workspace_diagnostics_refresh(
12662 Some(reg.id.clone()),
12663 caps.clone(),
12664 server.clone(),
12665 cx,
12666 )
12667 {
12668 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12669 }
12670 }
12671
12672 server.update_capabilities(|capabilities| {
12673 capabilities.diagnostic_provider = Some(caps);
12674 });
12675
12676 notify_server_capabilities_updated(&server, cx);
12677
12678 self.pull_document_diagnostics_for_server(server_id, cx)
12679 .detach();
12680 }
12681 }
12682 "textDocument/documentColor" => {
12683 let options = parse_register_capabilities(reg)?;
12684 let provider = match options {
12685 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12686 OneOf::Right(caps) => caps,
12687 };
12688 server.update_capabilities(|capabilities| {
12689 capabilities.color_provider = Some(provider);
12690 });
12691 notify_server_capabilities_updated(&server, cx);
12692 }
12693 _ => log::warn!("unhandled capability registration: {reg:?}"),
12694 }
12695 }
12696
12697 Ok(())
12698 }
12699
12700 fn unregister_server_capabilities(
12701 &mut self,
12702 server_id: LanguageServerId,
12703 params: lsp::UnregistrationParams,
12704 cx: &mut Context<Self>,
12705 ) -> anyhow::Result<()> {
12706 let server = self
12707 .language_server_for_id(server_id)
12708 .with_context(|| format!("no server {server_id} found"))?;
12709 for unreg in params.unregisterations.iter() {
12710 match unreg.method.as_str() {
12711 "workspace/didChangeWatchedFiles" => {
12712 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12713 local_lsp_store
12714 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12715 true
12716 } else {
12717 false
12718 };
12719 if notify {
12720 notify_server_capabilities_updated(&server, cx);
12721 }
12722 }
12723 "workspace/didChangeConfiguration" => {
12724 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12725 }
12726 "workspace/didChangeWorkspaceFolders" => {
12727 server.update_capabilities(|capabilities| {
12728 capabilities
12729 .workspace
12730 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12731 workspace_folders: None,
12732 file_operations: None,
12733 })
12734 .workspace_folders = None;
12735 });
12736 notify_server_capabilities_updated(&server, cx);
12737 }
12738 "workspace/symbol" => {
12739 server.update_capabilities(|capabilities| {
12740 capabilities.workspace_symbol_provider = None
12741 });
12742 notify_server_capabilities_updated(&server, cx);
12743 }
12744 "workspace/fileOperations" => {
12745 server.update_capabilities(|capabilities| {
12746 capabilities
12747 .workspace
12748 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12749 workspace_folders: None,
12750 file_operations: None,
12751 })
12752 .file_operations = None;
12753 });
12754 notify_server_capabilities_updated(&server, cx);
12755 }
12756 "workspace/executeCommand" => {
12757 server.update_capabilities(|capabilities| {
12758 capabilities.execute_command_provider = None;
12759 });
12760 notify_server_capabilities_updated(&server, cx);
12761 }
12762 "textDocument/rangeFormatting" => {
12763 server.update_capabilities(|capabilities| {
12764 capabilities.document_range_formatting_provider = None
12765 });
12766 notify_server_capabilities_updated(&server, cx);
12767 }
12768 "textDocument/onTypeFormatting" => {
12769 server.update_capabilities(|capabilities| {
12770 capabilities.document_on_type_formatting_provider = None;
12771 });
12772 notify_server_capabilities_updated(&server, cx);
12773 }
12774 "textDocument/formatting" => {
12775 server.update_capabilities(|capabilities| {
12776 capabilities.document_formatting_provider = None;
12777 });
12778 notify_server_capabilities_updated(&server, cx);
12779 }
12780 "textDocument/rename" => {
12781 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12782 notify_server_capabilities_updated(&server, cx);
12783 }
12784 "textDocument/codeAction" => {
12785 server.update_capabilities(|capabilities| {
12786 capabilities.code_action_provider = None;
12787 });
12788 notify_server_capabilities_updated(&server, cx);
12789 }
12790 "textDocument/definition" => {
12791 server.update_capabilities(|capabilities| {
12792 capabilities.definition_provider = None;
12793 });
12794 notify_server_capabilities_updated(&server, cx);
12795 }
12796 "textDocument/completion" => {
12797 server.update_capabilities(|capabilities| {
12798 capabilities.completion_provider = None;
12799 });
12800 notify_server_capabilities_updated(&server, cx);
12801 }
12802 "textDocument/hover" => {
12803 server.update_capabilities(|capabilities| {
12804 capabilities.hover_provider = None;
12805 });
12806 notify_server_capabilities_updated(&server, cx);
12807 }
12808 "textDocument/signatureHelp" => {
12809 server.update_capabilities(|capabilities| {
12810 capabilities.signature_help_provider = None;
12811 });
12812 notify_server_capabilities_updated(&server, cx);
12813 }
12814 "textDocument/didChange" => {
12815 server.update_capabilities(|capabilities| {
12816 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12817 sync_options.change = None;
12818 capabilities.text_document_sync =
12819 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12820 });
12821 notify_server_capabilities_updated(&server, cx);
12822 }
12823 "textDocument/didSave" => {
12824 server.update_capabilities(|capabilities| {
12825 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12826 sync_options.save = None;
12827 capabilities.text_document_sync =
12828 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12829 });
12830 notify_server_capabilities_updated(&server, cx);
12831 }
12832 "textDocument/codeLens" => {
12833 server.update_capabilities(|capabilities| {
12834 capabilities.code_lens_provider = None;
12835 });
12836 notify_server_capabilities_updated(&server, cx);
12837 }
12838 "textDocument/diagnostic" => {
12839 let local = self
12840 .as_local_mut()
12841 .context("Expected LSP Store to be local")?;
12842
12843 let state = local
12844 .language_servers
12845 .get_mut(&server_id)
12846 .context("Could not obtain Language Servers state")?;
12847 let registrations = local
12848 .language_server_dynamic_registrations
12849 .get_mut(&server_id)
12850 .with_context(|| {
12851 format!("Expected dynamic registration to exist for server {server_id}")
12852 })?;
12853 registrations.diagnostics
12854 .remove(&Some(unreg.id.clone()))
12855 .with_context(|| format!(
12856 "Attempted to unregister non-existent diagnostic registration with ID {}",
12857 unreg.id)
12858 )?;
12859 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12860
12861 if let LanguageServerState::Running {
12862 workspace_diagnostics_refresh_tasks,
12863 ..
12864 } = state
12865 {
12866 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12867 }
12868
12869 self.clear_unregistered_diagnostics(
12870 server_id,
12871 SharedString::from(unreg.id.clone()),
12872 cx,
12873 )?;
12874
12875 if removed_last_diagnostic_provider {
12876 server.update_capabilities(|capabilities| {
12877 debug_assert!(capabilities.diagnostic_provider.is_some());
12878 capabilities.diagnostic_provider = None;
12879 });
12880 }
12881
12882 notify_server_capabilities_updated(&server, cx);
12883 }
12884 "textDocument/documentColor" => {
12885 server.update_capabilities(|capabilities| {
12886 capabilities.color_provider = None;
12887 });
12888 notify_server_capabilities_updated(&server, cx);
12889 }
12890 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12891 }
12892 }
12893
12894 Ok(())
12895 }
12896
12897 fn clear_unregistered_diagnostics(
12898 &mut self,
12899 server_id: LanguageServerId,
12900 cleared_registration_id: SharedString,
12901 cx: &mut Context<Self>,
12902 ) -> anyhow::Result<()> {
12903 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12904
12905 self.buffer_store.update(cx, |buffer_store, cx| {
12906 for buffer_handle in buffer_store.buffers() {
12907 let buffer = buffer_handle.read(cx);
12908 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12909 let Some(abs_path) = abs_path else {
12910 continue;
12911 };
12912 affected_abs_paths.insert(abs_path);
12913 }
12914 });
12915
12916 let local = self.as_local().context("Expected LSP Store to be local")?;
12917 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12918 let Some(worktree) = self
12919 .worktree_store
12920 .read(cx)
12921 .worktree_for_id(*worktree_id, cx)
12922 else {
12923 continue;
12924 };
12925
12926 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12927 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12928 let has_matching_registration =
12929 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12930 entry.diagnostic.registration_id.as_ref()
12931 == Some(&cleared_registration_id)
12932 });
12933 if has_matching_registration {
12934 let abs_path = worktree.read(cx).absolutize(rel_path);
12935 affected_abs_paths.insert(abs_path);
12936 }
12937 }
12938 }
12939 }
12940
12941 if affected_abs_paths.is_empty() {
12942 return Ok(());
12943 }
12944
12945 // Send a fake diagnostic update which clears the state for the registration ID
12946 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12947 affected_abs_paths
12948 .into_iter()
12949 .map(|abs_path| DocumentDiagnosticsUpdate {
12950 diagnostics: DocumentDiagnostics {
12951 diagnostics: Vec::new(),
12952 document_abs_path: abs_path,
12953 version: None,
12954 },
12955 result_id: None,
12956 registration_id: Some(cleared_registration_id.clone()),
12957 server_id,
12958 disk_based_sources: Cow::Borrowed(&[]),
12959 })
12960 .collect();
12961
12962 let merge_registration_id = cleared_registration_id.clone();
12963 self.merge_diagnostic_entries(
12964 clears,
12965 move |_, diagnostic, _| {
12966 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12967 diagnostic.registration_id != Some(merge_registration_id.clone())
12968 } else {
12969 true
12970 }
12971 },
12972 cx,
12973 )?;
12974
12975 Ok(())
12976 }
12977
12978 async fn deduplicate_range_based_lsp_requests<T>(
12979 lsp_store: &Entity<Self>,
12980 server_id: Option<LanguageServerId>,
12981 lsp_request_id: LspRequestId,
12982 proto_request: &T::ProtoRequest,
12983 range: Range<Anchor>,
12984 cx: &mut AsyncApp,
12985 ) -> Result<()>
12986 where
12987 T: LspCommand,
12988 T::ProtoRequest: proto::LspRequestMessage,
12989 {
12990 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12991 let version = deserialize_version(proto_request.buffer_version());
12992 let buffer = lsp_store.update(cx, |this, cx| {
12993 this.buffer_store.read(cx).get_existing(buffer_id)
12994 })?;
12995 buffer
12996 .update(cx, |buffer, _| buffer.wait_for_version(version))
12997 .await?;
12998 lsp_store.update(cx, |lsp_store, cx| {
12999 let buffer_snapshot = buffer.read(cx).snapshot();
13000 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13001 let chunks_queried_for = lsp_data
13002 .inlay_hints
13003 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13004 .collect::<Vec<_>>();
13005 match chunks_queried_for.as_slice() {
13006 &[chunk] => {
13007 let key = LspKey {
13008 request_type: TypeId::of::<T>(),
13009 server_queried: server_id,
13010 };
13011 let previous_request = lsp_data
13012 .chunk_lsp_requests
13013 .entry(key)
13014 .or_default()
13015 .insert(chunk, lsp_request_id);
13016 if let Some((previous_request, running_requests)) =
13017 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13018 {
13019 running_requests.remove(&previous_request);
13020 }
13021 }
13022 _ambiguous_chunks => {
13023 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13024 // there, a buffer version-based check will be performed and outdated requests discarded.
13025 }
13026 }
13027 anyhow::Ok(())
13028 })?;
13029
13030 Ok(())
13031 }
13032
13033 async fn query_lsp_locally<T>(
13034 lsp_store: Entity<Self>,
13035 for_server_id: Option<LanguageServerId>,
13036 sender_id: proto::PeerId,
13037 lsp_request_id: LspRequestId,
13038 proto_request: T::ProtoRequest,
13039 position: Option<Anchor>,
13040 cx: &mut AsyncApp,
13041 ) -> Result<()>
13042 where
13043 T: LspCommand + Clone,
13044 T::ProtoRequest: proto::LspRequestMessage,
13045 <T::ProtoRequest as proto::RequestMessage>::Response:
13046 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13047 {
13048 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13049 let version = deserialize_version(proto_request.buffer_version());
13050 let buffer = lsp_store.update(cx, |this, cx| {
13051 this.buffer_store.read(cx).get_existing(buffer_id)
13052 })?;
13053 buffer
13054 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13055 .await?;
13056 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13057 let request =
13058 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13059 let key = LspKey {
13060 request_type: TypeId::of::<T>(),
13061 server_queried: for_server_id,
13062 };
13063 lsp_store.update(cx, |lsp_store, cx| {
13064 let request_task = match for_server_id {
13065 Some(server_id) => {
13066 let server_task = lsp_store.request_lsp(
13067 buffer.clone(),
13068 LanguageServerToQuery::Other(server_id),
13069 request.clone(),
13070 cx,
13071 );
13072 cx.background_spawn(async move {
13073 let mut responses = Vec::new();
13074 match server_task.await {
13075 Ok(response) => responses.push((server_id, response)),
13076 // rust-analyzer likes to error with this when its still loading up
13077 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13078 Err(e) => log::error!(
13079 "Error handling response for request {request:?}: {e:#}"
13080 ),
13081 }
13082 responses
13083 })
13084 }
13085 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13086 };
13087 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13088 if T::ProtoRequest::stop_previous_requests() {
13089 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13090 lsp_requests.clear();
13091 }
13092 }
13093 lsp_data.lsp_requests.entry(key).or_default().insert(
13094 lsp_request_id,
13095 cx.spawn(async move |lsp_store, cx| {
13096 let response = request_task.await;
13097 lsp_store
13098 .update(cx, |lsp_store, cx| {
13099 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13100 {
13101 let response = response
13102 .into_iter()
13103 .map(|(server_id, response)| {
13104 (
13105 server_id.to_proto(),
13106 T::response_to_proto(
13107 response,
13108 lsp_store,
13109 sender_id,
13110 &buffer_version,
13111 cx,
13112 )
13113 .into(),
13114 )
13115 })
13116 .collect::<HashMap<_, _>>();
13117 match client.send_lsp_response::<T::ProtoRequest>(
13118 project_id,
13119 lsp_request_id,
13120 response,
13121 ) {
13122 Ok(()) => {}
13123 Err(e) => {
13124 log::error!("Failed to send LSP response: {e:#}",)
13125 }
13126 }
13127 }
13128 })
13129 .ok();
13130 }),
13131 );
13132 });
13133 Ok(())
13134 }
13135
13136 fn take_text_document_sync_options(
13137 capabilities: &mut lsp::ServerCapabilities,
13138 ) -> lsp::TextDocumentSyncOptions {
13139 match capabilities.text_document_sync.take() {
13140 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13141 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13142 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13143 sync_options.change = Some(sync_kind);
13144 sync_options
13145 }
13146 None => lsp::TextDocumentSyncOptions::default(),
13147 }
13148 }
13149
13150 #[cfg(any(test, feature = "test-support"))]
13151 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13152 Some(
13153 self.lsp_data
13154 .get_mut(&buffer_id)?
13155 .code_lens
13156 .take()?
13157 .update
13158 .take()?
13159 .1,
13160 )
13161 }
13162
13163 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13164 self.downstream_client.clone()
13165 }
13166
13167 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13168 self.worktree_store.clone()
13169 }
13170
13171 /// Gets what's stored in the LSP data for the given buffer.
13172 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13173 self.lsp_data.get_mut(&buffer_id)
13174 }
13175
13176 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13177 /// new [`BufferLspData`] will be created to replace the previous state.
13178 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13179 let (buffer_id, buffer_version) =
13180 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13181 let lsp_data = self
13182 .lsp_data
13183 .entry(buffer_id)
13184 .or_insert_with(|| BufferLspData::new(buffer, cx));
13185 if buffer_version.changed_since(&lsp_data.buffer_version) {
13186 *lsp_data = BufferLspData::new(buffer, cx);
13187 }
13188 lsp_data
13189 }
13190}
13191
13192// Registration with registerOptions as null, should fallback to true.
13193// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13194fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13195 reg: lsp::Registration,
13196) -> Result<OneOf<bool, T>> {
13197 Ok(match reg.register_options {
13198 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13199 None => OneOf::Left(true),
13200 })
13201}
13202
13203fn subscribe_to_binary_statuses(
13204 languages: &Arc<LanguageRegistry>,
13205 cx: &mut Context<'_, LspStore>,
13206) -> Task<()> {
13207 let mut server_statuses = languages.language_server_binary_statuses();
13208 cx.spawn(async move |lsp_store, cx| {
13209 while let Some((server_name, binary_status)) = server_statuses.next().await {
13210 if lsp_store
13211 .update(cx, |_, cx| {
13212 let mut message = None;
13213 let binary_status = match binary_status {
13214 BinaryStatus::None => proto::ServerBinaryStatus::None,
13215 BinaryStatus::CheckingForUpdate => {
13216 proto::ServerBinaryStatus::CheckingForUpdate
13217 }
13218 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13219 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13220 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13221 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13222 BinaryStatus::Failed { error } => {
13223 message = Some(error);
13224 proto::ServerBinaryStatus::Failed
13225 }
13226 };
13227 cx.emit(LspStoreEvent::LanguageServerUpdate {
13228 // Binary updates are about the binary that might not have any language server id at that point.
13229 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13230 language_server_id: LanguageServerId(0),
13231 name: Some(server_name),
13232 message: proto::update_language_server::Variant::StatusUpdate(
13233 proto::StatusUpdate {
13234 message,
13235 status: Some(proto::status_update::Status::Binary(
13236 binary_status as i32,
13237 )),
13238 },
13239 ),
13240 });
13241 })
13242 .is_err()
13243 {
13244 break;
13245 }
13246 }
13247 })
13248}
13249
13250fn lsp_workspace_diagnostics_refresh(
13251 registration_id: Option<String>,
13252 options: DiagnosticServerCapabilities,
13253 server: Arc<LanguageServer>,
13254 cx: &mut Context<'_, LspStore>,
13255) -> Option<WorkspaceRefreshTask> {
13256 let identifier = workspace_diagnostic_identifier(&options)?;
13257 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13258
13259 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13260 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13261 refresh_tx.try_send(()).ok();
13262
13263 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13264 let mut attempts = 0;
13265 let max_attempts = 50;
13266 let mut requests = 0;
13267
13268 loop {
13269 let Some(()) = refresh_rx.recv().await else {
13270 return;
13271 };
13272
13273 'request: loop {
13274 requests += 1;
13275 if attempts > max_attempts {
13276 log::error!(
13277 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13278 );
13279 return;
13280 }
13281 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13282 cx.background_executor()
13283 .timer(Duration::from_millis(backoff_millis))
13284 .await;
13285 attempts += 1;
13286
13287 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13288 lsp_store
13289 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13290 .into_iter()
13291 .filter_map(|(abs_path, result_id)| {
13292 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13293 Some(lsp::PreviousResultId {
13294 uri,
13295 value: result_id.to_string(),
13296 })
13297 })
13298 .collect()
13299 }) else {
13300 return;
13301 };
13302
13303 let token = if let Some(registration_id) = ®istration_id {
13304 format!(
13305 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13306 server.server_id(),
13307 )
13308 } else {
13309 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13310 };
13311
13312 progress_rx.try_recv().ok();
13313 let timer =
13314 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13315 let progress = pin!(progress_rx.recv().fuse());
13316 let response_result = server
13317 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13318 lsp::WorkspaceDiagnosticParams {
13319 previous_result_ids,
13320 identifier: identifier.clone(),
13321 work_done_progress_params: Default::default(),
13322 partial_result_params: lsp::PartialResultParams {
13323 partial_result_token: Some(lsp::ProgressToken::String(token)),
13324 },
13325 },
13326 select(timer, progress).then(|either| match either {
13327 Either::Left((message, ..)) => ready(message).left_future(),
13328 Either::Right(..) => pending::<String>().right_future(),
13329 }),
13330 )
13331 .await;
13332
13333 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13334 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13335 match response_result {
13336 ConnectionResult::Timeout => {
13337 log::error!("Timeout during workspace diagnostics pull");
13338 continue 'request;
13339 }
13340 ConnectionResult::ConnectionReset => {
13341 log::error!("Server closed a workspace diagnostics pull request");
13342 continue 'request;
13343 }
13344 ConnectionResult::Result(Err(e)) => {
13345 log::error!("Error during workspace diagnostics pull: {e:#}");
13346 break 'request;
13347 }
13348 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13349 attempts = 0;
13350 if lsp_store
13351 .update(cx, |lsp_store, cx| {
13352 lsp_store.apply_workspace_diagnostic_report(
13353 server.server_id(),
13354 pulled_diagnostics,
13355 registration_id_shared.clone(),
13356 cx,
13357 )
13358 })
13359 .is_err()
13360 {
13361 return;
13362 }
13363 break 'request;
13364 }
13365 }
13366 }
13367 }
13368 });
13369
13370 Some(WorkspaceRefreshTask {
13371 refresh_tx,
13372 progress_tx,
13373 task: workspace_query_language_server,
13374 })
13375}
13376
13377fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13378 match &options {
13379 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13380 diagnostic_options.identifier.clone()
13381 }
13382 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13383 let diagnostic_options = ®istration_options.diagnostic_options;
13384 diagnostic_options.identifier.clone()
13385 }
13386 }
13387}
13388
13389fn workspace_diagnostic_identifier(
13390 options: &DiagnosticServerCapabilities,
13391) -> Option<Option<String>> {
13392 match &options {
13393 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13394 if !diagnostic_options.workspace_diagnostics {
13395 return None;
13396 }
13397 Some(diagnostic_options.identifier.clone())
13398 }
13399 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13400 let diagnostic_options = ®istration_options.diagnostic_options;
13401 if !diagnostic_options.workspace_diagnostics {
13402 return None;
13403 }
13404 Some(diagnostic_options.identifier.clone())
13405 }
13406 }
13407}
13408
13409fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13410 let CompletionSource::BufferWord {
13411 word_range,
13412 resolved,
13413 } = &mut completion.source
13414 else {
13415 return;
13416 };
13417 if *resolved {
13418 return;
13419 }
13420
13421 if completion.new_text
13422 != snapshot
13423 .text_for_range(word_range.clone())
13424 .collect::<String>()
13425 {
13426 return;
13427 }
13428
13429 let mut offset = 0;
13430 for chunk in snapshot.chunks(word_range.clone(), true) {
13431 let end_offset = offset + chunk.text.len();
13432 if let Some(highlight_id) = chunk.syntax_highlight_id {
13433 completion
13434 .label
13435 .runs
13436 .push((offset..end_offset, highlight_id));
13437 }
13438 offset = end_offset;
13439 }
13440 *resolved = true;
13441}
13442
13443impl EventEmitter<LspStoreEvent> for LspStore {}
13444
13445fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13446 hover
13447 .contents
13448 .retain(|hover_block| !hover_block.text.trim().is_empty());
13449 if hover.contents.is_empty() {
13450 None
13451 } else {
13452 Some(hover)
13453 }
13454}
13455
13456async fn populate_labels_for_completions(
13457 new_completions: Vec<CoreCompletion>,
13458 language: Option<Arc<Language>>,
13459 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13460) -> Vec<Completion> {
13461 let lsp_completions = new_completions
13462 .iter()
13463 .filter_map(|new_completion| {
13464 new_completion
13465 .source
13466 .lsp_completion(true)
13467 .map(|lsp_completion| lsp_completion.into_owned())
13468 })
13469 .collect::<Vec<_>>();
13470
13471 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13472 lsp_adapter
13473 .labels_for_completions(&lsp_completions, language)
13474 .await
13475 .log_err()
13476 .unwrap_or_default()
13477 } else {
13478 Vec::new()
13479 }
13480 .into_iter()
13481 .fuse();
13482
13483 let mut completions = Vec::new();
13484 for completion in new_completions {
13485 match completion.source.lsp_completion(true) {
13486 Some(lsp_completion) => {
13487 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13488
13489 let mut label = labels.next().flatten().unwrap_or_else(|| {
13490 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13491 });
13492 ensure_uniform_list_compatible_label(&mut label);
13493 completions.push(Completion {
13494 label,
13495 documentation,
13496 replace_range: completion.replace_range,
13497 new_text: completion.new_text,
13498 insert_text_mode: lsp_completion.insert_text_mode,
13499 source: completion.source,
13500 icon_path: None,
13501 confirm: None,
13502 match_start: None,
13503 snippet_deduplication_key: None,
13504 });
13505 }
13506 None => {
13507 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13508 ensure_uniform_list_compatible_label(&mut label);
13509 completions.push(Completion {
13510 label,
13511 documentation: None,
13512 replace_range: completion.replace_range,
13513 new_text: completion.new_text,
13514 source: completion.source,
13515 insert_text_mode: None,
13516 icon_path: None,
13517 confirm: None,
13518 match_start: None,
13519 snippet_deduplication_key: None,
13520 });
13521 }
13522 }
13523 }
13524 completions
13525}
13526
13527#[derive(Debug)]
13528pub enum LanguageServerToQuery {
13529 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13530 FirstCapable,
13531 /// Query a specific language server.
13532 Other(LanguageServerId),
13533}
13534
13535#[derive(Default)]
13536struct RenamePathsWatchedForServer {
13537 did_rename: Vec<RenameActionPredicate>,
13538 will_rename: Vec<RenameActionPredicate>,
13539}
13540
13541impl RenamePathsWatchedForServer {
13542 fn with_did_rename_patterns(
13543 mut self,
13544 did_rename: Option<&FileOperationRegistrationOptions>,
13545 ) -> Self {
13546 if let Some(did_rename) = did_rename {
13547 self.did_rename = did_rename
13548 .filters
13549 .iter()
13550 .filter_map(|filter| filter.try_into().log_err())
13551 .collect();
13552 }
13553 self
13554 }
13555 fn with_will_rename_patterns(
13556 mut self,
13557 will_rename: Option<&FileOperationRegistrationOptions>,
13558 ) -> Self {
13559 if let Some(will_rename) = will_rename {
13560 self.will_rename = will_rename
13561 .filters
13562 .iter()
13563 .filter_map(|filter| filter.try_into().log_err())
13564 .collect();
13565 }
13566 self
13567 }
13568
13569 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13570 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13571 }
13572 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13573 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13574 }
13575}
13576
13577impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13578 type Error = globset::Error;
13579 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13580 Ok(Self {
13581 kind: ops.pattern.matches.clone(),
13582 glob: GlobBuilder::new(&ops.pattern.glob)
13583 .case_insensitive(
13584 ops.pattern
13585 .options
13586 .as_ref()
13587 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13588 )
13589 .build()?
13590 .compile_matcher(),
13591 })
13592 }
13593}
13594struct RenameActionPredicate {
13595 glob: GlobMatcher,
13596 kind: Option<FileOperationPatternKind>,
13597}
13598
13599impl RenameActionPredicate {
13600 // Returns true if language server should be notified
13601 fn eval(&self, path: &str, is_dir: bool) -> bool {
13602 self.kind.as_ref().is_none_or(|kind| {
13603 let expected_kind = if is_dir {
13604 FileOperationPatternKind::Folder
13605 } else {
13606 FileOperationPatternKind::File
13607 };
13608 kind == &expected_kind
13609 }) && self.glob.is_match(path)
13610 }
13611}
13612
13613#[derive(Default)]
13614struct LanguageServerWatchedPaths {
13615 worktree_paths: HashMap<WorktreeId, GlobSet>,
13616 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13617}
13618
13619#[derive(Default)]
13620struct LanguageServerWatchedPathsBuilder {
13621 worktree_paths: HashMap<WorktreeId, GlobSet>,
13622 abs_paths: HashMap<Arc<Path>, GlobSet>,
13623}
13624
13625impl LanguageServerWatchedPathsBuilder {
13626 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13627 self.worktree_paths.insert(worktree_id, glob_set);
13628 }
13629 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13630 self.abs_paths.insert(path, glob_set);
13631 }
13632 fn build(
13633 self,
13634 fs: Arc<dyn Fs>,
13635 language_server_id: LanguageServerId,
13636 cx: &mut Context<LspStore>,
13637 ) -> LanguageServerWatchedPaths {
13638 let lsp_store = cx.weak_entity();
13639
13640 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13641 let abs_paths = self
13642 .abs_paths
13643 .into_iter()
13644 .map(|(abs_path, globset)| {
13645 let task = cx.spawn({
13646 let abs_path = abs_path.clone();
13647 let fs = fs.clone();
13648
13649 let lsp_store = lsp_store.clone();
13650 async move |_, cx| {
13651 maybe!(async move {
13652 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13653 while let Some(update) = push_updates.0.next().await {
13654 let action = lsp_store
13655 .update(cx, |this, _| {
13656 let Some(local) = this.as_local() else {
13657 return ControlFlow::Break(());
13658 };
13659 let Some(watcher) = local
13660 .language_server_watched_paths
13661 .get(&language_server_id)
13662 else {
13663 return ControlFlow::Break(());
13664 };
13665 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13666 "Watched abs path is not registered with a watcher",
13667 );
13668 let matching_entries = update
13669 .into_iter()
13670 .filter(|event| globs.is_match(&event.path))
13671 .collect::<Vec<_>>();
13672 this.lsp_notify_abs_paths_changed(
13673 language_server_id,
13674 matching_entries,
13675 );
13676 ControlFlow::Continue(())
13677 })
13678 .ok()?;
13679
13680 if action.is_break() {
13681 break;
13682 }
13683 }
13684 Some(())
13685 })
13686 .await;
13687 }
13688 });
13689 (abs_path, (globset, task))
13690 })
13691 .collect();
13692 LanguageServerWatchedPaths {
13693 worktree_paths: self.worktree_paths,
13694 abs_paths,
13695 }
13696 }
13697}
13698
13699struct LspBufferSnapshot {
13700 version: i32,
13701 snapshot: TextBufferSnapshot,
13702}
13703
13704/// A prompt requested by LSP server.
13705#[derive(Clone, Debug)]
13706pub struct LanguageServerPromptRequest {
13707 pub level: PromptLevel,
13708 pub message: String,
13709 pub actions: Vec<MessageActionItem>,
13710 pub lsp_name: String,
13711 pub(crate) response_channel: Sender<MessageActionItem>,
13712}
13713
13714impl LanguageServerPromptRequest {
13715 pub async fn respond(self, index: usize) -> Option<()> {
13716 if let Some(response) = self.actions.into_iter().nth(index) {
13717 self.response_channel.send(response).await.ok()
13718 } else {
13719 None
13720 }
13721 }
13722}
13723impl PartialEq for LanguageServerPromptRequest {
13724 fn eq(&self, other: &Self) -> bool {
13725 self.message == other.message && self.actions == other.actions
13726 }
13727}
13728
13729#[derive(Clone, Debug, PartialEq)]
13730pub enum LanguageServerLogType {
13731 Log(MessageType),
13732 Trace { verbose_info: Option<String> },
13733 Rpc { received: bool },
13734}
13735
13736impl LanguageServerLogType {
13737 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13738 match self {
13739 Self::Log(log_type) => {
13740 use proto::log_message::LogLevel;
13741 let level = match *log_type {
13742 MessageType::ERROR => LogLevel::Error,
13743 MessageType::WARNING => LogLevel::Warning,
13744 MessageType::INFO => LogLevel::Info,
13745 MessageType::LOG => LogLevel::Log,
13746 other => {
13747 log::warn!("Unknown lsp log message type: {other:?}");
13748 LogLevel::Log
13749 }
13750 };
13751 proto::language_server_log::LogType::Log(proto::LogMessage {
13752 level: level as i32,
13753 })
13754 }
13755 Self::Trace { verbose_info } => {
13756 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13757 verbose_info: verbose_info.to_owned(),
13758 })
13759 }
13760 Self::Rpc { received } => {
13761 let kind = if *received {
13762 proto::rpc_message::Kind::Received
13763 } else {
13764 proto::rpc_message::Kind::Sent
13765 };
13766 let kind = kind as i32;
13767 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13768 }
13769 }
13770 }
13771
13772 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13773 use proto::log_message::LogLevel;
13774 use proto::rpc_message;
13775 match log_type {
13776 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13777 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13778 LogLevel::Error => MessageType::ERROR,
13779 LogLevel::Warning => MessageType::WARNING,
13780 LogLevel::Info => MessageType::INFO,
13781 LogLevel::Log => MessageType::LOG,
13782 },
13783 ),
13784 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13785 verbose_info: trace_message.verbose_info,
13786 },
13787 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13788 received: match rpc_message::Kind::from_i32(message.kind)
13789 .unwrap_or(rpc_message::Kind::Received)
13790 {
13791 rpc_message::Kind::Received => true,
13792 rpc_message::Kind::Sent => false,
13793 },
13794 },
13795 }
13796 }
13797}
13798
13799pub struct WorkspaceRefreshTask {
13800 refresh_tx: mpsc::Sender<()>,
13801 progress_tx: mpsc::Sender<()>,
13802 #[allow(dead_code)]
13803 task: Task<()>,
13804}
13805
13806pub enum LanguageServerState {
13807 Starting {
13808 startup: Task<Option<Arc<LanguageServer>>>,
13809 /// List of language servers that will be added to the workspace once it's initialization completes.
13810 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13811 },
13812
13813 Running {
13814 adapter: Arc<CachedLspAdapter>,
13815 server: Arc<LanguageServer>,
13816 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13817 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13818 },
13819}
13820
13821impl LanguageServerState {
13822 fn add_workspace_folder(&self, uri: Uri) {
13823 match self {
13824 LanguageServerState::Starting {
13825 pending_workspace_folders,
13826 ..
13827 } => {
13828 pending_workspace_folders.lock().insert(uri);
13829 }
13830 LanguageServerState::Running { server, .. } => {
13831 server.add_workspace_folder(uri);
13832 }
13833 }
13834 }
13835 fn _remove_workspace_folder(&self, uri: Uri) {
13836 match self {
13837 LanguageServerState::Starting {
13838 pending_workspace_folders,
13839 ..
13840 } => {
13841 pending_workspace_folders.lock().remove(&uri);
13842 }
13843 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13844 }
13845 }
13846}
13847
13848impl std::fmt::Debug for LanguageServerState {
13849 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13850 match self {
13851 LanguageServerState::Starting { .. } => {
13852 f.debug_struct("LanguageServerState::Starting").finish()
13853 }
13854 LanguageServerState::Running { .. } => {
13855 f.debug_struct("LanguageServerState::Running").finish()
13856 }
13857 }
13858 }
13859}
13860
13861#[derive(Clone, Debug, Serialize)]
13862pub struct LanguageServerProgress {
13863 pub is_disk_based_diagnostics_progress: bool,
13864 pub is_cancellable: bool,
13865 pub title: Option<String>,
13866 pub message: Option<String>,
13867 pub percentage: Option<usize>,
13868 #[serde(skip_serializing)]
13869 pub last_update_at: Instant,
13870}
13871
13872#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13873pub struct DiagnosticSummary {
13874 pub error_count: usize,
13875 pub warning_count: usize,
13876}
13877
13878impl DiagnosticSummary {
13879 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13880 let mut this = Self {
13881 error_count: 0,
13882 warning_count: 0,
13883 };
13884
13885 for entry in diagnostics {
13886 if entry.diagnostic.is_primary {
13887 match entry.diagnostic.severity {
13888 DiagnosticSeverity::ERROR => this.error_count += 1,
13889 DiagnosticSeverity::WARNING => this.warning_count += 1,
13890 _ => {}
13891 }
13892 }
13893 }
13894
13895 this
13896 }
13897
13898 pub fn is_empty(&self) -> bool {
13899 self.error_count == 0 && self.warning_count == 0
13900 }
13901
13902 pub fn to_proto(
13903 self,
13904 language_server_id: LanguageServerId,
13905 path: &RelPath,
13906 ) -> proto::DiagnosticSummary {
13907 proto::DiagnosticSummary {
13908 path: path.to_proto(),
13909 language_server_id: language_server_id.0 as u64,
13910 error_count: self.error_count as u32,
13911 warning_count: self.warning_count as u32,
13912 }
13913 }
13914}
13915
13916#[derive(Clone, Debug)]
13917pub enum CompletionDocumentation {
13918 /// There is no documentation for this completion.
13919 Undocumented,
13920 /// A single line of documentation.
13921 SingleLine(SharedString),
13922 /// Multiple lines of plain text documentation.
13923 MultiLinePlainText(SharedString),
13924 /// Markdown documentation.
13925 MultiLineMarkdown(SharedString),
13926 /// Both single line and multiple lines of plain text documentation.
13927 SingleLineAndMultiLinePlainText {
13928 single_line: SharedString,
13929 plain_text: Option<SharedString>,
13930 },
13931}
13932
13933impl CompletionDocumentation {
13934 #[cfg(any(test, feature = "test-support"))]
13935 pub fn text(&self) -> SharedString {
13936 match self {
13937 CompletionDocumentation::Undocumented => "".into(),
13938 CompletionDocumentation::SingleLine(s) => s.clone(),
13939 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13940 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13941 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13942 single_line.clone()
13943 }
13944 }
13945 }
13946}
13947
13948impl From<lsp::Documentation> for CompletionDocumentation {
13949 fn from(docs: lsp::Documentation) -> Self {
13950 match docs {
13951 lsp::Documentation::String(text) => {
13952 if text.lines().count() <= 1 {
13953 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13954 } else {
13955 CompletionDocumentation::MultiLinePlainText(text.into())
13956 }
13957 }
13958
13959 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13960 lsp::MarkupKind::PlainText => {
13961 if value.lines().count() <= 1 {
13962 CompletionDocumentation::SingleLine(value.into())
13963 } else {
13964 CompletionDocumentation::MultiLinePlainText(value.into())
13965 }
13966 }
13967
13968 lsp::MarkupKind::Markdown => {
13969 CompletionDocumentation::MultiLineMarkdown(value.into())
13970 }
13971 },
13972 }
13973 }
13974}
13975
13976pub enum ResolvedHint {
13977 Resolved(InlayHint),
13978 Resolving(Shared<Task<()>>),
13979}
13980
13981fn glob_literal_prefix(glob: &Path) -> PathBuf {
13982 glob.components()
13983 .take_while(|component| match component {
13984 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13985 _ => true,
13986 })
13987 .collect()
13988}
13989
13990pub struct SshLspAdapter {
13991 name: LanguageServerName,
13992 binary: LanguageServerBinary,
13993 initialization_options: Option<String>,
13994 code_action_kinds: Option<Vec<CodeActionKind>>,
13995}
13996
13997impl SshLspAdapter {
13998 pub fn new(
13999 name: LanguageServerName,
14000 binary: LanguageServerBinary,
14001 initialization_options: Option<String>,
14002 code_action_kinds: Option<String>,
14003 ) -> Self {
14004 Self {
14005 name,
14006 binary,
14007 initialization_options,
14008 code_action_kinds: code_action_kinds
14009 .as_ref()
14010 .and_then(|c| serde_json::from_str(c).ok()),
14011 }
14012 }
14013}
14014
14015impl LspInstaller for SshLspAdapter {
14016 type BinaryVersion = ();
14017 async fn check_if_user_installed(
14018 &self,
14019 _: &dyn LspAdapterDelegate,
14020 _: Option<Toolchain>,
14021 _: &AsyncApp,
14022 ) -> Option<LanguageServerBinary> {
14023 Some(self.binary.clone())
14024 }
14025
14026 async fn cached_server_binary(
14027 &self,
14028 _: PathBuf,
14029 _: &dyn LspAdapterDelegate,
14030 ) -> Option<LanguageServerBinary> {
14031 None
14032 }
14033
14034 async fn fetch_latest_server_version(
14035 &self,
14036 _: &dyn LspAdapterDelegate,
14037 _: bool,
14038 _: &mut AsyncApp,
14039 ) -> Result<()> {
14040 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14041 }
14042
14043 async fn fetch_server_binary(
14044 &self,
14045 _: (),
14046 _: PathBuf,
14047 _: &dyn LspAdapterDelegate,
14048 ) -> Result<LanguageServerBinary> {
14049 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14050 }
14051}
14052
14053#[async_trait(?Send)]
14054impl LspAdapter for SshLspAdapter {
14055 fn name(&self) -> LanguageServerName {
14056 self.name.clone()
14057 }
14058
14059 async fn initialization_options(
14060 self: Arc<Self>,
14061 _: &Arc<dyn LspAdapterDelegate>,
14062 ) -> Result<Option<serde_json::Value>> {
14063 let Some(options) = &self.initialization_options else {
14064 return Ok(None);
14065 };
14066 let result = serde_json::from_str(options)?;
14067 Ok(result)
14068 }
14069
14070 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14071 self.code_action_kinds.clone()
14072 }
14073}
14074
14075pub fn language_server_settings<'a>(
14076 delegate: &'a dyn LspAdapterDelegate,
14077 language: &LanguageServerName,
14078 cx: &'a App,
14079) -> Option<&'a LspSettings> {
14080 language_server_settings_for(
14081 SettingsLocation {
14082 worktree_id: delegate.worktree_id(),
14083 path: RelPath::empty(),
14084 },
14085 language,
14086 cx,
14087 )
14088}
14089
14090pub fn language_server_settings_for<'a>(
14091 location: SettingsLocation<'a>,
14092 language: &LanguageServerName,
14093 cx: &'a App,
14094) -> Option<&'a LspSettings> {
14095 ProjectSettings::get(Some(location), cx).lsp.get(language)
14096}
14097
14098pub struct LocalLspAdapterDelegate {
14099 lsp_store: WeakEntity<LspStore>,
14100 worktree: worktree::Snapshot,
14101 fs: Arc<dyn Fs>,
14102 http_client: Arc<dyn HttpClient>,
14103 language_registry: Arc<LanguageRegistry>,
14104 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14105}
14106
14107impl LocalLspAdapterDelegate {
14108 pub fn new(
14109 language_registry: Arc<LanguageRegistry>,
14110 environment: &Entity<ProjectEnvironment>,
14111 lsp_store: WeakEntity<LspStore>,
14112 worktree: &Entity<Worktree>,
14113 http_client: Arc<dyn HttpClient>,
14114 fs: Arc<dyn Fs>,
14115 cx: &mut App,
14116 ) -> Arc<Self> {
14117 let load_shell_env_task =
14118 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14119
14120 Arc::new(Self {
14121 lsp_store,
14122 worktree: worktree.read(cx).snapshot(),
14123 fs,
14124 http_client,
14125 language_registry,
14126 load_shell_env_task,
14127 })
14128 }
14129
14130 pub fn from_local_lsp(
14131 local: &LocalLspStore,
14132 worktree: &Entity<Worktree>,
14133 cx: &mut App,
14134 ) -> Arc<Self> {
14135 Self::new(
14136 local.languages.clone(),
14137 &local.environment,
14138 local.weak.clone(),
14139 worktree,
14140 local.http_client.clone(),
14141 local.fs.clone(),
14142 cx,
14143 )
14144 }
14145}
14146
14147#[async_trait]
14148impl LspAdapterDelegate for LocalLspAdapterDelegate {
14149 fn show_notification(&self, message: &str, cx: &mut App) {
14150 self.lsp_store
14151 .update(cx, |_, cx| {
14152 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14153 })
14154 .ok();
14155 }
14156
14157 fn http_client(&self) -> Arc<dyn HttpClient> {
14158 self.http_client.clone()
14159 }
14160
14161 fn worktree_id(&self) -> WorktreeId {
14162 self.worktree.id()
14163 }
14164
14165 fn worktree_root_path(&self) -> &Path {
14166 self.worktree.abs_path().as_ref()
14167 }
14168
14169 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14170 self.worktree.resolve_executable_path(path)
14171 }
14172
14173 async fn shell_env(&self) -> HashMap<String, String> {
14174 let task = self.load_shell_env_task.clone();
14175 task.await.unwrap_or_default()
14176 }
14177
14178 async fn npm_package_installed_version(
14179 &self,
14180 package_name: &str,
14181 ) -> Result<Option<(PathBuf, Version)>> {
14182 let local_package_directory = self.worktree_root_path();
14183 let node_modules_directory = local_package_directory.join("node_modules");
14184
14185 if let Some(version) =
14186 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14187 {
14188 return Ok(Some((node_modules_directory, version)));
14189 }
14190 let Some(npm) = self.which("npm".as_ref()).await else {
14191 log::warn!(
14192 "Failed to find npm executable for {:?}",
14193 local_package_directory
14194 );
14195 return Ok(None);
14196 };
14197
14198 let env = self.shell_env().await;
14199 let output = util::command::new_smol_command(&npm)
14200 .args(["root", "-g"])
14201 .envs(env)
14202 .current_dir(local_package_directory)
14203 .output()
14204 .await?;
14205 let global_node_modules =
14206 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14207
14208 if let Some(version) =
14209 read_package_installed_version(global_node_modules.clone(), package_name).await?
14210 {
14211 return Ok(Some((global_node_modules, version)));
14212 }
14213 return Ok(None);
14214 }
14215
14216 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14217 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14218 if self.fs.is_file(&worktree_abs_path).await {
14219 worktree_abs_path.pop();
14220 }
14221
14222 let env = self.shell_env().await;
14223
14224 let shell_path = env.get("PATH").cloned();
14225
14226 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14227 }
14228
14229 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14230 let mut working_dir = self.worktree_root_path().to_path_buf();
14231 if self.fs.is_file(&working_dir).await {
14232 working_dir.pop();
14233 }
14234 let output = util::command::new_smol_command(&command.path)
14235 .args(command.arguments)
14236 .envs(command.env.clone().unwrap_or_default())
14237 .current_dir(working_dir)
14238 .output()
14239 .await?;
14240
14241 anyhow::ensure!(
14242 output.status.success(),
14243 "{}, stdout: {:?}, stderr: {:?}",
14244 output.status,
14245 String::from_utf8_lossy(&output.stdout),
14246 String::from_utf8_lossy(&output.stderr)
14247 );
14248 Ok(())
14249 }
14250
14251 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14252 self.language_registry
14253 .update_lsp_binary_status(server_name, status);
14254 }
14255
14256 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14257 self.language_registry
14258 .all_lsp_adapters()
14259 .into_iter()
14260 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14261 .collect()
14262 }
14263
14264 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14265 let dir = self.language_registry.language_server_download_dir(name)?;
14266
14267 if !dir.exists() {
14268 smol::fs::create_dir_all(&dir)
14269 .await
14270 .context("failed to create container directory")
14271 .log_err()?;
14272 }
14273
14274 Some(dir)
14275 }
14276
14277 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14278 let entry = self
14279 .worktree
14280 .entry_for_path(path)
14281 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14282 let abs_path = self.worktree.absolutize(&entry.path);
14283 self.fs.load(&abs_path).await
14284 }
14285}
14286
14287async fn populate_labels_for_symbols(
14288 symbols: Vec<CoreSymbol>,
14289 language_registry: &Arc<LanguageRegistry>,
14290 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14291 output: &mut Vec<Symbol>,
14292) {
14293 #[allow(clippy::mutable_key_type)]
14294 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14295
14296 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14297 for symbol in symbols {
14298 let Some(file_name) = symbol.path.file_name() else {
14299 continue;
14300 };
14301 let language = language_registry
14302 .load_language_for_file_path(Path::new(file_name))
14303 .await
14304 .ok()
14305 .or_else(|| {
14306 unknown_paths.insert(file_name.into());
14307 None
14308 });
14309 symbols_by_language
14310 .entry(language)
14311 .or_default()
14312 .push(symbol);
14313 }
14314
14315 for unknown_path in unknown_paths {
14316 log::info!("no language found for symbol in file {unknown_path:?}");
14317 }
14318
14319 let mut label_params = Vec::new();
14320 for (language, mut symbols) in symbols_by_language {
14321 label_params.clear();
14322 label_params.extend(
14323 symbols
14324 .iter_mut()
14325 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14326 );
14327
14328 let mut labels = Vec::new();
14329 if let Some(language) = language {
14330 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14331 language_registry
14332 .lsp_adapters(&language.name())
14333 .first()
14334 .cloned()
14335 });
14336 if let Some(lsp_adapter) = lsp_adapter {
14337 labels = lsp_adapter
14338 .labels_for_symbols(&label_params, &language)
14339 .await
14340 .log_err()
14341 .unwrap_or_default();
14342 }
14343 }
14344
14345 for ((symbol, (name, _)), label) in symbols
14346 .into_iter()
14347 .zip(label_params.drain(..))
14348 .zip(labels.into_iter().chain(iter::repeat(None)))
14349 {
14350 output.push(Symbol {
14351 language_server_name: symbol.language_server_name,
14352 source_worktree_id: symbol.source_worktree_id,
14353 source_language_server_id: symbol.source_language_server_id,
14354 path: symbol.path,
14355 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14356 name,
14357 kind: symbol.kind,
14358 range: symbol.range,
14359 });
14360 }
14361 }
14362}
14363
14364fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14365 match server.capabilities().text_document_sync.as_ref()? {
14366 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14367 // Server wants didSave but didn't specify includeText.
14368 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14369 // Server doesn't want didSave at all.
14370 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14371 // Server provided SaveOptions.
14372 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14373 Some(save_options.include_text.unwrap_or(false))
14374 }
14375 },
14376 // We do not have any save info. Kind affects didChange only.
14377 lsp::TextDocumentSyncCapability::Kind(_) => None,
14378 }
14379}
14380
14381/// Completion items are displayed in a `UniformList`.
14382/// Usually, those items are single-line strings, but in LSP responses,
14383/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14384/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14385/// 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,
14386/// breaking the completions menu presentation.
14387///
14388/// 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.
14389fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14390 let mut new_text = String::with_capacity(label.text.len());
14391 let mut offset_map = vec![0; label.text.len() + 1];
14392 let mut last_char_was_space = false;
14393 let mut new_idx = 0;
14394 let chars = label.text.char_indices().fuse();
14395 let mut newlines_removed = false;
14396
14397 for (idx, c) in chars {
14398 offset_map[idx] = new_idx;
14399
14400 match c {
14401 '\n' if last_char_was_space => {
14402 newlines_removed = true;
14403 }
14404 '\t' | ' ' if last_char_was_space => {}
14405 '\n' if !last_char_was_space => {
14406 new_text.push(' ');
14407 new_idx += 1;
14408 last_char_was_space = true;
14409 newlines_removed = true;
14410 }
14411 ' ' | '\t' => {
14412 new_text.push(' ');
14413 new_idx += 1;
14414 last_char_was_space = true;
14415 }
14416 _ => {
14417 new_text.push(c);
14418 new_idx += c.len_utf8();
14419 last_char_was_space = false;
14420 }
14421 }
14422 }
14423 offset_map[label.text.len()] = new_idx;
14424
14425 // Only modify the label if newlines were removed.
14426 if !newlines_removed {
14427 return;
14428 }
14429
14430 let last_index = new_idx;
14431 let mut run_ranges_errors = Vec::new();
14432 label.runs.retain_mut(|(range, _)| {
14433 match offset_map.get(range.start) {
14434 Some(&start) => range.start = start,
14435 None => {
14436 run_ranges_errors.push(range.clone());
14437 return false;
14438 }
14439 }
14440
14441 match offset_map.get(range.end) {
14442 Some(&end) => range.end = end,
14443 None => {
14444 run_ranges_errors.push(range.clone());
14445 range.end = last_index;
14446 }
14447 }
14448 true
14449 });
14450 if !run_ranges_errors.is_empty() {
14451 log::error!(
14452 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14453 label.text
14454 );
14455 }
14456
14457 let mut wrong_filter_range = None;
14458 if label.filter_range == (0..label.text.len()) {
14459 label.filter_range = 0..new_text.len();
14460 } else {
14461 let mut original_filter_range = Some(label.filter_range.clone());
14462 match offset_map.get(label.filter_range.start) {
14463 Some(&start) => label.filter_range.start = start,
14464 None => {
14465 wrong_filter_range = original_filter_range.take();
14466 label.filter_range.start = last_index;
14467 }
14468 }
14469
14470 match offset_map.get(label.filter_range.end) {
14471 Some(&end) => label.filter_range.end = end,
14472 None => {
14473 wrong_filter_range = original_filter_range.take();
14474 label.filter_range.end = last_index;
14475 }
14476 }
14477 }
14478 if let Some(wrong_filter_range) = wrong_filter_range {
14479 log::error!(
14480 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14481 label.text
14482 );
14483 }
14484
14485 label.text = new_text;
14486}
14487
14488#[cfg(test)]
14489mod tests {
14490 use language::HighlightId;
14491
14492 use super::*;
14493
14494 #[test]
14495 fn test_glob_literal_prefix() {
14496 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14497 assert_eq!(
14498 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14499 Path::new("node_modules")
14500 );
14501 assert_eq!(
14502 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14503 Path::new("foo")
14504 );
14505 assert_eq!(
14506 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14507 Path::new("foo/bar/baz.js")
14508 );
14509
14510 #[cfg(target_os = "windows")]
14511 {
14512 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14513 assert_eq!(
14514 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14515 Path::new("node_modules")
14516 );
14517 assert_eq!(
14518 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14519 Path::new("foo")
14520 );
14521 assert_eq!(
14522 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14523 Path::new("foo/bar/baz.js")
14524 );
14525 }
14526 }
14527
14528 #[test]
14529 fn test_multi_len_chars_normalization() {
14530 let mut label = CodeLabel::new(
14531 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14532 0..6,
14533 vec![(0..6, HighlightId(1))],
14534 );
14535 ensure_uniform_list_compatible_label(&mut label);
14536 assert_eq!(
14537 label,
14538 CodeLabel::new(
14539 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14540 0..6,
14541 vec![(0..6, HighlightId(1))],
14542 )
14543 );
14544 }
14545
14546 #[test]
14547 fn test_trailing_newline_in_completion_documentation() {
14548 let doc = lsp::Documentation::String(
14549 "Inappropriate argument value (of correct type).\n".to_string(),
14550 );
14551 let completion_doc: CompletionDocumentation = doc.into();
14552 assert!(
14553 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
14554 );
14555
14556 let doc = lsp::Documentation::String(" some value \n".to_string());
14557 let completion_doc: CompletionDocumentation = doc.into();
14558 assert!(matches!(
14559 completion_doc,
14560 CompletionDocumentation::SingleLine(s) if s == "some value"
14561 ));
14562 }
14563}