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, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 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#[derive(Default, Debug)]
253struct DynamicRegistrations {
254 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
255 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
256}
257
258pub struct LocalLspStore {
259 weak: WeakEntity<LspStore>,
260 worktree_store: Entity<WorktreeStore>,
261 toolchain_store: Entity<LocalToolchainStore>,
262 http_client: Arc<dyn HttpClient>,
263 environment: Entity<ProjectEnvironment>,
264 fs: Arc<dyn Fs>,
265 languages: Arc<LanguageRegistry>,
266 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
267 yarn: Entity<YarnPathStore>,
268 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
269 buffers_being_formatted: HashSet<BufferId>,
270 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
271 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
272 watched_manifest_filenames: HashSet<ManifestName>,
273 language_server_paths_watched_for_rename:
274 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
275 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
276 supplementary_language_servers:
277 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
278 prettier_store: Entity<PrettierStore>,
279 next_diagnostic_group_id: usize,
280 diagnostics: HashMap<
281 WorktreeId,
282 HashMap<
283 Arc<RelPath>,
284 Vec<(
285 LanguageServerId,
286 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
287 )>,
288 >,
289 >,
290 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
291 _subscription: gpui::Subscription,
292 lsp_tree: LanguageServerTree,
293 registered_buffers: HashMap<BufferId, usize>,
294 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
295 buffer_pull_diagnostics_result_ids: HashMap<
296 LanguageServerId,
297 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
298 >,
299 workspace_pull_diagnostics_result_ids: HashMap<
300 LanguageServerId,
301 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
302 >,
303 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, Receiver<()>)>,
304}
305
306impl LocalLspStore {
307 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
308 pub fn running_language_server_for_id(
309 &self,
310 id: LanguageServerId,
311 ) -> Option<&Arc<LanguageServer>> {
312 let language_server_state = self.language_servers.get(&id)?;
313
314 match language_server_state {
315 LanguageServerState::Running { server, .. } => Some(server),
316 LanguageServerState::Starting { .. } => None,
317 }
318 }
319
320 fn get_or_insert_language_server(
321 &mut self,
322 worktree_handle: &Entity<Worktree>,
323 delegate: Arc<LocalLspAdapterDelegate>,
324 disposition: &Arc<LaunchDisposition>,
325 language_name: &LanguageName,
326 cx: &mut App,
327 ) -> LanguageServerId {
328 let key = LanguageServerSeed {
329 worktree_id: worktree_handle.read(cx).id(),
330 name: disposition.server_name.clone(),
331 settings: disposition.settings.clone(),
332 toolchain: disposition.toolchain.clone(),
333 };
334 if let Some(state) = self.language_server_ids.get_mut(&key) {
335 state.project_roots.insert(disposition.path.path.clone());
336 state.id
337 } else {
338 let adapter = self
339 .languages
340 .lsp_adapters(language_name)
341 .into_iter()
342 .find(|adapter| adapter.name() == disposition.server_name)
343 .expect("To find LSP adapter");
344 let new_language_server_id = self.start_language_server(
345 worktree_handle,
346 delegate,
347 adapter,
348 disposition.settings.clone(),
349 key.clone(),
350 cx,
351 );
352 if let Some(state) = self.language_server_ids.get_mut(&key) {
353 state.project_roots.insert(disposition.path.path.clone());
354 } else {
355 debug_assert!(
356 false,
357 "Expected `start_language_server` to ensure that `key` exists in a map"
358 );
359 }
360 new_language_server_id
361 }
362 }
363
364 fn start_language_server(
365 &mut self,
366 worktree_handle: &Entity<Worktree>,
367 delegate: Arc<LocalLspAdapterDelegate>,
368 adapter: Arc<CachedLspAdapter>,
369 settings: Arc<LspSettings>,
370 key: LanguageServerSeed,
371 cx: &mut App,
372 ) -> LanguageServerId {
373 let worktree = worktree_handle.read(cx);
374
375 let worktree_id = worktree.id();
376 let worktree_abs_path = worktree.abs_path();
377 let toolchain = key.toolchain.clone();
378 let override_options = settings.initialization_options.clone();
379
380 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
381
382 let server_id = self.languages.next_language_server_id();
383 log::trace!(
384 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
385 adapter.name.0
386 );
387
388 let untrusted_worktree_task =
389 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
390 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
391 trusted_worktrees.can_trust(worktree_id, cx)
392 });
393 if can_trust {
394 self.restricted_worktrees_tasks.remove(&worktree_id);
395 None
396 } else {
397 match self.restricted_worktrees_tasks.entry(worktree_id) {
398 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
399 hash_map::Entry::Vacant(v) => {
400 let (tx, rx) = smol::channel::bounded::<()>(1);
401 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, _| {
402 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
403 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
404 tx.send_blocking(()).ok();
405 }
406 }
407 });
408 v.insert((subscription, rx.clone()));
409 Some(rx)
410 }
411 }
412 }
413 });
414 let update_binary_status = untrusted_worktree_task.is_none();
415
416 let binary = self.get_language_server_binary(
417 worktree_abs_path.clone(),
418 adapter.clone(),
419 settings,
420 toolchain.clone(),
421 delegate.clone(),
422 true,
423 untrusted_worktree_task,
424 cx,
425 );
426 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
427
428 let pending_server = cx.spawn({
429 let adapter = adapter.clone();
430 let server_name = adapter.name.clone();
431 let stderr_capture = stderr_capture.clone();
432 #[cfg(any(test, feature = "test-support"))]
433 let lsp_store = self.weak.clone();
434 let pending_workspace_folders = pending_workspace_folders.clone();
435 async move |cx| {
436 let binary = binary.await?;
437 #[cfg(any(test, feature = "test-support"))]
438 if let Some(server) = lsp_store
439 .update(&mut cx.clone(), |this, cx| {
440 this.languages.create_fake_language_server(
441 server_id,
442 &server_name,
443 binary.clone(),
444 &mut cx.to_async(),
445 )
446 })
447 .ok()
448 .flatten()
449 {
450 return Ok(server);
451 }
452
453 let code_action_kinds = adapter.code_action_kinds();
454 lsp::LanguageServer::new(
455 stderr_capture,
456 server_id,
457 server_name,
458 binary,
459 &worktree_abs_path,
460 code_action_kinds,
461 Some(pending_workspace_folders),
462 cx,
463 )
464 }
465 });
466
467 let startup = {
468 let server_name = adapter.name.0.clone();
469 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
470 let key = key.clone();
471 let adapter = adapter.clone();
472 let lsp_store = self.weak.clone();
473 let pending_workspace_folders = pending_workspace_folders.clone();
474
475 let pull_diagnostics = ProjectSettings::get_global(cx)
476 .diagnostics
477 .lsp_pull_diagnostics
478 .enabled;
479 cx.spawn(async move |cx| {
480 let result = async {
481 let language_server = pending_server.await?;
482
483 let workspace_config = Self::workspace_configuration_for_adapter(
484 adapter.adapter.clone(),
485 &delegate,
486 toolchain,
487 None,
488 cx,
489 )
490 .await?;
491
492 let mut initialization_options = Self::initialization_options_for_adapter(
493 adapter.adapter.clone(),
494 &delegate,
495 )
496 .await?;
497
498 match (&mut initialization_options, override_options) {
499 (Some(initialization_options), Some(override_options)) => {
500 merge_json_value_into(override_options, initialization_options);
501 }
502 (None, override_options) => initialization_options = override_options,
503 _ => {}
504 }
505
506 let initialization_params = cx.update(|cx| {
507 let mut params =
508 language_server.default_initialize_params(pull_diagnostics, cx);
509 params.initialization_options = initialization_options;
510 adapter.adapter.prepare_initialize_params(params, cx)
511 })??;
512
513 Self::setup_lsp_messages(
514 lsp_store.clone(),
515 &language_server,
516 delegate.clone(),
517 adapter.clone(),
518 );
519
520 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
521 settings: workspace_config,
522 };
523 let language_server = cx
524 .update(|cx| {
525 language_server.initialize(
526 initialization_params,
527 Arc::new(did_change_configuration_params.clone()),
528 cx,
529 )
530 })?
531 .await
532 .inspect_err(|_| {
533 if let Some(lsp_store) = lsp_store.upgrade() {
534 lsp_store
535 .update(cx, |lsp_store, cx| {
536 lsp_store.cleanup_lsp_data(server_id);
537 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
538 })
539 .ok();
540 }
541 })?;
542
543 language_server.notify::<lsp::notification::DidChangeConfiguration>(
544 did_change_configuration_params,
545 )?;
546
547 anyhow::Ok(language_server)
548 }
549 .await;
550
551 match result {
552 Ok(server) => {
553 lsp_store
554 .update(cx, |lsp_store, cx| {
555 lsp_store.insert_newly_running_language_server(
556 adapter,
557 server.clone(),
558 server_id,
559 key,
560 pending_workspace_folders,
561 cx,
562 );
563 })
564 .ok();
565 stderr_capture.lock().take();
566 Some(server)
567 }
568
569 Err(err) => {
570 let log = stderr_capture.lock().take().unwrap_or_default();
571 delegate.update_status(
572 adapter.name(),
573 BinaryStatus::Failed {
574 error: if log.is_empty() {
575 format!("{err:#}")
576 } else {
577 format!("{err:#}\n-- stderr --\n{log}")
578 },
579 },
580 );
581 log::error!(
582 "Failed to start language server {server_name:?}: {}",
583 redact_command(&format!("{err:?}"))
584 );
585 if !log.is_empty() {
586 log::error!("server stderr: {}", redact_command(&log));
587 }
588 None
589 }
590 }
591 })
592 };
593 let state = LanguageServerState::Starting {
594 startup,
595 pending_workspace_folders,
596 };
597
598 if update_binary_status {
599 self.languages
600 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
601 }
602
603 self.language_servers.insert(server_id, state);
604 self.language_server_ids
605 .entry(key)
606 .or_insert(UnifiedLanguageServer {
607 id: server_id,
608 project_roots: Default::default(),
609 });
610 server_id
611 }
612
613 fn get_language_server_binary(
614 &self,
615 worktree_abs_path: Arc<Path>,
616 adapter: Arc<CachedLspAdapter>,
617 settings: Arc<LspSettings>,
618 toolchain: Option<Toolchain>,
619 delegate: Arc<dyn LspAdapterDelegate>,
620 allow_binary_download: bool,
621 untrusted_worktree_task: Option<Receiver<()>>,
622 cx: &mut App,
623 ) -> Task<Result<LanguageServerBinary>> {
624 if let Some(settings) = &settings.binary
625 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
626 {
627 let settings = settings.clone();
628 let languages = self.languages.clone();
629 return cx.background_spawn(async move {
630 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
631 log::info!(
632 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
633 adapter.name(),
634 );
635 untrusted_worktree_task.recv().await.ok();
636 log::info!(
637 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
638 adapter.name(),
639 );
640 languages
641 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
642 }
643 let mut env = delegate.shell_env().await;
644 env.extend(settings.env.unwrap_or_default());
645
646 Ok(LanguageServerBinary {
647 path: delegate.resolve_executable_path(path),
648 env: Some(env),
649 arguments: settings
650 .arguments
651 .unwrap_or_default()
652 .iter()
653 .map(Into::into)
654 .collect(),
655 })
656 });
657 }
658 let lsp_binary_options = LanguageServerBinaryOptions {
659 allow_path_lookup: !settings
660 .binary
661 .as_ref()
662 .and_then(|b| b.ignore_system_version)
663 .unwrap_or_default(),
664 allow_binary_download,
665 pre_release: settings
666 .fetch
667 .as_ref()
668 .and_then(|f| f.pre_release)
669 .unwrap_or(false),
670 };
671
672 cx.spawn(async move |cx| {
673 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
674 log::info!(
675 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
676 adapter.name(),
677 );
678 untrusted_worktree_task.recv().await.ok();
679 log::info!(
680 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
681 adapter.name(),
682 );
683 }
684
685 let (existing_binary, maybe_download_binary) = adapter
686 .clone()
687 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
688 .await
689 .await;
690
691 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
692
693 let mut binary = match (existing_binary, maybe_download_binary) {
694 (binary, None) => binary?,
695 (Err(_), Some(downloader)) => downloader.await?,
696 (Ok(existing_binary), Some(downloader)) => {
697 let mut download_timeout = cx
698 .background_executor()
699 .timer(SERVER_DOWNLOAD_TIMEOUT)
700 .fuse();
701 let mut downloader = downloader.fuse();
702 futures::select! {
703 _ = download_timeout => {
704 // Return existing binary and kick the existing work to the background.
705 cx.spawn(async move |_| downloader.await).detach();
706 Ok(existing_binary)
707 },
708 downloaded_or_existing_binary = downloader => {
709 // If download fails, this results in the existing binary.
710 downloaded_or_existing_binary
711 }
712 }?
713 }
714 };
715 let mut shell_env = delegate.shell_env().await;
716
717 shell_env.extend(binary.env.unwrap_or_default());
718
719 if let Some(settings) = settings.binary.as_ref() {
720 if let Some(arguments) = &settings.arguments {
721 binary.arguments = arguments.iter().map(Into::into).collect();
722 }
723 if let Some(env) = &settings.env {
724 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
725 }
726 }
727
728 binary.env = Some(shell_env);
729 Ok(binary)
730 })
731 }
732
733 fn setup_lsp_messages(
734 lsp_store: WeakEntity<LspStore>,
735 language_server: &LanguageServer,
736 delegate: Arc<dyn LspAdapterDelegate>,
737 adapter: Arc<CachedLspAdapter>,
738 ) {
739 let name = language_server.name();
740 let server_id = language_server.server_id();
741 language_server
742 .on_notification::<lsp::notification::PublishDiagnostics, _>({
743 let adapter = adapter.clone();
744 let this = lsp_store.clone();
745 move |mut params, cx| {
746 let adapter = adapter.clone();
747 if let Some(this) = this.upgrade() {
748 this.update(cx, |this, cx| {
749 {
750 let buffer = params
751 .uri
752 .to_file_path()
753 .map(|file_path| this.get_buffer(&file_path, cx))
754 .ok()
755 .flatten();
756 adapter.process_diagnostics(&mut params, server_id, buffer);
757 }
758
759 this.merge_lsp_diagnostics(
760 DiagnosticSourceKind::Pushed,
761 vec![DocumentDiagnosticsUpdate {
762 server_id,
763 diagnostics: params,
764 result_id: None,
765 disk_based_sources: Cow::Borrowed(
766 &adapter.disk_based_diagnostic_sources,
767 ),
768 registration_id: None,
769 }],
770 |_, diagnostic, cx| match diagnostic.source_kind {
771 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
772 adapter.retain_old_diagnostic(diagnostic, cx)
773 }
774 DiagnosticSourceKind::Pulled => true,
775 },
776 cx,
777 )
778 .log_err();
779 })
780 .ok();
781 }
782 }
783 })
784 .detach();
785 language_server
786 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
787 let adapter = adapter.adapter.clone();
788 let delegate = delegate.clone();
789 let this = lsp_store.clone();
790 move |params, cx| {
791 let adapter = adapter.clone();
792 let delegate = delegate.clone();
793 let this = this.clone();
794 let mut cx = cx.clone();
795 async move {
796 let toolchain_for_id = this
797 .update(&mut cx, |this, _| {
798 this.as_local()?.language_server_ids.iter().find_map(
799 |(seed, value)| {
800 (value.id == server_id).then(|| seed.toolchain.clone())
801 },
802 )
803 })?
804 .context("Expected the LSP store to be in a local mode")?;
805
806 let mut scope_uri_to_workspace_config = BTreeMap::new();
807 for item in ¶ms.items {
808 let scope_uri = item.scope_uri.clone();
809 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
810 scope_uri_to_workspace_config.entry(scope_uri.clone())
811 else {
812 // We've already queried workspace configuration of this URI.
813 continue;
814 };
815 let workspace_config = Self::workspace_configuration_for_adapter(
816 adapter.clone(),
817 &delegate,
818 toolchain_for_id.clone(),
819 scope_uri,
820 &mut cx,
821 )
822 .await?;
823 new_scope_uri.insert(workspace_config);
824 }
825
826 Ok(params
827 .items
828 .into_iter()
829 .filter_map(|item| {
830 let workspace_config =
831 scope_uri_to_workspace_config.get(&item.scope_uri)?;
832 if let Some(section) = &item.section {
833 Some(
834 workspace_config
835 .get(section)
836 .cloned()
837 .unwrap_or(serde_json::Value::Null),
838 )
839 } else {
840 Some(workspace_config.clone())
841 }
842 })
843 .collect())
844 }
845 }
846 })
847 .detach();
848
849 language_server
850 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
851 let this = lsp_store.clone();
852 move |_, cx| {
853 let this = this.clone();
854 let cx = cx.clone();
855 async move {
856 let Some(server) =
857 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
858 else {
859 return Ok(None);
860 };
861 let root = server.workspace_folders();
862 Ok(Some(
863 root.into_iter()
864 .map(|uri| WorkspaceFolder {
865 uri,
866 name: Default::default(),
867 })
868 .collect(),
869 ))
870 }
871 }
872 })
873 .detach();
874 // Even though we don't have handling for these requests, respond to them to
875 // avoid stalling any language server like `gopls` which waits for a response
876 // to these requests when initializing.
877 language_server
878 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
879 let this = lsp_store.clone();
880 move |params, cx| {
881 let this = this.clone();
882 let mut cx = cx.clone();
883 async move {
884 this.update(&mut cx, |this, _| {
885 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
886 {
887 status
888 .progress_tokens
889 .insert(ProgressToken::from_lsp(params.token));
890 }
891 })?;
892
893 Ok(())
894 }
895 }
896 })
897 .detach();
898
899 language_server
900 .on_request::<lsp::request::RegisterCapability, _, _>({
901 let lsp_store = lsp_store.clone();
902 move |params, cx| {
903 let lsp_store = lsp_store.clone();
904 let mut cx = cx.clone();
905 async move {
906 lsp_store
907 .update(&mut cx, |lsp_store, cx| {
908 if lsp_store.as_local().is_some() {
909 match lsp_store
910 .register_server_capabilities(server_id, params, cx)
911 {
912 Ok(()) => {}
913 Err(e) => {
914 log::error!(
915 "Failed to register server capabilities: {e:#}"
916 );
917 }
918 };
919 }
920 })
921 .ok();
922 Ok(())
923 }
924 }
925 })
926 .detach();
927
928 language_server
929 .on_request::<lsp::request::UnregisterCapability, _, _>({
930 let lsp_store = lsp_store.clone();
931 move |params, cx| {
932 let lsp_store = lsp_store.clone();
933 let mut cx = cx.clone();
934 async move {
935 lsp_store
936 .update(&mut cx, |lsp_store, cx| {
937 if lsp_store.as_local().is_some() {
938 match lsp_store
939 .unregister_server_capabilities(server_id, params, cx)
940 {
941 Ok(()) => {}
942 Err(e) => {
943 log::error!(
944 "Failed to unregister server capabilities: {e:#}"
945 );
946 }
947 }
948 }
949 })
950 .ok();
951 Ok(())
952 }
953 }
954 })
955 .detach();
956
957 language_server
958 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
959 let this = lsp_store.clone();
960 move |params, cx| {
961 let mut cx = cx.clone();
962 let this = this.clone();
963 async move {
964 LocalLspStore::on_lsp_workspace_edit(
965 this.clone(),
966 params,
967 server_id,
968 &mut cx,
969 )
970 .await
971 }
972 }
973 })
974 .detach();
975
976 language_server
977 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
978 let lsp_store = lsp_store.clone();
979 let request_id = Arc::new(AtomicUsize::new(0));
980 move |(), cx| {
981 let lsp_store = lsp_store.clone();
982 let request_id = request_id.clone();
983 let mut cx = cx.clone();
984 async move {
985 lsp_store
986 .update(&mut cx, |lsp_store, cx| {
987 let request_id =
988 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
989 cx.emit(LspStoreEvent::RefreshInlayHints {
990 server_id,
991 request_id,
992 });
993 lsp_store
994 .downstream_client
995 .as_ref()
996 .map(|(client, project_id)| {
997 client.send(proto::RefreshInlayHints {
998 project_id: *project_id,
999 server_id: server_id.to_proto(),
1000 request_id: request_id.map(|id| id as u64),
1001 })
1002 })
1003 })?
1004 .transpose()?;
1005 Ok(())
1006 }
1007 }
1008 })
1009 .detach();
1010
1011 language_server
1012 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1013 let this = lsp_store.clone();
1014 move |(), cx| {
1015 let this = this.clone();
1016 let mut cx = cx.clone();
1017 async move {
1018 this.update(&mut cx, |this, cx| {
1019 cx.emit(LspStoreEvent::RefreshCodeLens);
1020 this.downstream_client.as_ref().map(|(client, project_id)| {
1021 client.send(proto::RefreshCodeLens {
1022 project_id: *project_id,
1023 })
1024 })
1025 })?
1026 .transpose()?;
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1035 let this = lsp_store.clone();
1036 move |(), cx| {
1037 let this = this.clone();
1038 let mut cx = cx.clone();
1039 async move {
1040 this.update(&mut cx, |lsp_store, _| {
1041 lsp_store.pull_workspace_diagnostics(server_id);
1042 lsp_store
1043 .downstream_client
1044 .as_ref()
1045 .map(|(client, project_id)| {
1046 client.send(proto::PullWorkspaceDiagnostics {
1047 project_id: *project_id,
1048 server_id: server_id.to_proto(),
1049 })
1050 })
1051 })?
1052 .transpose()?;
1053 Ok(())
1054 }
1055 }
1056 })
1057 .detach();
1058
1059 language_server
1060 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1061 let this = lsp_store.clone();
1062 let name = name.to_string();
1063 let adapter = adapter.clone();
1064 move |params, cx| {
1065 let this = this.clone();
1066 let name = name.to_string();
1067 let adapter = adapter.clone();
1068 let mut cx = cx.clone();
1069 async move {
1070 let actions = params.actions.unwrap_or_default();
1071 let message = params.message.clone();
1072 let (tx, rx) = smol::channel::bounded(1);
1073 let request = LanguageServerPromptRequest {
1074 level: match params.typ {
1075 lsp::MessageType::ERROR => PromptLevel::Critical,
1076 lsp::MessageType::WARNING => PromptLevel::Warning,
1077 _ => PromptLevel::Info,
1078 },
1079 message: params.message,
1080 actions,
1081 response_channel: tx,
1082 lsp_name: name.clone(),
1083 };
1084
1085 let did_update = this
1086 .update(&mut cx, |_, cx| {
1087 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1088 })
1089 .is_ok();
1090 if did_update {
1091 let response = rx.recv().await.ok();
1092 if let Some(ref selected_action) = response {
1093 let context = language::PromptResponseContext {
1094 message,
1095 selected_action: selected_action.clone(),
1096 };
1097 adapter.process_prompt_response(&context, &mut cx)
1098 }
1099
1100 Ok(response)
1101 } else {
1102 Ok(None)
1103 }
1104 }
1105 }
1106 })
1107 .detach();
1108 language_server
1109 .on_notification::<lsp::notification::ShowMessage, _>({
1110 let this = lsp_store.clone();
1111 let name = name.to_string();
1112 move |params, cx| {
1113 let this = this.clone();
1114 let name = name.to_string();
1115 let mut cx = cx.clone();
1116
1117 let (tx, _) = smol::channel::bounded(1);
1118 let request = LanguageServerPromptRequest {
1119 level: match params.typ {
1120 lsp::MessageType::ERROR => PromptLevel::Critical,
1121 lsp::MessageType::WARNING => PromptLevel::Warning,
1122 _ => PromptLevel::Info,
1123 },
1124 message: params.message,
1125 actions: vec![],
1126 response_channel: tx,
1127 lsp_name: name,
1128 };
1129
1130 let _ = this.update(&mut cx, |_, cx| {
1131 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1132 });
1133 }
1134 })
1135 .detach();
1136
1137 let disk_based_diagnostics_progress_token =
1138 adapter.disk_based_diagnostics_progress_token.clone();
1139
1140 language_server
1141 .on_notification::<lsp::notification::Progress, _>({
1142 let this = lsp_store.clone();
1143 move |params, cx| {
1144 if let Some(this) = this.upgrade() {
1145 this.update(cx, |this, cx| {
1146 this.on_lsp_progress(
1147 params,
1148 server_id,
1149 disk_based_diagnostics_progress_token.clone(),
1150 cx,
1151 );
1152 })
1153 .ok();
1154 }
1155 }
1156 })
1157 .detach();
1158
1159 language_server
1160 .on_notification::<lsp::notification::LogMessage, _>({
1161 let this = lsp_store.clone();
1162 move |params, cx| {
1163 if let Some(this) = this.upgrade() {
1164 this.update(cx, |_, cx| {
1165 cx.emit(LspStoreEvent::LanguageServerLog(
1166 server_id,
1167 LanguageServerLogType::Log(params.typ),
1168 params.message,
1169 ));
1170 })
1171 .ok();
1172 }
1173 }
1174 })
1175 .detach();
1176
1177 language_server
1178 .on_notification::<lsp::notification::LogTrace, _>({
1179 let this = lsp_store.clone();
1180 move |params, cx| {
1181 let mut cx = cx.clone();
1182 if let Some(this) = this.upgrade() {
1183 this.update(&mut cx, |_, cx| {
1184 cx.emit(LspStoreEvent::LanguageServerLog(
1185 server_id,
1186 LanguageServerLogType::Trace {
1187 verbose_info: params.verbose,
1188 },
1189 params.message,
1190 ));
1191 })
1192 .ok();
1193 }
1194 }
1195 })
1196 .detach();
1197
1198 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1199 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1200 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1201 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1202 }
1203
1204 fn shutdown_language_servers_on_quit(
1205 &mut self,
1206 _: &mut Context<LspStore>,
1207 ) -> impl Future<Output = ()> + use<> {
1208 let shutdown_futures = self
1209 .language_servers
1210 .drain()
1211 .map(|(_, server_state)| Self::shutdown_server(server_state))
1212 .collect::<Vec<_>>();
1213
1214 async move {
1215 join_all(shutdown_futures).await;
1216 }
1217 }
1218
1219 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1220 match server_state {
1221 LanguageServerState::Running { server, .. } => {
1222 if let Some(shutdown) = server.shutdown() {
1223 shutdown.await;
1224 }
1225 }
1226 LanguageServerState::Starting { startup, .. } => {
1227 if let Some(server) = startup.await
1228 && let Some(shutdown) = server.shutdown()
1229 {
1230 shutdown.await;
1231 }
1232 }
1233 }
1234 Ok(())
1235 }
1236
1237 fn language_servers_for_worktree(
1238 &self,
1239 worktree_id: WorktreeId,
1240 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1241 self.language_server_ids
1242 .iter()
1243 .filter_map(move |(seed, state)| {
1244 if seed.worktree_id != worktree_id {
1245 return None;
1246 }
1247
1248 if let Some(LanguageServerState::Running { server, .. }) =
1249 self.language_servers.get(&state.id)
1250 {
1251 Some(server)
1252 } else {
1253 None
1254 }
1255 })
1256 }
1257
1258 fn language_server_ids_for_project_path(
1259 &self,
1260 project_path: ProjectPath,
1261 language: &Language,
1262 cx: &mut App,
1263 ) -> Vec<LanguageServerId> {
1264 let Some(worktree) = self
1265 .worktree_store
1266 .read(cx)
1267 .worktree_for_id(project_path.worktree_id, cx)
1268 else {
1269 return Vec::new();
1270 };
1271 let delegate: Arc<dyn ManifestDelegate> =
1272 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1273
1274 self.lsp_tree
1275 .get(
1276 project_path,
1277 language.name(),
1278 language.manifest(),
1279 &delegate,
1280 cx,
1281 )
1282 .collect::<Vec<_>>()
1283 }
1284
1285 fn language_server_ids_for_buffer(
1286 &self,
1287 buffer: &Buffer,
1288 cx: &mut App,
1289 ) -> Vec<LanguageServerId> {
1290 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1291 let worktree_id = file.worktree_id(cx);
1292
1293 let path: Arc<RelPath> = file
1294 .path()
1295 .parent()
1296 .map(Arc::from)
1297 .unwrap_or_else(|| file.path().clone());
1298 let worktree_path = ProjectPath { worktree_id, path };
1299 self.language_server_ids_for_project_path(worktree_path, language, cx)
1300 } else {
1301 Vec::new()
1302 }
1303 }
1304
1305 fn language_servers_for_buffer<'a>(
1306 &'a self,
1307 buffer: &'a Buffer,
1308 cx: &'a mut App,
1309 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1310 self.language_server_ids_for_buffer(buffer, cx)
1311 .into_iter()
1312 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1313 LanguageServerState::Running {
1314 adapter, server, ..
1315 } => Some((adapter, server)),
1316 _ => None,
1317 })
1318 }
1319
1320 async fn execute_code_action_kind_locally(
1321 lsp_store: WeakEntity<LspStore>,
1322 mut buffers: Vec<Entity<Buffer>>,
1323 kind: CodeActionKind,
1324 push_to_history: bool,
1325 cx: &mut AsyncApp,
1326 ) -> anyhow::Result<ProjectTransaction> {
1327 // Do not allow multiple concurrent code actions requests for the
1328 // same buffer.
1329 lsp_store.update(cx, |this, cx| {
1330 let this = this.as_local_mut().unwrap();
1331 buffers.retain(|buffer| {
1332 this.buffers_being_formatted
1333 .insert(buffer.read(cx).remote_id())
1334 });
1335 })?;
1336 let _cleanup = defer({
1337 let this = lsp_store.clone();
1338 let mut cx = cx.clone();
1339 let buffers = &buffers;
1340 move || {
1341 this.update(&mut cx, |this, cx| {
1342 let this = this.as_local_mut().unwrap();
1343 for buffer in buffers {
1344 this.buffers_being_formatted
1345 .remove(&buffer.read(cx).remote_id());
1346 }
1347 })
1348 .ok();
1349 }
1350 });
1351 let mut project_transaction = ProjectTransaction::default();
1352
1353 for buffer in &buffers {
1354 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1355 buffer.update(cx, |buffer, cx| {
1356 lsp_store
1357 .as_local()
1358 .unwrap()
1359 .language_servers_for_buffer(buffer, cx)
1360 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1361 .collect::<Vec<_>>()
1362 })
1363 })?;
1364 for (_, language_server) in adapters_and_servers.iter() {
1365 let actions = Self::get_server_code_actions_from_action_kinds(
1366 &lsp_store,
1367 language_server.server_id(),
1368 vec![kind.clone()],
1369 buffer,
1370 cx,
1371 )
1372 .await?;
1373 Self::execute_code_actions_on_server(
1374 &lsp_store,
1375 language_server,
1376 actions,
1377 push_to_history,
1378 &mut project_transaction,
1379 cx,
1380 )
1381 .await?;
1382 }
1383 }
1384 Ok(project_transaction)
1385 }
1386
1387 async fn format_locally(
1388 lsp_store: WeakEntity<LspStore>,
1389 mut buffers: Vec<FormattableBuffer>,
1390 push_to_history: bool,
1391 trigger: FormatTrigger,
1392 logger: zlog::Logger,
1393 cx: &mut AsyncApp,
1394 ) -> anyhow::Result<ProjectTransaction> {
1395 // Do not allow multiple concurrent formatting requests for the
1396 // same buffer.
1397 lsp_store.update(cx, |this, cx| {
1398 let this = this.as_local_mut().unwrap();
1399 buffers.retain(|buffer| {
1400 this.buffers_being_formatted
1401 .insert(buffer.handle.read(cx).remote_id())
1402 });
1403 })?;
1404
1405 let _cleanup = defer({
1406 let this = lsp_store.clone();
1407 let mut cx = cx.clone();
1408 let buffers = &buffers;
1409 move || {
1410 this.update(&mut cx, |this, cx| {
1411 let this = this.as_local_mut().unwrap();
1412 for buffer in buffers {
1413 this.buffers_being_formatted
1414 .remove(&buffer.handle.read(cx).remote_id());
1415 }
1416 })
1417 .ok();
1418 }
1419 });
1420
1421 let mut project_transaction = ProjectTransaction::default();
1422
1423 for buffer in &buffers {
1424 zlog::debug!(
1425 logger =>
1426 "formatting buffer '{:?}'",
1427 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1428 );
1429 // Create an empty transaction to hold all of the formatting edits.
1430 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1431 // ensure no transactions created while formatting are
1432 // grouped with the previous transaction in the history
1433 // based on the transaction group interval
1434 buffer.finalize_last_transaction();
1435 buffer
1436 .start_transaction()
1437 .context("transaction already open")?;
1438 buffer.end_transaction(cx);
1439 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1440 buffer.finalize_last_transaction();
1441 anyhow::Ok(transaction_id)
1442 })??;
1443
1444 let result = Self::format_buffer_locally(
1445 lsp_store.clone(),
1446 buffer,
1447 formatting_transaction_id,
1448 trigger,
1449 logger,
1450 cx,
1451 )
1452 .await;
1453
1454 buffer.handle.update(cx, |buffer, cx| {
1455 let Some(formatting_transaction) =
1456 buffer.get_transaction(formatting_transaction_id).cloned()
1457 else {
1458 zlog::warn!(logger => "no formatting transaction");
1459 return;
1460 };
1461 if formatting_transaction.edit_ids.is_empty() {
1462 zlog::debug!(logger => "no changes made while formatting");
1463 buffer.forget_transaction(formatting_transaction_id);
1464 return;
1465 }
1466 if !push_to_history {
1467 zlog::trace!(logger => "forgetting format transaction");
1468 buffer.forget_transaction(formatting_transaction.id);
1469 }
1470 project_transaction
1471 .0
1472 .insert(cx.entity(), formatting_transaction);
1473 })?;
1474
1475 result?;
1476 }
1477
1478 Ok(project_transaction)
1479 }
1480
1481 async fn format_buffer_locally(
1482 lsp_store: WeakEntity<LspStore>,
1483 buffer: &FormattableBuffer,
1484 formatting_transaction_id: clock::Lamport,
1485 trigger: FormatTrigger,
1486 logger: zlog::Logger,
1487 cx: &mut AsyncApp,
1488 ) -> Result<()> {
1489 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1490 buffer.handle.update(cx, |buffer, cx| {
1491 let adapters_and_servers = lsp_store
1492 .as_local()
1493 .unwrap()
1494 .language_servers_for_buffer(buffer, cx)
1495 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1496 .collect::<Vec<_>>();
1497 let settings =
1498 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1499 .into_owned();
1500 (adapters_and_servers, settings)
1501 })
1502 })?;
1503
1504 /// Apply edits to the buffer that will become part of the formatting transaction.
1505 /// Fails if the buffer has been edited since the start of that transaction.
1506 fn extend_formatting_transaction(
1507 buffer: &FormattableBuffer,
1508 formatting_transaction_id: text::TransactionId,
1509 cx: &mut AsyncApp,
1510 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1511 ) -> anyhow::Result<()> {
1512 buffer.handle.update(cx, |buffer, cx| {
1513 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1514 if last_transaction_id != Some(formatting_transaction_id) {
1515 anyhow::bail!("Buffer edited while formatting. Aborting")
1516 }
1517 buffer.start_transaction();
1518 operation(buffer, cx);
1519 if let Some(transaction_id) = buffer.end_transaction(cx) {
1520 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1521 }
1522 Ok(())
1523 })?
1524 }
1525
1526 // handle whitespace formatting
1527 if settings.remove_trailing_whitespace_on_save {
1528 zlog::trace!(logger => "removing trailing whitespace");
1529 let diff = buffer
1530 .handle
1531 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1532 .await;
1533 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1534 buffer.apply_diff(diff, cx);
1535 })?;
1536 }
1537
1538 if settings.ensure_final_newline_on_save {
1539 zlog::trace!(logger => "ensuring final newline");
1540 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1541 buffer.ensure_final_newline(cx);
1542 })?;
1543 }
1544
1545 // Formatter for `code_actions_on_format` that runs before
1546 // the rest of the formatters
1547 let mut code_actions_on_format_formatters = None;
1548 let should_run_code_actions_on_format = !matches!(
1549 (trigger, &settings.format_on_save),
1550 (FormatTrigger::Save, &FormatOnSave::Off)
1551 );
1552 if should_run_code_actions_on_format {
1553 let have_code_actions_to_run_on_format = settings
1554 .code_actions_on_format
1555 .values()
1556 .any(|enabled| *enabled);
1557 if have_code_actions_to_run_on_format {
1558 zlog::trace!(logger => "going to run code actions on format");
1559 code_actions_on_format_formatters = Some(
1560 settings
1561 .code_actions_on_format
1562 .iter()
1563 .filter_map(|(action, enabled)| enabled.then_some(action))
1564 .cloned()
1565 .map(Formatter::CodeAction)
1566 .collect::<Vec<_>>(),
1567 );
1568 }
1569 }
1570
1571 let formatters = match (trigger, &settings.format_on_save) {
1572 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1573 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1574 settings.formatter.as_ref()
1575 }
1576 };
1577
1578 let formatters = code_actions_on_format_formatters
1579 .iter()
1580 .flatten()
1581 .chain(formatters);
1582
1583 for formatter in formatters {
1584 let formatter = if formatter == &Formatter::Auto {
1585 if settings.prettier.allowed {
1586 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1587 &Formatter::Prettier
1588 } else {
1589 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1590 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1591 }
1592 } else {
1593 formatter
1594 };
1595 match formatter {
1596 Formatter::Auto => unreachable!("Auto resolved above"),
1597 Formatter::Prettier => {
1598 let logger = zlog::scoped!(logger => "prettier");
1599 zlog::trace!(logger => "formatting");
1600 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1601
1602 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1603 lsp_store.prettier_store().unwrap().downgrade()
1604 })?;
1605 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1606 .await
1607 .transpose()?;
1608 let Some(diff) = diff else {
1609 zlog::trace!(logger => "No changes");
1610 continue;
1611 };
1612
1613 extend_formatting_transaction(
1614 buffer,
1615 formatting_transaction_id,
1616 cx,
1617 |buffer, cx| {
1618 buffer.apply_diff(diff, cx);
1619 },
1620 )?;
1621 }
1622 Formatter::External { command, arguments } => {
1623 let logger = zlog::scoped!(logger => "command");
1624 zlog::trace!(logger => "formatting");
1625 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1626
1627 let diff = Self::format_via_external_command(
1628 buffer,
1629 command.as_ref(),
1630 arguments.as_deref(),
1631 cx,
1632 )
1633 .await
1634 .with_context(|| {
1635 format!("Failed to format buffer via external command: {}", command)
1636 })?;
1637 let Some(diff) = diff else {
1638 zlog::trace!(logger => "No changes");
1639 continue;
1640 };
1641
1642 extend_formatting_transaction(
1643 buffer,
1644 formatting_transaction_id,
1645 cx,
1646 |buffer, cx| {
1647 buffer.apply_diff(diff, cx);
1648 },
1649 )?;
1650 }
1651 Formatter::LanguageServer(specifier) => {
1652 let logger = zlog::scoped!(logger => "language-server");
1653 zlog::trace!(logger => "formatting");
1654 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1655
1656 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1657 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1658 continue;
1659 };
1660
1661 let language_server = match specifier {
1662 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1663 adapters_and_servers.iter().find_map(|(adapter, server)| {
1664 if adapter.name.0.as_ref() == name {
1665 Some(server.clone())
1666 } else {
1667 None
1668 }
1669 })
1670 }
1671 settings::LanguageServerFormatterSpecifier::Current => {
1672 adapters_and_servers.first().map(|e| e.1.clone())
1673 }
1674 };
1675
1676 let Some(language_server) = language_server else {
1677 log::debug!(
1678 "No language server found to format buffer '{:?}'. Skipping",
1679 buffer_path_abs.as_path().to_string_lossy()
1680 );
1681 continue;
1682 };
1683
1684 zlog::trace!(
1685 logger =>
1686 "Formatting buffer '{:?}' using language server '{:?}'",
1687 buffer_path_abs.as_path().to_string_lossy(),
1688 language_server.name()
1689 );
1690
1691 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1692 zlog::trace!(logger => "formatting ranges");
1693 Self::format_ranges_via_lsp(
1694 &lsp_store,
1695 &buffer.handle,
1696 ranges,
1697 buffer_path_abs,
1698 &language_server,
1699 &settings,
1700 cx,
1701 )
1702 .await
1703 .context("Failed to format ranges via language server")?
1704 } else {
1705 zlog::trace!(logger => "formatting full");
1706 Self::format_via_lsp(
1707 &lsp_store,
1708 &buffer.handle,
1709 buffer_path_abs,
1710 &language_server,
1711 &settings,
1712 cx,
1713 )
1714 .await
1715 .context("failed to format via language server")?
1716 };
1717
1718 if edits.is_empty() {
1719 zlog::trace!(logger => "No changes");
1720 continue;
1721 }
1722 extend_formatting_transaction(
1723 buffer,
1724 formatting_transaction_id,
1725 cx,
1726 |buffer, cx| {
1727 buffer.edit(edits, None, cx);
1728 },
1729 )?;
1730 }
1731 Formatter::CodeAction(code_action_name) => {
1732 let logger = zlog::scoped!(logger => "code-actions");
1733 zlog::trace!(logger => "formatting");
1734 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1735
1736 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1737 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1738 continue;
1739 };
1740
1741 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1742 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1743
1744 let mut actions_and_servers = Vec::new();
1745
1746 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1747 let actions_result = Self::get_server_code_actions_from_action_kinds(
1748 &lsp_store,
1749 language_server.server_id(),
1750 vec![code_action_kind.clone()],
1751 &buffer.handle,
1752 cx,
1753 )
1754 .await
1755 .with_context(|| {
1756 format!(
1757 "Failed to resolve code action {:?} with language server {}",
1758 code_action_kind,
1759 language_server.name()
1760 )
1761 });
1762 let Ok(actions) = actions_result else {
1763 // note: it may be better to set result to the error and break formatters here
1764 // but for now we try to execute the actions that we can resolve and skip the rest
1765 zlog::error!(
1766 logger =>
1767 "Failed to resolve code action {:?} with language server {}",
1768 code_action_kind,
1769 language_server.name()
1770 );
1771 continue;
1772 };
1773 for action in actions {
1774 actions_and_servers.push((action, index));
1775 }
1776 }
1777
1778 if actions_and_servers.is_empty() {
1779 zlog::warn!(logger => "No code actions were resolved, continuing");
1780 continue;
1781 }
1782
1783 'actions: for (mut action, server_index) in actions_and_servers {
1784 let server = &adapters_and_servers[server_index].1;
1785
1786 let describe_code_action = |action: &CodeAction| {
1787 format!(
1788 "code action '{}' with title \"{}\" on server {}",
1789 action
1790 .lsp_action
1791 .action_kind()
1792 .unwrap_or("unknown".into())
1793 .as_str(),
1794 action.lsp_action.title(),
1795 server.name(),
1796 )
1797 };
1798
1799 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1800
1801 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1802 zlog::error!(
1803 logger =>
1804 "Failed to resolve {}. Error: {}",
1805 describe_code_action(&action),
1806 err
1807 );
1808 continue;
1809 }
1810
1811 if let Some(edit) = action.lsp_action.edit().cloned() {
1812 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1813 // but filters out and logs warnings for code actions that require unreasonably
1814 // difficult handling on our part, such as:
1815 // - applying edits that call commands
1816 // which can result in arbitrary workspace edits being sent from the server that
1817 // have no way of being tied back to the command that initiated them (i.e. we
1818 // can't know which edits are part of the format request, or if the server is done sending
1819 // actions in response to the command)
1820 // - actions that create/delete/modify/rename files other than the one we are formatting
1821 // as we then would need to handle such changes correctly in the local history as well
1822 // as the remote history through the ProjectTransaction
1823 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1824 // Supporting these actions is not impossible, but not supported as of yet.
1825 if edit.changes.is_none() && edit.document_changes.is_none() {
1826 zlog::trace!(
1827 logger =>
1828 "No changes for code action. Skipping {}",
1829 describe_code_action(&action),
1830 );
1831 continue;
1832 }
1833
1834 let mut operations = Vec::new();
1835 if let Some(document_changes) = edit.document_changes {
1836 match document_changes {
1837 lsp::DocumentChanges::Edits(edits) => operations.extend(
1838 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1839 ),
1840 lsp::DocumentChanges::Operations(ops) => operations = ops,
1841 }
1842 } else if let Some(changes) = edit.changes {
1843 operations.extend(changes.into_iter().map(|(uri, edits)| {
1844 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1845 text_document:
1846 lsp::OptionalVersionedTextDocumentIdentifier {
1847 uri,
1848 version: None,
1849 },
1850 edits: edits.into_iter().map(Edit::Plain).collect(),
1851 })
1852 }));
1853 }
1854
1855 let mut edits = Vec::with_capacity(operations.len());
1856
1857 if operations.is_empty() {
1858 zlog::trace!(
1859 logger =>
1860 "No changes for code action. Skipping {}",
1861 describe_code_action(&action),
1862 );
1863 continue;
1864 }
1865 for operation in operations {
1866 let op = match operation {
1867 lsp::DocumentChangeOperation::Edit(op) => op,
1868 lsp::DocumentChangeOperation::Op(_) => {
1869 zlog::warn!(
1870 logger =>
1871 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1872 describe_code_action(&action),
1873 );
1874 continue 'actions;
1875 }
1876 };
1877 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1878 zlog::warn!(
1879 logger =>
1880 "Failed to convert URI '{:?}' to file path. Skipping {}",
1881 &op.text_document.uri,
1882 describe_code_action(&action),
1883 );
1884 continue 'actions;
1885 };
1886 if &file_path != buffer_path_abs {
1887 zlog::warn!(
1888 logger =>
1889 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1890 file_path,
1891 buffer_path_abs,
1892 describe_code_action(&action),
1893 );
1894 continue 'actions;
1895 }
1896
1897 let mut lsp_edits = Vec::new();
1898 for edit in op.edits {
1899 match edit {
1900 Edit::Plain(edit) => {
1901 if !lsp_edits.contains(&edit) {
1902 lsp_edits.push(edit);
1903 }
1904 }
1905 Edit::Annotated(edit) => {
1906 if !lsp_edits.contains(&edit.text_edit) {
1907 lsp_edits.push(edit.text_edit);
1908 }
1909 }
1910 Edit::Snippet(_) => {
1911 zlog::warn!(
1912 logger =>
1913 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1914 describe_code_action(&action),
1915 );
1916 continue 'actions;
1917 }
1918 }
1919 }
1920 let edits_result = lsp_store
1921 .update(cx, |lsp_store, cx| {
1922 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1923 &buffer.handle,
1924 lsp_edits,
1925 server.server_id(),
1926 op.text_document.version,
1927 cx,
1928 )
1929 })?
1930 .await;
1931 let Ok(resolved_edits) = edits_result else {
1932 zlog::warn!(
1933 logger =>
1934 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1935 buffer_path_abs.as_path(),
1936 describe_code_action(&action),
1937 );
1938 continue 'actions;
1939 };
1940 edits.extend(resolved_edits);
1941 }
1942
1943 if edits.is_empty() {
1944 zlog::warn!(logger => "No edits resolved from LSP");
1945 continue;
1946 }
1947
1948 extend_formatting_transaction(
1949 buffer,
1950 formatting_transaction_id,
1951 cx,
1952 |buffer, cx| {
1953 zlog::info!(
1954 "Applying edits {edits:?}. Content: {:?}",
1955 buffer.text()
1956 );
1957 buffer.edit(edits, None, cx);
1958 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1959 },
1960 )?;
1961 }
1962
1963 if let Some(command) = action.lsp_action.command() {
1964 zlog::warn!(
1965 logger =>
1966 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1967 &command.command,
1968 );
1969
1970 // bail early if command is invalid
1971 let server_capabilities = server.capabilities();
1972 let available_commands = server_capabilities
1973 .execute_command_provider
1974 .as_ref()
1975 .map(|options| options.commands.as_slice())
1976 .unwrap_or_default();
1977 if !available_commands.contains(&command.command) {
1978 zlog::warn!(
1979 logger =>
1980 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1981 command.command,
1982 server.name(),
1983 );
1984 continue;
1985 }
1986
1987 // noop so we just ensure buffer hasn't been edited since resolving code actions
1988 extend_formatting_transaction(
1989 buffer,
1990 formatting_transaction_id,
1991 cx,
1992 |_, _| {},
1993 )?;
1994 zlog::info!(logger => "Executing command {}", &command.command);
1995
1996 lsp_store.update(cx, |this, _| {
1997 this.as_local_mut()
1998 .unwrap()
1999 .last_workspace_edits_by_language_server
2000 .remove(&server.server_id());
2001 })?;
2002
2003 let execute_command_result = server
2004 .request::<lsp::request::ExecuteCommand>(
2005 lsp::ExecuteCommandParams {
2006 command: command.command.clone(),
2007 arguments: command.arguments.clone().unwrap_or_default(),
2008 ..Default::default()
2009 },
2010 )
2011 .await
2012 .into_response();
2013
2014 if execute_command_result.is_err() {
2015 zlog::error!(
2016 logger =>
2017 "Failed to execute command '{}' as part of {}",
2018 &command.command,
2019 describe_code_action(&action),
2020 );
2021 continue 'actions;
2022 }
2023
2024 let mut project_transaction_command =
2025 lsp_store.update(cx, |this, _| {
2026 this.as_local_mut()
2027 .unwrap()
2028 .last_workspace_edits_by_language_server
2029 .remove(&server.server_id())
2030 .unwrap_or_default()
2031 })?;
2032
2033 if let Some(transaction) =
2034 project_transaction_command.0.remove(&buffer.handle)
2035 {
2036 zlog::trace!(
2037 logger =>
2038 "Successfully captured {} edits that resulted from command {}",
2039 transaction.edit_ids.len(),
2040 &command.command,
2041 );
2042 let transaction_id_project_transaction = transaction.id;
2043 buffer.handle.update(cx, |buffer, _| {
2044 // it may have been removed from history if push_to_history was
2045 // false in deserialize_workspace_edit. If so push it so we
2046 // can merge it with the format transaction
2047 // and pop the combined transaction off the history stack
2048 // later if push_to_history is false
2049 if buffer.get_transaction(transaction.id).is_none() {
2050 buffer.push_transaction(transaction, Instant::now());
2051 }
2052 buffer.merge_transactions(
2053 transaction_id_project_transaction,
2054 formatting_transaction_id,
2055 );
2056 })?;
2057 }
2058
2059 if !project_transaction_command.0.is_empty() {
2060 let mut extra_buffers = String::new();
2061 for buffer in project_transaction_command.0.keys() {
2062 buffer
2063 .read_with(cx, |b, cx| {
2064 if let Some(path) = b.project_path(cx) {
2065 if !extra_buffers.is_empty() {
2066 extra_buffers.push_str(", ");
2067 }
2068 extra_buffers.push_str(path.path.as_unix_str());
2069 }
2070 })
2071 .ok();
2072 }
2073 zlog::warn!(
2074 logger =>
2075 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2076 &command.command,
2077 extra_buffers,
2078 );
2079 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2080 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2081 // add it so it's included, and merge it into the format transaction when its created later
2082 }
2083 }
2084 }
2085 }
2086 }
2087 }
2088
2089 Ok(())
2090 }
2091
2092 pub async fn format_ranges_via_lsp(
2093 this: &WeakEntity<LspStore>,
2094 buffer_handle: &Entity<Buffer>,
2095 ranges: &[Range<Anchor>],
2096 abs_path: &Path,
2097 language_server: &Arc<LanguageServer>,
2098 settings: &LanguageSettings,
2099 cx: &mut AsyncApp,
2100 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2101 let capabilities = &language_server.capabilities();
2102 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2103 if range_formatting_provider == Some(&OneOf::Left(false)) {
2104 anyhow::bail!(
2105 "{} language server does not support range formatting",
2106 language_server.name()
2107 );
2108 }
2109
2110 let uri = file_path_to_lsp_url(abs_path)?;
2111 let text_document = lsp::TextDocumentIdentifier::new(uri);
2112
2113 let lsp_edits = {
2114 let mut lsp_ranges = Vec::new();
2115 this.update(cx, |_this, cx| {
2116 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2117 // not have been sent to the language server. This seems like a fairly systemic
2118 // issue, though, the resolution probably is not specific to formatting.
2119 //
2120 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2121 // LSP.
2122 let snapshot = buffer_handle.read(cx).snapshot();
2123 for range in ranges {
2124 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2125 }
2126 anyhow::Ok(())
2127 })??;
2128
2129 let mut edits = None;
2130 for range in lsp_ranges {
2131 if let Some(mut edit) = language_server
2132 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2133 text_document: text_document.clone(),
2134 range,
2135 options: lsp_command::lsp_formatting_options(settings),
2136 work_done_progress_params: Default::default(),
2137 })
2138 .await
2139 .into_response()?
2140 {
2141 edits.get_or_insert_with(Vec::new).append(&mut edit);
2142 }
2143 }
2144 edits
2145 };
2146
2147 if let Some(lsp_edits) = lsp_edits {
2148 this.update(cx, |this, cx| {
2149 this.as_local_mut().unwrap().edits_from_lsp(
2150 buffer_handle,
2151 lsp_edits,
2152 language_server.server_id(),
2153 None,
2154 cx,
2155 )
2156 })?
2157 .await
2158 } else {
2159 Ok(Vec::with_capacity(0))
2160 }
2161 }
2162
2163 async fn format_via_lsp(
2164 this: &WeakEntity<LspStore>,
2165 buffer: &Entity<Buffer>,
2166 abs_path: &Path,
2167 language_server: &Arc<LanguageServer>,
2168 settings: &LanguageSettings,
2169 cx: &mut AsyncApp,
2170 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2171 let logger = zlog::scoped!("lsp_format");
2172 zlog::debug!(logger => "Formatting via LSP");
2173
2174 let uri = file_path_to_lsp_url(abs_path)?;
2175 let text_document = lsp::TextDocumentIdentifier::new(uri);
2176 let capabilities = &language_server.capabilities();
2177
2178 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2179 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2180
2181 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2182 let _timer = zlog::time!(logger => "format-full");
2183 language_server
2184 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2185 text_document,
2186 options: lsp_command::lsp_formatting_options(settings),
2187 work_done_progress_params: Default::default(),
2188 })
2189 .await
2190 .into_response()?
2191 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2192 let _timer = zlog::time!(logger => "format-range");
2193 let buffer_start = lsp::Position::new(0, 0);
2194 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2195 language_server
2196 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2197 text_document: text_document.clone(),
2198 range: lsp::Range::new(buffer_start, buffer_end),
2199 options: lsp_command::lsp_formatting_options(settings),
2200 work_done_progress_params: Default::default(),
2201 })
2202 .await
2203 .into_response()?
2204 } else {
2205 None
2206 };
2207
2208 if let Some(lsp_edits) = lsp_edits {
2209 this.update(cx, |this, cx| {
2210 this.as_local_mut().unwrap().edits_from_lsp(
2211 buffer,
2212 lsp_edits,
2213 language_server.server_id(),
2214 None,
2215 cx,
2216 )
2217 })?
2218 .await
2219 } else {
2220 Ok(Vec::with_capacity(0))
2221 }
2222 }
2223
2224 async fn format_via_external_command(
2225 buffer: &FormattableBuffer,
2226 command: &str,
2227 arguments: Option<&[String]>,
2228 cx: &mut AsyncApp,
2229 ) -> Result<Option<Diff>> {
2230 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2231 let file = File::from_dyn(buffer.file())?;
2232 let worktree = file.worktree.read(cx);
2233 let mut worktree_path = worktree.abs_path().to_path_buf();
2234 if worktree.root_entry()?.is_file() {
2235 worktree_path.pop();
2236 }
2237 Some(worktree_path)
2238 })?;
2239
2240 let mut child = util::command::new_smol_command(command);
2241
2242 if let Some(buffer_env) = buffer.env.as_ref() {
2243 child.envs(buffer_env);
2244 }
2245
2246 if let Some(working_dir_path) = working_dir_path {
2247 child.current_dir(working_dir_path);
2248 }
2249
2250 if let Some(arguments) = arguments {
2251 child.args(arguments.iter().map(|arg| {
2252 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2253 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2254 } else {
2255 arg.replace("{buffer_path}", "Untitled")
2256 }
2257 }));
2258 }
2259
2260 let mut child = child
2261 .stdin(smol::process::Stdio::piped())
2262 .stdout(smol::process::Stdio::piped())
2263 .stderr(smol::process::Stdio::piped())
2264 .spawn()?;
2265
2266 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2267 let text = buffer
2268 .handle
2269 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2270 for chunk in text.chunks() {
2271 stdin.write_all(chunk.as_bytes()).await?;
2272 }
2273 stdin.flush().await?;
2274
2275 let output = child.output().await?;
2276 anyhow::ensure!(
2277 output.status.success(),
2278 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2279 output.status.code(),
2280 String::from_utf8_lossy(&output.stdout),
2281 String::from_utf8_lossy(&output.stderr),
2282 );
2283
2284 let stdout = String::from_utf8(output.stdout)?;
2285 Ok(Some(
2286 buffer
2287 .handle
2288 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2289 .await,
2290 ))
2291 }
2292
2293 async fn try_resolve_code_action(
2294 lang_server: &LanguageServer,
2295 action: &mut CodeAction,
2296 ) -> anyhow::Result<()> {
2297 match &mut action.lsp_action {
2298 LspAction::Action(lsp_action) => {
2299 if !action.resolved
2300 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2301 && lsp_action.data.is_some()
2302 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2303 {
2304 **lsp_action = lang_server
2305 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2306 .await
2307 .into_response()?;
2308 }
2309 }
2310 LspAction::CodeLens(lens) => {
2311 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2312 *lens = lang_server
2313 .request::<lsp::request::CodeLensResolve>(lens.clone())
2314 .await
2315 .into_response()?;
2316 }
2317 }
2318 LspAction::Command(_) => {}
2319 }
2320
2321 action.resolved = true;
2322 anyhow::Ok(())
2323 }
2324
2325 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2326 let buffer = buffer_handle.read(cx);
2327
2328 let file = buffer.file().cloned();
2329
2330 let Some(file) = File::from_dyn(file.as_ref()) else {
2331 return;
2332 };
2333 if !file.is_local() {
2334 return;
2335 }
2336 let path = ProjectPath::from_file(file, cx);
2337 let worktree_id = file.worktree_id(cx);
2338 let language = buffer.language().cloned();
2339
2340 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2341 for (server_id, diagnostics) in
2342 diagnostics.get(file.path()).cloned().unwrap_or_default()
2343 {
2344 self.update_buffer_diagnostics(
2345 buffer_handle,
2346 server_id,
2347 None,
2348 None,
2349 None,
2350 Vec::new(),
2351 diagnostics,
2352 cx,
2353 )
2354 .log_err();
2355 }
2356 }
2357 let Some(language) = language else {
2358 return;
2359 };
2360 let Some(snapshot) = self
2361 .worktree_store
2362 .read(cx)
2363 .worktree_for_id(worktree_id, cx)
2364 .map(|worktree| worktree.read(cx).snapshot())
2365 else {
2366 return;
2367 };
2368 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2369
2370 for server_id in
2371 self.lsp_tree
2372 .get(path, language.name(), language.manifest(), &delegate, cx)
2373 {
2374 let server = self
2375 .language_servers
2376 .get(&server_id)
2377 .and_then(|server_state| {
2378 if let LanguageServerState::Running { server, .. } = server_state {
2379 Some(server.clone())
2380 } else {
2381 None
2382 }
2383 });
2384 let server = match server {
2385 Some(server) => server,
2386 None => continue,
2387 };
2388
2389 buffer_handle.update(cx, |buffer, cx| {
2390 buffer.set_completion_triggers(
2391 server.server_id(),
2392 server
2393 .capabilities()
2394 .completion_provider
2395 .as_ref()
2396 .and_then(|provider| {
2397 provider
2398 .trigger_characters
2399 .as_ref()
2400 .map(|characters| characters.iter().cloned().collect())
2401 })
2402 .unwrap_or_default(),
2403 cx,
2404 );
2405 });
2406 }
2407 }
2408
2409 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2410 buffer.update(cx, |buffer, cx| {
2411 let Some(language) = buffer.language() else {
2412 return;
2413 };
2414 let path = ProjectPath {
2415 worktree_id: old_file.worktree_id(cx),
2416 path: old_file.path.clone(),
2417 };
2418 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2419 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2420 buffer.set_completion_triggers(server_id, Default::default(), cx);
2421 }
2422 });
2423 }
2424
2425 fn update_buffer_diagnostics(
2426 &mut self,
2427 buffer: &Entity<Buffer>,
2428 server_id: LanguageServerId,
2429 registration_id: Option<Option<SharedString>>,
2430 result_id: Option<SharedString>,
2431 version: Option<i32>,
2432 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2433 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2434 cx: &mut Context<LspStore>,
2435 ) -> Result<()> {
2436 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2437 Ordering::Equal
2438 .then_with(|| b.is_primary.cmp(&a.is_primary))
2439 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2440 .then_with(|| a.severity.cmp(&b.severity))
2441 .then_with(|| a.message.cmp(&b.message))
2442 }
2443
2444 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2445 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2446 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2447
2448 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2449 Ordering::Equal
2450 .then_with(|| a.range.start.cmp(&b.range.start))
2451 .then_with(|| b.range.end.cmp(&a.range.end))
2452 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2453 });
2454
2455 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2456
2457 let edits_since_save = std::cell::LazyCell::new(|| {
2458 let saved_version = buffer.read(cx).saved_version();
2459 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2460 });
2461
2462 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2463
2464 for (new_diagnostic, entry) in diagnostics {
2465 let start;
2466 let end;
2467 if new_diagnostic && entry.diagnostic.is_disk_based {
2468 // Some diagnostics are based on files on disk instead of buffers'
2469 // current contents. Adjust these diagnostics' ranges to reflect
2470 // any unsaved edits.
2471 // Do not alter the reused ones though, as their coordinates were stored as anchors
2472 // and were properly adjusted on reuse.
2473 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2474 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2475 } else {
2476 start = entry.range.start;
2477 end = entry.range.end;
2478 }
2479
2480 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2481 ..snapshot.clip_point_utf16(end, Bias::Right);
2482
2483 // Expand empty ranges by one codepoint
2484 if range.start == range.end {
2485 // This will be go to the next boundary when being clipped
2486 range.end.column += 1;
2487 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2488 if range.start == range.end && range.end.column > 0 {
2489 range.start.column -= 1;
2490 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2491 }
2492 }
2493
2494 sanitized_diagnostics.push(DiagnosticEntry {
2495 range,
2496 diagnostic: entry.diagnostic,
2497 });
2498 }
2499 drop(edits_since_save);
2500
2501 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2502 buffer.update(cx, |buffer, cx| {
2503 if let Some(registration_id) = registration_id {
2504 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2505 self.buffer_pull_diagnostics_result_ids
2506 .entry(server_id)
2507 .or_default()
2508 .entry(registration_id)
2509 .or_default()
2510 .insert(abs_path, result_id);
2511 }
2512 }
2513
2514 buffer.update_diagnostics(server_id, set, cx)
2515 });
2516
2517 Ok(())
2518 }
2519
2520 fn register_language_server_for_invisible_worktree(
2521 &mut self,
2522 worktree: &Entity<Worktree>,
2523 language_server_id: LanguageServerId,
2524 cx: &mut App,
2525 ) {
2526 let worktree = worktree.read(cx);
2527 let worktree_id = worktree.id();
2528 debug_assert!(!worktree.is_visible());
2529 let Some(mut origin_seed) = self
2530 .language_server_ids
2531 .iter()
2532 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2533 else {
2534 return;
2535 };
2536 origin_seed.worktree_id = worktree_id;
2537 self.language_server_ids
2538 .entry(origin_seed)
2539 .or_insert_with(|| UnifiedLanguageServer {
2540 id: language_server_id,
2541 project_roots: Default::default(),
2542 });
2543 }
2544
2545 fn register_buffer_with_language_servers(
2546 &mut self,
2547 buffer_handle: &Entity<Buffer>,
2548 only_register_servers: HashSet<LanguageServerSelector>,
2549 cx: &mut Context<LspStore>,
2550 ) {
2551 let buffer = buffer_handle.read(cx);
2552 let buffer_id = buffer.remote_id();
2553
2554 let Some(file) = File::from_dyn(buffer.file()) else {
2555 return;
2556 };
2557 if !file.is_local() {
2558 return;
2559 }
2560
2561 let abs_path = file.abs_path(cx);
2562 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2563 return;
2564 };
2565 let initial_snapshot = buffer.text_snapshot();
2566 let worktree_id = file.worktree_id(cx);
2567
2568 let Some(language) = buffer.language().cloned() else {
2569 return;
2570 };
2571 let path: Arc<RelPath> = file
2572 .path()
2573 .parent()
2574 .map(Arc::from)
2575 .unwrap_or_else(|| file.path().clone());
2576 let Some(worktree) = self
2577 .worktree_store
2578 .read(cx)
2579 .worktree_for_id(worktree_id, cx)
2580 else {
2581 return;
2582 };
2583 let language_name = language.name();
2584 let (reused, delegate, servers) = self
2585 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2586 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2587 .unwrap_or_else(|| {
2588 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2589 let delegate: Arc<dyn ManifestDelegate> =
2590 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2591
2592 let servers = self
2593 .lsp_tree
2594 .walk(
2595 ProjectPath { worktree_id, path },
2596 language.name(),
2597 language.manifest(),
2598 &delegate,
2599 cx,
2600 )
2601 .collect::<Vec<_>>();
2602 (false, lsp_delegate, servers)
2603 });
2604 let servers_and_adapters = servers
2605 .into_iter()
2606 .filter_map(|server_node| {
2607 if reused && server_node.server_id().is_none() {
2608 return None;
2609 }
2610 if !only_register_servers.is_empty() {
2611 if let Some(server_id) = server_node.server_id()
2612 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2613 {
2614 return None;
2615 }
2616 if let Some(name) = server_node.name()
2617 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2618 {
2619 return None;
2620 }
2621 }
2622
2623 let server_id = server_node.server_id_or_init(|disposition| {
2624 let path = &disposition.path;
2625
2626 {
2627 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2628
2629 let server_id = self.get_or_insert_language_server(
2630 &worktree,
2631 delegate.clone(),
2632 disposition,
2633 &language_name,
2634 cx,
2635 );
2636
2637 if let Some(state) = self.language_servers.get(&server_id)
2638 && let Ok(uri) = uri
2639 {
2640 state.add_workspace_folder(uri);
2641 };
2642 server_id
2643 }
2644 })?;
2645 let server_state = self.language_servers.get(&server_id)?;
2646 if let LanguageServerState::Running {
2647 server, adapter, ..
2648 } = server_state
2649 {
2650 Some((server.clone(), adapter.clone()))
2651 } else {
2652 None
2653 }
2654 })
2655 .collect::<Vec<_>>();
2656 for (server, adapter) in servers_and_adapters {
2657 buffer_handle.update(cx, |buffer, cx| {
2658 buffer.set_completion_triggers(
2659 server.server_id(),
2660 server
2661 .capabilities()
2662 .completion_provider
2663 .as_ref()
2664 .and_then(|provider| {
2665 provider
2666 .trigger_characters
2667 .as_ref()
2668 .map(|characters| characters.iter().cloned().collect())
2669 })
2670 .unwrap_or_default(),
2671 cx,
2672 );
2673 });
2674
2675 let snapshot = LspBufferSnapshot {
2676 version: 0,
2677 snapshot: initial_snapshot.clone(),
2678 };
2679
2680 let mut registered = false;
2681 self.buffer_snapshots
2682 .entry(buffer_id)
2683 .or_default()
2684 .entry(server.server_id())
2685 .or_insert_with(|| {
2686 registered = true;
2687 server.register_buffer(
2688 uri.clone(),
2689 adapter.language_id(&language.name()),
2690 0,
2691 initial_snapshot.text(),
2692 );
2693
2694 vec![snapshot]
2695 });
2696
2697 self.buffers_opened_in_servers
2698 .entry(buffer_id)
2699 .or_default()
2700 .insert(server.server_id());
2701 if registered {
2702 cx.emit(LspStoreEvent::LanguageServerUpdate {
2703 language_server_id: server.server_id(),
2704 name: None,
2705 message: proto::update_language_server::Variant::RegisteredForBuffer(
2706 proto::RegisteredForBuffer {
2707 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2708 buffer_id: buffer_id.to_proto(),
2709 },
2710 ),
2711 });
2712 }
2713 }
2714 }
2715
2716 fn reuse_existing_language_server<'lang_name>(
2717 &self,
2718 server_tree: &LanguageServerTree,
2719 worktree: &Entity<Worktree>,
2720 language_name: &'lang_name LanguageName,
2721 cx: &mut App,
2722 ) -> Option<(
2723 Arc<LocalLspAdapterDelegate>,
2724 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2725 )> {
2726 if worktree.read(cx).is_visible() {
2727 return None;
2728 }
2729
2730 let worktree_store = self.worktree_store.read(cx);
2731 let servers = server_tree
2732 .instances
2733 .iter()
2734 .filter(|(worktree_id, _)| {
2735 worktree_store
2736 .worktree_for_id(**worktree_id, cx)
2737 .is_some_and(|worktree| worktree.read(cx).is_visible())
2738 })
2739 .flat_map(|(worktree_id, servers)| {
2740 servers
2741 .roots
2742 .iter()
2743 .flat_map(|(_, language_servers)| language_servers)
2744 .map(move |(_, (server_node, server_languages))| {
2745 (worktree_id, server_node, server_languages)
2746 })
2747 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2748 .map(|(worktree_id, server_node, _)| {
2749 (
2750 *worktree_id,
2751 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2752 )
2753 })
2754 })
2755 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2756 acc.entry(worktree_id)
2757 .or_insert_with(Vec::new)
2758 .push(server_node);
2759 acc
2760 })
2761 .into_values()
2762 .max_by_key(|servers| servers.len())?;
2763
2764 let worktree_id = worktree.read(cx).id();
2765 let apply = move |tree: &mut LanguageServerTree| {
2766 for server_node in &servers {
2767 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2768 }
2769 servers
2770 };
2771
2772 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2773 Some((delegate, apply))
2774 }
2775
2776 pub(crate) fn unregister_old_buffer_from_language_servers(
2777 &mut self,
2778 buffer: &Entity<Buffer>,
2779 old_file: &File,
2780 cx: &mut App,
2781 ) {
2782 let old_path = match old_file.as_local() {
2783 Some(local) => local.abs_path(cx),
2784 None => return,
2785 };
2786
2787 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2788 debug_panic!("{old_path:?} is not parseable as an URI");
2789 return;
2790 };
2791 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2792 }
2793
2794 pub(crate) fn unregister_buffer_from_language_servers(
2795 &mut self,
2796 buffer: &Entity<Buffer>,
2797 file_url: &lsp::Uri,
2798 cx: &mut App,
2799 ) {
2800 buffer.update(cx, |buffer, cx| {
2801 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2802
2803 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2804 if snapshots
2805 .as_mut()
2806 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2807 {
2808 language_server.unregister_buffer(file_url.clone());
2809 }
2810 }
2811 });
2812 }
2813
2814 fn buffer_snapshot_for_lsp_version(
2815 &mut self,
2816 buffer: &Entity<Buffer>,
2817 server_id: LanguageServerId,
2818 version: Option<i32>,
2819 cx: &App,
2820 ) -> Result<TextBufferSnapshot> {
2821 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2822
2823 if let Some(version) = version {
2824 let buffer_id = buffer.read(cx).remote_id();
2825 let snapshots = if let Some(snapshots) = self
2826 .buffer_snapshots
2827 .get_mut(&buffer_id)
2828 .and_then(|m| m.get_mut(&server_id))
2829 {
2830 snapshots
2831 } else if version == 0 {
2832 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2833 // We detect this case and treat it as if the version was `None`.
2834 return Ok(buffer.read(cx).text_snapshot());
2835 } else {
2836 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2837 };
2838
2839 let found_snapshot = snapshots
2840 .binary_search_by_key(&version, |e| e.version)
2841 .map(|ix| snapshots[ix].snapshot.clone())
2842 .map_err(|_| {
2843 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2844 })?;
2845
2846 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2847 Ok(found_snapshot)
2848 } else {
2849 Ok((buffer.read(cx)).text_snapshot())
2850 }
2851 }
2852
2853 async fn get_server_code_actions_from_action_kinds(
2854 lsp_store: &WeakEntity<LspStore>,
2855 language_server_id: LanguageServerId,
2856 code_action_kinds: Vec<lsp::CodeActionKind>,
2857 buffer: &Entity<Buffer>,
2858 cx: &mut AsyncApp,
2859 ) -> Result<Vec<CodeAction>> {
2860 let actions = lsp_store
2861 .update(cx, move |this, cx| {
2862 let request = GetCodeActions {
2863 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2864 kinds: Some(code_action_kinds),
2865 };
2866 let server = LanguageServerToQuery::Other(language_server_id);
2867 this.request_lsp(buffer.clone(), server, request, cx)
2868 })?
2869 .await?;
2870 Ok(actions)
2871 }
2872
2873 pub async fn execute_code_actions_on_server(
2874 lsp_store: &WeakEntity<LspStore>,
2875 language_server: &Arc<LanguageServer>,
2876
2877 actions: Vec<CodeAction>,
2878 push_to_history: bool,
2879 project_transaction: &mut ProjectTransaction,
2880 cx: &mut AsyncApp,
2881 ) -> anyhow::Result<()> {
2882 for mut action in actions {
2883 Self::try_resolve_code_action(language_server, &mut action)
2884 .await
2885 .context("resolving a formatting code action")?;
2886
2887 if let Some(edit) = action.lsp_action.edit() {
2888 if edit.changes.is_none() && edit.document_changes.is_none() {
2889 continue;
2890 }
2891
2892 let new = Self::deserialize_workspace_edit(
2893 lsp_store.upgrade().context("project dropped")?,
2894 edit.clone(),
2895 push_to_history,
2896 language_server.clone(),
2897 cx,
2898 )
2899 .await?;
2900 project_transaction.0.extend(new.0);
2901 }
2902
2903 if let Some(command) = action.lsp_action.command() {
2904 let server_capabilities = language_server.capabilities();
2905 let available_commands = server_capabilities
2906 .execute_command_provider
2907 .as_ref()
2908 .map(|options| options.commands.as_slice())
2909 .unwrap_or_default();
2910 if available_commands.contains(&command.command) {
2911 lsp_store.update(cx, |lsp_store, _| {
2912 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2913 mode.last_workspace_edits_by_language_server
2914 .remove(&language_server.server_id());
2915 }
2916 })?;
2917
2918 language_server
2919 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2920 command: command.command.clone(),
2921 arguments: command.arguments.clone().unwrap_or_default(),
2922 ..Default::default()
2923 })
2924 .await
2925 .into_response()
2926 .context("execute command")?;
2927
2928 lsp_store.update(cx, |this, _| {
2929 if let LspStoreMode::Local(mode) = &mut this.mode {
2930 project_transaction.0.extend(
2931 mode.last_workspace_edits_by_language_server
2932 .remove(&language_server.server_id())
2933 .unwrap_or_default()
2934 .0,
2935 )
2936 }
2937 })?;
2938 } else {
2939 log::warn!(
2940 "Cannot execute a command {} not listed in the language server capabilities",
2941 command.command
2942 )
2943 }
2944 }
2945 }
2946 Ok(())
2947 }
2948
2949 pub async fn deserialize_text_edits(
2950 this: Entity<LspStore>,
2951 buffer_to_edit: Entity<Buffer>,
2952 edits: Vec<lsp::TextEdit>,
2953 push_to_history: bool,
2954 _: Arc<CachedLspAdapter>,
2955 language_server: Arc<LanguageServer>,
2956 cx: &mut AsyncApp,
2957 ) -> Result<Option<Transaction>> {
2958 let edits = this
2959 .update(cx, |this, cx| {
2960 this.as_local_mut().unwrap().edits_from_lsp(
2961 &buffer_to_edit,
2962 edits,
2963 language_server.server_id(),
2964 None,
2965 cx,
2966 )
2967 })?
2968 .await?;
2969
2970 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2971 buffer.finalize_last_transaction();
2972 buffer.start_transaction();
2973 for (range, text) in edits {
2974 buffer.edit([(range, text)], None, cx);
2975 }
2976
2977 if buffer.end_transaction(cx).is_some() {
2978 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2979 if !push_to_history {
2980 buffer.forget_transaction(transaction.id);
2981 }
2982 Some(transaction)
2983 } else {
2984 None
2985 }
2986 })?;
2987
2988 Ok(transaction)
2989 }
2990
2991 #[allow(clippy::type_complexity)]
2992 pub(crate) fn edits_from_lsp(
2993 &mut self,
2994 buffer: &Entity<Buffer>,
2995 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2996 server_id: LanguageServerId,
2997 version: Option<i32>,
2998 cx: &mut Context<LspStore>,
2999 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3000 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3001 cx.background_spawn(async move {
3002 let snapshot = snapshot?;
3003 let mut lsp_edits = lsp_edits
3004 .into_iter()
3005 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3006 .collect::<Vec<_>>();
3007
3008 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3009
3010 let mut lsp_edits = lsp_edits.into_iter().peekable();
3011 let mut edits = Vec::new();
3012 while let Some((range, mut new_text)) = lsp_edits.next() {
3013 // Clip invalid ranges provided by the language server.
3014 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3015 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3016
3017 // Combine any LSP edits that are adjacent.
3018 //
3019 // Also, combine LSP edits that are separated from each other by only
3020 // a newline. This is important because for some code actions,
3021 // Rust-analyzer rewrites the entire buffer via a series of edits that
3022 // are separated by unchanged newline characters.
3023 //
3024 // In order for the diffing logic below to work properly, any edits that
3025 // cancel each other out must be combined into one.
3026 while let Some((next_range, next_text)) = lsp_edits.peek() {
3027 if next_range.start.0 > range.end {
3028 if next_range.start.0.row > range.end.row + 1
3029 || next_range.start.0.column > 0
3030 || snapshot.clip_point_utf16(
3031 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3032 Bias::Left,
3033 ) > range.end
3034 {
3035 break;
3036 }
3037 new_text.push('\n');
3038 }
3039 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3040 new_text.push_str(next_text);
3041 lsp_edits.next();
3042 }
3043
3044 // For multiline edits, perform a diff of the old and new text so that
3045 // we can identify the changes more precisely, preserving the locations
3046 // of any anchors positioned in the unchanged regions.
3047 if range.end.row > range.start.row {
3048 let offset = range.start.to_offset(&snapshot);
3049 let old_text = snapshot.text_for_range(range).collect::<String>();
3050 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3051 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3052 (
3053 snapshot.anchor_after(offset + range.start)
3054 ..snapshot.anchor_before(offset + range.end),
3055 replacement,
3056 )
3057 }));
3058 } else if range.end == range.start {
3059 let anchor = snapshot.anchor_after(range.start);
3060 edits.push((anchor..anchor, new_text.into()));
3061 } else {
3062 let edit_start = snapshot.anchor_after(range.start);
3063 let edit_end = snapshot.anchor_before(range.end);
3064 edits.push((edit_start..edit_end, new_text.into()));
3065 }
3066 }
3067
3068 Ok(edits)
3069 })
3070 }
3071
3072 pub(crate) async fn deserialize_workspace_edit(
3073 this: Entity<LspStore>,
3074 edit: lsp::WorkspaceEdit,
3075 push_to_history: bool,
3076 language_server: Arc<LanguageServer>,
3077 cx: &mut AsyncApp,
3078 ) -> Result<ProjectTransaction> {
3079 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3080
3081 let mut operations = Vec::new();
3082 if let Some(document_changes) = edit.document_changes {
3083 match document_changes {
3084 lsp::DocumentChanges::Edits(edits) => {
3085 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3086 }
3087 lsp::DocumentChanges::Operations(ops) => operations = ops,
3088 }
3089 } else if let Some(changes) = edit.changes {
3090 operations.extend(changes.into_iter().map(|(uri, edits)| {
3091 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3092 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3093 uri,
3094 version: None,
3095 },
3096 edits: edits.into_iter().map(Edit::Plain).collect(),
3097 })
3098 }));
3099 }
3100
3101 let mut project_transaction = ProjectTransaction::default();
3102 for operation in operations {
3103 match operation {
3104 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3105 let abs_path = op
3106 .uri
3107 .to_file_path()
3108 .map_err(|()| anyhow!("can't convert URI to path"))?;
3109
3110 if let Some(parent_path) = abs_path.parent() {
3111 fs.create_dir(parent_path).await?;
3112 }
3113 if abs_path.ends_with("/") {
3114 fs.create_dir(&abs_path).await?;
3115 } else {
3116 fs.create_file(
3117 &abs_path,
3118 op.options
3119 .map(|options| fs::CreateOptions {
3120 overwrite: options.overwrite.unwrap_or(false),
3121 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3122 })
3123 .unwrap_or_default(),
3124 )
3125 .await?;
3126 }
3127 }
3128
3129 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3130 let source_abs_path = op
3131 .old_uri
3132 .to_file_path()
3133 .map_err(|()| anyhow!("can't convert URI to path"))?;
3134 let target_abs_path = op
3135 .new_uri
3136 .to_file_path()
3137 .map_err(|()| anyhow!("can't convert URI to path"))?;
3138
3139 let options = fs::RenameOptions {
3140 overwrite: op
3141 .options
3142 .as_ref()
3143 .and_then(|options| options.overwrite)
3144 .unwrap_or(false),
3145 ignore_if_exists: op
3146 .options
3147 .as_ref()
3148 .and_then(|options| options.ignore_if_exists)
3149 .unwrap_or(false),
3150 create_parents: true,
3151 };
3152
3153 fs.rename(&source_abs_path, &target_abs_path, options)
3154 .await?;
3155 }
3156
3157 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3158 let abs_path = op
3159 .uri
3160 .to_file_path()
3161 .map_err(|()| anyhow!("can't convert URI to path"))?;
3162 let options = op
3163 .options
3164 .map(|options| fs::RemoveOptions {
3165 recursive: options.recursive.unwrap_or(false),
3166 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3167 })
3168 .unwrap_or_default();
3169 if abs_path.ends_with("/") {
3170 fs.remove_dir(&abs_path, options).await?;
3171 } else {
3172 fs.remove_file(&abs_path, options).await?;
3173 }
3174 }
3175
3176 lsp::DocumentChangeOperation::Edit(op) => {
3177 let buffer_to_edit = this
3178 .update(cx, |this, cx| {
3179 this.open_local_buffer_via_lsp(
3180 op.text_document.uri.clone(),
3181 language_server.server_id(),
3182 cx,
3183 )
3184 })?
3185 .await?;
3186
3187 let edits = this
3188 .update(cx, |this, cx| {
3189 let path = buffer_to_edit.read(cx).project_path(cx);
3190 let active_entry = this.active_entry;
3191 let is_active_entry = path.is_some_and(|project_path| {
3192 this.worktree_store
3193 .read(cx)
3194 .entry_for_path(&project_path, cx)
3195 .is_some_and(|entry| Some(entry.id) == active_entry)
3196 });
3197 let local = this.as_local_mut().unwrap();
3198
3199 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3200 for edit in op.edits {
3201 match edit {
3202 Edit::Plain(edit) => {
3203 if !edits.contains(&edit) {
3204 edits.push(edit)
3205 }
3206 }
3207 Edit::Annotated(edit) => {
3208 if !edits.contains(&edit.text_edit) {
3209 edits.push(edit.text_edit)
3210 }
3211 }
3212 Edit::Snippet(edit) => {
3213 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3214 else {
3215 continue;
3216 };
3217
3218 if is_active_entry {
3219 snippet_edits.push((edit.range, snippet));
3220 } else {
3221 // Since this buffer is not focused, apply a normal edit.
3222 let new_edit = TextEdit {
3223 range: edit.range,
3224 new_text: snippet.text,
3225 };
3226 if !edits.contains(&new_edit) {
3227 edits.push(new_edit);
3228 }
3229 }
3230 }
3231 }
3232 }
3233 if !snippet_edits.is_empty() {
3234 let buffer_id = buffer_to_edit.read(cx).remote_id();
3235 let version = if let Some(buffer_version) = op.text_document.version
3236 {
3237 local
3238 .buffer_snapshot_for_lsp_version(
3239 &buffer_to_edit,
3240 language_server.server_id(),
3241 Some(buffer_version),
3242 cx,
3243 )
3244 .ok()
3245 .map(|snapshot| snapshot.version)
3246 } else {
3247 Some(buffer_to_edit.read(cx).saved_version().clone())
3248 };
3249
3250 let most_recent_edit =
3251 version.and_then(|version| version.most_recent());
3252 // Check if the edit that triggered that edit has been made by this participant.
3253
3254 if let Some(most_recent_edit) = most_recent_edit {
3255 cx.emit(LspStoreEvent::SnippetEdit {
3256 buffer_id,
3257 edits: snippet_edits,
3258 most_recent_edit,
3259 });
3260 }
3261 }
3262
3263 local.edits_from_lsp(
3264 &buffer_to_edit,
3265 edits,
3266 language_server.server_id(),
3267 op.text_document.version,
3268 cx,
3269 )
3270 })?
3271 .await?;
3272
3273 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3274 buffer.finalize_last_transaction();
3275 buffer.start_transaction();
3276 for (range, text) in edits {
3277 buffer.edit([(range, text)], None, cx);
3278 }
3279
3280 buffer.end_transaction(cx).and_then(|transaction_id| {
3281 if push_to_history {
3282 buffer.finalize_last_transaction();
3283 buffer.get_transaction(transaction_id).cloned()
3284 } else {
3285 buffer.forget_transaction(transaction_id)
3286 }
3287 })
3288 })?;
3289 if let Some(transaction) = transaction {
3290 project_transaction.0.insert(buffer_to_edit, transaction);
3291 }
3292 }
3293 }
3294 }
3295
3296 Ok(project_transaction)
3297 }
3298
3299 async fn on_lsp_workspace_edit(
3300 this: WeakEntity<LspStore>,
3301 params: lsp::ApplyWorkspaceEditParams,
3302 server_id: LanguageServerId,
3303 cx: &mut AsyncApp,
3304 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3305 let this = this.upgrade().context("project project closed")?;
3306 let language_server = this
3307 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3308 .context("language server not found")?;
3309 let transaction = Self::deserialize_workspace_edit(
3310 this.clone(),
3311 params.edit,
3312 true,
3313 language_server.clone(),
3314 cx,
3315 )
3316 .await
3317 .log_err();
3318 this.update(cx, |this, cx| {
3319 if let Some(transaction) = transaction {
3320 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3321
3322 this.as_local_mut()
3323 .unwrap()
3324 .last_workspace_edits_by_language_server
3325 .insert(server_id, transaction);
3326 }
3327 })?;
3328 Ok(lsp::ApplyWorkspaceEditResponse {
3329 applied: true,
3330 failed_change: None,
3331 failure_reason: None,
3332 })
3333 }
3334
3335 fn remove_worktree(
3336 &mut self,
3337 id_to_remove: WorktreeId,
3338 cx: &mut Context<LspStore>,
3339 ) -> Vec<LanguageServerId> {
3340 self.restricted_worktrees_tasks.remove(&id_to_remove);
3341 self.diagnostics.remove(&id_to_remove);
3342 self.prettier_store.update(cx, |prettier_store, cx| {
3343 prettier_store.remove_worktree(id_to_remove, cx);
3344 });
3345
3346 let mut servers_to_remove = BTreeSet::default();
3347 let mut servers_to_preserve = HashSet::default();
3348 for (seed, state) in &self.language_server_ids {
3349 if seed.worktree_id == id_to_remove {
3350 servers_to_remove.insert(state.id);
3351 } else {
3352 servers_to_preserve.insert(state.id);
3353 }
3354 }
3355 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3356 self.language_server_ids
3357 .retain(|_, state| !servers_to_remove.contains(&state.id));
3358 for server_id_to_remove in &servers_to_remove {
3359 self.language_server_watched_paths
3360 .remove(server_id_to_remove);
3361 self.language_server_paths_watched_for_rename
3362 .remove(server_id_to_remove);
3363 self.last_workspace_edits_by_language_server
3364 .remove(server_id_to_remove);
3365 self.language_servers.remove(server_id_to_remove);
3366 self.buffer_pull_diagnostics_result_ids
3367 .remove(server_id_to_remove);
3368 self.workspace_pull_diagnostics_result_ids
3369 .remove(server_id_to_remove);
3370 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3371 buffer_servers.remove(server_id_to_remove);
3372 }
3373 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3374 }
3375 servers_to_remove.into_iter().collect()
3376 }
3377
3378 fn rebuild_watched_paths_inner<'a>(
3379 &'a self,
3380 language_server_id: LanguageServerId,
3381 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3382 cx: &mut Context<LspStore>,
3383 ) -> LanguageServerWatchedPathsBuilder {
3384 let worktrees = self
3385 .worktree_store
3386 .read(cx)
3387 .worktrees()
3388 .filter_map(|worktree| {
3389 self.language_servers_for_worktree(worktree.read(cx).id())
3390 .find(|server| server.server_id() == language_server_id)
3391 .map(|_| worktree)
3392 })
3393 .collect::<Vec<_>>();
3394
3395 let mut worktree_globs = HashMap::default();
3396 let mut abs_globs = HashMap::default();
3397 log::trace!(
3398 "Processing new watcher paths for language server with id {}",
3399 language_server_id
3400 );
3401
3402 for watcher in watchers {
3403 if let Some((worktree, literal_prefix, pattern)) =
3404 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3405 {
3406 worktree.update(cx, |worktree, _| {
3407 if let Some((tree, glob)) =
3408 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3409 {
3410 tree.add_path_prefix_to_scan(literal_prefix);
3411 worktree_globs
3412 .entry(tree.id())
3413 .or_insert_with(GlobSetBuilder::new)
3414 .add(glob);
3415 }
3416 });
3417 } else {
3418 let (path, pattern) = match &watcher.glob_pattern {
3419 lsp::GlobPattern::String(s) => {
3420 let watcher_path = SanitizedPath::new(s);
3421 let path = glob_literal_prefix(watcher_path.as_path());
3422 let pattern = watcher_path
3423 .as_path()
3424 .strip_prefix(&path)
3425 .map(|p| p.to_string_lossy().into_owned())
3426 .unwrap_or_else(|e| {
3427 debug_panic!(
3428 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3429 s,
3430 path.display(),
3431 e
3432 );
3433 watcher_path.as_path().to_string_lossy().into_owned()
3434 });
3435 (path, pattern)
3436 }
3437 lsp::GlobPattern::Relative(rp) => {
3438 let Ok(mut base_uri) = match &rp.base_uri {
3439 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3440 lsp::OneOf::Right(base_uri) => base_uri,
3441 }
3442 .to_file_path() else {
3443 continue;
3444 };
3445
3446 let path = glob_literal_prefix(Path::new(&rp.pattern));
3447 let pattern = Path::new(&rp.pattern)
3448 .strip_prefix(&path)
3449 .map(|p| p.to_string_lossy().into_owned())
3450 .unwrap_or_else(|e| {
3451 debug_panic!(
3452 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3453 rp.pattern,
3454 path.display(),
3455 e
3456 );
3457 rp.pattern.clone()
3458 });
3459 base_uri.push(path);
3460 (base_uri, pattern)
3461 }
3462 };
3463
3464 if let Some(glob) = Glob::new(&pattern).log_err() {
3465 if !path
3466 .components()
3467 .any(|c| matches!(c, path::Component::Normal(_)))
3468 {
3469 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3470 // rather than adding a new watcher for `/`.
3471 for worktree in &worktrees {
3472 worktree_globs
3473 .entry(worktree.read(cx).id())
3474 .or_insert_with(GlobSetBuilder::new)
3475 .add(glob.clone());
3476 }
3477 } else {
3478 abs_globs
3479 .entry(path.into())
3480 .or_insert_with(GlobSetBuilder::new)
3481 .add(glob);
3482 }
3483 }
3484 }
3485 }
3486
3487 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3488 for (worktree_id, builder) in worktree_globs {
3489 if let Ok(globset) = builder.build() {
3490 watch_builder.watch_worktree(worktree_id, globset);
3491 }
3492 }
3493 for (abs_path, builder) in abs_globs {
3494 if let Ok(globset) = builder.build() {
3495 watch_builder.watch_abs_path(abs_path, globset);
3496 }
3497 }
3498 watch_builder
3499 }
3500
3501 fn worktree_and_path_for_file_watcher(
3502 worktrees: &[Entity<Worktree>],
3503 watcher: &FileSystemWatcher,
3504 cx: &App,
3505 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3506 worktrees.iter().find_map(|worktree| {
3507 let tree = worktree.read(cx);
3508 let worktree_root_path = tree.abs_path();
3509 let path_style = tree.path_style();
3510 match &watcher.glob_pattern {
3511 lsp::GlobPattern::String(s) => {
3512 let watcher_path = SanitizedPath::new(s);
3513 let relative = watcher_path
3514 .as_path()
3515 .strip_prefix(&worktree_root_path)
3516 .ok()?;
3517 let literal_prefix = glob_literal_prefix(relative);
3518 Some((
3519 worktree.clone(),
3520 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3521 relative.to_string_lossy().into_owned(),
3522 ))
3523 }
3524 lsp::GlobPattern::Relative(rp) => {
3525 let base_uri = match &rp.base_uri {
3526 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3527 lsp::OneOf::Right(base_uri) => base_uri,
3528 }
3529 .to_file_path()
3530 .ok()?;
3531 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3532 let mut literal_prefix = relative.to_owned();
3533 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3534 Some((
3535 worktree.clone(),
3536 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3537 rp.pattern.clone(),
3538 ))
3539 }
3540 }
3541 })
3542 }
3543
3544 fn rebuild_watched_paths(
3545 &mut self,
3546 language_server_id: LanguageServerId,
3547 cx: &mut Context<LspStore>,
3548 ) {
3549 let Some(registrations) = self
3550 .language_server_dynamic_registrations
3551 .get(&language_server_id)
3552 else {
3553 return;
3554 };
3555
3556 let watch_builder = self.rebuild_watched_paths_inner(
3557 language_server_id,
3558 registrations.did_change_watched_files.values().flatten(),
3559 cx,
3560 );
3561 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3562 self.language_server_watched_paths
3563 .insert(language_server_id, watcher);
3564
3565 cx.notify();
3566 }
3567
3568 fn on_lsp_did_change_watched_files(
3569 &mut self,
3570 language_server_id: LanguageServerId,
3571 registration_id: &str,
3572 params: DidChangeWatchedFilesRegistrationOptions,
3573 cx: &mut Context<LspStore>,
3574 ) {
3575 let registrations = self
3576 .language_server_dynamic_registrations
3577 .entry(language_server_id)
3578 .or_default();
3579
3580 registrations
3581 .did_change_watched_files
3582 .insert(registration_id.to_string(), params.watchers);
3583
3584 self.rebuild_watched_paths(language_server_id, cx);
3585 }
3586
3587 fn on_lsp_unregister_did_change_watched_files(
3588 &mut self,
3589 language_server_id: LanguageServerId,
3590 registration_id: &str,
3591 cx: &mut Context<LspStore>,
3592 ) {
3593 let registrations = self
3594 .language_server_dynamic_registrations
3595 .entry(language_server_id)
3596 .or_default();
3597
3598 if registrations
3599 .did_change_watched_files
3600 .remove(registration_id)
3601 .is_some()
3602 {
3603 log::info!(
3604 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3605 language_server_id,
3606 registration_id
3607 );
3608 } else {
3609 log::warn!(
3610 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3611 language_server_id,
3612 registration_id
3613 );
3614 }
3615
3616 self.rebuild_watched_paths(language_server_id, cx);
3617 }
3618
3619 async fn initialization_options_for_adapter(
3620 adapter: Arc<dyn LspAdapter>,
3621 delegate: &Arc<dyn LspAdapterDelegate>,
3622 ) -> Result<Option<serde_json::Value>> {
3623 let Some(mut initialization_config) =
3624 adapter.clone().initialization_options(delegate).await?
3625 else {
3626 return Ok(None);
3627 };
3628
3629 for other_adapter in delegate.registered_lsp_adapters() {
3630 if other_adapter.name() == adapter.name() {
3631 continue;
3632 }
3633 if let Ok(Some(target_config)) = other_adapter
3634 .clone()
3635 .additional_initialization_options(adapter.name(), delegate)
3636 .await
3637 {
3638 merge_json_value_into(target_config.clone(), &mut initialization_config);
3639 }
3640 }
3641
3642 Ok(Some(initialization_config))
3643 }
3644
3645 async fn workspace_configuration_for_adapter(
3646 adapter: Arc<dyn LspAdapter>,
3647 delegate: &Arc<dyn LspAdapterDelegate>,
3648 toolchain: Option<Toolchain>,
3649 requested_uri: Option<Uri>,
3650 cx: &mut AsyncApp,
3651 ) -> Result<serde_json::Value> {
3652 let mut workspace_config = adapter
3653 .clone()
3654 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3655 .await?;
3656
3657 for other_adapter in delegate.registered_lsp_adapters() {
3658 if other_adapter.name() == adapter.name() {
3659 continue;
3660 }
3661 if let Ok(Some(target_config)) = other_adapter
3662 .clone()
3663 .additional_workspace_configuration(adapter.name(), delegate, cx)
3664 .await
3665 {
3666 merge_json_value_into(target_config.clone(), &mut workspace_config);
3667 }
3668 }
3669
3670 Ok(workspace_config)
3671 }
3672
3673 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3674 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3675 Some(server.clone())
3676 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3677 Some(Arc::clone(server))
3678 } else {
3679 None
3680 }
3681 }
3682}
3683
3684fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3685 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3686 cx.emit(LspStoreEvent::LanguageServerUpdate {
3687 language_server_id: server.server_id(),
3688 name: Some(server.name()),
3689 message: proto::update_language_server::Variant::MetadataUpdated(
3690 proto::ServerMetadataUpdated {
3691 capabilities: Some(capabilities),
3692 binary: Some(proto::LanguageServerBinaryInfo {
3693 path: server.binary().path.to_string_lossy().into_owned(),
3694 arguments: server
3695 .binary()
3696 .arguments
3697 .iter()
3698 .map(|arg| arg.to_string_lossy().into_owned())
3699 .collect(),
3700 }),
3701 configuration: serde_json::to_string(server.configuration()).ok(),
3702 workspace_folders: server
3703 .workspace_folders()
3704 .iter()
3705 .map(|uri| uri.to_string())
3706 .collect(),
3707 },
3708 ),
3709 });
3710 }
3711}
3712
3713#[derive(Debug)]
3714pub struct FormattableBuffer {
3715 handle: Entity<Buffer>,
3716 abs_path: Option<PathBuf>,
3717 env: Option<HashMap<String, String>>,
3718 ranges: Option<Vec<Range<Anchor>>>,
3719}
3720
3721pub struct RemoteLspStore {
3722 upstream_client: Option<AnyProtoClient>,
3723 upstream_project_id: u64,
3724}
3725
3726pub(crate) enum LspStoreMode {
3727 Local(LocalLspStore), // ssh host and collab host
3728 Remote(RemoteLspStore), // collab guest
3729}
3730
3731impl LspStoreMode {
3732 fn is_local(&self) -> bool {
3733 matches!(self, LspStoreMode::Local(_))
3734 }
3735}
3736
3737pub struct LspStore {
3738 mode: LspStoreMode,
3739 last_formatting_failure: Option<String>,
3740 downstream_client: Option<(AnyProtoClient, u64)>,
3741 nonce: u128,
3742 buffer_store: Entity<BufferStore>,
3743 worktree_store: Entity<WorktreeStore>,
3744 pub languages: Arc<LanguageRegistry>,
3745 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3746 active_entry: Option<ProjectEntryId>,
3747 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3748 _maintain_buffer_languages: Task<()>,
3749 diagnostic_summaries:
3750 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3751 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3752 lsp_data: HashMap<BufferId, BufferLspData>,
3753 next_hint_id: Arc<AtomicUsize>,
3754}
3755
3756#[derive(Debug)]
3757pub struct BufferLspData {
3758 buffer_version: Global,
3759 document_colors: Option<DocumentColorData>,
3760 code_lens: Option<CodeLensData>,
3761 inlay_hints: BufferInlayHints,
3762 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3763 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3764}
3765
3766#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3767struct LspKey {
3768 request_type: TypeId,
3769 server_queried: Option<LanguageServerId>,
3770}
3771
3772impl BufferLspData {
3773 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3774 Self {
3775 buffer_version: buffer.read(cx).version(),
3776 document_colors: None,
3777 code_lens: None,
3778 inlay_hints: BufferInlayHints::new(buffer, cx),
3779 lsp_requests: HashMap::default(),
3780 chunk_lsp_requests: HashMap::default(),
3781 }
3782 }
3783
3784 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3785 if let Some(document_colors) = &mut self.document_colors {
3786 document_colors.colors.remove(&for_server);
3787 document_colors.cache_version += 1;
3788 }
3789
3790 if let Some(code_lens) = &mut self.code_lens {
3791 code_lens.lens.remove(&for_server);
3792 }
3793
3794 self.inlay_hints.remove_server_data(for_server);
3795 }
3796
3797 #[cfg(any(test, feature = "test-support"))]
3798 pub fn inlay_hints(&self) -> &BufferInlayHints {
3799 &self.inlay_hints
3800 }
3801}
3802
3803#[derive(Debug, Default, Clone)]
3804pub struct DocumentColors {
3805 pub colors: HashSet<DocumentColor>,
3806 pub cache_version: Option<usize>,
3807}
3808
3809type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3810type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3811
3812#[derive(Debug, Default)]
3813struct DocumentColorData {
3814 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3815 cache_version: usize,
3816 colors_update: Option<(Global, DocumentColorTask)>,
3817}
3818
3819#[derive(Debug, Default)]
3820struct CodeLensData {
3821 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3822 update: Option<(Global, CodeLensTask)>,
3823}
3824
3825#[derive(Debug)]
3826pub enum LspStoreEvent {
3827 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3828 LanguageServerRemoved(LanguageServerId),
3829 LanguageServerUpdate {
3830 language_server_id: LanguageServerId,
3831 name: Option<LanguageServerName>,
3832 message: proto::update_language_server::Variant,
3833 },
3834 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3835 LanguageServerPrompt(LanguageServerPromptRequest),
3836 LanguageDetected {
3837 buffer: Entity<Buffer>,
3838 new_language: Option<Arc<Language>>,
3839 },
3840 Notification(String),
3841 RefreshInlayHints {
3842 server_id: LanguageServerId,
3843 request_id: Option<usize>,
3844 },
3845 RefreshCodeLens,
3846 DiagnosticsUpdated {
3847 server_id: LanguageServerId,
3848 paths: Vec<ProjectPath>,
3849 },
3850 DiskBasedDiagnosticsStarted {
3851 language_server_id: LanguageServerId,
3852 },
3853 DiskBasedDiagnosticsFinished {
3854 language_server_id: LanguageServerId,
3855 },
3856 SnippetEdit {
3857 buffer_id: BufferId,
3858 edits: Vec<(lsp::Range, Snippet)>,
3859 most_recent_edit: clock::Lamport,
3860 },
3861 WorkspaceEditApplied(ProjectTransaction),
3862}
3863
3864#[derive(Clone, Debug, Serialize)]
3865pub struct LanguageServerStatus {
3866 pub name: LanguageServerName,
3867 pub server_version: Option<SharedString>,
3868 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3869 pub has_pending_diagnostic_updates: bool,
3870 pub progress_tokens: HashSet<ProgressToken>,
3871 pub worktree: Option<WorktreeId>,
3872 pub binary: Option<LanguageServerBinary>,
3873 pub configuration: Option<Value>,
3874 pub workspace_folders: BTreeSet<Uri>,
3875}
3876
3877#[derive(Clone, Debug)]
3878struct CoreSymbol {
3879 pub language_server_name: LanguageServerName,
3880 pub source_worktree_id: WorktreeId,
3881 pub source_language_server_id: LanguageServerId,
3882 pub path: SymbolLocation,
3883 pub name: String,
3884 pub kind: lsp::SymbolKind,
3885 pub range: Range<Unclipped<PointUtf16>>,
3886}
3887
3888#[derive(Clone, Debug, PartialEq, Eq)]
3889pub enum SymbolLocation {
3890 InProject(ProjectPath),
3891 OutsideProject {
3892 abs_path: Arc<Path>,
3893 signature: [u8; 32],
3894 },
3895}
3896
3897impl SymbolLocation {
3898 fn file_name(&self) -> Option<&str> {
3899 match self {
3900 Self::InProject(path) => path.path.file_name(),
3901 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3902 }
3903 }
3904}
3905
3906impl LspStore {
3907 pub fn init(client: &AnyProtoClient) {
3908 client.add_entity_request_handler(Self::handle_lsp_query);
3909 client.add_entity_message_handler(Self::handle_lsp_query_response);
3910 client.add_entity_request_handler(Self::handle_restart_language_servers);
3911 client.add_entity_request_handler(Self::handle_stop_language_servers);
3912 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3913 client.add_entity_message_handler(Self::handle_start_language_server);
3914 client.add_entity_message_handler(Self::handle_update_language_server);
3915 client.add_entity_message_handler(Self::handle_language_server_log);
3916 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3917 client.add_entity_request_handler(Self::handle_format_buffers);
3918 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3919 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3920 client.add_entity_request_handler(Self::handle_apply_code_action);
3921 client.add_entity_request_handler(Self::handle_get_project_symbols);
3922 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3923 client.add_entity_request_handler(Self::handle_get_color_presentation);
3924 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3925 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3926 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3927 client.add_entity_request_handler(Self::handle_on_type_formatting);
3928 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3929 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3930 client.add_entity_request_handler(Self::handle_rename_project_entry);
3931 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3932 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3933 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3934 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3935 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3936 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3937 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3938
3939 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3940 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3941 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3942 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3943 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3944 client.add_entity_request_handler(
3945 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3946 );
3947 client.add_entity_request_handler(
3948 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3949 );
3950 client.add_entity_request_handler(
3951 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3952 );
3953 }
3954
3955 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3956 match &self.mode {
3957 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3958 _ => None,
3959 }
3960 }
3961
3962 pub fn as_local(&self) -> Option<&LocalLspStore> {
3963 match &self.mode {
3964 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3965 _ => None,
3966 }
3967 }
3968
3969 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3970 match &mut self.mode {
3971 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3972 _ => None,
3973 }
3974 }
3975
3976 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3977 match &self.mode {
3978 LspStoreMode::Remote(RemoteLspStore {
3979 upstream_client: Some(upstream_client),
3980 upstream_project_id,
3981 ..
3982 }) => Some((upstream_client.clone(), *upstream_project_id)),
3983
3984 LspStoreMode::Remote(RemoteLspStore {
3985 upstream_client: None,
3986 ..
3987 }) => None,
3988 LspStoreMode::Local(_) => None,
3989 }
3990 }
3991
3992 pub fn new_local(
3993 buffer_store: Entity<BufferStore>,
3994 worktree_store: Entity<WorktreeStore>,
3995 prettier_store: Entity<PrettierStore>,
3996 toolchain_store: Entity<LocalToolchainStore>,
3997 environment: Entity<ProjectEnvironment>,
3998 manifest_tree: Entity<ManifestTree>,
3999 languages: Arc<LanguageRegistry>,
4000 http_client: Arc<dyn HttpClient>,
4001 fs: Arc<dyn Fs>,
4002 cx: &mut Context<Self>,
4003 ) -> Self {
4004 let yarn = YarnPathStore::new(fs.clone(), cx);
4005 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4006 .detach();
4007 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4008 .detach();
4009 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4010 .detach();
4011 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4012 .detach();
4013 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4014 .detach();
4015 subscribe_to_binary_statuses(&languages, cx).detach();
4016
4017 let _maintain_workspace_config = {
4018 let (sender, receiver) = watch::channel();
4019 (Self::maintain_workspace_config(receiver, cx), sender)
4020 };
4021
4022 Self {
4023 mode: LspStoreMode::Local(LocalLspStore {
4024 weak: cx.weak_entity(),
4025 worktree_store: worktree_store.clone(),
4026
4027 supplementary_language_servers: Default::default(),
4028 languages: languages.clone(),
4029 language_server_ids: Default::default(),
4030 language_servers: Default::default(),
4031 last_workspace_edits_by_language_server: Default::default(),
4032 language_server_watched_paths: Default::default(),
4033 language_server_paths_watched_for_rename: Default::default(),
4034 language_server_dynamic_registrations: Default::default(),
4035 buffers_being_formatted: Default::default(),
4036 buffer_snapshots: Default::default(),
4037 prettier_store,
4038 environment,
4039 http_client,
4040 fs,
4041 yarn,
4042 next_diagnostic_group_id: Default::default(),
4043 diagnostics: Default::default(),
4044 _subscription: cx.on_app_quit(|this, cx| {
4045 this.as_local_mut()
4046 .unwrap()
4047 .shutdown_language_servers_on_quit(cx)
4048 }),
4049 lsp_tree: LanguageServerTree::new(
4050 manifest_tree,
4051 languages.clone(),
4052 toolchain_store.clone(),
4053 ),
4054 toolchain_store,
4055 registered_buffers: HashMap::default(),
4056 buffers_opened_in_servers: HashMap::default(),
4057 buffer_pull_diagnostics_result_ids: HashMap::default(),
4058 workspace_pull_diagnostics_result_ids: HashMap::default(),
4059 restricted_worktrees_tasks: HashMap::default(),
4060 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4061 .manifest_file_names(),
4062 }),
4063 last_formatting_failure: None,
4064 downstream_client: None,
4065 buffer_store,
4066 worktree_store,
4067 languages: languages.clone(),
4068 language_server_statuses: Default::default(),
4069 nonce: StdRng::from_os_rng().random(),
4070 diagnostic_summaries: HashMap::default(),
4071 lsp_server_capabilities: HashMap::default(),
4072 lsp_data: HashMap::default(),
4073 next_hint_id: Arc::default(),
4074 active_entry: None,
4075 _maintain_workspace_config,
4076 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4077 }
4078 }
4079
4080 fn send_lsp_proto_request<R: LspCommand>(
4081 &self,
4082 buffer: Entity<Buffer>,
4083 client: AnyProtoClient,
4084 upstream_project_id: u64,
4085 request: R,
4086 cx: &mut Context<LspStore>,
4087 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4088 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4089 return Task::ready(Ok(R::Response::default()));
4090 }
4091 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4092 cx.spawn(async move |this, cx| {
4093 let response = client.request(message).await?;
4094 let this = this.upgrade().context("project dropped")?;
4095 request
4096 .response_from_proto(response, this, buffer, cx.clone())
4097 .await
4098 })
4099 }
4100
4101 pub(super) fn new_remote(
4102 buffer_store: Entity<BufferStore>,
4103 worktree_store: Entity<WorktreeStore>,
4104 languages: Arc<LanguageRegistry>,
4105 upstream_client: AnyProtoClient,
4106 project_id: u64,
4107 cx: &mut Context<Self>,
4108 ) -> Self {
4109 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4110 .detach();
4111 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4112 .detach();
4113 subscribe_to_binary_statuses(&languages, cx).detach();
4114 let _maintain_workspace_config = {
4115 let (sender, receiver) = watch::channel();
4116 (Self::maintain_workspace_config(receiver, cx), sender)
4117 };
4118 Self {
4119 mode: LspStoreMode::Remote(RemoteLspStore {
4120 upstream_client: Some(upstream_client),
4121 upstream_project_id: project_id,
4122 }),
4123 downstream_client: None,
4124 last_formatting_failure: None,
4125 buffer_store,
4126 worktree_store,
4127 languages: languages.clone(),
4128 language_server_statuses: Default::default(),
4129 nonce: StdRng::from_os_rng().random(),
4130 diagnostic_summaries: HashMap::default(),
4131 lsp_server_capabilities: HashMap::default(),
4132 next_hint_id: Arc::default(),
4133 lsp_data: HashMap::default(),
4134 active_entry: None,
4135
4136 _maintain_workspace_config,
4137 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4138 }
4139 }
4140
4141 fn on_buffer_store_event(
4142 &mut self,
4143 _: Entity<BufferStore>,
4144 event: &BufferStoreEvent,
4145 cx: &mut Context<Self>,
4146 ) {
4147 match event {
4148 BufferStoreEvent::BufferAdded(buffer) => {
4149 self.on_buffer_added(buffer, cx).log_err();
4150 }
4151 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4152 let buffer_id = buffer.read(cx).remote_id();
4153 if let Some(local) = self.as_local_mut()
4154 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4155 {
4156 local.reset_buffer(buffer, old_file, cx);
4157
4158 if local.registered_buffers.contains_key(&buffer_id) {
4159 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4160 }
4161 }
4162
4163 self.detect_language_for_buffer(buffer, cx);
4164 if let Some(local) = self.as_local_mut() {
4165 local.initialize_buffer(buffer, cx);
4166 if local.registered_buffers.contains_key(&buffer_id) {
4167 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4168 }
4169 }
4170 }
4171 _ => {}
4172 }
4173 }
4174
4175 fn on_worktree_store_event(
4176 &mut self,
4177 _: Entity<WorktreeStore>,
4178 event: &WorktreeStoreEvent,
4179 cx: &mut Context<Self>,
4180 ) {
4181 match event {
4182 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4183 if !worktree.read(cx).is_local() {
4184 return;
4185 }
4186 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4187 worktree::Event::UpdatedEntries(changes) => {
4188 this.update_local_worktree_language_servers(&worktree, changes, cx);
4189 }
4190 worktree::Event::UpdatedGitRepositories(_)
4191 | worktree::Event::DeletedEntry(_) => {}
4192 })
4193 .detach()
4194 }
4195 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4196 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4197 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4198 }
4199 WorktreeStoreEvent::WorktreeReleased(..)
4200 | WorktreeStoreEvent::WorktreeOrderChanged
4201 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4202 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4203 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4204 }
4205 }
4206
4207 fn on_prettier_store_event(
4208 &mut self,
4209 _: Entity<PrettierStore>,
4210 event: &PrettierStoreEvent,
4211 cx: &mut Context<Self>,
4212 ) {
4213 match event {
4214 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4215 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4216 }
4217 PrettierStoreEvent::LanguageServerAdded {
4218 new_server_id,
4219 name,
4220 prettier_server,
4221 } => {
4222 self.register_supplementary_language_server(
4223 *new_server_id,
4224 name.clone(),
4225 prettier_server.clone(),
4226 cx,
4227 );
4228 }
4229 }
4230 }
4231
4232 fn on_toolchain_store_event(
4233 &mut self,
4234 _: Entity<LocalToolchainStore>,
4235 event: &ToolchainStoreEvent,
4236 _: &mut Context<Self>,
4237 ) {
4238 if let ToolchainStoreEvent::ToolchainActivated = event {
4239 self.request_workspace_config_refresh()
4240 }
4241 }
4242
4243 fn request_workspace_config_refresh(&mut self) {
4244 *self._maintain_workspace_config.1.borrow_mut() = ();
4245 }
4246
4247 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4248 self.as_local().map(|local| local.prettier_store.clone())
4249 }
4250
4251 fn on_buffer_event(
4252 &mut self,
4253 buffer: Entity<Buffer>,
4254 event: &language::BufferEvent,
4255 cx: &mut Context<Self>,
4256 ) {
4257 match event {
4258 language::BufferEvent::Edited => {
4259 self.on_buffer_edited(buffer, cx);
4260 }
4261
4262 language::BufferEvent::Saved => {
4263 self.on_buffer_saved(buffer, cx);
4264 }
4265
4266 _ => {}
4267 }
4268 }
4269
4270 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4271 buffer
4272 .read(cx)
4273 .set_language_registry(self.languages.clone());
4274
4275 cx.subscribe(buffer, |this, buffer, event, cx| {
4276 this.on_buffer_event(buffer, event, cx);
4277 })
4278 .detach();
4279
4280 self.detect_language_for_buffer(buffer, cx);
4281 if let Some(local) = self.as_local_mut() {
4282 local.initialize_buffer(buffer, cx);
4283 }
4284
4285 Ok(())
4286 }
4287
4288 pub(crate) fn register_buffer_with_language_servers(
4289 &mut self,
4290 buffer: &Entity<Buffer>,
4291 only_register_servers: HashSet<LanguageServerSelector>,
4292 ignore_refcounts: bool,
4293 cx: &mut Context<Self>,
4294 ) -> OpenLspBufferHandle {
4295 let buffer_id = buffer.read(cx).remote_id();
4296 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4297 if let Some(local) = self.as_local_mut() {
4298 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4299 if !ignore_refcounts {
4300 *refcount += 1;
4301 }
4302
4303 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4304 // 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
4305 // 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
4306 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4307 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4308 return handle;
4309 };
4310 if !file.is_local() {
4311 return handle;
4312 }
4313
4314 if ignore_refcounts || *refcount == 1 {
4315 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4316 }
4317 if !ignore_refcounts {
4318 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4319 let refcount = {
4320 let local = lsp_store.as_local_mut().unwrap();
4321 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4322 debug_panic!("bad refcounting");
4323 return;
4324 };
4325
4326 *refcount -= 1;
4327 *refcount
4328 };
4329 if refcount == 0 {
4330 lsp_store.lsp_data.remove(&buffer_id);
4331 let local = lsp_store.as_local_mut().unwrap();
4332 local.registered_buffers.remove(&buffer_id);
4333
4334 local.buffers_opened_in_servers.remove(&buffer_id);
4335 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4336 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4337
4338 let buffer_abs_path = file.abs_path(cx);
4339 for (_, buffer_pull_diagnostics_result_ids) in
4340 &mut local.buffer_pull_diagnostics_result_ids
4341 {
4342 buffer_pull_diagnostics_result_ids.retain(
4343 |_, buffer_result_ids| {
4344 buffer_result_ids.remove(&buffer_abs_path);
4345 !buffer_result_ids.is_empty()
4346 },
4347 );
4348 }
4349
4350 let diagnostic_updates = local
4351 .language_servers
4352 .keys()
4353 .cloned()
4354 .map(|server_id| DocumentDiagnosticsUpdate {
4355 diagnostics: DocumentDiagnostics {
4356 document_abs_path: buffer_abs_path.clone(),
4357 version: None,
4358 diagnostics: Vec::new(),
4359 },
4360 result_id: None,
4361 registration_id: None,
4362 server_id: server_id,
4363 disk_based_sources: Cow::Borrowed(&[]),
4364 })
4365 .collect::<Vec<_>>();
4366
4367 lsp_store
4368 .merge_diagnostic_entries(
4369 diagnostic_updates,
4370 |_, diagnostic, _| {
4371 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4372 },
4373 cx,
4374 )
4375 .context("Clearing diagnostics for the closed buffer")
4376 .log_err();
4377 }
4378 }
4379 })
4380 .detach();
4381 }
4382 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4383 let buffer_id = buffer.read(cx).remote_id().to_proto();
4384 cx.background_spawn(async move {
4385 upstream_client
4386 .request(proto::RegisterBufferWithLanguageServers {
4387 project_id: upstream_project_id,
4388 buffer_id,
4389 only_servers: only_register_servers
4390 .into_iter()
4391 .map(|selector| {
4392 let selector = match selector {
4393 LanguageServerSelector::Id(language_server_id) => {
4394 proto::language_server_selector::Selector::ServerId(
4395 language_server_id.to_proto(),
4396 )
4397 }
4398 LanguageServerSelector::Name(language_server_name) => {
4399 proto::language_server_selector::Selector::Name(
4400 language_server_name.to_string(),
4401 )
4402 }
4403 };
4404 proto::LanguageServerSelector {
4405 selector: Some(selector),
4406 }
4407 })
4408 .collect(),
4409 })
4410 .await
4411 })
4412 .detach();
4413 } else {
4414 // Our remote connection got closed
4415 }
4416 handle
4417 }
4418
4419 fn maintain_buffer_languages(
4420 languages: Arc<LanguageRegistry>,
4421 cx: &mut Context<Self>,
4422 ) -> Task<()> {
4423 let mut subscription = languages.subscribe();
4424 let mut prev_reload_count = languages.reload_count();
4425 cx.spawn(async move |this, cx| {
4426 while let Some(()) = subscription.next().await {
4427 if let Some(this) = this.upgrade() {
4428 // If the language registry has been reloaded, then remove and
4429 // re-assign the languages on all open buffers.
4430 let reload_count = languages.reload_count();
4431 if reload_count > prev_reload_count {
4432 prev_reload_count = reload_count;
4433 this.update(cx, |this, cx| {
4434 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4435 for buffer in buffer_store.buffers() {
4436 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4437 {
4438 buffer.update(cx, |buffer, cx| {
4439 buffer.set_language_async(None, cx)
4440 });
4441 if let Some(local) = this.as_local_mut() {
4442 local.reset_buffer(&buffer, &f, cx);
4443
4444 if local
4445 .registered_buffers
4446 .contains_key(&buffer.read(cx).remote_id())
4447 && let Some(file_url) =
4448 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4449 {
4450 local.unregister_buffer_from_language_servers(
4451 &buffer, &file_url, cx,
4452 );
4453 }
4454 }
4455 }
4456 }
4457 });
4458 })
4459 .ok();
4460 }
4461
4462 this.update(cx, |this, cx| {
4463 let mut plain_text_buffers = Vec::new();
4464 let mut buffers_with_unknown_injections = Vec::new();
4465 for handle in this.buffer_store.read(cx).buffers() {
4466 let buffer = handle.read(cx);
4467 if buffer.language().is_none()
4468 || buffer.language() == Some(&*language::PLAIN_TEXT)
4469 {
4470 plain_text_buffers.push(handle);
4471 } else if buffer.contains_unknown_injections() {
4472 buffers_with_unknown_injections.push(handle);
4473 }
4474 }
4475
4476 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4477 // and reused later in the invisible worktrees.
4478 plain_text_buffers.sort_by_key(|buffer| {
4479 Reverse(
4480 File::from_dyn(buffer.read(cx).file())
4481 .map(|file| file.worktree.read(cx).is_visible()),
4482 )
4483 });
4484
4485 for buffer in plain_text_buffers {
4486 this.detect_language_for_buffer(&buffer, cx);
4487 if let Some(local) = this.as_local_mut() {
4488 local.initialize_buffer(&buffer, cx);
4489 if local
4490 .registered_buffers
4491 .contains_key(&buffer.read(cx).remote_id())
4492 {
4493 local.register_buffer_with_language_servers(
4494 &buffer,
4495 HashSet::default(),
4496 cx,
4497 );
4498 }
4499 }
4500 }
4501
4502 for buffer in buffers_with_unknown_injections {
4503 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4504 }
4505 })
4506 .ok();
4507 }
4508 }
4509 })
4510 }
4511
4512 fn detect_language_for_buffer(
4513 &mut self,
4514 buffer_handle: &Entity<Buffer>,
4515 cx: &mut Context<Self>,
4516 ) -> Option<language::AvailableLanguage> {
4517 // If the buffer has a language, set it and start the language server if we haven't already.
4518 let buffer = buffer_handle.read(cx);
4519 let file = buffer.file()?;
4520
4521 let content = buffer.as_rope();
4522 let available_language = self.languages.language_for_file(file, Some(content), cx);
4523 if let Some(available_language) = &available_language {
4524 if let Some(Ok(Ok(new_language))) = self
4525 .languages
4526 .load_language(available_language)
4527 .now_or_never()
4528 {
4529 self.set_language_for_buffer(buffer_handle, new_language, cx);
4530 }
4531 } else {
4532 cx.emit(LspStoreEvent::LanguageDetected {
4533 buffer: buffer_handle.clone(),
4534 new_language: None,
4535 });
4536 }
4537
4538 available_language
4539 }
4540
4541 pub(crate) fn set_language_for_buffer(
4542 &mut self,
4543 buffer_entity: &Entity<Buffer>,
4544 new_language: Arc<Language>,
4545 cx: &mut Context<Self>,
4546 ) {
4547 let buffer = buffer_entity.read(cx);
4548 let buffer_file = buffer.file().cloned();
4549 let buffer_id = buffer.remote_id();
4550 if let Some(local_store) = self.as_local_mut()
4551 && local_store.registered_buffers.contains_key(&buffer_id)
4552 && let Some(abs_path) =
4553 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4554 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4555 {
4556 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4557 }
4558 buffer_entity.update(cx, |buffer, cx| {
4559 if buffer
4560 .language()
4561 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4562 {
4563 buffer.set_language_async(Some(new_language.clone()), cx);
4564 }
4565 });
4566
4567 let settings =
4568 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4569 let buffer_file = File::from_dyn(buffer_file.as_ref());
4570
4571 let worktree_id = if let Some(file) = buffer_file {
4572 let worktree = file.worktree.clone();
4573
4574 if let Some(local) = self.as_local_mut()
4575 && local.registered_buffers.contains_key(&buffer_id)
4576 {
4577 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4578 }
4579 Some(worktree.read(cx).id())
4580 } else {
4581 None
4582 };
4583
4584 if settings.prettier.allowed
4585 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4586 {
4587 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4588 if let Some(prettier_store) = prettier_store {
4589 prettier_store.update(cx, |prettier_store, cx| {
4590 prettier_store.install_default_prettier(
4591 worktree_id,
4592 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4593 cx,
4594 )
4595 })
4596 }
4597 }
4598
4599 cx.emit(LspStoreEvent::LanguageDetected {
4600 buffer: buffer_entity.clone(),
4601 new_language: Some(new_language),
4602 })
4603 }
4604
4605 pub fn buffer_store(&self) -> Entity<BufferStore> {
4606 self.buffer_store.clone()
4607 }
4608
4609 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4610 self.active_entry = active_entry;
4611 }
4612
4613 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4614 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4615 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4616 {
4617 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4618 summaries
4619 .iter()
4620 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4621 });
4622 if let Some(summary) = summaries.next() {
4623 client
4624 .send(proto::UpdateDiagnosticSummary {
4625 project_id: downstream_project_id,
4626 worktree_id: worktree.id().to_proto(),
4627 summary: Some(summary),
4628 more_summaries: summaries.collect(),
4629 })
4630 .log_err();
4631 }
4632 }
4633 }
4634
4635 fn is_capable_for_proto_request<R>(
4636 &self,
4637 buffer: &Entity<Buffer>,
4638 request: &R,
4639 cx: &App,
4640 ) -> bool
4641 where
4642 R: LspCommand,
4643 {
4644 self.check_if_capable_for_proto_request(
4645 buffer,
4646 |capabilities| {
4647 request.check_capabilities(AdapterServerCapabilities {
4648 server_capabilities: capabilities.clone(),
4649 code_action_kinds: None,
4650 })
4651 },
4652 cx,
4653 )
4654 }
4655
4656 fn check_if_capable_for_proto_request<F>(
4657 &self,
4658 buffer: &Entity<Buffer>,
4659 check: F,
4660 cx: &App,
4661 ) -> bool
4662 where
4663 F: FnMut(&lsp::ServerCapabilities) -> bool,
4664 {
4665 let Some(language) = buffer.read(cx).language().cloned() else {
4666 return false;
4667 };
4668 let relevant_language_servers = self
4669 .languages
4670 .lsp_adapters(&language.name())
4671 .into_iter()
4672 .map(|lsp_adapter| lsp_adapter.name())
4673 .collect::<HashSet<_>>();
4674 self.language_server_statuses
4675 .iter()
4676 .filter_map(|(server_id, server_status)| {
4677 relevant_language_servers
4678 .contains(&server_status.name)
4679 .then_some(server_id)
4680 })
4681 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4682 .any(check)
4683 }
4684
4685 fn all_capable_for_proto_request<F>(
4686 &self,
4687 buffer: &Entity<Buffer>,
4688 mut check: F,
4689 cx: &App,
4690 ) -> Vec<lsp::LanguageServerId>
4691 where
4692 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4693 {
4694 let Some(language) = buffer.read(cx).language().cloned() else {
4695 return Vec::default();
4696 };
4697 let relevant_language_servers = self
4698 .languages
4699 .lsp_adapters(&language.name())
4700 .into_iter()
4701 .map(|lsp_adapter| lsp_adapter.name())
4702 .collect::<HashSet<_>>();
4703 self.language_server_statuses
4704 .iter()
4705 .filter_map(|(server_id, server_status)| {
4706 relevant_language_servers
4707 .contains(&server_status.name)
4708 .then_some((server_id, &server_status.name))
4709 })
4710 .filter_map(|(server_id, server_name)| {
4711 self.lsp_server_capabilities
4712 .get(server_id)
4713 .map(|c| (server_id, server_name, c))
4714 })
4715 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4716 .map(|(server_id, _, _)| *server_id)
4717 .collect()
4718 }
4719
4720 pub fn request_lsp<R>(
4721 &mut self,
4722 buffer: Entity<Buffer>,
4723 server: LanguageServerToQuery,
4724 request: R,
4725 cx: &mut Context<Self>,
4726 ) -> Task<Result<R::Response>>
4727 where
4728 R: LspCommand,
4729 <R::LspRequest as lsp::request::Request>::Result: Send,
4730 <R::LspRequest as lsp::request::Request>::Params: Send,
4731 {
4732 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4733 return self.send_lsp_proto_request(
4734 buffer,
4735 upstream_client,
4736 upstream_project_id,
4737 request,
4738 cx,
4739 );
4740 }
4741
4742 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4743 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4744 local
4745 .language_servers_for_buffer(buffer, cx)
4746 .find(|(_, server)| {
4747 request.check_capabilities(server.adapter_server_capabilities())
4748 })
4749 .map(|(_, server)| server.clone())
4750 }),
4751 LanguageServerToQuery::Other(id) => self
4752 .language_server_for_local_buffer(buffer, id, cx)
4753 .and_then(|(_, server)| {
4754 request
4755 .check_capabilities(server.adapter_server_capabilities())
4756 .then(|| Arc::clone(server))
4757 }),
4758 }) else {
4759 return Task::ready(Ok(Default::default()));
4760 };
4761
4762 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4763
4764 let Some(file) = file else {
4765 return Task::ready(Ok(Default::default()));
4766 };
4767
4768 let lsp_params = match request.to_lsp_params_or_response(
4769 &file.abs_path(cx),
4770 buffer.read(cx),
4771 &language_server,
4772 cx,
4773 ) {
4774 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4775 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4776 Err(err) => {
4777 let message = format!(
4778 "{} via {} failed: {}",
4779 request.display_name(),
4780 language_server.name(),
4781 err
4782 );
4783 // rust-analyzer likes to error with this when its still loading up
4784 if !message.ends_with("content modified") {
4785 log::warn!("{message}");
4786 }
4787 return Task::ready(Err(anyhow!(message)));
4788 }
4789 };
4790
4791 let status = request.status();
4792 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4793 return Task::ready(Ok(Default::default()));
4794 }
4795 cx.spawn(async move |this, cx| {
4796 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4797
4798 let id = lsp_request.id();
4799 let _cleanup = if status.is_some() {
4800 cx.update(|cx| {
4801 this.update(cx, |this, cx| {
4802 this.on_lsp_work_start(
4803 language_server.server_id(),
4804 ProgressToken::Number(id),
4805 LanguageServerProgress {
4806 is_disk_based_diagnostics_progress: false,
4807 is_cancellable: false,
4808 title: None,
4809 message: status.clone(),
4810 percentage: None,
4811 last_update_at: cx.background_executor().now(),
4812 },
4813 cx,
4814 );
4815 })
4816 })
4817 .log_err();
4818
4819 Some(defer(|| {
4820 cx.update(|cx| {
4821 this.update(cx, |this, cx| {
4822 this.on_lsp_work_end(
4823 language_server.server_id(),
4824 ProgressToken::Number(id),
4825 cx,
4826 );
4827 })
4828 })
4829 .log_err();
4830 }))
4831 } else {
4832 None
4833 };
4834
4835 let result = lsp_request.await.into_response();
4836
4837 let response = result.map_err(|err| {
4838 let message = format!(
4839 "{} via {} failed: {}",
4840 request.display_name(),
4841 language_server.name(),
4842 err
4843 );
4844 // rust-analyzer likes to error with this when its still loading up
4845 if !message.ends_with("content modified") {
4846 log::warn!("{message}");
4847 }
4848 anyhow::anyhow!(message)
4849 })?;
4850
4851 request
4852 .response_from_lsp(
4853 response,
4854 this.upgrade().context("no app context")?,
4855 buffer,
4856 language_server.server_id(),
4857 cx.clone(),
4858 )
4859 .await
4860 })
4861 }
4862
4863 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4864 let mut language_formatters_to_check = Vec::new();
4865 for buffer in self.buffer_store.read(cx).buffers() {
4866 let buffer = buffer.read(cx);
4867 let buffer_file = File::from_dyn(buffer.file());
4868 let buffer_language = buffer.language();
4869 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4870 if buffer_language.is_some() {
4871 language_formatters_to_check.push((
4872 buffer_file.map(|f| f.worktree_id(cx)),
4873 settings.into_owned(),
4874 ));
4875 }
4876 }
4877
4878 self.request_workspace_config_refresh();
4879
4880 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4881 prettier_store.update(cx, |prettier_store, cx| {
4882 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4883 })
4884 }
4885
4886 cx.notify();
4887 }
4888
4889 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4890 let buffer_store = self.buffer_store.clone();
4891 let Some(local) = self.as_local_mut() else {
4892 return;
4893 };
4894 let mut adapters = BTreeMap::default();
4895 let get_adapter = {
4896 let languages = local.languages.clone();
4897 let environment = local.environment.clone();
4898 let weak = local.weak.clone();
4899 let worktree_store = local.worktree_store.clone();
4900 let http_client = local.http_client.clone();
4901 let fs = local.fs.clone();
4902 move |worktree_id, cx: &mut App| {
4903 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4904 Some(LocalLspAdapterDelegate::new(
4905 languages.clone(),
4906 &environment,
4907 weak.clone(),
4908 &worktree,
4909 http_client.clone(),
4910 fs.clone(),
4911 cx,
4912 ))
4913 }
4914 };
4915
4916 let mut messages_to_report = Vec::new();
4917 let (new_tree, to_stop) = {
4918 let mut rebase = local.lsp_tree.rebase();
4919 let buffers = buffer_store
4920 .read(cx)
4921 .buffers()
4922 .filter_map(|buffer| {
4923 let raw_buffer = buffer.read(cx);
4924 if !local
4925 .registered_buffers
4926 .contains_key(&raw_buffer.remote_id())
4927 {
4928 return None;
4929 }
4930 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4931 let language = raw_buffer.language().cloned()?;
4932 Some((file, language, raw_buffer.remote_id()))
4933 })
4934 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4935 for (file, language, buffer_id) in buffers {
4936 let worktree_id = file.worktree_id(cx);
4937 let Some(worktree) = local
4938 .worktree_store
4939 .read(cx)
4940 .worktree_for_id(worktree_id, cx)
4941 else {
4942 continue;
4943 };
4944
4945 if let Some((_, apply)) = local.reuse_existing_language_server(
4946 rebase.server_tree(),
4947 &worktree,
4948 &language.name(),
4949 cx,
4950 ) {
4951 (apply)(rebase.server_tree());
4952 } else if let Some(lsp_delegate) = adapters
4953 .entry(worktree_id)
4954 .or_insert_with(|| get_adapter(worktree_id, cx))
4955 .clone()
4956 {
4957 let delegate =
4958 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4959 let path = file
4960 .path()
4961 .parent()
4962 .map(Arc::from)
4963 .unwrap_or_else(|| file.path().clone());
4964 let worktree_path = ProjectPath { worktree_id, path };
4965 let abs_path = file.abs_path(cx);
4966 let nodes = rebase
4967 .walk(
4968 worktree_path,
4969 language.name(),
4970 language.manifest(),
4971 delegate.clone(),
4972 cx,
4973 )
4974 .collect::<Vec<_>>();
4975 for node in nodes {
4976 let server_id = node.server_id_or_init(|disposition| {
4977 let path = &disposition.path;
4978 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4979 let key = LanguageServerSeed {
4980 worktree_id,
4981 name: disposition.server_name.clone(),
4982 settings: disposition.settings.clone(),
4983 toolchain: local.toolchain_store.read(cx).active_toolchain(
4984 path.worktree_id,
4985 &path.path,
4986 language.name(),
4987 ),
4988 };
4989 local.language_server_ids.remove(&key);
4990
4991 let server_id = local.get_or_insert_language_server(
4992 &worktree,
4993 lsp_delegate.clone(),
4994 disposition,
4995 &language.name(),
4996 cx,
4997 );
4998 if let Some(state) = local.language_servers.get(&server_id)
4999 && let Ok(uri) = uri
5000 {
5001 state.add_workspace_folder(uri);
5002 };
5003 server_id
5004 });
5005
5006 if let Some(language_server_id) = server_id {
5007 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5008 language_server_id,
5009 name: node.name(),
5010 message:
5011 proto::update_language_server::Variant::RegisteredForBuffer(
5012 proto::RegisteredForBuffer {
5013 buffer_abs_path: abs_path
5014 .to_string_lossy()
5015 .into_owned(),
5016 buffer_id: buffer_id.to_proto(),
5017 },
5018 ),
5019 });
5020 }
5021 }
5022 } else {
5023 continue;
5024 }
5025 }
5026 rebase.finish()
5027 };
5028 for message in messages_to_report {
5029 cx.emit(message);
5030 }
5031 local.lsp_tree = new_tree;
5032 for (id, _) in to_stop {
5033 self.stop_local_language_server(id, cx).detach();
5034 }
5035 }
5036
5037 pub fn apply_code_action(
5038 &self,
5039 buffer_handle: Entity<Buffer>,
5040 mut action: CodeAction,
5041 push_to_history: bool,
5042 cx: &mut Context<Self>,
5043 ) -> Task<Result<ProjectTransaction>> {
5044 if let Some((upstream_client, project_id)) = self.upstream_client() {
5045 let request = proto::ApplyCodeAction {
5046 project_id,
5047 buffer_id: buffer_handle.read(cx).remote_id().into(),
5048 action: Some(Self::serialize_code_action(&action)),
5049 };
5050 let buffer_store = self.buffer_store();
5051 cx.spawn(async move |_, cx| {
5052 let response = upstream_client
5053 .request(request)
5054 .await?
5055 .transaction
5056 .context("missing transaction")?;
5057
5058 buffer_store
5059 .update(cx, |buffer_store, cx| {
5060 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5061 })?
5062 .await
5063 })
5064 } else if self.mode.is_local() {
5065 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5066 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5067 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5068 }) else {
5069 return Task::ready(Ok(ProjectTransaction::default()));
5070 };
5071 cx.spawn(async move |this, cx| {
5072 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5073 .await
5074 .context("resolving a code action")?;
5075 if let Some(edit) = action.lsp_action.edit()
5076 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5077 return LocalLspStore::deserialize_workspace_edit(
5078 this.upgrade().context("no app present")?,
5079 edit.clone(),
5080 push_to_history,
5081
5082 lang_server.clone(),
5083 cx,
5084 )
5085 .await;
5086 }
5087
5088 if let Some(command) = action.lsp_action.command() {
5089 let server_capabilities = lang_server.capabilities();
5090 let available_commands = server_capabilities
5091 .execute_command_provider
5092 .as_ref()
5093 .map(|options| options.commands.as_slice())
5094 .unwrap_or_default();
5095 if available_commands.contains(&command.command) {
5096 this.update(cx, |this, _| {
5097 this.as_local_mut()
5098 .unwrap()
5099 .last_workspace_edits_by_language_server
5100 .remove(&lang_server.server_id());
5101 })?;
5102
5103 let _result = lang_server
5104 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5105 command: command.command.clone(),
5106 arguments: command.arguments.clone().unwrap_or_default(),
5107 ..lsp::ExecuteCommandParams::default()
5108 })
5109 .await.into_response()
5110 .context("execute command")?;
5111
5112 return this.update(cx, |this, _| {
5113 this.as_local_mut()
5114 .unwrap()
5115 .last_workspace_edits_by_language_server
5116 .remove(&lang_server.server_id())
5117 .unwrap_or_default()
5118 });
5119 } else {
5120 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5121 }
5122 }
5123
5124 Ok(ProjectTransaction::default())
5125 })
5126 } else {
5127 Task::ready(Err(anyhow!("no upstream client and not local")))
5128 }
5129 }
5130
5131 pub fn apply_code_action_kind(
5132 &mut self,
5133 buffers: HashSet<Entity<Buffer>>,
5134 kind: CodeActionKind,
5135 push_to_history: bool,
5136 cx: &mut Context<Self>,
5137 ) -> Task<anyhow::Result<ProjectTransaction>> {
5138 if self.as_local().is_some() {
5139 cx.spawn(async move |lsp_store, cx| {
5140 let buffers = buffers.into_iter().collect::<Vec<_>>();
5141 let result = LocalLspStore::execute_code_action_kind_locally(
5142 lsp_store.clone(),
5143 buffers,
5144 kind,
5145 push_to_history,
5146 cx,
5147 )
5148 .await;
5149 lsp_store.update(cx, |lsp_store, _| {
5150 lsp_store.update_last_formatting_failure(&result);
5151 })?;
5152 result
5153 })
5154 } else if let Some((client, project_id)) = self.upstream_client() {
5155 let buffer_store = self.buffer_store();
5156 cx.spawn(async move |lsp_store, cx| {
5157 let result = client
5158 .request(proto::ApplyCodeActionKind {
5159 project_id,
5160 kind: kind.as_str().to_owned(),
5161 buffer_ids: buffers
5162 .iter()
5163 .map(|buffer| {
5164 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5165 })
5166 .collect::<Result<_>>()?,
5167 })
5168 .await
5169 .and_then(|result| result.transaction.context("missing transaction"));
5170 lsp_store.update(cx, |lsp_store, _| {
5171 lsp_store.update_last_formatting_failure(&result);
5172 })?;
5173
5174 let transaction_response = result?;
5175 buffer_store
5176 .update(cx, |buffer_store, cx| {
5177 buffer_store.deserialize_project_transaction(
5178 transaction_response,
5179 push_to_history,
5180 cx,
5181 )
5182 })?
5183 .await
5184 })
5185 } else {
5186 Task::ready(Ok(ProjectTransaction::default()))
5187 }
5188 }
5189
5190 pub fn resolved_hint(
5191 &mut self,
5192 buffer_id: BufferId,
5193 id: InlayId,
5194 cx: &mut Context<Self>,
5195 ) -> Option<ResolvedHint> {
5196 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5197
5198 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5199 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5200 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5201 let (server_id, resolve_data) = match &hint.resolve_state {
5202 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5203 ResolveState::Resolving => {
5204 return Some(ResolvedHint::Resolving(
5205 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5206 ));
5207 }
5208 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5209 };
5210
5211 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5212 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5213 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5214 id,
5215 cx.spawn(async move |lsp_store, cx| {
5216 let resolved_hint = resolve_task.await;
5217 lsp_store
5218 .update(cx, |lsp_store, _| {
5219 if let Some(old_inlay_hint) = lsp_store
5220 .lsp_data
5221 .get_mut(&buffer_id)
5222 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5223 {
5224 match resolved_hint {
5225 Ok(resolved_hint) => {
5226 *old_inlay_hint = resolved_hint;
5227 }
5228 Err(e) => {
5229 old_inlay_hint.resolve_state =
5230 ResolveState::CanResolve(server_id, resolve_data);
5231 log::error!("Inlay hint resolve failed: {e:#}");
5232 }
5233 }
5234 }
5235 })
5236 .ok();
5237 })
5238 .shared(),
5239 );
5240 debug_assert!(
5241 previous_task.is_none(),
5242 "Did not change hint's resolve state after spawning its resolve"
5243 );
5244 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5245 None
5246 }
5247
5248 fn resolve_inlay_hint(
5249 &self,
5250 mut hint: InlayHint,
5251 buffer: Entity<Buffer>,
5252 server_id: LanguageServerId,
5253 cx: &mut Context<Self>,
5254 ) -> Task<anyhow::Result<InlayHint>> {
5255 if let Some((upstream_client, project_id)) = self.upstream_client() {
5256 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5257 {
5258 hint.resolve_state = ResolveState::Resolved;
5259 return Task::ready(Ok(hint));
5260 }
5261 let request = proto::ResolveInlayHint {
5262 project_id,
5263 buffer_id: buffer.read(cx).remote_id().into(),
5264 language_server_id: server_id.0 as u64,
5265 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5266 };
5267 cx.background_spawn(async move {
5268 let response = upstream_client
5269 .request(request)
5270 .await
5271 .context("inlay hints proto request")?;
5272 match response.hint {
5273 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5274 .context("inlay hints proto resolve response conversion"),
5275 None => Ok(hint),
5276 }
5277 })
5278 } else {
5279 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5280 self.language_server_for_local_buffer(buffer, server_id, cx)
5281 .map(|(_, server)| server.clone())
5282 }) else {
5283 return Task::ready(Ok(hint));
5284 };
5285 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5286 return Task::ready(Ok(hint));
5287 }
5288 let buffer_snapshot = buffer.read(cx).snapshot();
5289 cx.spawn(async move |_, cx| {
5290 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5291 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5292 );
5293 let resolved_hint = resolve_task
5294 .await
5295 .into_response()
5296 .context("inlay hint resolve LSP request")?;
5297 let resolved_hint = InlayHints::lsp_to_project_hint(
5298 resolved_hint,
5299 &buffer,
5300 server_id,
5301 ResolveState::Resolved,
5302 false,
5303 cx,
5304 )
5305 .await?;
5306 Ok(resolved_hint)
5307 })
5308 }
5309 }
5310
5311 pub fn resolve_color_presentation(
5312 &mut self,
5313 mut color: DocumentColor,
5314 buffer: Entity<Buffer>,
5315 server_id: LanguageServerId,
5316 cx: &mut Context<Self>,
5317 ) -> Task<Result<DocumentColor>> {
5318 if color.resolved {
5319 return Task::ready(Ok(color));
5320 }
5321
5322 if let Some((upstream_client, project_id)) = self.upstream_client() {
5323 let start = color.lsp_range.start;
5324 let end = color.lsp_range.end;
5325 let request = proto::GetColorPresentation {
5326 project_id,
5327 server_id: server_id.to_proto(),
5328 buffer_id: buffer.read(cx).remote_id().into(),
5329 color: Some(proto::ColorInformation {
5330 red: color.color.red,
5331 green: color.color.green,
5332 blue: color.color.blue,
5333 alpha: color.color.alpha,
5334 lsp_range_start: Some(proto::PointUtf16 {
5335 row: start.line,
5336 column: start.character,
5337 }),
5338 lsp_range_end: Some(proto::PointUtf16 {
5339 row: end.line,
5340 column: end.character,
5341 }),
5342 }),
5343 };
5344 cx.background_spawn(async move {
5345 let response = upstream_client
5346 .request(request)
5347 .await
5348 .context("color presentation proto request")?;
5349 color.resolved = true;
5350 color.color_presentations = response
5351 .presentations
5352 .into_iter()
5353 .map(|presentation| ColorPresentation {
5354 label: SharedString::from(presentation.label),
5355 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5356 additional_text_edits: presentation
5357 .additional_text_edits
5358 .into_iter()
5359 .filter_map(deserialize_lsp_edit)
5360 .collect(),
5361 })
5362 .collect();
5363 Ok(color)
5364 })
5365 } else {
5366 let path = match buffer
5367 .update(cx, |buffer, cx| {
5368 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5369 })
5370 .context("buffer with the missing path")
5371 {
5372 Ok(path) => path,
5373 Err(e) => return Task::ready(Err(e)),
5374 };
5375 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5376 self.language_server_for_local_buffer(buffer, server_id, cx)
5377 .map(|(_, server)| server.clone())
5378 }) else {
5379 return Task::ready(Ok(color));
5380 };
5381 cx.background_spawn(async move {
5382 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5383 lsp::ColorPresentationParams {
5384 text_document: make_text_document_identifier(&path)?,
5385 color: color.color,
5386 range: color.lsp_range,
5387 work_done_progress_params: Default::default(),
5388 partial_result_params: Default::default(),
5389 },
5390 );
5391 color.color_presentations = resolve_task
5392 .await
5393 .into_response()
5394 .context("color presentation resolve LSP request")?
5395 .into_iter()
5396 .map(|presentation| ColorPresentation {
5397 label: SharedString::from(presentation.label),
5398 text_edit: presentation.text_edit,
5399 additional_text_edits: presentation
5400 .additional_text_edits
5401 .unwrap_or_default(),
5402 })
5403 .collect();
5404 color.resolved = true;
5405 Ok(color)
5406 })
5407 }
5408 }
5409
5410 pub(crate) fn linked_edits(
5411 &mut self,
5412 buffer: &Entity<Buffer>,
5413 position: Anchor,
5414 cx: &mut Context<Self>,
5415 ) -> Task<Result<Vec<Range<Anchor>>>> {
5416 let snapshot = buffer.read(cx).snapshot();
5417 let scope = snapshot.language_scope_at(position);
5418 let Some(server_id) = self
5419 .as_local()
5420 .and_then(|local| {
5421 buffer.update(cx, |buffer, cx| {
5422 local
5423 .language_servers_for_buffer(buffer, cx)
5424 .filter(|(_, server)| {
5425 LinkedEditingRange::check_server_capabilities(server.capabilities())
5426 })
5427 .filter(|(adapter, _)| {
5428 scope
5429 .as_ref()
5430 .map(|scope| scope.language_allowed(&adapter.name))
5431 .unwrap_or(true)
5432 })
5433 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5434 .next()
5435 })
5436 })
5437 .or_else(|| {
5438 self.upstream_client()
5439 .is_some()
5440 .then_some(LanguageServerToQuery::FirstCapable)
5441 })
5442 .filter(|_| {
5443 maybe!({
5444 let language = buffer.read(cx).language_at(position)?;
5445 Some(
5446 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5447 .linked_edits,
5448 )
5449 }) == Some(true)
5450 })
5451 else {
5452 return Task::ready(Ok(Vec::new()));
5453 };
5454
5455 self.request_lsp(
5456 buffer.clone(),
5457 server_id,
5458 LinkedEditingRange { position },
5459 cx,
5460 )
5461 }
5462
5463 fn apply_on_type_formatting(
5464 &mut self,
5465 buffer: Entity<Buffer>,
5466 position: Anchor,
5467 trigger: String,
5468 cx: &mut Context<Self>,
5469 ) -> Task<Result<Option<Transaction>>> {
5470 if let Some((client, project_id)) = self.upstream_client() {
5471 if !self.check_if_capable_for_proto_request(
5472 &buffer,
5473 |capabilities| {
5474 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5475 },
5476 cx,
5477 ) {
5478 return Task::ready(Ok(None));
5479 }
5480 let request = proto::OnTypeFormatting {
5481 project_id,
5482 buffer_id: buffer.read(cx).remote_id().into(),
5483 position: Some(serialize_anchor(&position)),
5484 trigger,
5485 version: serialize_version(&buffer.read(cx).version()),
5486 };
5487 cx.background_spawn(async move {
5488 client
5489 .request(request)
5490 .await?
5491 .transaction
5492 .map(language::proto::deserialize_transaction)
5493 .transpose()
5494 })
5495 } else if let Some(local) = self.as_local_mut() {
5496 let buffer_id = buffer.read(cx).remote_id();
5497 local.buffers_being_formatted.insert(buffer_id);
5498 cx.spawn(async move |this, cx| {
5499 let _cleanup = defer({
5500 let this = this.clone();
5501 let mut cx = cx.clone();
5502 move || {
5503 this.update(&mut cx, |this, _| {
5504 if let Some(local) = this.as_local_mut() {
5505 local.buffers_being_formatted.remove(&buffer_id);
5506 }
5507 })
5508 .ok();
5509 }
5510 });
5511
5512 buffer
5513 .update(cx, |buffer, _| {
5514 buffer.wait_for_edits(Some(position.timestamp))
5515 })?
5516 .await?;
5517 this.update(cx, |this, cx| {
5518 let position = position.to_point_utf16(buffer.read(cx));
5519 this.on_type_format(buffer, position, trigger, false, cx)
5520 })?
5521 .await
5522 })
5523 } else {
5524 Task::ready(Err(anyhow!("No upstream client or local language server")))
5525 }
5526 }
5527
5528 pub fn on_type_format<T: ToPointUtf16>(
5529 &mut self,
5530 buffer: Entity<Buffer>,
5531 position: T,
5532 trigger: String,
5533 push_to_history: bool,
5534 cx: &mut Context<Self>,
5535 ) -> Task<Result<Option<Transaction>>> {
5536 let position = position.to_point_utf16(buffer.read(cx));
5537 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5538 }
5539
5540 fn on_type_format_impl(
5541 &mut self,
5542 buffer: Entity<Buffer>,
5543 position: PointUtf16,
5544 trigger: String,
5545 push_to_history: bool,
5546 cx: &mut Context<Self>,
5547 ) -> Task<Result<Option<Transaction>>> {
5548 let options = buffer.update(cx, |buffer, cx| {
5549 lsp_command::lsp_formatting_options(
5550 language_settings(
5551 buffer.language_at(position).map(|l| l.name()),
5552 buffer.file(),
5553 cx,
5554 )
5555 .as_ref(),
5556 )
5557 });
5558
5559 cx.spawn(async move |this, cx| {
5560 if let Some(waiter) =
5561 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5562 {
5563 waiter.await?;
5564 }
5565 cx.update(|cx| {
5566 this.update(cx, |this, cx| {
5567 this.request_lsp(
5568 buffer.clone(),
5569 LanguageServerToQuery::FirstCapable,
5570 OnTypeFormatting {
5571 position,
5572 trigger,
5573 options,
5574 push_to_history,
5575 },
5576 cx,
5577 )
5578 })
5579 })??
5580 .await
5581 })
5582 }
5583
5584 pub fn definitions(
5585 &mut self,
5586 buffer: &Entity<Buffer>,
5587 position: PointUtf16,
5588 cx: &mut Context<Self>,
5589 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5590 if let Some((upstream_client, project_id)) = self.upstream_client() {
5591 let request = GetDefinitions { position };
5592 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5593 return Task::ready(Ok(None));
5594 }
5595 let request_task = upstream_client.request_lsp(
5596 project_id,
5597 None,
5598 LSP_REQUEST_TIMEOUT,
5599 cx.background_executor().clone(),
5600 request.to_proto(project_id, buffer.read(cx)),
5601 );
5602 let buffer = buffer.clone();
5603 cx.spawn(async move |weak_lsp_store, cx| {
5604 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5605 return Ok(None);
5606 };
5607 let Some(responses) = request_task.await? else {
5608 return Ok(None);
5609 };
5610 let actions = join_all(responses.payload.into_iter().map(|response| {
5611 GetDefinitions { position }.response_from_proto(
5612 response.response,
5613 lsp_store.clone(),
5614 buffer.clone(),
5615 cx.clone(),
5616 )
5617 }))
5618 .await;
5619
5620 Ok(Some(
5621 actions
5622 .into_iter()
5623 .collect::<Result<Vec<Vec<_>>>>()?
5624 .into_iter()
5625 .flatten()
5626 .dedup()
5627 .collect(),
5628 ))
5629 })
5630 } else {
5631 let definitions_task = self.request_multiple_lsp_locally(
5632 buffer,
5633 Some(position),
5634 GetDefinitions { position },
5635 cx,
5636 );
5637 cx.background_spawn(async move {
5638 Ok(Some(
5639 definitions_task
5640 .await
5641 .into_iter()
5642 .flat_map(|(_, definitions)| definitions)
5643 .dedup()
5644 .collect(),
5645 ))
5646 })
5647 }
5648 }
5649
5650 pub fn declarations(
5651 &mut self,
5652 buffer: &Entity<Buffer>,
5653 position: PointUtf16,
5654 cx: &mut Context<Self>,
5655 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5656 if let Some((upstream_client, project_id)) = self.upstream_client() {
5657 let request = GetDeclarations { position };
5658 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5659 return Task::ready(Ok(None));
5660 }
5661 let request_task = upstream_client.request_lsp(
5662 project_id,
5663 None,
5664 LSP_REQUEST_TIMEOUT,
5665 cx.background_executor().clone(),
5666 request.to_proto(project_id, buffer.read(cx)),
5667 );
5668 let buffer = buffer.clone();
5669 cx.spawn(async move |weak_lsp_store, cx| {
5670 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5671 return Ok(None);
5672 };
5673 let Some(responses) = request_task.await? else {
5674 return Ok(None);
5675 };
5676 let actions = join_all(responses.payload.into_iter().map(|response| {
5677 GetDeclarations { position }.response_from_proto(
5678 response.response,
5679 lsp_store.clone(),
5680 buffer.clone(),
5681 cx.clone(),
5682 )
5683 }))
5684 .await;
5685
5686 Ok(Some(
5687 actions
5688 .into_iter()
5689 .collect::<Result<Vec<Vec<_>>>>()?
5690 .into_iter()
5691 .flatten()
5692 .dedup()
5693 .collect(),
5694 ))
5695 })
5696 } else {
5697 let declarations_task = self.request_multiple_lsp_locally(
5698 buffer,
5699 Some(position),
5700 GetDeclarations { position },
5701 cx,
5702 );
5703 cx.background_spawn(async move {
5704 Ok(Some(
5705 declarations_task
5706 .await
5707 .into_iter()
5708 .flat_map(|(_, declarations)| declarations)
5709 .dedup()
5710 .collect(),
5711 ))
5712 })
5713 }
5714 }
5715
5716 pub fn type_definitions(
5717 &mut self,
5718 buffer: &Entity<Buffer>,
5719 position: PointUtf16,
5720 cx: &mut Context<Self>,
5721 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5722 if let Some((upstream_client, project_id)) = self.upstream_client() {
5723 let request = GetTypeDefinitions { position };
5724 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5725 return Task::ready(Ok(None));
5726 }
5727 let request_task = upstream_client.request_lsp(
5728 project_id,
5729 None,
5730 LSP_REQUEST_TIMEOUT,
5731 cx.background_executor().clone(),
5732 request.to_proto(project_id, buffer.read(cx)),
5733 );
5734 let buffer = buffer.clone();
5735 cx.spawn(async move |weak_lsp_store, cx| {
5736 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5737 return Ok(None);
5738 };
5739 let Some(responses) = request_task.await? else {
5740 return Ok(None);
5741 };
5742 let actions = join_all(responses.payload.into_iter().map(|response| {
5743 GetTypeDefinitions { position }.response_from_proto(
5744 response.response,
5745 lsp_store.clone(),
5746 buffer.clone(),
5747 cx.clone(),
5748 )
5749 }))
5750 .await;
5751
5752 Ok(Some(
5753 actions
5754 .into_iter()
5755 .collect::<Result<Vec<Vec<_>>>>()?
5756 .into_iter()
5757 .flatten()
5758 .dedup()
5759 .collect(),
5760 ))
5761 })
5762 } else {
5763 let type_definitions_task = self.request_multiple_lsp_locally(
5764 buffer,
5765 Some(position),
5766 GetTypeDefinitions { position },
5767 cx,
5768 );
5769 cx.background_spawn(async move {
5770 Ok(Some(
5771 type_definitions_task
5772 .await
5773 .into_iter()
5774 .flat_map(|(_, type_definitions)| type_definitions)
5775 .dedup()
5776 .collect(),
5777 ))
5778 })
5779 }
5780 }
5781
5782 pub fn implementations(
5783 &mut self,
5784 buffer: &Entity<Buffer>,
5785 position: PointUtf16,
5786 cx: &mut Context<Self>,
5787 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5788 if let Some((upstream_client, project_id)) = self.upstream_client() {
5789 let request = GetImplementations { position };
5790 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5791 return Task::ready(Ok(None));
5792 }
5793 let request_task = upstream_client.request_lsp(
5794 project_id,
5795 None,
5796 LSP_REQUEST_TIMEOUT,
5797 cx.background_executor().clone(),
5798 request.to_proto(project_id, buffer.read(cx)),
5799 );
5800 let buffer = buffer.clone();
5801 cx.spawn(async move |weak_lsp_store, cx| {
5802 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5803 return Ok(None);
5804 };
5805 let Some(responses) = request_task.await? else {
5806 return Ok(None);
5807 };
5808 let actions = join_all(responses.payload.into_iter().map(|response| {
5809 GetImplementations { position }.response_from_proto(
5810 response.response,
5811 lsp_store.clone(),
5812 buffer.clone(),
5813 cx.clone(),
5814 )
5815 }))
5816 .await;
5817
5818 Ok(Some(
5819 actions
5820 .into_iter()
5821 .collect::<Result<Vec<Vec<_>>>>()?
5822 .into_iter()
5823 .flatten()
5824 .dedup()
5825 .collect(),
5826 ))
5827 })
5828 } else {
5829 let implementations_task = self.request_multiple_lsp_locally(
5830 buffer,
5831 Some(position),
5832 GetImplementations { position },
5833 cx,
5834 );
5835 cx.background_spawn(async move {
5836 Ok(Some(
5837 implementations_task
5838 .await
5839 .into_iter()
5840 .flat_map(|(_, implementations)| implementations)
5841 .dedup()
5842 .collect(),
5843 ))
5844 })
5845 }
5846 }
5847
5848 pub fn references(
5849 &mut self,
5850 buffer: &Entity<Buffer>,
5851 position: PointUtf16,
5852 cx: &mut Context<Self>,
5853 ) -> Task<Result<Option<Vec<Location>>>> {
5854 if let Some((upstream_client, project_id)) = self.upstream_client() {
5855 let request = GetReferences { position };
5856 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5857 return Task::ready(Ok(None));
5858 }
5859
5860 let request_task = upstream_client.request_lsp(
5861 project_id,
5862 None,
5863 LSP_REQUEST_TIMEOUT,
5864 cx.background_executor().clone(),
5865 request.to_proto(project_id, buffer.read(cx)),
5866 );
5867 let buffer = buffer.clone();
5868 cx.spawn(async move |weak_lsp_store, cx| {
5869 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5870 return Ok(None);
5871 };
5872 let Some(responses) = request_task.await? else {
5873 return Ok(None);
5874 };
5875
5876 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5877 GetReferences { position }.response_from_proto(
5878 lsp_response.response,
5879 lsp_store.clone(),
5880 buffer.clone(),
5881 cx.clone(),
5882 )
5883 }))
5884 .await
5885 .into_iter()
5886 .collect::<Result<Vec<Vec<_>>>>()?
5887 .into_iter()
5888 .flatten()
5889 .dedup()
5890 .collect();
5891 Ok(Some(locations))
5892 })
5893 } else {
5894 let references_task = self.request_multiple_lsp_locally(
5895 buffer,
5896 Some(position),
5897 GetReferences { position },
5898 cx,
5899 );
5900 cx.background_spawn(async move {
5901 Ok(Some(
5902 references_task
5903 .await
5904 .into_iter()
5905 .flat_map(|(_, references)| references)
5906 .dedup()
5907 .collect(),
5908 ))
5909 })
5910 }
5911 }
5912
5913 pub fn code_actions(
5914 &mut self,
5915 buffer: &Entity<Buffer>,
5916 range: Range<Anchor>,
5917 kinds: Option<Vec<CodeActionKind>>,
5918 cx: &mut Context<Self>,
5919 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5920 if let Some((upstream_client, project_id)) = self.upstream_client() {
5921 let request = GetCodeActions {
5922 range: range.clone(),
5923 kinds: kinds.clone(),
5924 };
5925 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5926 return Task::ready(Ok(None));
5927 }
5928 let request_task = upstream_client.request_lsp(
5929 project_id,
5930 None,
5931 LSP_REQUEST_TIMEOUT,
5932 cx.background_executor().clone(),
5933 request.to_proto(project_id, buffer.read(cx)),
5934 );
5935 let buffer = buffer.clone();
5936 cx.spawn(async move |weak_lsp_store, cx| {
5937 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5938 return Ok(None);
5939 };
5940 let Some(responses) = request_task.await? else {
5941 return Ok(None);
5942 };
5943 let actions = join_all(responses.payload.into_iter().map(|response| {
5944 GetCodeActions {
5945 range: range.clone(),
5946 kinds: kinds.clone(),
5947 }
5948 .response_from_proto(
5949 response.response,
5950 lsp_store.clone(),
5951 buffer.clone(),
5952 cx.clone(),
5953 )
5954 }))
5955 .await;
5956
5957 Ok(Some(
5958 actions
5959 .into_iter()
5960 .collect::<Result<Vec<Vec<_>>>>()?
5961 .into_iter()
5962 .flatten()
5963 .collect(),
5964 ))
5965 })
5966 } else {
5967 let all_actions_task = self.request_multiple_lsp_locally(
5968 buffer,
5969 Some(range.start),
5970 GetCodeActions { range, kinds },
5971 cx,
5972 );
5973 cx.background_spawn(async move {
5974 Ok(Some(
5975 all_actions_task
5976 .await
5977 .into_iter()
5978 .flat_map(|(_, actions)| actions)
5979 .collect(),
5980 ))
5981 })
5982 }
5983 }
5984
5985 pub fn code_lens_actions(
5986 &mut self,
5987 buffer: &Entity<Buffer>,
5988 cx: &mut Context<Self>,
5989 ) -> CodeLensTask {
5990 let version_queried_for = buffer.read(cx).version();
5991 let buffer_id = buffer.read(cx).remote_id();
5992 let existing_servers = self.as_local().map(|local| {
5993 local
5994 .buffers_opened_in_servers
5995 .get(&buffer_id)
5996 .cloned()
5997 .unwrap_or_default()
5998 });
5999
6000 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6001 if let Some(cached_lens) = &lsp_data.code_lens {
6002 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6003 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6004 existing_servers != cached_lens.lens.keys().copied().collect()
6005 });
6006 if !has_different_servers {
6007 return Task::ready(Ok(Some(
6008 cached_lens.lens.values().flatten().cloned().collect(),
6009 )))
6010 .shared();
6011 }
6012 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6013 if !version_queried_for.changed_since(updating_for) {
6014 return running_update.clone();
6015 }
6016 }
6017 }
6018 }
6019
6020 let lens_lsp_data = self
6021 .latest_lsp_data(buffer, cx)
6022 .code_lens
6023 .get_or_insert_default();
6024 let buffer = buffer.clone();
6025 let query_version_queried_for = version_queried_for.clone();
6026 let new_task = cx
6027 .spawn(async move |lsp_store, cx| {
6028 cx.background_executor()
6029 .timer(Duration::from_millis(30))
6030 .await;
6031 let fetched_lens = lsp_store
6032 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6033 .map_err(Arc::new)?
6034 .await
6035 .context("fetching code lens")
6036 .map_err(Arc::new);
6037 let fetched_lens = match fetched_lens {
6038 Ok(fetched_lens) => fetched_lens,
6039 Err(e) => {
6040 lsp_store
6041 .update(cx, |lsp_store, _| {
6042 if let Some(lens_lsp_data) = lsp_store
6043 .lsp_data
6044 .get_mut(&buffer_id)
6045 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6046 {
6047 lens_lsp_data.update = None;
6048 }
6049 })
6050 .ok();
6051 return Err(e);
6052 }
6053 };
6054
6055 lsp_store
6056 .update(cx, |lsp_store, _| {
6057 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6058 let code_lens = lsp_data.code_lens.as_mut()?;
6059 if let Some(fetched_lens) = fetched_lens {
6060 if lsp_data.buffer_version == query_version_queried_for {
6061 code_lens.lens.extend(fetched_lens);
6062 } else if !lsp_data
6063 .buffer_version
6064 .changed_since(&query_version_queried_for)
6065 {
6066 lsp_data.buffer_version = query_version_queried_for;
6067 code_lens.lens = fetched_lens;
6068 }
6069 }
6070 code_lens.update = None;
6071 Some(code_lens.lens.values().flatten().cloned().collect())
6072 })
6073 .map_err(Arc::new)
6074 })
6075 .shared();
6076 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6077 new_task
6078 }
6079
6080 fn fetch_code_lens(
6081 &mut self,
6082 buffer: &Entity<Buffer>,
6083 cx: &mut Context<Self>,
6084 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6085 if let Some((upstream_client, project_id)) = self.upstream_client() {
6086 let request = GetCodeLens;
6087 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6088 return Task::ready(Ok(None));
6089 }
6090 let request_task = upstream_client.request_lsp(
6091 project_id,
6092 None,
6093 LSP_REQUEST_TIMEOUT,
6094 cx.background_executor().clone(),
6095 request.to_proto(project_id, buffer.read(cx)),
6096 );
6097 let buffer = buffer.clone();
6098 cx.spawn(async move |weak_lsp_store, cx| {
6099 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6100 return Ok(None);
6101 };
6102 let Some(responses) = request_task.await? else {
6103 return Ok(None);
6104 };
6105
6106 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6107 let lsp_store = lsp_store.clone();
6108 let buffer = buffer.clone();
6109 let cx = cx.clone();
6110 async move {
6111 (
6112 LanguageServerId::from_proto(response.server_id),
6113 GetCodeLens
6114 .response_from_proto(response.response, lsp_store, buffer, cx)
6115 .await,
6116 )
6117 }
6118 }))
6119 .await;
6120
6121 let mut has_errors = false;
6122 let code_lens_actions = code_lens_actions
6123 .into_iter()
6124 .filter_map(|(server_id, code_lens)| match code_lens {
6125 Ok(code_lens) => Some((server_id, code_lens)),
6126 Err(e) => {
6127 has_errors = true;
6128 log::error!("{e:#}");
6129 None
6130 }
6131 })
6132 .collect::<HashMap<_, _>>();
6133 anyhow::ensure!(
6134 !has_errors || !code_lens_actions.is_empty(),
6135 "Failed to fetch code lens"
6136 );
6137 Ok(Some(code_lens_actions))
6138 })
6139 } else {
6140 let code_lens_actions_task =
6141 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6142 cx.background_spawn(async move {
6143 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6144 })
6145 }
6146 }
6147
6148 #[inline(never)]
6149 pub fn completions(
6150 &self,
6151 buffer: &Entity<Buffer>,
6152 position: PointUtf16,
6153 context: CompletionContext,
6154 cx: &mut Context<Self>,
6155 ) -> Task<Result<Vec<CompletionResponse>>> {
6156 let language_registry = self.languages.clone();
6157
6158 if let Some((upstream_client, project_id)) = self.upstream_client() {
6159 let snapshot = buffer.read(cx).snapshot();
6160 let offset = position.to_offset(&snapshot);
6161 let scope = snapshot.language_scope_at(offset);
6162 let capable_lsps = self.all_capable_for_proto_request(
6163 buffer,
6164 |server_name, capabilities| {
6165 capabilities.completion_provider.is_some()
6166 && scope
6167 .as_ref()
6168 .map(|scope| scope.language_allowed(server_name))
6169 .unwrap_or(true)
6170 },
6171 cx,
6172 );
6173 if capable_lsps.is_empty() {
6174 return Task::ready(Ok(Vec::new()));
6175 }
6176
6177 let language = buffer.read(cx).language().cloned();
6178
6179 // In the future, we should provide project guests with the names of LSP adapters,
6180 // so that they can use the correct LSP adapter when computing labels. For now,
6181 // guests just use the first LSP adapter associated with the buffer's language.
6182 let lsp_adapter = language.as_ref().and_then(|language| {
6183 language_registry
6184 .lsp_adapters(&language.name())
6185 .first()
6186 .cloned()
6187 });
6188
6189 let buffer = buffer.clone();
6190
6191 cx.spawn(async move |this, cx| {
6192 let requests = join_all(
6193 capable_lsps
6194 .into_iter()
6195 .map(|id| {
6196 let request = GetCompletions {
6197 position,
6198 context: context.clone(),
6199 server_id: Some(id),
6200 };
6201 let buffer = buffer.clone();
6202 let language = language.clone();
6203 let lsp_adapter = lsp_adapter.clone();
6204 let upstream_client = upstream_client.clone();
6205 let response = this
6206 .update(cx, |this, cx| {
6207 this.send_lsp_proto_request(
6208 buffer,
6209 upstream_client,
6210 project_id,
6211 request,
6212 cx,
6213 )
6214 })
6215 .log_err();
6216 async move {
6217 let response = response?.await.log_err()?;
6218
6219 let completions = populate_labels_for_completions(
6220 response.completions,
6221 language,
6222 lsp_adapter,
6223 )
6224 .await;
6225
6226 Some(CompletionResponse {
6227 completions,
6228 display_options: CompletionDisplayOptions::default(),
6229 is_incomplete: response.is_incomplete,
6230 })
6231 }
6232 })
6233 .collect::<Vec<_>>(),
6234 );
6235 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6236 })
6237 } else if let Some(local) = self.as_local() {
6238 let snapshot = buffer.read(cx).snapshot();
6239 let offset = position.to_offset(&snapshot);
6240 let scope = snapshot.language_scope_at(offset);
6241 let language = snapshot.language().cloned();
6242 let completion_settings = language_settings(
6243 language.as_ref().map(|language| language.name()),
6244 buffer.read(cx).file(),
6245 cx,
6246 )
6247 .completions
6248 .clone();
6249 if !completion_settings.lsp {
6250 return Task::ready(Ok(Vec::new()));
6251 }
6252
6253 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6254 local
6255 .language_servers_for_buffer(buffer, cx)
6256 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6257 .filter(|(adapter, _)| {
6258 scope
6259 .as_ref()
6260 .map(|scope| scope.language_allowed(&adapter.name))
6261 .unwrap_or(true)
6262 })
6263 .map(|(_, server)| server.server_id())
6264 .collect()
6265 });
6266
6267 let buffer = buffer.clone();
6268 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6269 let lsp_timeout = if lsp_timeout > 0 {
6270 Some(Duration::from_millis(lsp_timeout))
6271 } else {
6272 None
6273 };
6274 cx.spawn(async move |this, cx| {
6275 let mut tasks = Vec::with_capacity(server_ids.len());
6276 this.update(cx, |lsp_store, cx| {
6277 for server_id in server_ids {
6278 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6279 let lsp_timeout = lsp_timeout
6280 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6281 let mut timeout = cx.background_spawn(async move {
6282 match lsp_timeout {
6283 Some(lsp_timeout) => {
6284 lsp_timeout.await;
6285 true
6286 },
6287 None => false,
6288 }
6289 }).fuse();
6290 let mut lsp_request = lsp_store.request_lsp(
6291 buffer.clone(),
6292 LanguageServerToQuery::Other(server_id),
6293 GetCompletions {
6294 position,
6295 context: context.clone(),
6296 server_id: Some(server_id),
6297 },
6298 cx,
6299 ).fuse();
6300 let new_task = cx.background_spawn(async move {
6301 select_biased! {
6302 response = lsp_request => anyhow::Ok(Some(response?)),
6303 timeout_happened = timeout => {
6304 if timeout_happened {
6305 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6306 Ok(None)
6307 } else {
6308 let completions = lsp_request.await?;
6309 Ok(Some(completions))
6310 }
6311 },
6312 }
6313 });
6314 tasks.push((lsp_adapter, new_task));
6315 }
6316 })?;
6317
6318 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6319 let completion_response = task.await.ok()??;
6320 let completions = populate_labels_for_completions(
6321 completion_response.completions,
6322 language.clone(),
6323 lsp_adapter,
6324 )
6325 .await;
6326 Some(CompletionResponse {
6327 completions,
6328 display_options: CompletionDisplayOptions::default(),
6329 is_incomplete: completion_response.is_incomplete,
6330 })
6331 });
6332
6333 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6334
6335 Ok(responses.into_iter().flatten().collect())
6336 })
6337 } else {
6338 Task::ready(Err(anyhow!("No upstream client or local language server")))
6339 }
6340 }
6341
6342 pub fn resolve_completions(
6343 &self,
6344 buffer: Entity<Buffer>,
6345 completion_indices: Vec<usize>,
6346 completions: Rc<RefCell<Box<[Completion]>>>,
6347 cx: &mut Context<Self>,
6348 ) -> Task<Result<bool>> {
6349 let client = self.upstream_client();
6350 let buffer_id = buffer.read(cx).remote_id();
6351 let buffer_snapshot = buffer.read(cx).snapshot();
6352
6353 if !self.check_if_capable_for_proto_request(
6354 &buffer,
6355 GetCompletions::can_resolve_completions,
6356 cx,
6357 ) {
6358 return Task::ready(Ok(false));
6359 }
6360 cx.spawn(async move |lsp_store, cx| {
6361 let mut did_resolve = false;
6362 if let Some((client, project_id)) = client {
6363 for completion_index in completion_indices {
6364 let server_id = {
6365 let completion = &completions.borrow()[completion_index];
6366 completion.source.server_id()
6367 };
6368 if let Some(server_id) = server_id {
6369 if Self::resolve_completion_remote(
6370 project_id,
6371 server_id,
6372 buffer_id,
6373 completions.clone(),
6374 completion_index,
6375 client.clone(),
6376 )
6377 .await
6378 .log_err()
6379 .is_some()
6380 {
6381 did_resolve = true;
6382 }
6383 } else {
6384 resolve_word_completion(
6385 &buffer_snapshot,
6386 &mut completions.borrow_mut()[completion_index],
6387 );
6388 }
6389 }
6390 } else {
6391 for completion_index in completion_indices {
6392 let server_id = {
6393 let completion = &completions.borrow()[completion_index];
6394 completion.source.server_id()
6395 };
6396 if let Some(server_id) = server_id {
6397 let server_and_adapter = lsp_store
6398 .read_with(cx, |lsp_store, _| {
6399 let server = lsp_store.language_server_for_id(server_id)?;
6400 let adapter =
6401 lsp_store.language_server_adapter_for_id(server.server_id())?;
6402 Some((server, adapter))
6403 })
6404 .ok()
6405 .flatten();
6406 let Some((server, adapter)) = server_and_adapter else {
6407 continue;
6408 };
6409
6410 let resolved = Self::resolve_completion_local(
6411 server,
6412 completions.clone(),
6413 completion_index,
6414 )
6415 .await
6416 .log_err()
6417 .is_some();
6418 if resolved {
6419 Self::regenerate_completion_labels(
6420 adapter,
6421 &buffer_snapshot,
6422 completions.clone(),
6423 completion_index,
6424 )
6425 .await
6426 .log_err();
6427 did_resolve = true;
6428 }
6429 } else {
6430 resolve_word_completion(
6431 &buffer_snapshot,
6432 &mut completions.borrow_mut()[completion_index],
6433 );
6434 }
6435 }
6436 }
6437
6438 Ok(did_resolve)
6439 })
6440 }
6441
6442 async fn resolve_completion_local(
6443 server: Arc<lsp::LanguageServer>,
6444 completions: Rc<RefCell<Box<[Completion]>>>,
6445 completion_index: usize,
6446 ) -> Result<()> {
6447 let server_id = server.server_id();
6448 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6449 return Ok(());
6450 }
6451
6452 let request = {
6453 let completion = &completions.borrow()[completion_index];
6454 match &completion.source {
6455 CompletionSource::Lsp {
6456 lsp_completion,
6457 resolved,
6458 server_id: completion_server_id,
6459 ..
6460 } => {
6461 if *resolved {
6462 return Ok(());
6463 }
6464 anyhow::ensure!(
6465 server_id == *completion_server_id,
6466 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6467 );
6468 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6469 }
6470 CompletionSource::BufferWord { .. }
6471 | CompletionSource::Dap { .. }
6472 | CompletionSource::Custom => {
6473 return Ok(());
6474 }
6475 }
6476 };
6477 let resolved_completion = request
6478 .await
6479 .into_response()
6480 .context("resolve completion")?;
6481
6482 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6483 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6484
6485 let mut completions = completions.borrow_mut();
6486 let completion = &mut completions[completion_index];
6487 if let CompletionSource::Lsp {
6488 lsp_completion,
6489 resolved,
6490 server_id: completion_server_id,
6491 ..
6492 } = &mut completion.source
6493 {
6494 if *resolved {
6495 return Ok(());
6496 }
6497 anyhow::ensure!(
6498 server_id == *completion_server_id,
6499 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6500 );
6501 **lsp_completion = resolved_completion;
6502 *resolved = true;
6503 }
6504 Ok(())
6505 }
6506
6507 async fn regenerate_completion_labels(
6508 adapter: Arc<CachedLspAdapter>,
6509 snapshot: &BufferSnapshot,
6510 completions: Rc<RefCell<Box<[Completion]>>>,
6511 completion_index: usize,
6512 ) -> Result<()> {
6513 let completion_item = completions.borrow()[completion_index]
6514 .source
6515 .lsp_completion(true)
6516 .map(Cow::into_owned);
6517 if let Some(lsp_documentation) = completion_item
6518 .as_ref()
6519 .and_then(|completion_item| completion_item.documentation.clone())
6520 {
6521 let mut completions = completions.borrow_mut();
6522 let completion = &mut completions[completion_index];
6523 completion.documentation = Some(lsp_documentation.into());
6524 } else {
6525 let mut completions = completions.borrow_mut();
6526 let completion = &mut completions[completion_index];
6527 completion.documentation = Some(CompletionDocumentation::Undocumented);
6528 }
6529
6530 let mut new_label = match completion_item {
6531 Some(completion_item) => {
6532 // NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
6533 // So we have to update the label here anyway...
6534 let language = snapshot.language();
6535 match language {
6536 Some(language) => {
6537 adapter
6538 .labels_for_completions(
6539 std::slice::from_ref(&completion_item),
6540 language,
6541 )
6542 .await?
6543 }
6544 None => Vec::new(),
6545 }
6546 .pop()
6547 .flatten()
6548 .unwrap_or_else(|| {
6549 CodeLabel::fallback_for_completion(
6550 &completion_item,
6551 language.map(|language| language.as_ref()),
6552 )
6553 })
6554 }
6555 None => CodeLabel::plain(
6556 completions.borrow()[completion_index].new_text.clone(),
6557 None,
6558 ),
6559 };
6560 ensure_uniform_list_compatible_label(&mut new_label);
6561
6562 let mut completions = completions.borrow_mut();
6563 let completion = &mut completions[completion_index];
6564 if completion.label.filter_text() == new_label.filter_text() {
6565 completion.label = new_label;
6566 } else {
6567 log::error!(
6568 "Resolved completion changed display label from {} to {}. \
6569 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6570 completion.label.text(),
6571 new_label.text(),
6572 completion.label.filter_text(),
6573 new_label.filter_text()
6574 );
6575 }
6576
6577 Ok(())
6578 }
6579
6580 async fn resolve_completion_remote(
6581 project_id: u64,
6582 server_id: LanguageServerId,
6583 buffer_id: BufferId,
6584 completions: Rc<RefCell<Box<[Completion]>>>,
6585 completion_index: usize,
6586 client: AnyProtoClient,
6587 ) -> Result<()> {
6588 let lsp_completion = {
6589 let completion = &completions.borrow()[completion_index];
6590 match &completion.source {
6591 CompletionSource::Lsp {
6592 lsp_completion,
6593 resolved,
6594 server_id: completion_server_id,
6595 ..
6596 } => {
6597 anyhow::ensure!(
6598 server_id == *completion_server_id,
6599 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6600 );
6601 if *resolved {
6602 return Ok(());
6603 }
6604 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6605 }
6606 CompletionSource::Custom
6607 | CompletionSource::Dap { .. }
6608 | CompletionSource::BufferWord { .. } => {
6609 return Ok(());
6610 }
6611 }
6612 };
6613 let request = proto::ResolveCompletionDocumentation {
6614 project_id,
6615 language_server_id: server_id.0 as u64,
6616 lsp_completion,
6617 buffer_id: buffer_id.into(),
6618 };
6619
6620 let response = client
6621 .request(request)
6622 .await
6623 .context("completion documentation resolve proto request")?;
6624 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6625
6626 let documentation = if response.documentation.is_empty() {
6627 CompletionDocumentation::Undocumented
6628 } else if response.documentation_is_markdown {
6629 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6630 } else if response.documentation.lines().count() <= 1 {
6631 CompletionDocumentation::SingleLine(response.documentation.into())
6632 } else {
6633 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6634 };
6635
6636 let mut completions = completions.borrow_mut();
6637 let completion = &mut completions[completion_index];
6638 completion.documentation = Some(documentation);
6639 if let CompletionSource::Lsp {
6640 insert_range,
6641 lsp_completion,
6642 resolved,
6643 server_id: completion_server_id,
6644 lsp_defaults: _,
6645 } = &mut completion.source
6646 {
6647 let completion_insert_range = response
6648 .old_insert_start
6649 .and_then(deserialize_anchor)
6650 .zip(response.old_insert_end.and_then(deserialize_anchor));
6651 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6652
6653 if *resolved {
6654 return Ok(());
6655 }
6656 anyhow::ensure!(
6657 server_id == *completion_server_id,
6658 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6659 );
6660 **lsp_completion = resolved_lsp_completion;
6661 *resolved = true;
6662 }
6663
6664 let replace_range = response
6665 .old_replace_start
6666 .and_then(deserialize_anchor)
6667 .zip(response.old_replace_end.and_then(deserialize_anchor));
6668 if let Some((old_replace_start, old_replace_end)) = replace_range
6669 && !response.new_text.is_empty()
6670 {
6671 completion.new_text = response.new_text;
6672 completion.replace_range = old_replace_start..old_replace_end;
6673 }
6674
6675 Ok(())
6676 }
6677
6678 pub fn apply_additional_edits_for_completion(
6679 &self,
6680 buffer_handle: Entity<Buffer>,
6681 completions: Rc<RefCell<Box<[Completion]>>>,
6682 completion_index: usize,
6683 push_to_history: bool,
6684 cx: &mut Context<Self>,
6685 ) -> Task<Result<Option<Transaction>>> {
6686 if let Some((client, project_id)) = self.upstream_client() {
6687 let buffer = buffer_handle.read(cx);
6688 let buffer_id = buffer.remote_id();
6689 cx.spawn(async move |_, cx| {
6690 let request = {
6691 let completion = completions.borrow()[completion_index].clone();
6692 proto::ApplyCompletionAdditionalEdits {
6693 project_id,
6694 buffer_id: buffer_id.into(),
6695 completion: Some(Self::serialize_completion(&CoreCompletion {
6696 replace_range: completion.replace_range,
6697 new_text: completion.new_text,
6698 source: completion.source,
6699 })),
6700 }
6701 };
6702
6703 if let Some(transaction) = client.request(request).await?.transaction {
6704 let transaction = language::proto::deserialize_transaction(transaction)?;
6705 buffer_handle
6706 .update(cx, |buffer, _| {
6707 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6708 })?
6709 .await?;
6710 if push_to_history {
6711 buffer_handle.update(cx, |buffer, _| {
6712 buffer.push_transaction(transaction.clone(), Instant::now());
6713 buffer.finalize_last_transaction();
6714 })?;
6715 }
6716 Ok(Some(transaction))
6717 } else {
6718 Ok(None)
6719 }
6720 })
6721 } else {
6722 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6723 let completion = &completions.borrow()[completion_index];
6724 let server_id = completion.source.server_id()?;
6725 Some(
6726 self.language_server_for_local_buffer(buffer, server_id, cx)?
6727 .1
6728 .clone(),
6729 )
6730 }) else {
6731 return Task::ready(Ok(None));
6732 };
6733
6734 cx.spawn(async move |this, cx| {
6735 Self::resolve_completion_local(
6736 server.clone(),
6737 completions.clone(),
6738 completion_index,
6739 )
6740 .await
6741 .context("resolving completion")?;
6742 let completion = completions.borrow()[completion_index].clone();
6743 let additional_text_edits = completion
6744 .source
6745 .lsp_completion(true)
6746 .as_ref()
6747 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6748 if let Some(edits) = additional_text_edits {
6749 let edits = this
6750 .update(cx, |this, cx| {
6751 this.as_local_mut().unwrap().edits_from_lsp(
6752 &buffer_handle,
6753 edits,
6754 server.server_id(),
6755 None,
6756 cx,
6757 )
6758 })?
6759 .await?;
6760
6761 buffer_handle.update(cx, |buffer, cx| {
6762 buffer.finalize_last_transaction();
6763 buffer.start_transaction();
6764
6765 for (range, text) in edits {
6766 let primary = &completion.replace_range;
6767
6768 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6769 // and the primary completion is just an insertion (empty range), then this is likely
6770 // an auto-import scenario and should not be considered overlapping
6771 // https://github.com/zed-industries/zed/issues/26136
6772 let is_file_start_auto_import = {
6773 let snapshot = buffer.snapshot();
6774 let primary_start_point = primary.start.to_point(&snapshot);
6775 let range_start_point = range.start.to_point(&snapshot);
6776
6777 let result = primary_start_point.row == 0
6778 && primary_start_point.column == 0
6779 && range_start_point.row == 0
6780 && range_start_point.column == 0;
6781
6782 result
6783 };
6784
6785 let has_overlap = if is_file_start_auto_import {
6786 false
6787 } else {
6788 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6789 && primary.end.cmp(&range.start, buffer).is_ge();
6790 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6791 && range.end.cmp(&primary.end, buffer).is_ge();
6792 let result = start_within || end_within;
6793 result
6794 };
6795
6796 //Skip additional edits which overlap with the primary completion edit
6797 //https://github.com/zed-industries/zed/pull/1871
6798 if !has_overlap {
6799 buffer.edit([(range, text)], None, cx);
6800 }
6801 }
6802
6803 let transaction = if buffer.end_transaction(cx).is_some() {
6804 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6805 if !push_to_history {
6806 buffer.forget_transaction(transaction.id);
6807 }
6808 Some(transaction)
6809 } else {
6810 None
6811 };
6812 Ok(transaction)
6813 })?
6814 } else {
6815 Ok(None)
6816 }
6817 })
6818 }
6819 }
6820
6821 pub fn pull_diagnostics(
6822 &mut self,
6823 buffer: Entity<Buffer>,
6824 cx: &mut Context<Self>,
6825 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6826 let buffer_id = buffer.read(cx).remote_id();
6827
6828 if let Some((client, upstream_project_id)) = self.upstream_client() {
6829 let mut suitable_capabilities = None;
6830 // Are we capable for proto request?
6831 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6832 &buffer,
6833 |capabilities| {
6834 if let Some(caps) = &capabilities.diagnostic_provider {
6835 suitable_capabilities = Some(caps.clone());
6836 true
6837 } else {
6838 false
6839 }
6840 },
6841 cx,
6842 );
6843 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6844 let Some(dynamic_caps) = suitable_capabilities else {
6845 return Task::ready(Ok(None));
6846 };
6847 assert!(any_server_has_diagnostics_provider);
6848
6849 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6850 let request = GetDocumentDiagnostics {
6851 previous_result_id: None,
6852 identifier,
6853 registration_id: None,
6854 };
6855 let request_task = client.request_lsp(
6856 upstream_project_id,
6857 None,
6858 LSP_REQUEST_TIMEOUT,
6859 cx.background_executor().clone(),
6860 request.to_proto(upstream_project_id, buffer.read(cx)),
6861 );
6862 cx.background_spawn(async move {
6863 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6864 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6865 // Do not attempt to further process the dummy responses here.
6866 let _response = request_task.await?;
6867 Ok(None)
6868 })
6869 } else {
6870 let servers = buffer.update(cx, |buffer, cx| {
6871 self.running_language_servers_for_local_buffer(buffer, cx)
6872 .map(|(_, server)| server.clone())
6873 .collect::<Vec<_>>()
6874 });
6875
6876 let pull_diagnostics = servers
6877 .into_iter()
6878 .flat_map(|server| {
6879 let result = maybe!({
6880 let local = self.as_local()?;
6881 let server_id = server.server_id();
6882 let providers_with_identifiers = local
6883 .language_server_dynamic_registrations
6884 .get(&server_id)
6885 .into_iter()
6886 .flat_map(|registrations| registrations.diagnostics.clone())
6887 .collect::<Vec<_>>();
6888 Some(
6889 providers_with_identifiers
6890 .into_iter()
6891 .map(|(registration_id, dynamic_caps)| {
6892 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6893 let registration_id = registration_id.map(SharedString::from);
6894 let result_id = self.result_id_for_buffer_pull(
6895 server_id,
6896 buffer_id,
6897 ®istration_id,
6898 cx,
6899 );
6900 self.request_lsp(
6901 buffer.clone(),
6902 LanguageServerToQuery::Other(server_id),
6903 GetDocumentDiagnostics {
6904 previous_result_id: result_id,
6905 registration_id,
6906 identifier,
6907 },
6908 cx,
6909 )
6910 })
6911 .collect::<Vec<_>>(),
6912 )
6913 });
6914
6915 result.unwrap_or_default()
6916 })
6917 .collect::<Vec<_>>();
6918
6919 cx.background_spawn(async move {
6920 let mut responses = Vec::new();
6921 for diagnostics in join_all(pull_diagnostics).await {
6922 responses.extend(diagnostics?);
6923 }
6924 Ok(Some(responses))
6925 })
6926 }
6927 }
6928
6929 pub fn applicable_inlay_chunks(
6930 &mut self,
6931 buffer: &Entity<Buffer>,
6932 ranges: &[Range<text::Anchor>],
6933 cx: &mut Context<Self>,
6934 ) -> Vec<Range<BufferRow>> {
6935 let buffer_snapshot = buffer.read(cx).snapshot();
6936 let ranges = ranges
6937 .iter()
6938 .map(|range| range.to_point(&buffer_snapshot))
6939 .collect::<Vec<_>>();
6940
6941 self.latest_lsp_data(buffer, cx)
6942 .inlay_hints
6943 .applicable_chunks(ranges.as_slice())
6944 .map(|chunk| chunk.row_range())
6945 .collect()
6946 }
6947
6948 pub fn invalidate_inlay_hints<'a>(
6949 &'a mut self,
6950 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6951 ) {
6952 for buffer_id in for_buffers {
6953 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6954 lsp_data.inlay_hints.clear();
6955 }
6956 }
6957 }
6958
6959 pub fn inlay_hints(
6960 &mut self,
6961 invalidate: InvalidationStrategy,
6962 buffer: Entity<Buffer>,
6963 ranges: Vec<Range<text::Anchor>>,
6964 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6965 cx: &mut Context<Self>,
6966 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6967 let next_hint_id = self.next_hint_id.clone();
6968 let lsp_data = self.latest_lsp_data(&buffer, cx);
6969 let query_version = lsp_data.buffer_version.clone();
6970 let mut lsp_refresh_requested = false;
6971 let for_server = if let InvalidationStrategy::RefreshRequested {
6972 server_id,
6973 request_id,
6974 } = invalidate
6975 {
6976 let invalidated = lsp_data
6977 .inlay_hints
6978 .invalidate_for_server_refresh(server_id, request_id);
6979 lsp_refresh_requested = invalidated;
6980 Some(server_id)
6981 } else {
6982 None
6983 };
6984 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6985 let known_chunks = known_chunks
6986 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6987 .map(|(_, known_chunks)| known_chunks)
6988 .unwrap_or_default();
6989
6990 let buffer_snapshot = buffer.read(cx).snapshot();
6991 let ranges = ranges
6992 .iter()
6993 .map(|range| range.to_point(&buffer_snapshot))
6994 .collect::<Vec<_>>();
6995
6996 let mut hint_fetch_tasks = Vec::new();
6997 let mut cached_inlay_hints = None;
6998 let mut ranges_to_query = None;
6999 let applicable_chunks = existing_inlay_hints
7000 .applicable_chunks(ranges.as_slice())
7001 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7002 .collect::<Vec<_>>();
7003 if applicable_chunks.is_empty() {
7004 return HashMap::default();
7005 }
7006
7007 for row_chunk in applicable_chunks {
7008 match (
7009 existing_inlay_hints
7010 .cached_hints(&row_chunk)
7011 .filter(|_| !lsp_refresh_requested)
7012 .cloned(),
7013 existing_inlay_hints
7014 .fetched_hints(&row_chunk)
7015 .as_ref()
7016 .filter(|_| !lsp_refresh_requested)
7017 .cloned(),
7018 ) {
7019 (None, None) => {
7020 let chunk_range = row_chunk.anchor_range();
7021 ranges_to_query
7022 .get_or_insert_with(Vec::new)
7023 .push((row_chunk, chunk_range));
7024 }
7025 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7026 (Some(cached_hints), None) => {
7027 for (server_id, cached_hints) in cached_hints {
7028 if for_server.is_none_or(|for_server| for_server == server_id) {
7029 cached_inlay_hints
7030 .get_or_insert_with(HashMap::default)
7031 .entry(row_chunk.row_range())
7032 .or_insert_with(HashMap::default)
7033 .entry(server_id)
7034 .or_insert_with(Vec::new)
7035 .extend(cached_hints);
7036 }
7037 }
7038 }
7039 (Some(cached_hints), Some(fetched_hints)) => {
7040 hint_fetch_tasks.push((row_chunk, fetched_hints));
7041 for (server_id, cached_hints) in cached_hints {
7042 if for_server.is_none_or(|for_server| for_server == server_id) {
7043 cached_inlay_hints
7044 .get_or_insert_with(HashMap::default)
7045 .entry(row_chunk.row_range())
7046 .or_insert_with(HashMap::default)
7047 .entry(server_id)
7048 .or_insert_with(Vec::new)
7049 .extend(cached_hints);
7050 }
7051 }
7052 }
7053 }
7054 }
7055
7056 if hint_fetch_tasks.is_empty()
7057 && ranges_to_query
7058 .as_ref()
7059 .is_none_or(|ranges| ranges.is_empty())
7060 && let Some(cached_inlay_hints) = cached_inlay_hints
7061 {
7062 cached_inlay_hints
7063 .into_iter()
7064 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7065 .collect()
7066 } else {
7067 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7068 let next_hint_id = next_hint_id.clone();
7069 let buffer = buffer.clone();
7070 let query_version = query_version.clone();
7071 let new_inlay_hints = cx
7072 .spawn(async move |lsp_store, cx| {
7073 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7074 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7075 })?;
7076 new_fetch_task
7077 .await
7078 .and_then(|new_hints_by_server| {
7079 lsp_store.update(cx, |lsp_store, cx| {
7080 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7081 let update_cache = lsp_data.buffer_version == query_version;
7082 if new_hints_by_server.is_empty() {
7083 if update_cache {
7084 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7085 }
7086 HashMap::default()
7087 } else {
7088 new_hints_by_server
7089 .into_iter()
7090 .map(|(server_id, new_hints)| {
7091 let new_hints = new_hints
7092 .into_iter()
7093 .map(|new_hint| {
7094 (
7095 InlayId::Hint(next_hint_id.fetch_add(
7096 1,
7097 atomic::Ordering::AcqRel,
7098 )),
7099 new_hint,
7100 )
7101 })
7102 .collect::<Vec<_>>();
7103 if update_cache {
7104 lsp_data.inlay_hints.insert_new_hints(
7105 chunk,
7106 server_id,
7107 new_hints.clone(),
7108 );
7109 }
7110 (server_id, new_hints)
7111 })
7112 .collect()
7113 }
7114 })
7115 })
7116 .map_err(Arc::new)
7117 })
7118 .shared();
7119
7120 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7121 *fetch_task = Some(new_inlay_hints.clone());
7122 hint_fetch_tasks.push((chunk, new_inlay_hints));
7123 }
7124
7125 cached_inlay_hints
7126 .unwrap_or_default()
7127 .into_iter()
7128 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7129 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7130 (
7131 chunk.row_range(),
7132 cx.spawn(async move |_, _| {
7133 hints_fetch.await.map_err(|e| {
7134 if e.error_code() != ErrorCode::Internal {
7135 anyhow!(e.error_code())
7136 } else {
7137 anyhow!("{e:#}")
7138 }
7139 })
7140 }),
7141 )
7142 }))
7143 .collect()
7144 }
7145 }
7146
7147 fn fetch_inlay_hints(
7148 &mut self,
7149 for_server: Option<LanguageServerId>,
7150 buffer: &Entity<Buffer>,
7151 range: Range<Anchor>,
7152 cx: &mut Context<Self>,
7153 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7154 let request = InlayHints {
7155 range: range.clone(),
7156 };
7157 if let Some((upstream_client, project_id)) = self.upstream_client() {
7158 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7159 return Task::ready(Ok(HashMap::default()));
7160 }
7161 let request_task = upstream_client.request_lsp(
7162 project_id,
7163 for_server.map(|id| id.to_proto()),
7164 LSP_REQUEST_TIMEOUT,
7165 cx.background_executor().clone(),
7166 request.to_proto(project_id, buffer.read(cx)),
7167 );
7168 let buffer = buffer.clone();
7169 cx.spawn(async move |weak_lsp_store, cx| {
7170 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7171 return Ok(HashMap::default());
7172 };
7173 let Some(responses) = request_task.await? else {
7174 return Ok(HashMap::default());
7175 };
7176
7177 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7178 let lsp_store = lsp_store.clone();
7179 let buffer = buffer.clone();
7180 let cx = cx.clone();
7181 let request = request.clone();
7182 async move {
7183 (
7184 LanguageServerId::from_proto(response.server_id),
7185 request
7186 .response_from_proto(response.response, lsp_store, buffer, cx)
7187 .await,
7188 )
7189 }
7190 }))
7191 .await;
7192
7193 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7194 let mut has_errors = false;
7195 let inlay_hints = inlay_hints
7196 .into_iter()
7197 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7198 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7199 Err(e) => {
7200 has_errors = true;
7201 log::error!("{e:#}");
7202 None
7203 }
7204 })
7205 .map(|(server_id, mut new_hints)| {
7206 new_hints.retain(|hint| {
7207 hint.position.is_valid(&buffer_snapshot)
7208 && range.start.is_valid(&buffer_snapshot)
7209 && range.end.is_valid(&buffer_snapshot)
7210 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7211 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7212 });
7213 (server_id, new_hints)
7214 })
7215 .collect::<HashMap<_, _>>();
7216 anyhow::ensure!(
7217 !has_errors || !inlay_hints.is_empty(),
7218 "Failed to fetch inlay hints"
7219 );
7220 Ok(inlay_hints)
7221 })
7222 } else {
7223 let inlay_hints_task = match for_server {
7224 Some(server_id) => {
7225 let server_task = self.request_lsp(
7226 buffer.clone(),
7227 LanguageServerToQuery::Other(server_id),
7228 request,
7229 cx,
7230 );
7231 cx.background_spawn(async move {
7232 let mut responses = Vec::new();
7233 match server_task.await {
7234 Ok(response) => responses.push((server_id, response)),
7235 // rust-analyzer likes to error with this when its still loading up
7236 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7237 Err(e) => log::error!(
7238 "Error handling response for inlay hints request: {e:#}"
7239 ),
7240 }
7241 responses
7242 })
7243 }
7244 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7245 };
7246 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7247 cx.background_spawn(async move {
7248 Ok(inlay_hints_task
7249 .await
7250 .into_iter()
7251 .map(|(server_id, mut new_hints)| {
7252 new_hints.retain(|hint| {
7253 hint.position.is_valid(&buffer_snapshot)
7254 && range.start.is_valid(&buffer_snapshot)
7255 && range.end.is_valid(&buffer_snapshot)
7256 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7257 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7258 });
7259 (server_id, new_hints)
7260 })
7261 .collect())
7262 })
7263 }
7264 }
7265
7266 pub fn pull_diagnostics_for_buffer(
7267 &mut self,
7268 buffer: Entity<Buffer>,
7269 cx: &mut Context<Self>,
7270 ) -> Task<anyhow::Result<()>> {
7271 let diagnostics = self.pull_diagnostics(buffer, cx);
7272 cx.spawn(async move |lsp_store, cx| {
7273 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7274 return Ok(());
7275 };
7276 lsp_store.update(cx, |lsp_store, cx| {
7277 if lsp_store.as_local().is_none() {
7278 return;
7279 }
7280
7281 let mut unchanged_buffers = HashMap::default();
7282 let server_diagnostics_updates = diagnostics
7283 .into_iter()
7284 .filter_map(|diagnostics_set| match diagnostics_set {
7285 LspPullDiagnostics::Response {
7286 server_id,
7287 uri,
7288 diagnostics,
7289 registration_id,
7290 } => Some((server_id, uri, diagnostics, registration_id)),
7291 LspPullDiagnostics::Default => None,
7292 })
7293 .fold(
7294 HashMap::default(),
7295 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7296 let (result_id, diagnostics) = match diagnostics {
7297 PulledDiagnostics::Unchanged { result_id } => {
7298 unchanged_buffers
7299 .entry(new_registration_id.clone())
7300 .or_insert_with(HashSet::default)
7301 .insert(uri.clone());
7302 (Some(result_id), Vec::new())
7303 }
7304 PulledDiagnostics::Changed {
7305 result_id,
7306 diagnostics,
7307 } => (result_id, diagnostics),
7308 };
7309 let disk_based_sources = Cow::Owned(
7310 lsp_store
7311 .language_server_adapter_for_id(server_id)
7312 .as_ref()
7313 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7314 .unwrap_or(&[])
7315 .to_vec(),
7316 );
7317 acc.entry(server_id)
7318 .or_insert_with(HashMap::default)
7319 .entry(new_registration_id.clone())
7320 .or_insert_with(Vec::new)
7321 .push(DocumentDiagnosticsUpdate {
7322 server_id,
7323 diagnostics: lsp::PublishDiagnosticsParams {
7324 uri,
7325 diagnostics,
7326 version: None,
7327 },
7328 result_id,
7329 disk_based_sources,
7330 registration_id: new_registration_id,
7331 });
7332 acc
7333 },
7334 );
7335
7336 for diagnostic_updates in server_diagnostics_updates.into_values() {
7337 for (registration_id, diagnostic_updates) in diagnostic_updates {
7338 lsp_store
7339 .merge_lsp_diagnostics(
7340 DiagnosticSourceKind::Pulled,
7341 diagnostic_updates,
7342 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7343 DiagnosticSourceKind::Pulled => {
7344 old_diagnostic.registration_id != registration_id
7345 || unchanged_buffers
7346 .get(&old_diagnostic.registration_id)
7347 .is_some_and(|unchanged_buffers| {
7348 unchanged_buffers.contains(&document_uri)
7349 })
7350 }
7351 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7352 true
7353 }
7354 },
7355 cx,
7356 )
7357 .log_err();
7358 }
7359 }
7360 })
7361 })
7362 }
7363
7364 pub fn document_colors(
7365 &mut self,
7366 known_cache_version: Option<usize>,
7367 buffer: Entity<Buffer>,
7368 cx: &mut Context<Self>,
7369 ) -> Option<DocumentColorTask> {
7370 let version_queried_for = buffer.read(cx).version();
7371 let buffer_id = buffer.read(cx).remote_id();
7372
7373 let current_language_servers = self.as_local().map(|local| {
7374 local
7375 .buffers_opened_in_servers
7376 .get(&buffer_id)
7377 .cloned()
7378 .unwrap_or_default()
7379 });
7380
7381 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7382 if let Some(cached_colors) = &lsp_data.document_colors {
7383 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7384 let has_different_servers =
7385 current_language_servers.is_some_and(|current_language_servers| {
7386 current_language_servers
7387 != cached_colors.colors.keys().copied().collect()
7388 });
7389 if !has_different_servers {
7390 let cache_version = cached_colors.cache_version;
7391 if Some(cache_version) == known_cache_version {
7392 return None;
7393 } else {
7394 return Some(
7395 Task::ready(Ok(DocumentColors {
7396 colors: cached_colors
7397 .colors
7398 .values()
7399 .flatten()
7400 .cloned()
7401 .collect(),
7402 cache_version: Some(cache_version),
7403 }))
7404 .shared(),
7405 );
7406 }
7407 }
7408 }
7409 }
7410 }
7411
7412 let color_lsp_data = self
7413 .latest_lsp_data(&buffer, cx)
7414 .document_colors
7415 .get_or_insert_default();
7416 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7417 && !version_queried_for.changed_since(updating_for)
7418 {
7419 return Some(running_update.clone());
7420 }
7421 let buffer_version_queried_for = version_queried_for.clone();
7422 let new_task = cx
7423 .spawn(async move |lsp_store, cx| {
7424 cx.background_executor()
7425 .timer(Duration::from_millis(30))
7426 .await;
7427 let fetched_colors = lsp_store
7428 .update(cx, |lsp_store, cx| {
7429 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7430 })?
7431 .await
7432 .context("fetching document colors")
7433 .map_err(Arc::new);
7434 let fetched_colors = match fetched_colors {
7435 Ok(fetched_colors) => {
7436 if Some(true)
7437 == buffer
7438 .update(cx, |buffer, _| {
7439 buffer.version() != buffer_version_queried_for
7440 })
7441 .ok()
7442 {
7443 return Ok(DocumentColors::default());
7444 }
7445 fetched_colors
7446 }
7447 Err(e) => {
7448 lsp_store
7449 .update(cx, |lsp_store, _| {
7450 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7451 if let Some(document_colors) = &mut lsp_data.document_colors {
7452 document_colors.colors_update = None;
7453 }
7454 }
7455 })
7456 .ok();
7457 return Err(e);
7458 }
7459 };
7460
7461 lsp_store
7462 .update(cx, |lsp_store, cx| {
7463 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7464 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7465
7466 if let Some(fetched_colors) = fetched_colors {
7467 if lsp_data.buffer_version == buffer_version_queried_for {
7468 lsp_colors.colors.extend(fetched_colors);
7469 lsp_colors.cache_version += 1;
7470 } else if !lsp_data
7471 .buffer_version
7472 .changed_since(&buffer_version_queried_for)
7473 {
7474 lsp_data.buffer_version = buffer_version_queried_for;
7475 lsp_colors.colors = fetched_colors;
7476 lsp_colors.cache_version += 1;
7477 }
7478 }
7479 lsp_colors.colors_update = None;
7480 let colors = lsp_colors
7481 .colors
7482 .values()
7483 .flatten()
7484 .cloned()
7485 .collect::<HashSet<_>>();
7486 DocumentColors {
7487 colors,
7488 cache_version: Some(lsp_colors.cache_version),
7489 }
7490 })
7491 .map_err(Arc::new)
7492 })
7493 .shared();
7494 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7495 Some(new_task)
7496 }
7497
7498 fn fetch_document_colors_for_buffer(
7499 &mut self,
7500 buffer: &Entity<Buffer>,
7501 cx: &mut Context<Self>,
7502 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7503 if let Some((client, project_id)) = self.upstream_client() {
7504 let request = GetDocumentColor {};
7505 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7506 return Task::ready(Ok(None));
7507 }
7508
7509 let request_task = client.request_lsp(
7510 project_id,
7511 None,
7512 LSP_REQUEST_TIMEOUT,
7513 cx.background_executor().clone(),
7514 request.to_proto(project_id, buffer.read(cx)),
7515 );
7516 let buffer = buffer.clone();
7517 cx.spawn(async move |lsp_store, cx| {
7518 let Some(lsp_store) = lsp_store.upgrade() else {
7519 return Ok(None);
7520 };
7521 let colors = join_all(
7522 request_task
7523 .await
7524 .log_err()
7525 .flatten()
7526 .map(|response| response.payload)
7527 .unwrap_or_default()
7528 .into_iter()
7529 .map(|color_response| {
7530 let response = request.response_from_proto(
7531 color_response.response,
7532 lsp_store.clone(),
7533 buffer.clone(),
7534 cx.clone(),
7535 );
7536 async move {
7537 (
7538 LanguageServerId::from_proto(color_response.server_id),
7539 response.await.log_err().unwrap_or_default(),
7540 )
7541 }
7542 }),
7543 )
7544 .await
7545 .into_iter()
7546 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7547 acc.entry(server_id)
7548 .or_insert_with(HashSet::default)
7549 .extend(colors);
7550 acc
7551 });
7552 Ok(Some(colors))
7553 })
7554 } else {
7555 let document_colors_task =
7556 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7557 cx.background_spawn(async move {
7558 Ok(Some(
7559 document_colors_task
7560 .await
7561 .into_iter()
7562 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7563 acc.entry(server_id)
7564 .or_insert_with(HashSet::default)
7565 .extend(colors);
7566 acc
7567 })
7568 .into_iter()
7569 .collect(),
7570 ))
7571 })
7572 }
7573 }
7574
7575 pub fn signature_help<T: ToPointUtf16>(
7576 &mut self,
7577 buffer: &Entity<Buffer>,
7578 position: T,
7579 cx: &mut Context<Self>,
7580 ) -> Task<Option<Vec<SignatureHelp>>> {
7581 let position = position.to_point_utf16(buffer.read(cx));
7582
7583 if let Some((client, upstream_project_id)) = self.upstream_client() {
7584 let request = GetSignatureHelp { position };
7585 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7586 return Task::ready(None);
7587 }
7588 let request_task = client.request_lsp(
7589 upstream_project_id,
7590 None,
7591 LSP_REQUEST_TIMEOUT,
7592 cx.background_executor().clone(),
7593 request.to_proto(upstream_project_id, buffer.read(cx)),
7594 );
7595 let buffer = buffer.clone();
7596 cx.spawn(async move |weak_lsp_store, cx| {
7597 let lsp_store = weak_lsp_store.upgrade()?;
7598 let signatures = join_all(
7599 request_task
7600 .await
7601 .log_err()
7602 .flatten()
7603 .map(|response| response.payload)
7604 .unwrap_or_default()
7605 .into_iter()
7606 .map(|response| {
7607 let response = GetSignatureHelp { position }.response_from_proto(
7608 response.response,
7609 lsp_store.clone(),
7610 buffer.clone(),
7611 cx.clone(),
7612 );
7613 async move { response.await.log_err().flatten() }
7614 }),
7615 )
7616 .await
7617 .into_iter()
7618 .flatten()
7619 .collect();
7620 Some(signatures)
7621 })
7622 } else {
7623 let all_actions_task = self.request_multiple_lsp_locally(
7624 buffer,
7625 Some(position),
7626 GetSignatureHelp { position },
7627 cx,
7628 );
7629 cx.background_spawn(async move {
7630 Some(
7631 all_actions_task
7632 .await
7633 .into_iter()
7634 .flat_map(|(_, actions)| actions)
7635 .collect::<Vec<_>>(),
7636 )
7637 })
7638 }
7639 }
7640
7641 pub fn hover(
7642 &mut self,
7643 buffer: &Entity<Buffer>,
7644 position: PointUtf16,
7645 cx: &mut Context<Self>,
7646 ) -> Task<Option<Vec<Hover>>> {
7647 if let Some((client, upstream_project_id)) = self.upstream_client() {
7648 let request = GetHover { position };
7649 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7650 return Task::ready(None);
7651 }
7652 let request_task = client.request_lsp(
7653 upstream_project_id,
7654 None,
7655 LSP_REQUEST_TIMEOUT,
7656 cx.background_executor().clone(),
7657 request.to_proto(upstream_project_id, buffer.read(cx)),
7658 );
7659 let buffer = buffer.clone();
7660 cx.spawn(async move |weak_lsp_store, cx| {
7661 let lsp_store = weak_lsp_store.upgrade()?;
7662 let hovers = join_all(
7663 request_task
7664 .await
7665 .log_err()
7666 .flatten()
7667 .map(|response| response.payload)
7668 .unwrap_or_default()
7669 .into_iter()
7670 .map(|response| {
7671 let response = GetHover { position }.response_from_proto(
7672 response.response,
7673 lsp_store.clone(),
7674 buffer.clone(),
7675 cx.clone(),
7676 );
7677 async move {
7678 response
7679 .await
7680 .log_err()
7681 .flatten()
7682 .and_then(remove_empty_hover_blocks)
7683 }
7684 }),
7685 )
7686 .await
7687 .into_iter()
7688 .flatten()
7689 .collect();
7690 Some(hovers)
7691 })
7692 } else {
7693 let all_actions_task = self.request_multiple_lsp_locally(
7694 buffer,
7695 Some(position),
7696 GetHover { position },
7697 cx,
7698 );
7699 cx.background_spawn(async move {
7700 Some(
7701 all_actions_task
7702 .await
7703 .into_iter()
7704 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7705 .collect::<Vec<Hover>>(),
7706 )
7707 })
7708 }
7709 }
7710
7711 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7712 let language_registry = self.languages.clone();
7713
7714 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7715 let request = upstream_client.request(proto::GetProjectSymbols {
7716 project_id: *project_id,
7717 query: query.to_string(),
7718 });
7719 cx.foreground_executor().spawn(async move {
7720 let response = request.await?;
7721 let mut symbols = Vec::new();
7722 let core_symbols = response
7723 .symbols
7724 .into_iter()
7725 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7726 .collect::<Vec<_>>();
7727 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7728 .await;
7729 Ok(symbols)
7730 })
7731 } else if let Some(local) = self.as_local() {
7732 struct WorkspaceSymbolsResult {
7733 server_id: LanguageServerId,
7734 lsp_adapter: Arc<CachedLspAdapter>,
7735 worktree: WeakEntity<Worktree>,
7736 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7737 }
7738
7739 let mut requests = Vec::new();
7740 let mut requested_servers = BTreeSet::new();
7741 for (seed, state) in local.language_server_ids.iter() {
7742 let Some(worktree_handle) = self
7743 .worktree_store
7744 .read(cx)
7745 .worktree_for_id(seed.worktree_id, cx)
7746 else {
7747 continue;
7748 };
7749 let worktree = worktree_handle.read(cx);
7750 if !worktree.is_visible() {
7751 continue;
7752 }
7753
7754 if !requested_servers.insert(state.id) {
7755 continue;
7756 }
7757
7758 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7759 Some(LanguageServerState::Running {
7760 adapter, server, ..
7761 }) => (adapter.clone(), server),
7762
7763 _ => continue,
7764 };
7765 let supports_workspace_symbol_request =
7766 match server.capabilities().workspace_symbol_provider {
7767 Some(OneOf::Left(supported)) => supported,
7768 Some(OneOf::Right(_)) => true,
7769 None => false,
7770 };
7771 if !supports_workspace_symbol_request {
7772 continue;
7773 }
7774 let worktree_handle = worktree_handle.clone();
7775 let server_id = server.server_id();
7776 requests.push(
7777 server
7778 .request::<lsp::request::WorkspaceSymbolRequest>(
7779 lsp::WorkspaceSymbolParams {
7780 query: query.to_string(),
7781 ..Default::default()
7782 },
7783 )
7784 .map(move |response| {
7785 let lsp_symbols = response.into_response()
7786 .context("workspace symbols request")
7787 .log_err()
7788 .flatten()
7789 .map(|symbol_response| match symbol_response {
7790 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7791 flat_responses.into_iter().map(|lsp_symbol| {
7792 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7793 }).collect::<Vec<_>>()
7794 }
7795 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7796 nested_responses.into_iter().filter_map(|lsp_symbol| {
7797 let location = match lsp_symbol.location {
7798 OneOf::Left(location) => location,
7799 OneOf::Right(_) => {
7800 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7801 return None
7802 }
7803 };
7804 Some((lsp_symbol.name, lsp_symbol.kind, location))
7805 }).collect::<Vec<_>>()
7806 }
7807 }).unwrap_or_default();
7808
7809 WorkspaceSymbolsResult {
7810 server_id,
7811 lsp_adapter,
7812 worktree: worktree_handle.downgrade(),
7813 lsp_symbols,
7814 }
7815 }),
7816 );
7817 }
7818
7819 cx.spawn(async move |this, cx| {
7820 let responses = futures::future::join_all(requests).await;
7821 let this = match this.upgrade() {
7822 Some(this) => this,
7823 None => return Ok(Vec::new()),
7824 };
7825
7826 let mut symbols = Vec::new();
7827 for result in responses {
7828 let core_symbols = this.update(cx, |this, cx| {
7829 result
7830 .lsp_symbols
7831 .into_iter()
7832 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7833 let abs_path = symbol_location.uri.to_file_path().ok()?;
7834 let source_worktree = result.worktree.upgrade()?;
7835 let source_worktree_id = source_worktree.read(cx).id();
7836
7837 let path = if let Some((tree, rel_path)) =
7838 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7839 {
7840 let worktree_id = tree.read(cx).id();
7841 SymbolLocation::InProject(ProjectPath {
7842 worktree_id,
7843 path: rel_path,
7844 })
7845 } else {
7846 SymbolLocation::OutsideProject {
7847 signature: this.symbol_signature(&abs_path),
7848 abs_path: abs_path.into(),
7849 }
7850 };
7851
7852 Some(CoreSymbol {
7853 source_language_server_id: result.server_id,
7854 language_server_name: result.lsp_adapter.name.clone(),
7855 source_worktree_id,
7856 path,
7857 kind: symbol_kind,
7858 name: symbol_name,
7859 range: range_from_lsp(symbol_location.range),
7860 })
7861 })
7862 .collect()
7863 })?;
7864
7865 populate_labels_for_symbols(
7866 core_symbols,
7867 &language_registry,
7868 Some(result.lsp_adapter),
7869 &mut symbols,
7870 )
7871 .await;
7872 }
7873
7874 Ok(symbols)
7875 })
7876 } else {
7877 Task::ready(Err(anyhow!("No upstream client or local language server")))
7878 }
7879 }
7880
7881 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7882 let mut summary = DiagnosticSummary::default();
7883 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7884 summary.error_count += path_summary.error_count;
7885 summary.warning_count += path_summary.warning_count;
7886 }
7887 summary
7888 }
7889
7890 /// Returns the diagnostic summary for a specific project path.
7891 pub fn diagnostic_summary_for_path(
7892 &self,
7893 project_path: &ProjectPath,
7894 _: &App,
7895 ) -> DiagnosticSummary {
7896 if let Some(summaries) = self
7897 .diagnostic_summaries
7898 .get(&project_path.worktree_id)
7899 .and_then(|map| map.get(&project_path.path))
7900 {
7901 let (error_count, warning_count) = summaries.iter().fold(
7902 (0, 0),
7903 |(error_count, warning_count), (_language_server_id, summary)| {
7904 (
7905 error_count + summary.error_count,
7906 warning_count + summary.warning_count,
7907 )
7908 },
7909 );
7910
7911 DiagnosticSummary {
7912 error_count,
7913 warning_count,
7914 }
7915 } else {
7916 DiagnosticSummary::default()
7917 }
7918 }
7919
7920 pub fn diagnostic_summaries<'a>(
7921 &'a self,
7922 include_ignored: bool,
7923 cx: &'a App,
7924 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7925 self.worktree_store
7926 .read(cx)
7927 .visible_worktrees(cx)
7928 .filter_map(|worktree| {
7929 let worktree = worktree.read(cx);
7930 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7931 })
7932 .flat_map(move |(worktree, summaries)| {
7933 let worktree_id = worktree.id();
7934 summaries
7935 .iter()
7936 .filter(move |(path, _)| {
7937 include_ignored
7938 || worktree
7939 .entry_for_path(path.as_ref())
7940 .is_some_and(|entry| !entry.is_ignored)
7941 })
7942 .flat_map(move |(path, summaries)| {
7943 summaries.iter().map(move |(server_id, summary)| {
7944 (
7945 ProjectPath {
7946 worktree_id,
7947 path: path.clone(),
7948 },
7949 *server_id,
7950 *summary,
7951 )
7952 })
7953 })
7954 })
7955 }
7956
7957 pub fn on_buffer_edited(
7958 &mut self,
7959 buffer: Entity<Buffer>,
7960 cx: &mut Context<Self>,
7961 ) -> Option<()> {
7962 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7963 Some(
7964 self.as_local()?
7965 .language_servers_for_buffer(buffer, cx)
7966 .map(|i| i.1.clone())
7967 .collect(),
7968 )
7969 })?;
7970
7971 let buffer = buffer.read(cx);
7972 let file = File::from_dyn(buffer.file())?;
7973 let abs_path = file.as_local()?.abs_path(cx);
7974 let uri = lsp::Uri::from_file_path(&abs_path)
7975 .ok()
7976 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7977 .log_err()?;
7978 let next_snapshot = buffer.text_snapshot();
7979 for language_server in language_servers {
7980 let language_server = language_server.clone();
7981
7982 let buffer_snapshots = self
7983 .as_local_mut()?
7984 .buffer_snapshots
7985 .get_mut(&buffer.remote_id())
7986 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7987 let previous_snapshot = buffer_snapshots.last()?;
7988
7989 let build_incremental_change = || {
7990 buffer
7991 .edits_since::<Dimensions<PointUtf16, usize>>(
7992 previous_snapshot.snapshot.version(),
7993 )
7994 .map(|edit| {
7995 let edit_start = edit.new.start.0;
7996 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7997 let new_text = next_snapshot
7998 .text_for_range(edit.new.start.1..edit.new.end.1)
7999 .collect();
8000 lsp::TextDocumentContentChangeEvent {
8001 range: Some(lsp::Range::new(
8002 point_to_lsp(edit_start),
8003 point_to_lsp(edit_end),
8004 )),
8005 range_length: None,
8006 text: new_text,
8007 }
8008 })
8009 .collect()
8010 };
8011
8012 let document_sync_kind = language_server
8013 .capabilities()
8014 .text_document_sync
8015 .as_ref()
8016 .and_then(|sync| match sync {
8017 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8018 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8019 });
8020
8021 let content_changes: Vec<_> = match document_sync_kind {
8022 Some(lsp::TextDocumentSyncKind::FULL) => {
8023 vec![lsp::TextDocumentContentChangeEvent {
8024 range: None,
8025 range_length: None,
8026 text: next_snapshot.text(),
8027 }]
8028 }
8029 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8030 _ => {
8031 #[cfg(any(test, feature = "test-support"))]
8032 {
8033 build_incremental_change()
8034 }
8035
8036 #[cfg(not(any(test, feature = "test-support")))]
8037 {
8038 continue;
8039 }
8040 }
8041 };
8042
8043 let next_version = previous_snapshot.version + 1;
8044 buffer_snapshots.push(LspBufferSnapshot {
8045 version: next_version,
8046 snapshot: next_snapshot.clone(),
8047 });
8048
8049 language_server
8050 .notify::<lsp::notification::DidChangeTextDocument>(
8051 lsp::DidChangeTextDocumentParams {
8052 text_document: lsp::VersionedTextDocumentIdentifier::new(
8053 uri.clone(),
8054 next_version,
8055 ),
8056 content_changes,
8057 },
8058 )
8059 .ok();
8060 self.pull_workspace_diagnostics(language_server.server_id());
8061 }
8062
8063 None
8064 }
8065
8066 pub fn on_buffer_saved(
8067 &mut self,
8068 buffer: Entity<Buffer>,
8069 cx: &mut Context<Self>,
8070 ) -> Option<()> {
8071 let file = File::from_dyn(buffer.read(cx).file())?;
8072 let worktree_id = file.worktree_id(cx);
8073 let abs_path = file.as_local()?.abs_path(cx);
8074 let text_document = lsp::TextDocumentIdentifier {
8075 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8076 };
8077 let local = self.as_local()?;
8078
8079 for server in local.language_servers_for_worktree(worktree_id) {
8080 if let Some(include_text) = include_text(server.as_ref()) {
8081 let text = if include_text {
8082 Some(buffer.read(cx).text())
8083 } else {
8084 None
8085 };
8086 server
8087 .notify::<lsp::notification::DidSaveTextDocument>(
8088 lsp::DidSaveTextDocumentParams {
8089 text_document: text_document.clone(),
8090 text,
8091 },
8092 )
8093 .ok();
8094 }
8095 }
8096
8097 let language_servers = buffer.update(cx, |buffer, cx| {
8098 local.language_server_ids_for_buffer(buffer, cx)
8099 });
8100 for language_server_id in language_servers {
8101 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8102 }
8103
8104 None
8105 }
8106
8107 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8108 maybe!(async move {
8109 let mut refreshed_servers = HashSet::default();
8110 let servers = lsp_store
8111 .update(cx, |lsp_store, cx| {
8112 let local = lsp_store.as_local()?;
8113
8114 let servers = local
8115 .language_server_ids
8116 .iter()
8117 .filter_map(|(seed, state)| {
8118 let worktree = lsp_store
8119 .worktree_store
8120 .read(cx)
8121 .worktree_for_id(seed.worktree_id, cx);
8122 let delegate: Arc<dyn LspAdapterDelegate> =
8123 worktree.map(|worktree| {
8124 LocalLspAdapterDelegate::new(
8125 local.languages.clone(),
8126 &local.environment,
8127 cx.weak_entity(),
8128 &worktree,
8129 local.http_client.clone(),
8130 local.fs.clone(),
8131 cx,
8132 )
8133 })?;
8134 let server_id = state.id;
8135
8136 let states = local.language_servers.get(&server_id)?;
8137
8138 match states {
8139 LanguageServerState::Starting { .. } => None,
8140 LanguageServerState::Running {
8141 adapter, server, ..
8142 } => {
8143 let adapter = adapter.clone();
8144 let server = server.clone();
8145 refreshed_servers.insert(server.name());
8146 let toolchain = seed.toolchain.clone();
8147 Some(cx.spawn(async move |_, cx| {
8148 let settings =
8149 LocalLspStore::workspace_configuration_for_adapter(
8150 adapter.adapter.clone(),
8151 &delegate,
8152 toolchain,
8153 None,
8154 cx,
8155 )
8156 .await
8157 .ok()?;
8158 server
8159 .notify::<lsp::notification::DidChangeConfiguration>(
8160 lsp::DidChangeConfigurationParams { settings },
8161 )
8162 .ok()?;
8163 Some(())
8164 }))
8165 }
8166 }
8167 })
8168 .collect::<Vec<_>>();
8169
8170 Some(servers)
8171 })
8172 .ok()
8173 .flatten()?;
8174
8175 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8176 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8177 // to stop and unregister its language server wrapper.
8178 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8179 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8180 let _: Vec<Option<()>> = join_all(servers).await;
8181
8182 Some(())
8183 })
8184 .await;
8185 }
8186
8187 fn maintain_workspace_config(
8188 external_refresh_requests: watch::Receiver<()>,
8189 cx: &mut Context<Self>,
8190 ) -> Task<Result<()>> {
8191 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8192 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8193
8194 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8195 *settings_changed_tx.borrow_mut() = ();
8196 });
8197
8198 let mut joint_future =
8199 futures::stream::select(settings_changed_rx, external_refresh_requests);
8200 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8201 // - 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).
8202 // - 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.
8203 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8204 // - 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,
8205 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8206 cx.spawn(async move |this, cx| {
8207 while let Some(()) = joint_future.next().await {
8208 this.update(cx, |this, cx| {
8209 this.refresh_server_tree(cx);
8210 })
8211 .ok();
8212
8213 Self::refresh_workspace_configurations(&this, cx).await;
8214 }
8215
8216 drop(settings_observation);
8217 anyhow::Ok(())
8218 })
8219 }
8220
8221 pub fn running_language_servers_for_local_buffer<'a>(
8222 &'a self,
8223 buffer: &Buffer,
8224 cx: &mut App,
8225 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8226 let local = self.as_local();
8227 let language_server_ids = local
8228 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8229 .unwrap_or_default();
8230
8231 language_server_ids
8232 .into_iter()
8233 .filter_map(
8234 move |server_id| match local?.language_servers.get(&server_id)? {
8235 LanguageServerState::Running {
8236 adapter, server, ..
8237 } => Some((adapter, server)),
8238 _ => None,
8239 },
8240 )
8241 }
8242
8243 pub fn language_servers_for_local_buffer(
8244 &self,
8245 buffer: &Buffer,
8246 cx: &mut App,
8247 ) -> Vec<LanguageServerId> {
8248 let local = self.as_local();
8249 local
8250 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8251 .unwrap_or_default()
8252 }
8253
8254 pub fn language_server_for_local_buffer<'a>(
8255 &'a self,
8256 buffer: &'a Buffer,
8257 server_id: LanguageServerId,
8258 cx: &'a mut App,
8259 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8260 self.as_local()?
8261 .language_servers_for_buffer(buffer, cx)
8262 .find(|(_, s)| s.server_id() == server_id)
8263 }
8264
8265 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8266 self.diagnostic_summaries.remove(&id_to_remove);
8267 if let Some(local) = self.as_local_mut() {
8268 let to_remove = local.remove_worktree(id_to_remove, cx);
8269 for server in to_remove {
8270 self.language_server_statuses.remove(&server);
8271 }
8272 }
8273 }
8274
8275 pub fn shared(
8276 &mut self,
8277 project_id: u64,
8278 downstream_client: AnyProtoClient,
8279 _: &mut Context<Self>,
8280 ) {
8281 self.downstream_client = Some((downstream_client.clone(), project_id));
8282
8283 for (server_id, status) in &self.language_server_statuses {
8284 if let Some(server) = self.language_server_for_id(*server_id) {
8285 downstream_client
8286 .send(proto::StartLanguageServer {
8287 project_id,
8288 server: Some(proto::LanguageServer {
8289 id: server_id.to_proto(),
8290 name: status.name.to_string(),
8291 worktree_id: status.worktree.map(|id| id.to_proto()),
8292 }),
8293 capabilities: serde_json::to_string(&server.capabilities())
8294 .expect("serializing server LSP capabilities"),
8295 })
8296 .log_err();
8297 }
8298 }
8299 }
8300
8301 pub fn disconnected_from_host(&mut self) {
8302 self.downstream_client.take();
8303 }
8304
8305 pub fn disconnected_from_ssh_remote(&mut self) {
8306 if let LspStoreMode::Remote(RemoteLspStore {
8307 upstream_client, ..
8308 }) = &mut self.mode
8309 {
8310 upstream_client.take();
8311 }
8312 }
8313
8314 pub(crate) fn set_language_server_statuses_from_proto(
8315 &mut self,
8316 project: WeakEntity<Project>,
8317 language_servers: Vec<proto::LanguageServer>,
8318 server_capabilities: Vec<String>,
8319 cx: &mut Context<Self>,
8320 ) {
8321 let lsp_logs = cx
8322 .try_global::<GlobalLogStore>()
8323 .map(|lsp_store| lsp_store.0.clone());
8324
8325 self.language_server_statuses = language_servers
8326 .into_iter()
8327 .zip(server_capabilities)
8328 .map(|(server, server_capabilities)| {
8329 let server_id = LanguageServerId(server.id as usize);
8330 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8331 self.lsp_server_capabilities
8332 .insert(server_id, server_capabilities);
8333 }
8334
8335 let name = LanguageServerName::from_proto(server.name);
8336 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8337
8338 if let Some(lsp_logs) = &lsp_logs {
8339 lsp_logs.update(cx, |lsp_logs, cx| {
8340 lsp_logs.add_language_server(
8341 // Only remote clients get their language servers set from proto
8342 LanguageServerKind::Remote {
8343 project: project.clone(),
8344 },
8345 server_id,
8346 Some(name.clone()),
8347 worktree,
8348 None,
8349 cx,
8350 );
8351 });
8352 }
8353
8354 (
8355 server_id,
8356 LanguageServerStatus {
8357 name,
8358 server_version: None,
8359 pending_work: Default::default(),
8360 has_pending_diagnostic_updates: false,
8361 progress_tokens: Default::default(),
8362 worktree,
8363 binary: None,
8364 configuration: None,
8365 workspace_folders: BTreeSet::new(),
8366 },
8367 )
8368 })
8369 .collect();
8370 }
8371
8372 #[cfg(test)]
8373 pub fn update_diagnostic_entries(
8374 &mut self,
8375 server_id: LanguageServerId,
8376 abs_path: PathBuf,
8377 result_id: Option<SharedString>,
8378 version: Option<i32>,
8379 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8380 cx: &mut Context<Self>,
8381 ) -> anyhow::Result<()> {
8382 self.merge_diagnostic_entries(
8383 vec![DocumentDiagnosticsUpdate {
8384 diagnostics: DocumentDiagnostics {
8385 diagnostics,
8386 document_abs_path: abs_path,
8387 version,
8388 },
8389 result_id,
8390 server_id,
8391 disk_based_sources: Cow::Borrowed(&[]),
8392 registration_id: None,
8393 }],
8394 |_, _, _| false,
8395 cx,
8396 )?;
8397 Ok(())
8398 }
8399
8400 pub fn merge_diagnostic_entries<'a>(
8401 &mut self,
8402 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8403 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8404 cx: &mut Context<Self>,
8405 ) -> anyhow::Result<()> {
8406 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8407 let mut updated_diagnostics_paths = HashMap::default();
8408 for mut update in diagnostic_updates {
8409 let abs_path = &update.diagnostics.document_abs_path;
8410 let server_id = update.server_id;
8411 let Some((worktree, relative_path)) =
8412 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8413 else {
8414 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8415 return Ok(());
8416 };
8417
8418 let worktree_id = worktree.read(cx).id();
8419 let project_path = ProjectPath {
8420 worktree_id,
8421 path: relative_path,
8422 };
8423
8424 let document_uri = lsp::Uri::from_file_path(abs_path)
8425 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8426 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8427 let snapshot = buffer_handle.read(cx).snapshot();
8428 let buffer = buffer_handle.read(cx);
8429 let reused_diagnostics = buffer
8430 .buffer_diagnostics(Some(server_id))
8431 .iter()
8432 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8433 .map(|v| {
8434 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8435 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8436 DiagnosticEntry {
8437 range: start..end,
8438 diagnostic: v.diagnostic.clone(),
8439 }
8440 })
8441 .collect::<Vec<_>>();
8442
8443 self.as_local_mut()
8444 .context("cannot merge diagnostics on a remote LspStore")?
8445 .update_buffer_diagnostics(
8446 &buffer_handle,
8447 server_id,
8448 Some(update.registration_id),
8449 update.result_id,
8450 update.diagnostics.version,
8451 update.diagnostics.diagnostics.clone(),
8452 reused_diagnostics.clone(),
8453 cx,
8454 )?;
8455
8456 update.diagnostics.diagnostics.extend(reused_diagnostics);
8457 } else if let Some(local) = self.as_local() {
8458 let reused_diagnostics = local
8459 .diagnostics
8460 .get(&worktree_id)
8461 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8462 .and_then(|diagnostics_by_server_id| {
8463 diagnostics_by_server_id
8464 .binary_search_by_key(&server_id, |e| e.0)
8465 .ok()
8466 .map(|ix| &diagnostics_by_server_id[ix].1)
8467 })
8468 .into_iter()
8469 .flatten()
8470 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8471
8472 update
8473 .diagnostics
8474 .diagnostics
8475 .extend(reused_diagnostics.cloned());
8476 }
8477
8478 let updated = worktree.update(cx, |worktree, cx| {
8479 self.update_worktree_diagnostics(
8480 worktree.id(),
8481 server_id,
8482 project_path.path.clone(),
8483 update.diagnostics.diagnostics,
8484 cx,
8485 )
8486 })?;
8487 match updated {
8488 ControlFlow::Continue(new_summary) => {
8489 if let Some((project_id, new_summary)) = new_summary {
8490 match &mut diagnostics_summary {
8491 Some(diagnostics_summary) => {
8492 diagnostics_summary
8493 .more_summaries
8494 .push(proto::DiagnosticSummary {
8495 path: project_path.path.as_ref().to_proto(),
8496 language_server_id: server_id.0 as u64,
8497 error_count: new_summary.error_count,
8498 warning_count: new_summary.warning_count,
8499 })
8500 }
8501 None => {
8502 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8503 project_id,
8504 worktree_id: worktree_id.to_proto(),
8505 summary: Some(proto::DiagnosticSummary {
8506 path: project_path.path.as_ref().to_proto(),
8507 language_server_id: server_id.0 as u64,
8508 error_count: new_summary.error_count,
8509 warning_count: new_summary.warning_count,
8510 }),
8511 more_summaries: Vec::new(),
8512 })
8513 }
8514 }
8515 }
8516 updated_diagnostics_paths
8517 .entry(server_id)
8518 .or_insert_with(Vec::new)
8519 .push(project_path);
8520 }
8521 ControlFlow::Break(()) => {}
8522 }
8523 }
8524
8525 if let Some((diagnostics_summary, (downstream_client, _))) =
8526 diagnostics_summary.zip(self.downstream_client.as_ref())
8527 {
8528 downstream_client.send(diagnostics_summary).log_err();
8529 }
8530 for (server_id, paths) in updated_diagnostics_paths {
8531 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8532 }
8533 Ok(())
8534 }
8535
8536 fn update_worktree_diagnostics(
8537 &mut self,
8538 worktree_id: WorktreeId,
8539 server_id: LanguageServerId,
8540 path_in_worktree: Arc<RelPath>,
8541 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8542 _: &mut Context<Worktree>,
8543 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8544 let local = match &mut self.mode {
8545 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8546 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8547 };
8548
8549 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8550 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8551 let summaries_by_server_id = summaries_for_tree
8552 .entry(path_in_worktree.clone())
8553 .or_default();
8554
8555 let old_summary = summaries_by_server_id
8556 .remove(&server_id)
8557 .unwrap_or_default();
8558
8559 let new_summary = DiagnosticSummary::new(&diagnostics);
8560 if diagnostics.is_empty() {
8561 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8562 {
8563 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8564 diagnostics_by_server_id.remove(ix);
8565 }
8566 if diagnostics_by_server_id.is_empty() {
8567 diagnostics_for_tree.remove(&path_in_worktree);
8568 }
8569 }
8570 } else {
8571 summaries_by_server_id.insert(server_id, new_summary);
8572 let diagnostics_by_server_id = diagnostics_for_tree
8573 .entry(path_in_worktree.clone())
8574 .or_default();
8575 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8576 Ok(ix) => {
8577 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8578 }
8579 Err(ix) => {
8580 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8581 }
8582 }
8583 }
8584
8585 if !old_summary.is_empty() || !new_summary.is_empty() {
8586 if let Some((_, project_id)) = &self.downstream_client {
8587 Ok(ControlFlow::Continue(Some((
8588 *project_id,
8589 proto::DiagnosticSummary {
8590 path: path_in_worktree.to_proto(),
8591 language_server_id: server_id.0 as u64,
8592 error_count: new_summary.error_count as u32,
8593 warning_count: new_summary.warning_count as u32,
8594 },
8595 ))))
8596 } else {
8597 Ok(ControlFlow::Continue(None))
8598 }
8599 } else {
8600 Ok(ControlFlow::Break(()))
8601 }
8602 }
8603
8604 pub fn open_buffer_for_symbol(
8605 &mut self,
8606 symbol: &Symbol,
8607 cx: &mut Context<Self>,
8608 ) -> Task<Result<Entity<Buffer>>> {
8609 if let Some((client, project_id)) = self.upstream_client() {
8610 let request = client.request(proto::OpenBufferForSymbol {
8611 project_id,
8612 symbol: Some(Self::serialize_symbol(symbol)),
8613 });
8614 cx.spawn(async move |this, cx| {
8615 let response = request.await?;
8616 let buffer_id = BufferId::new(response.buffer_id)?;
8617 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8618 .await
8619 })
8620 } else if let Some(local) = self.as_local() {
8621 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8622 seed.worktree_id == symbol.source_worktree_id
8623 && state.id == symbol.source_language_server_id
8624 && symbol.language_server_name == seed.name
8625 });
8626 if !is_valid {
8627 return Task::ready(Err(anyhow!(
8628 "language server for worktree and language not found"
8629 )));
8630 };
8631
8632 let symbol_abs_path = match &symbol.path {
8633 SymbolLocation::InProject(project_path) => self
8634 .worktree_store
8635 .read(cx)
8636 .absolutize(&project_path, cx)
8637 .context("no such worktree"),
8638 SymbolLocation::OutsideProject {
8639 abs_path,
8640 signature: _,
8641 } => Ok(abs_path.to_path_buf()),
8642 };
8643 let symbol_abs_path = match symbol_abs_path {
8644 Ok(abs_path) => abs_path,
8645 Err(err) => return Task::ready(Err(err)),
8646 };
8647 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8648 uri
8649 } else {
8650 return Task::ready(Err(anyhow!("invalid symbol path")));
8651 };
8652
8653 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8654 } else {
8655 Task::ready(Err(anyhow!("no upstream client or local store")))
8656 }
8657 }
8658
8659 pub(crate) fn open_local_buffer_via_lsp(
8660 &mut self,
8661 abs_path: lsp::Uri,
8662 language_server_id: LanguageServerId,
8663 cx: &mut Context<Self>,
8664 ) -> Task<Result<Entity<Buffer>>> {
8665 cx.spawn(async move |lsp_store, cx| {
8666 // Escape percent-encoded string.
8667 let current_scheme = abs_path.scheme().to_owned();
8668 // Uri is immutable, so we can't modify the scheme
8669
8670 let abs_path = abs_path
8671 .to_file_path()
8672 .map_err(|()| anyhow!("can't convert URI to path"))?;
8673 let p = abs_path.clone();
8674 let yarn_worktree = lsp_store
8675 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8676 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8677 cx.spawn(async move |this, cx| {
8678 let t = this
8679 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8680 .ok()?;
8681 t.await
8682 })
8683 }),
8684 None => Task::ready(None),
8685 })?
8686 .await;
8687 let (worktree_root_target, known_relative_path) =
8688 if let Some((zip_root, relative_path)) = yarn_worktree {
8689 (zip_root, Some(relative_path))
8690 } else {
8691 (Arc::<Path>::from(abs_path.as_path()), None)
8692 };
8693 let (worktree, relative_path) = if let Some(result) =
8694 lsp_store.update(cx, |lsp_store, cx| {
8695 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8696 worktree_store.find_worktree(&worktree_root_target, cx)
8697 })
8698 })? {
8699 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8700 (result.0, relative_path)
8701 } else {
8702 let worktree = lsp_store
8703 .update(cx, |lsp_store, cx| {
8704 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8705 worktree_store.create_worktree(&worktree_root_target, false, cx)
8706 })
8707 })?
8708 .await?;
8709 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8710 lsp_store
8711 .update(cx, |lsp_store, cx| {
8712 if let Some(local) = lsp_store.as_local_mut() {
8713 local.register_language_server_for_invisible_worktree(
8714 &worktree,
8715 language_server_id,
8716 cx,
8717 )
8718 }
8719 })
8720 .ok();
8721 }
8722 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8723 let relative_path = if let Some(known_path) = known_relative_path {
8724 known_path
8725 } else {
8726 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8727 .into_arc()
8728 };
8729 (worktree, relative_path)
8730 };
8731 let project_path = ProjectPath {
8732 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8733 path: relative_path,
8734 };
8735 lsp_store
8736 .update(cx, |lsp_store, cx| {
8737 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8738 buffer_store.open_buffer(project_path, cx)
8739 })
8740 })?
8741 .await
8742 })
8743 }
8744
8745 fn request_multiple_lsp_locally<P, R>(
8746 &mut self,
8747 buffer: &Entity<Buffer>,
8748 position: Option<P>,
8749 request: R,
8750 cx: &mut Context<Self>,
8751 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8752 where
8753 P: ToOffset,
8754 R: LspCommand + Clone,
8755 <R::LspRequest as lsp::request::Request>::Result: Send,
8756 <R::LspRequest as lsp::request::Request>::Params: Send,
8757 {
8758 let Some(local) = self.as_local() else {
8759 return Task::ready(Vec::new());
8760 };
8761
8762 let snapshot = buffer.read(cx).snapshot();
8763 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8764
8765 let server_ids = buffer.update(cx, |buffer, cx| {
8766 local
8767 .language_servers_for_buffer(buffer, cx)
8768 .filter(|(adapter, _)| {
8769 scope
8770 .as_ref()
8771 .map(|scope| scope.language_allowed(&adapter.name))
8772 .unwrap_or(true)
8773 })
8774 .map(|(_, server)| server.server_id())
8775 .filter(|server_id| {
8776 self.as_local().is_none_or(|local| {
8777 local
8778 .buffers_opened_in_servers
8779 .get(&snapshot.remote_id())
8780 .is_some_and(|servers| servers.contains(server_id))
8781 })
8782 })
8783 .collect::<Vec<_>>()
8784 });
8785
8786 let mut response_results = server_ids
8787 .into_iter()
8788 .map(|server_id| {
8789 let task = self.request_lsp(
8790 buffer.clone(),
8791 LanguageServerToQuery::Other(server_id),
8792 request.clone(),
8793 cx,
8794 );
8795 async move { (server_id, task.await) }
8796 })
8797 .collect::<FuturesUnordered<_>>();
8798
8799 cx.background_spawn(async move {
8800 let mut responses = Vec::with_capacity(response_results.len());
8801 while let Some((server_id, response_result)) = response_results.next().await {
8802 match response_result {
8803 Ok(response) => responses.push((server_id, response)),
8804 // rust-analyzer likes to error with this when its still loading up
8805 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8806 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8807 }
8808 }
8809 responses
8810 })
8811 }
8812
8813 async fn handle_lsp_get_completions(
8814 this: Entity<Self>,
8815 envelope: TypedEnvelope<proto::GetCompletions>,
8816 mut cx: AsyncApp,
8817 ) -> Result<proto::GetCompletionsResponse> {
8818 let sender_id = envelope.original_sender_id().unwrap_or_default();
8819
8820 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8821 let buffer_handle = this.update(&mut cx, |this, cx| {
8822 this.buffer_store.read(cx).get_existing(buffer_id)
8823 })??;
8824 let request = GetCompletions::from_proto(
8825 envelope.payload,
8826 this.clone(),
8827 buffer_handle.clone(),
8828 cx.clone(),
8829 )
8830 .await?;
8831
8832 let server_to_query = match request.server_id {
8833 Some(server_id) => LanguageServerToQuery::Other(server_id),
8834 None => LanguageServerToQuery::FirstCapable,
8835 };
8836
8837 let response = this
8838 .update(&mut cx, |this, cx| {
8839 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8840 })?
8841 .await?;
8842 this.update(&mut cx, |this, cx| {
8843 Ok(GetCompletions::response_to_proto(
8844 response,
8845 this,
8846 sender_id,
8847 &buffer_handle.read(cx).version(),
8848 cx,
8849 ))
8850 })?
8851 }
8852
8853 async fn handle_lsp_command<T: LspCommand>(
8854 this: Entity<Self>,
8855 envelope: TypedEnvelope<T::ProtoRequest>,
8856 mut cx: AsyncApp,
8857 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8858 where
8859 <T::LspRequest as lsp::request::Request>::Params: Send,
8860 <T::LspRequest as lsp::request::Request>::Result: Send,
8861 {
8862 let sender_id = envelope.original_sender_id().unwrap_or_default();
8863 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8864 let buffer_handle = this.update(&mut cx, |this, cx| {
8865 this.buffer_store.read(cx).get_existing(buffer_id)
8866 })??;
8867 let request = T::from_proto(
8868 envelope.payload,
8869 this.clone(),
8870 buffer_handle.clone(),
8871 cx.clone(),
8872 )
8873 .await?;
8874 let response = this
8875 .update(&mut cx, |this, cx| {
8876 this.request_lsp(
8877 buffer_handle.clone(),
8878 LanguageServerToQuery::FirstCapable,
8879 request,
8880 cx,
8881 )
8882 })?
8883 .await?;
8884 this.update(&mut cx, |this, cx| {
8885 Ok(T::response_to_proto(
8886 response,
8887 this,
8888 sender_id,
8889 &buffer_handle.read(cx).version(),
8890 cx,
8891 ))
8892 })?
8893 }
8894
8895 async fn handle_lsp_query(
8896 lsp_store: Entity<Self>,
8897 envelope: TypedEnvelope<proto::LspQuery>,
8898 mut cx: AsyncApp,
8899 ) -> Result<proto::Ack> {
8900 use proto::lsp_query::Request;
8901 let sender_id = envelope.original_sender_id().unwrap_or_default();
8902 let lsp_query = envelope.payload;
8903 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8904 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8905 match lsp_query.request.context("invalid LSP query request")? {
8906 Request::GetReferences(get_references) => {
8907 let position = get_references.position.clone().and_then(deserialize_anchor);
8908 Self::query_lsp_locally::<GetReferences>(
8909 lsp_store,
8910 server_id,
8911 sender_id,
8912 lsp_request_id,
8913 get_references,
8914 position,
8915 &mut cx,
8916 )
8917 .await?;
8918 }
8919 Request::GetDocumentColor(get_document_color) => {
8920 Self::query_lsp_locally::<GetDocumentColor>(
8921 lsp_store,
8922 server_id,
8923 sender_id,
8924 lsp_request_id,
8925 get_document_color,
8926 None,
8927 &mut cx,
8928 )
8929 .await?;
8930 }
8931 Request::GetHover(get_hover) => {
8932 let position = get_hover.position.clone().and_then(deserialize_anchor);
8933 Self::query_lsp_locally::<GetHover>(
8934 lsp_store,
8935 server_id,
8936 sender_id,
8937 lsp_request_id,
8938 get_hover,
8939 position,
8940 &mut cx,
8941 )
8942 .await?;
8943 }
8944 Request::GetCodeActions(get_code_actions) => {
8945 Self::query_lsp_locally::<GetCodeActions>(
8946 lsp_store,
8947 server_id,
8948 sender_id,
8949 lsp_request_id,
8950 get_code_actions,
8951 None,
8952 &mut cx,
8953 )
8954 .await?;
8955 }
8956 Request::GetSignatureHelp(get_signature_help) => {
8957 let position = get_signature_help
8958 .position
8959 .clone()
8960 .and_then(deserialize_anchor);
8961 Self::query_lsp_locally::<GetSignatureHelp>(
8962 lsp_store,
8963 server_id,
8964 sender_id,
8965 lsp_request_id,
8966 get_signature_help,
8967 position,
8968 &mut cx,
8969 )
8970 .await?;
8971 }
8972 Request::GetCodeLens(get_code_lens) => {
8973 Self::query_lsp_locally::<GetCodeLens>(
8974 lsp_store,
8975 server_id,
8976 sender_id,
8977 lsp_request_id,
8978 get_code_lens,
8979 None,
8980 &mut cx,
8981 )
8982 .await?;
8983 }
8984 Request::GetDefinition(get_definition) => {
8985 let position = get_definition.position.clone().and_then(deserialize_anchor);
8986 Self::query_lsp_locally::<GetDefinitions>(
8987 lsp_store,
8988 server_id,
8989 sender_id,
8990 lsp_request_id,
8991 get_definition,
8992 position,
8993 &mut cx,
8994 )
8995 .await?;
8996 }
8997 Request::GetDeclaration(get_declaration) => {
8998 let position = get_declaration
8999 .position
9000 .clone()
9001 .and_then(deserialize_anchor);
9002 Self::query_lsp_locally::<GetDeclarations>(
9003 lsp_store,
9004 server_id,
9005 sender_id,
9006 lsp_request_id,
9007 get_declaration,
9008 position,
9009 &mut cx,
9010 )
9011 .await?;
9012 }
9013 Request::GetTypeDefinition(get_type_definition) => {
9014 let position = get_type_definition
9015 .position
9016 .clone()
9017 .and_then(deserialize_anchor);
9018 Self::query_lsp_locally::<GetTypeDefinitions>(
9019 lsp_store,
9020 server_id,
9021 sender_id,
9022 lsp_request_id,
9023 get_type_definition,
9024 position,
9025 &mut cx,
9026 )
9027 .await?;
9028 }
9029 Request::GetImplementation(get_implementation) => {
9030 let position = get_implementation
9031 .position
9032 .clone()
9033 .and_then(deserialize_anchor);
9034 Self::query_lsp_locally::<GetImplementations>(
9035 lsp_store,
9036 server_id,
9037 sender_id,
9038 lsp_request_id,
9039 get_implementation,
9040 position,
9041 &mut cx,
9042 )
9043 .await?;
9044 }
9045 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9046 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9047 let version = deserialize_version(get_document_diagnostics.buffer_version());
9048 let buffer = lsp_store.update(&mut cx, |this, cx| {
9049 this.buffer_store.read(cx).get_existing(buffer_id)
9050 })??;
9051 buffer
9052 .update(&mut cx, |buffer, _| {
9053 buffer.wait_for_version(version.clone())
9054 })?
9055 .await?;
9056 lsp_store.update(&mut cx, |lsp_store, cx| {
9057 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9058 let key = LspKey {
9059 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9060 server_queried: server_id,
9061 };
9062 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9063 ) {
9064 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9065 lsp_requests.clear();
9066 };
9067 }
9068
9069 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9070 existing_queries.insert(
9071 lsp_request_id,
9072 cx.spawn(async move |lsp_store, cx| {
9073 let diagnostics_pull = lsp_store
9074 .update(cx, |lsp_store, cx| {
9075 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9076 })
9077 .ok();
9078 if let Some(diagnostics_pull) = diagnostics_pull {
9079 match diagnostics_pull.await {
9080 Ok(()) => {}
9081 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9082 };
9083 }
9084 }),
9085 );
9086 })?;
9087 }
9088 Request::InlayHints(inlay_hints) => {
9089 let query_start = inlay_hints
9090 .start
9091 .clone()
9092 .and_then(deserialize_anchor)
9093 .context("invalid inlay hints range start")?;
9094 let query_end = inlay_hints
9095 .end
9096 .clone()
9097 .and_then(deserialize_anchor)
9098 .context("invalid inlay hints range end")?;
9099 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9100 &lsp_store,
9101 server_id,
9102 lsp_request_id,
9103 &inlay_hints,
9104 query_start..query_end,
9105 &mut cx,
9106 )
9107 .await
9108 .context("preparing inlay hints request")?;
9109 Self::query_lsp_locally::<InlayHints>(
9110 lsp_store,
9111 server_id,
9112 sender_id,
9113 lsp_request_id,
9114 inlay_hints,
9115 None,
9116 &mut cx,
9117 )
9118 .await
9119 .context("querying for inlay hints")?
9120 }
9121 }
9122 Ok(proto::Ack {})
9123 }
9124
9125 async fn handle_lsp_query_response(
9126 lsp_store: Entity<Self>,
9127 envelope: TypedEnvelope<proto::LspQueryResponse>,
9128 cx: AsyncApp,
9129 ) -> Result<()> {
9130 lsp_store.read_with(&cx, |lsp_store, _| {
9131 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9132 upstream_client.handle_lsp_response(envelope.clone());
9133 }
9134 })?;
9135 Ok(())
9136 }
9137
9138 async fn handle_apply_code_action(
9139 this: Entity<Self>,
9140 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9141 mut cx: AsyncApp,
9142 ) -> Result<proto::ApplyCodeActionResponse> {
9143 let sender_id = envelope.original_sender_id().unwrap_or_default();
9144 let action =
9145 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9146 let apply_code_action = this.update(&mut cx, |this, cx| {
9147 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9148 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9149 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9150 })??;
9151
9152 let project_transaction = apply_code_action.await?;
9153 let project_transaction = this.update(&mut cx, |this, cx| {
9154 this.buffer_store.update(cx, |buffer_store, cx| {
9155 buffer_store.serialize_project_transaction_for_peer(
9156 project_transaction,
9157 sender_id,
9158 cx,
9159 )
9160 })
9161 })?;
9162 Ok(proto::ApplyCodeActionResponse {
9163 transaction: Some(project_transaction),
9164 })
9165 }
9166
9167 async fn handle_register_buffer_with_language_servers(
9168 this: Entity<Self>,
9169 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9170 mut cx: AsyncApp,
9171 ) -> Result<proto::Ack> {
9172 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9173 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9174 this.update(&mut cx, |this, cx| {
9175 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9176 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9177 project_id: upstream_project_id,
9178 buffer_id: buffer_id.to_proto(),
9179 only_servers: envelope.payload.only_servers,
9180 });
9181 }
9182
9183 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9184 anyhow::bail!("buffer is not open");
9185 };
9186
9187 let handle = this.register_buffer_with_language_servers(
9188 &buffer,
9189 envelope
9190 .payload
9191 .only_servers
9192 .into_iter()
9193 .filter_map(|selector| {
9194 Some(match selector.selector? {
9195 proto::language_server_selector::Selector::ServerId(server_id) => {
9196 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9197 }
9198 proto::language_server_selector::Selector::Name(name) => {
9199 LanguageServerSelector::Name(LanguageServerName(
9200 SharedString::from(name),
9201 ))
9202 }
9203 })
9204 })
9205 .collect(),
9206 false,
9207 cx,
9208 );
9209 this.buffer_store().update(cx, |buffer_store, _| {
9210 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9211 });
9212
9213 Ok(())
9214 })??;
9215 Ok(proto::Ack {})
9216 }
9217
9218 async fn handle_rename_project_entry(
9219 this: Entity<Self>,
9220 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9221 mut cx: AsyncApp,
9222 ) -> Result<proto::ProjectEntryResponse> {
9223 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9224 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9225 let new_path =
9226 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9227
9228 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9229 .update(&mut cx, |this, cx| {
9230 let (worktree, entry) = this
9231 .worktree_store
9232 .read(cx)
9233 .worktree_and_entry_for_id(entry_id, cx)?;
9234 let new_worktree = this
9235 .worktree_store
9236 .read(cx)
9237 .worktree_for_id(new_worktree_id, cx)?;
9238 Some((
9239 this.worktree_store.clone(),
9240 worktree,
9241 new_worktree,
9242 entry.clone(),
9243 ))
9244 })?
9245 .context("worktree not found")?;
9246 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9247 (worktree.absolutize(&old_entry.path), worktree.id())
9248 })?;
9249 let new_abs_path =
9250 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9251
9252 let _transaction = Self::will_rename_entry(
9253 this.downgrade(),
9254 old_worktree_id,
9255 &old_abs_path,
9256 &new_abs_path,
9257 old_entry.is_dir(),
9258 cx.clone(),
9259 )
9260 .await;
9261 let response = WorktreeStore::handle_rename_project_entry(
9262 worktree_store,
9263 envelope.payload,
9264 cx.clone(),
9265 )
9266 .await;
9267 this.read_with(&cx, |this, _| {
9268 this.did_rename_entry(
9269 old_worktree_id,
9270 &old_abs_path,
9271 &new_abs_path,
9272 old_entry.is_dir(),
9273 );
9274 })
9275 .ok();
9276 response
9277 }
9278
9279 async fn handle_update_diagnostic_summary(
9280 this: Entity<Self>,
9281 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9282 mut cx: AsyncApp,
9283 ) -> Result<()> {
9284 this.update(&mut cx, |lsp_store, cx| {
9285 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9286 let mut updated_diagnostics_paths = HashMap::default();
9287 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9288 for message_summary in envelope
9289 .payload
9290 .summary
9291 .into_iter()
9292 .chain(envelope.payload.more_summaries)
9293 {
9294 let project_path = ProjectPath {
9295 worktree_id,
9296 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9297 };
9298 let path = project_path.path.clone();
9299 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9300 let summary = DiagnosticSummary {
9301 error_count: message_summary.error_count as usize,
9302 warning_count: message_summary.warning_count as usize,
9303 };
9304
9305 if summary.is_empty() {
9306 if let Some(worktree_summaries) =
9307 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9308 && let Some(summaries) = worktree_summaries.get_mut(&path)
9309 {
9310 summaries.remove(&server_id);
9311 if summaries.is_empty() {
9312 worktree_summaries.remove(&path);
9313 }
9314 }
9315 } else {
9316 lsp_store
9317 .diagnostic_summaries
9318 .entry(worktree_id)
9319 .or_default()
9320 .entry(path)
9321 .or_default()
9322 .insert(server_id, summary);
9323 }
9324
9325 if let Some((_, project_id)) = &lsp_store.downstream_client {
9326 match &mut diagnostics_summary {
9327 Some(diagnostics_summary) => {
9328 diagnostics_summary
9329 .more_summaries
9330 .push(proto::DiagnosticSummary {
9331 path: project_path.path.as_ref().to_proto(),
9332 language_server_id: server_id.0 as u64,
9333 error_count: summary.error_count as u32,
9334 warning_count: summary.warning_count as u32,
9335 })
9336 }
9337 None => {
9338 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9339 project_id: *project_id,
9340 worktree_id: worktree_id.to_proto(),
9341 summary: Some(proto::DiagnosticSummary {
9342 path: project_path.path.as_ref().to_proto(),
9343 language_server_id: server_id.0 as u64,
9344 error_count: summary.error_count as u32,
9345 warning_count: summary.warning_count as u32,
9346 }),
9347 more_summaries: Vec::new(),
9348 })
9349 }
9350 }
9351 }
9352 updated_diagnostics_paths
9353 .entry(server_id)
9354 .or_insert_with(Vec::new)
9355 .push(project_path);
9356 }
9357
9358 if let Some((diagnostics_summary, (downstream_client, _))) =
9359 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9360 {
9361 downstream_client.send(diagnostics_summary).log_err();
9362 }
9363 for (server_id, paths) in updated_diagnostics_paths {
9364 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9365 }
9366 Ok(())
9367 })?
9368 }
9369
9370 async fn handle_start_language_server(
9371 lsp_store: Entity<Self>,
9372 envelope: TypedEnvelope<proto::StartLanguageServer>,
9373 mut cx: AsyncApp,
9374 ) -> Result<()> {
9375 let server = envelope.payload.server.context("invalid server")?;
9376 let server_capabilities =
9377 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9378 .with_context(|| {
9379 format!(
9380 "incorrect server capabilities {}",
9381 envelope.payload.capabilities
9382 )
9383 })?;
9384 lsp_store.update(&mut cx, |lsp_store, cx| {
9385 let server_id = LanguageServerId(server.id as usize);
9386 let server_name = LanguageServerName::from_proto(server.name.clone());
9387 lsp_store
9388 .lsp_server_capabilities
9389 .insert(server_id, server_capabilities);
9390 lsp_store.language_server_statuses.insert(
9391 server_id,
9392 LanguageServerStatus {
9393 name: server_name.clone(),
9394 server_version: None,
9395 pending_work: Default::default(),
9396 has_pending_diagnostic_updates: false,
9397 progress_tokens: Default::default(),
9398 worktree: server.worktree_id.map(WorktreeId::from_proto),
9399 binary: None,
9400 configuration: None,
9401 workspace_folders: BTreeSet::new(),
9402 },
9403 );
9404 cx.emit(LspStoreEvent::LanguageServerAdded(
9405 server_id,
9406 server_name,
9407 server.worktree_id.map(WorktreeId::from_proto),
9408 ));
9409 cx.notify();
9410 })?;
9411 Ok(())
9412 }
9413
9414 async fn handle_update_language_server(
9415 lsp_store: Entity<Self>,
9416 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9417 mut cx: AsyncApp,
9418 ) -> Result<()> {
9419 lsp_store.update(&mut cx, |lsp_store, cx| {
9420 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9421
9422 match envelope.payload.variant.context("invalid variant")? {
9423 proto::update_language_server::Variant::WorkStart(payload) => {
9424 lsp_store.on_lsp_work_start(
9425 language_server_id,
9426 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9427 .context("invalid progress token value")?,
9428 LanguageServerProgress {
9429 title: payload.title,
9430 is_disk_based_diagnostics_progress: false,
9431 is_cancellable: payload.is_cancellable.unwrap_or(false),
9432 message: payload.message,
9433 percentage: payload.percentage.map(|p| p as usize),
9434 last_update_at: cx.background_executor().now(),
9435 },
9436 cx,
9437 );
9438 }
9439 proto::update_language_server::Variant::WorkProgress(payload) => {
9440 lsp_store.on_lsp_work_progress(
9441 language_server_id,
9442 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9443 .context("invalid progress token value")?,
9444 LanguageServerProgress {
9445 title: None,
9446 is_disk_based_diagnostics_progress: false,
9447 is_cancellable: payload.is_cancellable.unwrap_or(false),
9448 message: payload.message,
9449 percentage: payload.percentage.map(|p| p as usize),
9450 last_update_at: cx.background_executor().now(),
9451 },
9452 cx,
9453 );
9454 }
9455
9456 proto::update_language_server::Variant::WorkEnd(payload) => {
9457 lsp_store.on_lsp_work_end(
9458 language_server_id,
9459 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9460 .context("invalid progress token value")?,
9461 cx,
9462 );
9463 }
9464
9465 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9466 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9467 }
9468
9469 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9470 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9471 }
9472
9473 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9474 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9475 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9476 cx.emit(LspStoreEvent::LanguageServerUpdate {
9477 language_server_id,
9478 name: envelope
9479 .payload
9480 .server_name
9481 .map(SharedString::new)
9482 .map(LanguageServerName),
9483 message: non_lsp,
9484 });
9485 }
9486 }
9487
9488 Ok(())
9489 })?
9490 }
9491
9492 async fn handle_language_server_log(
9493 this: Entity<Self>,
9494 envelope: TypedEnvelope<proto::LanguageServerLog>,
9495 mut cx: AsyncApp,
9496 ) -> Result<()> {
9497 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9498 let log_type = envelope
9499 .payload
9500 .log_type
9501 .map(LanguageServerLogType::from_proto)
9502 .context("invalid language server log type")?;
9503
9504 let message = envelope.payload.message;
9505
9506 this.update(&mut cx, |_, cx| {
9507 cx.emit(LspStoreEvent::LanguageServerLog(
9508 language_server_id,
9509 log_type,
9510 message,
9511 ));
9512 })
9513 }
9514
9515 async fn handle_lsp_ext_cancel_flycheck(
9516 lsp_store: Entity<Self>,
9517 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9518 cx: AsyncApp,
9519 ) -> Result<proto::Ack> {
9520 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9521 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9522 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9523 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9524 } else {
9525 None
9526 }
9527 })?;
9528 if let Some(task) = task {
9529 task.context("handling lsp ext cancel flycheck")?;
9530 }
9531
9532 Ok(proto::Ack {})
9533 }
9534
9535 async fn handle_lsp_ext_run_flycheck(
9536 lsp_store: Entity<Self>,
9537 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9538 mut cx: AsyncApp,
9539 ) -> Result<proto::Ack> {
9540 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9541 lsp_store.update(&mut cx, |lsp_store, cx| {
9542 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9543 let text_document = if envelope.payload.current_file_only {
9544 let buffer_id = envelope
9545 .payload
9546 .buffer_id
9547 .map(|id| BufferId::new(id))
9548 .transpose()?;
9549 buffer_id
9550 .and_then(|buffer_id| {
9551 lsp_store
9552 .buffer_store()
9553 .read(cx)
9554 .get(buffer_id)
9555 .and_then(|buffer| {
9556 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9557 })
9558 .map(|path| make_text_document_identifier(&path))
9559 })
9560 .transpose()?
9561 } else {
9562 None
9563 };
9564 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9565 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9566 )?;
9567 }
9568 anyhow::Ok(())
9569 })??;
9570
9571 Ok(proto::Ack {})
9572 }
9573
9574 async fn handle_lsp_ext_clear_flycheck(
9575 lsp_store: Entity<Self>,
9576 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9577 cx: AsyncApp,
9578 ) -> Result<proto::Ack> {
9579 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9580 lsp_store
9581 .read_with(&cx, |lsp_store, _| {
9582 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9583 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9584 } else {
9585 None
9586 }
9587 })
9588 .context("handling lsp ext clear flycheck")?;
9589
9590 Ok(proto::Ack {})
9591 }
9592
9593 pub fn disk_based_diagnostics_started(
9594 &mut self,
9595 language_server_id: LanguageServerId,
9596 cx: &mut Context<Self>,
9597 ) {
9598 if let Some(language_server_status) =
9599 self.language_server_statuses.get_mut(&language_server_id)
9600 {
9601 language_server_status.has_pending_diagnostic_updates = true;
9602 }
9603
9604 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9605 cx.emit(LspStoreEvent::LanguageServerUpdate {
9606 language_server_id,
9607 name: self
9608 .language_server_adapter_for_id(language_server_id)
9609 .map(|adapter| adapter.name()),
9610 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9611 Default::default(),
9612 ),
9613 })
9614 }
9615
9616 pub fn disk_based_diagnostics_finished(
9617 &mut self,
9618 language_server_id: LanguageServerId,
9619 cx: &mut Context<Self>,
9620 ) {
9621 if let Some(language_server_status) =
9622 self.language_server_statuses.get_mut(&language_server_id)
9623 {
9624 language_server_status.has_pending_diagnostic_updates = false;
9625 }
9626
9627 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9628 cx.emit(LspStoreEvent::LanguageServerUpdate {
9629 language_server_id,
9630 name: self
9631 .language_server_adapter_for_id(language_server_id)
9632 .map(|adapter| adapter.name()),
9633 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9634 Default::default(),
9635 ),
9636 })
9637 }
9638
9639 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9640 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9641 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9642 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9643 // the language server might take some time to publish diagnostics.
9644 fn simulate_disk_based_diagnostics_events_if_needed(
9645 &mut self,
9646 language_server_id: LanguageServerId,
9647 cx: &mut Context<Self>,
9648 ) {
9649 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9650
9651 let Some(LanguageServerState::Running {
9652 simulate_disk_based_diagnostics_completion,
9653 adapter,
9654 ..
9655 }) = self
9656 .as_local_mut()
9657 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9658 else {
9659 return;
9660 };
9661
9662 if adapter.disk_based_diagnostics_progress_token.is_some() {
9663 return;
9664 }
9665
9666 let prev_task =
9667 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9668 cx.background_executor()
9669 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9670 .await;
9671
9672 this.update(cx, |this, cx| {
9673 this.disk_based_diagnostics_finished(language_server_id, cx);
9674
9675 if let Some(LanguageServerState::Running {
9676 simulate_disk_based_diagnostics_completion,
9677 ..
9678 }) = this.as_local_mut().and_then(|local_store| {
9679 local_store.language_servers.get_mut(&language_server_id)
9680 }) {
9681 *simulate_disk_based_diagnostics_completion = None;
9682 }
9683 })
9684 .ok();
9685 }));
9686
9687 if prev_task.is_none() {
9688 self.disk_based_diagnostics_started(language_server_id, cx);
9689 }
9690 }
9691
9692 pub fn language_server_statuses(
9693 &self,
9694 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9695 self.language_server_statuses
9696 .iter()
9697 .map(|(key, value)| (*key, value))
9698 }
9699
9700 pub(super) fn did_rename_entry(
9701 &self,
9702 worktree_id: WorktreeId,
9703 old_path: &Path,
9704 new_path: &Path,
9705 is_dir: bool,
9706 ) {
9707 maybe!({
9708 let local_store = self.as_local()?;
9709
9710 let old_uri = lsp::Uri::from_file_path(old_path)
9711 .ok()
9712 .map(|uri| uri.to_string())?;
9713 let new_uri = lsp::Uri::from_file_path(new_path)
9714 .ok()
9715 .map(|uri| uri.to_string())?;
9716
9717 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9718 let Some(filter) = local_store
9719 .language_server_paths_watched_for_rename
9720 .get(&language_server.server_id())
9721 else {
9722 continue;
9723 };
9724
9725 if filter.should_send_did_rename(&old_uri, is_dir) {
9726 language_server
9727 .notify::<DidRenameFiles>(RenameFilesParams {
9728 files: vec![FileRename {
9729 old_uri: old_uri.clone(),
9730 new_uri: new_uri.clone(),
9731 }],
9732 })
9733 .ok();
9734 }
9735 }
9736 Some(())
9737 });
9738 }
9739
9740 pub(super) fn will_rename_entry(
9741 this: WeakEntity<Self>,
9742 worktree_id: WorktreeId,
9743 old_path: &Path,
9744 new_path: &Path,
9745 is_dir: bool,
9746 cx: AsyncApp,
9747 ) -> Task<ProjectTransaction> {
9748 let old_uri = lsp::Uri::from_file_path(old_path)
9749 .ok()
9750 .map(|uri| uri.to_string());
9751 let new_uri = lsp::Uri::from_file_path(new_path)
9752 .ok()
9753 .map(|uri| uri.to_string());
9754 cx.spawn(async move |cx| {
9755 let mut tasks = vec![];
9756 this.update(cx, |this, cx| {
9757 let local_store = this.as_local()?;
9758 let old_uri = old_uri?;
9759 let new_uri = new_uri?;
9760 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9761 let Some(filter) = local_store
9762 .language_server_paths_watched_for_rename
9763 .get(&language_server.server_id())
9764 else {
9765 continue;
9766 };
9767
9768 if filter.should_send_will_rename(&old_uri, is_dir) {
9769 let apply_edit = cx.spawn({
9770 let old_uri = old_uri.clone();
9771 let new_uri = new_uri.clone();
9772 let language_server = language_server.clone();
9773 async move |this, cx| {
9774 let edit = language_server
9775 .request::<WillRenameFiles>(RenameFilesParams {
9776 files: vec![FileRename { old_uri, new_uri }],
9777 })
9778 .await
9779 .into_response()
9780 .context("will rename files")
9781 .log_err()
9782 .flatten()?;
9783
9784 let transaction = LocalLspStore::deserialize_workspace_edit(
9785 this.upgrade()?,
9786 edit,
9787 false,
9788 language_server.clone(),
9789 cx,
9790 )
9791 .await
9792 .ok()?;
9793 Some(transaction)
9794 }
9795 });
9796 tasks.push(apply_edit);
9797 }
9798 }
9799 Some(())
9800 })
9801 .ok()
9802 .flatten();
9803 let mut merged_transaction = ProjectTransaction::default();
9804 for task in tasks {
9805 // Await on tasks sequentially so that the order of application of edits is deterministic
9806 // (at least with regards to the order of registration of language servers)
9807 if let Some(transaction) = task.await {
9808 for (buffer, buffer_transaction) in transaction.0 {
9809 merged_transaction.0.insert(buffer, buffer_transaction);
9810 }
9811 }
9812 }
9813 merged_transaction
9814 })
9815 }
9816
9817 fn lsp_notify_abs_paths_changed(
9818 &mut self,
9819 server_id: LanguageServerId,
9820 changes: Vec<PathEvent>,
9821 ) {
9822 maybe!({
9823 let server = self.language_server_for_id(server_id)?;
9824 let changes = changes
9825 .into_iter()
9826 .filter_map(|event| {
9827 let typ = match event.kind? {
9828 PathEventKind::Created => lsp::FileChangeType::CREATED,
9829 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9830 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9831 };
9832 Some(lsp::FileEvent {
9833 uri: file_path_to_lsp_url(&event.path).log_err()?,
9834 typ,
9835 })
9836 })
9837 .collect::<Vec<_>>();
9838 if !changes.is_empty() {
9839 server
9840 .notify::<lsp::notification::DidChangeWatchedFiles>(
9841 lsp::DidChangeWatchedFilesParams { changes },
9842 )
9843 .ok();
9844 }
9845 Some(())
9846 });
9847 }
9848
9849 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9850 self.as_local()?.language_server_for_id(id)
9851 }
9852
9853 fn on_lsp_progress(
9854 &mut self,
9855 progress_params: lsp::ProgressParams,
9856 language_server_id: LanguageServerId,
9857 disk_based_diagnostics_progress_token: Option<String>,
9858 cx: &mut Context<Self>,
9859 ) {
9860 match progress_params.value {
9861 lsp::ProgressParamsValue::WorkDone(progress) => {
9862 self.handle_work_done_progress(
9863 progress,
9864 language_server_id,
9865 disk_based_diagnostics_progress_token,
9866 ProgressToken::from_lsp(progress_params.token),
9867 cx,
9868 );
9869 }
9870 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9871 let registration_id = match progress_params.token {
9872 lsp::NumberOrString::Number(_) => None,
9873 lsp::NumberOrString::String(token) => token
9874 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9875 .map(|(_, id)| id.to_owned()),
9876 };
9877 if let Some(LanguageServerState::Running {
9878 workspace_diagnostics_refresh_tasks,
9879 ..
9880 }) = self
9881 .as_local_mut()
9882 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9883 && let Some(workspace_diagnostics) =
9884 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9885 {
9886 workspace_diagnostics.progress_tx.try_send(()).ok();
9887 self.apply_workspace_diagnostic_report(
9888 language_server_id,
9889 report,
9890 registration_id.map(SharedString::from),
9891 cx,
9892 )
9893 }
9894 }
9895 }
9896 }
9897
9898 fn handle_work_done_progress(
9899 &mut self,
9900 progress: lsp::WorkDoneProgress,
9901 language_server_id: LanguageServerId,
9902 disk_based_diagnostics_progress_token: Option<String>,
9903 token: ProgressToken,
9904 cx: &mut Context<Self>,
9905 ) {
9906 let language_server_status =
9907 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9908 status
9909 } else {
9910 return;
9911 };
9912
9913 if !language_server_status.progress_tokens.contains(&token) {
9914 return;
9915 }
9916
9917 let is_disk_based_diagnostics_progress =
9918 if let (Some(disk_based_token), ProgressToken::String(token)) =
9919 (&disk_based_diagnostics_progress_token, &token)
9920 {
9921 token.starts_with(disk_based_token)
9922 } else {
9923 false
9924 };
9925
9926 match progress {
9927 lsp::WorkDoneProgress::Begin(report) => {
9928 if is_disk_based_diagnostics_progress {
9929 self.disk_based_diagnostics_started(language_server_id, cx);
9930 }
9931 self.on_lsp_work_start(
9932 language_server_id,
9933 token.clone(),
9934 LanguageServerProgress {
9935 title: Some(report.title),
9936 is_disk_based_diagnostics_progress,
9937 is_cancellable: report.cancellable.unwrap_or(false),
9938 message: report.message.clone(),
9939 percentage: report.percentage.map(|p| p as usize),
9940 last_update_at: cx.background_executor().now(),
9941 },
9942 cx,
9943 );
9944 }
9945 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9946 language_server_id,
9947 token,
9948 LanguageServerProgress {
9949 title: None,
9950 is_disk_based_diagnostics_progress,
9951 is_cancellable: report.cancellable.unwrap_or(false),
9952 message: report.message,
9953 percentage: report.percentage.map(|p| p as usize),
9954 last_update_at: cx.background_executor().now(),
9955 },
9956 cx,
9957 ),
9958 lsp::WorkDoneProgress::End(_) => {
9959 language_server_status.progress_tokens.remove(&token);
9960 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9961 if is_disk_based_diagnostics_progress {
9962 self.disk_based_diagnostics_finished(language_server_id, cx);
9963 }
9964 }
9965 }
9966 }
9967
9968 fn on_lsp_work_start(
9969 &mut self,
9970 language_server_id: LanguageServerId,
9971 token: ProgressToken,
9972 progress: LanguageServerProgress,
9973 cx: &mut Context<Self>,
9974 ) {
9975 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9976 status.pending_work.insert(token.clone(), progress.clone());
9977 cx.notify();
9978 }
9979 cx.emit(LspStoreEvent::LanguageServerUpdate {
9980 language_server_id,
9981 name: self
9982 .language_server_adapter_for_id(language_server_id)
9983 .map(|adapter| adapter.name()),
9984 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9985 token: Some(token.to_proto()),
9986 title: progress.title,
9987 message: progress.message,
9988 percentage: progress.percentage.map(|p| p as u32),
9989 is_cancellable: Some(progress.is_cancellable),
9990 }),
9991 })
9992 }
9993
9994 fn on_lsp_work_progress(
9995 &mut self,
9996 language_server_id: LanguageServerId,
9997 token: ProgressToken,
9998 progress: LanguageServerProgress,
9999 cx: &mut Context<Self>,
10000 ) {
10001 let mut did_update = false;
10002 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10003 match status.pending_work.entry(token.clone()) {
10004 btree_map::Entry::Vacant(entry) => {
10005 entry.insert(progress.clone());
10006 did_update = true;
10007 }
10008 btree_map::Entry::Occupied(mut entry) => {
10009 let entry = entry.get_mut();
10010 if (progress.last_update_at - entry.last_update_at)
10011 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10012 {
10013 entry.last_update_at = progress.last_update_at;
10014 if progress.message.is_some() {
10015 entry.message = progress.message.clone();
10016 }
10017 if progress.percentage.is_some() {
10018 entry.percentage = progress.percentage;
10019 }
10020 if progress.is_cancellable != entry.is_cancellable {
10021 entry.is_cancellable = progress.is_cancellable;
10022 }
10023 did_update = true;
10024 }
10025 }
10026 }
10027 }
10028
10029 if did_update {
10030 cx.emit(LspStoreEvent::LanguageServerUpdate {
10031 language_server_id,
10032 name: self
10033 .language_server_adapter_for_id(language_server_id)
10034 .map(|adapter| adapter.name()),
10035 message: proto::update_language_server::Variant::WorkProgress(
10036 proto::LspWorkProgress {
10037 token: Some(token.to_proto()),
10038 message: progress.message,
10039 percentage: progress.percentage.map(|p| p as u32),
10040 is_cancellable: Some(progress.is_cancellable),
10041 },
10042 ),
10043 })
10044 }
10045 }
10046
10047 fn on_lsp_work_end(
10048 &mut self,
10049 language_server_id: LanguageServerId,
10050 token: ProgressToken,
10051 cx: &mut Context<Self>,
10052 ) {
10053 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10054 if let Some(work) = status.pending_work.remove(&token)
10055 && !work.is_disk_based_diagnostics_progress
10056 {
10057 cx.emit(LspStoreEvent::RefreshInlayHints {
10058 server_id: language_server_id,
10059 request_id: None,
10060 });
10061 }
10062 cx.notify();
10063 }
10064
10065 cx.emit(LspStoreEvent::LanguageServerUpdate {
10066 language_server_id,
10067 name: self
10068 .language_server_adapter_for_id(language_server_id)
10069 .map(|adapter| adapter.name()),
10070 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10071 token: Some(token.to_proto()),
10072 }),
10073 })
10074 }
10075
10076 pub async fn handle_resolve_completion_documentation(
10077 this: Entity<Self>,
10078 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10079 mut cx: AsyncApp,
10080 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10081 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10082
10083 let completion = this
10084 .read_with(&cx, |this, cx| {
10085 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10086 let server = this
10087 .language_server_for_id(id)
10088 .with_context(|| format!("No language server {id}"))?;
10089
10090 anyhow::Ok(cx.background_spawn(async move {
10091 let can_resolve = server
10092 .capabilities()
10093 .completion_provider
10094 .as_ref()
10095 .and_then(|options| options.resolve_provider)
10096 .unwrap_or(false);
10097 if can_resolve {
10098 server
10099 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10100 .await
10101 .into_response()
10102 .context("resolve completion item")
10103 } else {
10104 anyhow::Ok(lsp_completion)
10105 }
10106 }))
10107 })??
10108 .await?;
10109
10110 let mut documentation_is_markdown = false;
10111 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10112 let documentation = match completion.documentation {
10113 Some(lsp::Documentation::String(text)) => text,
10114
10115 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10116 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10117 value
10118 }
10119
10120 _ => String::new(),
10121 };
10122
10123 // If we have a new buffer_id, that means we're talking to a new client
10124 // and want to check for new text_edits in the completion too.
10125 let mut old_replace_start = None;
10126 let mut old_replace_end = None;
10127 let mut old_insert_start = None;
10128 let mut old_insert_end = None;
10129 let mut new_text = String::default();
10130 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10131 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10132 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10133 anyhow::Ok(buffer.read(cx).snapshot())
10134 })??;
10135
10136 if let Some(text_edit) = completion.text_edit.as_ref() {
10137 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10138
10139 if let Some(mut edit) = edit {
10140 LineEnding::normalize(&mut edit.new_text);
10141
10142 new_text = edit.new_text;
10143 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10144 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10145 if let Some(insert_range) = edit.insert_range {
10146 old_insert_start = Some(serialize_anchor(&insert_range.start));
10147 old_insert_end = Some(serialize_anchor(&insert_range.end));
10148 }
10149 }
10150 }
10151 }
10152
10153 Ok(proto::ResolveCompletionDocumentationResponse {
10154 documentation,
10155 documentation_is_markdown,
10156 old_replace_start,
10157 old_replace_end,
10158 new_text,
10159 lsp_completion,
10160 old_insert_start,
10161 old_insert_end,
10162 })
10163 }
10164
10165 async fn handle_on_type_formatting(
10166 this: Entity<Self>,
10167 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10168 mut cx: AsyncApp,
10169 ) -> Result<proto::OnTypeFormattingResponse> {
10170 let on_type_formatting = this.update(&mut cx, |this, cx| {
10171 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10172 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10173 let position = envelope
10174 .payload
10175 .position
10176 .and_then(deserialize_anchor)
10177 .context("invalid position")?;
10178 anyhow::Ok(this.apply_on_type_formatting(
10179 buffer,
10180 position,
10181 envelope.payload.trigger.clone(),
10182 cx,
10183 ))
10184 })??;
10185
10186 let transaction = on_type_formatting
10187 .await?
10188 .as_ref()
10189 .map(language::proto::serialize_transaction);
10190 Ok(proto::OnTypeFormattingResponse { transaction })
10191 }
10192
10193 async fn handle_refresh_inlay_hints(
10194 lsp_store: Entity<Self>,
10195 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10196 mut cx: AsyncApp,
10197 ) -> Result<proto::Ack> {
10198 lsp_store.update(&mut cx, |_, cx| {
10199 cx.emit(LspStoreEvent::RefreshInlayHints {
10200 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10201 request_id: envelope.payload.request_id.map(|id| id as usize),
10202 });
10203 })?;
10204 Ok(proto::Ack {})
10205 }
10206
10207 async fn handle_pull_workspace_diagnostics(
10208 lsp_store: Entity<Self>,
10209 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10210 mut cx: AsyncApp,
10211 ) -> Result<proto::Ack> {
10212 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10213 lsp_store.update(&mut cx, |lsp_store, _| {
10214 lsp_store.pull_workspace_diagnostics(server_id);
10215 })?;
10216 Ok(proto::Ack {})
10217 }
10218
10219 async fn handle_get_color_presentation(
10220 lsp_store: Entity<Self>,
10221 envelope: TypedEnvelope<proto::GetColorPresentation>,
10222 mut cx: AsyncApp,
10223 ) -> Result<proto::GetColorPresentationResponse> {
10224 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10225 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10226 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10227 })??;
10228
10229 let color = envelope
10230 .payload
10231 .color
10232 .context("invalid color resolve request")?;
10233 let start = color
10234 .lsp_range_start
10235 .context("invalid color resolve request")?;
10236 let end = color
10237 .lsp_range_end
10238 .context("invalid color resolve request")?;
10239
10240 let color = DocumentColor {
10241 lsp_range: lsp::Range {
10242 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10243 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10244 },
10245 color: lsp::Color {
10246 red: color.red,
10247 green: color.green,
10248 blue: color.blue,
10249 alpha: color.alpha,
10250 },
10251 resolved: false,
10252 color_presentations: Vec::new(),
10253 };
10254 let resolved_color = lsp_store
10255 .update(&mut cx, |lsp_store, cx| {
10256 lsp_store.resolve_color_presentation(
10257 color,
10258 buffer.clone(),
10259 LanguageServerId(envelope.payload.server_id as usize),
10260 cx,
10261 )
10262 })?
10263 .await
10264 .context("resolving color presentation")?;
10265
10266 Ok(proto::GetColorPresentationResponse {
10267 presentations: resolved_color
10268 .color_presentations
10269 .into_iter()
10270 .map(|presentation| proto::ColorPresentation {
10271 label: presentation.label.to_string(),
10272 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10273 additional_text_edits: presentation
10274 .additional_text_edits
10275 .into_iter()
10276 .map(serialize_lsp_edit)
10277 .collect(),
10278 })
10279 .collect(),
10280 })
10281 }
10282
10283 async fn handle_resolve_inlay_hint(
10284 lsp_store: Entity<Self>,
10285 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10286 mut cx: AsyncApp,
10287 ) -> Result<proto::ResolveInlayHintResponse> {
10288 let proto_hint = envelope
10289 .payload
10290 .hint
10291 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10292 let hint = InlayHints::proto_to_project_hint(proto_hint)
10293 .context("resolved proto inlay hint conversion")?;
10294 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10295 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10296 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10297 })??;
10298 let response_hint = lsp_store
10299 .update(&mut cx, |lsp_store, cx| {
10300 lsp_store.resolve_inlay_hint(
10301 hint,
10302 buffer,
10303 LanguageServerId(envelope.payload.language_server_id as usize),
10304 cx,
10305 )
10306 })?
10307 .await
10308 .context("inlay hints fetch")?;
10309 Ok(proto::ResolveInlayHintResponse {
10310 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10311 })
10312 }
10313
10314 async fn handle_refresh_code_lens(
10315 this: Entity<Self>,
10316 _: TypedEnvelope<proto::RefreshCodeLens>,
10317 mut cx: AsyncApp,
10318 ) -> Result<proto::Ack> {
10319 this.update(&mut cx, |_, cx| {
10320 cx.emit(LspStoreEvent::RefreshCodeLens);
10321 })?;
10322 Ok(proto::Ack {})
10323 }
10324
10325 async fn handle_open_buffer_for_symbol(
10326 this: Entity<Self>,
10327 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10328 mut cx: AsyncApp,
10329 ) -> Result<proto::OpenBufferForSymbolResponse> {
10330 let peer_id = envelope.original_sender_id().unwrap_or_default();
10331 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10332 let symbol = Self::deserialize_symbol(symbol)?;
10333 this.read_with(&cx, |this, _| {
10334 if let SymbolLocation::OutsideProject {
10335 abs_path,
10336 signature,
10337 } = &symbol.path
10338 {
10339 let new_signature = this.symbol_signature(&abs_path);
10340 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10341 }
10342 Ok(())
10343 })??;
10344 let buffer = this
10345 .update(&mut cx, |this, cx| {
10346 this.open_buffer_for_symbol(
10347 &Symbol {
10348 language_server_name: symbol.language_server_name,
10349 source_worktree_id: symbol.source_worktree_id,
10350 source_language_server_id: symbol.source_language_server_id,
10351 path: symbol.path,
10352 name: symbol.name,
10353 kind: symbol.kind,
10354 range: symbol.range,
10355 label: CodeLabel::default(),
10356 },
10357 cx,
10358 )
10359 })?
10360 .await?;
10361
10362 this.update(&mut cx, |this, cx| {
10363 let is_private = buffer
10364 .read(cx)
10365 .file()
10366 .map(|f| f.is_private())
10367 .unwrap_or_default();
10368 if is_private {
10369 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10370 } else {
10371 this.buffer_store
10372 .update(cx, |buffer_store, cx| {
10373 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10374 })
10375 .detach_and_log_err(cx);
10376 let buffer_id = buffer.read(cx).remote_id().to_proto();
10377 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10378 }
10379 })?
10380 }
10381
10382 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10383 let mut hasher = Sha256::new();
10384 hasher.update(abs_path.to_string_lossy().as_bytes());
10385 hasher.update(self.nonce.to_be_bytes());
10386 hasher.finalize().as_slice().try_into().unwrap()
10387 }
10388
10389 pub async fn handle_get_project_symbols(
10390 this: Entity<Self>,
10391 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10392 mut cx: AsyncApp,
10393 ) -> Result<proto::GetProjectSymbolsResponse> {
10394 let symbols = this
10395 .update(&mut cx, |this, cx| {
10396 this.symbols(&envelope.payload.query, cx)
10397 })?
10398 .await?;
10399
10400 Ok(proto::GetProjectSymbolsResponse {
10401 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10402 })
10403 }
10404
10405 pub async fn handle_restart_language_servers(
10406 this: Entity<Self>,
10407 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10408 mut cx: AsyncApp,
10409 ) -> Result<proto::Ack> {
10410 this.update(&mut cx, |lsp_store, cx| {
10411 let buffers =
10412 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10413 lsp_store.restart_language_servers_for_buffers(
10414 buffers,
10415 envelope
10416 .payload
10417 .only_servers
10418 .into_iter()
10419 .filter_map(|selector| {
10420 Some(match selector.selector? {
10421 proto::language_server_selector::Selector::ServerId(server_id) => {
10422 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10423 }
10424 proto::language_server_selector::Selector::Name(name) => {
10425 LanguageServerSelector::Name(LanguageServerName(
10426 SharedString::from(name),
10427 ))
10428 }
10429 })
10430 })
10431 .collect(),
10432 cx,
10433 );
10434 })?;
10435
10436 Ok(proto::Ack {})
10437 }
10438
10439 pub async fn handle_stop_language_servers(
10440 lsp_store: Entity<Self>,
10441 envelope: TypedEnvelope<proto::StopLanguageServers>,
10442 mut cx: AsyncApp,
10443 ) -> Result<proto::Ack> {
10444 lsp_store.update(&mut cx, |lsp_store, cx| {
10445 if envelope.payload.all
10446 && envelope.payload.also_servers.is_empty()
10447 && envelope.payload.buffer_ids.is_empty()
10448 {
10449 lsp_store.stop_all_language_servers(cx);
10450 } else {
10451 let buffers =
10452 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10453 lsp_store
10454 .stop_language_servers_for_buffers(
10455 buffers,
10456 envelope
10457 .payload
10458 .also_servers
10459 .into_iter()
10460 .filter_map(|selector| {
10461 Some(match selector.selector? {
10462 proto::language_server_selector::Selector::ServerId(
10463 server_id,
10464 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10465 server_id,
10466 )),
10467 proto::language_server_selector::Selector::Name(name) => {
10468 LanguageServerSelector::Name(LanguageServerName(
10469 SharedString::from(name),
10470 ))
10471 }
10472 })
10473 })
10474 .collect(),
10475 cx,
10476 )
10477 .detach_and_log_err(cx);
10478 }
10479 })?;
10480
10481 Ok(proto::Ack {})
10482 }
10483
10484 pub async fn handle_cancel_language_server_work(
10485 lsp_store: Entity<Self>,
10486 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10487 mut cx: AsyncApp,
10488 ) -> Result<proto::Ack> {
10489 lsp_store.update(&mut cx, |lsp_store, cx| {
10490 if let Some(work) = envelope.payload.work {
10491 match work {
10492 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10493 let buffers =
10494 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10495 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10496 }
10497 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10498 let server_id = LanguageServerId::from_proto(work.language_server_id);
10499 let token = work
10500 .token
10501 .map(|token| {
10502 ProgressToken::from_proto(token)
10503 .context("invalid work progress token")
10504 })
10505 .transpose()?;
10506 lsp_store.cancel_language_server_work(server_id, token, cx);
10507 }
10508 }
10509 }
10510 anyhow::Ok(())
10511 })??;
10512
10513 Ok(proto::Ack {})
10514 }
10515
10516 fn buffer_ids_to_buffers(
10517 &mut self,
10518 buffer_ids: impl Iterator<Item = u64>,
10519 cx: &mut Context<Self>,
10520 ) -> Vec<Entity<Buffer>> {
10521 buffer_ids
10522 .into_iter()
10523 .flat_map(|buffer_id| {
10524 self.buffer_store
10525 .read(cx)
10526 .get(BufferId::new(buffer_id).log_err()?)
10527 })
10528 .collect::<Vec<_>>()
10529 }
10530
10531 async fn handle_apply_additional_edits_for_completion(
10532 this: Entity<Self>,
10533 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10534 mut cx: AsyncApp,
10535 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10536 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10537 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10538 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10539 let completion = Self::deserialize_completion(
10540 envelope.payload.completion.context("invalid completion")?,
10541 )?;
10542 anyhow::Ok((buffer, completion))
10543 })??;
10544
10545 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10546 this.apply_additional_edits_for_completion(
10547 buffer,
10548 Rc::new(RefCell::new(Box::new([Completion {
10549 replace_range: completion.replace_range,
10550 new_text: completion.new_text,
10551 source: completion.source,
10552 documentation: None,
10553 label: CodeLabel::default(),
10554 match_start: None,
10555 snippet_deduplication_key: None,
10556 insert_text_mode: None,
10557 icon_path: None,
10558 confirm: None,
10559 }]))),
10560 0,
10561 false,
10562 cx,
10563 )
10564 })?;
10565
10566 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10567 transaction: apply_additional_edits
10568 .await?
10569 .as_ref()
10570 .map(language::proto::serialize_transaction),
10571 })
10572 }
10573
10574 pub fn last_formatting_failure(&self) -> Option<&str> {
10575 self.last_formatting_failure.as_deref()
10576 }
10577
10578 pub fn reset_last_formatting_failure(&mut self) {
10579 self.last_formatting_failure = None;
10580 }
10581
10582 pub fn environment_for_buffer(
10583 &self,
10584 buffer: &Entity<Buffer>,
10585 cx: &mut Context<Self>,
10586 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10587 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10588 environment.update(cx, |env, cx| {
10589 env.buffer_environment(buffer, &self.worktree_store, cx)
10590 })
10591 } else {
10592 Task::ready(None).shared()
10593 }
10594 }
10595
10596 pub fn format(
10597 &mut self,
10598 buffers: HashSet<Entity<Buffer>>,
10599 target: LspFormatTarget,
10600 push_to_history: bool,
10601 trigger: FormatTrigger,
10602 cx: &mut Context<Self>,
10603 ) -> Task<anyhow::Result<ProjectTransaction>> {
10604 let logger = zlog::scoped!("format");
10605 if self.as_local().is_some() {
10606 zlog::trace!(logger => "Formatting locally");
10607 let logger = zlog::scoped!(logger => "local");
10608 let buffers = buffers
10609 .into_iter()
10610 .map(|buffer_handle| {
10611 let buffer = buffer_handle.read(cx);
10612 let buffer_abs_path = File::from_dyn(buffer.file())
10613 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10614
10615 (buffer_handle, buffer_abs_path, buffer.remote_id())
10616 })
10617 .collect::<Vec<_>>();
10618
10619 cx.spawn(async move |lsp_store, cx| {
10620 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10621
10622 for (handle, abs_path, id) in buffers {
10623 let env = lsp_store
10624 .update(cx, |lsp_store, cx| {
10625 lsp_store.environment_for_buffer(&handle, cx)
10626 })?
10627 .await;
10628
10629 let ranges = match &target {
10630 LspFormatTarget::Buffers => None,
10631 LspFormatTarget::Ranges(ranges) => {
10632 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10633 }
10634 };
10635
10636 formattable_buffers.push(FormattableBuffer {
10637 handle,
10638 abs_path,
10639 env,
10640 ranges,
10641 });
10642 }
10643 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10644
10645 let format_timer = zlog::time!(logger => "Formatting buffers");
10646 let result = LocalLspStore::format_locally(
10647 lsp_store.clone(),
10648 formattable_buffers,
10649 push_to_history,
10650 trigger,
10651 logger,
10652 cx,
10653 )
10654 .await;
10655 format_timer.end();
10656
10657 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10658
10659 lsp_store.update(cx, |lsp_store, _| {
10660 lsp_store.update_last_formatting_failure(&result);
10661 })?;
10662
10663 result
10664 })
10665 } else if let Some((client, project_id)) = self.upstream_client() {
10666 zlog::trace!(logger => "Formatting remotely");
10667 let logger = zlog::scoped!(logger => "remote");
10668 // Don't support formatting ranges via remote
10669 match target {
10670 LspFormatTarget::Buffers => {}
10671 LspFormatTarget::Ranges(_) => {
10672 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10673 return Task::ready(Ok(ProjectTransaction::default()));
10674 }
10675 }
10676
10677 let buffer_store = self.buffer_store();
10678 cx.spawn(async move |lsp_store, cx| {
10679 zlog::trace!(logger => "Sending remote format request");
10680 let request_timer = zlog::time!(logger => "remote format request");
10681 let result = client
10682 .request(proto::FormatBuffers {
10683 project_id,
10684 trigger: trigger as i32,
10685 buffer_ids: buffers
10686 .iter()
10687 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10688 .collect::<Result<_>>()?,
10689 })
10690 .await
10691 .and_then(|result| result.transaction.context("missing transaction"));
10692 request_timer.end();
10693
10694 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10695
10696 lsp_store.update(cx, |lsp_store, _| {
10697 lsp_store.update_last_formatting_failure(&result);
10698 })?;
10699
10700 let transaction_response = result?;
10701 let _timer = zlog::time!(logger => "deserializing project transaction");
10702 buffer_store
10703 .update(cx, |buffer_store, cx| {
10704 buffer_store.deserialize_project_transaction(
10705 transaction_response,
10706 push_to_history,
10707 cx,
10708 )
10709 })?
10710 .await
10711 })
10712 } else {
10713 zlog::trace!(logger => "Not formatting");
10714 Task::ready(Ok(ProjectTransaction::default()))
10715 }
10716 }
10717
10718 async fn handle_format_buffers(
10719 this: Entity<Self>,
10720 envelope: TypedEnvelope<proto::FormatBuffers>,
10721 mut cx: AsyncApp,
10722 ) -> Result<proto::FormatBuffersResponse> {
10723 let sender_id = envelope.original_sender_id().unwrap_or_default();
10724 let format = this.update(&mut cx, |this, cx| {
10725 let mut buffers = HashSet::default();
10726 for buffer_id in &envelope.payload.buffer_ids {
10727 let buffer_id = BufferId::new(*buffer_id)?;
10728 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10729 }
10730 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10731 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10732 })??;
10733
10734 let project_transaction = format.await?;
10735 let project_transaction = this.update(&mut cx, |this, cx| {
10736 this.buffer_store.update(cx, |buffer_store, cx| {
10737 buffer_store.serialize_project_transaction_for_peer(
10738 project_transaction,
10739 sender_id,
10740 cx,
10741 )
10742 })
10743 })?;
10744 Ok(proto::FormatBuffersResponse {
10745 transaction: Some(project_transaction),
10746 })
10747 }
10748
10749 async fn handle_apply_code_action_kind(
10750 this: Entity<Self>,
10751 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10752 mut cx: AsyncApp,
10753 ) -> Result<proto::ApplyCodeActionKindResponse> {
10754 let sender_id = envelope.original_sender_id().unwrap_or_default();
10755 let format = this.update(&mut cx, |this, cx| {
10756 let mut buffers = HashSet::default();
10757 for buffer_id in &envelope.payload.buffer_ids {
10758 let buffer_id = BufferId::new(*buffer_id)?;
10759 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10760 }
10761 let kind = match envelope.payload.kind.as_str() {
10762 "" => CodeActionKind::EMPTY,
10763 "quickfix" => CodeActionKind::QUICKFIX,
10764 "refactor" => CodeActionKind::REFACTOR,
10765 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10766 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10767 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10768 "source" => CodeActionKind::SOURCE,
10769 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10770 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10771 _ => anyhow::bail!(
10772 "Invalid code action kind {}",
10773 envelope.payload.kind.as_str()
10774 ),
10775 };
10776 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10777 })??;
10778
10779 let project_transaction = format.await?;
10780 let project_transaction = this.update(&mut cx, |this, cx| {
10781 this.buffer_store.update(cx, |buffer_store, cx| {
10782 buffer_store.serialize_project_transaction_for_peer(
10783 project_transaction,
10784 sender_id,
10785 cx,
10786 )
10787 })
10788 })?;
10789 Ok(proto::ApplyCodeActionKindResponse {
10790 transaction: Some(project_transaction),
10791 })
10792 }
10793
10794 async fn shutdown_language_server(
10795 server_state: Option<LanguageServerState>,
10796 name: LanguageServerName,
10797 cx: &mut AsyncApp,
10798 ) {
10799 let server = match server_state {
10800 Some(LanguageServerState::Starting { startup, .. }) => {
10801 let mut timer = cx
10802 .background_executor()
10803 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10804 .fuse();
10805
10806 select! {
10807 server = startup.fuse() => server,
10808 () = timer => {
10809 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10810 None
10811 },
10812 }
10813 }
10814
10815 Some(LanguageServerState::Running { server, .. }) => Some(server),
10816
10817 None => None,
10818 };
10819
10820 if let Some(server) = server
10821 && let Some(shutdown) = server.shutdown()
10822 {
10823 shutdown.await;
10824 }
10825 }
10826
10827 // Returns a list of all of the worktrees which no longer have a language server and the root path
10828 // for the stopped server
10829 fn stop_local_language_server(
10830 &mut self,
10831 server_id: LanguageServerId,
10832 cx: &mut Context<Self>,
10833 ) -> Task<()> {
10834 let local = match &mut self.mode {
10835 LspStoreMode::Local(local) => local,
10836 _ => {
10837 return Task::ready(());
10838 }
10839 };
10840
10841 // Remove this server ID from all entries in the given worktree.
10842 local
10843 .language_server_ids
10844 .retain(|_, state| state.id != server_id);
10845 self.buffer_store.update(cx, |buffer_store, cx| {
10846 for buffer in buffer_store.buffers() {
10847 buffer.update(cx, |buffer, cx| {
10848 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10849 buffer.set_completion_triggers(server_id, Default::default(), cx);
10850 });
10851 }
10852 });
10853
10854 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10855 summaries.retain(|path, summaries_by_server_id| {
10856 if summaries_by_server_id.remove(&server_id).is_some() {
10857 if let Some((client, project_id)) = self.downstream_client.clone() {
10858 client
10859 .send(proto::UpdateDiagnosticSummary {
10860 project_id,
10861 worktree_id: worktree_id.to_proto(),
10862 summary: Some(proto::DiagnosticSummary {
10863 path: path.as_ref().to_proto(),
10864 language_server_id: server_id.0 as u64,
10865 error_count: 0,
10866 warning_count: 0,
10867 }),
10868 more_summaries: Vec::new(),
10869 })
10870 .log_err();
10871 }
10872 !summaries_by_server_id.is_empty()
10873 } else {
10874 true
10875 }
10876 });
10877 }
10878
10879 let local = self.as_local_mut().unwrap();
10880 for diagnostics in local.diagnostics.values_mut() {
10881 diagnostics.retain(|_, diagnostics_by_server_id| {
10882 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10883 diagnostics_by_server_id.remove(ix);
10884 !diagnostics_by_server_id.is_empty()
10885 } else {
10886 true
10887 }
10888 });
10889 }
10890 local.language_server_watched_paths.remove(&server_id);
10891
10892 let server_state = local.language_servers.remove(&server_id);
10893 self.cleanup_lsp_data(server_id);
10894 let name = self
10895 .language_server_statuses
10896 .remove(&server_id)
10897 .map(|status| status.name)
10898 .or_else(|| {
10899 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10900 Some(adapter.name())
10901 } else {
10902 None
10903 }
10904 });
10905
10906 if let Some(name) = name {
10907 log::info!("stopping language server {name}");
10908 self.languages
10909 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10910 cx.notify();
10911
10912 return cx.spawn(async move |lsp_store, cx| {
10913 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10914 lsp_store
10915 .update(cx, |lsp_store, cx| {
10916 lsp_store
10917 .languages
10918 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10919 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10920 cx.notify();
10921 })
10922 .ok();
10923 });
10924 }
10925
10926 if server_state.is_some() {
10927 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10928 }
10929 Task::ready(())
10930 }
10931
10932 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10933 if let Some((client, project_id)) = self.upstream_client() {
10934 let request = client.request(proto::StopLanguageServers {
10935 project_id,
10936 buffer_ids: Vec::new(),
10937 also_servers: Vec::new(),
10938 all: true,
10939 });
10940 cx.background_spawn(request).detach_and_log_err(cx);
10941 } else {
10942 let Some(local) = self.as_local_mut() else {
10943 return;
10944 };
10945 let language_servers_to_stop = local
10946 .language_server_ids
10947 .values()
10948 .map(|state| state.id)
10949 .collect();
10950 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10951 let tasks = language_servers_to_stop
10952 .into_iter()
10953 .map(|server| self.stop_local_language_server(server, cx))
10954 .collect::<Vec<_>>();
10955 cx.background_spawn(async move {
10956 futures::future::join_all(tasks).await;
10957 })
10958 .detach();
10959 }
10960 }
10961
10962 pub fn restart_language_servers_for_buffers(
10963 &mut self,
10964 buffers: Vec<Entity<Buffer>>,
10965 only_restart_servers: HashSet<LanguageServerSelector>,
10966 cx: &mut Context<Self>,
10967 ) {
10968 if let Some((client, project_id)) = self.upstream_client() {
10969 let request = client.request(proto::RestartLanguageServers {
10970 project_id,
10971 buffer_ids: buffers
10972 .into_iter()
10973 .map(|b| b.read(cx).remote_id().to_proto())
10974 .collect(),
10975 only_servers: only_restart_servers
10976 .into_iter()
10977 .map(|selector| {
10978 let selector = match selector {
10979 LanguageServerSelector::Id(language_server_id) => {
10980 proto::language_server_selector::Selector::ServerId(
10981 language_server_id.to_proto(),
10982 )
10983 }
10984 LanguageServerSelector::Name(language_server_name) => {
10985 proto::language_server_selector::Selector::Name(
10986 language_server_name.to_string(),
10987 )
10988 }
10989 };
10990 proto::LanguageServerSelector {
10991 selector: Some(selector),
10992 }
10993 })
10994 .collect(),
10995 all: false,
10996 });
10997 cx.background_spawn(request).detach_and_log_err(cx);
10998 } else {
10999 let stop_task = if only_restart_servers.is_empty() {
11000 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11001 } else {
11002 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11003 };
11004 cx.spawn(async move |lsp_store, cx| {
11005 stop_task.await;
11006 lsp_store
11007 .update(cx, |lsp_store, cx| {
11008 for buffer in buffers {
11009 lsp_store.register_buffer_with_language_servers(
11010 &buffer,
11011 only_restart_servers.clone(),
11012 true,
11013 cx,
11014 );
11015 }
11016 })
11017 .ok()
11018 })
11019 .detach();
11020 }
11021 }
11022
11023 pub fn stop_language_servers_for_buffers(
11024 &mut self,
11025 buffers: Vec<Entity<Buffer>>,
11026 also_stop_servers: HashSet<LanguageServerSelector>,
11027 cx: &mut Context<Self>,
11028 ) -> Task<Result<()>> {
11029 if let Some((client, project_id)) = self.upstream_client() {
11030 let request = client.request(proto::StopLanguageServers {
11031 project_id,
11032 buffer_ids: buffers
11033 .into_iter()
11034 .map(|b| b.read(cx).remote_id().to_proto())
11035 .collect(),
11036 also_servers: also_stop_servers
11037 .into_iter()
11038 .map(|selector| {
11039 let selector = match selector {
11040 LanguageServerSelector::Id(language_server_id) => {
11041 proto::language_server_selector::Selector::ServerId(
11042 language_server_id.to_proto(),
11043 )
11044 }
11045 LanguageServerSelector::Name(language_server_name) => {
11046 proto::language_server_selector::Selector::Name(
11047 language_server_name.to_string(),
11048 )
11049 }
11050 };
11051 proto::LanguageServerSelector {
11052 selector: Some(selector),
11053 }
11054 })
11055 .collect(),
11056 all: false,
11057 });
11058 cx.background_spawn(async move {
11059 let _ = request.await?;
11060 Ok(())
11061 })
11062 } else {
11063 let task =
11064 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11065 cx.background_spawn(async move {
11066 task.await;
11067 Ok(())
11068 })
11069 }
11070 }
11071
11072 fn stop_local_language_servers_for_buffers(
11073 &mut self,
11074 buffers: &[Entity<Buffer>],
11075 also_stop_servers: HashSet<LanguageServerSelector>,
11076 cx: &mut Context<Self>,
11077 ) -> Task<()> {
11078 let Some(local) = self.as_local_mut() else {
11079 return Task::ready(());
11080 };
11081 let mut language_server_names_to_stop = BTreeSet::default();
11082 let mut language_servers_to_stop = also_stop_servers
11083 .into_iter()
11084 .flat_map(|selector| match selector {
11085 LanguageServerSelector::Id(id) => Some(id),
11086 LanguageServerSelector::Name(name) => {
11087 language_server_names_to_stop.insert(name);
11088 None
11089 }
11090 })
11091 .collect::<BTreeSet<_>>();
11092
11093 let mut covered_worktrees = HashSet::default();
11094 for buffer in buffers {
11095 buffer.update(cx, |buffer, cx| {
11096 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11097 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11098 && covered_worktrees.insert(worktree_id)
11099 {
11100 language_server_names_to_stop.retain(|name| {
11101 let old_ids_count = language_servers_to_stop.len();
11102 let all_language_servers_with_this_name = local
11103 .language_server_ids
11104 .iter()
11105 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11106 language_servers_to_stop.extend(all_language_servers_with_this_name);
11107 old_ids_count == language_servers_to_stop.len()
11108 });
11109 }
11110 });
11111 }
11112 for name in language_server_names_to_stop {
11113 language_servers_to_stop.extend(
11114 local
11115 .language_server_ids
11116 .iter()
11117 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11118 );
11119 }
11120
11121 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11122 let tasks = language_servers_to_stop
11123 .into_iter()
11124 .map(|server| self.stop_local_language_server(server, cx))
11125 .collect::<Vec<_>>();
11126
11127 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11128 }
11129
11130 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11131 let (worktree, relative_path) =
11132 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11133
11134 let project_path = ProjectPath {
11135 worktree_id: worktree.read(cx).id(),
11136 path: relative_path,
11137 };
11138
11139 Some(
11140 self.buffer_store()
11141 .read(cx)
11142 .get_by_path(&project_path)?
11143 .read(cx),
11144 )
11145 }
11146
11147 #[cfg(any(test, feature = "test-support"))]
11148 pub fn update_diagnostics(
11149 &mut self,
11150 server_id: LanguageServerId,
11151 diagnostics: lsp::PublishDiagnosticsParams,
11152 result_id: Option<SharedString>,
11153 source_kind: DiagnosticSourceKind,
11154 disk_based_sources: &[String],
11155 cx: &mut Context<Self>,
11156 ) -> Result<()> {
11157 self.merge_lsp_diagnostics(
11158 source_kind,
11159 vec![DocumentDiagnosticsUpdate {
11160 diagnostics,
11161 result_id,
11162 server_id,
11163 disk_based_sources: Cow::Borrowed(disk_based_sources),
11164 registration_id: None,
11165 }],
11166 |_, _, _| false,
11167 cx,
11168 )
11169 }
11170
11171 pub fn merge_lsp_diagnostics(
11172 &mut self,
11173 source_kind: DiagnosticSourceKind,
11174 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11175 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11176 cx: &mut Context<Self>,
11177 ) -> Result<()> {
11178 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11179 let updates = lsp_diagnostics
11180 .into_iter()
11181 .filter_map(|update| {
11182 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11183 Some(DocumentDiagnosticsUpdate {
11184 diagnostics: self.lsp_to_document_diagnostics(
11185 abs_path,
11186 source_kind,
11187 update.server_id,
11188 update.diagnostics,
11189 &update.disk_based_sources,
11190 update.registration_id.clone(),
11191 ),
11192 result_id: update.result_id,
11193 server_id: update.server_id,
11194 disk_based_sources: update.disk_based_sources,
11195 registration_id: update.registration_id,
11196 })
11197 })
11198 .collect();
11199 self.merge_diagnostic_entries(updates, merge, cx)?;
11200 Ok(())
11201 }
11202
11203 fn lsp_to_document_diagnostics(
11204 &mut self,
11205 document_abs_path: PathBuf,
11206 source_kind: DiagnosticSourceKind,
11207 server_id: LanguageServerId,
11208 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11209 disk_based_sources: &[String],
11210 registration_id: Option<SharedString>,
11211 ) -> DocumentDiagnostics {
11212 let mut diagnostics = Vec::default();
11213 let mut primary_diagnostic_group_ids = HashMap::default();
11214 let mut sources_by_group_id = HashMap::default();
11215 let mut supporting_diagnostics = HashMap::default();
11216
11217 let adapter = self.language_server_adapter_for_id(server_id);
11218
11219 // Ensure that primary diagnostics are always the most severe
11220 lsp_diagnostics
11221 .diagnostics
11222 .sort_by_key(|item| item.severity);
11223
11224 for diagnostic in &lsp_diagnostics.diagnostics {
11225 let source = diagnostic.source.as_ref();
11226 let range = range_from_lsp(diagnostic.range);
11227 let is_supporting = diagnostic
11228 .related_information
11229 .as_ref()
11230 .is_some_and(|infos| {
11231 infos.iter().any(|info| {
11232 primary_diagnostic_group_ids.contains_key(&(
11233 source,
11234 diagnostic.code.clone(),
11235 range_from_lsp(info.location.range),
11236 ))
11237 })
11238 });
11239
11240 let is_unnecessary = diagnostic
11241 .tags
11242 .as_ref()
11243 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11244
11245 let underline = self
11246 .language_server_adapter_for_id(server_id)
11247 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11248
11249 if is_supporting {
11250 supporting_diagnostics.insert(
11251 (source, diagnostic.code.clone(), range),
11252 (diagnostic.severity, is_unnecessary),
11253 );
11254 } else {
11255 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11256 let is_disk_based =
11257 source.is_some_and(|source| disk_based_sources.contains(source));
11258
11259 sources_by_group_id.insert(group_id, source);
11260 primary_diagnostic_group_ids
11261 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11262
11263 diagnostics.push(DiagnosticEntry {
11264 range,
11265 diagnostic: Diagnostic {
11266 source: diagnostic.source.clone(),
11267 source_kind,
11268 code: diagnostic.code.clone(),
11269 code_description: diagnostic
11270 .code_description
11271 .as_ref()
11272 .and_then(|d| d.href.clone()),
11273 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11274 markdown: adapter.as_ref().and_then(|adapter| {
11275 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11276 }),
11277 message: diagnostic.message.trim().to_string(),
11278 group_id,
11279 is_primary: true,
11280 is_disk_based,
11281 is_unnecessary,
11282 underline,
11283 data: diagnostic.data.clone(),
11284 registration_id: registration_id.clone(),
11285 },
11286 });
11287 if let Some(infos) = &diagnostic.related_information {
11288 for info in infos {
11289 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11290 let range = range_from_lsp(info.location.range);
11291 diagnostics.push(DiagnosticEntry {
11292 range,
11293 diagnostic: Diagnostic {
11294 source: diagnostic.source.clone(),
11295 source_kind,
11296 code: diagnostic.code.clone(),
11297 code_description: diagnostic
11298 .code_description
11299 .as_ref()
11300 .and_then(|d| d.href.clone()),
11301 severity: DiagnosticSeverity::INFORMATION,
11302 markdown: adapter.as_ref().and_then(|adapter| {
11303 adapter.diagnostic_message_to_markdown(&info.message)
11304 }),
11305 message: info.message.trim().to_string(),
11306 group_id,
11307 is_primary: false,
11308 is_disk_based,
11309 is_unnecessary: false,
11310 underline,
11311 data: diagnostic.data.clone(),
11312 registration_id: registration_id.clone(),
11313 },
11314 });
11315 }
11316 }
11317 }
11318 }
11319 }
11320
11321 for entry in &mut diagnostics {
11322 let diagnostic = &mut entry.diagnostic;
11323 if !diagnostic.is_primary {
11324 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11325 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11326 source,
11327 diagnostic.code.clone(),
11328 entry.range.clone(),
11329 )) {
11330 if let Some(severity) = severity {
11331 diagnostic.severity = severity;
11332 }
11333 diagnostic.is_unnecessary = is_unnecessary;
11334 }
11335 }
11336 }
11337
11338 DocumentDiagnostics {
11339 diagnostics,
11340 document_abs_path,
11341 version: lsp_diagnostics.version,
11342 }
11343 }
11344
11345 fn insert_newly_running_language_server(
11346 &mut self,
11347 adapter: Arc<CachedLspAdapter>,
11348 language_server: Arc<LanguageServer>,
11349 server_id: LanguageServerId,
11350 key: LanguageServerSeed,
11351 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11352 cx: &mut Context<Self>,
11353 ) {
11354 let Some(local) = self.as_local_mut() else {
11355 return;
11356 };
11357 // If the language server for this key doesn't match the server id, don't store the
11358 // server. Which will cause it to be dropped, killing the process
11359 if local
11360 .language_server_ids
11361 .get(&key)
11362 .map(|state| state.id != server_id)
11363 .unwrap_or(false)
11364 {
11365 return;
11366 }
11367
11368 // Update language_servers collection with Running variant of LanguageServerState
11369 // indicating that the server is up and running and ready
11370 let workspace_folders = workspace_folders.lock().clone();
11371 language_server.set_workspace_folders(workspace_folders);
11372
11373 let workspace_diagnostics_refresh_tasks = language_server
11374 .capabilities()
11375 .diagnostic_provider
11376 .and_then(|provider| {
11377 local
11378 .language_server_dynamic_registrations
11379 .entry(server_id)
11380 .or_default()
11381 .diagnostics
11382 .entry(None)
11383 .or_insert(provider.clone());
11384 let workspace_refresher =
11385 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11386
11387 Some((None, workspace_refresher))
11388 })
11389 .into_iter()
11390 .collect();
11391 local.language_servers.insert(
11392 server_id,
11393 LanguageServerState::Running {
11394 workspace_diagnostics_refresh_tasks,
11395 adapter: adapter.clone(),
11396 server: language_server.clone(),
11397 simulate_disk_based_diagnostics_completion: None,
11398 },
11399 );
11400 local
11401 .languages
11402 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11403 if let Some(file_ops_caps) = language_server
11404 .capabilities()
11405 .workspace
11406 .as_ref()
11407 .and_then(|ws| ws.file_operations.as_ref())
11408 {
11409 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11410 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11411 if did_rename_caps.or(will_rename_caps).is_some() {
11412 let watcher = RenamePathsWatchedForServer::default()
11413 .with_did_rename_patterns(did_rename_caps)
11414 .with_will_rename_patterns(will_rename_caps);
11415 local
11416 .language_server_paths_watched_for_rename
11417 .insert(server_id, watcher);
11418 }
11419 }
11420
11421 self.language_server_statuses.insert(
11422 server_id,
11423 LanguageServerStatus {
11424 name: language_server.name(),
11425 server_version: language_server.version(),
11426 pending_work: Default::default(),
11427 has_pending_diagnostic_updates: false,
11428 progress_tokens: Default::default(),
11429 worktree: Some(key.worktree_id),
11430 binary: Some(language_server.binary().clone()),
11431 configuration: Some(language_server.configuration().clone()),
11432 workspace_folders: language_server.workspace_folders(),
11433 },
11434 );
11435
11436 cx.emit(LspStoreEvent::LanguageServerAdded(
11437 server_id,
11438 language_server.name(),
11439 Some(key.worktree_id),
11440 ));
11441
11442 let server_capabilities = language_server.capabilities();
11443 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11444 downstream_client
11445 .send(proto::StartLanguageServer {
11446 project_id: *project_id,
11447 server: Some(proto::LanguageServer {
11448 id: server_id.to_proto(),
11449 name: language_server.name().to_string(),
11450 worktree_id: Some(key.worktree_id.to_proto()),
11451 }),
11452 capabilities: serde_json::to_string(&server_capabilities)
11453 .expect("serializing server LSP capabilities"),
11454 })
11455 .log_err();
11456 }
11457 self.lsp_server_capabilities
11458 .insert(server_id, server_capabilities);
11459
11460 // Tell the language server about every open buffer in the worktree that matches the language.
11461 // Also check for buffers in worktrees that reused this server
11462 let mut worktrees_using_server = vec![key.worktree_id];
11463 if let Some(local) = self.as_local() {
11464 // Find all worktrees that have this server in their language server tree
11465 for (worktree_id, servers) in &local.lsp_tree.instances {
11466 if *worktree_id != key.worktree_id {
11467 for server_map in servers.roots.values() {
11468 if server_map
11469 .values()
11470 .any(|(node, _)| node.id() == Some(server_id))
11471 {
11472 worktrees_using_server.push(*worktree_id);
11473 }
11474 }
11475 }
11476 }
11477 }
11478
11479 let mut buffer_paths_registered = Vec::new();
11480 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11481 let mut lsp_adapters = HashMap::default();
11482 for buffer_handle in buffer_store.buffers() {
11483 let buffer = buffer_handle.read(cx);
11484 let file = match File::from_dyn(buffer.file()) {
11485 Some(file) => file,
11486 None => continue,
11487 };
11488 let language = match buffer.language() {
11489 Some(language) => language,
11490 None => continue,
11491 };
11492
11493 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11494 || !lsp_adapters
11495 .entry(language.name())
11496 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11497 .iter()
11498 .any(|a| a.name == key.name)
11499 {
11500 continue;
11501 }
11502 // didOpen
11503 let file = match file.as_local() {
11504 Some(file) => file,
11505 None => continue,
11506 };
11507
11508 let local = self.as_local_mut().unwrap();
11509
11510 let buffer_id = buffer.remote_id();
11511 if local.registered_buffers.contains_key(&buffer_id) {
11512 let versions = local
11513 .buffer_snapshots
11514 .entry(buffer_id)
11515 .or_default()
11516 .entry(server_id)
11517 .and_modify(|_| {
11518 assert!(
11519 false,
11520 "There should not be an existing snapshot for a newly inserted buffer"
11521 )
11522 })
11523 .or_insert_with(|| {
11524 vec![LspBufferSnapshot {
11525 version: 0,
11526 snapshot: buffer.text_snapshot(),
11527 }]
11528 });
11529
11530 let snapshot = versions.last().unwrap();
11531 let version = snapshot.version;
11532 let initial_snapshot = &snapshot.snapshot;
11533 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11534 language_server.register_buffer(
11535 uri,
11536 adapter.language_id(&language.name()),
11537 version,
11538 initial_snapshot.text(),
11539 );
11540 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11541 local
11542 .buffers_opened_in_servers
11543 .entry(buffer_id)
11544 .or_default()
11545 .insert(server_id);
11546 }
11547 buffer_handle.update(cx, |buffer, cx| {
11548 buffer.set_completion_triggers(
11549 server_id,
11550 language_server
11551 .capabilities()
11552 .completion_provider
11553 .as_ref()
11554 .and_then(|provider| {
11555 provider
11556 .trigger_characters
11557 .as_ref()
11558 .map(|characters| characters.iter().cloned().collect())
11559 })
11560 .unwrap_or_default(),
11561 cx,
11562 )
11563 });
11564 }
11565 });
11566
11567 for (buffer_id, abs_path) in buffer_paths_registered {
11568 cx.emit(LspStoreEvent::LanguageServerUpdate {
11569 language_server_id: server_id,
11570 name: Some(adapter.name()),
11571 message: proto::update_language_server::Variant::RegisteredForBuffer(
11572 proto::RegisteredForBuffer {
11573 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11574 buffer_id: buffer_id.to_proto(),
11575 },
11576 ),
11577 });
11578 }
11579
11580 cx.notify();
11581 }
11582
11583 pub fn language_servers_running_disk_based_diagnostics(
11584 &self,
11585 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11586 self.language_server_statuses
11587 .iter()
11588 .filter_map(|(id, status)| {
11589 if status.has_pending_diagnostic_updates {
11590 Some(*id)
11591 } else {
11592 None
11593 }
11594 })
11595 }
11596
11597 pub(crate) fn cancel_language_server_work_for_buffers(
11598 &mut self,
11599 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11600 cx: &mut Context<Self>,
11601 ) {
11602 if let Some((client, project_id)) = self.upstream_client() {
11603 let request = client.request(proto::CancelLanguageServerWork {
11604 project_id,
11605 work: Some(proto::cancel_language_server_work::Work::Buffers(
11606 proto::cancel_language_server_work::Buffers {
11607 buffer_ids: buffers
11608 .into_iter()
11609 .map(|b| b.read(cx).remote_id().to_proto())
11610 .collect(),
11611 },
11612 )),
11613 });
11614 cx.background_spawn(request).detach_and_log_err(cx);
11615 } else if let Some(local) = self.as_local() {
11616 let servers = buffers
11617 .into_iter()
11618 .flat_map(|buffer| {
11619 buffer.update(cx, |buffer, cx| {
11620 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11621 })
11622 })
11623 .collect::<HashSet<_>>();
11624 for server_id in servers {
11625 self.cancel_language_server_work(server_id, None, cx);
11626 }
11627 }
11628 }
11629
11630 pub(crate) fn cancel_language_server_work(
11631 &mut self,
11632 server_id: LanguageServerId,
11633 token_to_cancel: Option<ProgressToken>,
11634 cx: &mut Context<Self>,
11635 ) {
11636 if let Some(local) = self.as_local() {
11637 let status = self.language_server_statuses.get(&server_id);
11638 let server = local.language_servers.get(&server_id);
11639 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11640 {
11641 for (token, progress) in &status.pending_work {
11642 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11643 && token != token_to_cancel
11644 {
11645 continue;
11646 }
11647 if progress.is_cancellable {
11648 server
11649 .notify::<lsp::notification::WorkDoneProgressCancel>(
11650 WorkDoneProgressCancelParams {
11651 token: token.to_lsp(),
11652 },
11653 )
11654 .ok();
11655 }
11656 }
11657 }
11658 } else if let Some((client, project_id)) = self.upstream_client() {
11659 let request = client.request(proto::CancelLanguageServerWork {
11660 project_id,
11661 work: Some(
11662 proto::cancel_language_server_work::Work::LanguageServerWork(
11663 proto::cancel_language_server_work::LanguageServerWork {
11664 language_server_id: server_id.to_proto(),
11665 token: token_to_cancel.map(|token| token.to_proto()),
11666 },
11667 ),
11668 ),
11669 });
11670 cx.background_spawn(request).detach_and_log_err(cx);
11671 }
11672 }
11673
11674 fn register_supplementary_language_server(
11675 &mut self,
11676 id: LanguageServerId,
11677 name: LanguageServerName,
11678 server: Arc<LanguageServer>,
11679 cx: &mut Context<Self>,
11680 ) {
11681 if let Some(local) = self.as_local_mut() {
11682 local
11683 .supplementary_language_servers
11684 .insert(id, (name.clone(), server));
11685 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11686 }
11687 }
11688
11689 fn unregister_supplementary_language_server(
11690 &mut self,
11691 id: LanguageServerId,
11692 cx: &mut Context<Self>,
11693 ) {
11694 if let Some(local) = self.as_local_mut() {
11695 local.supplementary_language_servers.remove(&id);
11696 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11697 }
11698 }
11699
11700 pub(crate) fn supplementary_language_servers(
11701 &self,
11702 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11703 self.as_local().into_iter().flat_map(|local| {
11704 local
11705 .supplementary_language_servers
11706 .iter()
11707 .map(|(id, (name, _))| (*id, name.clone()))
11708 })
11709 }
11710
11711 pub fn language_server_adapter_for_id(
11712 &self,
11713 id: LanguageServerId,
11714 ) -> Option<Arc<CachedLspAdapter>> {
11715 self.as_local()
11716 .and_then(|local| local.language_servers.get(&id))
11717 .and_then(|language_server_state| match language_server_state {
11718 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11719 _ => None,
11720 })
11721 }
11722
11723 pub(super) fn update_local_worktree_language_servers(
11724 &mut self,
11725 worktree_handle: &Entity<Worktree>,
11726 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11727 cx: &mut Context<Self>,
11728 ) {
11729 if changes.is_empty() {
11730 return;
11731 }
11732
11733 let Some(local) = self.as_local() else { return };
11734
11735 local.prettier_store.update(cx, |prettier_store, cx| {
11736 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11737 });
11738
11739 let worktree_id = worktree_handle.read(cx).id();
11740 let mut language_server_ids = local
11741 .language_server_ids
11742 .iter()
11743 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11744 .collect::<Vec<_>>();
11745 language_server_ids.sort();
11746 language_server_ids.dedup();
11747
11748 // let abs_path = worktree_handle.read(cx).abs_path();
11749 for server_id in &language_server_ids {
11750 if let Some(LanguageServerState::Running { server, .. }) =
11751 local.language_servers.get(server_id)
11752 && let Some(watched_paths) = local
11753 .language_server_watched_paths
11754 .get(server_id)
11755 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11756 {
11757 let params = lsp::DidChangeWatchedFilesParams {
11758 changes: changes
11759 .iter()
11760 .filter_map(|(path, _, change)| {
11761 if !watched_paths.is_match(path.as_std_path()) {
11762 return None;
11763 }
11764 let typ = match change {
11765 PathChange::Loaded => return None,
11766 PathChange::Added => lsp::FileChangeType::CREATED,
11767 PathChange::Removed => lsp::FileChangeType::DELETED,
11768 PathChange::Updated => lsp::FileChangeType::CHANGED,
11769 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11770 };
11771 let uri = lsp::Uri::from_file_path(
11772 worktree_handle.read(cx).absolutize(&path),
11773 )
11774 .ok()?;
11775 Some(lsp::FileEvent { uri, typ })
11776 })
11777 .collect(),
11778 };
11779 if !params.changes.is_empty() {
11780 server
11781 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11782 .ok();
11783 }
11784 }
11785 }
11786 for (path, _, _) in changes {
11787 if let Some(file_name) = path.file_name()
11788 && local.watched_manifest_filenames.contains(file_name)
11789 {
11790 self.request_workspace_config_refresh();
11791 break;
11792 }
11793 }
11794 }
11795
11796 pub fn wait_for_remote_buffer(
11797 &mut self,
11798 id: BufferId,
11799 cx: &mut Context<Self>,
11800 ) -> Task<Result<Entity<Buffer>>> {
11801 self.buffer_store.update(cx, |buffer_store, cx| {
11802 buffer_store.wait_for_remote_buffer(id, cx)
11803 })
11804 }
11805
11806 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11807 let mut result = proto::Symbol {
11808 language_server_name: symbol.language_server_name.0.to_string(),
11809 source_worktree_id: symbol.source_worktree_id.to_proto(),
11810 language_server_id: symbol.source_language_server_id.to_proto(),
11811 name: symbol.name.clone(),
11812 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11813 start: Some(proto::PointUtf16 {
11814 row: symbol.range.start.0.row,
11815 column: symbol.range.start.0.column,
11816 }),
11817 end: Some(proto::PointUtf16 {
11818 row: symbol.range.end.0.row,
11819 column: symbol.range.end.0.column,
11820 }),
11821 worktree_id: Default::default(),
11822 path: Default::default(),
11823 signature: Default::default(),
11824 };
11825 match &symbol.path {
11826 SymbolLocation::InProject(path) => {
11827 result.worktree_id = path.worktree_id.to_proto();
11828 result.path = path.path.to_proto();
11829 }
11830 SymbolLocation::OutsideProject {
11831 abs_path,
11832 signature,
11833 } => {
11834 result.path = abs_path.to_string_lossy().into_owned();
11835 result.signature = signature.to_vec();
11836 }
11837 }
11838 result
11839 }
11840
11841 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11842 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11843 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11844 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11845
11846 let path = if serialized_symbol.signature.is_empty() {
11847 SymbolLocation::InProject(ProjectPath {
11848 worktree_id,
11849 path: RelPath::from_proto(&serialized_symbol.path)
11850 .context("invalid symbol path")?,
11851 })
11852 } else {
11853 SymbolLocation::OutsideProject {
11854 abs_path: Path::new(&serialized_symbol.path).into(),
11855 signature: serialized_symbol
11856 .signature
11857 .try_into()
11858 .map_err(|_| anyhow!("invalid signature"))?,
11859 }
11860 };
11861
11862 let start = serialized_symbol.start.context("invalid start")?;
11863 let end = serialized_symbol.end.context("invalid end")?;
11864 Ok(CoreSymbol {
11865 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11866 source_worktree_id,
11867 source_language_server_id: LanguageServerId::from_proto(
11868 serialized_symbol.language_server_id,
11869 ),
11870 path,
11871 name: serialized_symbol.name,
11872 range: Unclipped(PointUtf16::new(start.row, start.column))
11873 ..Unclipped(PointUtf16::new(end.row, end.column)),
11874 kind,
11875 })
11876 }
11877
11878 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11879 let mut serialized_completion = proto::Completion {
11880 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11881 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11882 new_text: completion.new_text.clone(),
11883 ..proto::Completion::default()
11884 };
11885 match &completion.source {
11886 CompletionSource::Lsp {
11887 insert_range,
11888 server_id,
11889 lsp_completion,
11890 lsp_defaults,
11891 resolved,
11892 } => {
11893 let (old_insert_start, old_insert_end) = insert_range
11894 .as_ref()
11895 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11896 .unzip();
11897
11898 serialized_completion.old_insert_start = old_insert_start;
11899 serialized_completion.old_insert_end = old_insert_end;
11900 serialized_completion.source = proto::completion::Source::Lsp as i32;
11901 serialized_completion.server_id = server_id.0 as u64;
11902 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11903 serialized_completion.lsp_defaults = lsp_defaults
11904 .as_deref()
11905 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11906 serialized_completion.resolved = *resolved;
11907 }
11908 CompletionSource::BufferWord {
11909 word_range,
11910 resolved,
11911 } => {
11912 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11913 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11914 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11915 serialized_completion.resolved = *resolved;
11916 }
11917 CompletionSource::Custom => {
11918 serialized_completion.source = proto::completion::Source::Custom as i32;
11919 serialized_completion.resolved = true;
11920 }
11921 CompletionSource::Dap { sort_text } => {
11922 serialized_completion.source = proto::completion::Source::Dap as i32;
11923 serialized_completion.sort_text = Some(sort_text.clone());
11924 }
11925 }
11926
11927 serialized_completion
11928 }
11929
11930 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11931 let old_replace_start = completion
11932 .old_replace_start
11933 .and_then(deserialize_anchor)
11934 .context("invalid old start")?;
11935 let old_replace_end = completion
11936 .old_replace_end
11937 .and_then(deserialize_anchor)
11938 .context("invalid old end")?;
11939 let insert_range = {
11940 match completion.old_insert_start.zip(completion.old_insert_end) {
11941 Some((start, end)) => {
11942 let start = deserialize_anchor(start).context("invalid insert old start")?;
11943 let end = deserialize_anchor(end).context("invalid insert old end")?;
11944 Some(start..end)
11945 }
11946 None => None,
11947 }
11948 };
11949 Ok(CoreCompletion {
11950 replace_range: old_replace_start..old_replace_end,
11951 new_text: completion.new_text,
11952 source: match proto::completion::Source::from_i32(completion.source) {
11953 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11954 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11955 insert_range,
11956 server_id: LanguageServerId::from_proto(completion.server_id),
11957 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11958 lsp_defaults: completion
11959 .lsp_defaults
11960 .as_deref()
11961 .map(serde_json::from_slice)
11962 .transpose()?,
11963 resolved: completion.resolved,
11964 },
11965 Some(proto::completion::Source::BufferWord) => {
11966 let word_range = completion
11967 .buffer_word_start
11968 .and_then(deserialize_anchor)
11969 .context("invalid buffer word start")?
11970 ..completion
11971 .buffer_word_end
11972 .and_then(deserialize_anchor)
11973 .context("invalid buffer word end")?;
11974 CompletionSource::BufferWord {
11975 word_range,
11976 resolved: completion.resolved,
11977 }
11978 }
11979 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11980 sort_text: completion
11981 .sort_text
11982 .context("expected sort text to exist")?,
11983 },
11984 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11985 },
11986 })
11987 }
11988
11989 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11990 let (kind, lsp_action) = match &action.lsp_action {
11991 LspAction::Action(code_action) => (
11992 proto::code_action::Kind::Action as i32,
11993 serde_json::to_vec(code_action).unwrap(),
11994 ),
11995 LspAction::Command(command) => (
11996 proto::code_action::Kind::Command as i32,
11997 serde_json::to_vec(command).unwrap(),
11998 ),
11999 LspAction::CodeLens(code_lens) => (
12000 proto::code_action::Kind::CodeLens as i32,
12001 serde_json::to_vec(code_lens).unwrap(),
12002 ),
12003 };
12004
12005 proto::CodeAction {
12006 server_id: action.server_id.0 as u64,
12007 start: Some(serialize_anchor(&action.range.start)),
12008 end: Some(serialize_anchor(&action.range.end)),
12009 lsp_action,
12010 kind,
12011 resolved: action.resolved,
12012 }
12013 }
12014
12015 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12016 let start = action
12017 .start
12018 .and_then(deserialize_anchor)
12019 .context("invalid start")?;
12020 let end = action
12021 .end
12022 .and_then(deserialize_anchor)
12023 .context("invalid end")?;
12024 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12025 Some(proto::code_action::Kind::Action) => {
12026 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12027 }
12028 Some(proto::code_action::Kind::Command) => {
12029 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12030 }
12031 Some(proto::code_action::Kind::CodeLens) => {
12032 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12033 }
12034 None => anyhow::bail!("Unknown action kind {}", action.kind),
12035 };
12036 Ok(CodeAction {
12037 server_id: LanguageServerId(action.server_id as usize),
12038 range: start..end,
12039 resolved: action.resolved,
12040 lsp_action,
12041 })
12042 }
12043
12044 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12045 match &formatting_result {
12046 Ok(_) => self.last_formatting_failure = None,
12047 Err(error) => {
12048 let error_string = format!("{error:#}");
12049 log::error!("Formatting failed: {error_string}");
12050 self.last_formatting_failure
12051 .replace(error_string.lines().join(" "));
12052 }
12053 }
12054 }
12055
12056 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12057 self.lsp_server_capabilities.remove(&for_server);
12058 for lsp_data in self.lsp_data.values_mut() {
12059 lsp_data.remove_server_data(for_server);
12060 }
12061 if let Some(local) = self.as_local_mut() {
12062 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12063 local
12064 .workspace_pull_diagnostics_result_ids
12065 .remove(&for_server);
12066 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12067 buffer_servers.remove(&for_server);
12068 }
12069 }
12070 }
12071
12072 pub fn result_id_for_buffer_pull(
12073 &self,
12074 server_id: LanguageServerId,
12075 buffer_id: BufferId,
12076 registration_id: &Option<SharedString>,
12077 cx: &App,
12078 ) -> Option<SharedString> {
12079 let abs_path = self
12080 .buffer_store
12081 .read(cx)
12082 .get(buffer_id)
12083 .and_then(|b| File::from_dyn(b.read(cx).file()))
12084 .map(|f| f.abs_path(cx))?;
12085 self.as_local()?
12086 .buffer_pull_diagnostics_result_ids
12087 .get(&server_id)?
12088 .get(registration_id)?
12089 .get(&abs_path)?
12090 .clone()
12091 }
12092
12093 /// Gets all result_ids for a workspace diagnostics pull request.
12094 /// 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.
12095 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12096 pub fn result_ids_for_workspace_refresh(
12097 &self,
12098 server_id: LanguageServerId,
12099 registration_id: &Option<SharedString>,
12100 ) -> HashMap<PathBuf, SharedString> {
12101 let Some(local) = self.as_local() else {
12102 return HashMap::default();
12103 };
12104 local
12105 .workspace_pull_diagnostics_result_ids
12106 .get(&server_id)
12107 .into_iter()
12108 .filter_map(|diagnostics| diagnostics.get(registration_id))
12109 .flatten()
12110 .filter_map(|(abs_path, result_id)| {
12111 let result_id = local
12112 .buffer_pull_diagnostics_result_ids
12113 .get(&server_id)
12114 .and_then(|buffer_ids_result_ids| {
12115 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12116 })
12117 .cloned()
12118 .flatten()
12119 .or_else(|| result_id.clone())?;
12120 Some((abs_path.clone(), result_id))
12121 })
12122 .collect()
12123 }
12124
12125 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12126 if let Some(LanguageServerState::Running {
12127 workspace_diagnostics_refresh_tasks,
12128 ..
12129 }) = self
12130 .as_local_mut()
12131 .and_then(|local| local.language_servers.get_mut(&server_id))
12132 {
12133 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12134 diagnostics.refresh_tx.try_send(()).ok();
12135 }
12136 }
12137 }
12138
12139 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12140 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12141 return;
12142 };
12143 let Some(local) = self.as_local_mut() else {
12144 return;
12145 };
12146
12147 for server_id in buffer.update(cx, |buffer, cx| {
12148 local.language_server_ids_for_buffer(buffer, cx)
12149 }) {
12150 if let Some(LanguageServerState::Running {
12151 workspace_diagnostics_refresh_tasks,
12152 ..
12153 }) = local.language_servers.get_mut(&server_id)
12154 {
12155 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12156 diagnostics.refresh_tx.try_send(()).ok();
12157 }
12158 }
12159 }
12160 }
12161
12162 fn apply_workspace_diagnostic_report(
12163 &mut self,
12164 server_id: LanguageServerId,
12165 report: lsp::WorkspaceDiagnosticReportResult,
12166 registration_id: Option<SharedString>,
12167 cx: &mut Context<Self>,
12168 ) {
12169 let workspace_diagnostics =
12170 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12171 report,
12172 server_id,
12173 registration_id,
12174 );
12175 let mut unchanged_buffers = HashMap::default();
12176 let workspace_diagnostics_updates = workspace_diagnostics
12177 .into_iter()
12178 .filter_map(
12179 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12180 LspPullDiagnostics::Response {
12181 server_id,
12182 uri,
12183 diagnostics,
12184 registration_id,
12185 } => Some((
12186 server_id,
12187 uri,
12188 diagnostics,
12189 workspace_diagnostics.version,
12190 registration_id,
12191 )),
12192 LspPullDiagnostics::Default => None,
12193 },
12194 )
12195 .fold(
12196 HashMap::default(),
12197 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12198 let (result_id, diagnostics) = match diagnostics {
12199 PulledDiagnostics::Unchanged { result_id } => {
12200 unchanged_buffers
12201 .entry(new_registration_id.clone())
12202 .or_insert_with(HashSet::default)
12203 .insert(uri.clone());
12204 (Some(result_id), Vec::new())
12205 }
12206 PulledDiagnostics::Changed {
12207 result_id,
12208 diagnostics,
12209 } => (result_id, diagnostics),
12210 };
12211 let disk_based_sources = Cow::Owned(
12212 self.language_server_adapter_for_id(server_id)
12213 .as_ref()
12214 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12215 .unwrap_or(&[])
12216 .to_vec(),
12217 );
12218
12219 let Some(abs_path) = uri.to_file_path().ok() else {
12220 return acc;
12221 };
12222 let Some((worktree, relative_path)) =
12223 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12224 else {
12225 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12226 return acc;
12227 };
12228 let worktree_id = worktree.read(cx).id();
12229 let project_path = ProjectPath {
12230 worktree_id,
12231 path: relative_path,
12232 };
12233 if let Some(local_lsp_store) = self.as_local_mut() {
12234 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12235 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12236 }
12237 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12238 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12239 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12240 acc.entry(server_id)
12241 .or_insert_with(HashMap::default)
12242 .entry(new_registration_id.clone())
12243 .or_insert_with(Vec::new)
12244 .push(DocumentDiagnosticsUpdate {
12245 server_id,
12246 diagnostics: lsp::PublishDiagnosticsParams {
12247 uri,
12248 diagnostics,
12249 version,
12250 },
12251 result_id,
12252 disk_based_sources,
12253 registration_id: new_registration_id,
12254 });
12255 }
12256 acc
12257 },
12258 );
12259
12260 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12261 for (registration_id, diagnostic_updates) in diagnostic_updates {
12262 self.merge_lsp_diagnostics(
12263 DiagnosticSourceKind::Pulled,
12264 diagnostic_updates,
12265 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12266 DiagnosticSourceKind::Pulled => {
12267 old_diagnostic.registration_id != registration_id
12268 || unchanged_buffers
12269 .get(&old_diagnostic.registration_id)
12270 .is_some_and(|unchanged_buffers| {
12271 unchanged_buffers.contains(&document_uri)
12272 })
12273 }
12274 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12275 },
12276 cx,
12277 )
12278 .log_err();
12279 }
12280 }
12281 }
12282
12283 fn register_server_capabilities(
12284 &mut self,
12285 server_id: LanguageServerId,
12286 params: lsp::RegistrationParams,
12287 cx: &mut Context<Self>,
12288 ) -> anyhow::Result<()> {
12289 let server = self
12290 .language_server_for_id(server_id)
12291 .with_context(|| format!("no server {server_id} found"))?;
12292 for reg in params.registrations {
12293 match reg.method.as_str() {
12294 "workspace/didChangeWatchedFiles" => {
12295 if let Some(options) = reg.register_options {
12296 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12297 let caps = serde_json::from_value(options)?;
12298 local_lsp_store
12299 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12300 true
12301 } else {
12302 false
12303 };
12304 if notify {
12305 notify_server_capabilities_updated(&server, cx);
12306 }
12307 }
12308 }
12309 "workspace/didChangeConfiguration" => {
12310 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12311 }
12312 "workspace/didChangeWorkspaceFolders" => {
12313 // In this case register options is an empty object, we can ignore it
12314 let caps = lsp::WorkspaceFoldersServerCapabilities {
12315 supported: Some(true),
12316 change_notifications: Some(OneOf::Right(reg.id)),
12317 };
12318 server.update_capabilities(|capabilities| {
12319 capabilities
12320 .workspace
12321 .get_or_insert_default()
12322 .workspace_folders = Some(caps);
12323 });
12324 notify_server_capabilities_updated(&server, cx);
12325 }
12326 "workspace/symbol" => {
12327 let options = parse_register_capabilities(reg)?;
12328 server.update_capabilities(|capabilities| {
12329 capabilities.workspace_symbol_provider = Some(options);
12330 });
12331 notify_server_capabilities_updated(&server, cx);
12332 }
12333 "workspace/fileOperations" => {
12334 if let Some(options) = reg.register_options {
12335 let caps = serde_json::from_value(options)?;
12336 server.update_capabilities(|capabilities| {
12337 capabilities
12338 .workspace
12339 .get_or_insert_default()
12340 .file_operations = Some(caps);
12341 });
12342 notify_server_capabilities_updated(&server, cx);
12343 }
12344 }
12345 "workspace/executeCommand" => {
12346 if let Some(options) = reg.register_options {
12347 let options = serde_json::from_value(options)?;
12348 server.update_capabilities(|capabilities| {
12349 capabilities.execute_command_provider = Some(options);
12350 });
12351 notify_server_capabilities_updated(&server, cx);
12352 }
12353 }
12354 "textDocument/rangeFormatting" => {
12355 let options = parse_register_capabilities(reg)?;
12356 server.update_capabilities(|capabilities| {
12357 capabilities.document_range_formatting_provider = Some(options);
12358 });
12359 notify_server_capabilities_updated(&server, cx);
12360 }
12361 "textDocument/onTypeFormatting" => {
12362 if let Some(options) = reg
12363 .register_options
12364 .map(serde_json::from_value)
12365 .transpose()?
12366 {
12367 server.update_capabilities(|capabilities| {
12368 capabilities.document_on_type_formatting_provider = Some(options);
12369 });
12370 notify_server_capabilities_updated(&server, cx);
12371 }
12372 }
12373 "textDocument/formatting" => {
12374 let options = parse_register_capabilities(reg)?;
12375 server.update_capabilities(|capabilities| {
12376 capabilities.document_formatting_provider = Some(options);
12377 });
12378 notify_server_capabilities_updated(&server, cx);
12379 }
12380 "textDocument/rename" => {
12381 let options = parse_register_capabilities(reg)?;
12382 server.update_capabilities(|capabilities| {
12383 capabilities.rename_provider = Some(options);
12384 });
12385 notify_server_capabilities_updated(&server, cx);
12386 }
12387 "textDocument/inlayHint" => {
12388 let options = parse_register_capabilities(reg)?;
12389 server.update_capabilities(|capabilities| {
12390 capabilities.inlay_hint_provider = Some(options);
12391 });
12392 notify_server_capabilities_updated(&server, cx);
12393 }
12394 "textDocument/documentSymbol" => {
12395 let options = parse_register_capabilities(reg)?;
12396 server.update_capabilities(|capabilities| {
12397 capabilities.document_symbol_provider = Some(options);
12398 });
12399 notify_server_capabilities_updated(&server, cx);
12400 }
12401 "textDocument/codeAction" => {
12402 let options = parse_register_capabilities(reg)?;
12403 let provider = match options {
12404 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12405 OneOf::Right(caps) => caps,
12406 };
12407 server.update_capabilities(|capabilities| {
12408 capabilities.code_action_provider = Some(provider);
12409 });
12410 notify_server_capabilities_updated(&server, cx);
12411 }
12412 "textDocument/definition" => {
12413 let options = parse_register_capabilities(reg)?;
12414 server.update_capabilities(|capabilities| {
12415 capabilities.definition_provider = Some(options);
12416 });
12417 notify_server_capabilities_updated(&server, cx);
12418 }
12419 "textDocument/completion" => {
12420 if let Some(caps) = reg
12421 .register_options
12422 .map(serde_json::from_value::<CompletionOptions>)
12423 .transpose()?
12424 {
12425 server.update_capabilities(|capabilities| {
12426 capabilities.completion_provider = Some(caps.clone());
12427 });
12428
12429 if let Some(local) = self.as_local() {
12430 let mut buffers_with_language_server = Vec::new();
12431 for handle in self.buffer_store.read(cx).buffers() {
12432 let buffer_id = handle.read(cx).remote_id();
12433 if local
12434 .buffers_opened_in_servers
12435 .get(&buffer_id)
12436 .filter(|s| s.contains(&server_id))
12437 .is_some()
12438 {
12439 buffers_with_language_server.push(handle);
12440 }
12441 }
12442 let triggers = caps
12443 .trigger_characters
12444 .unwrap_or_default()
12445 .into_iter()
12446 .collect::<BTreeSet<_>>();
12447 for handle in buffers_with_language_server {
12448 let triggers = triggers.clone();
12449 let _ = handle.update(cx, move |buffer, cx| {
12450 buffer.set_completion_triggers(server_id, triggers, cx);
12451 });
12452 }
12453 }
12454 notify_server_capabilities_updated(&server, cx);
12455 }
12456 }
12457 "textDocument/hover" => {
12458 let options = parse_register_capabilities(reg)?;
12459 let provider = match options {
12460 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12461 OneOf::Right(caps) => caps,
12462 };
12463 server.update_capabilities(|capabilities| {
12464 capabilities.hover_provider = Some(provider);
12465 });
12466 notify_server_capabilities_updated(&server, cx);
12467 }
12468 "textDocument/signatureHelp" => {
12469 if let Some(caps) = reg
12470 .register_options
12471 .map(serde_json::from_value)
12472 .transpose()?
12473 {
12474 server.update_capabilities(|capabilities| {
12475 capabilities.signature_help_provider = Some(caps);
12476 });
12477 notify_server_capabilities_updated(&server, cx);
12478 }
12479 }
12480 "textDocument/didChange" => {
12481 if let Some(sync_kind) = reg
12482 .register_options
12483 .and_then(|opts| opts.get("syncKind").cloned())
12484 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12485 .transpose()?
12486 {
12487 server.update_capabilities(|capabilities| {
12488 let mut sync_options =
12489 Self::take_text_document_sync_options(capabilities);
12490 sync_options.change = Some(sync_kind);
12491 capabilities.text_document_sync =
12492 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12493 });
12494 notify_server_capabilities_updated(&server, cx);
12495 }
12496 }
12497 "textDocument/didSave" => {
12498 if let Some(include_text) = reg
12499 .register_options
12500 .map(|opts| {
12501 let transpose = opts
12502 .get("includeText")
12503 .cloned()
12504 .map(serde_json::from_value::<Option<bool>>)
12505 .transpose();
12506 match transpose {
12507 Ok(value) => Ok(value.flatten()),
12508 Err(e) => Err(e),
12509 }
12510 })
12511 .transpose()?
12512 {
12513 server.update_capabilities(|capabilities| {
12514 let mut sync_options =
12515 Self::take_text_document_sync_options(capabilities);
12516 sync_options.save =
12517 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12518 include_text,
12519 }));
12520 capabilities.text_document_sync =
12521 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12522 });
12523 notify_server_capabilities_updated(&server, cx);
12524 }
12525 }
12526 "textDocument/codeLens" => {
12527 if let Some(caps) = reg
12528 .register_options
12529 .map(serde_json::from_value)
12530 .transpose()?
12531 {
12532 server.update_capabilities(|capabilities| {
12533 capabilities.code_lens_provider = Some(caps);
12534 });
12535 notify_server_capabilities_updated(&server, cx);
12536 }
12537 }
12538 "textDocument/diagnostic" => {
12539 if let Some(caps) = reg
12540 .register_options
12541 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12542 .transpose()?
12543 {
12544 let local = self
12545 .as_local_mut()
12546 .context("Expected LSP Store to be local")?;
12547 let state = local
12548 .language_servers
12549 .get_mut(&server_id)
12550 .context("Could not obtain Language Servers state")?;
12551 local
12552 .language_server_dynamic_registrations
12553 .entry(server_id)
12554 .or_default()
12555 .diagnostics
12556 .insert(Some(reg.id.clone()), caps.clone());
12557
12558 let supports_workspace_diagnostics =
12559 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12560 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12561 diagnostic_options.workspace_diagnostics
12562 }
12563 DiagnosticServerCapabilities::RegistrationOptions(
12564 diagnostic_registration_options,
12565 ) => {
12566 diagnostic_registration_options
12567 .diagnostic_options
12568 .workspace_diagnostics
12569 }
12570 };
12571
12572 if supports_workspace_diagnostics(&caps) {
12573 if let LanguageServerState::Running {
12574 workspace_diagnostics_refresh_tasks,
12575 ..
12576 } = state
12577 && let Some(task) = lsp_workspace_diagnostics_refresh(
12578 Some(reg.id.clone()),
12579 caps.clone(),
12580 server.clone(),
12581 cx,
12582 )
12583 {
12584 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12585 }
12586 }
12587
12588 server.update_capabilities(|capabilities| {
12589 capabilities.diagnostic_provider = Some(caps);
12590 });
12591
12592 notify_server_capabilities_updated(&server, cx);
12593 }
12594 }
12595 "textDocument/documentColor" => {
12596 let options = parse_register_capabilities(reg)?;
12597 let provider = match options {
12598 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12599 OneOf::Right(caps) => caps,
12600 };
12601 server.update_capabilities(|capabilities| {
12602 capabilities.color_provider = Some(provider);
12603 });
12604 notify_server_capabilities_updated(&server, cx);
12605 }
12606 _ => log::warn!("unhandled capability registration: {reg:?}"),
12607 }
12608 }
12609
12610 Ok(())
12611 }
12612
12613 fn unregister_server_capabilities(
12614 &mut self,
12615 server_id: LanguageServerId,
12616 params: lsp::UnregistrationParams,
12617 cx: &mut Context<Self>,
12618 ) -> anyhow::Result<()> {
12619 let server = self
12620 .language_server_for_id(server_id)
12621 .with_context(|| format!("no server {server_id} found"))?;
12622 for unreg in params.unregisterations.iter() {
12623 match unreg.method.as_str() {
12624 "workspace/didChangeWatchedFiles" => {
12625 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12626 local_lsp_store
12627 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12628 true
12629 } else {
12630 false
12631 };
12632 if notify {
12633 notify_server_capabilities_updated(&server, cx);
12634 }
12635 }
12636 "workspace/didChangeConfiguration" => {
12637 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12638 }
12639 "workspace/didChangeWorkspaceFolders" => {
12640 server.update_capabilities(|capabilities| {
12641 capabilities
12642 .workspace
12643 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12644 workspace_folders: None,
12645 file_operations: None,
12646 })
12647 .workspace_folders = None;
12648 });
12649 notify_server_capabilities_updated(&server, cx);
12650 }
12651 "workspace/symbol" => {
12652 server.update_capabilities(|capabilities| {
12653 capabilities.workspace_symbol_provider = None
12654 });
12655 notify_server_capabilities_updated(&server, cx);
12656 }
12657 "workspace/fileOperations" => {
12658 server.update_capabilities(|capabilities| {
12659 capabilities
12660 .workspace
12661 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12662 workspace_folders: None,
12663 file_operations: None,
12664 })
12665 .file_operations = None;
12666 });
12667 notify_server_capabilities_updated(&server, cx);
12668 }
12669 "workspace/executeCommand" => {
12670 server.update_capabilities(|capabilities| {
12671 capabilities.execute_command_provider = None;
12672 });
12673 notify_server_capabilities_updated(&server, cx);
12674 }
12675 "textDocument/rangeFormatting" => {
12676 server.update_capabilities(|capabilities| {
12677 capabilities.document_range_formatting_provider = None
12678 });
12679 notify_server_capabilities_updated(&server, cx);
12680 }
12681 "textDocument/onTypeFormatting" => {
12682 server.update_capabilities(|capabilities| {
12683 capabilities.document_on_type_formatting_provider = None;
12684 });
12685 notify_server_capabilities_updated(&server, cx);
12686 }
12687 "textDocument/formatting" => {
12688 server.update_capabilities(|capabilities| {
12689 capabilities.document_formatting_provider = None;
12690 });
12691 notify_server_capabilities_updated(&server, cx);
12692 }
12693 "textDocument/rename" => {
12694 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12695 notify_server_capabilities_updated(&server, cx);
12696 }
12697 "textDocument/codeAction" => {
12698 server.update_capabilities(|capabilities| {
12699 capabilities.code_action_provider = None;
12700 });
12701 notify_server_capabilities_updated(&server, cx);
12702 }
12703 "textDocument/definition" => {
12704 server.update_capabilities(|capabilities| {
12705 capabilities.definition_provider = None;
12706 });
12707 notify_server_capabilities_updated(&server, cx);
12708 }
12709 "textDocument/completion" => {
12710 server.update_capabilities(|capabilities| {
12711 capabilities.completion_provider = None;
12712 });
12713 notify_server_capabilities_updated(&server, cx);
12714 }
12715 "textDocument/hover" => {
12716 server.update_capabilities(|capabilities| {
12717 capabilities.hover_provider = None;
12718 });
12719 notify_server_capabilities_updated(&server, cx);
12720 }
12721 "textDocument/signatureHelp" => {
12722 server.update_capabilities(|capabilities| {
12723 capabilities.signature_help_provider = None;
12724 });
12725 notify_server_capabilities_updated(&server, cx);
12726 }
12727 "textDocument/didChange" => {
12728 server.update_capabilities(|capabilities| {
12729 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12730 sync_options.change = None;
12731 capabilities.text_document_sync =
12732 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12733 });
12734 notify_server_capabilities_updated(&server, cx);
12735 }
12736 "textDocument/didSave" => {
12737 server.update_capabilities(|capabilities| {
12738 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12739 sync_options.save = None;
12740 capabilities.text_document_sync =
12741 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12742 });
12743 notify_server_capabilities_updated(&server, cx);
12744 }
12745 "textDocument/codeLens" => {
12746 server.update_capabilities(|capabilities| {
12747 capabilities.code_lens_provider = None;
12748 });
12749 notify_server_capabilities_updated(&server, cx);
12750 }
12751 "textDocument/diagnostic" => {
12752 let local = self
12753 .as_local_mut()
12754 .context("Expected LSP Store to be local")?;
12755
12756 let state = local
12757 .language_servers
12758 .get_mut(&server_id)
12759 .context("Could not obtain Language Servers state")?;
12760 let registrations = local
12761 .language_server_dynamic_registrations
12762 .get_mut(&server_id)
12763 .with_context(|| {
12764 format!("Expected dynamic registration to exist for server {server_id}")
12765 })?;
12766 registrations.diagnostics
12767 .remove(&Some(unreg.id.clone()))
12768 .with_context(|| format!(
12769 "Attempted to unregister non-existent diagnostic registration with ID {}",
12770 unreg.id)
12771 )?;
12772 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12773
12774 if let LanguageServerState::Running {
12775 workspace_diagnostics_refresh_tasks,
12776 ..
12777 } = state
12778 {
12779 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12780 }
12781
12782 if removed_last_diagnostic_provider {
12783 server.update_capabilities(|capabilities| {
12784 debug_assert!(capabilities.diagnostic_provider.is_some());
12785 capabilities.diagnostic_provider = None;
12786 });
12787 }
12788
12789 notify_server_capabilities_updated(&server, cx);
12790 }
12791 "textDocument/documentColor" => {
12792 server.update_capabilities(|capabilities| {
12793 capabilities.color_provider = None;
12794 });
12795 notify_server_capabilities_updated(&server, cx);
12796 }
12797 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12798 }
12799 }
12800
12801 Ok(())
12802 }
12803
12804 async fn deduplicate_range_based_lsp_requests<T>(
12805 lsp_store: &Entity<Self>,
12806 server_id: Option<LanguageServerId>,
12807 lsp_request_id: LspRequestId,
12808 proto_request: &T::ProtoRequest,
12809 range: Range<Anchor>,
12810 cx: &mut AsyncApp,
12811 ) -> Result<()>
12812 where
12813 T: LspCommand,
12814 T::ProtoRequest: proto::LspRequestMessage,
12815 {
12816 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12817 let version = deserialize_version(proto_request.buffer_version());
12818 let buffer = lsp_store.update(cx, |this, cx| {
12819 this.buffer_store.read(cx).get_existing(buffer_id)
12820 })??;
12821 buffer
12822 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12823 .await?;
12824 lsp_store.update(cx, |lsp_store, cx| {
12825 let buffer_snapshot = buffer.read(cx).snapshot();
12826 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12827 let chunks_queried_for = lsp_data
12828 .inlay_hints
12829 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12830 .collect::<Vec<_>>();
12831 match chunks_queried_for.as_slice() {
12832 &[chunk] => {
12833 let key = LspKey {
12834 request_type: TypeId::of::<T>(),
12835 server_queried: server_id,
12836 };
12837 let previous_request = lsp_data
12838 .chunk_lsp_requests
12839 .entry(key)
12840 .or_default()
12841 .insert(chunk, lsp_request_id);
12842 if let Some((previous_request, running_requests)) =
12843 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12844 {
12845 running_requests.remove(&previous_request);
12846 }
12847 }
12848 _ambiguous_chunks => {
12849 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12850 // there, a buffer version-based check will be performed and outdated requests discarded.
12851 }
12852 }
12853 anyhow::Ok(())
12854 })??;
12855
12856 Ok(())
12857 }
12858
12859 async fn query_lsp_locally<T>(
12860 lsp_store: Entity<Self>,
12861 for_server_id: Option<LanguageServerId>,
12862 sender_id: proto::PeerId,
12863 lsp_request_id: LspRequestId,
12864 proto_request: T::ProtoRequest,
12865 position: Option<Anchor>,
12866 cx: &mut AsyncApp,
12867 ) -> Result<()>
12868 where
12869 T: LspCommand + Clone,
12870 T::ProtoRequest: proto::LspRequestMessage,
12871 <T::ProtoRequest as proto::RequestMessage>::Response:
12872 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12873 {
12874 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12875 let version = deserialize_version(proto_request.buffer_version());
12876 let buffer = lsp_store.update(cx, |this, cx| {
12877 this.buffer_store.read(cx).get_existing(buffer_id)
12878 })??;
12879 buffer
12880 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12881 .await?;
12882 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12883 let request =
12884 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12885 let key = LspKey {
12886 request_type: TypeId::of::<T>(),
12887 server_queried: for_server_id,
12888 };
12889 lsp_store.update(cx, |lsp_store, cx| {
12890 let request_task = match for_server_id {
12891 Some(server_id) => {
12892 let server_task = lsp_store.request_lsp(
12893 buffer.clone(),
12894 LanguageServerToQuery::Other(server_id),
12895 request.clone(),
12896 cx,
12897 );
12898 cx.background_spawn(async move {
12899 let mut responses = Vec::new();
12900 match server_task.await {
12901 Ok(response) => responses.push((server_id, response)),
12902 // rust-analyzer likes to error with this when its still loading up
12903 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12904 Err(e) => log::error!(
12905 "Error handling response for request {request:?}: {e:#}"
12906 ),
12907 }
12908 responses
12909 })
12910 }
12911 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12912 };
12913 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12914 if T::ProtoRequest::stop_previous_requests() {
12915 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12916 lsp_requests.clear();
12917 }
12918 }
12919 lsp_data.lsp_requests.entry(key).or_default().insert(
12920 lsp_request_id,
12921 cx.spawn(async move |lsp_store, cx| {
12922 let response = request_task.await;
12923 lsp_store
12924 .update(cx, |lsp_store, cx| {
12925 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12926 {
12927 let response = response
12928 .into_iter()
12929 .map(|(server_id, response)| {
12930 (
12931 server_id.to_proto(),
12932 T::response_to_proto(
12933 response,
12934 lsp_store,
12935 sender_id,
12936 &buffer_version,
12937 cx,
12938 )
12939 .into(),
12940 )
12941 })
12942 .collect::<HashMap<_, _>>();
12943 match client.send_lsp_response::<T::ProtoRequest>(
12944 project_id,
12945 lsp_request_id,
12946 response,
12947 ) {
12948 Ok(()) => {}
12949 Err(e) => {
12950 log::error!("Failed to send LSP response: {e:#}",)
12951 }
12952 }
12953 }
12954 })
12955 .ok();
12956 }),
12957 );
12958 })?;
12959 Ok(())
12960 }
12961
12962 fn take_text_document_sync_options(
12963 capabilities: &mut lsp::ServerCapabilities,
12964 ) -> lsp::TextDocumentSyncOptions {
12965 match capabilities.text_document_sync.take() {
12966 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12967 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12968 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12969 sync_options.change = Some(sync_kind);
12970 sync_options
12971 }
12972 None => lsp::TextDocumentSyncOptions::default(),
12973 }
12974 }
12975
12976 #[cfg(any(test, feature = "test-support"))]
12977 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12978 Some(
12979 self.lsp_data
12980 .get_mut(&buffer_id)?
12981 .code_lens
12982 .take()?
12983 .update
12984 .take()?
12985 .1,
12986 )
12987 }
12988
12989 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12990 self.downstream_client.clone()
12991 }
12992
12993 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12994 self.worktree_store.clone()
12995 }
12996
12997 /// Gets what's stored in the LSP data for the given buffer.
12998 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12999 self.lsp_data.get_mut(&buffer_id)
13000 }
13001
13002 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13003 /// new [`BufferLspData`] will be created to replace the previous state.
13004 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13005 let (buffer_id, buffer_version) =
13006 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13007 let lsp_data = self
13008 .lsp_data
13009 .entry(buffer_id)
13010 .or_insert_with(|| BufferLspData::new(buffer, cx));
13011 if buffer_version.changed_since(&lsp_data.buffer_version) {
13012 *lsp_data = BufferLspData::new(buffer, cx);
13013 }
13014 lsp_data
13015 }
13016}
13017
13018// Registration with registerOptions as null, should fallback to true.
13019// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13020fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13021 reg: lsp::Registration,
13022) -> Result<OneOf<bool, T>> {
13023 Ok(match reg.register_options {
13024 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13025 None => OneOf::Left(true),
13026 })
13027}
13028
13029fn subscribe_to_binary_statuses(
13030 languages: &Arc<LanguageRegistry>,
13031 cx: &mut Context<'_, LspStore>,
13032) -> Task<()> {
13033 let mut server_statuses = languages.language_server_binary_statuses();
13034 cx.spawn(async move |lsp_store, cx| {
13035 while let Some((server_name, binary_status)) = server_statuses.next().await {
13036 if lsp_store
13037 .update(cx, |_, cx| {
13038 let mut message = None;
13039 let binary_status = match binary_status {
13040 BinaryStatus::None => proto::ServerBinaryStatus::None,
13041 BinaryStatus::CheckingForUpdate => {
13042 proto::ServerBinaryStatus::CheckingForUpdate
13043 }
13044 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13045 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13046 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13047 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13048 BinaryStatus::Failed { error } => {
13049 message = Some(error);
13050 proto::ServerBinaryStatus::Failed
13051 }
13052 };
13053 cx.emit(LspStoreEvent::LanguageServerUpdate {
13054 // Binary updates are about the binary that might not have any language server id at that point.
13055 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13056 language_server_id: LanguageServerId(0),
13057 name: Some(server_name),
13058 message: proto::update_language_server::Variant::StatusUpdate(
13059 proto::StatusUpdate {
13060 message,
13061 status: Some(proto::status_update::Status::Binary(
13062 binary_status as i32,
13063 )),
13064 },
13065 ),
13066 });
13067 })
13068 .is_err()
13069 {
13070 break;
13071 }
13072 }
13073 })
13074}
13075
13076fn lsp_workspace_diagnostics_refresh(
13077 registration_id: Option<String>,
13078 options: DiagnosticServerCapabilities,
13079 server: Arc<LanguageServer>,
13080 cx: &mut Context<'_, LspStore>,
13081) -> Option<WorkspaceRefreshTask> {
13082 let identifier = workspace_diagnostic_identifier(&options)?;
13083 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13084
13085 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13086 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13087 refresh_tx.try_send(()).ok();
13088
13089 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13090 let mut attempts = 0;
13091 let max_attempts = 50;
13092 let mut requests = 0;
13093
13094 loop {
13095 let Some(()) = refresh_rx.recv().await else {
13096 return;
13097 };
13098
13099 'request: loop {
13100 requests += 1;
13101 if attempts > max_attempts {
13102 log::error!(
13103 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13104 );
13105 return;
13106 }
13107 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13108 cx.background_executor()
13109 .timer(Duration::from_millis(backoff_millis))
13110 .await;
13111 attempts += 1;
13112
13113 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13114 lsp_store
13115 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13116 .into_iter()
13117 .filter_map(|(abs_path, result_id)| {
13118 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13119 Some(lsp::PreviousResultId {
13120 uri,
13121 value: result_id.to_string(),
13122 })
13123 })
13124 .collect()
13125 }) else {
13126 return;
13127 };
13128
13129 let token = if let Some(registration_id) = ®istration_id {
13130 format!(
13131 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13132 server.server_id(),
13133 )
13134 } else {
13135 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13136 };
13137
13138 progress_rx.try_recv().ok();
13139 let timer =
13140 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13141 let progress = pin!(progress_rx.recv().fuse());
13142 let response_result = server
13143 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13144 lsp::WorkspaceDiagnosticParams {
13145 previous_result_ids,
13146 identifier: identifier.clone(),
13147 work_done_progress_params: Default::default(),
13148 partial_result_params: lsp::PartialResultParams {
13149 partial_result_token: Some(lsp::ProgressToken::String(token)),
13150 },
13151 },
13152 select(timer, progress).then(|either| match either {
13153 Either::Left((message, ..)) => ready(message).left_future(),
13154 Either::Right(..) => pending::<String>().right_future(),
13155 }),
13156 )
13157 .await;
13158
13159 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13160 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13161 match response_result {
13162 ConnectionResult::Timeout => {
13163 log::error!("Timeout during workspace diagnostics pull");
13164 continue 'request;
13165 }
13166 ConnectionResult::ConnectionReset => {
13167 log::error!("Server closed a workspace diagnostics pull request");
13168 continue 'request;
13169 }
13170 ConnectionResult::Result(Err(e)) => {
13171 log::error!("Error during workspace diagnostics pull: {e:#}");
13172 break 'request;
13173 }
13174 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13175 attempts = 0;
13176 if lsp_store
13177 .update(cx, |lsp_store, cx| {
13178 lsp_store.apply_workspace_diagnostic_report(
13179 server.server_id(),
13180 pulled_diagnostics,
13181 registration_id_shared.clone(),
13182 cx,
13183 )
13184 })
13185 .is_err()
13186 {
13187 return;
13188 }
13189 break 'request;
13190 }
13191 }
13192 }
13193 }
13194 });
13195
13196 Some(WorkspaceRefreshTask {
13197 refresh_tx,
13198 progress_tx,
13199 task: workspace_query_language_server,
13200 })
13201}
13202
13203fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13204 match &options {
13205 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13206 diagnostic_options.identifier.clone()
13207 }
13208 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13209 let diagnostic_options = ®istration_options.diagnostic_options;
13210 diagnostic_options.identifier.clone()
13211 }
13212 }
13213}
13214
13215fn workspace_diagnostic_identifier(
13216 options: &DiagnosticServerCapabilities,
13217) -> Option<Option<String>> {
13218 match &options {
13219 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13220 if !diagnostic_options.workspace_diagnostics {
13221 return None;
13222 }
13223 Some(diagnostic_options.identifier.clone())
13224 }
13225 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13226 let diagnostic_options = ®istration_options.diagnostic_options;
13227 if !diagnostic_options.workspace_diagnostics {
13228 return None;
13229 }
13230 Some(diagnostic_options.identifier.clone())
13231 }
13232 }
13233}
13234
13235fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13236 let CompletionSource::BufferWord {
13237 word_range,
13238 resolved,
13239 } = &mut completion.source
13240 else {
13241 return;
13242 };
13243 if *resolved {
13244 return;
13245 }
13246
13247 if completion.new_text
13248 != snapshot
13249 .text_for_range(word_range.clone())
13250 .collect::<String>()
13251 {
13252 return;
13253 }
13254
13255 let mut offset = 0;
13256 for chunk in snapshot.chunks(word_range.clone(), true) {
13257 let end_offset = offset + chunk.text.len();
13258 if let Some(highlight_id) = chunk.syntax_highlight_id {
13259 completion
13260 .label
13261 .runs
13262 .push((offset..end_offset, highlight_id));
13263 }
13264 offset = end_offset;
13265 }
13266 *resolved = true;
13267}
13268
13269impl EventEmitter<LspStoreEvent> for LspStore {}
13270
13271fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13272 hover
13273 .contents
13274 .retain(|hover_block| !hover_block.text.trim().is_empty());
13275 if hover.contents.is_empty() {
13276 None
13277 } else {
13278 Some(hover)
13279 }
13280}
13281
13282async fn populate_labels_for_completions(
13283 new_completions: Vec<CoreCompletion>,
13284 language: Option<Arc<Language>>,
13285 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13286) -> Vec<Completion> {
13287 let lsp_completions = new_completions
13288 .iter()
13289 .filter_map(|new_completion| {
13290 new_completion
13291 .source
13292 .lsp_completion(true)
13293 .map(|lsp_completion| lsp_completion.into_owned())
13294 })
13295 .collect::<Vec<_>>();
13296
13297 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13298 lsp_adapter
13299 .labels_for_completions(&lsp_completions, language)
13300 .await
13301 .log_err()
13302 .unwrap_or_default()
13303 } else {
13304 Vec::new()
13305 }
13306 .into_iter()
13307 .fuse();
13308
13309 let mut completions = Vec::new();
13310 for completion in new_completions {
13311 match completion.source.lsp_completion(true) {
13312 Some(lsp_completion) => {
13313 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13314
13315 let mut label = labels.next().flatten().unwrap_or_else(|| {
13316 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13317 });
13318 ensure_uniform_list_compatible_label(&mut label);
13319 completions.push(Completion {
13320 label,
13321 documentation,
13322 replace_range: completion.replace_range,
13323 new_text: completion.new_text,
13324 insert_text_mode: lsp_completion.insert_text_mode,
13325 source: completion.source,
13326 icon_path: None,
13327 confirm: None,
13328 match_start: None,
13329 snippet_deduplication_key: None,
13330 });
13331 }
13332 None => {
13333 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13334 ensure_uniform_list_compatible_label(&mut label);
13335 completions.push(Completion {
13336 label,
13337 documentation: None,
13338 replace_range: completion.replace_range,
13339 new_text: completion.new_text,
13340 source: completion.source,
13341 insert_text_mode: None,
13342 icon_path: None,
13343 confirm: None,
13344 match_start: None,
13345 snippet_deduplication_key: None,
13346 });
13347 }
13348 }
13349 }
13350 completions
13351}
13352
13353#[derive(Debug)]
13354pub enum LanguageServerToQuery {
13355 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13356 FirstCapable,
13357 /// Query a specific language server.
13358 Other(LanguageServerId),
13359}
13360
13361#[derive(Default)]
13362struct RenamePathsWatchedForServer {
13363 did_rename: Vec<RenameActionPredicate>,
13364 will_rename: Vec<RenameActionPredicate>,
13365}
13366
13367impl RenamePathsWatchedForServer {
13368 fn with_did_rename_patterns(
13369 mut self,
13370 did_rename: Option<&FileOperationRegistrationOptions>,
13371 ) -> Self {
13372 if let Some(did_rename) = did_rename {
13373 self.did_rename = did_rename
13374 .filters
13375 .iter()
13376 .filter_map(|filter| filter.try_into().log_err())
13377 .collect();
13378 }
13379 self
13380 }
13381 fn with_will_rename_patterns(
13382 mut self,
13383 will_rename: Option<&FileOperationRegistrationOptions>,
13384 ) -> Self {
13385 if let Some(will_rename) = will_rename {
13386 self.will_rename = will_rename
13387 .filters
13388 .iter()
13389 .filter_map(|filter| filter.try_into().log_err())
13390 .collect();
13391 }
13392 self
13393 }
13394
13395 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13396 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13397 }
13398 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13399 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13400 }
13401}
13402
13403impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13404 type Error = globset::Error;
13405 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13406 Ok(Self {
13407 kind: ops.pattern.matches.clone(),
13408 glob: GlobBuilder::new(&ops.pattern.glob)
13409 .case_insensitive(
13410 ops.pattern
13411 .options
13412 .as_ref()
13413 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13414 )
13415 .build()?
13416 .compile_matcher(),
13417 })
13418 }
13419}
13420struct RenameActionPredicate {
13421 glob: GlobMatcher,
13422 kind: Option<FileOperationPatternKind>,
13423}
13424
13425impl RenameActionPredicate {
13426 // Returns true if language server should be notified
13427 fn eval(&self, path: &str, is_dir: bool) -> bool {
13428 self.kind.as_ref().is_none_or(|kind| {
13429 let expected_kind = if is_dir {
13430 FileOperationPatternKind::Folder
13431 } else {
13432 FileOperationPatternKind::File
13433 };
13434 kind == &expected_kind
13435 }) && self.glob.is_match(path)
13436 }
13437}
13438
13439#[derive(Default)]
13440struct LanguageServerWatchedPaths {
13441 worktree_paths: HashMap<WorktreeId, GlobSet>,
13442 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13443}
13444
13445#[derive(Default)]
13446struct LanguageServerWatchedPathsBuilder {
13447 worktree_paths: HashMap<WorktreeId, GlobSet>,
13448 abs_paths: HashMap<Arc<Path>, GlobSet>,
13449}
13450
13451impl LanguageServerWatchedPathsBuilder {
13452 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13453 self.worktree_paths.insert(worktree_id, glob_set);
13454 }
13455 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13456 self.abs_paths.insert(path, glob_set);
13457 }
13458 fn build(
13459 self,
13460 fs: Arc<dyn Fs>,
13461 language_server_id: LanguageServerId,
13462 cx: &mut Context<LspStore>,
13463 ) -> LanguageServerWatchedPaths {
13464 let lsp_store = cx.weak_entity();
13465
13466 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13467 let abs_paths = self
13468 .abs_paths
13469 .into_iter()
13470 .map(|(abs_path, globset)| {
13471 let task = cx.spawn({
13472 let abs_path = abs_path.clone();
13473 let fs = fs.clone();
13474
13475 let lsp_store = lsp_store.clone();
13476 async move |_, cx| {
13477 maybe!(async move {
13478 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13479 while let Some(update) = push_updates.0.next().await {
13480 let action = lsp_store
13481 .update(cx, |this, _| {
13482 let Some(local) = this.as_local() else {
13483 return ControlFlow::Break(());
13484 };
13485 let Some(watcher) = local
13486 .language_server_watched_paths
13487 .get(&language_server_id)
13488 else {
13489 return ControlFlow::Break(());
13490 };
13491 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13492 "Watched abs path is not registered with a watcher",
13493 );
13494 let matching_entries = update
13495 .into_iter()
13496 .filter(|event| globs.is_match(&event.path))
13497 .collect::<Vec<_>>();
13498 this.lsp_notify_abs_paths_changed(
13499 language_server_id,
13500 matching_entries,
13501 );
13502 ControlFlow::Continue(())
13503 })
13504 .ok()?;
13505
13506 if action.is_break() {
13507 break;
13508 }
13509 }
13510 Some(())
13511 })
13512 .await;
13513 }
13514 });
13515 (abs_path, (globset, task))
13516 })
13517 .collect();
13518 LanguageServerWatchedPaths {
13519 worktree_paths: self.worktree_paths,
13520 abs_paths,
13521 }
13522 }
13523}
13524
13525struct LspBufferSnapshot {
13526 version: i32,
13527 snapshot: TextBufferSnapshot,
13528}
13529
13530/// A prompt requested by LSP server.
13531#[derive(Clone, Debug)]
13532pub struct LanguageServerPromptRequest {
13533 pub level: PromptLevel,
13534 pub message: String,
13535 pub actions: Vec<MessageActionItem>,
13536 pub lsp_name: String,
13537 pub(crate) response_channel: Sender<MessageActionItem>,
13538}
13539
13540impl LanguageServerPromptRequest {
13541 pub async fn respond(self, index: usize) -> Option<()> {
13542 if let Some(response) = self.actions.into_iter().nth(index) {
13543 self.response_channel.send(response).await.ok()
13544 } else {
13545 None
13546 }
13547 }
13548}
13549impl PartialEq for LanguageServerPromptRequest {
13550 fn eq(&self, other: &Self) -> bool {
13551 self.message == other.message && self.actions == other.actions
13552 }
13553}
13554
13555#[derive(Clone, Debug, PartialEq)]
13556pub enum LanguageServerLogType {
13557 Log(MessageType),
13558 Trace { verbose_info: Option<String> },
13559 Rpc { received: bool },
13560}
13561
13562impl LanguageServerLogType {
13563 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13564 match self {
13565 Self::Log(log_type) => {
13566 use proto::log_message::LogLevel;
13567 let level = match *log_type {
13568 MessageType::ERROR => LogLevel::Error,
13569 MessageType::WARNING => LogLevel::Warning,
13570 MessageType::INFO => LogLevel::Info,
13571 MessageType::LOG => LogLevel::Log,
13572 other => {
13573 log::warn!("Unknown lsp log message type: {other:?}");
13574 LogLevel::Log
13575 }
13576 };
13577 proto::language_server_log::LogType::Log(proto::LogMessage {
13578 level: level as i32,
13579 })
13580 }
13581 Self::Trace { verbose_info } => {
13582 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13583 verbose_info: verbose_info.to_owned(),
13584 })
13585 }
13586 Self::Rpc { received } => {
13587 let kind = if *received {
13588 proto::rpc_message::Kind::Received
13589 } else {
13590 proto::rpc_message::Kind::Sent
13591 };
13592 let kind = kind as i32;
13593 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13594 }
13595 }
13596 }
13597
13598 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13599 use proto::log_message::LogLevel;
13600 use proto::rpc_message;
13601 match log_type {
13602 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13603 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13604 LogLevel::Error => MessageType::ERROR,
13605 LogLevel::Warning => MessageType::WARNING,
13606 LogLevel::Info => MessageType::INFO,
13607 LogLevel::Log => MessageType::LOG,
13608 },
13609 ),
13610 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13611 verbose_info: trace_message.verbose_info,
13612 },
13613 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13614 received: match rpc_message::Kind::from_i32(message.kind)
13615 .unwrap_or(rpc_message::Kind::Received)
13616 {
13617 rpc_message::Kind::Received => true,
13618 rpc_message::Kind::Sent => false,
13619 },
13620 },
13621 }
13622 }
13623}
13624
13625pub struct WorkspaceRefreshTask {
13626 refresh_tx: mpsc::Sender<()>,
13627 progress_tx: mpsc::Sender<()>,
13628 #[allow(dead_code)]
13629 task: Task<()>,
13630}
13631
13632pub enum LanguageServerState {
13633 Starting {
13634 startup: Task<Option<Arc<LanguageServer>>>,
13635 /// List of language servers that will be added to the workspace once it's initialization completes.
13636 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13637 },
13638
13639 Running {
13640 adapter: Arc<CachedLspAdapter>,
13641 server: Arc<LanguageServer>,
13642 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13643 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13644 },
13645}
13646
13647impl LanguageServerState {
13648 fn add_workspace_folder(&self, uri: Uri) {
13649 match self {
13650 LanguageServerState::Starting {
13651 pending_workspace_folders,
13652 ..
13653 } => {
13654 pending_workspace_folders.lock().insert(uri);
13655 }
13656 LanguageServerState::Running { server, .. } => {
13657 server.add_workspace_folder(uri);
13658 }
13659 }
13660 }
13661 fn _remove_workspace_folder(&self, uri: Uri) {
13662 match self {
13663 LanguageServerState::Starting {
13664 pending_workspace_folders,
13665 ..
13666 } => {
13667 pending_workspace_folders.lock().remove(&uri);
13668 }
13669 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13670 }
13671 }
13672}
13673
13674impl std::fmt::Debug for LanguageServerState {
13675 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13676 match self {
13677 LanguageServerState::Starting { .. } => {
13678 f.debug_struct("LanguageServerState::Starting").finish()
13679 }
13680 LanguageServerState::Running { .. } => {
13681 f.debug_struct("LanguageServerState::Running").finish()
13682 }
13683 }
13684 }
13685}
13686
13687#[derive(Clone, Debug, Serialize)]
13688pub struct LanguageServerProgress {
13689 pub is_disk_based_diagnostics_progress: bool,
13690 pub is_cancellable: bool,
13691 pub title: Option<String>,
13692 pub message: Option<String>,
13693 pub percentage: Option<usize>,
13694 #[serde(skip_serializing)]
13695 pub last_update_at: Instant,
13696}
13697
13698#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13699pub struct DiagnosticSummary {
13700 pub error_count: usize,
13701 pub warning_count: usize,
13702}
13703
13704impl DiagnosticSummary {
13705 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13706 let mut this = Self {
13707 error_count: 0,
13708 warning_count: 0,
13709 };
13710
13711 for entry in diagnostics {
13712 if entry.diagnostic.is_primary {
13713 match entry.diagnostic.severity {
13714 DiagnosticSeverity::ERROR => this.error_count += 1,
13715 DiagnosticSeverity::WARNING => this.warning_count += 1,
13716 _ => {}
13717 }
13718 }
13719 }
13720
13721 this
13722 }
13723
13724 pub fn is_empty(&self) -> bool {
13725 self.error_count == 0 && self.warning_count == 0
13726 }
13727
13728 pub fn to_proto(
13729 self,
13730 language_server_id: LanguageServerId,
13731 path: &RelPath,
13732 ) -> proto::DiagnosticSummary {
13733 proto::DiagnosticSummary {
13734 path: path.to_proto(),
13735 language_server_id: language_server_id.0 as u64,
13736 error_count: self.error_count as u32,
13737 warning_count: self.warning_count as u32,
13738 }
13739 }
13740}
13741
13742#[derive(Clone, Debug)]
13743pub enum CompletionDocumentation {
13744 /// There is no documentation for this completion.
13745 Undocumented,
13746 /// A single line of documentation.
13747 SingleLine(SharedString),
13748 /// Multiple lines of plain text documentation.
13749 MultiLinePlainText(SharedString),
13750 /// Markdown documentation.
13751 MultiLineMarkdown(SharedString),
13752 /// Both single line and multiple lines of plain text documentation.
13753 SingleLineAndMultiLinePlainText {
13754 single_line: SharedString,
13755 plain_text: Option<SharedString>,
13756 },
13757}
13758
13759impl CompletionDocumentation {
13760 #[cfg(any(test, feature = "test-support"))]
13761 pub fn text(&self) -> SharedString {
13762 match self {
13763 CompletionDocumentation::Undocumented => "".into(),
13764 CompletionDocumentation::SingleLine(s) => s.clone(),
13765 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13766 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13767 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13768 single_line.clone()
13769 }
13770 }
13771 }
13772}
13773
13774impl From<lsp::Documentation> for CompletionDocumentation {
13775 fn from(docs: lsp::Documentation) -> Self {
13776 match docs {
13777 lsp::Documentation::String(text) => {
13778 if text.lines().count() <= 1 {
13779 CompletionDocumentation::SingleLine(text.into())
13780 } else {
13781 CompletionDocumentation::MultiLinePlainText(text.into())
13782 }
13783 }
13784
13785 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13786 lsp::MarkupKind::PlainText => {
13787 if value.lines().count() <= 1 {
13788 CompletionDocumentation::SingleLine(value.into())
13789 } else {
13790 CompletionDocumentation::MultiLinePlainText(value.into())
13791 }
13792 }
13793
13794 lsp::MarkupKind::Markdown => {
13795 CompletionDocumentation::MultiLineMarkdown(value.into())
13796 }
13797 },
13798 }
13799 }
13800}
13801
13802pub enum ResolvedHint {
13803 Resolved(InlayHint),
13804 Resolving(Shared<Task<()>>),
13805}
13806
13807fn glob_literal_prefix(glob: &Path) -> PathBuf {
13808 glob.components()
13809 .take_while(|component| match component {
13810 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13811 _ => true,
13812 })
13813 .collect()
13814}
13815
13816pub struct SshLspAdapter {
13817 name: LanguageServerName,
13818 binary: LanguageServerBinary,
13819 initialization_options: Option<String>,
13820 code_action_kinds: Option<Vec<CodeActionKind>>,
13821}
13822
13823impl SshLspAdapter {
13824 pub fn new(
13825 name: LanguageServerName,
13826 binary: LanguageServerBinary,
13827 initialization_options: Option<String>,
13828 code_action_kinds: Option<String>,
13829 ) -> Self {
13830 Self {
13831 name,
13832 binary,
13833 initialization_options,
13834 code_action_kinds: code_action_kinds
13835 .as_ref()
13836 .and_then(|c| serde_json::from_str(c).ok()),
13837 }
13838 }
13839}
13840
13841impl LspInstaller for SshLspAdapter {
13842 type BinaryVersion = ();
13843 async fn check_if_user_installed(
13844 &self,
13845 _: &dyn LspAdapterDelegate,
13846 _: Option<Toolchain>,
13847 _: &AsyncApp,
13848 ) -> Option<LanguageServerBinary> {
13849 Some(self.binary.clone())
13850 }
13851
13852 async fn cached_server_binary(
13853 &self,
13854 _: PathBuf,
13855 _: &dyn LspAdapterDelegate,
13856 ) -> Option<LanguageServerBinary> {
13857 None
13858 }
13859
13860 async fn fetch_latest_server_version(
13861 &self,
13862 _: &dyn LspAdapterDelegate,
13863 _: bool,
13864 _: &mut AsyncApp,
13865 ) -> Result<()> {
13866 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13867 }
13868
13869 async fn fetch_server_binary(
13870 &self,
13871 _: (),
13872 _: PathBuf,
13873 _: &dyn LspAdapterDelegate,
13874 ) -> Result<LanguageServerBinary> {
13875 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13876 }
13877}
13878
13879#[async_trait(?Send)]
13880impl LspAdapter for SshLspAdapter {
13881 fn name(&self) -> LanguageServerName {
13882 self.name.clone()
13883 }
13884
13885 async fn initialization_options(
13886 self: Arc<Self>,
13887 _: &Arc<dyn LspAdapterDelegate>,
13888 ) -> Result<Option<serde_json::Value>> {
13889 let Some(options) = &self.initialization_options else {
13890 return Ok(None);
13891 };
13892 let result = serde_json::from_str(options)?;
13893 Ok(result)
13894 }
13895
13896 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13897 self.code_action_kinds.clone()
13898 }
13899}
13900
13901pub fn language_server_settings<'a>(
13902 delegate: &'a dyn LspAdapterDelegate,
13903 language: &LanguageServerName,
13904 cx: &'a App,
13905) -> Option<&'a LspSettings> {
13906 language_server_settings_for(
13907 SettingsLocation {
13908 worktree_id: delegate.worktree_id(),
13909 path: RelPath::empty(),
13910 },
13911 language,
13912 cx,
13913 )
13914}
13915
13916pub fn language_server_settings_for<'a>(
13917 location: SettingsLocation<'a>,
13918 language: &LanguageServerName,
13919 cx: &'a App,
13920) -> Option<&'a LspSettings> {
13921 ProjectSettings::get(Some(location), cx).lsp.get(language)
13922}
13923
13924pub struct LocalLspAdapterDelegate {
13925 lsp_store: WeakEntity<LspStore>,
13926 worktree: worktree::Snapshot,
13927 fs: Arc<dyn Fs>,
13928 http_client: Arc<dyn HttpClient>,
13929 language_registry: Arc<LanguageRegistry>,
13930 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13931}
13932
13933impl LocalLspAdapterDelegate {
13934 pub fn new(
13935 language_registry: Arc<LanguageRegistry>,
13936 environment: &Entity<ProjectEnvironment>,
13937 lsp_store: WeakEntity<LspStore>,
13938 worktree: &Entity<Worktree>,
13939 http_client: Arc<dyn HttpClient>,
13940 fs: Arc<dyn Fs>,
13941 cx: &mut App,
13942 ) -> Arc<Self> {
13943 let load_shell_env_task =
13944 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13945
13946 Arc::new(Self {
13947 lsp_store,
13948 worktree: worktree.read(cx).snapshot(),
13949 fs,
13950 http_client,
13951 language_registry,
13952 load_shell_env_task,
13953 })
13954 }
13955
13956 fn from_local_lsp(
13957 local: &LocalLspStore,
13958 worktree: &Entity<Worktree>,
13959 cx: &mut App,
13960 ) -> Arc<Self> {
13961 Self::new(
13962 local.languages.clone(),
13963 &local.environment,
13964 local.weak.clone(),
13965 worktree,
13966 local.http_client.clone(),
13967 local.fs.clone(),
13968 cx,
13969 )
13970 }
13971}
13972
13973#[async_trait]
13974impl LspAdapterDelegate for LocalLspAdapterDelegate {
13975 fn show_notification(&self, message: &str, cx: &mut App) {
13976 self.lsp_store
13977 .update(cx, |_, cx| {
13978 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13979 })
13980 .ok();
13981 }
13982
13983 fn http_client(&self) -> Arc<dyn HttpClient> {
13984 self.http_client.clone()
13985 }
13986
13987 fn worktree_id(&self) -> WorktreeId {
13988 self.worktree.id()
13989 }
13990
13991 fn worktree_root_path(&self) -> &Path {
13992 self.worktree.abs_path().as_ref()
13993 }
13994
13995 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13996 self.worktree.resolve_executable_path(path)
13997 }
13998
13999 async fn shell_env(&self) -> HashMap<String, String> {
14000 let task = self.load_shell_env_task.clone();
14001 task.await.unwrap_or_default()
14002 }
14003
14004 async fn npm_package_installed_version(
14005 &self,
14006 package_name: &str,
14007 ) -> Result<Option<(PathBuf, Version)>> {
14008 let local_package_directory = self.worktree_root_path();
14009 let node_modules_directory = local_package_directory.join("node_modules");
14010
14011 if let Some(version) =
14012 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14013 {
14014 return Ok(Some((node_modules_directory, version)));
14015 }
14016 let Some(npm) = self.which("npm".as_ref()).await else {
14017 log::warn!(
14018 "Failed to find npm executable for {:?}",
14019 local_package_directory
14020 );
14021 return Ok(None);
14022 };
14023
14024 let env = self.shell_env().await;
14025 let output = util::command::new_smol_command(&npm)
14026 .args(["root", "-g"])
14027 .envs(env)
14028 .current_dir(local_package_directory)
14029 .output()
14030 .await?;
14031 let global_node_modules =
14032 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14033
14034 if let Some(version) =
14035 read_package_installed_version(global_node_modules.clone(), package_name).await?
14036 {
14037 return Ok(Some((global_node_modules, version)));
14038 }
14039 return Ok(None);
14040 }
14041
14042 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14043 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14044 if self.fs.is_file(&worktree_abs_path).await {
14045 worktree_abs_path.pop();
14046 }
14047
14048 let env = self.shell_env().await;
14049
14050 let shell_path = env.get("PATH").cloned();
14051
14052 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14053 }
14054
14055 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14056 let mut working_dir = self.worktree_root_path().to_path_buf();
14057 if self.fs.is_file(&working_dir).await {
14058 working_dir.pop();
14059 }
14060 let output = util::command::new_smol_command(&command.path)
14061 .args(command.arguments)
14062 .envs(command.env.clone().unwrap_or_default())
14063 .current_dir(working_dir)
14064 .output()
14065 .await?;
14066
14067 anyhow::ensure!(
14068 output.status.success(),
14069 "{}, stdout: {:?}, stderr: {:?}",
14070 output.status,
14071 String::from_utf8_lossy(&output.stdout),
14072 String::from_utf8_lossy(&output.stderr)
14073 );
14074 Ok(())
14075 }
14076
14077 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14078 self.language_registry
14079 .update_lsp_binary_status(server_name, status);
14080 }
14081
14082 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14083 self.language_registry
14084 .all_lsp_adapters()
14085 .into_iter()
14086 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14087 .collect()
14088 }
14089
14090 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14091 let dir = self.language_registry.language_server_download_dir(name)?;
14092
14093 if !dir.exists() {
14094 smol::fs::create_dir_all(&dir)
14095 .await
14096 .context("failed to create container directory")
14097 .log_err()?;
14098 }
14099
14100 Some(dir)
14101 }
14102
14103 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14104 let entry = self
14105 .worktree
14106 .entry_for_path(path)
14107 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14108 let abs_path = self.worktree.absolutize(&entry.path);
14109 self.fs.load(&abs_path).await
14110 }
14111}
14112
14113async fn populate_labels_for_symbols(
14114 symbols: Vec<CoreSymbol>,
14115 language_registry: &Arc<LanguageRegistry>,
14116 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14117 output: &mut Vec<Symbol>,
14118) {
14119 #[allow(clippy::mutable_key_type)]
14120 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14121
14122 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14123 for symbol in symbols {
14124 let Some(file_name) = symbol.path.file_name() else {
14125 continue;
14126 };
14127 let language = language_registry
14128 .load_language_for_file_path(Path::new(file_name))
14129 .await
14130 .ok()
14131 .or_else(|| {
14132 unknown_paths.insert(file_name.into());
14133 None
14134 });
14135 symbols_by_language
14136 .entry(language)
14137 .or_default()
14138 .push(symbol);
14139 }
14140
14141 for unknown_path in unknown_paths {
14142 log::info!("no language found for symbol in file {unknown_path:?}");
14143 }
14144
14145 let mut label_params = Vec::new();
14146 for (language, mut symbols) in symbols_by_language {
14147 label_params.clear();
14148 label_params.extend(
14149 symbols
14150 .iter_mut()
14151 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14152 );
14153
14154 let mut labels = Vec::new();
14155 if let Some(language) = language {
14156 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14157 language_registry
14158 .lsp_adapters(&language.name())
14159 .first()
14160 .cloned()
14161 });
14162 if let Some(lsp_adapter) = lsp_adapter {
14163 labels = lsp_adapter
14164 .labels_for_symbols(&label_params, &language)
14165 .await
14166 .log_err()
14167 .unwrap_or_default();
14168 }
14169 }
14170
14171 for ((symbol, (name, _)), label) in symbols
14172 .into_iter()
14173 .zip(label_params.drain(..))
14174 .zip(labels.into_iter().chain(iter::repeat(None)))
14175 {
14176 output.push(Symbol {
14177 language_server_name: symbol.language_server_name,
14178 source_worktree_id: symbol.source_worktree_id,
14179 source_language_server_id: symbol.source_language_server_id,
14180 path: symbol.path,
14181 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14182 name,
14183 kind: symbol.kind,
14184 range: symbol.range,
14185 });
14186 }
14187 }
14188}
14189
14190fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14191 match server.capabilities().text_document_sync.as_ref()? {
14192 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14193 // Server wants didSave but didn't specify includeText.
14194 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14195 // Server doesn't want didSave at all.
14196 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14197 // Server provided SaveOptions.
14198 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14199 Some(save_options.include_text.unwrap_or(false))
14200 }
14201 },
14202 // We do not have any save info. Kind affects didChange only.
14203 lsp::TextDocumentSyncCapability::Kind(_) => None,
14204 }
14205}
14206
14207/// Completion items are displayed in a `UniformList`.
14208/// Usually, those items are single-line strings, but in LSP responses,
14209/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14210/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14211/// 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,
14212/// breaking the completions menu presentation.
14213///
14214/// 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.
14215fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14216 let mut new_text = String::with_capacity(label.text.len());
14217 let mut offset_map = vec![0; label.text.len() + 1];
14218 let mut last_char_was_space = false;
14219 let mut new_idx = 0;
14220 let chars = label.text.char_indices().fuse();
14221 let mut newlines_removed = false;
14222
14223 for (idx, c) in chars {
14224 offset_map[idx] = new_idx;
14225
14226 match c {
14227 '\n' if last_char_was_space => {
14228 newlines_removed = true;
14229 }
14230 '\t' | ' ' if last_char_was_space => {}
14231 '\n' if !last_char_was_space => {
14232 new_text.push(' ');
14233 new_idx += 1;
14234 last_char_was_space = true;
14235 newlines_removed = true;
14236 }
14237 ' ' | '\t' => {
14238 new_text.push(' ');
14239 new_idx += 1;
14240 last_char_was_space = true;
14241 }
14242 _ => {
14243 new_text.push(c);
14244 new_idx += c.len_utf8();
14245 last_char_was_space = false;
14246 }
14247 }
14248 }
14249 offset_map[label.text.len()] = new_idx;
14250
14251 // Only modify the label if newlines were removed.
14252 if !newlines_removed {
14253 return;
14254 }
14255
14256 let last_index = new_idx;
14257 let mut run_ranges_errors = Vec::new();
14258 label.runs.retain_mut(|(range, _)| {
14259 match offset_map.get(range.start) {
14260 Some(&start) => range.start = start,
14261 None => {
14262 run_ranges_errors.push(range.clone());
14263 return false;
14264 }
14265 }
14266
14267 match offset_map.get(range.end) {
14268 Some(&end) => range.end = end,
14269 None => {
14270 run_ranges_errors.push(range.clone());
14271 range.end = last_index;
14272 }
14273 }
14274 true
14275 });
14276 if !run_ranges_errors.is_empty() {
14277 log::error!(
14278 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14279 label.text
14280 );
14281 }
14282
14283 let mut wrong_filter_range = None;
14284 if label.filter_range == (0..label.text.len()) {
14285 label.filter_range = 0..new_text.len();
14286 } else {
14287 let mut original_filter_range = Some(label.filter_range.clone());
14288 match offset_map.get(label.filter_range.start) {
14289 Some(&start) => label.filter_range.start = start,
14290 None => {
14291 wrong_filter_range = original_filter_range.take();
14292 label.filter_range.start = last_index;
14293 }
14294 }
14295
14296 match offset_map.get(label.filter_range.end) {
14297 Some(&end) => label.filter_range.end = end,
14298 None => {
14299 wrong_filter_range = original_filter_range.take();
14300 label.filter_range.end = last_index;
14301 }
14302 }
14303 }
14304 if let Some(wrong_filter_range) = wrong_filter_range {
14305 log::error!(
14306 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14307 label.text
14308 );
14309 }
14310
14311 label.text = new_text;
14312}
14313
14314#[cfg(test)]
14315mod tests {
14316 use language::HighlightId;
14317
14318 use super::*;
14319
14320 #[test]
14321 fn test_glob_literal_prefix() {
14322 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14323 assert_eq!(
14324 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14325 Path::new("node_modules")
14326 );
14327 assert_eq!(
14328 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14329 Path::new("foo")
14330 );
14331 assert_eq!(
14332 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14333 Path::new("foo/bar/baz.js")
14334 );
14335
14336 #[cfg(target_os = "windows")]
14337 {
14338 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14339 assert_eq!(
14340 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14341 Path::new("node_modules")
14342 );
14343 assert_eq!(
14344 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14345 Path::new("foo")
14346 );
14347 assert_eq!(
14348 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14349 Path::new("foo/bar/baz.js")
14350 );
14351 }
14352 }
14353
14354 #[test]
14355 fn test_multi_len_chars_normalization() {
14356 let mut label = CodeLabel::new(
14357 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14358 0..6,
14359 vec![(0..6, HighlightId(1))],
14360 );
14361 ensure_uniform_list_compatible_label(&mut label);
14362 assert_eq!(
14363 label,
14364 CodeLabel::new(
14365 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14366 0..6,
14367 vec![(0..6, HighlightId(1))],
14368 )
14369 );
14370 }
14371}