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