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 serde::Serialize;
97use serde_json::Value;
98use settings::{Settings, SettingsLocation, SettingsStore};
99use sha2::{Digest, Sha256};
100use smol::channel::{Receiver, Sender};
101use snippet::Snippet;
102use std::{
103 any::TypeId,
104 borrow::Cow,
105 cell::RefCell,
106 cmp::{Ordering, Reverse},
107 collections::hash_map,
108 convert::TryInto,
109 ffi::OsStr,
110 future::ready,
111 iter, mem,
112 ops::{ControlFlow, Range},
113 path::{self, Path, PathBuf},
114 pin::pin,
115 rc::Rc,
116 sync::{
117 Arc,
118 atomic::{self, AtomicUsize},
119 },
120 time::{Duration, Instant},
121 vec,
122};
123use sum_tree::Dimensions;
124use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
125
126use util::{
127 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
128 paths::{PathStyle, SanitizedPath},
129 post_inc,
130 rel_path::RelPath,
131};
132
133pub use fs::*;
134pub use language::Location;
135pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
136#[cfg(any(test, feature = "test-support"))]
137pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
138pub use worktree::{
139 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
140 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
141};
142
143const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
144pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
145const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
146const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
147
148#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
149pub enum ProgressToken {
150 Number(i32),
151 String(SharedString),
152}
153
154impl std::fmt::Display for ProgressToken {
155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 match self {
157 Self::Number(number) => write!(f, "{number}"),
158 Self::String(string) => write!(f, "{string}"),
159 }
160 }
161}
162
163impl ProgressToken {
164 fn from_lsp(value: lsp::NumberOrString) -> Self {
165 match value {
166 lsp::NumberOrString::Number(number) => Self::Number(number),
167 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
168 }
169 }
170
171 fn to_lsp(&self) -> lsp::NumberOrString {
172 match self {
173 Self::Number(number) => lsp::NumberOrString::Number(*number),
174 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
175 }
176 }
177
178 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
179 Some(match value.value? {
180 proto::progress_token::Value::Number(number) => Self::Number(number),
181 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
182 })
183 }
184
185 fn to_proto(&self) -> proto::ProgressToken {
186 proto::ProgressToken {
187 value: Some(match self {
188 Self::Number(number) => proto::progress_token::Value::Number(*number),
189 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
190 }),
191 }
192 }
193}
194
195#[derive(Debug, Clone, Copy, PartialEq, Eq)]
196pub enum FormatTrigger {
197 Save,
198 Manual,
199}
200
201pub enum LspFormatTarget {
202 Buffers,
203 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
204}
205
206#[derive(Clone, PartialEq, Eq, Hash)]
207pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
208
209struct OpenLspBuffer(Entity<Buffer>);
210
211impl FormatTrigger {
212 fn from_proto(value: i32) -> FormatTrigger {
213 match value {
214 0 => FormatTrigger::Save,
215 1 => FormatTrigger::Manual,
216 _ => FormatTrigger::Save,
217 }
218 }
219}
220
221#[derive(Clone)]
222struct UnifiedLanguageServer {
223 id: LanguageServerId,
224 project_roots: HashSet<Arc<RelPath>>,
225}
226
227#[derive(Clone, Debug, Hash, PartialEq, Eq)]
228struct LanguageServerSeed {
229 worktree_id: WorktreeId,
230 name: LanguageServerName,
231 toolchain: Option<Toolchain>,
232 settings: Arc<LspSettings>,
233}
234
235#[derive(Debug)]
236pub struct DocumentDiagnosticsUpdate<'a, D> {
237 pub diagnostics: D,
238 pub result_id: Option<SharedString>,
239 pub registration_id: Option<SharedString>,
240 pub server_id: LanguageServerId,
241 pub disk_based_sources: Cow<'a, [String]>,
242}
243
244pub struct DocumentDiagnostics {
245 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
246 document_abs_path: PathBuf,
247 version: Option<i32>,
248}
249
250#[derive(Default, Debug)]
251struct DynamicRegistrations {
252 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
253 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
254}
255
256pub struct LocalLspStore {
257 weak: WeakEntity<LspStore>,
258 worktree_store: Entity<WorktreeStore>,
259 toolchain_store: Entity<LocalToolchainStore>,
260 http_client: Arc<dyn HttpClient>,
261 environment: Entity<ProjectEnvironment>,
262 fs: Arc<dyn Fs>,
263 languages: Arc<LanguageRegistry>,
264 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
265 yarn: Entity<YarnPathStore>,
266 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
267 buffers_being_formatted: HashSet<BufferId>,
268 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
269 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
270 watched_manifest_filenames: HashSet<ManifestName>,
271 language_server_paths_watched_for_rename:
272 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
273 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
274 supplementary_language_servers:
275 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
276 prettier_store: Entity<PrettierStore>,
277 next_diagnostic_group_id: usize,
278 diagnostics: HashMap<
279 WorktreeId,
280 HashMap<
281 Arc<RelPath>,
282 Vec<(
283 LanguageServerId,
284 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
285 )>,
286 >,
287 >,
288 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
289 _subscription: gpui::Subscription,
290 lsp_tree: LanguageServerTree,
291 registered_buffers: HashMap<BufferId, usize>,
292 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
293 buffer_pull_diagnostics_result_ids: HashMap<
294 LanguageServerId,
295 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
296 >,
297 workspace_pull_diagnostics_result_ids: HashMap<
298 LanguageServerId,
299 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
300 >,
301 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, Receiver<()>)>,
302}
303
304impl LocalLspStore {
305 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
306 pub fn running_language_server_for_id(
307 &self,
308 id: LanguageServerId,
309 ) -> Option<&Arc<LanguageServer>> {
310 let language_server_state = self.language_servers.get(&id)?;
311
312 match language_server_state {
313 LanguageServerState::Running { server, .. } => Some(server),
314 LanguageServerState::Starting { .. } => None,
315 }
316 }
317
318 fn get_or_insert_language_server(
319 &mut self,
320 worktree_handle: &Entity<Worktree>,
321 delegate: Arc<LocalLspAdapterDelegate>,
322 disposition: &Arc<LaunchDisposition>,
323 language_name: &LanguageName,
324 cx: &mut App,
325 ) -> LanguageServerId {
326 let key = LanguageServerSeed {
327 worktree_id: worktree_handle.read(cx).id(),
328 name: disposition.server_name.clone(),
329 settings: disposition.settings.clone(),
330 toolchain: disposition.toolchain.clone(),
331 };
332 if let Some(state) = self.language_server_ids.get_mut(&key) {
333 state.project_roots.insert(disposition.path.path.clone());
334 state.id
335 } else {
336 let adapter = self
337 .languages
338 .lsp_adapters(language_name)
339 .into_iter()
340 .find(|adapter| adapter.name() == disposition.server_name)
341 .expect("To find LSP adapter");
342 let new_language_server_id = self.start_language_server(
343 worktree_handle,
344 delegate,
345 adapter,
346 disposition.settings.clone(),
347 key.clone(),
348 cx,
349 );
350 if let Some(state) = self.language_server_ids.get_mut(&key) {
351 state.project_roots.insert(disposition.path.path.clone());
352 } else {
353 debug_assert!(
354 false,
355 "Expected `start_language_server` to ensure that `key` exists in a map"
356 );
357 }
358 new_language_server_id
359 }
360 }
361
362 fn start_language_server(
363 &mut self,
364 worktree_handle: &Entity<Worktree>,
365 delegate: Arc<LocalLspAdapterDelegate>,
366 adapter: Arc<CachedLspAdapter>,
367 settings: Arc<LspSettings>,
368 key: LanguageServerSeed,
369 cx: &mut App,
370 ) -> LanguageServerId {
371 let worktree = worktree_handle.read(cx);
372
373 let worktree_id = worktree.id();
374 let worktree_abs_path = worktree.abs_path();
375 let toolchain = key.toolchain.clone();
376 let override_options = settings.initialization_options.clone();
377
378 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
379
380 let server_id = self.languages.next_language_server_id();
381 log::trace!(
382 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
383 adapter.name.0
384 );
385
386 let untrusted_worktree_task =
387 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
388 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
389 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
390 });
391 if can_trust {
392 self.restricted_worktrees_tasks.remove(&worktree_id);
393 None
394 } else {
395 match self.restricted_worktrees_tasks.entry(worktree_id) {
396 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
397 hash_map::Entry::Vacant(v) => {
398 let (tx, rx) = smol::channel::bounded::<()>(1);
399 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, _| {
400 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
401 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
402 tx.send_blocking(()).ok();
403 }
404 }
405 });
406 v.insert((subscription, rx.clone()));
407 Some(rx)
408 }
409 }
410 }
411 });
412 let update_binary_status = untrusted_worktree_task.is_none();
413
414 let binary = self.get_language_server_binary(
415 worktree_abs_path.clone(),
416 adapter.clone(),
417 settings,
418 toolchain.clone(),
419 delegate.clone(),
420 true,
421 untrusted_worktree_task,
422 cx,
423 );
424 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
425
426 let pending_server = cx.spawn({
427 let adapter = adapter.clone();
428 let server_name = adapter.name.clone();
429 let stderr_capture = stderr_capture.clone();
430 #[cfg(any(test, feature = "test-support"))]
431 let lsp_store = self.weak.clone();
432 let pending_workspace_folders = pending_workspace_folders.clone();
433 async move |cx| {
434 let binary = binary.await?;
435 #[cfg(any(test, feature = "test-support"))]
436 if let Some(server) = lsp_store
437 .update(&mut cx.clone(), |this, cx| {
438 this.languages.create_fake_language_server(
439 server_id,
440 &server_name,
441 binary.clone(),
442 &mut cx.to_async(),
443 )
444 })
445 .ok()
446 .flatten()
447 {
448 return Ok(server);
449 }
450
451 let code_action_kinds = adapter.code_action_kinds();
452 lsp::LanguageServer::new(
453 stderr_capture,
454 server_id,
455 server_name,
456 binary,
457 &worktree_abs_path,
458 code_action_kinds,
459 Some(pending_workspace_folders),
460 cx,
461 )
462 }
463 });
464
465 let startup = {
466 let server_name = adapter.name.0.clone();
467 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
468 let key = key.clone();
469 let adapter = adapter.clone();
470 let lsp_store = self.weak.clone();
471 let pending_workspace_folders = pending_workspace_folders.clone();
472
473 let pull_diagnostics = ProjectSettings::get_global(cx)
474 .diagnostics
475 .lsp_pull_diagnostics
476 .enabled;
477 cx.spawn(async move |cx| {
478 let result = async {
479 let language_server = pending_server.await?;
480
481 let workspace_config = Self::workspace_configuration_for_adapter(
482 adapter.adapter.clone(),
483 &delegate,
484 toolchain,
485 None,
486 cx,
487 )
488 .await?;
489
490 let mut initialization_options = Self::initialization_options_for_adapter(
491 adapter.adapter.clone(),
492 &delegate,
493 )
494 .await?;
495
496 match (&mut initialization_options, override_options) {
497 (Some(initialization_options), Some(override_options)) => {
498 merge_json_value_into(override_options, initialization_options);
499 }
500 (None, override_options) => initialization_options = override_options,
501 _ => {}
502 }
503
504 let initialization_params = cx.update(|cx| {
505 let mut params =
506 language_server.default_initialize_params(pull_diagnostics, cx);
507 params.initialization_options = initialization_options;
508 adapter.adapter.prepare_initialize_params(params, cx)
509 })??;
510
511 Self::setup_lsp_messages(
512 lsp_store.clone(),
513 &language_server,
514 delegate.clone(),
515 adapter.clone(),
516 );
517
518 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
519 settings: workspace_config,
520 };
521 let language_server = cx
522 .update(|cx| {
523 language_server.initialize(
524 initialization_params,
525 Arc::new(did_change_configuration_params.clone()),
526 cx,
527 )
528 })?
529 .await
530 .inspect_err(|_| {
531 if let Some(lsp_store) = lsp_store.upgrade() {
532 lsp_store
533 .update(cx, |lsp_store, cx| {
534 lsp_store.cleanup_lsp_data(server_id);
535 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
536 })
537 .ok();
538 }
539 })?;
540
541 language_server.notify::<lsp::notification::DidChangeConfiguration>(
542 did_change_configuration_params,
543 )?;
544
545 anyhow::Ok(language_server)
546 }
547 .await;
548
549 match result {
550 Ok(server) => {
551 lsp_store
552 .update(cx, |lsp_store, cx| {
553 lsp_store.insert_newly_running_language_server(
554 adapter,
555 server.clone(),
556 server_id,
557 key,
558 pending_workspace_folders,
559 cx,
560 );
561 })
562 .ok();
563 stderr_capture.lock().take();
564 Some(server)
565 }
566
567 Err(err) => {
568 let log = stderr_capture.lock().take().unwrap_or_default();
569 delegate.update_status(
570 adapter.name(),
571 BinaryStatus::Failed {
572 error: if log.is_empty() {
573 format!("{err:#}")
574 } else {
575 format!("{err:#}\n-- stderr --\n{log}")
576 },
577 },
578 );
579 log::error!("Failed to start language server {server_name:?}: {err:?}");
580 if !log.is_empty() {
581 log::error!("server stderr: {log}");
582 }
583 None
584 }
585 }
586 })
587 };
588 let state = LanguageServerState::Starting {
589 startup,
590 pending_workspace_folders,
591 };
592
593 if update_binary_status {
594 self.languages
595 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
596 }
597
598 self.language_servers.insert(server_id, state);
599 self.language_server_ids
600 .entry(key)
601 .or_insert(UnifiedLanguageServer {
602 id: server_id,
603 project_roots: Default::default(),
604 });
605 server_id
606 }
607
608 fn get_language_server_binary(
609 &self,
610 worktree_abs_path: Arc<Path>,
611 adapter: Arc<CachedLspAdapter>,
612 settings: Arc<LspSettings>,
613 toolchain: Option<Toolchain>,
614 delegate: Arc<dyn LspAdapterDelegate>,
615 allow_binary_download: bool,
616 untrusted_worktree_task: Option<Receiver<()>>,
617 cx: &mut App,
618 ) -> Task<Result<LanguageServerBinary>> {
619 if let Some(settings) = &settings.binary
620 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
621 {
622 let settings = settings.clone();
623 let languages = self.languages.clone();
624 return cx.background_spawn(async move {
625 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
626 log::info!(
627 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
628 adapter.name(),
629 );
630 untrusted_worktree_task.recv().await.ok();
631 log::info!(
632 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
633 adapter.name(),
634 );
635 languages
636 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
637 }
638 let mut env = delegate.shell_env().await;
639 env.extend(settings.env.unwrap_or_default());
640
641 Ok(LanguageServerBinary {
642 path: delegate.resolve_executable_path(path),
643 env: Some(env),
644 arguments: settings
645 .arguments
646 .unwrap_or_default()
647 .iter()
648 .map(Into::into)
649 .collect(),
650 })
651 });
652 }
653 let lsp_binary_options = LanguageServerBinaryOptions {
654 allow_path_lookup: !settings
655 .binary
656 .as_ref()
657 .and_then(|b| b.ignore_system_version)
658 .unwrap_or_default(),
659 allow_binary_download,
660 pre_release: settings
661 .fetch
662 .as_ref()
663 .and_then(|f| f.pre_release)
664 .unwrap_or(false),
665 };
666
667 cx.spawn(async move |cx| {
668 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
669 log::info!(
670 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
671 adapter.name(),
672 );
673 untrusted_worktree_task.recv().await.ok();
674 log::info!(
675 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
676 adapter.name(),
677 );
678 }
679
680 let (existing_binary, maybe_download_binary) = adapter
681 .clone()
682 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
683 .await
684 .await;
685
686 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
687
688 let mut binary = match (existing_binary, maybe_download_binary) {
689 (binary, None) => binary?,
690 (Err(_), Some(downloader)) => downloader.await?,
691 (Ok(existing_binary), Some(downloader)) => {
692 let mut download_timeout = cx
693 .background_executor()
694 .timer(SERVER_DOWNLOAD_TIMEOUT)
695 .fuse();
696 let mut downloader = downloader.fuse();
697 futures::select! {
698 _ = download_timeout => {
699 // Return existing binary and kick the existing work to the background.
700 cx.spawn(async move |_| downloader.await).detach();
701 Ok(existing_binary)
702 },
703 downloaded_or_existing_binary = downloader => {
704 // If download fails, this results in the existing binary.
705 downloaded_or_existing_binary
706 }
707 }?
708 }
709 };
710 let mut shell_env = delegate.shell_env().await;
711
712 shell_env.extend(binary.env.unwrap_or_default());
713
714 if let Some(settings) = settings.binary.as_ref() {
715 if let Some(arguments) = &settings.arguments {
716 binary.arguments = arguments.iter().map(Into::into).collect();
717 }
718 if let Some(env) = &settings.env {
719 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
720 }
721 }
722
723 binary.env = Some(shell_env);
724 Ok(binary)
725 })
726 }
727
728 fn setup_lsp_messages(
729 lsp_store: WeakEntity<LspStore>,
730 language_server: &LanguageServer,
731 delegate: Arc<dyn LspAdapterDelegate>,
732 adapter: Arc<CachedLspAdapter>,
733 ) {
734 let name = language_server.name();
735 let server_id = language_server.server_id();
736 language_server
737 .on_notification::<lsp::notification::PublishDiagnostics, _>({
738 let adapter = adapter.clone();
739 let this = lsp_store.clone();
740 move |mut params, cx| {
741 let adapter = adapter.clone();
742 if let Some(this) = this.upgrade() {
743 this.update(cx, |this, cx| {
744 {
745 let buffer = params
746 .uri
747 .to_file_path()
748 .map(|file_path| this.get_buffer(&file_path, cx))
749 .ok()
750 .flatten();
751 adapter.process_diagnostics(&mut params, server_id, buffer);
752 }
753
754 this.merge_lsp_diagnostics(
755 DiagnosticSourceKind::Pushed,
756 vec![DocumentDiagnosticsUpdate {
757 server_id,
758 diagnostics: params,
759 result_id: None,
760 disk_based_sources: Cow::Borrowed(
761 &adapter.disk_based_diagnostic_sources,
762 ),
763 registration_id: None,
764 }],
765 |_, diagnostic, cx| match diagnostic.source_kind {
766 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
767 adapter.retain_old_diagnostic(diagnostic, cx)
768 }
769 DiagnosticSourceKind::Pulled => true,
770 },
771 cx,
772 )
773 .log_err();
774 })
775 .ok();
776 }
777 }
778 })
779 .detach();
780 language_server
781 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
782 let adapter = adapter.adapter.clone();
783 let delegate = delegate.clone();
784 let this = lsp_store.clone();
785 move |params, cx| {
786 let adapter = adapter.clone();
787 let delegate = delegate.clone();
788 let this = this.clone();
789 let mut cx = cx.clone();
790 async move {
791 let toolchain_for_id = this
792 .update(&mut cx, |this, _| {
793 this.as_local()?.language_server_ids.iter().find_map(
794 |(seed, value)| {
795 (value.id == server_id).then(|| seed.toolchain.clone())
796 },
797 )
798 })?
799 .context("Expected the LSP store to be in a local mode")?;
800
801 let mut scope_uri_to_workspace_config = BTreeMap::new();
802 for item in ¶ms.items {
803 let scope_uri = item.scope_uri.clone();
804 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
805 scope_uri_to_workspace_config.entry(scope_uri.clone())
806 else {
807 // We've already queried workspace configuration of this URI.
808 continue;
809 };
810 let workspace_config = Self::workspace_configuration_for_adapter(
811 adapter.clone(),
812 &delegate,
813 toolchain_for_id.clone(),
814 scope_uri,
815 &mut cx,
816 )
817 .await?;
818 new_scope_uri.insert(workspace_config);
819 }
820
821 Ok(params
822 .items
823 .into_iter()
824 .filter_map(|item| {
825 let workspace_config =
826 scope_uri_to_workspace_config.get(&item.scope_uri)?;
827 if let Some(section) = &item.section {
828 Some(
829 workspace_config
830 .get(section)
831 .cloned()
832 .unwrap_or(serde_json::Value::Null),
833 )
834 } else {
835 Some(workspace_config.clone())
836 }
837 })
838 .collect())
839 }
840 }
841 })
842 .detach();
843
844 language_server
845 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
846 let this = lsp_store.clone();
847 move |_, cx| {
848 let this = this.clone();
849 let cx = cx.clone();
850 async move {
851 let Some(server) =
852 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
853 else {
854 return Ok(None);
855 };
856 let root = server.workspace_folders();
857 Ok(Some(
858 root.into_iter()
859 .map(|uri| WorkspaceFolder {
860 uri,
861 name: Default::default(),
862 })
863 .collect(),
864 ))
865 }
866 }
867 })
868 .detach();
869 // Even though we don't have handling for these requests, respond to them to
870 // avoid stalling any language server like `gopls` which waits for a response
871 // to these requests when initializing.
872 language_server
873 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
874 let this = lsp_store.clone();
875 move |params, cx| {
876 let this = this.clone();
877 let mut cx = cx.clone();
878 async move {
879 this.update(&mut cx, |this, _| {
880 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
881 {
882 status
883 .progress_tokens
884 .insert(ProgressToken::from_lsp(params.token));
885 }
886 })?;
887
888 Ok(())
889 }
890 }
891 })
892 .detach();
893
894 language_server
895 .on_request::<lsp::request::RegisterCapability, _, _>({
896 let lsp_store = lsp_store.clone();
897 move |params, cx| {
898 let lsp_store = lsp_store.clone();
899 let mut cx = cx.clone();
900 async move {
901 lsp_store
902 .update(&mut cx, |lsp_store, cx| {
903 if lsp_store.as_local().is_some() {
904 match lsp_store
905 .register_server_capabilities(server_id, params, cx)
906 {
907 Ok(()) => {}
908 Err(e) => {
909 log::error!(
910 "Failed to register server capabilities: {e:#}"
911 );
912 }
913 };
914 }
915 })
916 .ok();
917 Ok(())
918 }
919 }
920 })
921 .detach();
922
923 language_server
924 .on_request::<lsp::request::UnregisterCapability, _, _>({
925 let lsp_store = lsp_store.clone();
926 move |params, cx| {
927 let lsp_store = lsp_store.clone();
928 let mut cx = cx.clone();
929 async move {
930 lsp_store
931 .update(&mut cx, |lsp_store, cx| {
932 if lsp_store.as_local().is_some() {
933 match lsp_store
934 .unregister_server_capabilities(server_id, params, cx)
935 {
936 Ok(()) => {}
937 Err(e) => {
938 log::error!(
939 "Failed to unregister server capabilities: {e:#}"
940 );
941 }
942 }
943 }
944 })
945 .ok();
946 Ok(())
947 }
948 }
949 })
950 .detach();
951
952 language_server
953 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
954 let this = lsp_store.clone();
955 move |params, cx| {
956 let mut cx = cx.clone();
957 let this = this.clone();
958 async move {
959 LocalLspStore::on_lsp_workspace_edit(
960 this.clone(),
961 params,
962 server_id,
963 &mut cx,
964 )
965 .await
966 }
967 }
968 })
969 .detach();
970
971 language_server
972 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
973 let lsp_store = lsp_store.clone();
974 let request_id = Arc::new(AtomicUsize::new(0));
975 move |(), cx| {
976 let lsp_store = lsp_store.clone();
977 let request_id = request_id.clone();
978 let mut cx = cx.clone();
979 async move {
980 lsp_store
981 .update(&mut cx, |lsp_store, cx| {
982 let request_id =
983 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
984 cx.emit(LspStoreEvent::RefreshInlayHints {
985 server_id,
986 request_id,
987 });
988 lsp_store
989 .downstream_client
990 .as_ref()
991 .map(|(client, project_id)| {
992 client.send(proto::RefreshInlayHints {
993 project_id: *project_id,
994 server_id: server_id.to_proto(),
995 request_id: request_id.map(|id| id as u64),
996 })
997 })
998 })?
999 .transpose()?;
1000 Ok(())
1001 }
1002 }
1003 })
1004 .detach();
1005
1006 language_server
1007 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1008 let this = lsp_store.clone();
1009 move |(), cx| {
1010 let this = this.clone();
1011 let mut cx = cx.clone();
1012 async move {
1013 this.update(&mut cx, |this, cx| {
1014 cx.emit(LspStoreEvent::RefreshCodeLens);
1015 this.downstream_client.as_ref().map(|(client, project_id)| {
1016 client.send(proto::RefreshCodeLens {
1017 project_id: *project_id,
1018 })
1019 })
1020 })?
1021 .transpose()?;
1022 Ok(())
1023 }
1024 }
1025 })
1026 .detach();
1027
1028 language_server
1029 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1030 let this = lsp_store.clone();
1031 move |(), cx| {
1032 let this = this.clone();
1033 let mut cx = cx.clone();
1034 async move {
1035 this.update(&mut cx, |lsp_store, _| {
1036 lsp_store.pull_workspace_diagnostics(server_id);
1037 lsp_store
1038 .downstream_client
1039 .as_ref()
1040 .map(|(client, project_id)| {
1041 client.send(proto::PullWorkspaceDiagnostics {
1042 project_id: *project_id,
1043 server_id: server_id.to_proto(),
1044 })
1045 })
1046 })?
1047 .transpose()?;
1048 Ok(())
1049 }
1050 }
1051 })
1052 .detach();
1053
1054 language_server
1055 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1056 let this = lsp_store.clone();
1057 let name = name.to_string();
1058 move |params, cx| {
1059 let this = this.clone();
1060 let name = name.to_string();
1061 let mut cx = cx.clone();
1062 async move {
1063 let actions = params.actions.unwrap_or_default();
1064 let (tx, rx) = smol::channel::bounded(1);
1065 let request = LanguageServerPromptRequest {
1066 level: match params.typ {
1067 lsp::MessageType::ERROR => PromptLevel::Critical,
1068 lsp::MessageType::WARNING => PromptLevel::Warning,
1069 _ => PromptLevel::Info,
1070 },
1071 message: params.message,
1072 actions,
1073 response_channel: tx,
1074 lsp_name: name.clone(),
1075 };
1076
1077 let did_update = this
1078 .update(&mut cx, |_, cx| {
1079 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1080 })
1081 .is_ok();
1082 if did_update {
1083 let response = rx.recv().await.ok();
1084 Ok(response)
1085 } else {
1086 Ok(None)
1087 }
1088 }
1089 }
1090 })
1091 .detach();
1092 language_server
1093 .on_notification::<lsp::notification::ShowMessage, _>({
1094 let this = lsp_store.clone();
1095 let name = name.to_string();
1096 move |params, cx| {
1097 let this = this.clone();
1098 let name = name.to_string();
1099 let mut cx = cx.clone();
1100
1101 let (tx, _) = smol::channel::bounded(1);
1102 let request = LanguageServerPromptRequest {
1103 level: match params.typ {
1104 lsp::MessageType::ERROR => PromptLevel::Critical,
1105 lsp::MessageType::WARNING => PromptLevel::Warning,
1106 _ => PromptLevel::Info,
1107 },
1108 message: params.message,
1109 actions: vec![],
1110 response_channel: tx,
1111 lsp_name: name,
1112 };
1113
1114 let _ = this.update(&mut cx, |_, cx| {
1115 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1116 });
1117 }
1118 })
1119 .detach();
1120
1121 let disk_based_diagnostics_progress_token =
1122 adapter.disk_based_diagnostics_progress_token.clone();
1123
1124 language_server
1125 .on_notification::<lsp::notification::Progress, _>({
1126 let this = lsp_store.clone();
1127 move |params, cx| {
1128 if let Some(this) = this.upgrade() {
1129 this.update(cx, |this, cx| {
1130 this.on_lsp_progress(
1131 params,
1132 server_id,
1133 disk_based_diagnostics_progress_token.clone(),
1134 cx,
1135 );
1136 })
1137 .ok();
1138 }
1139 }
1140 })
1141 .detach();
1142
1143 language_server
1144 .on_notification::<lsp::notification::LogMessage, _>({
1145 let this = lsp_store.clone();
1146 move |params, cx| {
1147 if let Some(this) = this.upgrade() {
1148 this.update(cx, |_, cx| {
1149 cx.emit(LspStoreEvent::LanguageServerLog(
1150 server_id,
1151 LanguageServerLogType::Log(params.typ),
1152 params.message,
1153 ));
1154 })
1155 .ok();
1156 }
1157 }
1158 })
1159 .detach();
1160
1161 language_server
1162 .on_notification::<lsp::notification::LogTrace, _>({
1163 let this = lsp_store.clone();
1164 move |params, cx| {
1165 let mut cx = cx.clone();
1166 if let Some(this) = this.upgrade() {
1167 this.update(&mut cx, |_, cx| {
1168 cx.emit(LspStoreEvent::LanguageServerLog(
1169 server_id,
1170 LanguageServerLogType::Trace {
1171 verbose_info: params.verbose,
1172 },
1173 params.message,
1174 ));
1175 })
1176 .ok();
1177 }
1178 }
1179 })
1180 .detach();
1181
1182 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1183 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1184 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1185 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1186 }
1187
1188 fn shutdown_language_servers_on_quit(
1189 &mut self,
1190 _: &mut Context<LspStore>,
1191 ) -> impl Future<Output = ()> + use<> {
1192 let shutdown_futures = self
1193 .language_servers
1194 .drain()
1195 .map(|(_, server_state)| Self::shutdown_server(server_state))
1196 .collect::<Vec<_>>();
1197
1198 async move {
1199 join_all(shutdown_futures).await;
1200 }
1201 }
1202
1203 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1204 match server_state {
1205 LanguageServerState::Running { server, .. } => {
1206 if let Some(shutdown) = server.shutdown() {
1207 shutdown.await;
1208 }
1209 }
1210 LanguageServerState::Starting { startup, .. } => {
1211 if let Some(server) = startup.await
1212 && let Some(shutdown) = server.shutdown()
1213 {
1214 shutdown.await;
1215 }
1216 }
1217 }
1218 Ok(())
1219 }
1220
1221 fn language_servers_for_worktree(
1222 &self,
1223 worktree_id: WorktreeId,
1224 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1225 self.language_server_ids
1226 .iter()
1227 .filter_map(move |(seed, state)| {
1228 if seed.worktree_id != worktree_id {
1229 return None;
1230 }
1231
1232 if let Some(LanguageServerState::Running { server, .. }) =
1233 self.language_servers.get(&state.id)
1234 {
1235 Some(server)
1236 } else {
1237 None
1238 }
1239 })
1240 }
1241
1242 fn language_server_ids_for_project_path(
1243 &self,
1244 project_path: ProjectPath,
1245 language: &Language,
1246 cx: &mut App,
1247 ) -> Vec<LanguageServerId> {
1248 let Some(worktree) = self
1249 .worktree_store
1250 .read(cx)
1251 .worktree_for_id(project_path.worktree_id, cx)
1252 else {
1253 return Vec::new();
1254 };
1255 let delegate: Arc<dyn ManifestDelegate> =
1256 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1257
1258 self.lsp_tree
1259 .get(
1260 project_path,
1261 language.name(),
1262 language.manifest(),
1263 &delegate,
1264 cx,
1265 )
1266 .collect::<Vec<_>>()
1267 }
1268
1269 fn language_server_ids_for_buffer(
1270 &self,
1271 buffer: &Buffer,
1272 cx: &mut App,
1273 ) -> Vec<LanguageServerId> {
1274 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1275 let worktree_id = file.worktree_id(cx);
1276
1277 let path: Arc<RelPath> = file
1278 .path()
1279 .parent()
1280 .map(Arc::from)
1281 .unwrap_or_else(|| file.path().clone());
1282 let worktree_path = ProjectPath { worktree_id, path };
1283 self.language_server_ids_for_project_path(worktree_path, language, cx)
1284 } else {
1285 Vec::new()
1286 }
1287 }
1288
1289 fn language_servers_for_buffer<'a>(
1290 &'a self,
1291 buffer: &'a Buffer,
1292 cx: &'a mut App,
1293 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1294 self.language_server_ids_for_buffer(buffer, cx)
1295 .into_iter()
1296 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1297 LanguageServerState::Running {
1298 adapter, server, ..
1299 } => Some((adapter, server)),
1300 _ => None,
1301 })
1302 }
1303
1304 async fn execute_code_action_kind_locally(
1305 lsp_store: WeakEntity<LspStore>,
1306 mut buffers: Vec<Entity<Buffer>>,
1307 kind: CodeActionKind,
1308 push_to_history: bool,
1309 cx: &mut AsyncApp,
1310 ) -> anyhow::Result<ProjectTransaction> {
1311 // Do not allow multiple concurrent code actions requests for the
1312 // same buffer.
1313 lsp_store.update(cx, |this, cx| {
1314 let this = this.as_local_mut().unwrap();
1315 buffers.retain(|buffer| {
1316 this.buffers_being_formatted
1317 .insert(buffer.read(cx).remote_id())
1318 });
1319 })?;
1320 let _cleanup = defer({
1321 let this = lsp_store.clone();
1322 let mut cx = cx.clone();
1323 let buffers = &buffers;
1324 move || {
1325 this.update(&mut cx, |this, cx| {
1326 let this = this.as_local_mut().unwrap();
1327 for buffer in buffers {
1328 this.buffers_being_formatted
1329 .remove(&buffer.read(cx).remote_id());
1330 }
1331 })
1332 .ok();
1333 }
1334 });
1335 let mut project_transaction = ProjectTransaction::default();
1336
1337 for buffer in &buffers {
1338 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1339 buffer.update(cx, |buffer, cx| {
1340 lsp_store
1341 .as_local()
1342 .unwrap()
1343 .language_servers_for_buffer(buffer, cx)
1344 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1345 .collect::<Vec<_>>()
1346 })
1347 })?;
1348 for (_, language_server) in adapters_and_servers.iter() {
1349 let actions = Self::get_server_code_actions_from_action_kinds(
1350 &lsp_store,
1351 language_server.server_id(),
1352 vec![kind.clone()],
1353 buffer,
1354 cx,
1355 )
1356 .await?;
1357 Self::execute_code_actions_on_server(
1358 &lsp_store,
1359 language_server,
1360 actions,
1361 push_to_history,
1362 &mut project_transaction,
1363 cx,
1364 )
1365 .await?;
1366 }
1367 }
1368 Ok(project_transaction)
1369 }
1370
1371 async fn format_locally(
1372 lsp_store: WeakEntity<LspStore>,
1373 mut buffers: Vec<FormattableBuffer>,
1374 push_to_history: bool,
1375 trigger: FormatTrigger,
1376 logger: zlog::Logger,
1377 cx: &mut AsyncApp,
1378 ) -> anyhow::Result<ProjectTransaction> {
1379 // Do not allow multiple concurrent formatting requests for the
1380 // same buffer.
1381 lsp_store.update(cx, |this, cx| {
1382 let this = this.as_local_mut().unwrap();
1383 buffers.retain(|buffer| {
1384 this.buffers_being_formatted
1385 .insert(buffer.handle.read(cx).remote_id())
1386 });
1387 })?;
1388
1389 let _cleanup = defer({
1390 let this = lsp_store.clone();
1391 let mut cx = cx.clone();
1392 let buffers = &buffers;
1393 move || {
1394 this.update(&mut cx, |this, cx| {
1395 let this = this.as_local_mut().unwrap();
1396 for buffer in buffers {
1397 this.buffers_being_formatted
1398 .remove(&buffer.handle.read(cx).remote_id());
1399 }
1400 })
1401 .ok();
1402 }
1403 });
1404
1405 let mut project_transaction = ProjectTransaction::default();
1406
1407 for buffer in &buffers {
1408 zlog::debug!(
1409 logger =>
1410 "formatting buffer '{:?}'",
1411 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1412 );
1413 // Create an empty transaction to hold all of the formatting edits.
1414 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1415 // ensure no transactions created while formatting are
1416 // grouped with the previous transaction in the history
1417 // based on the transaction group interval
1418 buffer.finalize_last_transaction();
1419 buffer
1420 .start_transaction()
1421 .context("transaction already open")?;
1422 buffer.end_transaction(cx);
1423 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1424 buffer.finalize_last_transaction();
1425 anyhow::Ok(transaction_id)
1426 })??;
1427
1428 let result = Self::format_buffer_locally(
1429 lsp_store.clone(),
1430 buffer,
1431 formatting_transaction_id,
1432 trigger,
1433 logger,
1434 cx,
1435 )
1436 .await;
1437
1438 buffer.handle.update(cx, |buffer, cx| {
1439 let Some(formatting_transaction) =
1440 buffer.get_transaction(formatting_transaction_id).cloned()
1441 else {
1442 zlog::warn!(logger => "no formatting transaction");
1443 return;
1444 };
1445 if formatting_transaction.edit_ids.is_empty() {
1446 zlog::debug!(logger => "no changes made while formatting");
1447 buffer.forget_transaction(formatting_transaction_id);
1448 return;
1449 }
1450 if !push_to_history {
1451 zlog::trace!(logger => "forgetting format transaction");
1452 buffer.forget_transaction(formatting_transaction.id);
1453 }
1454 project_transaction
1455 .0
1456 .insert(cx.entity(), formatting_transaction);
1457 })?;
1458
1459 result?;
1460 }
1461
1462 Ok(project_transaction)
1463 }
1464
1465 async fn format_buffer_locally(
1466 lsp_store: WeakEntity<LspStore>,
1467 buffer: &FormattableBuffer,
1468 formatting_transaction_id: clock::Lamport,
1469 trigger: FormatTrigger,
1470 logger: zlog::Logger,
1471 cx: &mut AsyncApp,
1472 ) -> Result<()> {
1473 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1474 buffer.handle.update(cx, |buffer, cx| {
1475 let adapters_and_servers = lsp_store
1476 .as_local()
1477 .unwrap()
1478 .language_servers_for_buffer(buffer, cx)
1479 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1480 .collect::<Vec<_>>();
1481 let settings =
1482 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1483 .into_owned();
1484 (adapters_and_servers, settings)
1485 })
1486 })?;
1487
1488 /// Apply edits to the buffer that will become part of the formatting transaction.
1489 /// Fails if the buffer has been edited since the start of that transaction.
1490 fn extend_formatting_transaction(
1491 buffer: &FormattableBuffer,
1492 formatting_transaction_id: text::TransactionId,
1493 cx: &mut AsyncApp,
1494 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1495 ) -> anyhow::Result<()> {
1496 buffer.handle.update(cx, |buffer, cx| {
1497 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1498 if last_transaction_id != Some(formatting_transaction_id) {
1499 anyhow::bail!("Buffer edited while formatting. Aborting")
1500 }
1501 buffer.start_transaction();
1502 operation(buffer, cx);
1503 if let Some(transaction_id) = buffer.end_transaction(cx) {
1504 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1505 }
1506 Ok(())
1507 })?
1508 }
1509
1510 // handle whitespace formatting
1511 if settings.remove_trailing_whitespace_on_save {
1512 zlog::trace!(logger => "removing trailing whitespace");
1513 let diff = buffer
1514 .handle
1515 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1516 .await;
1517 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1518 buffer.apply_diff(diff, cx);
1519 })?;
1520 }
1521
1522 if settings.ensure_final_newline_on_save {
1523 zlog::trace!(logger => "ensuring final newline");
1524 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1525 buffer.ensure_final_newline(cx);
1526 })?;
1527 }
1528
1529 // Formatter for `code_actions_on_format` that runs before
1530 // the rest of the formatters
1531 let mut code_actions_on_format_formatters = None;
1532 let should_run_code_actions_on_format = !matches!(
1533 (trigger, &settings.format_on_save),
1534 (FormatTrigger::Save, &FormatOnSave::Off)
1535 );
1536 if should_run_code_actions_on_format {
1537 let have_code_actions_to_run_on_format = settings
1538 .code_actions_on_format
1539 .values()
1540 .any(|enabled| *enabled);
1541 if have_code_actions_to_run_on_format {
1542 zlog::trace!(logger => "going to run code actions on format");
1543 code_actions_on_format_formatters = Some(
1544 settings
1545 .code_actions_on_format
1546 .iter()
1547 .filter_map(|(action, enabled)| enabled.then_some(action))
1548 .cloned()
1549 .map(Formatter::CodeAction)
1550 .collect::<Vec<_>>(),
1551 );
1552 }
1553 }
1554
1555 let formatters = match (trigger, &settings.format_on_save) {
1556 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1557 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1558 settings.formatter.as_ref()
1559 }
1560 };
1561
1562 let formatters = code_actions_on_format_formatters
1563 .iter()
1564 .flatten()
1565 .chain(formatters);
1566
1567 for formatter in formatters {
1568 let formatter = if formatter == &Formatter::Auto {
1569 if settings.prettier.allowed {
1570 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1571 &Formatter::Prettier
1572 } else {
1573 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1574 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1575 }
1576 } else {
1577 formatter
1578 };
1579 match formatter {
1580 Formatter::Auto => unreachable!("Auto resolved above"),
1581 Formatter::Prettier => {
1582 let logger = zlog::scoped!(logger => "prettier");
1583 zlog::trace!(logger => "formatting");
1584 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1585
1586 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1587 lsp_store.prettier_store().unwrap().downgrade()
1588 })?;
1589 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1590 .await
1591 .transpose()?;
1592 let Some(diff) = diff else {
1593 zlog::trace!(logger => "No changes");
1594 continue;
1595 };
1596
1597 extend_formatting_transaction(
1598 buffer,
1599 formatting_transaction_id,
1600 cx,
1601 |buffer, cx| {
1602 buffer.apply_diff(diff, cx);
1603 },
1604 )?;
1605 }
1606 Formatter::External { command, arguments } => {
1607 let logger = zlog::scoped!(logger => "command");
1608 zlog::trace!(logger => "formatting");
1609 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1610
1611 let diff = Self::format_via_external_command(
1612 buffer,
1613 command.as_ref(),
1614 arguments.as_deref(),
1615 cx,
1616 )
1617 .await
1618 .with_context(|| {
1619 format!("Failed to format buffer via external command: {}", command)
1620 })?;
1621 let Some(diff) = diff else {
1622 zlog::trace!(logger => "No changes");
1623 continue;
1624 };
1625
1626 extend_formatting_transaction(
1627 buffer,
1628 formatting_transaction_id,
1629 cx,
1630 |buffer, cx| {
1631 buffer.apply_diff(diff, cx);
1632 },
1633 )?;
1634 }
1635 Formatter::LanguageServer(specifier) => {
1636 let logger = zlog::scoped!(logger => "language-server");
1637 zlog::trace!(logger => "formatting");
1638 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1639
1640 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1641 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1642 continue;
1643 };
1644
1645 let language_server = match specifier {
1646 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1647 adapters_and_servers.iter().find_map(|(adapter, server)| {
1648 if adapter.name.0.as_ref() == name {
1649 Some(server.clone())
1650 } else {
1651 None
1652 }
1653 })
1654 }
1655 settings::LanguageServerFormatterSpecifier::Current => {
1656 adapters_and_servers.first().map(|e| e.1.clone())
1657 }
1658 };
1659
1660 let Some(language_server) = language_server else {
1661 log::debug!(
1662 "No language server found to format buffer '{:?}'. Skipping",
1663 buffer_path_abs.as_path().to_string_lossy()
1664 );
1665 continue;
1666 };
1667
1668 zlog::trace!(
1669 logger =>
1670 "Formatting buffer '{:?}' using language server '{:?}'",
1671 buffer_path_abs.as_path().to_string_lossy(),
1672 language_server.name()
1673 );
1674
1675 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1676 zlog::trace!(logger => "formatting ranges");
1677 Self::format_ranges_via_lsp(
1678 &lsp_store,
1679 &buffer.handle,
1680 ranges,
1681 buffer_path_abs,
1682 &language_server,
1683 &settings,
1684 cx,
1685 )
1686 .await
1687 .context("Failed to format ranges via language server")?
1688 } else {
1689 zlog::trace!(logger => "formatting full");
1690 Self::format_via_lsp(
1691 &lsp_store,
1692 &buffer.handle,
1693 buffer_path_abs,
1694 &language_server,
1695 &settings,
1696 cx,
1697 )
1698 .await
1699 .context("failed to format via language server")?
1700 };
1701
1702 if edits.is_empty() {
1703 zlog::trace!(logger => "No changes");
1704 continue;
1705 }
1706 extend_formatting_transaction(
1707 buffer,
1708 formatting_transaction_id,
1709 cx,
1710 |buffer, cx| {
1711 buffer.edit(edits, None, cx);
1712 },
1713 )?;
1714 }
1715 Formatter::CodeAction(code_action_name) => {
1716 let logger = zlog::scoped!(logger => "code-actions");
1717 zlog::trace!(logger => "formatting");
1718 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1719
1720 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1721 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1722 continue;
1723 };
1724
1725 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1726 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1727
1728 let mut actions_and_servers = Vec::new();
1729
1730 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1731 let actions_result = Self::get_server_code_actions_from_action_kinds(
1732 &lsp_store,
1733 language_server.server_id(),
1734 vec![code_action_kind.clone()],
1735 &buffer.handle,
1736 cx,
1737 )
1738 .await
1739 .with_context(|| {
1740 format!(
1741 "Failed to resolve code action {:?} with language server {}",
1742 code_action_kind,
1743 language_server.name()
1744 )
1745 });
1746 let Ok(actions) = actions_result else {
1747 // note: it may be better to set result to the error and break formatters here
1748 // but for now we try to execute the actions that we can resolve and skip the rest
1749 zlog::error!(
1750 logger =>
1751 "Failed to resolve code action {:?} with language server {}",
1752 code_action_kind,
1753 language_server.name()
1754 );
1755 continue;
1756 };
1757 for action in actions {
1758 actions_and_servers.push((action, index));
1759 }
1760 }
1761
1762 if actions_and_servers.is_empty() {
1763 zlog::warn!(logger => "No code actions were resolved, continuing");
1764 continue;
1765 }
1766
1767 'actions: for (mut action, server_index) in actions_and_servers {
1768 let server = &adapters_and_servers[server_index].1;
1769
1770 let describe_code_action = |action: &CodeAction| {
1771 format!(
1772 "code action '{}' with title \"{}\" on server {}",
1773 action
1774 .lsp_action
1775 .action_kind()
1776 .unwrap_or("unknown".into())
1777 .as_str(),
1778 action.lsp_action.title(),
1779 server.name(),
1780 )
1781 };
1782
1783 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1784
1785 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1786 zlog::error!(
1787 logger =>
1788 "Failed to resolve {}. Error: {}",
1789 describe_code_action(&action),
1790 err
1791 );
1792 continue;
1793 }
1794
1795 if let Some(edit) = action.lsp_action.edit().cloned() {
1796 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1797 // but filters out and logs warnings for code actions that require unreasonably
1798 // difficult handling on our part, such as:
1799 // - applying edits that call commands
1800 // which can result in arbitrary workspace edits being sent from the server that
1801 // have no way of being tied back to the command that initiated them (i.e. we
1802 // can't know which edits are part of the format request, or if the server is done sending
1803 // actions in response to the command)
1804 // - actions that create/delete/modify/rename files other than the one we are formatting
1805 // as we then would need to handle such changes correctly in the local history as well
1806 // as the remote history through the ProjectTransaction
1807 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1808 // Supporting these actions is not impossible, but not supported as of yet.
1809 if edit.changes.is_none() && edit.document_changes.is_none() {
1810 zlog::trace!(
1811 logger =>
1812 "No changes for code action. Skipping {}",
1813 describe_code_action(&action),
1814 );
1815 continue;
1816 }
1817
1818 let mut operations = Vec::new();
1819 if let Some(document_changes) = edit.document_changes {
1820 match document_changes {
1821 lsp::DocumentChanges::Edits(edits) => operations.extend(
1822 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1823 ),
1824 lsp::DocumentChanges::Operations(ops) => operations = ops,
1825 }
1826 } else if let Some(changes) = edit.changes {
1827 operations.extend(changes.into_iter().map(|(uri, edits)| {
1828 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1829 text_document:
1830 lsp::OptionalVersionedTextDocumentIdentifier {
1831 uri,
1832 version: None,
1833 },
1834 edits: edits.into_iter().map(Edit::Plain).collect(),
1835 })
1836 }));
1837 }
1838
1839 let mut edits = Vec::with_capacity(operations.len());
1840
1841 if operations.is_empty() {
1842 zlog::trace!(
1843 logger =>
1844 "No changes for code action. Skipping {}",
1845 describe_code_action(&action),
1846 );
1847 continue;
1848 }
1849 for operation in operations {
1850 let op = match operation {
1851 lsp::DocumentChangeOperation::Edit(op) => op,
1852 lsp::DocumentChangeOperation::Op(_) => {
1853 zlog::warn!(
1854 logger =>
1855 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1856 describe_code_action(&action),
1857 );
1858 continue 'actions;
1859 }
1860 };
1861 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1862 zlog::warn!(
1863 logger =>
1864 "Failed to convert URI '{:?}' to file path. Skipping {}",
1865 &op.text_document.uri,
1866 describe_code_action(&action),
1867 );
1868 continue 'actions;
1869 };
1870 if &file_path != buffer_path_abs {
1871 zlog::warn!(
1872 logger =>
1873 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1874 file_path,
1875 buffer_path_abs,
1876 describe_code_action(&action),
1877 );
1878 continue 'actions;
1879 }
1880
1881 let mut lsp_edits = Vec::new();
1882 for edit in op.edits {
1883 match edit {
1884 Edit::Plain(edit) => {
1885 if !lsp_edits.contains(&edit) {
1886 lsp_edits.push(edit);
1887 }
1888 }
1889 Edit::Annotated(edit) => {
1890 if !lsp_edits.contains(&edit.text_edit) {
1891 lsp_edits.push(edit.text_edit);
1892 }
1893 }
1894 Edit::Snippet(_) => {
1895 zlog::warn!(
1896 logger =>
1897 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1898 describe_code_action(&action),
1899 );
1900 continue 'actions;
1901 }
1902 }
1903 }
1904 let edits_result = lsp_store
1905 .update(cx, |lsp_store, cx| {
1906 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1907 &buffer.handle,
1908 lsp_edits,
1909 server.server_id(),
1910 op.text_document.version,
1911 cx,
1912 )
1913 })?
1914 .await;
1915 let Ok(resolved_edits) = edits_result else {
1916 zlog::warn!(
1917 logger =>
1918 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1919 buffer_path_abs.as_path(),
1920 describe_code_action(&action),
1921 );
1922 continue 'actions;
1923 };
1924 edits.extend(resolved_edits);
1925 }
1926
1927 if edits.is_empty() {
1928 zlog::warn!(logger => "No edits resolved from LSP");
1929 continue;
1930 }
1931
1932 extend_formatting_transaction(
1933 buffer,
1934 formatting_transaction_id,
1935 cx,
1936 |buffer, cx| {
1937 zlog::info!(
1938 "Applying edits {edits:?}. Content: {:?}",
1939 buffer.text()
1940 );
1941 buffer.edit(edits, None, cx);
1942 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1943 },
1944 )?;
1945 }
1946
1947 if let Some(command) = action.lsp_action.command() {
1948 zlog::warn!(
1949 logger =>
1950 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1951 &command.command,
1952 );
1953
1954 // bail early if command is invalid
1955 let server_capabilities = server.capabilities();
1956 let available_commands = server_capabilities
1957 .execute_command_provider
1958 .as_ref()
1959 .map(|options| options.commands.as_slice())
1960 .unwrap_or_default();
1961 if !available_commands.contains(&command.command) {
1962 zlog::warn!(
1963 logger =>
1964 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1965 command.command,
1966 server.name(),
1967 );
1968 continue;
1969 }
1970
1971 // noop so we just ensure buffer hasn't been edited since resolving code actions
1972 extend_formatting_transaction(
1973 buffer,
1974 formatting_transaction_id,
1975 cx,
1976 |_, _| {},
1977 )?;
1978 zlog::info!(logger => "Executing command {}", &command.command);
1979
1980 lsp_store.update(cx, |this, _| {
1981 this.as_local_mut()
1982 .unwrap()
1983 .last_workspace_edits_by_language_server
1984 .remove(&server.server_id());
1985 })?;
1986
1987 let execute_command_result = server
1988 .request::<lsp::request::ExecuteCommand>(
1989 lsp::ExecuteCommandParams {
1990 command: command.command.clone(),
1991 arguments: command.arguments.clone().unwrap_or_default(),
1992 ..Default::default()
1993 },
1994 )
1995 .await
1996 .into_response();
1997
1998 if execute_command_result.is_err() {
1999 zlog::error!(
2000 logger =>
2001 "Failed to execute command '{}' as part of {}",
2002 &command.command,
2003 describe_code_action(&action),
2004 );
2005 continue 'actions;
2006 }
2007
2008 let mut project_transaction_command =
2009 lsp_store.update(cx, |this, _| {
2010 this.as_local_mut()
2011 .unwrap()
2012 .last_workspace_edits_by_language_server
2013 .remove(&server.server_id())
2014 .unwrap_or_default()
2015 })?;
2016
2017 if let Some(transaction) =
2018 project_transaction_command.0.remove(&buffer.handle)
2019 {
2020 zlog::trace!(
2021 logger =>
2022 "Successfully captured {} edits that resulted from command {}",
2023 transaction.edit_ids.len(),
2024 &command.command,
2025 );
2026 let transaction_id_project_transaction = transaction.id;
2027 buffer.handle.update(cx, |buffer, _| {
2028 // it may have been removed from history if push_to_history was
2029 // false in deserialize_workspace_edit. If so push it so we
2030 // can merge it with the format transaction
2031 // and pop the combined transaction off the history stack
2032 // later if push_to_history is false
2033 if buffer.get_transaction(transaction.id).is_none() {
2034 buffer.push_transaction(transaction, Instant::now());
2035 }
2036 buffer.merge_transactions(
2037 transaction_id_project_transaction,
2038 formatting_transaction_id,
2039 );
2040 })?;
2041 }
2042
2043 if !project_transaction_command.0.is_empty() {
2044 let mut extra_buffers = String::new();
2045 for buffer in project_transaction_command.0.keys() {
2046 buffer
2047 .read_with(cx, |b, cx| {
2048 if let Some(path) = b.project_path(cx) {
2049 if !extra_buffers.is_empty() {
2050 extra_buffers.push_str(", ");
2051 }
2052 extra_buffers.push_str(path.path.as_unix_str());
2053 }
2054 })
2055 .ok();
2056 }
2057 zlog::warn!(
2058 logger =>
2059 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2060 &command.command,
2061 extra_buffers,
2062 );
2063 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2064 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2065 // add it so it's included, and merge it into the format transaction when its created later
2066 }
2067 }
2068 }
2069 }
2070 }
2071 }
2072
2073 Ok(())
2074 }
2075
2076 pub async fn format_ranges_via_lsp(
2077 this: &WeakEntity<LspStore>,
2078 buffer_handle: &Entity<Buffer>,
2079 ranges: &[Range<Anchor>],
2080 abs_path: &Path,
2081 language_server: &Arc<LanguageServer>,
2082 settings: &LanguageSettings,
2083 cx: &mut AsyncApp,
2084 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2085 let capabilities = &language_server.capabilities();
2086 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2087 if range_formatting_provider == Some(&OneOf::Left(false)) {
2088 anyhow::bail!(
2089 "{} language server does not support range formatting",
2090 language_server.name()
2091 );
2092 }
2093
2094 let uri = file_path_to_lsp_url(abs_path)?;
2095 let text_document = lsp::TextDocumentIdentifier::new(uri);
2096
2097 let lsp_edits = {
2098 let mut lsp_ranges = Vec::new();
2099 this.update(cx, |_this, cx| {
2100 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2101 // not have been sent to the language server. This seems like a fairly systemic
2102 // issue, though, the resolution probably is not specific to formatting.
2103 //
2104 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2105 // LSP.
2106 let snapshot = buffer_handle.read(cx).snapshot();
2107 for range in ranges {
2108 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2109 }
2110 anyhow::Ok(())
2111 })??;
2112
2113 let mut edits = None;
2114 for range in lsp_ranges {
2115 if let Some(mut edit) = language_server
2116 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2117 text_document: text_document.clone(),
2118 range,
2119 options: lsp_command::lsp_formatting_options(settings),
2120 work_done_progress_params: Default::default(),
2121 })
2122 .await
2123 .into_response()?
2124 {
2125 edits.get_or_insert_with(Vec::new).append(&mut edit);
2126 }
2127 }
2128 edits
2129 };
2130
2131 if let Some(lsp_edits) = lsp_edits {
2132 this.update(cx, |this, cx| {
2133 this.as_local_mut().unwrap().edits_from_lsp(
2134 buffer_handle,
2135 lsp_edits,
2136 language_server.server_id(),
2137 None,
2138 cx,
2139 )
2140 })?
2141 .await
2142 } else {
2143 Ok(Vec::with_capacity(0))
2144 }
2145 }
2146
2147 async fn format_via_lsp(
2148 this: &WeakEntity<LspStore>,
2149 buffer: &Entity<Buffer>,
2150 abs_path: &Path,
2151 language_server: &Arc<LanguageServer>,
2152 settings: &LanguageSettings,
2153 cx: &mut AsyncApp,
2154 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2155 let logger = zlog::scoped!("lsp_format");
2156 zlog::debug!(logger => "Formatting via LSP");
2157
2158 let uri = file_path_to_lsp_url(abs_path)?;
2159 let text_document = lsp::TextDocumentIdentifier::new(uri);
2160 let capabilities = &language_server.capabilities();
2161
2162 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2163 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2164
2165 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2166 let _timer = zlog::time!(logger => "format-full");
2167 language_server
2168 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2169 text_document,
2170 options: lsp_command::lsp_formatting_options(settings),
2171 work_done_progress_params: Default::default(),
2172 })
2173 .await
2174 .into_response()?
2175 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2176 let _timer = zlog::time!(logger => "format-range");
2177 let buffer_start = lsp::Position::new(0, 0);
2178 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2179 language_server
2180 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2181 text_document: text_document.clone(),
2182 range: lsp::Range::new(buffer_start, buffer_end),
2183 options: lsp_command::lsp_formatting_options(settings),
2184 work_done_progress_params: Default::default(),
2185 })
2186 .await
2187 .into_response()?
2188 } else {
2189 None
2190 };
2191
2192 if let Some(lsp_edits) = lsp_edits {
2193 this.update(cx, |this, cx| {
2194 this.as_local_mut().unwrap().edits_from_lsp(
2195 buffer,
2196 lsp_edits,
2197 language_server.server_id(),
2198 None,
2199 cx,
2200 )
2201 })?
2202 .await
2203 } else {
2204 Ok(Vec::with_capacity(0))
2205 }
2206 }
2207
2208 async fn format_via_external_command(
2209 buffer: &FormattableBuffer,
2210 command: &str,
2211 arguments: Option<&[String]>,
2212 cx: &mut AsyncApp,
2213 ) -> Result<Option<Diff>> {
2214 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2215 let file = File::from_dyn(buffer.file())?;
2216 let worktree = file.worktree.read(cx);
2217 let mut worktree_path = worktree.abs_path().to_path_buf();
2218 if worktree.root_entry()?.is_file() {
2219 worktree_path.pop();
2220 }
2221 Some(worktree_path)
2222 })?;
2223
2224 let mut child = util::command::new_smol_command(command);
2225
2226 if let Some(buffer_env) = buffer.env.as_ref() {
2227 child.envs(buffer_env);
2228 }
2229
2230 if let Some(working_dir_path) = working_dir_path {
2231 child.current_dir(working_dir_path);
2232 }
2233
2234 if let Some(arguments) = arguments {
2235 child.args(arguments.iter().map(|arg| {
2236 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2237 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2238 } else {
2239 arg.replace("{buffer_path}", "Untitled")
2240 }
2241 }));
2242 }
2243
2244 let mut child = child
2245 .stdin(smol::process::Stdio::piped())
2246 .stdout(smol::process::Stdio::piped())
2247 .stderr(smol::process::Stdio::piped())
2248 .spawn()?;
2249
2250 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2251 let text = buffer
2252 .handle
2253 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2254 for chunk in text.chunks() {
2255 stdin.write_all(chunk.as_bytes()).await?;
2256 }
2257 stdin.flush().await?;
2258
2259 let output = child.output().await?;
2260 anyhow::ensure!(
2261 output.status.success(),
2262 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2263 output.status.code(),
2264 String::from_utf8_lossy(&output.stdout),
2265 String::from_utf8_lossy(&output.stderr),
2266 );
2267
2268 let stdout = String::from_utf8(output.stdout)?;
2269 Ok(Some(
2270 buffer
2271 .handle
2272 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2273 .await,
2274 ))
2275 }
2276
2277 async fn try_resolve_code_action(
2278 lang_server: &LanguageServer,
2279 action: &mut CodeAction,
2280 ) -> anyhow::Result<()> {
2281 match &mut action.lsp_action {
2282 LspAction::Action(lsp_action) => {
2283 if !action.resolved
2284 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2285 && lsp_action.data.is_some()
2286 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2287 {
2288 *lsp_action = Box::new(
2289 lang_server
2290 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2291 .await
2292 .into_response()?,
2293 );
2294 }
2295 }
2296 LspAction::CodeLens(lens) => {
2297 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2298 *lens = lang_server
2299 .request::<lsp::request::CodeLensResolve>(lens.clone())
2300 .await
2301 .into_response()?;
2302 }
2303 }
2304 LspAction::Command(_) => {}
2305 }
2306
2307 action.resolved = true;
2308 anyhow::Ok(())
2309 }
2310
2311 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2312 let buffer = buffer_handle.read(cx);
2313
2314 let file = buffer.file().cloned();
2315
2316 let Some(file) = File::from_dyn(file.as_ref()) else {
2317 return;
2318 };
2319 if !file.is_local() {
2320 return;
2321 }
2322 let path = ProjectPath::from_file(file, cx);
2323 let worktree_id = file.worktree_id(cx);
2324 let language = buffer.language().cloned();
2325
2326 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2327 for (server_id, diagnostics) in
2328 diagnostics.get(file.path()).cloned().unwrap_or_default()
2329 {
2330 self.update_buffer_diagnostics(
2331 buffer_handle,
2332 server_id,
2333 None,
2334 None,
2335 None,
2336 Vec::new(),
2337 diagnostics,
2338 cx,
2339 )
2340 .log_err();
2341 }
2342 }
2343 let Some(language) = language else {
2344 return;
2345 };
2346 let Some(snapshot) = self
2347 .worktree_store
2348 .read(cx)
2349 .worktree_for_id(worktree_id, cx)
2350 .map(|worktree| worktree.read(cx).snapshot())
2351 else {
2352 return;
2353 };
2354 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2355
2356 for server_id in
2357 self.lsp_tree
2358 .get(path, language.name(), language.manifest(), &delegate, cx)
2359 {
2360 let server = self
2361 .language_servers
2362 .get(&server_id)
2363 .and_then(|server_state| {
2364 if let LanguageServerState::Running { server, .. } = server_state {
2365 Some(server.clone())
2366 } else {
2367 None
2368 }
2369 });
2370 let server = match server {
2371 Some(server) => server,
2372 None => continue,
2373 };
2374
2375 buffer_handle.update(cx, |buffer, cx| {
2376 buffer.set_completion_triggers(
2377 server.server_id(),
2378 server
2379 .capabilities()
2380 .completion_provider
2381 .as_ref()
2382 .and_then(|provider| {
2383 provider
2384 .trigger_characters
2385 .as_ref()
2386 .map(|characters| characters.iter().cloned().collect())
2387 })
2388 .unwrap_or_default(),
2389 cx,
2390 );
2391 });
2392 }
2393 }
2394
2395 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2396 buffer.update(cx, |buffer, cx| {
2397 let Some(language) = buffer.language() else {
2398 return;
2399 };
2400 let path = ProjectPath {
2401 worktree_id: old_file.worktree_id(cx),
2402 path: old_file.path.clone(),
2403 };
2404 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2405 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2406 buffer.set_completion_triggers(server_id, Default::default(), cx);
2407 }
2408 });
2409 }
2410
2411 fn update_buffer_diagnostics(
2412 &mut self,
2413 buffer: &Entity<Buffer>,
2414 server_id: LanguageServerId,
2415 registration_id: Option<Option<SharedString>>,
2416 result_id: Option<SharedString>,
2417 version: Option<i32>,
2418 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2419 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2420 cx: &mut Context<LspStore>,
2421 ) -> Result<()> {
2422 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2423 Ordering::Equal
2424 .then_with(|| b.is_primary.cmp(&a.is_primary))
2425 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2426 .then_with(|| a.severity.cmp(&b.severity))
2427 .then_with(|| a.message.cmp(&b.message))
2428 }
2429
2430 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2431 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2432 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2433
2434 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2435 Ordering::Equal
2436 .then_with(|| a.range.start.cmp(&b.range.start))
2437 .then_with(|| b.range.end.cmp(&a.range.end))
2438 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2439 });
2440
2441 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2442
2443 let edits_since_save = std::cell::LazyCell::new(|| {
2444 let saved_version = buffer.read(cx).saved_version();
2445 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2446 });
2447
2448 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2449
2450 for (new_diagnostic, entry) in diagnostics {
2451 let start;
2452 let end;
2453 if new_diagnostic && entry.diagnostic.is_disk_based {
2454 // Some diagnostics are based on files on disk instead of buffers'
2455 // current contents. Adjust these diagnostics' ranges to reflect
2456 // any unsaved edits.
2457 // Do not alter the reused ones though, as their coordinates were stored as anchors
2458 // and were properly adjusted on reuse.
2459 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2460 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2461 } else {
2462 start = entry.range.start;
2463 end = entry.range.end;
2464 }
2465
2466 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2467 ..snapshot.clip_point_utf16(end, Bias::Right);
2468
2469 // Expand empty ranges by one codepoint
2470 if range.start == range.end {
2471 // This will be go to the next boundary when being clipped
2472 range.end.column += 1;
2473 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2474 if range.start == range.end && range.end.column > 0 {
2475 range.start.column -= 1;
2476 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2477 }
2478 }
2479
2480 sanitized_diagnostics.push(DiagnosticEntry {
2481 range,
2482 diagnostic: entry.diagnostic,
2483 });
2484 }
2485 drop(edits_since_save);
2486
2487 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2488 buffer.update(cx, |buffer, cx| {
2489 if let Some(registration_id) = registration_id {
2490 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2491 self.buffer_pull_diagnostics_result_ids
2492 .entry(server_id)
2493 .or_default()
2494 .entry(registration_id)
2495 .or_default()
2496 .insert(abs_path, result_id);
2497 }
2498 }
2499
2500 buffer.update_diagnostics(server_id, set, cx)
2501 });
2502
2503 Ok(())
2504 }
2505
2506 fn register_language_server_for_invisible_worktree(
2507 &mut self,
2508 worktree: &Entity<Worktree>,
2509 language_server_id: LanguageServerId,
2510 cx: &mut App,
2511 ) {
2512 let worktree = worktree.read(cx);
2513 let worktree_id = worktree.id();
2514 debug_assert!(!worktree.is_visible());
2515 let Some(mut origin_seed) = self
2516 .language_server_ids
2517 .iter()
2518 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2519 else {
2520 return;
2521 };
2522 origin_seed.worktree_id = worktree_id;
2523 self.language_server_ids
2524 .entry(origin_seed)
2525 .or_insert_with(|| UnifiedLanguageServer {
2526 id: language_server_id,
2527 project_roots: Default::default(),
2528 });
2529 }
2530
2531 fn register_buffer_with_language_servers(
2532 &mut self,
2533 buffer_handle: &Entity<Buffer>,
2534 only_register_servers: HashSet<LanguageServerSelector>,
2535 cx: &mut Context<LspStore>,
2536 ) {
2537 let buffer = buffer_handle.read(cx);
2538 let buffer_id = buffer.remote_id();
2539
2540 let Some(file) = File::from_dyn(buffer.file()) else {
2541 return;
2542 };
2543 if !file.is_local() {
2544 return;
2545 }
2546
2547 let abs_path = file.abs_path(cx);
2548 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2549 return;
2550 };
2551 let initial_snapshot = buffer.text_snapshot();
2552 let worktree_id = file.worktree_id(cx);
2553
2554 let Some(language) = buffer.language().cloned() else {
2555 return;
2556 };
2557 let path: Arc<RelPath> = file
2558 .path()
2559 .parent()
2560 .map(Arc::from)
2561 .unwrap_or_else(|| file.path().clone());
2562 let Some(worktree) = self
2563 .worktree_store
2564 .read(cx)
2565 .worktree_for_id(worktree_id, cx)
2566 else {
2567 return;
2568 };
2569 let language_name = language.name();
2570 let (reused, delegate, servers) = self
2571 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2572 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2573 .unwrap_or_else(|| {
2574 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2575 let delegate: Arc<dyn ManifestDelegate> =
2576 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2577
2578 let servers = self
2579 .lsp_tree
2580 .walk(
2581 ProjectPath { worktree_id, path },
2582 language.name(),
2583 language.manifest(),
2584 &delegate,
2585 cx,
2586 )
2587 .collect::<Vec<_>>();
2588 (false, lsp_delegate, servers)
2589 });
2590 let servers_and_adapters = servers
2591 .into_iter()
2592 .filter_map(|server_node| {
2593 if reused && server_node.server_id().is_none() {
2594 return None;
2595 }
2596 if !only_register_servers.is_empty() {
2597 if let Some(server_id) = server_node.server_id()
2598 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2599 {
2600 return None;
2601 }
2602 if let Some(name) = server_node.name()
2603 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2604 {
2605 return None;
2606 }
2607 }
2608
2609 let server_id = server_node.server_id_or_init(|disposition| {
2610 let path = &disposition.path;
2611
2612 {
2613 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2614
2615 let server_id = self.get_or_insert_language_server(
2616 &worktree,
2617 delegate.clone(),
2618 disposition,
2619 &language_name,
2620 cx,
2621 );
2622
2623 if let Some(state) = self.language_servers.get(&server_id)
2624 && let Ok(uri) = uri
2625 {
2626 state.add_workspace_folder(uri);
2627 };
2628 server_id
2629 }
2630 })?;
2631 let server_state = self.language_servers.get(&server_id)?;
2632 if let LanguageServerState::Running {
2633 server, adapter, ..
2634 } = server_state
2635 {
2636 Some((server.clone(), adapter.clone()))
2637 } else {
2638 None
2639 }
2640 })
2641 .collect::<Vec<_>>();
2642 for (server, adapter) in servers_and_adapters {
2643 buffer_handle.update(cx, |buffer, cx| {
2644 buffer.set_completion_triggers(
2645 server.server_id(),
2646 server
2647 .capabilities()
2648 .completion_provider
2649 .as_ref()
2650 .and_then(|provider| {
2651 provider
2652 .trigger_characters
2653 .as_ref()
2654 .map(|characters| characters.iter().cloned().collect())
2655 })
2656 .unwrap_or_default(),
2657 cx,
2658 );
2659 });
2660
2661 let snapshot = LspBufferSnapshot {
2662 version: 0,
2663 snapshot: initial_snapshot.clone(),
2664 };
2665
2666 let mut registered = false;
2667 self.buffer_snapshots
2668 .entry(buffer_id)
2669 .or_default()
2670 .entry(server.server_id())
2671 .or_insert_with(|| {
2672 registered = true;
2673 server.register_buffer(
2674 uri.clone(),
2675 adapter.language_id(&language.name()),
2676 0,
2677 initial_snapshot.text(),
2678 );
2679
2680 vec![snapshot]
2681 });
2682
2683 self.buffers_opened_in_servers
2684 .entry(buffer_id)
2685 .or_default()
2686 .insert(server.server_id());
2687 if registered {
2688 cx.emit(LspStoreEvent::LanguageServerUpdate {
2689 language_server_id: server.server_id(),
2690 name: None,
2691 message: proto::update_language_server::Variant::RegisteredForBuffer(
2692 proto::RegisteredForBuffer {
2693 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2694 buffer_id: buffer_id.to_proto(),
2695 },
2696 ),
2697 });
2698 }
2699 }
2700 }
2701
2702 fn reuse_existing_language_server<'lang_name>(
2703 &self,
2704 server_tree: &LanguageServerTree,
2705 worktree: &Entity<Worktree>,
2706 language_name: &'lang_name LanguageName,
2707 cx: &mut App,
2708 ) -> Option<(
2709 Arc<LocalLspAdapterDelegate>,
2710 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2711 )> {
2712 if worktree.read(cx).is_visible() {
2713 return None;
2714 }
2715
2716 let worktree_store = self.worktree_store.read(cx);
2717 let servers = server_tree
2718 .instances
2719 .iter()
2720 .filter(|(worktree_id, _)| {
2721 worktree_store
2722 .worktree_for_id(**worktree_id, cx)
2723 .is_some_and(|worktree| worktree.read(cx).is_visible())
2724 })
2725 .flat_map(|(worktree_id, servers)| {
2726 servers
2727 .roots
2728 .iter()
2729 .flat_map(|(_, language_servers)| language_servers)
2730 .map(move |(_, (server_node, server_languages))| {
2731 (worktree_id, server_node, server_languages)
2732 })
2733 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2734 .map(|(worktree_id, server_node, _)| {
2735 (
2736 *worktree_id,
2737 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2738 )
2739 })
2740 })
2741 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2742 acc.entry(worktree_id)
2743 .or_insert_with(Vec::new)
2744 .push(server_node);
2745 acc
2746 })
2747 .into_values()
2748 .max_by_key(|servers| servers.len())?;
2749
2750 let worktree_id = worktree.read(cx).id();
2751 let apply = move |tree: &mut LanguageServerTree| {
2752 for server_node in &servers {
2753 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2754 }
2755 servers
2756 };
2757
2758 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2759 Some((delegate, apply))
2760 }
2761
2762 pub(crate) fn unregister_old_buffer_from_language_servers(
2763 &mut self,
2764 buffer: &Entity<Buffer>,
2765 old_file: &File,
2766 cx: &mut App,
2767 ) {
2768 let old_path = match old_file.as_local() {
2769 Some(local) => local.abs_path(cx),
2770 None => return,
2771 };
2772
2773 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2774 debug_panic!("{old_path:?} is not parseable as an URI");
2775 return;
2776 };
2777 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2778 }
2779
2780 pub(crate) fn unregister_buffer_from_language_servers(
2781 &mut self,
2782 buffer: &Entity<Buffer>,
2783 file_url: &lsp::Uri,
2784 cx: &mut App,
2785 ) {
2786 buffer.update(cx, |buffer, cx| {
2787 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2788
2789 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2790 if snapshots
2791 .as_mut()
2792 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2793 {
2794 language_server.unregister_buffer(file_url.clone());
2795 }
2796 }
2797 });
2798 }
2799
2800 fn buffer_snapshot_for_lsp_version(
2801 &mut self,
2802 buffer: &Entity<Buffer>,
2803 server_id: LanguageServerId,
2804 version: Option<i32>,
2805 cx: &App,
2806 ) -> Result<TextBufferSnapshot> {
2807 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2808
2809 if let Some(version) = version {
2810 let buffer_id = buffer.read(cx).remote_id();
2811 let snapshots = if let Some(snapshots) = self
2812 .buffer_snapshots
2813 .get_mut(&buffer_id)
2814 .and_then(|m| m.get_mut(&server_id))
2815 {
2816 snapshots
2817 } else if version == 0 {
2818 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2819 // We detect this case and treat it as if the version was `None`.
2820 return Ok(buffer.read(cx).text_snapshot());
2821 } else {
2822 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2823 };
2824
2825 let found_snapshot = snapshots
2826 .binary_search_by_key(&version, |e| e.version)
2827 .map(|ix| snapshots[ix].snapshot.clone())
2828 .map_err(|_| {
2829 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2830 })?;
2831
2832 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2833 Ok(found_snapshot)
2834 } else {
2835 Ok((buffer.read(cx)).text_snapshot())
2836 }
2837 }
2838
2839 async fn get_server_code_actions_from_action_kinds(
2840 lsp_store: &WeakEntity<LspStore>,
2841 language_server_id: LanguageServerId,
2842 code_action_kinds: Vec<lsp::CodeActionKind>,
2843 buffer: &Entity<Buffer>,
2844 cx: &mut AsyncApp,
2845 ) -> Result<Vec<CodeAction>> {
2846 let actions = lsp_store
2847 .update(cx, move |this, cx| {
2848 let request = GetCodeActions {
2849 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2850 kinds: Some(code_action_kinds),
2851 };
2852 let server = LanguageServerToQuery::Other(language_server_id);
2853 this.request_lsp(buffer.clone(), server, request, cx)
2854 })?
2855 .await?;
2856 Ok(actions)
2857 }
2858
2859 pub async fn execute_code_actions_on_server(
2860 lsp_store: &WeakEntity<LspStore>,
2861 language_server: &Arc<LanguageServer>,
2862
2863 actions: Vec<CodeAction>,
2864 push_to_history: bool,
2865 project_transaction: &mut ProjectTransaction,
2866 cx: &mut AsyncApp,
2867 ) -> anyhow::Result<()> {
2868 for mut action in actions {
2869 Self::try_resolve_code_action(language_server, &mut action)
2870 .await
2871 .context("resolving a formatting code action")?;
2872
2873 if let Some(edit) = action.lsp_action.edit() {
2874 if edit.changes.is_none() && edit.document_changes.is_none() {
2875 continue;
2876 }
2877
2878 let new = Self::deserialize_workspace_edit(
2879 lsp_store.upgrade().context("project dropped")?,
2880 edit.clone(),
2881 push_to_history,
2882 language_server.clone(),
2883 cx,
2884 )
2885 .await?;
2886 project_transaction.0.extend(new.0);
2887 }
2888
2889 if let Some(command) = action.lsp_action.command() {
2890 let server_capabilities = language_server.capabilities();
2891 let available_commands = server_capabilities
2892 .execute_command_provider
2893 .as_ref()
2894 .map(|options| options.commands.as_slice())
2895 .unwrap_or_default();
2896 if available_commands.contains(&command.command) {
2897 lsp_store.update(cx, |lsp_store, _| {
2898 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2899 mode.last_workspace_edits_by_language_server
2900 .remove(&language_server.server_id());
2901 }
2902 })?;
2903
2904 language_server
2905 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2906 command: command.command.clone(),
2907 arguments: command.arguments.clone().unwrap_or_default(),
2908 ..Default::default()
2909 })
2910 .await
2911 .into_response()
2912 .context("execute command")?;
2913
2914 lsp_store.update(cx, |this, _| {
2915 if let LspStoreMode::Local(mode) = &mut this.mode {
2916 project_transaction.0.extend(
2917 mode.last_workspace_edits_by_language_server
2918 .remove(&language_server.server_id())
2919 .unwrap_or_default()
2920 .0,
2921 )
2922 }
2923 })?;
2924 } else {
2925 log::warn!(
2926 "Cannot execute a command {} not listed in the language server capabilities",
2927 command.command
2928 )
2929 }
2930 }
2931 }
2932 Ok(())
2933 }
2934
2935 pub async fn deserialize_text_edits(
2936 this: Entity<LspStore>,
2937 buffer_to_edit: Entity<Buffer>,
2938 edits: Vec<lsp::TextEdit>,
2939 push_to_history: bool,
2940 _: Arc<CachedLspAdapter>,
2941 language_server: Arc<LanguageServer>,
2942 cx: &mut AsyncApp,
2943 ) -> Result<Option<Transaction>> {
2944 let edits = this
2945 .update(cx, |this, cx| {
2946 this.as_local_mut().unwrap().edits_from_lsp(
2947 &buffer_to_edit,
2948 edits,
2949 language_server.server_id(),
2950 None,
2951 cx,
2952 )
2953 })?
2954 .await?;
2955
2956 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2957 buffer.finalize_last_transaction();
2958 buffer.start_transaction();
2959 for (range, text) in edits {
2960 buffer.edit([(range, text)], None, cx);
2961 }
2962
2963 if buffer.end_transaction(cx).is_some() {
2964 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2965 if !push_to_history {
2966 buffer.forget_transaction(transaction.id);
2967 }
2968 Some(transaction)
2969 } else {
2970 None
2971 }
2972 })?;
2973
2974 Ok(transaction)
2975 }
2976
2977 #[allow(clippy::type_complexity)]
2978 pub(crate) fn edits_from_lsp(
2979 &mut self,
2980 buffer: &Entity<Buffer>,
2981 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2982 server_id: LanguageServerId,
2983 version: Option<i32>,
2984 cx: &mut Context<LspStore>,
2985 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2986 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2987 cx.background_spawn(async move {
2988 let snapshot = snapshot?;
2989 let mut lsp_edits = lsp_edits
2990 .into_iter()
2991 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2992 .collect::<Vec<_>>();
2993
2994 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2995
2996 let mut lsp_edits = lsp_edits.into_iter().peekable();
2997 let mut edits = Vec::new();
2998 while let Some((range, mut new_text)) = lsp_edits.next() {
2999 // Clip invalid ranges provided by the language server.
3000 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3001 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3002
3003 // Combine any LSP edits that are adjacent.
3004 //
3005 // Also, combine LSP edits that are separated from each other by only
3006 // a newline. This is important because for some code actions,
3007 // Rust-analyzer rewrites the entire buffer via a series of edits that
3008 // are separated by unchanged newline characters.
3009 //
3010 // In order for the diffing logic below to work properly, any edits that
3011 // cancel each other out must be combined into one.
3012 while let Some((next_range, next_text)) = lsp_edits.peek() {
3013 if next_range.start.0 > range.end {
3014 if next_range.start.0.row > range.end.row + 1
3015 || next_range.start.0.column > 0
3016 || snapshot.clip_point_utf16(
3017 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3018 Bias::Left,
3019 ) > range.end
3020 {
3021 break;
3022 }
3023 new_text.push('\n');
3024 }
3025 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3026 new_text.push_str(next_text);
3027 lsp_edits.next();
3028 }
3029
3030 // For multiline edits, perform a diff of the old and new text so that
3031 // we can identify the changes more precisely, preserving the locations
3032 // of any anchors positioned in the unchanged regions.
3033 if range.end.row > range.start.row {
3034 let offset = range.start.to_offset(&snapshot);
3035 let old_text = snapshot.text_for_range(range).collect::<String>();
3036 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3037 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3038 (
3039 snapshot.anchor_after(offset + range.start)
3040 ..snapshot.anchor_before(offset + range.end),
3041 replacement,
3042 )
3043 }));
3044 } else if range.end == range.start {
3045 let anchor = snapshot.anchor_after(range.start);
3046 edits.push((anchor..anchor, new_text.into()));
3047 } else {
3048 let edit_start = snapshot.anchor_after(range.start);
3049 let edit_end = snapshot.anchor_before(range.end);
3050 edits.push((edit_start..edit_end, new_text.into()));
3051 }
3052 }
3053
3054 Ok(edits)
3055 })
3056 }
3057
3058 pub(crate) async fn deserialize_workspace_edit(
3059 this: Entity<LspStore>,
3060 edit: lsp::WorkspaceEdit,
3061 push_to_history: bool,
3062 language_server: Arc<LanguageServer>,
3063 cx: &mut AsyncApp,
3064 ) -> Result<ProjectTransaction> {
3065 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3066
3067 let mut operations = Vec::new();
3068 if let Some(document_changes) = edit.document_changes {
3069 match document_changes {
3070 lsp::DocumentChanges::Edits(edits) => {
3071 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3072 }
3073 lsp::DocumentChanges::Operations(ops) => operations = ops,
3074 }
3075 } else if let Some(changes) = edit.changes {
3076 operations.extend(changes.into_iter().map(|(uri, edits)| {
3077 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3078 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3079 uri,
3080 version: None,
3081 },
3082 edits: edits.into_iter().map(Edit::Plain).collect(),
3083 })
3084 }));
3085 }
3086
3087 let mut project_transaction = ProjectTransaction::default();
3088 for operation in operations {
3089 match operation {
3090 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3091 let abs_path = op
3092 .uri
3093 .to_file_path()
3094 .map_err(|()| anyhow!("can't convert URI to path"))?;
3095
3096 if let Some(parent_path) = abs_path.parent() {
3097 fs.create_dir(parent_path).await?;
3098 }
3099 if abs_path.ends_with("/") {
3100 fs.create_dir(&abs_path).await?;
3101 } else {
3102 fs.create_file(
3103 &abs_path,
3104 op.options
3105 .map(|options| fs::CreateOptions {
3106 overwrite: options.overwrite.unwrap_or(false),
3107 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3108 })
3109 .unwrap_or_default(),
3110 )
3111 .await?;
3112 }
3113 }
3114
3115 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3116 let source_abs_path = op
3117 .old_uri
3118 .to_file_path()
3119 .map_err(|()| anyhow!("can't convert URI to path"))?;
3120 let target_abs_path = op
3121 .new_uri
3122 .to_file_path()
3123 .map_err(|()| anyhow!("can't convert URI to path"))?;
3124
3125 let options = fs::RenameOptions {
3126 overwrite: op
3127 .options
3128 .as_ref()
3129 .and_then(|options| options.overwrite)
3130 .unwrap_or(false),
3131 ignore_if_exists: op
3132 .options
3133 .as_ref()
3134 .and_then(|options| options.ignore_if_exists)
3135 .unwrap_or(false),
3136 create_parents: true,
3137 };
3138
3139 fs.rename(&source_abs_path, &target_abs_path, options)
3140 .await?;
3141 }
3142
3143 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3144 let abs_path = op
3145 .uri
3146 .to_file_path()
3147 .map_err(|()| anyhow!("can't convert URI to path"))?;
3148 let options = op
3149 .options
3150 .map(|options| fs::RemoveOptions {
3151 recursive: options.recursive.unwrap_or(false),
3152 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3153 })
3154 .unwrap_or_default();
3155 if abs_path.ends_with("/") {
3156 fs.remove_dir(&abs_path, options).await?;
3157 } else {
3158 fs.remove_file(&abs_path, options).await?;
3159 }
3160 }
3161
3162 lsp::DocumentChangeOperation::Edit(op) => {
3163 let buffer_to_edit = this
3164 .update(cx, |this, cx| {
3165 this.open_local_buffer_via_lsp(
3166 op.text_document.uri.clone(),
3167 language_server.server_id(),
3168 cx,
3169 )
3170 })?
3171 .await?;
3172
3173 let edits = this
3174 .update(cx, |this, cx| {
3175 let path = buffer_to_edit.read(cx).project_path(cx);
3176 let active_entry = this.active_entry;
3177 let is_active_entry = path.is_some_and(|project_path| {
3178 this.worktree_store
3179 .read(cx)
3180 .entry_for_path(&project_path, cx)
3181 .is_some_and(|entry| Some(entry.id) == active_entry)
3182 });
3183 let local = this.as_local_mut().unwrap();
3184
3185 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3186 for edit in op.edits {
3187 match edit {
3188 Edit::Plain(edit) => {
3189 if !edits.contains(&edit) {
3190 edits.push(edit)
3191 }
3192 }
3193 Edit::Annotated(edit) => {
3194 if !edits.contains(&edit.text_edit) {
3195 edits.push(edit.text_edit)
3196 }
3197 }
3198 Edit::Snippet(edit) => {
3199 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3200 else {
3201 continue;
3202 };
3203
3204 if is_active_entry {
3205 snippet_edits.push((edit.range, snippet));
3206 } else {
3207 // Since this buffer is not focused, apply a normal edit.
3208 let new_edit = TextEdit {
3209 range: edit.range,
3210 new_text: snippet.text,
3211 };
3212 if !edits.contains(&new_edit) {
3213 edits.push(new_edit);
3214 }
3215 }
3216 }
3217 }
3218 }
3219 if !snippet_edits.is_empty() {
3220 let buffer_id = buffer_to_edit.read(cx).remote_id();
3221 let version = if let Some(buffer_version) = op.text_document.version
3222 {
3223 local
3224 .buffer_snapshot_for_lsp_version(
3225 &buffer_to_edit,
3226 language_server.server_id(),
3227 Some(buffer_version),
3228 cx,
3229 )
3230 .ok()
3231 .map(|snapshot| snapshot.version)
3232 } else {
3233 Some(buffer_to_edit.read(cx).saved_version().clone())
3234 };
3235
3236 let most_recent_edit =
3237 version.and_then(|version| version.most_recent());
3238 // Check if the edit that triggered that edit has been made by this participant.
3239
3240 if let Some(most_recent_edit) = most_recent_edit {
3241 cx.emit(LspStoreEvent::SnippetEdit {
3242 buffer_id,
3243 edits: snippet_edits,
3244 most_recent_edit,
3245 });
3246 }
3247 }
3248
3249 local.edits_from_lsp(
3250 &buffer_to_edit,
3251 edits,
3252 language_server.server_id(),
3253 op.text_document.version,
3254 cx,
3255 )
3256 })?
3257 .await?;
3258
3259 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3260 buffer.finalize_last_transaction();
3261 buffer.start_transaction();
3262 for (range, text) in edits {
3263 buffer.edit([(range, text)], None, cx);
3264 }
3265
3266 buffer.end_transaction(cx).and_then(|transaction_id| {
3267 if push_to_history {
3268 buffer.finalize_last_transaction();
3269 buffer.get_transaction(transaction_id).cloned()
3270 } else {
3271 buffer.forget_transaction(transaction_id)
3272 }
3273 })
3274 })?;
3275 if let Some(transaction) = transaction {
3276 project_transaction.0.insert(buffer_to_edit, transaction);
3277 }
3278 }
3279 }
3280 }
3281
3282 Ok(project_transaction)
3283 }
3284
3285 async fn on_lsp_workspace_edit(
3286 this: WeakEntity<LspStore>,
3287 params: lsp::ApplyWorkspaceEditParams,
3288 server_id: LanguageServerId,
3289 cx: &mut AsyncApp,
3290 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3291 let this = this.upgrade().context("project project closed")?;
3292 let language_server = this
3293 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3294 .context("language server not found")?;
3295 let transaction = Self::deserialize_workspace_edit(
3296 this.clone(),
3297 params.edit,
3298 true,
3299 language_server.clone(),
3300 cx,
3301 )
3302 .await
3303 .log_err();
3304 this.update(cx, |this, _| {
3305 if let Some(transaction) = transaction {
3306 this.as_local_mut()
3307 .unwrap()
3308 .last_workspace_edits_by_language_server
3309 .insert(server_id, transaction);
3310 }
3311 })?;
3312 Ok(lsp::ApplyWorkspaceEditResponse {
3313 applied: true,
3314 failed_change: None,
3315 failure_reason: None,
3316 })
3317 }
3318
3319 fn remove_worktree(
3320 &mut self,
3321 id_to_remove: WorktreeId,
3322 cx: &mut Context<LspStore>,
3323 ) -> Vec<LanguageServerId> {
3324 self.restricted_worktrees_tasks.remove(&id_to_remove);
3325 self.diagnostics.remove(&id_to_remove);
3326 self.prettier_store.update(cx, |prettier_store, cx| {
3327 prettier_store.remove_worktree(id_to_remove, cx);
3328 });
3329
3330 let mut servers_to_remove = BTreeSet::default();
3331 let mut servers_to_preserve = HashSet::default();
3332 for (seed, state) in &self.language_server_ids {
3333 if seed.worktree_id == id_to_remove {
3334 servers_to_remove.insert(state.id);
3335 } else {
3336 servers_to_preserve.insert(state.id);
3337 }
3338 }
3339 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3340 self.language_server_ids
3341 .retain(|_, state| !servers_to_remove.contains(&state.id));
3342 for server_id_to_remove in &servers_to_remove {
3343 self.language_server_watched_paths
3344 .remove(server_id_to_remove);
3345 self.language_server_paths_watched_for_rename
3346 .remove(server_id_to_remove);
3347 self.last_workspace_edits_by_language_server
3348 .remove(server_id_to_remove);
3349 self.language_servers.remove(server_id_to_remove);
3350 self.buffer_pull_diagnostics_result_ids
3351 .remove(server_id_to_remove);
3352 self.workspace_pull_diagnostics_result_ids
3353 .remove(server_id_to_remove);
3354 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3355 buffer_servers.remove(server_id_to_remove);
3356 }
3357 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3358 }
3359 servers_to_remove.into_iter().collect()
3360 }
3361
3362 fn rebuild_watched_paths_inner<'a>(
3363 &'a self,
3364 language_server_id: LanguageServerId,
3365 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3366 cx: &mut Context<LspStore>,
3367 ) -> LanguageServerWatchedPathsBuilder {
3368 let worktrees = self
3369 .worktree_store
3370 .read(cx)
3371 .worktrees()
3372 .filter_map(|worktree| {
3373 self.language_servers_for_worktree(worktree.read(cx).id())
3374 .find(|server| server.server_id() == language_server_id)
3375 .map(|_| worktree)
3376 })
3377 .collect::<Vec<_>>();
3378
3379 let mut worktree_globs = HashMap::default();
3380 let mut abs_globs = HashMap::default();
3381 log::trace!(
3382 "Processing new watcher paths for language server with id {}",
3383 language_server_id
3384 );
3385
3386 for watcher in watchers {
3387 if let Some((worktree, literal_prefix, pattern)) =
3388 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3389 {
3390 worktree.update(cx, |worktree, _| {
3391 if let Some((tree, glob)) =
3392 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3393 {
3394 tree.add_path_prefix_to_scan(literal_prefix);
3395 worktree_globs
3396 .entry(tree.id())
3397 .or_insert_with(GlobSetBuilder::new)
3398 .add(glob);
3399 }
3400 });
3401 } else {
3402 let (path, pattern) = match &watcher.glob_pattern {
3403 lsp::GlobPattern::String(s) => {
3404 let watcher_path = SanitizedPath::new(s);
3405 let path = glob_literal_prefix(watcher_path.as_path());
3406 let pattern = watcher_path
3407 .as_path()
3408 .strip_prefix(&path)
3409 .map(|p| p.to_string_lossy().into_owned())
3410 .unwrap_or_else(|e| {
3411 debug_panic!(
3412 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3413 s,
3414 path.display(),
3415 e
3416 );
3417 watcher_path.as_path().to_string_lossy().into_owned()
3418 });
3419 (path, pattern)
3420 }
3421 lsp::GlobPattern::Relative(rp) => {
3422 let Ok(mut base_uri) = match &rp.base_uri {
3423 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3424 lsp::OneOf::Right(base_uri) => base_uri,
3425 }
3426 .to_file_path() else {
3427 continue;
3428 };
3429
3430 let path = glob_literal_prefix(Path::new(&rp.pattern));
3431 let pattern = Path::new(&rp.pattern)
3432 .strip_prefix(&path)
3433 .map(|p| p.to_string_lossy().into_owned())
3434 .unwrap_or_else(|e| {
3435 debug_panic!(
3436 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3437 rp.pattern,
3438 path.display(),
3439 e
3440 );
3441 rp.pattern.clone()
3442 });
3443 base_uri.push(path);
3444 (base_uri, pattern)
3445 }
3446 };
3447
3448 if let Some(glob) = Glob::new(&pattern).log_err() {
3449 if !path
3450 .components()
3451 .any(|c| matches!(c, path::Component::Normal(_)))
3452 {
3453 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3454 // rather than adding a new watcher for `/`.
3455 for worktree in &worktrees {
3456 worktree_globs
3457 .entry(worktree.read(cx).id())
3458 .or_insert_with(GlobSetBuilder::new)
3459 .add(glob.clone());
3460 }
3461 } else {
3462 abs_globs
3463 .entry(path.into())
3464 .or_insert_with(GlobSetBuilder::new)
3465 .add(glob);
3466 }
3467 }
3468 }
3469 }
3470
3471 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3472 for (worktree_id, builder) in worktree_globs {
3473 if let Ok(globset) = builder.build() {
3474 watch_builder.watch_worktree(worktree_id, globset);
3475 }
3476 }
3477 for (abs_path, builder) in abs_globs {
3478 if let Ok(globset) = builder.build() {
3479 watch_builder.watch_abs_path(abs_path, globset);
3480 }
3481 }
3482 watch_builder
3483 }
3484
3485 fn worktree_and_path_for_file_watcher(
3486 worktrees: &[Entity<Worktree>],
3487 watcher: &FileSystemWatcher,
3488 cx: &App,
3489 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3490 worktrees.iter().find_map(|worktree| {
3491 let tree = worktree.read(cx);
3492 let worktree_root_path = tree.abs_path();
3493 let path_style = tree.path_style();
3494 match &watcher.glob_pattern {
3495 lsp::GlobPattern::String(s) => {
3496 let watcher_path = SanitizedPath::new(s);
3497 let relative = watcher_path
3498 .as_path()
3499 .strip_prefix(&worktree_root_path)
3500 .ok()?;
3501 let literal_prefix = glob_literal_prefix(relative);
3502 Some((
3503 worktree.clone(),
3504 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3505 relative.to_string_lossy().into_owned(),
3506 ))
3507 }
3508 lsp::GlobPattern::Relative(rp) => {
3509 let base_uri = match &rp.base_uri {
3510 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3511 lsp::OneOf::Right(base_uri) => base_uri,
3512 }
3513 .to_file_path()
3514 .ok()?;
3515 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3516 let mut literal_prefix = relative.to_owned();
3517 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3518 Some((
3519 worktree.clone(),
3520 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3521 rp.pattern.clone(),
3522 ))
3523 }
3524 }
3525 })
3526 }
3527
3528 fn rebuild_watched_paths(
3529 &mut self,
3530 language_server_id: LanguageServerId,
3531 cx: &mut Context<LspStore>,
3532 ) {
3533 let Some(registrations) = self
3534 .language_server_dynamic_registrations
3535 .get(&language_server_id)
3536 else {
3537 return;
3538 };
3539
3540 let watch_builder = self.rebuild_watched_paths_inner(
3541 language_server_id,
3542 registrations.did_change_watched_files.values().flatten(),
3543 cx,
3544 );
3545 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3546 self.language_server_watched_paths
3547 .insert(language_server_id, watcher);
3548
3549 cx.notify();
3550 }
3551
3552 fn on_lsp_did_change_watched_files(
3553 &mut self,
3554 language_server_id: LanguageServerId,
3555 registration_id: &str,
3556 params: DidChangeWatchedFilesRegistrationOptions,
3557 cx: &mut Context<LspStore>,
3558 ) {
3559 let registrations = self
3560 .language_server_dynamic_registrations
3561 .entry(language_server_id)
3562 .or_default();
3563
3564 registrations
3565 .did_change_watched_files
3566 .insert(registration_id.to_string(), params.watchers);
3567
3568 self.rebuild_watched_paths(language_server_id, cx);
3569 }
3570
3571 fn on_lsp_unregister_did_change_watched_files(
3572 &mut self,
3573 language_server_id: LanguageServerId,
3574 registration_id: &str,
3575 cx: &mut Context<LspStore>,
3576 ) {
3577 let registrations = self
3578 .language_server_dynamic_registrations
3579 .entry(language_server_id)
3580 .or_default();
3581
3582 if registrations
3583 .did_change_watched_files
3584 .remove(registration_id)
3585 .is_some()
3586 {
3587 log::info!(
3588 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3589 language_server_id,
3590 registration_id
3591 );
3592 } else {
3593 log::warn!(
3594 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3595 language_server_id,
3596 registration_id
3597 );
3598 }
3599
3600 self.rebuild_watched_paths(language_server_id, cx);
3601 }
3602
3603 async fn initialization_options_for_adapter(
3604 adapter: Arc<dyn LspAdapter>,
3605 delegate: &Arc<dyn LspAdapterDelegate>,
3606 ) -> Result<Option<serde_json::Value>> {
3607 let Some(mut initialization_config) =
3608 adapter.clone().initialization_options(delegate).await?
3609 else {
3610 return Ok(None);
3611 };
3612
3613 for other_adapter in delegate.registered_lsp_adapters() {
3614 if other_adapter.name() == adapter.name() {
3615 continue;
3616 }
3617 if let Ok(Some(target_config)) = other_adapter
3618 .clone()
3619 .additional_initialization_options(adapter.name(), delegate)
3620 .await
3621 {
3622 merge_json_value_into(target_config.clone(), &mut initialization_config);
3623 }
3624 }
3625
3626 Ok(Some(initialization_config))
3627 }
3628
3629 async fn workspace_configuration_for_adapter(
3630 adapter: Arc<dyn LspAdapter>,
3631 delegate: &Arc<dyn LspAdapterDelegate>,
3632 toolchain: Option<Toolchain>,
3633 requested_uri: Option<Uri>,
3634 cx: &mut AsyncApp,
3635 ) -> Result<serde_json::Value> {
3636 let mut workspace_config = adapter
3637 .clone()
3638 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3639 .await?;
3640
3641 for other_adapter in delegate.registered_lsp_adapters() {
3642 if other_adapter.name() == adapter.name() {
3643 continue;
3644 }
3645 if let Ok(Some(target_config)) = other_adapter
3646 .clone()
3647 .additional_workspace_configuration(adapter.name(), delegate, cx)
3648 .await
3649 {
3650 merge_json_value_into(target_config.clone(), &mut workspace_config);
3651 }
3652 }
3653
3654 Ok(workspace_config)
3655 }
3656
3657 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3658 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3659 Some(server.clone())
3660 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3661 Some(Arc::clone(server))
3662 } else {
3663 None
3664 }
3665 }
3666}
3667
3668fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3669 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3670 cx.emit(LspStoreEvent::LanguageServerUpdate {
3671 language_server_id: server.server_id(),
3672 name: Some(server.name()),
3673 message: proto::update_language_server::Variant::MetadataUpdated(
3674 proto::ServerMetadataUpdated {
3675 capabilities: Some(capabilities),
3676 binary: Some(proto::LanguageServerBinaryInfo {
3677 path: server.binary().path.to_string_lossy().into_owned(),
3678 arguments: server
3679 .binary()
3680 .arguments
3681 .iter()
3682 .map(|arg| arg.to_string_lossy().into_owned())
3683 .collect(),
3684 }),
3685 configuration: serde_json::to_string(server.configuration()).ok(),
3686 workspace_folders: server
3687 .workspace_folders()
3688 .iter()
3689 .map(|uri| uri.to_string())
3690 .collect(),
3691 },
3692 ),
3693 });
3694 }
3695}
3696
3697#[derive(Debug)]
3698pub struct FormattableBuffer {
3699 handle: Entity<Buffer>,
3700 abs_path: Option<PathBuf>,
3701 env: Option<HashMap<String, String>>,
3702 ranges: Option<Vec<Range<Anchor>>>,
3703}
3704
3705pub struct RemoteLspStore {
3706 upstream_client: Option<AnyProtoClient>,
3707 upstream_project_id: u64,
3708}
3709
3710pub(crate) enum LspStoreMode {
3711 Local(LocalLspStore), // ssh host and collab host
3712 Remote(RemoteLspStore), // collab guest
3713}
3714
3715impl LspStoreMode {
3716 fn is_local(&self) -> bool {
3717 matches!(self, LspStoreMode::Local(_))
3718 }
3719}
3720
3721pub struct LspStore {
3722 mode: LspStoreMode,
3723 last_formatting_failure: Option<String>,
3724 downstream_client: Option<(AnyProtoClient, u64)>,
3725 nonce: u128,
3726 buffer_store: Entity<BufferStore>,
3727 worktree_store: Entity<WorktreeStore>,
3728 pub languages: Arc<LanguageRegistry>,
3729 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3730 active_entry: Option<ProjectEntryId>,
3731 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3732 _maintain_buffer_languages: Task<()>,
3733 diagnostic_summaries:
3734 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3735 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3736 lsp_data: HashMap<BufferId, BufferLspData>,
3737 next_hint_id: Arc<AtomicUsize>,
3738}
3739
3740#[derive(Debug)]
3741pub struct BufferLspData {
3742 buffer_version: Global,
3743 document_colors: Option<DocumentColorData>,
3744 code_lens: Option<CodeLensData>,
3745 inlay_hints: BufferInlayHints,
3746 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3747 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3748}
3749
3750#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3751struct LspKey {
3752 request_type: TypeId,
3753 server_queried: Option<LanguageServerId>,
3754}
3755
3756impl BufferLspData {
3757 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3758 Self {
3759 buffer_version: buffer.read(cx).version(),
3760 document_colors: None,
3761 code_lens: None,
3762 inlay_hints: BufferInlayHints::new(buffer, cx),
3763 lsp_requests: HashMap::default(),
3764 chunk_lsp_requests: HashMap::default(),
3765 }
3766 }
3767
3768 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3769 if let Some(document_colors) = &mut self.document_colors {
3770 document_colors.colors.remove(&for_server);
3771 document_colors.cache_version += 1;
3772 }
3773
3774 if let Some(code_lens) = &mut self.code_lens {
3775 code_lens.lens.remove(&for_server);
3776 }
3777
3778 self.inlay_hints.remove_server_data(for_server);
3779 }
3780
3781 #[cfg(any(test, feature = "test-support"))]
3782 pub fn inlay_hints(&self) -> &BufferInlayHints {
3783 &self.inlay_hints
3784 }
3785}
3786
3787#[derive(Debug, Default, Clone)]
3788pub struct DocumentColors {
3789 pub colors: HashSet<DocumentColor>,
3790 pub cache_version: Option<usize>,
3791}
3792
3793type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3794type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3795
3796#[derive(Debug, Default)]
3797struct DocumentColorData {
3798 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3799 cache_version: usize,
3800 colors_update: Option<(Global, DocumentColorTask)>,
3801}
3802
3803#[derive(Debug, Default)]
3804struct CodeLensData {
3805 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3806 update: Option<(Global, CodeLensTask)>,
3807}
3808
3809#[derive(Debug)]
3810pub enum LspStoreEvent {
3811 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3812 LanguageServerRemoved(LanguageServerId),
3813 LanguageServerUpdate {
3814 language_server_id: LanguageServerId,
3815 name: Option<LanguageServerName>,
3816 message: proto::update_language_server::Variant,
3817 },
3818 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3819 LanguageServerPrompt(LanguageServerPromptRequest),
3820 LanguageDetected {
3821 buffer: Entity<Buffer>,
3822 new_language: Option<Arc<Language>>,
3823 },
3824 Notification(String),
3825 RefreshInlayHints {
3826 server_id: LanguageServerId,
3827 request_id: Option<usize>,
3828 },
3829 RefreshCodeLens,
3830 DiagnosticsUpdated {
3831 server_id: LanguageServerId,
3832 paths: Vec<ProjectPath>,
3833 },
3834 DiskBasedDiagnosticsStarted {
3835 language_server_id: LanguageServerId,
3836 },
3837 DiskBasedDiagnosticsFinished {
3838 language_server_id: LanguageServerId,
3839 },
3840 SnippetEdit {
3841 buffer_id: BufferId,
3842 edits: Vec<(lsp::Range, Snippet)>,
3843 most_recent_edit: clock::Lamport,
3844 },
3845}
3846
3847#[derive(Clone, Debug, Serialize)]
3848pub struct LanguageServerStatus {
3849 pub name: LanguageServerName,
3850 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3851 pub has_pending_diagnostic_updates: bool,
3852 pub progress_tokens: HashSet<ProgressToken>,
3853 pub worktree: Option<WorktreeId>,
3854 pub binary: Option<LanguageServerBinary>,
3855 pub configuration: Option<Value>,
3856 pub workspace_folders: BTreeSet<Uri>,
3857}
3858
3859#[derive(Clone, Debug)]
3860struct CoreSymbol {
3861 pub language_server_name: LanguageServerName,
3862 pub source_worktree_id: WorktreeId,
3863 pub source_language_server_id: LanguageServerId,
3864 pub path: SymbolLocation,
3865 pub name: String,
3866 pub kind: lsp::SymbolKind,
3867 pub range: Range<Unclipped<PointUtf16>>,
3868}
3869
3870#[derive(Clone, Debug, PartialEq, Eq)]
3871pub enum SymbolLocation {
3872 InProject(ProjectPath),
3873 OutsideProject {
3874 abs_path: Arc<Path>,
3875 signature: [u8; 32],
3876 },
3877}
3878
3879impl SymbolLocation {
3880 fn file_name(&self) -> Option<&str> {
3881 match self {
3882 Self::InProject(path) => path.path.file_name(),
3883 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3884 }
3885 }
3886}
3887
3888impl LspStore {
3889 pub fn init(client: &AnyProtoClient) {
3890 client.add_entity_request_handler(Self::handle_lsp_query);
3891 client.add_entity_message_handler(Self::handle_lsp_query_response);
3892 client.add_entity_request_handler(Self::handle_restart_language_servers);
3893 client.add_entity_request_handler(Self::handle_stop_language_servers);
3894 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3895 client.add_entity_message_handler(Self::handle_start_language_server);
3896 client.add_entity_message_handler(Self::handle_update_language_server);
3897 client.add_entity_message_handler(Self::handle_language_server_log);
3898 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3899 client.add_entity_request_handler(Self::handle_format_buffers);
3900 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3901 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3902 client.add_entity_request_handler(Self::handle_apply_code_action);
3903 client.add_entity_request_handler(Self::handle_get_project_symbols);
3904 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3905 client.add_entity_request_handler(Self::handle_get_color_presentation);
3906 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3907 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3908 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3909 client.add_entity_request_handler(Self::handle_on_type_formatting);
3910 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3911 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3912 client.add_entity_request_handler(Self::handle_rename_project_entry);
3913 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3914 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3915 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3916 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3917 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3918 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3919 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3920
3921 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3922 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3923 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3924 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3925 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3926 client.add_entity_request_handler(
3927 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3928 );
3929 client.add_entity_request_handler(
3930 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3931 );
3932 client.add_entity_request_handler(
3933 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3934 );
3935 }
3936
3937 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3938 match &self.mode {
3939 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3940 _ => None,
3941 }
3942 }
3943
3944 pub fn as_local(&self) -> Option<&LocalLspStore> {
3945 match &self.mode {
3946 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3947 _ => None,
3948 }
3949 }
3950
3951 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3952 match &mut self.mode {
3953 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3954 _ => None,
3955 }
3956 }
3957
3958 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3959 match &self.mode {
3960 LspStoreMode::Remote(RemoteLspStore {
3961 upstream_client: Some(upstream_client),
3962 upstream_project_id,
3963 ..
3964 }) => Some((upstream_client.clone(), *upstream_project_id)),
3965
3966 LspStoreMode::Remote(RemoteLspStore {
3967 upstream_client: None,
3968 ..
3969 }) => None,
3970 LspStoreMode::Local(_) => None,
3971 }
3972 }
3973
3974 pub fn new_local(
3975 buffer_store: Entity<BufferStore>,
3976 worktree_store: Entity<WorktreeStore>,
3977 prettier_store: Entity<PrettierStore>,
3978 toolchain_store: Entity<LocalToolchainStore>,
3979 environment: Entity<ProjectEnvironment>,
3980 manifest_tree: Entity<ManifestTree>,
3981 languages: Arc<LanguageRegistry>,
3982 http_client: Arc<dyn HttpClient>,
3983 fs: Arc<dyn Fs>,
3984 cx: &mut Context<Self>,
3985 ) -> Self {
3986 let yarn = YarnPathStore::new(fs.clone(), cx);
3987 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3988 .detach();
3989 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3990 .detach();
3991 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3992 .detach();
3993 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3994 .detach();
3995 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3996 .detach();
3997 subscribe_to_binary_statuses(&languages, cx).detach();
3998
3999 let _maintain_workspace_config = {
4000 let (sender, receiver) = watch::channel();
4001 (Self::maintain_workspace_config(receiver, cx), sender)
4002 };
4003
4004 Self {
4005 mode: LspStoreMode::Local(LocalLspStore {
4006 weak: cx.weak_entity(),
4007 worktree_store: worktree_store.clone(),
4008
4009 supplementary_language_servers: Default::default(),
4010 languages: languages.clone(),
4011 language_server_ids: Default::default(),
4012 language_servers: Default::default(),
4013 last_workspace_edits_by_language_server: Default::default(),
4014 language_server_watched_paths: Default::default(),
4015 language_server_paths_watched_for_rename: Default::default(),
4016 language_server_dynamic_registrations: Default::default(),
4017 buffers_being_formatted: Default::default(),
4018 buffer_snapshots: Default::default(),
4019 prettier_store,
4020 environment,
4021 http_client,
4022 fs,
4023 yarn,
4024 next_diagnostic_group_id: Default::default(),
4025 diagnostics: Default::default(),
4026 _subscription: cx.on_app_quit(|this, cx| {
4027 this.as_local_mut()
4028 .unwrap()
4029 .shutdown_language_servers_on_quit(cx)
4030 }),
4031 lsp_tree: LanguageServerTree::new(
4032 manifest_tree,
4033 languages.clone(),
4034 toolchain_store.clone(),
4035 ),
4036 toolchain_store,
4037 registered_buffers: HashMap::default(),
4038 buffers_opened_in_servers: HashMap::default(),
4039 buffer_pull_diagnostics_result_ids: HashMap::default(),
4040 workspace_pull_diagnostics_result_ids: HashMap::default(),
4041 restricted_worktrees_tasks: HashMap::default(),
4042 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4043 .manifest_file_names(),
4044 }),
4045 last_formatting_failure: None,
4046 downstream_client: None,
4047 buffer_store,
4048 worktree_store,
4049 languages: languages.clone(),
4050 language_server_statuses: Default::default(),
4051 nonce: StdRng::from_os_rng().random(),
4052 diagnostic_summaries: HashMap::default(),
4053 lsp_server_capabilities: HashMap::default(),
4054 lsp_data: HashMap::default(),
4055 next_hint_id: Arc::default(),
4056 active_entry: None,
4057 _maintain_workspace_config,
4058 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4059 }
4060 }
4061
4062 fn send_lsp_proto_request<R: LspCommand>(
4063 &self,
4064 buffer: Entity<Buffer>,
4065 client: AnyProtoClient,
4066 upstream_project_id: u64,
4067 request: R,
4068 cx: &mut Context<LspStore>,
4069 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4070 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4071 return Task::ready(Ok(R::Response::default()));
4072 }
4073 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4074 cx.spawn(async move |this, cx| {
4075 let response = client.request(message).await?;
4076 let this = this.upgrade().context("project dropped")?;
4077 request
4078 .response_from_proto(response, this, buffer, cx.clone())
4079 .await
4080 })
4081 }
4082
4083 pub(super) fn new_remote(
4084 buffer_store: Entity<BufferStore>,
4085 worktree_store: Entity<WorktreeStore>,
4086 languages: Arc<LanguageRegistry>,
4087 upstream_client: AnyProtoClient,
4088 project_id: u64,
4089 cx: &mut Context<Self>,
4090 ) -> Self {
4091 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4092 .detach();
4093 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4094 .detach();
4095 subscribe_to_binary_statuses(&languages, cx).detach();
4096 let _maintain_workspace_config = {
4097 let (sender, receiver) = watch::channel();
4098 (Self::maintain_workspace_config(receiver, cx), sender)
4099 };
4100 Self {
4101 mode: LspStoreMode::Remote(RemoteLspStore {
4102 upstream_client: Some(upstream_client),
4103 upstream_project_id: project_id,
4104 }),
4105 downstream_client: None,
4106 last_formatting_failure: None,
4107 buffer_store,
4108 worktree_store,
4109 languages: languages.clone(),
4110 language_server_statuses: Default::default(),
4111 nonce: StdRng::from_os_rng().random(),
4112 diagnostic_summaries: HashMap::default(),
4113 lsp_server_capabilities: HashMap::default(),
4114 next_hint_id: Arc::default(),
4115 lsp_data: HashMap::default(),
4116 active_entry: None,
4117
4118 _maintain_workspace_config,
4119 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4120 }
4121 }
4122
4123 fn on_buffer_store_event(
4124 &mut self,
4125 _: Entity<BufferStore>,
4126 event: &BufferStoreEvent,
4127 cx: &mut Context<Self>,
4128 ) {
4129 match event {
4130 BufferStoreEvent::BufferAdded(buffer) => {
4131 self.on_buffer_added(buffer, cx).log_err();
4132 }
4133 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4134 let buffer_id = buffer.read(cx).remote_id();
4135 if let Some(local) = self.as_local_mut()
4136 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4137 {
4138 local.reset_buffer(buffer, old_file, cx);
4139
4140 if local.registered_buffers.contains_key(&buffer_id) {
4141 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4142 }
4143 }
4144
4145 self.detect_language_for_buffer(buffer, cx);
4146 if let Some(local) = self.as_local_mut() {
4147 local.initialize_buffer(buffer, cx);
4148 if local.registered_buffers.contains_key(&buffer_id) {
4149 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4150 }
4151 }
4152 }
4153 _ => {}
4154 }
4155 }
4156
4157 fn on_worktree_store_event(
4158 &mut self,
4159 _: Entity<WorktreeStore>,
4160 event: &WorktreeStoreEvent,
4161 cx: &mut Context<Self>,
4162 ) {
4163 match event {
4164 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4165 if !worktree.read(cx).is_local() {
4166 return;
4167 }
4168 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4169 worktree::Event::UpdatedEntries(changes) => {
4170 this.update_local_worktree_language_servers(&worktree, changes, cx);
4171 }
4172 worktree::Event::UpdatedGitRepositories(_)
4173 | worktree::Event::DeletedEntry(_) => {}
4174 })
4175 .detach()
4176 }
4177 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4178 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4179 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4180 }
4181 WorktreeStoreEvent::WorktreeReleased(..)
4182 | WorktreeStoreEvent::WorktreeOrderChanged
4183 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4184 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4185 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4186 }
4187 }
4188
4189 fn on_prettier_store_event(
4190 &mut self,
4191 _: Entity<PrettierStore>,
4192 event: &PrettierStoreEvent,
4193 cx: &mut Context<Self>,
4194 ) {
4195 match event {
4196 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4197 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4198 }
4199 PrettierStoreEvent::LanguageServerAdded {
4200 new_server_id,
4201 name,
4202 prettier_server,
4203 } => {
4204 self.register_supplementary_language_server(
4205 *new_server_id,
4206 name.clone(),
4207 prettier_server.clone(),
4208 cx,
4209 );
4210 }
4211 }
4212 }
4213
4214 fn on_toolchain_store_event(
4215 &mut self,
4216 _: Entity<LocalToolchainStore>,
4217 event: &ToolchainStoreEvent,
4218 _: &mut Context<Self>,
4219 ) {
4220 if let ToolchainStoreEvent::ToolchainActivated = event {
4221 self.request_workspace_config_refresh()
4222 }
4223 }
4224
4225 fn request_workspace_config_refresh(&mut self) {
4226 *self._maintain_workspace_config.1.borrow_mut() = ();
4227 }
4228
4229 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4230 self.as_local().map(|local| local.prettier_store.clone())
4231 }
4232
4233 fn on_buffer_event(
4234 &mut self,
4235 buffer: Entity<Buffer>,
4236 event: &language::BufferEvent,
4237 cx: &mut Context<Self>,
4238 ) {
4239 match event {
4240 language::BufferEvent::Edited => {
4241 self.on_buffer_edited(buffer, cx);
4242 }
4243
4244 language::BufferEvent::Saved => {
4245 self.on_buffer_saved(buffer, cx);
4246 }
4247
4248 _ => {}
4249 }
4250 }
4251
4252 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4253 buffer
4254 .read(cx)
4255 .set_language_registry(self.languages.clone());
4256
4257 cx.subscribe(buffer, |this, buffer, event, cx| {
4258 this.on_buffer_event(buffer, event, cx);
4259 })
4260 .detach();
4261
4262 self.detect_language_for_buffer(buffer, cx);
4263 if let Some(local) = self.as_local_mut() {
4264 local.initialize_buffer(buffer, cx);
4265 }
4266
4267 Ok(())
4268 }
4269
4270 pub(crate) fn register_buffer_with_language_servers(
4271 &mut self,
4272 buffer: &Entity<Buffer>,
4273 only_register_servers: HashSet<LanguageServerSelector>,
4274 ignore_refcounts: bool,
4275 cx: &mut Context<Self>,
4276 ) -> OpenLspBufferHandle {
4277 let buffer_id = buffer.read(cx).remote_id();
4278 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4279 if let Some(local) = self.as_local_mut() {
4280 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4281 if !ignore_refcounts {
4282 *refcount += 1;
4283 }
4284
4285 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4286 // 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
4287 // 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
4288 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4289 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4290 return handle;
4291 };
4292 if !file.is_local() {
4293 return handle;
4294 }
4295
4296 if ignore_refcounts || *refcount == 1 {
4297 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4298 }
4299 if !ignore_refcounts {
4300 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4301 let refcount = {
4302 let local = lsp_store.as_local_mut().unwrap();
4303 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4304 debug_panic!("bad refcounting");
4305 return;
4306 };
4307
4308 *refcount -= 1;
4309 *refcount
4310 };
4311 if refcount == 0 {
4312 lsp_store.lsp_data.remove(&buffer_id);
4313 let local = lsp_store.as_local_mut().unwrap();
4314 local.registered_buffers.remove(&buffer_id);
4315
4316 local.buffers_opened_in_servers.remove(&buffer_id);
4317 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4318 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4319
4320 let buffer_abs_path = file.abs_path(cx);
4321 for (_, buffer_pull_diagnostics_result_ids) in
4322 &mut local.buffer_pull_diagnostics_result_ids
4323 {
4324 buffer_pull_diagnostics_result_ids.retain(
4325 |_, buffer_result_ids| {
4326 buffer_result_ids.remove(&buffer_abs_path);
4327 !buffer_result_ids.is_empty()
4328 },
4329 );
4330 }
4331
4332 let diagnostic_updates = local
4333 .language_servers
4334 .keys()
4335 .cloned()
4336 .map(|server_id| DocumentDiagnosticsUpdate {
4337 diagnostics: DocumentDiagnostics {
4338 document_abs_path: buffer_abs_path.clone(),
4339 version: None,
4340 diagnostics: Vec::new(),
4341 },
4342 result_id: None,
4343 registration_id: None,
4344 server_id: server_id,
4345 disk_based_sources: Cow::Borrowed(&[]),
4346 })
4347 .collect::<Vec<_>>();
4348
4349 lsp_store
4350 .merge_diagnostic_entries(
4351 diagnostic_updates,
4352 |_, diagnostic, _| {
4353 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4354 },
4355 cx,
4356 )
4357 .context("Clearing diagnostics for the closed buffer")
4358 .log_err();
4359 }
4360 }
4361 })
4362 .detach();
4363 }
4364 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4365 let buffer_id = buffer.read(cx).remote_id().to_proto();
4366 cx.background_spawn(async move {
4367 upstream_client
4368 .request(proto::RegisterBufferWithLanguageServers {
4369 project_id: upstream_project_id,
4370 buffer_id,
4371 only_servers: only_register_servers
4372 .into_iter()
4373 .map(|selector| {
4374 let selector = match selector {
4375 LanguageServerSelector::Id(language_server_id) => {
4376 proto::language_server_selector::Selector::ServerId(
4377 language_server_id.to_proto(),
4378 )
4379 }
4380 LanguageServerSelector::Name(language_server_name) => {
4381 proto::language_server_selector::Selector::Name(
4382 language_server_name.to_string(),
4383 )
4384 }
4385 };
4386 proto::LanguageServerSelector {
4387 selector: Some(selector),
4388 }
4389 })
4390 .collect(),
4391 })
4392 .await
4393 })
4394 .detach();
4395 } else {
4396 // Our remote connection got closed
4397 }
4398 handle
4399 }
4400
4401 fn maintain_buffer_languages(
4402 languages: Arc<LanguageRegistry>,
4403 cx: &mut Context<Self>,
4404 ) -> Task<()> {
4405 let mut subscription = languages.subscribe();
4406 let mut prev_reload_count = languages.reload_count();
4407 cx.spawn(async move |this, cx| {
4408 while let Some(()) = subscription.next().await {
4409 if let Some(this) = this.upgrade() {
4410 // If the language registry has been reloaded, then remove and
4411 // re-assign the languages on all open buffers.
4412 let reload_count = languages.reload_count();
4413 if reload_count > prev_reload_count {
4414 prev_reload_count = reload_count;
4415 this.update(cx, |this, cx| {
4416 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4417 for buffer in buffer_store.buffers() {
4418 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4419 {
4420 buffer.update(cx, |buffer, cx| {
4421 buffer.set_language_async(None, cx)
4422 });
4423 if let Some(local) = this.as_local_mut() {
4424 local.reset_buffer(&buffer, &f, cx);
4425
4426 if local
4427 .registered_buffers
4428 .contains_key(&buffer.read(cx).remote_id())
4429 && let Some(file_url) =
4430 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4431 {
4432 local.unregister_buffer_from_language_servers(
4433 &buffer, &file_url, cx,
4434 );
4435 }
4436 }
4437 }
4438 }
4439 });
4440 })
4441 .ok();
4442 }
4443
4444 this.update(cx, |this, cx| {
4445 let mut plain_text_buffers = Vec::new();
4446 let mut buffers_with_unknown_injections = Vec::new();
4447 for handle in this.buffer_store.read(cx).buffers() {
4448 let buffer = handle.read(cx);
4449 if buffer.language().is_none()
4450 || buffer.language() == Some(&*language::PLAIN_TEXT)
4451 {
4452 plain_text_buffers.push(handle);
4453 } else if buffer.contains_unknown_injections() {
4454 buffers_with_unknown_injections.push(handle);
4455 }
4456 }
4457
4458 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4459 // and reused later in the invisible worktrees.
4460 plain_text_buffers.sort_by_key(|buffer| {
4461 Reverse(
4462 File::from_dyn(buffer.read(cx).file())
4463 .map(|file| file.worktree.read(cx).is_visible()),
4464 )
4465 });
4466
4467 for buffer in plain_text_buffers {
4468 this.detect_language_for_buffer(&buffer, cx);
4469 if let Some(local) = this.as_local_mut() {
4470 local.initialize_buffer(&buffer, cx);
4471 if local
4472 .registered_buffers
4473 .contains_key(&buffer.read(cx).remote_id())
4474 {
4475 local.register_buffer_with_language_servers(
4476 &buffer,
4477 HashSet::default(),
4478 cx,
4479 );
4480 }
4481 }
4482 }
4483
4484 for buffer in buffers_with_unknown_injections {
4485 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4486 }
4487 })
4488 .ok();
4489 }
4490 }
4491 })
4492 }
4493
4494 fn detect_language_for_buffer(
4495 &mut self,
4496 buffer_handle: &Entity<Buffer>,
4497 cx: &mut Context<Self>,
4498 ) -> Option<language::AvailableLanguage> {
4499 // If the buffer has a language, set it and start the language server if we haven't already.
4500 let buffer = buffer_handle.read(cx);
4501 let file = buffer.file()?;
4502
4503 let content = buffer.as_rope();
4504 let available_language = self.languages.language_for_file(file, Some(content), cx);
4505 if let Some(available_language) = &available_language {
4506 if let Some(Ok(Ok(new_language))) = self
4507 .languages
4508 .load_language(available_language)
4509 .now_or_never()
4510 {
4511 self.set_language_for_buffer(buffer_handle, new_language, cx);
4512 }
4513 } else {
4514 cx.emit(LspStoreEvent::LanguageDetected {
4515 buffer: buffer_handle.clone(),
4516 new_language: None,
4517 });
4518 }
4519
4520 available_language
4521 }
4522
4523 pub(crate) fn set_language_for_buffer(
4524 &mut self,
4525 buffer_entity: &Entity<Buffer>,
4526 new_language: Arc<Language>,
4527 cx: &mut Context<Self>,
4528 ) {
4529 let buffer = buffer_entity.read(cx);
4530 let buffer_file = buffer.file().cloned();
4531 let buffer_id = buffer.remote_id();
4532 if let Some(local_store) = self.as_local_mut()
4533 && local_store.registered_buffers.contains_key(&buffer_id)
4534 && let Some(abs_path) =
4535 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4536 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4537 {
4538 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4539 }
4540 buffer_entity.update(cx, |buffer, cx| {
4541 if buffer
4542 .language()
4543 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4544 {
4545 buffer.set_language_async(Some(new_language.clone()), cx);
4546 }
4547 });
4548
4549 let settings =
4550 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4551 let buffer_file = File::from_dyn(buffer_file.as_ref());
4552
4553 let worktree_id = if let Some(file) = buffer_file {
4554 let worktree = file.worktree.clone();
4555
4556 if let Some(local) = self.as_local_mut()
4557 && local.registered_buffers.contains_key(&buffer_id)
4558 {
4559 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4560 }
4561 Some(worktree.read(cx).id())
4562 } else {
4563 None
4564 };
4565
4566 if settings.prettier.allowed
4567 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4568 {
4569 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4570 if let Some(prettier_store) = prettier_store {
4571 prettier_store.update(cx, |prettier_store, cx| {
4572 prettier_store.install_default_prettier(
4573 worktree_id,
4574 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4575 cx,
4576 )
4577 })
4578 }
4579 }
4580
4581 cx.emit(LspStoreEvent::LanguageDetected {
4582 buffer: buffer_entity.clone(),
4583 new_language: Some(new_language),
4584 })
4585 }
4586
4587 pub fn buffer_store(&self) -> Entity<BufferStore> {
4588 self.buffer_store.clone()
4589 }
4590
4591 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4592 self.active_entry = active_entry;
4593 }
4594
4595 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4596 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4597 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4598 {
4599 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4600 summaries
4601 .iter()
4602 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4603 });
4604 if let Some(summary) = summaries.next() {
4605 client
4606 .send(proto::UpdateDiagnosticSummary {
4607 project_id: downstream_project_id,
4608 worktree_id: worktree.id().to_proto(),
4609 summary: Some(summary),
4610 more_summaries: summaries.collect(),
4611 })
4612 .log_err();
4613 }
4614 }
4615 }
4616
4617 fn is_capable_for_proto_request<R>(
4618 &self,
4619 buffer: &Entity<Buffer>,
4620 request: &R,
4621 cx: &App,
4622 ) -> bool
4623 where
4624 R: LspCommand,
4625 {
4626 self.check_if_capable_for_proto_request(
4627 buffer,
4628 |capabilities| {
4629 request.check_capabilities(AdapterServerCapabilities {
4630 server_capabilities: capabilities.clone(),
4631 code_action_kinds: None,
4632 })
4633 },
4634 cx,
4635 )
4636 }
4637
4638 fn check_if_capable_for_proto_request<F>(
4639 &self,
4640 buffer: &Entity<Buffer>,
4641 check: F,
4642 cx: &App,
4643 ) -> bool
4644 where
4645 F: FnMut(&lsp::ServerCapabilities) -> bool,
4646 {
4647 let Some(language) = buffer.read(cx).language().cloned() else {
4648 return false;
4649 };
4650 let relevant_language_servers = self
4651 .languages
4652 .lsp_adapters(&language.name())
4653 .into_iter()
4654 .map(|lsp_adapter| lsp_adapter.name())
4655 .collect::<HashSet<_>>();
4656 self.language_server_statuses
4657 .iter()
4658 .filter_map(|(server_id, server_status)| {
4659 relevant_language_servers
4660 .contains(&server_status.name)
4661 .then_some(server_id)
4662 })
4663 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4664 .any(check)
4665 }
4666
4667 fn all_capable_for_proto_request<F>(
4668 &self,
4669 buffer: &Entity<Buffer>,
4670 mut check: F,
4671 cx: &App,
4672 ) -> Vec<lsp::LanguageServerId>
4673 where
4674 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4675 {
4676 let Some(language) = buffer.read(cx).language().cloned() else {
4677 return Vec::default();
4678 };
4679 let relevant_language_servers = self
4680 .languages
4681 .lsp_adapters(&language.name())
4682 .into_iter()
4683 .map(|lsp_adapter| lsp_adapter.name())
4684 .collect::<HashSet<_>>();
4685 self.language_server_statuses
4686 .iter()
4687 .filter_map(|(server_id, server_status)| {
4688 relevant_language_servers
4689 .contains(&server_status.name)
4690 .then_some((server_id, &server_status.name))
4691 })
4692 .filter_map(|(server_id, server_name)| {
4693 self.lsp_server_capabilities
4694 .get(server_id)
4695 .map(|c| (server_id, server_name, c))
4696 })
4697 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4698 .map(|(server_id, _, _)| *server_id)
4699 .collect()
4700 }
4701
4702 pub fn request_lsp<R>(
4703 &mut self,
4704 buffer: Entity<Buffer>,
4705 server: LanguageServerToQuery,
4706 request: R,
4707 cx: &mut Context<Self>,
4708 ) -> Task<Result<R::Response>>
4709 where
4710 R: LspCommand,
4711 <R::LspRequest as lsp::request::Request>::Result: Send,
4712 <R::LspRequest as lsp::request::Request>::Params: Send,
4713 {
4714 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4715 return self.send_lsp_proto_request(
4716 buffer,
4717 upstream_client,
4718 upstream_project_id,
4719 request,
4720 cx,
4721 );
4722 }
4723
4724 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4725 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4726 local
4727 .language_servers_for_buffer(buffer, cx)
4728 .find(|(_, server)| {
4729 request.check_capabilities(server.adapter_server_capabilities())
4730 })
4731 .map(|(_, server)| server.clone())
4732 }),
4733 LanguageServerToQuery::Other(id) => self
4734 .language_server_for_local_buffer(buffer, id, cx)
4735 .and_then(|(_, server)| {
4736 request
4737 .check_capabilities(server.adapter_server_capabilities())
4738 .then(|| Arc::clone(server))
4739 }),
4740 }) else {
4741 return Task::ready(Ok(Default::default()));
4742 };
4743
4744 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4745
4746 let Some(file) = file else {
4747 return Task::ready(Ok(Default::default()));
4748 };
4749
4750 let lsp_params = match request.to_lsp_params_or_response(
4751 &file.abs_path(cx),
4752 buffer.read(cx),
4753 &language_server,
4754 cx,
4755 ) {
4756 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4757 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4758 Err(err) => {
4759 let message = format!(
4760 "{} via {} failed: {}",
4761 request.display_name(),
4762 language_server.name(),
4763 err
4764 );
4765 // rust-analyzer likes to error with this when its still loading up
4766 if !message.ends_with("content modified") {
4767 log::warn!("{message}");
4768 }
4769 return Task::ready(Err(anyhow!(message)));
4770 }
4771 };
4772
4773 let status = request.status();
4774 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4775 return Task::ready(Ok(Default::default()));
4776 }
4777 cx.spawn(async move |this, cx| {
4778 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4779
4780 let id = lsp_request.id();
4781 let _cleanup = if status.is_some() {
4782 cx.update(|cx| {
4783 this.update(cx, |this, cx| {
4784 this.on_lsp_work_start(
4785 language_server.server_id(),
4786 ProgressToken::Number(id),
4787 LanguageServerProgress {
4788 is_disk_based_diagnostics_progress: false,
4789 is_cancellable: false,
4790 title: None,
4791 message: status.clone(),
4792 percentage: None,
4793 last_update_at: cx.background_executor().now(),
4794 },
4795 cx,
4796 );
4797 })
4798 })
4799 .log_err();
4800
4801 Some(defer(|| {
4802 cx.update(|cx| {
4803 this.update(cx, |this, cx| {
4804 this.on_lsp_work_end(
4805 language_server.server_id(),
4806 ProgressToken::Number(id),
4807 cx,
4808 );
4809 })
4810 })
4811 .log_err();
4812 }))
4813 } else {
4814 None
4815 };
4816
4817 let result = lsp_request.await.into_response();
4818
4819 let response = result.map_err(|err| {
4820 let message = format!(
4821 "{} via {} failed: {}",
4822 request.display_name(),
4823 language_server.name(),
4824 err
4825 );
4826 // rust-analyzer likes to error with this when its still loading up
4827 if !message.ends_with("content modified") {
4828 log::warn!("{message}");
4829 }
4830 anyhow::anyhow!(message)
4831 })?;
4832
4833 request
4834 .response_from_lsp(
4835 response,
4836 this.upgrade().context("no app context")?,
4837 buffer,
4838 language_server.server_id(),
4839 cx.clone(),
4840 )
4841 .await
4842 })
4843 }
4844
4845 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4846 let mut language_formatters_to_check = Vec::new();
4847 for buffer in self.buffer_store.read(cx).buffers() {
4848 let buffer = buffer.read(cx);
4849 let buffer_file = File::from_dyn(buffer.file());
4850 let buffer_language = buffer.language();
4851 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4852 if buffer_language.is_some() {
4853 language_formatters_to_check.push((
4854 buffer_file.map(|f| f.worktree_id(cx)),
4855 settings.into_owned(),
4856 ));
4857 }
4858 }
4859
4860 self.request_workspace_config_refresh();
4861
4862 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4863 prettier_store.update(cx, |prettier_store, cx| {
4864 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4865 })
4866 }
4867
4868 cx.notify();
4869 }
4870
4871 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4872 let buffer_store = self.buffer_store.clone();
4873 let Some(local) = self.as_local_mut() else {
4874 return;
4875 };
4876 let mut adapters = BTreeMap::default();
4877 let get_adapter = {
4878 let languages = local.languages.clone();
4879 let environment = local.environment.clone();
4880 let weak = local.weak.clone();
4881 let worktree_store = local.worktree_store.clone();
4882 let http_client = local.http_client.clone();
4883 let fs = local.fs.clone();
4884 move |worktree_id, cx: &mut App| {
4885 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4886 Some(LocalLspAdapterDelegate::new(
4887 languages.clone(),
4888 &environment,
4889 weak.clone(),
4890 &worktree,
4891 http_client.clone(),
4892 fs.clone(),
4893 cx,
4894 ))
4895 }
4896 };
4897
4898 let mut messages_to_report = Vec::new();
4899 let (new_tree, to_stop) = {
4900 let mut rebase = local.lsp_tree.rebase();
4901 let buffers = buffer_store
4902 .read(cx)
4903 .buffers()
4904 .filter_map(|buffer| {
4905 let raw_buffer = buffer.read(cx);
4906 if !local
4907 .registered_buffers
4908 .contains_key(&raw_buffer.remote_id())
4909 {
4910 return None;
4911 }
4912 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4913 let language = raw_buffer.language().cloned()?;
4914 Some((file, language, raw_buffer.remote_id()))
4915 })
4916 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4917 for (file, language, buffer_id) in buffers {
4918 let worktree_id = file.worktree_id(cx);
4919 let Some(worktree) = local
4920 .worktree_store
4921 .read(cx)
4922 .worktree_for_id(worktree_id, cx)
4923 else {
4924 continue;
4925 };
4926
4927 if let Some((_, apply)) = local.reuse_existing_language_server(
4928 rebase.server_tree(),
4929 &worktree,
4930 &language.name(),
4931 cx,
4932 ) {
4933 (apply)(rebase.server_tree());
4934 } else if let Some(lsp_delegate) = adapters
4935 .entry(worktree_id)
4936 .or_insert_with(|| get_adapter(worktree_id, cx))
4937 .clone()
4938 {
4939 let delegate =
4940 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4941 let path = file
4942 .path()
4943 .parent()
4944 .map(Arc::from)
4945 .unwrap_or_else(|| file.path().clone());
4946 let worktree_path = ProjectPath { worktree_id, path };
4947 let abs_path = file.abs_path(cx);
4948 let nodes = rebase
4949 .walk(
4950 worktree_path,
4951 language.name(),
4952 language.manifest(),
4953 delegate.clone(),
4954 cx,
4955 )
4956 .collect::<Vec<_>>();
4957 for node in nodes {
4958 let server_id = node.server_id_or_init(|disposition| {
4959 let path = &disposition.path;
4960 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4961 let key = LanguageServerSeed {
4962 worktree_id,
4963 name: disposition.server_name.clone(),
4964 settings: disposition.settings.clone(),
4965 toolchain: local.toolchain_store.read(cx).active_toolchain(
4966 path.worktree_id,
4967 &path.path,
4968 language.name(),
4969 ),
4970 };
4971 local.language_server_ids.remove(&key);
4972
4973 let server_id = local.get_or_insert_language_server(
4974 &worktree,
4975 lsp_delegate.clone(),
4976 disposition,
4977 &language.name(),
4978 cx,
4979 );
4980 if let Some(state) = local.language_servers.get(&server_id)
4981 && let Ok(uri) = uri
4982 {
4983 state.add_workspace_folder(uri);
4984 };
4985 server_id
4986 });
4987
4988 if let Some(language_server_id) = server_id {
4989 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4990 language_server_id,
4991 name: node.name(),
4992 message:
4993 proto::update_language_server::Variant::RegisteredForBuffer(
4994 proto::RegisteredForBuffer {
4995 buffer_abs_path: abs_path
4996 .to_string_lossy()
4997 .into_owned(),
4998 buffer_id: buffer_id.to_proto(),
4999 },
5000 ),
5001 });
5002 }
5003 }
5004 } else {
5005 continue;
5006 }
5007 }
5008 rebase.finish()
5009 };
5010 for message in messages_to_report {
5011 cx.emit(message);
5012 }
5013 local.lsp_tree = new_tree;
5014 for (id, _) in to_stop {
5015 self.stop_local_language_server(id, cx).detach();
5016 }
5017 }
5018
5019 pub fn apply_code_action(
5020 &self,
5021 buffer_handle: Entity<Buffer>,
5022 mut action: CodeAction,
5023 push_to_history: bool,
5024 cx: &mut Context<Self>,
5025 ) -> Task<Result<ProjectTransaction>> {
5026 if let Some((upstream_client, project_id)) = self.upstream_client() {
5027 let request = proto::ApplyCodeAction {
5028 project_id,
5029 buffer_id: buffer_handle.read(cx).remote_id().into(),
5030 action: Some(Self::serialize_code_action(&action)),
5031 };
5032 let buffer_store = self.buffer_store();
5033 cx.spawn(async move |_, cx| {
5034 let response = upstream_client
5035 .request(request)
5036 .await?
5037 .transaction
5038 .context("missing transaction")?;
5039
5040 buffer_store
5041 .update(cx, |buffer_store, cx| {
5042 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5043 })?
5044 .await
5045 })
5046 } else if self.mode.is_local() {
5047 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5048 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5049 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5050 }) else {
5051 return Task::ready(Ok(ProjectTransaction::default()));
5052 };
5053 cx.spawn(async move |this, cx| {
5054 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5055 .await
5056 .context("resolving a code action")?;
5057 if let Some(edit) = action.lsp_action.edit()
5058 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5059 return LocalLspStore::deserialize_workspace_edit(
5060 this.upgrade().context("no app present")?,
5061 edit.clone(),
5062 push_to_history,
5063
5064 lang_server.clone(),
5065 cx,
5066 )
5067 .await;
5068 }
5069
5070 if let Some(command) = action.lsp_action.command() {
5071 let server_capabilities = lang_server.capabilities();
5072 let available_commands = server_capabilities
5073 .execute_command_provider
5074 .as_ref()
5075 .map(|options| options.commands.as_slice())
5076 .unwrap_or_default();
5077 if available_commands.contains(&command.command) {
5078 this.update(cx, |this, _| {
5079 this.as_local_mut()
5080 .unwrap()
5081 .last_workspace_edits_by_language_server
5082 .remove(&lang_server.server_id());
5083 })?;
5084
5085 let _result = lang_server
5086 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5087 command: command.command.clone(),
5088 arguments: command.arguments.clone().unwrap_or_default(),
5089 ..lsp::ExecuteCommandParams::default()
5090 })
5091 .await.into_response()
5092 .context("execute command")?;
5093
5094 return this.update(cx, |this, _| {
5095 this.as_local_mut()
5096 .unwrap()
5097 .last_workspace_edits_by_language_server
5098 .remove(&lang_server.server_id())
5099 .unwrap_or_default()
5100 });
5101 } else {
5102 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5103 }
5104 }
5105
5106 Ok(ProjectTransaction::default())
5107 })
5108 } else {
5109 Task::ready(Err(anyhow!("no upstream client and not local")))
5110 }
5111 }
5112
5113 pub fn apply_code_action_kind(
5114 &mut self,
5115 buffers: HashSet<Entity<Buffer>>,
5116 kind: CodeActionKind,
5117 push_to_history: bool,
5118 cx: &mut Context<Self>,
5119 ) -> Task<anyhow::Result<ProjectTransaction>> {
5120 if self.as_local().is_some() {
5121 cx.spawn(async move |lsp_store, cx| {
5122 let buffers = buffers.into_iter().collect::<Vec<_>>();
5123 let result = LocalLspStore::execute_code_action_kind_locally(
5124 lsp_store.clone(),
5125 buffers,
5126 kind,
5127 push_to_history,
5128 cx,
5129 )
5130 .await;
5131 lsp_store.update(cx, |lsp_store, _| {
5132 lsp_store.update_last_formatting_failure(&result);
5133 })?;
5134 result
5135 })
5136 } else if let Some((client, project_id)) = self.upstream_client() {
5137 let buffer_store = self.buffer_store();
5138 cx.spawn(async move |lsp_store, cx| {
5139 let result = client
5140 .request(proto::ApplyCodeActionKind {
5141 project_id,
5142 kind: kind.as_str().to_owned(),
5143 buffer_ids: buffers
5144 .iter()
5145 .map(|buffer| {
5146 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5147 })
5148 .collect::<Result<_>>()?,
5149 })
5150 .await
5151 .and_then(|result| result.transaction.context("missing transaction"));
5152 lsp_store.update(cx, |lsp_store, _| {
5153 lsp_store.update_last_formatting_failure(&result);
5154 })?;
5155
5156 let transaction_response = result?;
5157 buffer_store
5158 .update(cx, |buffer_store, cx| {
5159 buffer_store.deserialize_project_transaction(
5160 transaction_response,
5161 push_to_history,
5162 cx,
5163 )
5164 })?
5165 .await
5166 })
5167 } else {
5168 Task::ready(Ok(ProjectTransaction::default()))
5169 }
5170 }
5171
5172 pub fn resolved_hint(
5173 &mut self,
5174 buffer_id: BufferId,
5175 id: InlayId,
5176 cx: &mut Context<Self>,
5177 ) -> Option<ResolvedHint> {
5178 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5179
5180 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5181 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5182 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5183 let (server_id, resolve_data) = match &hint.resolve_state {
5184 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5185 ResolveState::Resolving => {
5186 return Some(ResolvedHint::Resolving(
5187 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5188 ));
5189 }
5190 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5191 };
5192
5193 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5194 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5195 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5196 id,
5197 cx.spawn(async move |lsp_store, cx| {
5198 let resolved_hint = resolve_task.await;
5199 lsp_store
5200 .update(cx, |lsp_store, _| {
5201 if let Some(old_inlay_hint) = lsp_store
5202 .lsp_data
5203 .get_mut(&buffer_id)
5204 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5205 {
5206 match resolved_hint {
5207 Ok(resolved_hint) => {
5208 *old_inlay_hint = resolved_hint;
5209 }
5210 Err(e) => {
5211 old_inlay_hint.resolve_state =
5212 ResolveState::CanResolve(server_id, resolve_data);
5213 log::error!("Inlay hint resolve failed: {e:#}");
5214 }
5215 }
5216 }
5217 })
5218 .ok();
5219 })
5220 .shared(),
5221 );
5222 debug_assert!(
5223 previous_task.is_none(),
5224 "Did not change hint's resolve state after spawning its resolve"
5225 );
5226 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5227 None
5228 }
5229
5230 fn resolve_inlay_hint(
5231 &self,
5232 mut hint: InlayHint,
5233 buffer: Entity<Buffer>,
5234 server_id: LanguageServerId,
5235 cx: &mut Context<Self>,
5236 ) -> Task<anyhow::Result<InlayHint>> {
5237 if let Some((upstream_client, project_id)) = self.upstream_client() {
5238 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5239 {
5240 hint.resolve_state = ResolveState::Resolved;
5241 return Task::ready(Ok(hint));
5242 }
5243 let request = proto::ResolveInlayHint {
5244 project_id,
5245 buffer_id: buffer.read(cx).remote_id().into(),
5246 language_server_id: server_id.0 as u64,
5247 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5248 };
5249 cx.background_spawn(async move {
5250 let response = upstream_client
5251 .request(request)
5252 .await
5253 .context("inlay hints proto request")?;
5254 match response.hint {
5255 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5256 .context("inlay hints proto resolve response conversion"),
5257 None => Ok(hint),
5258 }
5259 })
5260 } else {
5261 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5262 self.language_server_for_local_buffer(buffer, server_id, cx)
5263 .map(|(_, server)| server.clone())
5264 }) else {
5265 return Task::ready(Ok(hint));
5266 };
5267 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5268 return Task::ready(Ok(hint));
5269 }
5270 let buffer_snapshot = buffer.read(cx).snapshot();
5271 cx.spawn(async move |_, cx| {
5272 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5273 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5274 );
5275 let resolved_hint = resolve_task
5276 .await
5277 .into_response()
5278 .context("inlay hint resolve LSP request")?;
5279 let resolved_hint = InlayHints::lsp_to_project_hint(
5280 resolved_hint,
5281 &buffer,
5282 server_id,
5283 ResolveState::Resolved,
5284 false,
5285 cx,
5286 )
5287 .await?;
5288 Ok(resolved_hint)
5289 })
5290 }
5291 }
5292
5293 pub fn resolve_color_presentation(
5294 &mut self,
5295 mut color: DocumentColor,
5296 buffer: Entity<Buffer>,
5297 server_id: LanguageServerId,
5298 cx: &mut Context<Self>,
5299 ) -> Task<Result<DocumentColor>> {
5300 if color.resolved {
5301 return Task::ready(Ok(color));
5302 }
5303
5304 if let Some((upstream_client, project_id)) = self.upstream_client() {
5305 let start = color.lsp_range.start;
5306 let end = color.lsp_range.end;
5307 let request = proto::GetColorPresentation {
5308 project_id,
5309 server_id: server_id.to_proto(),
5310 buffer_id: buffer.read(cx).remote_id().into(),
5311 color: Some(proto::ColorInformation {
5312 red: color.color.red,
5313 green: color.color.green,
5314 blue: color.color.blue,
5315 alpha: color.color.alpha,
5316 lsp_range_start: Some(proto::PointUtf16 {
5317 row: start.line,
5318 column: start.character,
5319 }),
5320 lsp_range_end: Some(proto::PointUtf16 {
5321 row: end.line,
5322 column: end.character,
5323 }),
5324 }),
5325 };
5326 cx.background_spawn(async move {
5327 let response = upstream_client
5328 .request(request)
5329 .await
5330 .context("color presentation proto request")?;
5331 color.resolved = true;
5332 color.color_presentations = response
5333 .presentations
5334 .into_iter()
5335 .map(|presentation| ColorPresentation {
5336 label: SharedString::from(presentation.label),
5337 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5338 additional_text_edits: presentation
5339 .additional_text_edits
5340 .into_iter()
5341 .filter_map(deserialize_lsp_edit)
5342 .collect(),
5343 })
5344 .collect();
5345 Ok(color)
5346 })
5347 } else {
5348 let path = match buffer
5349 .update(cx, |buffer, cx| {
5350 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5351 })
5352 .context("buffer with the missing path")
5353 {
5354 Ok(path) => path,
5355 Err(e) => return Task::ready(Err(e)),
5356 };
5357 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5358 self.language_server_for_local_buffer(buffer, server_id, cx)
5359 .map(|(_, server)| server.clone())
5360 }) else {
5361 return Task::ready(Ok(color));
5362 };
5363 cx.background_spawn(async move {
5364 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5365 lsp::ColorPresentationParams {
5366 text_document: make_text_document_identifier(&path)?,
5367 color: color.color,
5368 range: color.lsp_range,
5369 work_done_progress_params: Default::default(),
5370 partial_result_params: Default::default(),
5371 },
5372 );
5373 color.color_presentations = resolve_task
5374 .await
5375 .into_response()
5376 .context("color presentation resolve LSP request")?
5377 .into_iter()
5378 .map(|presentation| ColorPresentation {
5379 label: SharedString::from(presentation.label),
5380 text_edit: presentation.text_edit,
5381 additional_text_edits: presentation
5382 .additional_text_edits
5383 .unwrap_or_default(),
5384 })
5385 .collect();
5386 color.resolved = true;
5387 Ok(color)
5388 })
5389 }
5390 }
5391
5392 pub(crate) fn linked_edits(
5393 &mut self,
5394 buffer: &Entity<Buffer>,
5395 position: Anchor,
5396 cx: &mut Context<Self>,
5397 ) -> Task<Result<Vec<Range<Anchor>>>> {
5398 let snapshot = buffer.read(cx).snapshot();
5399 let scope = snapshot.language_scope_at(position);
5400 let Some(server_id) = self
5401 .as_local()
5402 .and_then(|local| {
5403 buffer.update(cx, |buffer, cx| {
5404 local
5405 .language_servers_for_buffer(buffer, cx)
5406 .filter(|(_, server)| {
5407 LinkedEditingRange::check_server_capabilities(server.capabilities())
5408 })
5409 .filter(|(adapter, _)| {
5410 scope
5411 .as_ref()
5412 .map(|scope| scope.language_allowed(&adapter.name))
5413 .unwrap_or(true)
5414 })
5415 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5416 .next()
5417 })
5418 })
5419 .or_else(|| {
5420 self.upstream_client()
5421 .is_some()
5422 .then_some(LanguageServerToQuery::FirstCapable)
5423 })
5424 .filter(|_| {
5425 maybe!({
5426 let language = buffer.read(cx).language_at(position)?;
5427 Some(
5428 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5429 .linked_edits,
5430 )
5431 }) == Some(true)
5432 })
5433 else {
5434 return Task::ready(Ok(Vec::new()));
5435 };
5436
5437 self.request_lsp(
5438 buffer.clone(),
5439 server_id,
5440 LinkedEditingRange { position },
5441 cx,
5442 )
5443 }
5444
5445 fn apply_on_type_formatting(
5446 &mut self,
5447 buffer: Entity<Buffer>,
5448 position: Anchor,
5449 trigger: String,
5450 cx: &mut Context<Self>,
5451 ) -> Task<Result<Option<Transaction>>> {
5452 if let Some((client, project_id)) = self.upstream_client() {
5453 if !self.check_if_capable_for_proto_request(
5454 &buffer,
5455 |capabilities| {
5456 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5457 },
5458 cx,
5459 ) {
5460 return Task::ready(Ok(None));
5461 }
5462 let request = proto::OnTypeFormatting {
5463 project_id,
5464 buffer_id: buffer.read(cx).remote_id().into(),
5465 position: Some(serialize_anchor(&position)),
5466 trigger,
5467 version: serialize_version(&buffer.read(cx).version()),
5468 };
5469 cx.background_spawn(async move {
5470 client
5471 .request(request)
5472 .await?
5473 .transaction
5474 .map(language::proto::deserialize_transaction)
5475 .transpose()
5476 })
5477 } else if let Some(local) = self.as_local_mut() {
5478 let buffer_id = buffer.read(cx).remote_id();
5479 local.buffers_being_formatted.insert(buffer_id);
5480 cx.spawn(async move |this, cx| {
5481 let _cleanup = defer({
5482 let this = this.clone();
5483 let mut cx = cx.clone();
5484 move || {
5485 this.update(&mut cx, |this, _| {
5486 if let Some(local) = this.as_local_mut() {
5487 local.buffers_being_formatted.remove(&buffer_id);
5488 }
5489 })
5490 .ok();
5491 }
5492 });
5493
5494 buffer
5495 .update(cx, |buffer, _| {
5496 buffer.wait_for_edits(Some(position.timestamp))
5497 })?
5498 .await?;
5499 this.update(cx, |this, cx| {
5500 let position = position.to_point_utf16(buffer.read(cx));
5501 this.on_type_format(buffer, position, trigger, false, cx)
5502 })?
5503 .await
5504 })
5505 } else {
5506 Task::ready(Err(anyhow!("No upstream client or local language server")))
5507 }
5508 }
5509
5510 pub fn on_type_format<T: ToPointUtf16>(
5511 &mut self,
5512 buffer: Entity<Buffer>,
5513 position: T,
5514 trigger: String,
5515 push_to_history: bool,
5516 cx: &mut Context<Self>,
5517 ) -> Task<Result<Option<Transaction>>> {
5518 let position = position.to_point_utf16(buffer.read(cx));
5519 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5520 }
5521
5522 fn on_type_format_impl(
5523 &mut self,
5524 buffer: Entity<Buffer>,
5525 position: PointUtf16,
5526 trigger: String,
5527 push_to_history: bool,
5528 cx: &mut Context<Self>,
5529 ) -> Task<Result<Option<Transaction>>> {
5530 let options = buffer.update(cx, |buffer, cx| {
5531 lsp_command::lsp_formatting_options(
5532 language_settings(
5533 buffer.language_at(position).map(|l| l.name()),
5534 buffer.file(),
5535 cx,
5536 )
5537 .as_ref(),
5538 )
5539 });
5540
5541 cx.spawn(async move |this, cx| {
5542 if let Some(waiter) =
5543 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5544 {
5545 waiter.await?;
5546 }
5547 cx.update(|cx| {
5548 this.update(cx, |this, cx| {
5549 this.request_lsp(
5550 buffer.clone(),
5551 LanguageServerToQuery::FirstCapable,
5552 OnTypeFormatting {
5553 position,
5554 trigger,
5555 options,
5556 push_to_history,
5557 },
5558 cx,
5559 )
5560 })
5561 })??
5562 .await
5563 })
5564 }
5565
5566 pub fn definitions(
5567 &mut self,
5568 buffer: &Entity<Buffer>,
5569 position: PointUtf16,
5570 cx: &mut Context<Self>,
5571 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5572 if let Some((upstream_client, project_id)) = self.upstream_client() {
5573 let request = GetDefinitions { position };
5574 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5575 return Task::ready(Ok(None));
5576 }
5577 let request_task = upstream_client.request_lsp(
5578 project_id,
5579 None,
5580 LSP_REQUEST_TIMEOUT,
5581 cx.background_executor().clone(),
5582 request.to_proto(project_id, buffer.read(cx)),
5583 );
5584 let buffer = buffer.clone();
5585 cx.spawn(async move |weak_lsp_store, cx| {
5586 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5587 return Ok(None);
5588 };
5589 let Some(responses) = request_task.await? else {
5590 return Ok(None);
5591 };
5592 let actions = join_all(responses.payload.into_iter().map(|response| {
5593 GetDefinitions { position }.response_from_proto(
5594 response.response,
5595 lsp_store.clone(),
5596 buffer.clone(),
5597 cx.clone(),
5598 )
5599 }))
5600 .await;
5601
5602 Ok(Some(
5603 actions
5604 .into_iter()
5605 .collect::<Result<Vec<Vec<_>>>>()?
5606 .into_iter()
5607 .flatten()
5608 .dedup()
5609 .collect(),
5610 ))
5611 })
5612 } else {
5613 let definitions_task = self.request_multiple_lsp_locally(
5614 buffer,
5615 Some(position),
5616 GetDefinitions { position },
5617 cx,
5618 );
5619 cx.background_spawn(async move {
5620 Ok(Some(
5621 definitions_task
5622 .await
5623 .into_iter()
5624 .flat_map(|(_, definitions)| definitions)
5625 .dedup()
5626 .collect(),
5627 ))
5628 })
5629 }
5630 }
5631
5632 pub fn declarations(
5633 &mut self,
5634 buffer: &Entity<Buffer>,
5635 position: PointUtf16,
5636 cx: &mut Context<Self>,
5637 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5638 if let Some((upstream_client, project_id)) = self.upstream_client() {
5639 let request = GetDeclarations { position };
5640 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5641 return Task::ready(Ok(None));
5642 }
5643 let request_task = upstream_client.request_lsp(
5644 project_id,
5645 None,
5646 LSP_REQUEST_TIMEOUT,
5647 cx.background_executor().clone(),
5648 request.to_proto(project_id, buffer.read(cx)),
5649 );
5650 let buffer = buffer.clone();
5651 cx.spawn(async move |weak_lsp_store, cx| {
5652 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5653 return Ok(None);
5654 };
5655 let Some(responses) = request_task.await? else {
5656 return Ok(None);
5657 };
5658 let actions = join_all(responses.payload.into_iter().map(|response| {
5659 GetDeclarations { position }.response_from_proto(
5660 response.response,
5661 lsp_store.clone(),
5662 buffer.clone(),
5663 cx.clone(),
5664 )
5665 }))
5666 .await;
5667
5668 Ok(Some(
5669 actions
5670 .into_iter()
5671 .collect::<Result<Vec<Vec<_>>>>()?
5672 .into_iter()
5673 .flatten()
5674 .dedup()
5675 .collect(),
5676 ))
5677 })
5678 } else {
5679 let declarations_task = self.request_multiple_lsp_locally(
5680 buffer,
5681 Some(position),
5682 GetDeclarations { position },
5683 cx,
5684 );
5685 cx.background_spawn(async move {
5686 Ok(Some(
5687 declarations_task
5688 .await
5689 .into_iter()
5690 .flat_map(|(_, declarations)| declarations)
5691 .dedup()
5692 .collect(),
5693 ))
5694 })
5695 }
5696 }
5697
5698 pub fn type_definitions(
5699 &mut self,
5700 buffer: &Entity<Buffer>,
5701 position: PointUtf16,
5702 cx: &mut Context<Self>,
5703 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5704 if let Some((upstream_client, project_id)) = self.upstream_client() {
5705 let request = GetTypeDefinitions { position };
5706 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5707 return Task::ready(Ok(None));
5708 }
5709 let request_task = upstream_client.request_lsp(
5710 project_id,
5711 None,
5712 LSP_REQUEST_TIMEOUT,
5713 cx.background_executor().clone(),
5714 request.to_proto(project_id, buffer.read(cx)),
5715 );
5716 let buffer = buffer.clone();
5717 cx.spawn(async move |weak_lsp_store, cx| {
5718 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5719 return Ok(None);
5720 };
5721 let Some(responses) = request_task.await? else {
5722 return Ok(None);
5723 };
5724 let actions = join_all(responses.payload.into_iter().map(|response| {
5725 GetTypeDefinitions { position }.response_from_proto(
5726 response.response,
5727 lsp_store.clone(),
5728 buffer.clone(),
5729 cx.clone(),
5730 )
5731 }))
5732 .await;
5733
5734 Ok(Some(
5735 actions
5736 .into_iter()
5737 .collect::<Result<Vec<Vec<_>>>>()?
5738 .into_iter()
5739 .flatten()
5740 .dedup()
5741 .collect(),
5742 ))
5743 })
5744 } else {
5745 let type_definitions_task = self.request_multiple_lsp_locally(
5746 buffer,
5747 Some(position),
5748 GetTypeDefinitions { position },
5749 cx,
5750 );
5751 cx.background_spawn(async move {
5752 Ok(Some(
5753 type_definitions_task
5754 .await
5755 .into_iter()
5756 .flat_map(|(_, type_definitions)| type_definitions)
5757 .dedup()
5758 .collect(),
5759 ))
5760 })
5761 }
5762 }
5763
5764 pub fn implementations(
5765 &mut self,
5766 buffer: &Entity<Buffer>,
5767 position: PointUtf16,
5768 cx: &mut Context<Self>,
5769 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5770 if let Some((upstream_client, project_id)) = self.upstream_client() {
5771 let request = GetImplementations { position };
5772 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5773 return Task::ready(Ok(None));
5774 }
5775 let request_task = upstream_client.request_lsp(
5776 project_id,
5777 None,
5778 LSP_REQUEST_TIMEOUT,
5779 cx.background_executor().clone(),
5780 request.to_proto(project_id, buffer.read(cx)),
5781 );
5782 let buffer = buffer.clone();
5783 cx.spawn(async move |weak_lsp_store, cx| {
5784 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5785 return Ok(None);
5786 };
5787 let Some(responses) = request_task.await? else {
5788 return Ok(None);
5789 };
5790 let actions = join_all(responses.payload.into_iter().map(|response| {
5791 GetImplementations { position }.response_from_proto(
5792 response.response,
5793 lsp_store.clone(),
5794 buffer.clone(),
5795 cx.clone(),
5796 )
5797 }))
5798 .await;
5799
5800 Ok(Some(
5801 actions
5802 .into_iter()
5803 .collect::<Result<Vec<Vec<_>>>>()?
5804 .into_iter()
5805 .flatten()
5806 .dedup()
5807 .collect(),
5808 ))
5809 })
5810 } else {
5811 let implementations_task = self.request_multiple_lsp_locally(
5812 buffer,
5813 Some(position),
5814 GetImplementations { position },
5815 cx,
5816 );
5817 cx.background_spawn(async move {
5818 Ok(Some(
5819 implementations_task
5820 .await
5821 .into_iter()
5822 .flat_map(|(_, implementations)| implementations)
5823 .dedup()
5824 .collect(),
5825 ))
5826 })
5827 }
5828 }
5829
5830 pub fn references(
5831 &mut self,
5832 buffer: &Entity<Buffer>,
5833 position: PointUtf16,
5834 cx: &mut Context<Self>,
5835 ) -> Task<Result<Option<Vec<Location>>>> {
5836 if let Some((upstream_client, project_id)) = self.upstream_client() {
5837 let request = GetReferences { position };
5838 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5839 return Task::ready(Ok(None));
5840 }
5841
5842 let request_task = upstream_client.request_lsp(
5843 project_id,
5844 None,
5845 LSP_REQUEST_TIMEOUT,
5846 cx.background_executor().clone(),
5847 request.to_proto(project_id, buffer.read(cx)),
5848 );
5849 let buffer = buffer.clone();
5850 cx.spawn(async move |weak_lsp_store, cx| {
5851 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5852 return Ok(None);
5853 };
5854 let Some(responses) = request_task.await? else {
5855 return Ok(None);
5856 };
5857
5858 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5859 GetReferences { position }.response_from_proto(
5860 lsp_response.response,
5861 lsp_store.clone(),
5862 buffer.clone(),
5863 cx.clone(),
5864 )
5865 }))
5866 .await
5867 .into_iter()
5868 .collect::<Result<Vec<Vec<_>>>>()?
5869 .into_iter()
5870 .flatten()
5871 .dedup()
5872 .collect();
5873 Ok(Some(locations))
5874 })
5875 } else {
5876 let references_task = self.request_multiple_lsp_locally(
5877 buffer,
5878 Some(position),
5879 GetReferences { position },
5880 cx,
5881 );
5882 cx.background_spawn(async move {
5883 Ok(Some(
5884 references_task
5885 .await
5886 .into_iter()
5887 .flat_map(|(_, references)| references)
5888 .dedup()
5889 .collect(),
5890 ))
5891 })
5892 }
5893 }
5894
5895 pub fn code_actions(
5896 &mut self,
5897 buffer: &Entity<Buffer>,
5898 range: Range<Anchor>,
5899 kinds: Option<Vec<CodeActionKind>>,
5900 cx: &mut Context<Self>,
5901 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5902 if let Some((upstream_client, project_id)) = self.upstream_client() {
5903 let request = GetCodeActions {
5904 range: range.clone(),
5905 kinds: kinds.clone(),
5906 };
5907 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5908 return Task::ready(Ok(None));
5909 }
5910 let request_task = upstream_client.request_lsp(
5911 project_id,
5912 None,
5913 LSP_REQUEST_TIMEOUT,
5914 cx.background_executor().clone(),
5915 request.to_proto(project_id, buffer.read(cx)),
5916 );
5917 let buffer = buffer.clone();
5918 cx.spawn(async move |weak_lsp_store, cx| {
5919 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5920 return Ok(None);
5921 };
5922 let Some(responses) = request_task.await? else {
5923 return Ok(None);
5924 };
5925 let actions = join_all(responses.payload.into_iter().map(|response| {
5926 GetCodeActions {
5927 range: range.clone(),
5928 kinds: kinds.clone(),
5929 }
5930 .response_from_proto(
5931 response.response,
5932 lsp_store.clone(),
5933 buffer.clone(),
5934 cx.clone(),
5935 )
5936 }))
5937 .await;
5938
5939 Ok(Some(
5940 actions
5941 .into_iter()
5942 .collect::<Result<Vec<Vec<_>>>>()?
5943 .into_iter()
5944 .flatten()
5945 .collect(),
5946 ))
5947 })
5948 } else {
5949 let all_actions_task = self.request_multiple_lsp_locally(
5950 buffer,
5951 Some(range.start),
5952 GetCodeActions { range, kinds },
5953 cx,
5954 );
5955 cx.background_spawn(async move {
5956 Ok(Some(
5957 all_actions_task
5958 .await
5959 .into_iter()
5960 .flat_map(|(_, actions)| actions)
5961 .collect(),
5962 ))
5963 })
5964 }
5965 }
5966
5967 pub fn code_lens_actions(
5968 &mut self,
5969 buffer: &Entity<Buffer>,
5970 cx: &mut Context<Self>,
5971 ) -> CodeLensTask {
5972 let version_queried_for = buffer.read(cx).version();
5973 let buffer_id = buffer.read(cx).remote_id();
5974 let existing_servers = self.as_local().map(|local| {
5975 local
5976 .buffers_opened_in_servers
5977 .get(&buffer_id)
5978 .cloned()
5979 .unwrap_or_default()
5980 });
5981
5982 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5983 if let Some(cached_lens) = &lsp_data.code_lens {
5984 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5985 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5986 existing_servers != cached_lens.lens.keys().copied().collect()
5987 });
5988 if !has_different_servers {
5989 return Task::ready(Ok(Some(
5990 cached_lens.lens.values().flatten().cloned().collect(),
5991 )))
5992 .shared();
5993 }
5994 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5995 if !version_queried_for.changed_since(updating_for) {
5996 return running_update.clone();
5997 }
5998 }
5999 }
6000 }
6001
6002 let lens_lsp_data = self
6003 .latest_lsp_data(buffer, cx)
6004 .code_lens
6005 .get_or_insert_default();
6006 let buffer = buffer.clone();
6007 let query_version_queried_for = version_queried_for.clone();
6008 let new_task = cx
6009 .spawn(async move |lsp_store, cx| {
6010 cx.background_executor()
6011 .timer(Duration::from_millis(30))
6012 .await;
6013 let fetched_lens = lsp_store
6014 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6015 .map_err(Arc::new)?
6016 .await
6017 .context("fetching code lens")
6018 .map_err(Arc::new);
6019 let fetched_lens = match fetched_lens {
6020 Ok(fetched_lens) => fetched_lens,
6021 Err(e) => {
6022 lsp_store
6023 .update(cx, |lsp_store, _| {
6024 if let Some(lens_lsp_data) = lsp_store
6025 .lsp_data
6026 .get_mut(&buffer_id)
6027 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6028 {
6029 lens_lsp_data.update = None;
6030 }
6031 })
6032 .ok();
6033 return Err(e);
6034 }
6035 };
6036
6037 lsp_store
6038 .update(cx, |lsp_store, _| {
6039 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6040 let code_lens = lsp_data.code_lens.as_mut()?;
6041 if let Some(fetched_lens) = fetched_lens {
6042 if lsp_data.buffer_version == query_version_queried_for {
6043 code_lens.lens.extend(fetched_lens);
6044 } else if !lsp_data
6045 .buffer_version
6046 .changed_since(&query_version_queried_for)
6047 {
6048 lsp_data.buffer_version = query_version_queried_for;
6049 code_lens.lens = fetched_lens;
6050 }
6051 }
6052 code_lens.update = None;
6053 Some(code_lens.lens.values().flatten().cloned().collect())
6054 })
6055 .map_err(Arc::new)
6056 })
6057 .shared();
6058 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6059 new_task
6060 }
6061
6062 fn fetch_code_lens(
6063 &mut self,
6064 buffer: &Entity<Buffer>,
6065 cx: &mut Context<Self>,
6066 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6067 if let Some((upstream_client, project_id)) = self.upstream_client() {
6068 let request = GetCodeLens;
6069 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6070 return Task::ready(Ok(None));
6071 }
6072 let request_task = upstream_client.request_lsp(
6073 project_id,
6074 None,
6075 LSP_REQUEST_TIMEOUT,
6076 cx.background_executor().clone(),
6077 request.to_proto(project_id, buffer.read(cx)),
6078 );
6079 let buffer = buffer.clone();
6080 cx.spawn(async move |weak_lsp_store, cx| {
6081 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6082 return Ok(None);
6083 };
6084 let Some(responses) = request_task.await? else {
6085 return Ok(None);
6086 };
6087
6088 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6089 let lsp_store = lsp_store.clone();
6090 let buffer = buffer.clone();
6091 let cx = cx.clone();
6092 async move {
6093 (
6094 LanguageServerId::from_proto(response.server_id),
6095 GetCodeLens
6096 .response_from_proto(response.response, lsp_store, buffer, cx)
6097 .await,
6098 )
6099 }
6100 }))
6101 .await;
6102
6103 let mut has_errors = false;
6104 let code_lens_actions = code_lens_actions
6105 .into_iter()
6106 .filter_map(|(server_id, code_lens)| match code_lens {
6107 Ok(code_lens) => Some((server_id, code_lens)),
6108 Err(e) => {
6109 has_errors = true;
6110 log::error!("{e:#}");
6111 None
6112 }
6113 })
6114 .collect::<HashMap<_, _>>();
6115 anyhow::ensure!(
6116 !has_errors || !code_lens_actions.is_empty(),
6117 "Failed to fetch code lens"
6118 );
6119 Ok(Some(code_lens_actions))
6120 })
6121 } else {
6122 let code_lens_actions_task =
6123 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6124 cx.background_spawn(async move {
6125 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6126 })
6127 }
6128 }
6129
6130 #[inline(never)]
6131 pub fn completions(
6132 &self,
6133 buffer: &Entity<Buffer>,
6134 position: PointUtf16,
6135 context: CompletionContext,
6136 cx: &mut Context<Self>,
6137 ) -> Task<Result<Vec<CompletionResponse>>> {
6138 let language_registry = self.languages.clone();
6139
6140 if let Some((upstream_client, project_id)) = self.upstream_client() {
6141 let snapshot = buffer.read(cx).snapshot();
6142 let offset = position.to_offset(&snapshot);
6143 let scope = snapshot.language_scope_at(offset);
6144 let capable_lsps = self.all_capable_for_proto_request(
6145 buffer,
6146 |server_name, capabilities| {
6147 capabilities.completion_provider.is_some()
6148 && scope
6149 .as_ref()
6150 .map(|scope| scope.language_allowed(server_name))
6151 .unwrap_or(true)
6152 },
6153 cx,
6154 );
6155 if capable_lsps.is_empty() {
6156 return Task::ready(Ok(Vec::new()));
6157 }
6158
6159 let language = buffer.read(cx).language().cloned();
6160
6161 // In the future, we should provide project guests with the names of LSP adapters,
6162 // so that they can use the correct LSP adapter when computing labels. For now,
6163 // guests just use the first LSP adapter associated with the buffer's language.
6164 let lsp_adapter = language.as_ref().and_then(|language| {
6165 language_registry
6166 .lsp_adapters(&language.name())
6167 .first()
6168 .cloned()
6169 });
6170
6171 let buffer = buffer.clone();
6172
6173 cx.spawn(async move |this, cx| {
6174 let requests = join_all(
6175 capable_lsps
6176 .into_iter()
6177 .map(|id| {
6178 let request = GetCompletions {
6179 position,
6180 context: context.clone(),
6181 server_id: Some(id),
6182 };
6183 let buffer = buffer.clone();
6184 let language = language.clone();
6185 let lsp_adapter = lsp_adapter.clone();
6186 let upstream_client = upstream_client.clone();
6187 let response = this
6188 .update(cx, |this, cx| {
6189 this.send_lsp_proto_request(
6190 buffer,
6191 upstream_client,
6192 project_id,
6193 request,
6194 cx,
6195 )
6196 })
6197 .log_err();
6198 async move {
6199 let response = response?.await.log_err()?;
6200
6201 let completions = populate_labels_for_completions(
6202 response.completions,
6203 language,
6204 lsp_adapter,
6205 )
6206 .await;
6207
6208 Some(CompletionResponse {
6209 completions,
6210 display_options: CompletionDisplayOptions::default(),
6211 is_incomplete: response.is_incomplete,
6212 })
6213 }
6214 })
6215 .collect::<Vec<_>>(),
6216 );
6217 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6218 })
6219 } else if let Some(local) = self.as_local() {
6220 let snapshot = buffer.read(cx).snapshot();
6221 let offset = position.to_offset(&snapshot);
6222 let scope = snapshot.language_scope_at(offset);
6223 let language = snapshot.language().cloned();
6224 let completion_settings = language_settings(
6225 language.as_ref().map(|language| language.name()),
6226 buffer.read(cx).file(),
6227 cx,
6228 )
6229 .completions
6230 .clone();
6231 if !completion_settings.lsp {
6232 return Task::ready(Ok(Vec::new()));
6233 }
6234
6235 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6236 local
6237 .language_servers_for_buffer(buffer, cx)
6238 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6239 .filter(|(adapter, _)| {
6240 scope
6241 .as_ref()
6242 .map(|scope| scope.language_allowed(&adapter.name))
6243 .unwrap_or(true)
6244 })
6245 .map(|(_, server)| server.server_id())
6246 .collect()
6247 });
6248
6249 let buffer = buffer.clone();
6250 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6251 let lsp_timeout = if lsp_timeout > 0 {
6252 Some(Duration::from_millis(lsp_timeout))
6253 } else {
6254 None
6255 };
6256 cx.spawn(async move |this, cx| {
6257 let mut tasks = Vec::with_capacity(server_ids.len());
6258 this.update(cx, |lsp_store, cx| {
6259 for server_id in server_ids {
6260 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6261 let lsp_timeout = lsp_timeout
6262 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6263 let mut timeout = cx.background_spawn(async move {
6264 match lsp_timeout {
6265 Some(lsp_timeout) => {
6266 lsp_timeout.await;
6267 true
6268 },
6269 None => false,
6270 }
6271 }).fuse();
6272 let mut lsp_request = lsp_store.request_lsp(
6273 buffer.clone(),
6274 LanguageServerToQuery::Other(server_id),
6275 GetCompletions {
6276 position,
6277 context: context.clone(),
6278 server_id: Some(server_id),
6279 },
6280 cx,
6281 ).fuse();
6282 let new_task = cx.background_spawn(async move {
6283 select_biased! {
6284 response = lsp_request => anyhow::Ok(Some(response?)),
6285 timeout_happened = timeout => {
6286 if timeout_happened {
6287 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6288 Ok(None)
6289 } else {
6290 let completions = lsp_request.await?;
6291 Ok(Some(completions))
6292 }
6293 },
6294 }
6295 });
6296 tasks.push((lsp_adapter, new_task));
6297 }
6298 })?;
6299
6300 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6301 let completion_response = task.await.ok()??;
6302 let completions = populate_labels_for_completions(
6303 completion_response.completions,
6304 language.clone(),
6305 lsp_adapter,
6306 )
6307 .await;
6308 Some(CompletionResponse {
6309 completions,
6310 display_options: CompletionDisplayOptions::default(),
6311 is_incomplete: completion_response.is_incomplete,
6312 })
6313 });
6314
6315 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6316
6317 Ok(responses.into_iter().flatten().collect())
6318 })
6319 } else {
6320 Task::ready(Err(anyhow!("No upstream client or local language server")))
6321 }
6322 }
6323
6324 pub fn resolve_completions(
6325 &self,
6326 buffer: Entity<Buffer>,
6327 completion_indices: Vec<usize>,
6328 completions: Rc<RefCell<Box<[Completion]>>>,
6329 cx: &mut Context<Self>,
6330 ) -> Task<Result<bool>> {
6331 let client = self.upstream_client();
6332 let buffer_id = buffer.read(cx).remote_id();
6333 let buffer_snapshot = buffer.read(cx).snapshot();
6334
6335 if !self.check_if_capable_for_proto_request(
6336 &buffer,
6337 GetCompletions::can_resolve_completions,
6338 cx,
6339 ) {
6340 return Task::ready(Ok(false));
6341 }
6342 cx.spawn(async move |lsp_store, cx| {
6343 let mut did_resolve = false;
6344 if let Some((client, project_id)) = client {
6345 for completion_index in completion_indices {
6346 let server_id = {
6347 let completion = &completions.borrow()[completion_index];
6348 completion.source.server_id()
6349 };
6350 if let Some(server_id) = server_id {
6351 if Self::resolve_completion_remote(
6352 project_id,
6353 server_id,
6354 buffer_id,
6355 completions.clone(),
6356 completion_index,
6357 client.clone(),
6358 )
6359 .await
6360 .log_err()
6361 .is_some()
6362 {
6363 did_resolve = true;
6364 }
6365 } else {
6366 resolve_word_completion(
6367 &buffer_snapshot,
6368 &mut completions.borrow_mut()[completion_index],
6369 );
6370 }
6371 }
6372 } else {
6373 for completion_index in completion_indices {
6374 let server_id = {
6375 let completion = &completions.borrow()[completion_index];
6376 completion.source.server_id()
6377 };
6378 if let Some(server_id) = server_id {
6379 let server_and_adapter = lsp_store
6380 .read_with(cx, |lsp_store, _| {
6381 let server = lsp_store.language_server_for_id(server_id)?;
6382 let adapter =
6383 lsp_store.language_server_adapter_for_id(server.server_id())?;
6384 Some((server, adapter))
6385 })
6386 .ok()
6387 .flatten();
6388 let Some((server, adapter)) = server_and_adapter else {
6389 continue;
6390 };
6391
6392 let resolved = Self::resolve_completion_local(
6393 server,
6394 completions.clone(),
6395 completion_index,
6396 )
6397 .await
6398 .log_err()
6399 .is_some();
6400 if resolved {
6401 Self::regenerate_completion_labels(
6402 adapter,
6403 &buffer_snapshot,
6404 completions.clone(),
6405 completion_index,
6406 )
6407 .await
6408 .log_err();
6409 did_resolve = true;
6410 }
6411 } else {
6412 resolve_word_completion(
6413 &buffer_snapshot,
6414 &mut completions.borrow_mut()[completion_index],
6415 );
6416 }
6417 }
6418 }
6419
6420 Ok(did_resolve)
6421 })
6422 }
6423
6424 async fn resolve_completion_local(
6425 server: Arc<lsp::LanguageServer>,
6426 completions: Rc<RefCell<Box<[Completion]>>>,
6427 completion_index: usize,
6428 ) -> Result<()> {
6429 let server_id = server.server_id();
6430 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6431 return Ok(());
6432 }
6433
6434 let request = {
6435 let completion = &completions.borrow()[completion_index];
6436 match &completion.source {
6437 CompletionSource::Lsp {
6438 lsp_completion,
6439 resolved,
6440 server_id: completion_server_id,
6441 ..
6442 } => {
6443 if *resolved {
6444 return Ok(());
6445 }
6446 anyhow::ensure!(
6447 server_id == *completion_server_id,
6448 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6449 );
6450 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6451 }
6452 CompletionSource::BufferWord { .. }
6453 | CompletionSource::Dap { .. }
6454 | CompletionSource::Custom => {
6455 return Ok(());
6456 }
6457 }
6458 };
6459 let resolved_completion = request
6460 .await
6461 .into_response()
6462 .context("resolve completion")?;
6463
6464 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6465 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6466
6467 let mut completions = completions.borrow_mut();
6468 let completion = &mut completions[completion_index];
6469 if let CompletionSource::Lsp {
6470 lsp_completion,
6471 resolved,
6472 server_id: completion_server_id,
6473 ..
6474 } = &mut completion.source
6475 {
6476 if *resolved {
6477 return Ok(());
6478 }
6479 anyhow::ensure!(
6480 server_id == *completion_server_id,
6481 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6482 );
6483 *lsp_completion = Box::new(resolved_completion);
6484 *resolved = true;
6485 }
6486 Ok(())
6487 }
6488
6489 async fn regenerate_completion_labels(
6490 adapter: Arc<CachedLspAdapter>,
6491 snapshot: &BufferSnapshot,
6492 completions: Rc<RefCell<Box<[Completion]>>>,
6493 completion_index: usize,
6494 ) -> Result<()> {
6495 let completion_item = completions.borrow()[completion_index]
6496 .source
6497 .lsp_completion(true)
6498 .map(Cow::into_owned);
6499 if let Some(lsp_documentation) = completion_item
6500 .as_ref()
6501 .and_then(|completion_item| completion_item.documentation.clone())
6502 {
6503 let mut completions = completions.borrow_mut();
6504 let completion = &mut completions[completion_index];
6505 completion.documentation = Some(lsp_documentation.into());
6506 } else {
6507 let mut completions = completions.borrow_mut();
6508 let completion = &mut completions[completion_index];
6509 completion.documentation = Some(CompletionDocumentation::Undocumented);
6510 }
6511
6512 let mut new_label = match completion_item {
6513 Some(completion_item) => {
6514 // 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
6515 // So we have to update the label here anyway...
6516 let language = snapshot.language();
6517 match language {
6518 Some(language) => {
6519 adapter
6520 .labels_for_completions(
6521 std::slice::from_ref(&completion_item),
6522 language,
6523 )
6524 .await?
6525 }
6526 None => Vec::new(),
6527 }
6528 .pop()
6529 .flatten()
6530 .unwrap_or_else(|| {
6531 CodeLabel::fallback_for_completion(
6532 &completion_item,
6533 language.map(|language| language.as_ref()),
6534 )
6535 })
6536 }
6537 None => CodeLabel::plain(
6538 completions.borrow()[completion_index].new_text.clone(),
6539 None,
6540 ),
6541 };
6542 ensure_uniform_list_compatible_label(&mut new_label);
6543
6544 let mut completions = completions.borrow_mut();
6545 let completion = &mut completions[completion_index];
6546 if completion.label.filter_text() == new_label.filter_text() {
6547 completion.label = new_label;
6548 } else {
6549 log::error!(
6550 "Resolved completion changed display label from {} to {}. \
6551 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6552 completion.label.text(),
6553 new_label.text(),
6554 completion.label.filter_text(),
6555 new_label.filter_text()
6556 );
6557 }
6558
6559 Ok(())
6560 }
6561
6562 async fn resolve_completion_remote(
6563 project_id: u64,
6564 server_id: LanguageServerId,
6565 buffer_id: BufferId,
6566 completions: Rc<RefCell<Box<[Completion]>>>,
6567 completion_index: usize,
6568 client: AnyProtoClient,
6569 ) -> Result<()> {
6570 let lsp_completion = {
6571 let completion = &completions.borrow()[completion_index];
6572 match &completion.source {
6573 CompletionSource::Lsp {
6574 lsp_completion,
6575 resolved,
6576 server_id: completion_server_id,
6577 ..
6578 } => {
6579 anyhow::ensure!(
6580 server_id == *completion_server_id,
6581 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6582 );
6583 if *resolved {
6584 return Ok(());
6585 }
6586 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6587 }
6588 CompletionSource::Custom
6589 | CompletionSource::Dap { .. }
6590 | CompletionSource::BufferWord { .. } => {
6591 return Ok(());
6592 }
6593 }
6594 };
6595 let request = proto::ResolveCompletionDocumentation {
6596 project_id,
6597 language_server_id: server_id.0 as u64,
6598 lsp_completion,
6599 buffer_id: buffer_id.into(),
6600 };
6601
6602 let response = client
6603 .request(request)
6604 .await
6605 .context("completion documentation resolve proto request")?;
6606 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6607
6608 let documentation = if response.documentation.is_empty() {
6609 CompletionDocumentation::Undocumented
6610 } else if response.documentation_is_markdown {
6611 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6612 } else if response.documentation.lines().count() <= 1 {
6613 CompletionDocumentation::SingleLine(response.documentation.into())
6614 } else {
6615 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6616 };
6617
6618 let mut completions = completions.borrow_mut();
6619 let completion = &mut completions[completion_index];
6620 completion.documentation = Some(documentation);
6621 if let CompletionSource::Lsp {
6622 insert_range,
6623 lsp_completion,
6624 resolved,
6625 server_id: completion_server_id,
6626 lsp_defaults: _,
6627 } = &mut completion.source
6628 {
6629 let completion_insert_range = response
6630 .old_insert_start
6631 .and_then(deserialize_anchor)
6632 .zip(response.old_insert_end.and_then(deserialize_anchor));
6633 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6634
6635 if *resolved {
6636 return Ok(());
6637 }
6638 anyhow::ensure!(
6639 server_id == *completion_server_id,
6640 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6641 );
6642 *lsp_completion = Box::new(resolved_lsp_completion);
6643 *resolved = true;
6644 }
6645
6646 let replace_range = response
6647 .old_replace_start
6648 .and_then(deserialize_anchor)
6649 .zip(response.old_replace_end.and_then(deserialize_anchor));
6650 if let Some((old_replace_start, old_replace_end)) = replace_range
6651 && !response.new_text.is_empty()
6652 {
6653 completion.new_text = response.new_text;
6654 completion.replace_range = old_replace_start..old_replace_end;
6655 }
6656
6657 Ok(())
6658 }
6659
6660 pub fn apply_additional_edits_for_completion(
6661 &self,
6662 buffer_handle: Entity<Buffer>,
6663 completions: Rc<RefCell<Box<[Completion]>>>,
6664 completion_index: usize,
6665 push_to_history: bool,
6666 cx: &mut Context<Self>,
6667 ) -> Task<Result<Option<Transaction>>> {
6668 if let Some((client, project_id)) = self.upstream_client() {
6669 let buffer = buffer_handle.read(cx);
6670 let buffer_id = buffer.remote_id();
6671 cx.spawn(async move |_, cx| {
6672 let request = {
6673 let completion = completions.borrow()[completion_index].clone();
6674 proto::ApplyCompletionAdditionalEdits {
6675 project_id,
6676 buffer_id: buffer_id.into(),
6677 completion: Some(Self::serialize_completion(&CoreCompletion {
6678 replace_range: completion.replace_range,
6679 new_text: completion.new_text,
6680 source: completion.source,
6681 })),
6682 }
6683 };
6684
6685 if let Some(transaction) = client.request(request).await?.transaction {
6686 let transaction = language::proto::deserialize_transaction(transaction)?;
6687 buffer_handle
6688 .update(cx, |buffer, _| {
6689 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6690 })?
6691 .await?;
6692 if push_to_history {
6693 buffer_handle.update(cx, |buffer, _| {
6694 buffer.push_transaction(transaction.clone(), Instant::now());
6695 buffer.finalize_last_transaction();
6696 })?;
6697 }
6698 Ok(Some(transaction))
6699 } else {
6700 Ok(None)
6701 }
6702 })
6703 } else {
6704 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6705 let completion = &completions.borrow()[completion_index];
6706 let server_id = completion.source.server_id()?;
6707 Some(
6708 self.language_server_for_local_buffer(buffer, server_id, cx)?
6709 .1
6710 .clone(),
6711 )
6712 }) else {
6713 return Task::ready(Ok(None));
6714 };
6715
6716 cx.spawn(async move |this, cx| {
6717 Self::resolve_completion_local(
6718 server.clone(),
6719 completions.clone(),
6720 completion_index,
6721 )
6722 .await
6723 .context("resolving completion")?;
6724 let completion = completions.borrow()[completion_index].clone();
6725 let additional_text_edits = completion
6726 .source
6727 .lsp_completion(true)
6728 .as_ref()
6729 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6730 if let Some(edits) = additional_text_edits {
6731 let edits = this
6732 .update(cx, |this, cx| {
6733 this.as_local_mut().unwrap().edits_from_lsp(
6734 &buffer_handle,
6735 edits,
6736 server.server_id(),
6737 None,
6738 cx,
6739 )
6740 })?
6741 .await?;
6742
6743 buffer_handle.update(cx, |buffer, cx| {
6744 buffer.finalize_last_transaction();
6745 buffer.start_transaction();
6746
6747 for (range, text) in edits {
6748 let primary = &completion.replace_range;
6749
6750 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6751 // and the primary completion is just an insertion (empty range), then this is likely
6752 // an auto-import scenario and should not be considered overlapping
6753 // https://github.com/zed-industries/zed/issues/26136
6754 let is_file_start_auto_import = {
6755 let snapshot = buffer.snapshot();
6756 let primary_start_point = primary.start.to_point(&snapshot);
6757 let range_start_point = range.start.to_point(&snapshot);
6758
6759 let result = primary_start_point.row == 0
6760 && primary_start_point.column == 0
6761 && range_start_point.row == 0
6762 && range_start_point.column == 0;
6763
6764 result
6765 };
6766
6767 let has_overlap = if is_file_start_auto_import {
6768 false
6769 } else {
6770 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6771 && primary.end.cmp(&range.start, buffer).is_ge();
6772 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6773 && range.end.cmp(&primary.end, buffer).is_ge();
6774 let result = start_within || end_within;
6775 result
6776 };
6777
6778 //Skip additional edits which overlap with the primary completion edit
6779 //https://github.com/zed-industries/zed/pull/1871
6780 if !has_overlap {
6781 buffer.edit([(range, text)], None, cx);
6782 }
6783 }
6784
6785 let transaction = if buffer.end_transaction(cx).is_some() {
6786 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6787 if !push_to_history {
6788 buffer.forget_transaction(transaction.id);
6789 }
6790 Some(transaction)
6791 } else {
6792 None
6793 };
6794 Ok(transaction)
6795 })?
6796 } else {
6797 Ok(None)
6798 }
6799 })
6800 }
6801 }
6802
6803 pub fn pull_diagnostics(
6804 &mut self,
6805 buffer: Entity<Buffer>,
6806 cx: &mut Context<Self>,
6807 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6808 let buffer_id = buffer.read(cx).remote_id();
6809
6810 if let Some((client, upstream_project_id)) = self.upstream_client() {
6811 let mut suitable_capabilities = None;
6812 // Are we capable for proto request?
6813 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6814 &buffer,
6815 |capabilities| {
6816 if let Some(caps) = &capabilities.diagnostic_provider {
6817 suitable_capabilities = Some(caps.clone());
6818 true
6819 } else {
6820 false
6821 }
6822 },
6823 cx,
6824 );
6825 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6826 let Some(dynamic_caps) = suitable_capabilities else {
6827 return Task::ready(Ok(None));
6828 };
6829 assert!(any_server_has_diagnostics_provider);
6830
6831 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6832 let request = GetDocumentDiagnostics {
6833 previous_result_id: None,
6834 identifier,
6835 registration_id: None,
6836 };
6837 let request_task = client.request_lsp(
6838 upstream_project_id,
6839 None,
6840 LSP_REQUEST_TIMEOUT,
6841 cx.background_executor().clone(),
6842 request.to_proto(upstream_project_id, buffer.read(cx)),
6843 );
6844 cx.background_spawn(async move {
6845 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6846 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6847 // Do not attempt to further process the dummy responses here.
6848 let _response = request_task.await?;
6849 Ok(None)
6850 })
6851 } else {
6852 let servers = buffer.update(cx, |buffer, cx| {
6853 self.running_language_servers_for_local_buffer(buffer, cx)
6854 .map(|(_, server)| server.clone())
6855 .collect::<Vec<_>>()
6856 });
6857
6858 let pull_diagnostics = servers
6859 .into_iter()
6860 .flat_map(|server| {
6861 let result = maybe!({
6862 let local = self.as_local()?;
6863 let server_id = server.server_id();
6864 let providers_with_identifiers = local
6865 .language_server_dynamic_registrations
6866 .get(&server_id)
6867 .into_iter()
6868 .flat_map(|registrations| registrations.diagnostics.clone())
6869 .collect::<Vec<_>>();
6870 Some(
6871 providers_with_identifiers
6872 .into_iter()
6873 .map(|(registration_id, dynamic_caps)| {
6874 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6875 let registration_id = registration_id.map(SharedString::from);
6876 let result_id = self.result_id_for_buffer_pull(
6877 server_id,
6878 buffer_id,
6879 ®istration_id,
6880 cx,
6881 );
6882 self.request_lsp(
6883 buffer.clone(),
6884 LanguageServerToQuery::Other(server_id),
6885 GetDocumentDiagnostics {
6886 previous_result_id: result_id,
6887 registration_id,
6888 identifier,
6889 },
6890 cx,
6891 )
6892 })
6893 .collect::<Vec<_>>(),
6894 )
6895 });
6896
6897 result.unwrap_or_default()
6898 })
6899 .collect::<Vec<_>>();
6900
6901 cx.background_spawn(async move {
6902 let mut responses = Vec::new();
6903 for diagnostics in join_all(pull_diagnostics).await {
6904 responses.extend(diagnostics?);
6905 }
6906 Ok(Some(responses))
6907 })
6908 }
6909 }
6910
6911 pub fn applicable_inlay_chunks(
6912 &mut self,
6913 buffer: &Entity<Buffer>,
6914 ranges: &[Range<text::Anchor>],
6915 cx: &mut Context<Self>,
6916 ) -> Vec<Range<BufferRow>> {
6917 let buffer_snapshot = buffer.read(cx).snapshot();
6918 let ranges = ranges
6919 .iter()
6920 .map(|range| range.to_point(&buffer_snapshot))
6921 .collect::<Vec<_>>();
6922
6923 self.latest_lsp_data(buffer, cx)
6924 .inlay_hints
6925 .applicable_chunks(ranges.as_slice())
6926 .map(|chunk| chunk.row_range())
6927 .collect()
6928 }
6929
6930 pub fn invalidate_inlay_hints<'a>(
6931 &'a mut self,
6932 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6933 ) {
6934 for buffer_id in for_buffers {
6935 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6936 lsp_data.inlay_hints.clear();
6937 }
6938 }
6939 }
6940
6941 pub fn inlay_hints(
6942 &mut self,
6943 invalidate: InvalidationStrategy,
6944 buffer: Entity<Buffer>,
6945 ranges: Vec<Range<text::Anchor>>,
6946 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6947 cx: &mut Context<Self>,
6948 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6949 let next_hint_id = self.next_hint_id.clone();
6950 let lsp_data = self.latest_lsp_data(&buffer, cx);
6951 let query_version = lsp_data.buffer_version.clone();
6952 let mut lsp_refresh_requested = false;
6953 let for_server = if let InvalidationStrategy::RefreshRequested {
6954 server_id,
6955 request_id,
6956 } = invalidate
6957 {
6958 let invalidated = lsp_data
6959 .inlay_hints
6960 .invalidate_for_server_refresh(server_id, request_id);
6961 lsp_refresh_requested = invalidated;
6962 Some(server_id)
6963 } else {
6964 None
6965 };
6966 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6967 let known_chunks = known_chunks
6968 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6969 .map(|(_, known_chunks)| known_chunks)
6970 .unwrap_or_default();
6971
6972 let buffer_snapshot = buffer.read(cx).snapshot();
6973 let ranges = ranges
6974 .iter()
6975 .map(|range| range.to_point(&buffer_snapshot))
6976 .collect::<Vec<_>>();
6977
6978 let mut hint_fetch_tasks = Vec::new();
6979 let mut cached_inlay_hints = None;
6980 let mut ranges_to_query = None;
6981 let applicable_chunks = existing_inlay_hints
6982 .applicable_chunks(ranges.as_slice())
6983 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6984 .collect::<Vec<_>>();
6985 if applicable_chunks.is_empty() {
6986 return HashMap::default();
6987 }
6988
6989 for row_chunk in applicable_chunks {
6990 match (
6991 existing_inlay_hints
6992 .cached_hints(&row_chunk)
6993 .filter(|_| !lsp_refresh_requested)
6994 .cloned(),
6995 existing_inlay_hints
6996 .fetched_hints(&row_chunk)
6997 .as_ref()
6998 .filter(|_| !lsp_refresh_requested)
6999 .cloned(),
7000 ) {
7001 (None, None) => {
7002 let chunk_range = row_chunk.anchor_range();
7003 ranges_to_query
7004 .get_or_insert_with(Vec::new)
7005 .push((row_chunk, chunk_range));
7006 }
7007 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7008 (Some(cached_hints), None) => {
7009 for (server_id, cached_hints) in cached_hints {
7010 if for_server.is_none_or(|for_server| for_server == server_id) {
7011 cached_inlay_hints
7012 .get_or_insert_with(HashMap::default)
7013 .entry(row_chunk.row_range())
7014 .or_insert_with(HashMap::default)
7015 .entry(server_id)
7016 .or_insert_with(Vec::new)
7017 .extend(cached_hints);
7018 }
7019 }
7020 }
7021 (Some(cached_hints), Some(fetched_hints)) => {
7022 hint_fetch_tasks.push((row_chunk, fetched_hints));
7023 for (server_id, cached_hints) in cached_hints {
7024 if for_server.is_none_or(|for_server| for_server == server_id) {
7025 cached_inlay_hints
7026 .get_or_insert_with(HashMap::default)
7027 .entry(row_chunk.row_range())
7028 .or_insert_with(HashMap::default)
7029 .entry(server_id)
7030 .or_insert_with(Vec::new)
7031 .extend(cached_hints);
7032 }
7033 }
7034 }
7035 }
7036 }
7037
7038 if hint_fetch_tasks.is_empty()
7039 && ranges_to_query
7040 .as_ref()
7041 .is_none_or(|ranges| ranges.is_empty())
7042 && let Some(cached_inlay_hints) = cached_inlay_hints
7043 {
7044 cached_inlay_hints
7045 .into_iter()
7046 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7047 .collect()
7048 } else {
7049 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7050 let next_hint_id = next_hint_id.clone();
7051 let buffer = buffer.clone();
7052 let query_version = query_version.clone();
7053 let new_inlay_hints = cx
7054 .spawn(async move |lsp_store, cx| {
7055 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7056 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7057 })?;
7058 new_fetch_task
7059 .await
7060 .and_then(|new_hints_by_server| {
7061 lsp_store.update(cx, |lsp_store, cx| {
7062 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7063 let update_cache = lsp_data.buffer_version == query_version;
7064 if new_hints_by_server.is_empty() {
7065 if update_cache {
7066 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7067 }
7068 HashMap::default()
7069 } else {
7070 new_hints_by_server
7071 .into_iter()
7072 .map(|(server_id, new_hints)| {
7073 let new_hints = new_hints
7074 .into_iter()
7075 .map(|new_hint| {
7076 (
7077 InlayId::Hint(next_hint_id.fetch_add(
7078 1,
7079 atomic::Ordering::AcqRel,
7080 )),
7081 new_hint,
7082 )
7083 })
7084 .collect::<Vec<_>>();
7085 if update_cache {
7086 lsp_data.inlay_hints.insert_new_hints(
7087 chunk,
7088 server_id,
7089 new_hints.clone(),
7090 );
7091 }
7092 (server_id, new_hints)
7093 })
7094 .collect()
7095 }
7096 })
7097 })
7098 .map_err(Arc::new)
7099 })
7100 .shared();
7101
7102 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7103 *fetch_task = Some(new_inlay_hints.clone());
7104 hint_fetch_tasks.push((chunk, new_inlay_hints));
7105 }
7106
7107 cached_inlay_hints
7108 .unwrap_or_default()
7109 .into_iter()
7110 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7111 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7112 (
7113 chunk.row_range(),
7114 cx.spawn(async move |_, _| {
7115 hints_fetch.await.map_err(|e| {
7116 if e.error_code() != ErrorCode::Internal {
7117 anyhow!(e.error_code())
7118 } else {
7119 anyhow!("{e:#}")
7120 }
7121 })
7122 }),
7123 )
7124 }))
7125 .collect()
7126 }
7127 }
7128
7129 fn fetch_inlay_hints(
7130 &mut self,
7131 for_server: Option<LanguageServerId>,
7132 buffer: &Entity<Buffer>,
7133 range: Range<Anchor>,
7134 cx: &mut Context<Self>,
7135 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7136 let request = InlayHints {
7137 range: range.clone(),
7138 };
7139 if let Some((upstream_client, project_id)) = self.upstream_client() {
7140 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7141 return Task::ready(Ok(HashMap::default()));
7142 }
7143 let request_task = upstream_client.request_lsp(
7144 project_id,
7145 for_server.map(|id| id.to_proto()),
7146 LSP_REQUEST_TIMEOUT,
7147 cx.background_executor().clone(),
7148 request.to_proto(project_id, buffer.read(cx)),
7149 );
7150 let buffer = buffer.clone();
7151 cx.spawn(async move |weak_lsp_store, cx| {
7152 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7153 return Ok(HashMap::default());
7154 };
7155 let Some(responses) = request_task.await? else {
7156 return Ok(HashMap::default());
7157 };
7158
7159 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7160 let lsp_store = lsp_store.clone();
7161 let buffer = buffer.clone();
7162 let cx = cx.clone();
7163 let request = request.clone();
7164 async move {
7165 (
7166 LanguageServerId::from_proto(response.server_id),
7167 request
7168 .response_from_proto(response.response, lsp_store, buffer, cx)
7169 .await,
7170 )
7171 }
7172 }))
7173 .await;
7174
7175 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7176 let mut has_errors = false;
7177 let inlay_hints = inlay_hints
7178 .into_iter()
7179 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7180 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7181 Err(e) => {
7182 has_errors = true;
7183 log::error!("{e:#}");
7184 None
7185 }
7186 })
7187 .map(|(server_id, mut new_hints)| {
7188 new_hints.retain(|hint| {
7189 hint.position.is_valid(&buffer_snapshot)
7190 && range.start.is_valid(&buffer_snapshot)
7191 && range.end.is_valid(&buffer_snapshot)
7192 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7193 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7194 });
7195 (server_id, new_hints)
7196 })
7197 .collect::<HashMap<_, _>>();
7198 anyhow::ensure!(
7199 !has_errors || !inlay_hints.is_empty(),
7200 "Failed to fetch inlay hints"
7201 );
7202 Ok(inlay_hints)
7203 })
7204 } else {
7205 let inlay_hints_task = match for_server {
7206 Some(server_id) => {
7207 let server_task = self.request_lsp(
7208 buffer.clone(),
7209 LanguageServerToQuery::Other(server_id),
7210 request,
7211 cx,
7212 );
7213 cx.background_spawn(async move {
7214 let mut responses = Vec::new();
7215 match server_task.await {
7216 Ok(response) => responses.push((server_id, response)),
7217 // rust-analyzer likes to error with this when its still loading up
7218 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7219 Err(e) => log::error!(
7220 "Error handling response for inlay hints request: {e:#}"
7221 ),
7222 }
7223 responses
7224 })
7225 }
7226 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7227 };
7228 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7229 cx.background_spawn(async move {
7230 Ok(inlay_hints_task
7231 .await
7232 .into_iter()
7233 .map(|(server_id, mut new_hints)| {
7234 new_hints.retain(|hint| {
7235 hint.position.is_valid(&buffer_snapshot)
7236 && range.start.is_valid(&buffer_snapshot)
7237 && range.end.is_valid(&buffer_snapshot)
7238 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7239 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7240 });
7241 (server_id, new_hints)
7242 })
7243 .collect())
7244 })
7245 }
7246 }
7247
7248 fn diagnostic_registration_exists(
7249 &self,
7250 server_id: LanguageServerId,
7251 registration_id: &Option<SharedString>,
7252 ) -> bool {
7253 let Some(local) = self.as_local() else {
7254 return false;
7255 };
7256 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7257 else {
7258 return false;
7259 };
7260 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7261 registrations.diagnostics.contains_key(®istration_key)
7262 }
7263
7264 pub fn pull_diagnostics_for_buffer(
7265 &mut self,
7266 buffer: Entity<Buffer>,
7267 cx: &mut Context<Self>,
7268 ) -> Task<anyhow::Result<()>> {
7269 let diagnostics = self.pull_diagnostics(buffer, cx);
7270 cx.spawn(async move |lsp_store, cx| {
7271 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7272 return Ok(());
7273 };
7274 lsp_store.update(cx, |lsp_store, cx| {
7275 if lsp_store.as_local().is_none() {
7276 return;
7277 }
7278
7279 let mut unchanged_buffers = HashMap::default();
7280 let server_diagnostics_updates = diagnostics
7281 .into_iter()
7282 .filter_map(|diagnostics_set| match diagnostics_set {
7283 LspPullDiagnostics::Response {
7284 server_id,
7285 uri,
7286 diagnostics,
7287 registration_id,
7288 } => Some((server_id, uri, diagnostics, registration_id)),
7289 LspPullDiagnostics::Default => None,
7290 })
7291 .filter(|(server_id, _, _, registration_id)| {
7292 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7293 })
7294 .fold(
7295 HashMap::default(),
7296 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7297 let (result_id, diagnostics) = match diagnostics {
7298 PulledDiagnostics::Unchanged { result_id } => {
7299 unchanged_buffers
7300 .entry(new_registration_id.clone())
7301 .or_insert_with(HashSet::default)
7302 .insert(uri.clone());
7303 (Some(result_id), Vec::new())
7304 }
7305 PulledDiagnostics::Changed {
7306 result_id,
7307 diagnostics,
7308 } => (result_id, diagnostics),
7309 };
7310 let disk_based_sources = Cow::Owned(
7311 lsp_store
7312 .language_server_adapter_for_id(server_id)
7313 .as_ref()
7314 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7315 .unwrap_or(&[])
7316 .to_vec(),
7317 );
7318 acc.entry(server_id)
7319 .or_insert_with(HashMap::default)
7320 .entry(new_registration_id.clone())
7321 .or_insert_with(Vec::new)
7322 .push(DocumentDiagnosticsUpdate {
7323 server_id,
7324 diagnostics: lsp::PublishDiagnosticsParams {
7325 uri,
7326 diagnostics,
7327 version: None,
7328 },
7329 result_id,
7330 disk_based_sources,
7331 registration_id: new_registration_id,
7332 });
7333 acc
7334 },
7335 );
7336
7337 for diagnostic_updates in server_diagnostics_updates.into_values() {
7338 for (registration_id, diagnostic_updates) in diagnostic_updates {
7339 lsp_store
7340 .merge_lsp_diagnostics(
7341 DiagnosticSourceKind::Pulled,
7342 diagnostic_updates,
7343 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7344 DiagnosticSourceKind::Pulled => {
7345 old_diagnostic.registration_id != registration_id
7346 || unchanged_buffers
7347 .get(&old_diagnostic.registration_id)
7348 .is_some_and(|unchanged_buffers| {
7349 unchanged_buffers.contains(&document_uri)
7350 })
7351 }
7352 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7353 true
7354 }
7355 },
7356 cx,
7357 )
7358 .log_err();
7359 }
7360 }
7361 })
7362 })
7363 }
7364
7365 pub fn document_colors(
7366 &mut self,
7367 known_cache_version: Option<usize>,
7368 buffer: Entity<Buffer>,
7369 cx: &mut Context<Self>,
7370 ) -> Option<DocumentColorTask> {
7371 let version_queried_for = buffer.read(cx).version();
7372 let buffer_id = buffer.read(cx).remote_id();
7373
7374 let current_language_servers = self.as_local().map(|local| {
7375 local
7376 .buffers_opened_in_servers
7377 .get(&buffer_id)
7378 .cloned()
7379 .unwrap_or_default()
7380 });
7381
7382 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7383 if let Some(cached_colors) = &lsp_data.document_colors {
7384 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7385 let has_different_servers =
7386 current_language_servers.is_some_and(|current_language_servers| {
7387 current_language_servers
7388 != cached_colors.colors.keys().copied().collect()
7389 });
7390 if !has_different_servers {
7391 let cache_version = cached_colors.cache_version;
7392 if Some(cache_version) == known_cache_version {
7393 return None;
7394 } else {
7395 return Some(
7396 Task::ready(Ok(DocumentColors {
7397 colors: cached_colors
7398 .colors
7399 .values()
7400 .flatten()
7401 .cloned()
7402 .collect(),
7403 cache_version: Some(cache_version),
7404 }))
7405 .shared(),
7406 );
7407 }
7408 }
7409 }
7410 }
7411 }
7412
7413 let color_lsp_data = self
7414 .latest_lsp_data(&buffer, cx)
7415 .document_colors
7416 .get_or_insert_default();
7417 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7418 && !version_queried_for.changed_since(updating_for)
7419 {
7420 return Some(running_update.clone());
7421 }
7422 let buffer_version_queried_for = version_queried_for.clone();
7423 let new_task = cx
7424 .spawn(async move |lsp_store, cx| {
7425 cx.background_executor()
7426 .timer(Duration::from_millis(30))
7427 .await;
7428 let fetched_colors = lsp_store
7429 .update(cx, |lsp_store, cx| {
7430 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7431 })?
7432 .await
7433 .context("fetching document colors")
7434 .map_err(Arc::new);
7435 let fetched_colors = match fetched_colors {
7436 Ok(fetched_colors) => {
7437 if Some(true)
7438 == buffer
7439 .update(cx, |buffer, _| {
7440 buffer.version() != buffer_version_queried_for
7441 })
7442 .ok()
7443 {
7444 return Ok(DocumentColors::default());
7445 }
7446 fetched_colors
7447 }
7448 Err(e) => {
7449 lsp_store
7450 .update(cx, |lsp_store, _| {
7451 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7452 if let Some(document_colors) = &mut lsp_data.document_colors {
7453 document_colors.colors_update = None;
7454 }
7455 }
7456 })
7457 .ok();
7458 return Err(e);
7459 }
7460 };
7461
7462 lsp_store
7463 .update(cx, |lsp_store, cx| {
7464 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7465 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7466
7467 if let Some(fetched_colors) = fetched_colors {
7468 if lsp_data.buffer_version == buffer_version_queried_for {
7469 lsp_colors.colors.extend(fetched_colors);
7470 lsp_colors.cache_version += 1;
7471 } else if !lsp_data
7472 .buffer_version
7473 .changed_since(&buffer_version_queried_for)
7474 {
7475 lsp_data.buffer_version = buffer_version_queried_for;
7476 lsp_colors.colors = fetched_colors;
7477 lsp_colors.cache_version += 1;
7478 }
7479 }
7480 lsp_colors.colors_update = None;
7481 let colors = lsp_colors
7482 .colors
7483 .values()
7484 .flatten()
7485 .cloned()
7486 .collect::<HashSet<_>>();
7487 DocumentColors {
7488 colors,
7489 cache_version: Some(lsp_colors.cache_version),
7490 }
7491 })
7492 .map_err(Arc::new)
7493 })
7494 .shared();
7495 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7496 Some(new_task)
7497 }
7498
7499 fn fetch_document_colors_for_buffer(
7500 &mut self,
7501 buffer: &Entity<Buffer>,
7502 cx: &mut Context<Self>,
7503 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7504 if let Some((client, project_id)) = self.upstream_client() {
7505 let request = GetDocumentColor {};
7506 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7507 return Task::ready(Ok(None));
7508 }
7509
7510 let request_task = client.request_lsp(
7511 project_id,
7512 None,
7513 LSP_REQUEST_TIMEOUT,
7514 cx.background_executor().clone(),
7515 request.to_proto(project_id, buffer.read(cx)),
7516 );
7517 let buffer = buffer.clone();
7518 cx.spawn(async move |lsp_store, cx| {
7519 let Some(lsp_store) = lsp_store.upgrade() else {
7520 return Ok(None);
7521 };
7522 let colors = join_all(
7523 request_task
7524 .await
7525 .log_err()
7526 .flatten()
7527 .map(|response| response.payload)
7528 .unwrap_or_default()
7529 .into_iter()
7530 .map(|color_response| {
7531 let response = request.response_from_proto(
7532 color_response.response,
7533 lsp_store.clone(),
7534 buffer.clone(),
7535 cx.clone(),
7536 );
7537 async move {
7538 (
7539 LanguageServerId::from_proto(color_response.server_id),
7540 response.await.log_err().unwrap_or_default(),
7541 )
7542 }
7543 }),
7544 )
7545 .await
7546 .into_iter()
7547 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7548 acc.entry(server_id)
7549 .or_insert_with(HashSet::default)
7550 .extend(colors);
7551 acc
7552 });
7553 Ok(Some(colors))
7554 })
7555 } else {
7556 let document_colors_task =
7557 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7558 cx.background_spawn(async move {
7559 Ok(Some(
7560 document_colors_task
7561 .await
7562 .into_iter()
7563 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7564 acc.entry(server_id)
7565 .or_insert_with(HashSet::default)
7566 .extend(colors);
7567 acc
7568 })
7569 .into_iter()
7570 .collect(),
7571 ))
7572 })
7573 }
7574 }
7575
7576 pub fn signature_help<T: ToPointUtf16>(
7577 &mut self,
7578 buffer: &Entity<Buffer>,
7579 position: T,
7580 cx: &mut Context<Self>,
7581 ) -> Task<Option<Vec<SignatureHelp>>> {
7582 let position = position.to_point_utf16(buffer.read(cx));
7583
7584 if let Some((client, upstream_project_id)) = self.upstream_client() {
7585 let request = GetSignatureHelp { position };
7586 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7587 return Task::ready(None);
7588 }
7589 let request_task = client.request_lsp(
7590 upstream_project_id,
7591 None,
7592 LSP_REQUEST_TIMEOUT,
7593 cx.background_executor().clone(),
7594 request.to_proto(upstream_project_id, buffer.read(cx)),
7595 );
7596 let buffer = buffer.clone();
7597 cx.spawn(async move |weak_lsp_store, cx| {
7598 let lsp_store = weak_lsp_store.upgrade()?;
7599 let signatures = join_all(
7600 request_task
7601 .await
7602 .log_err()
7603 .flatten()
7604 .map(|response| response.payload)
7605 .unwrap_or_default()
7606 .into_iter()
7607 .map(|response| {
7608 let response = GetSignatureHelp { position }.response_from_proto(
7609 response.response,
7610 lsp_store.clone(),
7611 buffer.clone(),
7612 cx.clone(),
7613 );
7614 async move { response.await.log_err().flatten() }
7615 }),
7616 )
7617 .await
7618 .into_iter()
7619 .flatten()
7620 .collect();
7621 Some(signatures)
7622 })
7623 } else {
7624 let all_actions_task = self.request_multiple_lsp_locally(
7625 buffer,
7626 Some(position),
7627 GetSignatureHelp { position },
7628 cx,
7629 );
7630 cx.background_spawn(async move {
7631 Some(
7632 all_actions_task
7633 .await
7634 .into_iter()
7635 .flat_map(|(_, actions)| actions)
7636 .collect::<Vec<_>>(),
7637 )
7638 })
7639 }
7640 }
7641
7642 pub fn hover(
7643 &mut self,
7644 buffer: &Entity<Buffer>,
7645 position: PointUtf16,
7646 cx: &mut Context<Self>,
7647 ) -> Task<Option<Vec<Hover>>> {
7648 if let Some((client, upstream_project_id)) = self.upstream_client() {
7649 let request = GetHover { position };
7650 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7651 return Task::ready(None);
7652 }
7653 let request_task = client.request_lsp(
7654 upstream_project_id,
7655 None,
7656 LSP_REQUEST_TIMEOUT,
7657 cx.background_executor().clone(),
7658 request.to_proto(upstream_project_id, buffer.read(cx)),
7659 );
7660 let buffer = buffer.clone();
7661 cx.spawn(async move |weak_lsp_store, cx| {
7662 let lsp_store = weak_lsp_store.upgrade()?;
7663 let hovers = join_all(
7664 request_task
7665 .await
7666 .log_err()
7667 .flatten()
7668 .map(|response| response.payload)
7669 .unwrap_or_default()
7670 .into_iter()
7671 .map(|response| {
7672 let response = GetHover { position }.response_from_proto(
7673 response.response,
7674 lsp_store.clone(),
7675 buffer.clone(),
7676 cx.clone(),
7677 );
7678 async move {
7679 response
7680 .await
7681 .log_err()
7682 .flatten()
7683 .and_then(remove_empty_hover_blocks)
7684 }
7685 }),
7686 )
7687 .await
7688 .into_iter()
7689 .flatten()
7690 .collect();
7691 Some(hovers)
7692 })
7693 } else {
7694 let all_actions_task = self.request_multiple_lsp_locally(
7695 buffer,
7696 Some(position),
7697 GetHover { position },
7698 cx,
7699 );
7700 cx.background_spawn(async move {
7701 Some(
7702 all_actions_task
7703 .await
7704 .into_iter()
7705 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7706 .collect::<Vec<Hover>>(),
7707 )
7708 })
7709 }
7710 }
7711
7712 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7713 let language_registry = self.languages.clone();
7714
7715 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7716 let request = upstream_client.request(proto::GetProjectSymbols {
7717 project_id: *project_id,
7718 query: query.to_string(),
7719 });
7720 cx.foreground_executor().spawn(async move {
7721 let response = request.await?;
7722 let mut symbols = Vec::new();
7723 let core_symbols = response
7724 .symbols
7725 .into_iter()
7726 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7727 .collect::<Vec<_>>();
7728 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7729 .await;
7730 Ok(symbols)
7731 })
7732 } else if let Some(local) = self.as_local() {
7733 struct WorkspaceSymbolsResult {
7734 server_id: LanguageServerId,
7735 lsp_adapter: Arc<CachedLspAdapter>,
7736 worktree: WeakEntity<Worktree>,
7737 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7738 }
7739
7740 let mut requests = Vec::new();
7741 let mut requested_servers = BTreeSet::new();
7742 for (seed, state) in local.language_server_ids.iter() {
7743 let Some(worktree_handle) = self
7744 .worktree_store
7745 .read(cx)
7746 .worktree_for_id(seed.worktree_id, cx)
7747 else {
7748 continue;
7749 };
7750 let worktree = worktree_handle.read(cx);
7751 if !worktree.is_visible() {
7752 continue;
7753 }
7754
7755 if !requested_servers.insert(state.id) {
7756 continue;
7757 }
7758
7759 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7760 Some(LanguageServerState::Running {
7761 adapter, server, ..
7762 }) => (adapter.clone(), server),
7763
7764 _ => continue,
7765 };
7766 let supports_workspace_symbol_request =
7767 match server.capabilities().workspace_symbol_provider {
7768 Some(OneOf::Left(supported)) => supported,
7769 Some(OneOf::Right(_)) => true,
7770 None => false,
7771 };
7772 if !supports_workspace_symbol_request {
7773 continue;
7774 }
7775 let worktree_handle = worktree_handle.clone();
7776 let server_id = server.server_id();
7777 requests.push(
7778 server
7779 .request::<lsp::request::WorkspaceSymbolRequest>(
7780 lsp::WorkspaceSymbolParams {
7781 query: query.to_string(),
7782 ..Default::default()
7783 },
7784 )
7785 .map(move |response| {
7786 let lsp_symbols = response.into_response()
7787 .context("workspace symbols request")
7788 .log_err()
7789 .flatten()
7790 .map(|symbol_response| match symbol_response {
7791 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7792 flat_responses.into_iter().map(|lsp_symbol| {
7793 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7794 }).collect::<Vec<_>>()
7795 }
7796 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7797 nested_responses.into_iter().filter_map(|lsp_symbol| {
7798 let location = match lsp_symbol.location {
7799 OneOf::Left(location) => location,
7800 OneOf::Right(_) => {
7801 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7802 return None
7803 }
7804 };
7805 Some((lsp_symbol.name, lsp_symbol.kind, location))
7806 }).collect::<Vec<_>>()
7807 }
7808 }).unwrap_or_default();
7809
7810 WorkspaceSymbolsResult {
7811 server_id,
7812 lsp_adapter,
7813 worktree: worktree_handle.downgrade(),
7814 lsp_symbols,
7815 }
7816 }),
7817 );
7818 }
7819
7820 cx.spawn(async move |this, cx| {
7821 let responses = futures::future::join_all(requests).await;
7822 let this = match this.upgrade() {
7823 Some(this) => this,
7824 None => return Ok(Vec::new()),
7825 };
7826
7827 let mut symbols = Vec::new();
7828 for result in responses {
7829 let core_symbols = this.update(cx, |this, cx| {
7830 result
7831 .lsp_symbols
7832 .into_iter()
7833 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7834 let abs_path = symbol_location.uri.to_file_path().ok()?;
7835 let source_worktree = result.worktree.upgrade()?;
7836 let source_worktree_id = source_worktree.read(cx).id();
7837
7838 let path = if let Some((tree, rel_path)) =
7839 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7840 {
7841 let worktree_id = tree.read(cx).id();
7842 SymbolLocation::InProject(ProjectPath {
7843 worktree_id,
7844 path: rel_path,
7845 })
7846 } else {
7847 SymbolLocation::OutsideProject {
7848 signature: this.symbol_signature(&abs_path),
7849 abs_path: abs_path.into(),
7850 }
7851 };
7852
7853 Some(CoreSymbol {
7854 source_language_server_id: result.server_id,
7855 language_server_name: result.lsp_adapter.name.clone(),
7856 source_worktree_id,
7857 path,
7858 kind: symbol_kind,
7859 name: symbol_name,
7860 range: range_from_lsp(symbol_location.range),
7861 })
7862 })
7863 .collect()
7864 })?;
7865
7866 populate_labels_for_symbols(
7867 core_symbols,
7868 &language_registry,
7869 Some(result.lsp_adapter),
7870 &mut symbols,
7871 )
7872 .await;
7873 }
7874
7875 Ok(symbols)
7876 })
7877 } else {
7878 Task::ready(Err(anyhow!("No upstream client or local language server")))
7879 }
7880 }
7881
7882 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7883 let mut summary = DiagnosticSummary::default();
7884 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7885 summary.error_count += path_summary.error_count;
7886 summary.warning_count += path_summary.warning_count;
7887 }
7888 summary
7889 }
7890
7891 /// Returns the diagnostic summary for a specific project path.
7892 pub fn diagnostic_summary_for_path(
7893 &self,
7894 project_path: &ProjectPath,
7895 _: &App,
7896 ) -> DiagnosticSummary {
7897 if let Some(summaries) = self
7898 .diagnostic_summaries
7899 .get(&project_path.worktree_id)
7900 .and_then(|map| map.get(&project_path.path))
7901 {
7902 let (error_count, warning_count) = summaries.iter().fold(
7903 (0, 0),
7904 |(error_count, warning_count), (_language_server_id, summary)| {
7905 (
7906 error_count + summary.error_count,
7907 warning_count + summary.warning_count,
7908 )
7909 },
7910 );
7911
7912 DiagnosticSummary {
7913 error_count,
7914 warning_count,
7915 }
7916 } else {
7917 DiagnosticSummary::default()
7918 }
7919 }
7920
7921 pub fn diagnostic_summaries<'a>(
7922 &'a self,
7923 include_ignored: bool,
7924 cx: &'a App,
7925 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7926 self.worktree_store
7927 .read(cx)
7928 .visible_worktrees(cx)
7929 .filter_map(|worktree| {
7930 let worktree = worktree.read(cx);
7931 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7932 })
7933 .flat_map(move |(worktree, summaries)| {
7934 let worktree_id = worktree.id();
7935 summaries
7936 .iter()
7937 .filter(move |(path, _)| {
7938 include_ignored
7939 || worktree
7940 .entry_for_path(path.as_ref())
7941 .is_some_and(|entry| !entry.is_ignored)
7942 })
7943 .flat_map(move |(path, summaries)| {
7944 summaries.iter().map(move |(server_id, summary)| {
7945 (
7946 ProjectPath {
7947 worktree_id,
7948 path: path.clone(),
7949 },
7950 *server_id,
7951 *summary,
7952 )
7953 })
7954 })
7955 })
7956 }
7957
7958 pub fn on_buffer_edited(
7959 &mut self,
7960 buffer: Entity<Buffer>,
7961 cx: &mut Context<Self>,
7962 ) -> Option<()> {
7963 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7964 Some(
7965 self.as_local()?
7966 .language_servers_for_buffer(buffer, cx)
7967 .map(|i| i.1.clone())
7968 .collect(),
7969 )
7970 })?;
7971
7972 let buffer = buffer.read(cx);
7973 let file = File::from_dyn(buffer.file())?;
7974 let abs_path = file.as_local()?.abs_path(cx);
7975 let uri = lsp::Uri::from_file_path(&abs_path)
7976 .ok()
7977 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7978 .log_err()?;
7979 let next_snapshot = buffer.text_snapshot();
7980 for language_server in language_servers {
7981 let language_server = language_server.clone();
7982
7983 let buffer_snapshots = self
7984 .as_local_mut()?
7985 .buffer_snapshots
7986 .get_mut(&buffer.remote_id())
7987 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7988 let previous_snapshot = buffer_snapshots.last()?;
7989
7990 let build_incremental_change = || {
7991 buffer
7992 .edits_since::<Dimensions<PointUtf16, usize>>(
7993 previous_snapshot.snapshot.version(),
7994 )
7995 .map(|edit| {
7996 let edit_start = edit.new.start.0;
7997 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7998 let new_text = next_snapshot
7999 .text_for_range(edit.new.start.1..edit.new.end.1)
8000 .collect();
8001 lsp::TextDocumentContentChangeEvent {
8002 range: Some(lsp::Range::new(
8003 point_to_lsp(edit_start),
8004 point_to_lsp(edit_end),
8005 )),
8006 range_length: None,
8007 text: new_text,
8008 }
8009 })
8010 .collect()
8011 };
8012
8013 let document_sync_kind = language_server
8014 .capabilities()
8015 .text_document_sync
8016 .as_ref()
8017 .and_then(|sync| match sync {
8018 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8019 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8020 });
8021
8022 let content_changes: Vec<_> = match document_sync_kind {
8023 Some(lsp::TextDocumentSyncKind::FULL) => {
8024 vec![lsp::TextDocumentContentChangeEvent {
8025 range: None,
8026 range_length: None,
8027 text: next_snapshot.text(),
8028 }]
8029 }
8030 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8031 _ => {
8032 #[cfg(any(test, feature = "test-support"))]
8033 {
8034 build_incremental_change()
8035 }
8036
8037 #[cfg(not(any(test, feature = "test-support")))]
8038 {
8039 continue;
8040 }
8041 }
8042 };
8043
8044 let next_version = previous_snapshot.version + 1;
8045 buffer_snapshots.push(LspBufferSnapshot {
8046 version: next_version,
8047 snapshot: next_snapshot.clone(),
8048 });
8049
8050 language_server
8051 .notify::<lsp::notification::DidChangeTextDocument>(
8052 lsp::DidChangeTextDocumentParams {
8053 text_document: lsp::VersionedTextDocumentIdentifier::new(
8054 uri.clone(),
8055 next_version,
8056 ),
8057 content_changes,
8058 },
8059 )
8060 .ok();
8061 self.pull_workspace_diagnostics(language_server.server_id());
8062 }
8063
8064 None
8065 }
8066
8067 pub fn on_buffer_saved(
8068 &mut self,
8069 buffer: Entity<Buffer>,
8070 cx: &mut Context<Self>,
8071 ) -> Option<()> {
8072 let file = File::from_dyn(buffer.read(cx).file())?;
8073 let worktree_id = file.worktree_id(cx);
8074 let abs_path = file.as_local()?.abs_path(cx);
8075 let text_document = lsp::TextDocumentIdentifier {
8076 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8077 };
8078 let local = self.as_local()?;
8079
8080 for server in local.language_servers_for_worktree(worktree_id) {
8081 if let Some(include_text) = include_text(server.as_ref()) {
8082 let text = if include_text {
8083 Some(buffer.read(cx).text())
8084 } else {
8085 None
8086 };
8087 server
8088 .notify::<lsp::notification::DidSaveTextDocument>(
8089 lsp::DidSaveTextDocumentParams {
8090 text_document: text_document.clone(),
8091 text,
8092 },
8093 )
8094 .ok();
8095 }
8096 }
8097
8098 let language_servers = buffer.update(cx, |buffer, cx| {
8099 local.language_server_ids_for_buffer(buffer, cx)
8100 });
8101 for language_server_id in language_servers {
8102 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8103 }
8104
8105 None
8106 }
8107
8108 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8109 maybe!(async move {
8110 let mut refreshed_servers = HashSet::default();
8111 let servers = lsp_store
8112 .update(cx, |lsp_store, cx| {
8113 let local = lsp_store.as_local()?;
8114
8115 let servers = local
8116 .language_server_ids
8117 .iter()
8118 .filter_map(|(seed, state)| {
8119 let worktree = lsp_store
8120 .worktree_store
8121 .read(cx)
8122 .worktree_for_id(seed.worktree_id, cx);
8123 let delegate: Arc<dyn LspAdapterDelegate> =
8124 worktree.map(|worktree| {
8125 LocalLspAdapterDelegate::new(
8126 local.languages.clone(),
8127 &local.environment,
8128 cx.weak_entity(),
8129 &worktree,
8130 local.http_client.clone(),
8131 local.fs.clone(),
8132 cx,
8133 )
8134 })?;
8135 let server_id = state.id;
8136
8137 let states = local.language_servers.get(&server_id)?;
8138
8139 match states {
8140 LanguageServerState::Starting { .. } => None,
8141 LanguageServerState::Running {
8142 adapter, server, ..
8143 } => {
8144 let adapter = adapter.clone();
8145 let server = server.clone();
8146 refreshed_servers.insert(server.name());
8147 let toolchain = seed.toolchain.clone();
8148 Some(cx.spawn(async move |_, cx| {
8149 let settings =
8150 LocalLspStore::workspace_configuration_for_adapter(
8151 adapter.adapter.clone(),
8152 &delegate,
8153 toolchain,
8154 None,
8155 cx,
8156 )
8157 .await
8158 .ok()?;
8159 server
8160 .notify::<lsp::notification::DidChangeConfiguration>(
8161 lsp::DidChangeConfigurationParams { settings },
8162 )
8163 .ok()?;
8164 Some(())
8165 }))
8166 }
8167 }
8168 })
8169 .collect::<Vec<_>>();
8170
8171 Some(servers)
8172 })
8173 .ok()
8174 .flatten()?;
8175
8176 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8177 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8178 // to stop and unregister its language server wrapper.
8179 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8180 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8181 let _: Vec<Option<()>> = join_all(servers).await;
8182
8183 Some(())
8184 })
8185 .await;
8186 }
8187
8188 fn maintain_workspace_config(
8189 external_refresh_requests: watch::Receiver<()>,
8190 cx: &mut Context<Self>,
8191 ) -> Task<Result<()>> {
8192 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8193 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8194
8195 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8196 *settings_changed_tx.borrow_mut() = ();
8197 });
8198
8199 let mut joint_future =
8200 futures::stream::select(settings_changed_rx, external_refresh_requests);
8201 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8202 // - 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).
8203 // - 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.
8204 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8205 // - 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,
8206 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8207 cx.spawn(async move |this, cx| {
8208 while let Some(()) = joint_future.next().await {
8209 this.update(cx, |this, cx| {
8210 this.refresh_server_tree(cx);
8211 })
8212 .ok();
8213
8214 Self::refresh_workspace_configurations(&this, cx).await;
8215 }
8216
8217 drop(settings_observation);
8218 anyhow::Ok(())
8219 })
8220 }
8221
8222 pub fn running_language_servers_for_local_buffer<'a>(
8223 &'a self,
8224 buffer: &Buffer,
8225 cx: &mut App,
8226 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8227 let local = self.as_local();
8228 let language_server_ids = local
8229 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8230 .unwrap_or_default();
8231
8232 language_server_ids
8233 .into_iter()
8234 .filter_map(
8235 move |server_id| match local?.language_servers.get(&server_id)? {
8236 LanguageServerState::Running {
8237 adapter, server, ..
8238 } => Some((adapter, server)),
8239 _ => None,
8240 },
8241 )
8242 }
8243
8244 pub fn language_servers_for_local_buffer(
8245 &self,
8246 buffer: &Buffer,
8247 cx: &mut App,
8248 ) -> Vec<LanguageServerId> {
8249 let local = self.as_local();
8250 local
8251 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8252 .unwrap_or_default()
8253 }
8254
8255 pub fn language_server_for_local_buffer<'a>(
8256 &'a self,
8257 buffer: &'a Buffer,
8258 server_id: LanguageServerId,
8259 cx: &'a mut App,
8260 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8261 self.as_local()?
8262 .language_servers_for_buffer(buffer, cx)
8263 .find(|(_, s)| s.server_id() == server_id)
8264 }
8265
8266 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8267 self.diagnostic_summaries.remove(&id_to_remove);
8268 if let Some(local) = self.as_local_mut() {
8269 let to_remove = local.remove_worktree(id_to_remove, cx);
8270 for server in to_remove {
8271 self.language_server_statuses.remove(&server);
8272 }
8273 }
8274 }
8275
8276 pub fn shared(
8277 &mut self,
8278 project_id: u64,
8279 downstream_client: AnyProtoClient,
8280 _: &mut Context<Self>,
8281 ) {
8282 self.downstream_client = Some((downstream_client.clone(), project_id));
8283
8284 for (server_id, status) in &self.language_server_statuses {
8285 if let Some(server) = self.language_server_for_id(*server_id) {
8286 downstream_client
8287 .send(proto::StartLanguageServer {
8288 project_id,
8289 server: Some(proto::LanguageServer {
8290 id: server_id.to_proto(),
8291 name: status.name.to_string(),
8292 worktree_id: status.worktree.map(|id| id.to_proto()),
8293 }),
8294 capabilities: serde_json::to_string(&server.capabilities())
8295 .expect("serializing server LSP capabilities"),
8296 })
8297 .log_err();
8298 }
8299 }
8300 }
8301
8302 pub fn disconnected_from_host(&mut self) {
8303 self.downstream_client.take();
8304 }
8305
8306 pub fn disconnected_from_ssh_remote(&mut self) {
8307 if let LspStoreMode::Remote(RemoteLspStore {
8308 upstream_client, ..
8309 }) = &mut self.mode
8310 {
8311 upstream_client.take();
8312 }
8313 }
8314
8315 pub(crate) fn set_language_server_statuses_from_proto(
8316 &mut self,
8317 project: WeakEntity<Project>,
8318 language_servers: Vec<proto::LanguageServer>,
8319 server_capabilities: Vec<String>,
8320 cx: &mut Context<Self>,
8321 ) {
8322 let lsp_logs = cx
8323 .try_global::<GlobalLogStore>()
8324 .map(|lsp_store| lsp_store.0.clone());
8325
8326 self.language_server_statuses = language_servers
8327 .into_iter()
8328 .zip(server_capabilities)
8329 .map(|(server, server_capabilities)| {
8330 let server_id = LanguageServerId(server.id as usize);
8331 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8332 self.lsp_server_capabilities
8333 .insert(server_id, server_capabilities);
8334 }
8335
8336 let name = LanguageServerName::from_proto(server.name);
8337 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8338
8339 if let Some(lsp_logs) = &lsp_logs {
8340 lsp_logs.update(cx, |lsp_logs, cx| {
8341 lsp_logs.add_language_server(
8342 // Only remote clients get their language servers set from proto
8343 LanguageServerKind::Remote {
8344 project: project.clone(),
8345 },
8346 server_id,
8347 Some(name.clone()),
8348 worktree,
8349 None,
8350 cx,
8351 );
8352 });
8353 }
8354
8355 (
8356 server_id,
8357 LanguageServerStatus {
8358 name,
8359 pending_work: Default::default(),
8360 has_pending_diagnostic_updates: false,
8361 progress_tokens: Default::default(),
8362 worktree,
8363 binary: None,
8364 configuration: None,
8365 workspace_folders: BTreeSet::new(),
8366 },
8367 )
8368 })
8369 .collect();
8370 }
8371
8372 #[cfg(test)]
8373 pub fn update_diagnostic_entries(
8374 &mut self,
8375 server_id: LanguageServerId,
8376 abs_path: PathBuf,
8377 result_id: Option<SharedString>,
8378 version: Option<i32>,
8379 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8380 cx: &mut Context<Self>,
8381 ) -> anyhow::Result<()> {
8382 self.merge_diagnostic_entries(
8383 vec![DocumentDiagnosticsUpdate {
8384 diagnostics: DocumentDiagnostics {
8385 diagnostics,
8386 document_abs_path: abs_path,
8387 version,
8388 },
8389 result_id,
8390 server_id,
8391 disk_based_sources: Cow::Borrowed(&[]),
8392 registration_id: None,
8393 }],
8394 |_, _, _| false,
8395 cx,
8396 )?;
8397 Ok(())
8398 }
8399
8400 pub fn merge_diagnostic_entries<'a>(
8401 &mut self,
8402 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8403 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8404 cx: &mut Context<Self>,
8405 ) -> anyhow::Result<()> {
8406 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8407 let mut updated_diagnostics_paths = HashMap::default();
8408 for mut update in diagnostic_updates {
8409 let abs_path = &update.diagnostics.document_abs_path;
8410 let server_id = update.server_id;
8411 let Some((worktree, relative_path)) =
8412 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8413 else {
8414 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8415 return Ok(());
8416 };
8417
8418 let worktree_id = worktree.read(cx).id();
8419 let project_path = ProjectPath {
8420 worktree_id,
8421 path: relative_path,
8422 };
8423
8424 let document_uri = lsp::Uri::from_file_path(abs_path)
8425 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8426 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8427 let snapshot = buffer_handle.read(cx).snapshot();
8428 let buffer = buffer_handle.read(cx);
8429 let reused_diagnostics = buffer
8430 .buffer_diagnostics(Some(server_id))
8431 .iter()
8432 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8433 .map(|v| {
8434 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8435 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8436 DiagnosticEntry {
8437 range: start..end,
8438 diagnostic: v.diagnostic.clone(),
8439 }
8440 })
8441 .collect::<Vec<_>>();
8442
8443 self.as_local_mut()
8444 .context("cannot merge diagnostics on a remote LspStore")?
8445 .update_buffer_diagnostics(
8446 &buffer_handle,
8447 server_id,
8448 Some(update.registration_id),
8449 update.result_id,
8450 update.diagnostics.version,
8451 update.diagnostics.diagnostics.clone(),
8452 reused_diagnostics.clone(),
8453 cx,
8454 )?;
8455
8456 update.diagnostics.diagnostics.extend(reused_diagnostics);
8457 } else if let Some(local) = self.as_local() {
8458 let reused_diagnostics = local
8459 .diagnostics
8460 .get(&worktree_id)
8461 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8462 .and_then(|diagnostics_by_server_id| {
8463 diagnostics_by_server_id
8464 .binary_search_by_key(&server_id, |e| e.0)
8465 .ok()
8466 .map(|ix| &diagnostics_by_server_id[ix].1)
8467 })
8468 .into_iter()
8469 .flatten()
8470 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8471
8472 update
8473 .diagnostics
8474 .diagnostics
8475 .extend(reused_diagnostics.cloned());
8476 }
8477
8478 let updated = worktree.update(cx, |worktree, cx| {
8479 self.update_worktree_diagnostics(
8480 worktree.id(),
8481 server_id,
8482 project_path.path.clone(),
8483 update.diagnostics.diagnostics,
8484 cx,
8485 )
8486 })?;
8487 match updated {
8488 ControlFlow::Continue(new_summary) => {
8489 if let Some((project_id, new_summary)) = new_summary {
8490 match &mut diagnostics_summary {
8491 Some(diagnostics_summary) => {
8492 diagnostics_summary
8493 .more_summaries
8494 .push(proto::DiagnosticSummary {
8495 path: project_path.path.as_ref().to_proto(),
8496 language_server_id: server_id.0 as u64,
8497 error_count: new_summary.error_count,
8498 warning_count: new_summary.warning_count,
8499 })
8500 }
8501 None => {
8502 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8503 project_id,
8504 worktree_id: worktree_id.to_proto(),
8505 summary: Some(proto::DiagnosticSummary {
8506 path: project_path.path.as_ref().to_proto(),
8507 language_server_id: server_id.0 as u64,
8508 error_count: new_summary.error_count,
8509 warning_count: new_summary.warning_count,
8510 }),
8511 more_summaries: Vec::new(),
8512 })
8513 }
8514 }
8515 }
8516 updated_diagnostics_paths
8517 .entry(server_id)
8518 .or_insert_with(Vec::new)
8519 .push(project_path);
8520 }
8521 ControlFlow::Break(()) => {}
8522 }
8523 }
8524
8525 if let Some((diagnostics_summary, (downstream_client, _))) =
8526 diagnostics_summary.zip(self.downstream_client.as_ref())
8527 {
8528 downstream_client.send(diagnostics_summary).log_err();
8529 }
8530 for (server_id, paths) in updated_diagnostics_paths {
8531 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8532 }
8533 Ok(())
8534 }
8535
8536 fn update_worktree_diagnostics(
8537 &mut self,
8538 worktree_id: WorktreeId,
8539 server_id: LanguageServerId,
8540 path_in_worktree: Arc<RelPath>,
8541 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8542 _: &mut Context<Worktree>,
8543 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8544 let local = match &mut self.mode {
8545 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8546 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8547 };
8548
8549 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8550 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8551 let summaries_by_server_id = summaries_for_tree
8552 .entry(path_in_worktree.clone())
8553 .or_default();
8554
8555 let old_summary = summaries_by_server_id
8556 .remove(&server_id)
8557 .unwrap_or_default();
8558
8559 let new_summary = DiagnosticSummary::new(&diagnostics);
8560 if diagnostics.is_empty() {
8561 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8562 {
8563 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8564 diagnostics_by_server_id.remove(ix);
8565 }
8566 if diagnostics_by_server_id.is_empty() {
8567 diagnostics_for_tree.remove(&path_in_worktree);
8568 }
8569 }
8570 } else {
8571 summaries_by_server_id.insert(server_id, new_summary);
8572 let diagnostics_by_server_id = diagnostics_for_tree
8573 .entry(path_in_worktree.clone())
8574 .or_default();
8575 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8576 Ok(ix) => {
8577 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8578 }
8579 Err(ix) => {
8580 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8581 }
8582 }
8583 }
8584
8585 if !old_summary.is_empty() || !new_summary.is_empty() {
8586 if let Some((_, project_id)) = &self.downstream_client {
8587 Ok(ControlFlow::Continue(Some((
8588 *project_id,
8589 proto::DiagnosticSummary {
8590 path: path_in_worktree.to_proto(),
8591 language_server_id: server_id.0 as u64,
8592 error_count: new_summary.error_count as u32,
8593 warning_count: new_summary.warning_count as u32,
8594 },
8595 ))))
8596 } else {
8597 Ok(ControlFlow::Continue(None))
8598 }
8599 } else {
8600 Ok(ControlFlow::Break(()))
8601 }
8602 }
8603
8604 pub fn open_buffer_for_symbol(
8605 &mut self,
8606 symbol: &Symbol,
8607 cx: &mut Context<Self>,
8608 ) -> Task<Result<Entity<Buffer>>> {
8609 if let Some((client, project_id)) = self.upstream_client() {
8610 let request = client.request(proto::OpenBufferForSymbol {
8611 project_id,
8612 symbol: Some(Self::serialize_symbol(symbol)),
8613 });
8614 cx.spawn(async move |this, cx| {
8615 let response = request.await?;
8616 let buffer_id = BufferId::new(response.buffer_id)?;
8617 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8618 .await
8619 })
8620 } else if let Some(local) = self.as_local() {
8621 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8622 seed.worktree_id == symbol.source_worktree_id
8623 && state.id == symbol.source_language_server_id
8624 && symbol.language_server_name == seed.name
8625 });
8626 if !is_valid {
8627 return Task::ready(Err(anyhow!(
8628 "language server for worktree and language not found"
8629 )));
8630 };
8631
8632 let symbol_abs_path = match &symbol.path {
8633 SymbolLocation::InProject(project_path) => self
8634 .worktree_store
8635 .read(cx)
8636 .absolutize(&project_path, cx)
8637 .context("no such worktree"),
8638 SymbolLocation::OutsideProject {
8639 abs_path,
8640 signature: _,
8641 } => Ok(abs_path.to_path_buf()),
8642 };
8643 let symbol_abs_path = match symbol_abs_path {
8644 Ok(abs_path) => abs_path,
8645 Err(err) => return Task::ready(Err(err)),
8646 };
8647 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8648 uri
8649 } else {
8650 return Task::ready(Err(anyhow!("invalid symbol path")));
8651 };
8652
8653 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8654 } else {
8655 Task::ready(Err(anyhow!("no upstream client or local store")))
8656 }
8657 }
8658
8659 pub(crate) fn open_local_buffer_via_lsp(
8660 &mut self,
8661 abs_path: lsp::Uri,
8662 language_server_id: LanguageServerId,
8663 cx: &mut Context<Self>,
8664 ) -> Task<Result<Entity<Buffer>>> {
8665 cx.spawn(async move |lsp_store, cx| {
8666 // Escape percent-encoded string.
8667 let current_scheme = abs_path.scheme().to_owned();
8668 // Uri is immutable, so we can't modify the scheme
8669
8670 let abs_path = abs_path
8671 .to_file_path()
8672 .map_err(|()| anyhow!("can't convert URI to path"))?;
8673 let p = abs_path.clone();
8674 let yarn_worktree = lsp_store
8675 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8676 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8677 cx.spawn(async move |this, cx| {
8678 let t = this
8679 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8680 .ok()?;
8681 t.await
8682 })
8683 }),
8684 None => Task::ready(None),
8685 })?
8686 .await;
8687 let (worktree_root_target, known_relative_path) =
8688 if let Some((zip_root, relative_path)) = yarn_worktree {
8689 (zip_root, Some(relative_path))
8690 } else {
8691 (Arc::<Path>::from(abs_path.as_path()), None)
8692 };
8693 let (worktree, relative_path) = if let Some(result) =
8694 lsp_store.update(cx, |lsp_store, cx| {
8695 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8696 worktree_store.find_worktree(&worktree_root_target, cx)
8697 })
8698 })? {
8699 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8700 (result.0, relative_path)
8701 } else {
8702 let worktree = lsp_store
8703 .update(cx, |lsp_store, cx| {
8704 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8705 worktree_store.create_worktree(&worktree_root_target, false, cx)
8706 })
8707 })?
8708 .await?;
8709 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8710 lsp_store
8711 .update(cx, |lsp_store, cx| {
8712 if let Some(local) = lsp_store.as_local_mut() {
8713 local.register_language_server_for_invisible_worktree(
8714 &worktree,
8715 language_server_id,
8716 cx,
8717 )
8718 }
8719 })
8720 .ok();
8721 }
8722 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8723 let relative_path = if let Some(known_path) = known_relative_path {
8724 known_path
8725 } else {
8726 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8727 .into_arc()
8728 };
8729 (worktree, relative_path)
8730 };
8731 let project_path = ProjectPath {
8732 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8733 path: relative_path,
8734 };
8735 lsp_store
8736 .update(cx, |lsp_store, cx| {
8737 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8738 buffer_store.open_buffer(project_path, cx)
8739 })
8740 })?
8741 .await
8742 })
8743 }
8744
8745 fn request_multiple_lsp_locally<P, R>(
8746 &mut self,
8747 buffer: &Entity<Buffer>,
8748 position: Option<P>,
8749 request: R,
8750 cx: &mut Context<Self>,
8751 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8752 where
8753 P: ToOffset,
8754 R: LspCommand + Clone,
8755 <R::LspRequest as lsp::request::Request>::Result: Send,
8756 <R::LspRequest as lsp::request::Request>::Params: Send,
8757 {
8758 let Some(local) = self.as_local() else {
8759 return Task::ready(Vec::new());
8760 };
8761
8762 let snapshot = buffer.read(cx).snapshot();
8763 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8764
8765 let server_ids = buffer.update(cx, |buffer, cx| {
8766 local
8767 .language_servers_for_buffer(buffer, cx)
8768 .filter(|(adapter, _)| {
8769 scope
8770 .as_ref()
8771 .map(|scope| scope.language_allowed(&adapter.name))
8772 .unwrap_or(true)
8773 })
8774 .map(|(_, server)| server.server_id())
8775 .filter(|server_id| {
8776 self.as_local().is_none_or(|local| {
8777 local
8778 .buffers_opened_in_servers
8779 .get(&snapshot.remote_id())
8780 .is_some_and(|servers| servers.contains(server_id))
8781 })
8782 })
8783 .collect::<Vec<_>>()
8784 });
8785
8786 let mut response_results = server_ids
8787 .into_iter()
8788 .map(|server_id| {
8789 let task = self.request_lsp(
8790 buffer.clone(),
8791 LanguageServerToQuery::Other(server_id),
8792 request.clone(),
8793 cx,
8794 );
8795 async move { (server_id, task.await) }
8796 })
8797 .collect::<FuturesUnordered<_>>();
8798
8799 cx.background_spawn(async move {
8800 let mut responses = Vec::with_capacity(response_results.len());
8801 while let Some((server_id, response_result)) = response_results.next().await {
8802 match response_result {
8803 Ok(response) => responses.push((server_id, response)),
8804 // rust-analyzer likes to error with this when its still loading up
8805 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8806 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8807 }
8808 }
8809 responses
8810 })
8811 }
8812
8813 async fn handle_lsp_get_completions(
8814 this: Entity<Self>,
8815 envelope: TypedEnvelope<proto::GetCompletions>,
8816 mut cx: AsyncApp,
8817 ) -> Result<proto::GetCompletionsResponse> {
8818 let sender_id = envelope.original_sender_id().unwrap_or_default();
8819
8820 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8821 let buffer_handle = this.update(&mut cx, |this, cx| {
8822 this.buffer_store.read(cx).get_existing(buffer_id)
8823 })??;
8824 let request = GetCompletions::from_proto(
8825 envelope.payload,
8826 this.clone(),
8827 buffer_handle.clone(),
8828 cx.clone(),
8829 )
8830 .await?;
8831
8832 let server_to_query = match request.server_id {
8833 Some(server_id) => LanguageServerToQuery::Other(server_id),
8834 None => LanguageServerToQuery::FirstCapable,
8835 };
8836
8837 let response = this
8838 .update(&mut cx, |this, cx| {
8839 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8840 })?
8841 .await?;
8842 this.update(&mut cx, |this, cx| {
8843 Ok(GetCompletions::response_to_proto(
8844 response,
8845 this,
8846 sender_id,
8847 &buffer_handle.read(cx).version(),
8848 cx,
8849 ))
8850 })?
8851 }
8852
8853 async fn handle_lsp_command<T: LspCommand>(
8854 this: Entity<Self>,
8855 envelope: TypedEnvelope<T::ProtoRequest>,
8856 mut cx: AsyncApp,
8857 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8858 where
8859 <T::LspRequest as lsp::request::Request>::Params: Send,
8860 <T::LspRequest as lsp::request::Request>::Result: Send,
8861 {
8862 let sender_id = envelope.original_sender_id().unwrap_or_default();
8863 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8864 let buffer_handle = this.update(&mut cx, |this, cx| {
8865 this.buffer_store.read(cx).get_existing(buffer_id)
8866 })??;
8867 let request = T::from_proto(
8868 envelope.payload,
8869 this.clone(),
8870 buffer_handle.clone(),
8871 cx.clone(),
8872 )
8873 .await?;
8874 let response = this
8875 .update(&mut cx, |this, cx| {
8876 this.request_lsp(
8877 buffer_handle.clone(),
8878 LanguageServerToQuery::FirstCapable,
8879 request,
8880 cx,
8881 )
8882 })?
8883 .await?;
8884 this.update(&mut cx, |this, cx| {
8885 Ok(T::response_to_proto(
8886 response,
8887 this,
8888 sender_id,
8889 &buffer_handle.read(cx).version(),
8890 cx,
8891 ))
8892 })?
8893 }
8894
8895 async fn handle_lsp_query(
8896 lsp_store: Entity<Self>,
8897 envelope: TypedEnvelope<proto::LspQuery>,
8898 mut cx: AsyncApp,
8899 ) -> Result<proto::Ack> {
8900 use proto::lsp_query::Request;
8901 let sender_id = envelope.original_sender_id().unwrap_or_default();
8902 let lsp_query = envelope.payload;
8903 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8904 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8905 match lsp_query.request.context("invalid LSP query request")? {
8906 Request::GetReferences(get_references) => {
8907 let position = get_references.position.clone().and_then(deserialize_anchor);
8908 Self::query_lsp_locally::<GetReferences>(
8909 lsp_store,
8910 server_id,
8911 sender_id,
8912 lsp_request_id,
8913 get_references,
8914 position,
8915 &mut cx,
8916 )
8917 .await?;
8918 }
8919 Request::GetDocumentColor(get_document_color) => {
8920 Self::query_lsp_locally::<GetDocumentColor>(
8921 lsp_store,
8922 server_id,
8923 sender_id,
8924 lsp_request_id,
8925 get_document_color,
8926 None,
8927 &mut cx,
8928 )
8929 .await?;
8930 }
8931 Request::GetHover(get_hover) => {
8932 let position = get_hover.position.clone().and_then(deserialize_anchor);
8933 Self::query_lsp_locally::<GetHover>(
8934 lsp_store,
8935 server_id,
8936 sender_id,
8937 lsp_request_id,
8938 get_hover,
8939 position,
8940 &mut cx,
8941 )
8942 .await?;
8943 }
8944 Request::GetCodeActions(get_code_actions) => {
8945 Self::query_lsp_locally::<GetCodeActions>(
8946 lsp_store,
8947 server_id,
8948 sender_id,
8949 lsp_request_id,
8950 get_code_actions,
8951 None,
8952 &mut cx,
8953 )
8954 .await?;
8955 }
8956 Request::GetSignatureHelp(get_signature_help) => {
8957 let position = get_signature_help
8958 .position
8959 .clone()
8960 .and_then(deserialize_anchor);
8961 Self::query_lsp_locally::<GetSignatureHelp>(
8962 lsp_store,
8963 server_id,
8964 sender_id,
8965 lsp_request_id,
8966 get_signature_help,
8967 position,
8968 &mut cx,
8969 )
8970 .await?;
8971 }
8972 Request::GetCodeLens(get_code_lens) => {
8973 Self::query_lsp_locally::<GetCodeLens>(
8974 lsp_store,
8975 server_id,
8976 sender_id,
8977 lsp_request_id,
8978 get_code_lens,
8979 None,
8980 &mut cx,
8981 )
8982 .await?;
8983 }
8984 Request::GetDefinition(get_definition) => {
8985 let position = get_definition.position.clone().and_then(deserialize_anchor);
8986 Self::query_lsp_locally::<GetDefinitions>(
8987 lsp_store,
8988 server_id,
8989 sender_id,
8990 lsp_request_id,
8991 get_definition,
8992 position,
8993 &mut cx,
8994 )
8995 .await?;
8996 }
8997 Request::GetDeclaration(get_declaration) => {
8998 let position = get_declaration
8999 .position
9000 .clone()
9001 .and_then(deserialize_anchor);
9002 Self::query_lsp_locally::<GetDeclarations>(
9003 lsp_store,
9004 server_id,
9005 sender_id,
9006 lsp_request_id,
9007 get_declaration,
9008 position,
9009 &mut cx,
9010 )
9011 .await?;
9012 }
9013 Request::GetTypeDefinition(get_type_definition) => {
9014 let position = get_type_definition
9015 .position
9016 .clone()
9017 .and_then(deserialize_anchor);
9018 Self::query_lsp_locally::<GetTypeDefinitions>(
9019 lsp_store,
9020 server_id,
9021 sender_id,
9022 lsp_request_id,
9023 get_type_definition,
9024 position,
9025 &mut cx,
9026 )
9027 .await?;
9028 }
9029 Request::GetImplementation(get_implementation) => {
9030 let position = get_implementation
9031 .position
9032 .clone()
9033 .and_then(deserialize_anchor);
9034 Self::query_lsp_locally::<GetImplementations>(
9035 lsp_store,
9036 server_id,
9037 sender_id,
9038 lsp_request_id,
9039 get_implementation,
9040 position,
9041 &mut cx,
9042 )
9043 .await?;
9044 }
9045 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9046 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9047 let version = deserialize_version(get_document_diagnostics.buffer_version());
9048 let buffer = lsp_store.update(&mut cx, |this, cx| {
9049 this.buffer_store.read(cx).get_existing(buffer_id)
9050 })??;
9051 buffer
9052 .update(&mut cx, |buffer, _| {
9053 buffer.wait_for_version(version.clone())
9054 })?
9055 .await?;
9056 lsp_store.update(&mut cx, |lsp_store, cx| {
9057 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9058 let key = LspKey {
9059 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9060 server_queried: server_id,
9061 };
9062 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9063 ) {
9064 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9065 lsp_requests.clear();
9066 };
9067 }
9068
9069 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9070 existing_queries.insert(
9071 lsp_request_id,
9072 cx.spawn(async move |lsp_store, cx| {
9073 let diagnostics_pull = lsp_store
9074 .update(cx, |lsp_store, cx| {
9075 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9076 })
9077 .ok();
9078 if let Some(diagnostics_pull) = diagnostics_pull {
9079 match diagnostics_pull.await {
9080 Ok(()) => {}
9081 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9082 };
9083 }
9084 }),
9085 );
9086 })?;
9087 }
9088 Request::InlayHints(inlay_hints) => {
9089 let query_start = inlay_hints
9090 .start
9091 .clone()
9092 .and_then(deserialize_anchor)
9093 .context("invalid inlay hints range start")?;
9094 let query_end = inlay_hints
9095 .end
9096 .clone()
9097 .and_then(deserialize_anchor)
9098 .context("invalid inlay hints range end")?;
9099 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9100 &lsp_store,
9101 server_id,
9102 lsp_request_id,
9103 &inlay_hints,
9104 query_start..query_end,
9105 &mut cx,
9106 )
9107 .await
9108 .context("preparing inlay hints request")?;
9109 Self::query_lsp_locally::<InlayHints>(
9110 lsp_store,
9111 server_id,
9112 sender_id,
9113 lsp_request_id,
9114 inlay_hints,
9115 None,
9116 &mut cx,
9117 )
9118 .await
9119 .context("querying for inlay hints")?
9120 }
9121 }
9122 Ok(proto::Ack {})
9123 }
9124
9125 async fn handle_lsp_query_response(
9126 lsp_store: Entity<Self>,
9127 envelope: TypedEnvelope<proto::LspQueryResponse>,
9128 cx: AsyncApp,
9129 ) -> Result<()> {
9130 lsp_store.read_with(&cx, |lsp_store, _| {
9131 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9132 upstream_client.handle_lsp_response(envelope.clone());
9133 }
9134 })?;
9135 Ok(())
9136 }
9137
9138 async fn handle_apply_code_action(
9139 this: Entity<Self>,
9140 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9141 mut cx: AsyncApp,
9142 ) -> Result<proto::ApplyCodeActionResponse> {
9143 let sender_id = envelope.original_sender_id().unwrap_or_default();
9144 let action =
9145 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9146 let apply_code_action = this.update(&mut cx, |this, cx| {
9147 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9148 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9149 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9150 })??;
9151
9152 let project_transaction = apply_code_action.await?;
9153 let project_transaction = this.update(&mut cx, |this, cx| {
9154 this.buffer_store.update(cx, |buffer_store, cx| {
9155 buffer_store.serialize_project_transaction_for_peer(
9156 project_transaction,
9157 sender_id,
9158 cx,
9159 )
9160 })
9161 })?;
9162 Ok(proto::ApplyCodeActionResponse {
9163 transaction: Some(project_transaction),
9164 })
9165 }
9166
9167 async fn handle_register_buffer_with_language_servers(
9168 this: Entity<Self>,
9169 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9170 mut cx: AsyncApp,
9171 ) -> Result<proto::Ack> {
9172 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9173 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9174 this.update(&mut cx, |this, cx| {
9175 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9176 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9177 project_id: upstream_project_id,
9178 buffer_id: buffer_id.to_proto(),
9179 only_servers: envelope.payload.only_servers,
9180 });
9181 }
9182
9183 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9184 anyhow::bail!("buffer is not open");
9185 };
9186
9187 let handle = this.register_buffer_with_language_servers(
9188 &buffer,
9189 envelope
9190 .payload
9191 .only_servers
9192 .into_iter()
9193 .filter_map(|selector| {
9194 Some(match selector.selector? {
9195 proto::language_server_selector::Selector::ServerId(server_id) => {
9196 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9197 }
9198 proto::language_server_selector::Selector::Name(name) => {
9199 LanguageServerSelector::Name(LanguageServerName(
9200 SharedString::from(name),
9201 ))
9202 }
9203 })
9204 })
9205 .collect(),
9206 false,
9207 cx,
9208 );
9209 this.buffer_store().update(cx, |buffer_store, _| {
9210 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9211 });
9212
9213 Ok(())
9214 })??;
9215 Ok(proto::Ack {})
9216 }
9217
9218 async fn handle_rename_project_entry(
9219 this: Entity<Self>,
9220 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9221 mut cx: AsyncApp,
9222 ) -> Result<proto::ProjectEntryResponse> {
9223 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9224 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9225 let new_path =
9226 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9227
9228 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9229 .update(&mut cx, |this, cx| {
9230 let (worktree, entry) = this
9231 .worktree_store
9232 .read(cx)
9233 .worktree_and_entry_for_id(entry_id, cx)?;
9234 let new_worktree = this
9235 .worktree_store
9236 .read(cx)
9237 .worktree_for_id(new_worktree_id, cx)?;
9238 Some((
9239 this.worktree_store.clone(),
9240 worktree,
9241 new_worktree,
9242 entry.clone(),
9243 ))
9244 })?
9245 .context("worktree not found")?;
9246 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9247 (worktree.absolutize(&old_entry.path), worktree.id())
9248 })?;
9249 let new_abs_path =
9250 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9251
9252 let _transaction = Self::will_rename_entry(
9253 this.downgrade(),
9254 old_worktree_id,
9255 &old_abs_path,
9256 &new_abs_path,
9257 old_entry.is_dir(),
9258 cx.clone(),
9259 )
9260 .await;
9261 let response = WorktreeStore::handle_rename_project_entry(
9262 worktree_store,
9263 envelope.payload,
9264 cx.clone(),
9265 )
9266 .await;
9267 this.read_with(&cx, |this, _| {
9268 this.did_rename_entry(
9269 old_worktree_id,
9270 &old_abs_path,
9271 &new_abs_path,
9272 old_entry.is_dir(),
9273 );
9274 })
9275 .ok();
9276 response
9277 }
9278
9279 async fn handle_update_diagnostic_summary(
9280 this: Entity<Self>,
9281 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9282 mut cx: AsyncApp,
9283 ) -> Result<()> {
9284 this.update(&mut cx, |lsp_store, cx| {
9285 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9286 let mut updated_diagnostics_paths = HashMap::default();
9287 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9288 for message_summary in envelope
9289 .payload
9290 .summary
9291 .into_iter()
9292 .chain(envelope.payload.more_summaries)
9293 {
9294 let project_path = ProjectPath {
9295 worktree_id,
9296 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9297 };
9298 let path = project_path.path.clone();
9299 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9300 let summary = DiagnosticSummary {
9301 error_count: message_summary.error_count as usize,
9302 warning_count: message_summary.warning_count as usize,
9303 };
9304
9305 if summary.is_empty() {
9306 if let Some(worktree_summaries) =
9307 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9308 && let Some(summaries) = worktree_summaries.get_mut(&path)
9309 {
9310 summaries.remove(&server_id);
9311 if summaries.is_empty() {
9312 worktree_summaries.remove(&path);
9313 }
9314 }
9315 } else {
9316 lsp_store
9317 .diagnostic_summaries
9318 .entry(worktree_id)
9319 .or_default()
9320 .entry(path)
9321 .or_default()
9322 .insert(server_id, summary);
9323 }
9324
9325 if let Some((_, project_id)) = &lsp_store.downstream_client {
9326 match &mut diagnostics_summary {
9327 Some(diagnostics_summary) => {
9328 diagnostics_summary
9329 .more_summaries
9330 .push(proto::DiagnosticSummary {
9331 path: project_path.path.as_ref().to_proto(),
9332 language_server_id: server_id.0 as u64,
9333 error_count: summary.error_count as u32,
9334 warning_count: summary.warning_count as u32,
9335 })
9336 }
9337 None => {
9338 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9339 project_id: *project_id,
9340 worktree_id: worktree_id.to_proto(),
9341 summary: Some(proto::DiagnosticSummary {
9342 path: project_path.path.as_ref().to_proto(),
9343 language_server_id: server_id.0 as u64,
9344 error_count: summary.error_count as u32,
9345 warning_count: summary.warning_count as u32,
9346 }),
9347 more_summaries: Vec::new(),
9348 })
9349 }
9350 }
9351 }
9352 updated_diagnostics_paths
9353 .entry(server_id)
9354 .or_insert_with(Vec::new)
9355 .push(project_path);
9356 }
9357
9358 if let Some((diagnostics_summary, (downstream_client, _))) =
9359 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9360 {
9361 downstream_client.send(diagnostics_summary).log_err();
9362 }
9363 for (server_id, paths) in updated_diagnostics_paths {
9364 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9365 }
9366 Ok(())
9367 })?
9368 }
9369
9370 async fn handle_start_language_server(
9371 lsp_store: Entity<Self>,
9372 envelope: TypedEnvelope<proto::StartLanguageServer>,
9373 mut cx: AsyncApp,
9374 ) -> Result<()> {
9375 let server = envelope.payload.server.context("invalid server")?;
9376 let server_capabilities =
9377 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9378 .with_context(|| {
9379 format!(
9380 "incorrect server capabilities {}",
9381 envelope.payload.capabilities
9382 )
9383 })?;
9384 lsp_store.update(&mut cx, |lsp_store, cx| {
9385 let server_id = LanguageServerId(server.id as usize);
9386 let server_name = LanguageServerName::from_proto(server.name.clone());
9387 lsp_store
9388 .lsp_server_capabilities
9389 .insert(server_id, server_capabilities);
9390 lsp_store.language_server_statuses.insert(
9391 server_id,
9392 LanguageServerStatus {
9393 name: server_name.clone(),
9394 pending_work: Default::default(),
9395 has_pending_diagnostic_updates: false,
9396 progress_tokens: Default::default(),
9397 worktree: server.worktree_id.map(WorktreeId::from_proto),
9398 binary: None,
9399 configuration: None,
9400 workspace_folders: BTreeSet::new(),
9401 },
9402 );
9403 cx.emit(LspStoreEvent::LanguageServerAdded(
9404 server_id,
9405 server_name,
9406 server.worktree_id.map(WorktreeId::from_proto),
9407 ));
9408 cx.notify();
9409 })?;
9410 Ok(())
9411 }
9412
9413 async fn handle_update_language_server(
9414 lsp_store: Entity<Self>,
9415 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9416 mut cx: AsyncApp,
9417 ) -> Result<()> {
9418 lsp_store.update(&mut cx, |lsp_store, cx| {
9419 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9420
9421 match envelope.payload.variant.context("invalid variant")? {
9422 proto::update_language_server::Variant::WorkStart(payload) => {
9423 lsp_store.on_lsp_work_start(
9424 language_server_id,
9425 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9426 .context("invalid progress token value")?,
9427 LanguageServerProgress {
9428 title: payload.title,
9429 is_disk_based_diagnostics_progress: false,
9430 is_cancellable: payload.is_cancellable.unwrap_or(false),
9431 message: payload.message,
9432 percentage: payload.percentage.map(|p| p as usize),
9433 last_update_at: cx.background_executor().now(),
9434 },
9435 cx,
9436 );
9437 }
9438 proto::update_language_server::Variant::WorkProgress(payload) => {
9439 lsp_store.on_lsp_work_progress(
9440 language_server_id,
9441 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9442 .context("invalid progress token value")?,
9443 LanguageServerProgress {
9444 title: None,
9445 is_disk_based_diagnostics_progress: false,
9446 is_cancellable: payload.is_cancellable.unwrap_or(false),
9447 message: payload.message,
9448 percentage: payload.percentage.map(|p| p as usize),
9449 last_update_at: cx.background_executor().now(),
9450 },
9451 cx,
9452 );
9453 }
9454
9455 proto::update_language_server::Variant::WorkEnd(payload) => {
9456 lsp_store.on_lsp_work_end(
9457 language_server_id,
9458 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9459 .context("invalid progress token value")?,
9460 cx,
9461 );
9462 }
9463
9464 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9465 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9466 }
9467
9468 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9469 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9470 }
9471
9472 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9473 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9474 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9475 cx.emit(LspStoreEvent::LanguageServerUpdate {
9476 language_server_id,
9477 name: envelope
9478 .payload
9479 .server_name
9480 .map(SharedString::new)
9481 .map(LanguageServerName),
9482 message: non_lsp,
9483 });
9484 }
9485 }
9486
9487 Ok(())
9488 })?
9489 }
9490
9491 async fn handle_language_server_log(
9492 this: Entity<Self>,
9493 envelope: TypedEnvelope<proto::LanguageServerLog>,
9494 mut cx: AsyncApp,
9495 ) -> Result<()> {
9496 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9497 let log_type = envelope
9498 .payload
9499 .log_type
9500 .map(LanguageServerLogType::from_proto)
9501 .context("invalid language server log type")?;
9502
9503 let message = envelope.payload.message;
9504
9505 this.update(&mut cx, |_, cx| {
9506 cx.emit(LspStoreEvent::LanguageServerLog(
9507 language_server_id,
9508 log_type,
9509 message,
9510 ));
9511 })
9512 }
9513
9514 async fn handle_lsp_ext_cancel_flycheck(
9515 lsp_store: Entity<Self>,
9516 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9517 cx: AsyncApp,
9518 ) -> Result<proto::Ack> {
9519 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9520 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9521 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9522 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9523 } else {
9524 None
9525 }
9526 })?;
9527 if let Some(task) = task {
9528 task.context("handling lsp ext cancel flycheck")?;
9529 }
9530
9531 Ok(proto::Ack {})
9532 }
9533
9534 async fn handle_lsp_ext_run_flycheck(
9535 lsp_store: Entity<Self>,
9536 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9537 mut cx: AsyncApp,
9538 ) -> Result<proto::Ack> {
9539 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9540 lsp_store.update(&mut cx, |lsp_store, cx| {
9541 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9542 let text_document = if envelope.payload.current_file_only {
9543 let buffer_id = envelope
9544 .payload
9545 .buffer_id
9546 .map(|id| BufferId::new(id))
9547 .transpose()?;
9548 buffer_id
9549 .and_then(|buffer_id| {
9550 lsp_store
9551 .buffer_store()
9552 .read(cx)
9553 .get(buffer_id)
9554 .and_then(|buffer| {
9555 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9556 })
9557 .map(|path| make_text_document_identifier(&path))
9558 })
9559 .transpose()?
9560 } else {
9561 None
9562 };
9563 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9564 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9565 )?;
9566 }
9567 anyhow::Ok(())
9568 })??;
9569
9570 Ok(proto::Ack {})
9571 }
9572
9573 async fn handle_lsp_ext_clear_flycheck(
9574 lsp_store: Entity<Self>,
9575 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9576 cx: AsyncApp,
9577 ) -> Result<proto::Ack> {
9578 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9579 lsp_store
9580 .read_with(&cx, |lsp_store, _| {
9581 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9582 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9583 } else {
9584 None
9585 }
9586 })
9587 .context("handling lsp ext clear flycheck")?;
9588
9589 Ok(proto::Ack {})
9590 }
9591
9592 pub fn disk_based_diagnostics_started(
9593 &mut self,
9594 language_server_id: LanguageServerId,
9595 cx: &mut Context<Self>,
9596 ) {
9597 if let Some(language_server_status) =
9598 self.language_server_statuses.get_mut(&language_server_id)
9599 {
9600 language_server_status.has_pending_diagnostic_updates = true;
9601 }
9602
9603 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9604 cx.emit(LspStoreEvent::LanguageServerUpdate {
9605 language_server_id,
9606 name: self
9607 .language_server_adapter_for_id(language_server_id)
9608 .map(|adapter| adapter.name()),
9609 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9610 Default::default(),
9611 ),
9612 })
9613 }
9614
9615 pub fn disk_based_diagnostics_finished(
9616 &mut self,
9617 language_server_id: LanguageServerId,
9618 cx: &mut Context<Self>,
9619 ) {
9620 if let Some(language_server_status) =
9621 self.language_server_statuses.get_mut(&language_server_id)
9622 {
9623 language_server_status.has_pending_diagnostic_updates = false;
9624 }
9625
9626 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9627 cx.emit(LspStoreEvent::LanguageServerUpdate {
9628 language_server_id,
9629 name: self
9630 .language_server_adapter_for_id(language_server_id)
9631 .map(|adapter| adapter.name()),
9632 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9633 Default::default(),
9634 ),
9635 })
9636 }
9637
9638 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9639 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9640 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9641 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9642 // the language server might take some time to publish diagnostics.
9643 fn simulate_disk_based_diagnostics_events_if_needed(
9644 &mut self,
9645 language_server_id: LanguageServerId,
9646 cx: &mut Context<Self>,
9647 ) {
9648 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9649
9650 let Some(LanguageServerState::Running {
9651 simulate_disk_based_diagnostics_completion,
9652 adapter,
9653 ..
9654 }) = self
9655 .as_local_mut()
9656 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9657 else {
9658 return;
9659 };
9660
9661 if adapter.disk_based_diagnostics_progress_token.is_some() {
9662 return;
9663 }
9664
9665 let prev_task =
9666 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9667 cx.background_executor()
9668 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9669 .await;
9670
9671 this.update(cx, |this, cx| {
9672 this.disk_based_diagnostics_finished(language_server_id, cx);
9673
9674 if let Some(LanguageServerState::Running {
9675 simulate_disk_based_diagnostics_completion,
9676 ..
9677 }) = this.as_local_mut().and_then(|local_store| {
9678 local_store.language_servers.get_mut(&language_server_id)
9679 }) {
9680 *simulate_disk_based_diagnostics_completion = None;
9681 }
9682 })
9683 .ok();
9684 }));
9685
9686 if prev_task.is_none() {
9687 self.disk_based_diagnostics_started(language_server_id, cx);
9688 }
9689 }
9690
9691 pub fn language_server_statuses(
9692 &self,
9693 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9694 self.language_server_statuses
9695 .iter()
9696 .map(|(key, value)| (*key, value))
9697 }
9698
9699 pub(super) fn did_rename_entry(
9700 &self,
9701 worktree_id: WorktreeId,
9702 old_path: &Path,
9703 new_path: &Path,
9704 is_dir: bool,
9705 ) {
9706 maybe!({
9707 let local_store = self.as_local()?;
9708
9709 let old_uri = lsp::Uri::from_file_path(old_path)
9710 .ok()
9711 .map(|uri| uri.to_string())?;
9712 let new_uri = lsp::Uri::from_file_path(new_path)
9713 .ok()
9714 .map(|uri| uri.to_string())?;
9715
9716 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9717 let Some(filter) = local_store
9718 .language_server_paths_watched_for_rename
9719 .get(&language_server.server_id())
9720 else {
9721 continue;
9722 };
9723
9724 if filter.should_send_did_rename(&old_uri, is_dir) {
9725 language_server
9726 .notify::<DidRenameFiles>(RenameFilesParams {
9727 files: vec![FileRename {
9728 old_uri: old_uri.clone(),
9729 new_uri: new_uri.clone(),
9730 }],
9731 })
9732 .ok();
9733 }
9734 }
9735 Some(())
9736 });
9737 }
9738
9739 pub(super) fn will_rename_entry(
9740 this: WeakEntity<Self>,
9741 worktree_id: WorktreeId,
9742 old_path: &Path,
9743 new_path: &Path,
9744 is_dir: bool,
9745 cx: AsyncApp,
9746 ) -> Task<ProjectTransaction> {
9747 let old_uri = lsp::Uri::from_file_path(old_path)
9748 .ok()
9749 .map(|uri| uri.to_string());
9750 let new_uri = lsp::Uri::from_file_path(new_path)
9751 .ok()
9752 .map(|uri| uri.to_string());
9753 cx.spawn(async move |cx| {
9754 let mut tasks = vec![];
9755 this.update(cx, |this, cx| {
9756 let local_store = this.as_local()?;
9757 let old_uri = old_uri?;
9758 let new_uri = new_uri?;
9759 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9760 let Some(filter) = local_store
9761 .language_server_paths_watched_for_rename
9762 .get(&language_server.server_id())
9763 else {
9764 continue;
9765 };
9766
9767 if filter.should_send_will_rename(&old_uri, is_dir) {
9768 let apply_edit = cx.spawn({
9769 let old_uri = old_uri.clone();
9770 let new_uri = new_uri.clone();
9771 let language_server = language_server.clone();
9772 async move |this, cx| {
9773 let edit = language_server
9774 .request::<WillRenameFiles>(RenameFilesParams {
9775 files: vec![FileRename { old_uri, new_uri }],
9776 })
9777 .await
9778 .into_response()
9779 .context("will rename files")
9780 .log_err()
9781 .flatten()?;
9782
9783 let transaction = LocalLspStore::deserialize_workspace_edit(
9784 this.upgrade()?,
9785 edit,
9786 false,
9787 language_server.clone(),
9788 cx,
9789 )
9790 .await
9791 .ok()?;
9792 Some(transaction)
9793 }
9794 });
9795 tasks.push(apply_edit);
9796 }
9797 }
9798 Some(())
9799 })
9800 .ok()
9801 .flatten();
9802 let mut merged_transaction = ProjectTransaction::default();
9803 for task in tasks {
9804 // Await on tasks sequentially so that the order of application of edits is deterministic
9805 // (at least with regards to the order of registration of language servers)
9806 if let Some(transaction) = task.await {
9807 for (buffer, buffer_transaction) in transaction.0 {
9808 merged_transaction.0.insert(buffer, buffer_transaction);
9809 }
9810 }
9811 }
9812 merged_transaction
9813 })
9814 }
9815
9816 fn lsp_notify_abs_paths_changed(
9817 &mut self,
9818 server_id: LanguageServerId,
9819 changes: Vec<PathEvent>,
9820 ) {
9821 maybe!({
9822 let server = self.language_server_for_id(server_id)?;
9823 let changes = changes
9824 .into_iter()
9825 .filter_map(|event| {
9826 let typ = match event.kind? {
9827 PathEventKind::Created => lsp::FileChangeType::CREATED,
9828 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9829 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9830 };
9831 Some(lsp::FileEvent {
9832 uri: file_path_to_lsp_url(&event.path).log_err()?,
9833 typ,
9834 })
9835 })
9836 .collect::<Vec<_>>();
9837 if !changes.is_empty() {
9838 server
9839 .notify::<lsp::notification::DidChangeWatchedFiles>(
9840 lsp::DidChangeWatchedFilesParams { changes },
9841 )
9842 .ok();
9843 }
9844 Some(())
9845 });
9846 }
9847
9848 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9849 self.as_local()?.language_server_for_id(id)
9850 }
9851
9852 fn on_lsp_progress(
9853 &mut self,
9854 progress_params: lsp::ProgressParams,
9855 language_server_id: LanguageServerId,
9856 disk_based_diagnostics_progress_token: Option<String>,
9857 cx: &mut Context<Self>,
9858 ) {
9859 match progress_params.value {
9860 lsp::ProgressParamsValue::WorkDone(progress) => {
9861 self.handle_work_done_progress(
9862 progress,
9863 language_server_id,
9864 disk_based_diagnostics_progress_token,
9865 ProgressToken::from_lsp(progress_params.token),
9866 cx,
9867 );
9868 }
9869 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9870 let registration_id = match progress_params.token {
9871 lsp::NumberOrString::Number(_) => None,
9872 lsp::NumberOrString::String(token) => token
9873 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9874 .map(|(_, id)| id.to_owned()),
9875 };
9876 if let Some(LanguageServerState::Running {
9877 workspace_diagnostics_refresh_tasks,
9878 ..
9879 }) = self
9880 .as_local_mut()
9881 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9882 && let Some(workspace_diagnostics) =
9883 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9884 {
9885 workspace_diagnostics.progress_tx.try_send(()).ok();
9886 self.apply_workspace_diagnostic_report(
9887 language_server_id,
9888 report,
9889 registration_id.map(SharedString::from),
9890 cx,
9891 )
9892 }
9893 }
9894 }
9895 }
9896
9897 fn handle_work_done_progress(
9898 &mut self,
9899 progress: lsp::WorkDoneProgress,
9900 language_server_id: LanguageServerId,
9901 disk_based_diagnostics_progress_token: Option<String>,
9902 token: ProgressToken,
9903 cx: &mut Context<Self>,
9904 ) {
9905 let language_server_status =
9906 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9907 status
9908 } else {
9909 return;
9910 };
9911
9912 if !language_server_status.progress_tokens.contains(&token) {
9913 return;
9914 }
9915
9916 let is_disk_based_diagnostics_progress =
9917 if let (Some(disk_based_token), ProgressToken::String(token)) =
9918 (&disk_based_diagnostics_progress_token, &token)
9919 {
9920 token.starts_with(disk_based_token)
9921 } else {
9922 false
9923 };
9924
9925 match progress {
9926 lsp::WorkDoneProgress::Begin(report) => {
9927 if is_disk_based_diagnostics_progress {
9928 self.disk_based_diagnostics_started(language_server_id, cx);
9929 }
9930 self.on_lsp_work_start(
9931 language_server_id,
9932 token.clone(),
9933 LanguageServerProgress {
9934 title: Some(report.title),
9935 is_disk_based_diagnostics_progress,
9936 is_cancellable: report.cancellable.unwrap_or(false),
9937 message: report.message.clone(),
9938 percentage: report.percentage.map(|p| p as usize),
9939 last_update_at: cx.background_executor().now(),
9940 },
9941 cx,
9942 );
9943 }
9944 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9945 language_server_id,
9946 token,
9947 LanguageServerProgress {
9948 title: None,
9949 is_disk_based_diagnostics_progress,
9950 is_cancellable: report.cancellable.unwrap_or(false),
9951 message: report.message,
9952 percentage: report.percentage.map(|p| p as usize),
9953 last_update_at: cx.background_executor().now(),
9954 },
9955 cx,
9956 ),
9957 lsp::WorkDoneProgress::End(_) => {
9958 language_server_status.progress_tokens.remove(&token);
9959 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9960 if is_disk_based_diagnostics_progress {
9961 self.disk_based_diagnostics_finished(language_server_id, cx);
9962 }
9963 }
9964 }
9965 }
9966
9967 fn on_lsp_work_start(
9968 &mut self,
9969 language_server_id: LanguageServerId,
9970 token: ProgressToken,
9971 progress: LanguageServerProgress,
9972 cx: &mut Context<Self>,
9973 ) {
9974 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9975 status.pending_work.insert(token.clone(), progress.clone());
9976 cx.notify();
9977 }
9978 cx.emit(LspStoreEvent::LanguageServerUpdate {
9979 language_server_id,
9980 name: self
9981 .language_server_adapter_for_id(language_server_id)
9982 .map(|adapter| adapter.name()),
9983 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9984 token: Some(token.to_proto()),
9985 title: progress.title,
9986 message: progress.message,
9987 percentage: progress.percentage.map(|p| p as u32),
9988 is_cancellable: Some(progress.is_cancellable),
9989 }),
9990 })
9991 }
9992
9993 fn on_lsp_work_progress(
9994 &mut self,
9995 language_server_id: LanguageServerId,
9996 token: ProgressToken,
9997 progress: LanguageServerProgress,
9998 cx: &mut Context<Self>,
9999 ) {
10000 let mut did_update = false;
10001 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10002 match status.pending_work.entry(token.clone()) {
10003 btree_map::Entry::Vacant(entry) => {
10004 entry.insert(progress.clone());
10005 did_update = true;
10006 }
10007 btree_map::Entry::Occupied(mut entry) => {
10008 let entry = entry.get_mut();
10009 if (progress.last_update_at - entry.last_update_at)
10010 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10011 {
10012 entry.last_update_at = progress.last_update_at;
10013 if progress.message.is_some() {
10014 entry.message = progress.message.clone();
10015 }
10016 if progress.percentage.is_some() {
10017 entry.percentage = progress.percentage;
10018 }
10019 if progress.is_cancellable != entry.is_cancellable {
10020 entry.is_cancellable = progress.is_cancellable;
10021 }
10022 did_update = true;
10023 }
10024 }
10025 }
10026 }
10027
10028 if did_update {
10029 cx.emit(LspStoreEvent::LanguageServerUpdate {
10030 language_server_id,
10031 name: self
10032 .language_server_adapter_for_id(language_server_id)
10033 .map(|adapter| adapter.name()),
10034 message: proto::update_language_server::Variant::WorkProgress(
10035 proto::LspWorkProgress {
10036 token: Some(token.to_proto()),
10037 message: progress.message,
10038 percentage: progress.percentage.map(|p| p as u32),
10039 is_cancellable: Some(progress.is_cancellable),
10040 },
10041 ),
10042 })
10043 }
10044 }
10045
10046 fn on_lsp_work_end(
10047 &mut self,
10048 language_server_id: LanguageServerId,
10049 token: ProgressToken,
10050 cx: &mut Context<Self>,
10051 ) {
10052 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10053 if let Some(work) = status.pending_work.remove(&token)
10054 && !work.is_disk_based_diagnostics_progress
10055 {
10056 cx.emit(LspStoreEvent::RefreshInlayHints {
10057 server_id: language_server_id,
10058 request_id: None,
10059 });
10060 }
10061 cx.notify();
10062 }
10063
10064 cx.emit(LspStoreEvent::LanguageServerUpdate {
10065 language_server_id,
10066 name: self
10067 .language_server_adapter_for_id(language_server_id)
10068 .map(|adapter| adapter.name()),
10069 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10070 token: Some(token.to_proto()),
10071 }),
10072 })
10073 }
10074
10075 pub async fn handle_resolve_completion_documentation(
10076 this: Entity<Self>,
10077 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10078 mut cx: AsyncApp,
10079 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10080 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10081
10082 let completion = this
10083 .read_with(&cx, |this, cx| {
10084 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10085 let server = this
10086 .language_server_for_id(id)
10087 .with_context(|| format!("No language server {id}"))?;
10088
10089 anyhow::Ok(cx.background_spawn(async move {
10090 let can_resolve = server
10091 .capabilities()
10092 .completion_provider
10093 .as_ref()
10094 .and_then(|options| options.resolve_provider)
10095 .unwrap_or(false);
10096 if can_resolve {
10097 server
10098 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10099 .await
10100 .into_response()
10101 .context("resolve completion item")
10102 } else {
10103 anyhow::Ok(lsp_completion)
10104 }
10105 }))
10106 })??
10107 .await?;
10108
10109 let mut documentation_is_markdown = false;
10110 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10111 let documentation = match completion.documentation {
10112 Some(lsp::Documentation::String(text)) => text,
10113
10114 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10115 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10116 value
10117 }
10118
10119 _ => String::new(),
10120 };
10121
10122 // If we have a new buffer_id, that means we're talking to a new client
10123 // and want to check for new text_edits in the completion too.
10124 let mut old_replace_start = None;
10125 let mut old_replace_end = None;
10126 let mut old_insert_start = None;
10127 let mut old_insert_end = None;
10128 let mut new_text = String::default();
10129 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10130 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10131 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10132 anyhow::Ok(buffer.read(cx).snapshot())
10133 })??;
10134
10135 if let Some(text_edit) = completion.text_edit.as_ref() {
10136 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10137
10138 if let Some(mut edit) = edit {
10139 LineEnding::normalize(&mut edit.new_text);
10140
10141 new_text = edit.new_text;
10142 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10143 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10144 if let Some(insert_range) = edit.insert_range {
10145 old_insert_start = Some(serialize_anchor(&insert_range.start));
10146 old_insert_end = Some(serialize_anchor(&insert_range.end));
10147 }
10148 }
10149 }
10150 }
10151
10152 Ok(proto::ResolveCompletionDocumentationResponse {
10153 documentation,
10154 documentation_is_markdown,
10155 old_replace_start,
10156 old_replace_end,
10157 new_text,
10158 lsp_completion,
10159 old_insert_start,
10160 old_insert_end,
10161 })
10162 }
10163
10164 async fn handle_on_type_formatting(
10165 this: Entity<Self>,
10166 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10167 mut cx: AsyncApp,
10168 ) -> Result<proto::OnTypeFormattingResponse> {
10169 let on_type_formatting = this.update(&mut cx, |this, cx| {
10170 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10171 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10172 let position = envelope
10173 .payload
10174 .position
10175 .and_then(deserialize_anchor)
10176 .context("invalid position")?;
10177 anyhow::Ok(this.apply_on_type_formatting(
10178 buffer,
10179 position,
10180 envelope.payload.trigger.clone(),
10181 cx,
10182 ))
10183 })??;
10184
10185 let transaction = on_type_formatting
10186 .await?
10187 .as_ref()
10188 .map(language::proto::serialize_transaction);
10189 Ok(proto::OnTypeFormattingResponse { transaction })
10190 }
10191
10192 async fn handle_refresh_inlay_hints(
10193 lsp_store: Entity<Self>,
10194 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10195 mut cx: AsyncApp,
10196 ) -> Result<proto::Ack> {
10197 lsp_store.update(&mut cx, |_, cx| {
10198 cx.emit(LspStoreEvent::RefreshInlayHints {
10199 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10200 request_id: envelope.payload.request_id.map(|id| id as usize),
10201 });
10202 })?;
10203 Ok(proto::Ack {})
10204 }
10205
10206 async fn handle_pull_workspace_diagnostics(
10207 lsp_store: Entity<Self>,
10208 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10209 mut cx: AsyncApp,
10210 ) -> Result<proto::Ack> {
10211 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10212 lsp_store.update(&mut cx, |lsp_store, _| {
10213 lsp_store.pull_workspace_diagnostics(server_id);
10214 })?;
10215 Ok(proto::Ack {})
10216 }
10217
10218 async fn handle_get_color_presentation(
10219 lsp_store: Entity<Self>,
10220 envelope: TypedEnvelope<proto::GetColorPresentation>,
10221 mut cx: AsyncApp,
10222 ) -> Result<proto::GetColorPresentationResponse> {
10223 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10224 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10225 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10226 })??;
10227
10228 let color = envelope
10229 .payload
10230 .color
10231 .context("invalid color resolve request")?;
10232 let start = color
10233 .lsp_range_start
10234 .context("invalid color resolve request")?;
10235 let end = color
10236 .lsp_range_end
10237 .context("invalid color resolve request")?;
10238
10239 let color = DocumentColor {
10240 lsp_range: lsp::Range {
10241 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10242 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10243 },
10244 color: lsp::Color {
10245 red: color.red,
10246 green: color.green,
10247 blue: color.blue,
10248 alpha: color.alpha,
10249 },
10250 resolved: false,
10251 color_presentations: Vec::new(),
10252 };
10253 let resolved_color = lsp_store
10254 .update(&mut cx, |lsp_store, cx| {
10255 lsp_store.resolve_color_presentation(
10256 color,
10257 buffer.clone(),
10258 LanguageServerId(envelope.payload.server_id as usize),
10259 cx,
10260 )
10261 })?
10262 .await
10263 .context("resolving color presentation")?;
10264
10265 Ok(proto::GetColorPresentationResponse {
10266 presentations: resolved_color
10267 .color_presentations
10268 .into_iter()
10269 .map(|presentation| proto::ColorPresentation {
10270 label: presentation.label.to_string(),
10271 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10272 additional_text_edits: presentation
10273 .additional_text_edits
10274 .into_iter()
10275 .map(serialize_lsp_edit)
10276 .collect(),
10277 })
10278 .collect(),
10279 })
10280 }
10281
10282 async fn handle_resolve_inlay_hint(
10283 lsp_store: Entity<Self>,
10284 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10285 mut cx: AsyncApp,
10286 ) -> Result<proto::ResolveInlayHintResponse> {
10287 let proto_hint = envelope
10288 .payload
10289 .hint
10290 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10291 let hint = InlayHints::proto_to_project_hint(proto_hint)
10292 .context("resolved proto inlay hint conversion")?;
10293 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10294 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10295 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10296 })??;
10297 let response_hint = lsp_store
10298 .update(&mut cx, |lsp_store, cx| {
10299 lsp_store.resolve_inlay_hint(
10300 hint,
10301 buffer,
10302 LanguageServerId(envelope.payload.language_server_id as usize),
10303 cx,
10304 )
10305 })?
10306 .await
10307 .context("inlay hints fetch")?;
10308 Ok(proto::ResolveInlayHintResponse {
10309 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10310 })
10311 }
10312
10313 async fn handle_refresh_code_lens(
10314 this: Entity<Self>,
10315 _: TypedEnvelope<proto::RefreshCodeLens>,
10316 mut cx: AsyncApp,
10317 ) -> Result<proto::Ack> {
10318 this.update(&mut cx, |_, cx| {
10319 cx.emit(LspStoreEvent::RefreshCodeLens);
10320 })?;
10321 Ok(proto::Ack {})
10322 }
10323
10324 async fn handle_open_buffer_for_symbol(
10325 this: Entity<Self>,
10326 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10327 mut cx: AsyncApp,
10328 ) -> Result<proto::OpenBufferForSymbolResponse> {
10329 let peer_id = envelope.original_sender_id().unwrap_or_default();
10330 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10331 let symbol = Self::deserialize_symbol(symbol)?;
10332 this.read_with(&cx, |this, _| {
10333 if let SymbolLocation::OutsideProject {
10334 abs_path,
10335 signature,
10336 } = &symbol.path
10337 {
10338 let new_signature = this.symbol_signature(&abs_path);
10339 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10340 }
10341 Ok(())
10342 })??;
10343 let buffer = this
10344 .update(&mut cx, |this, cx| {
10345 this.open_buffer_for_symbol(
10346 &Symbol {
10347 language_server_name: symbol.language_server_name,
10348 source_worktree_id: symbol.source_worktree_id,
10349 source_language_server_id: symbol.source_language_server_id,
10350 path: symbol.path,
10351 name: symbol.name,
10352 kind: symbol.kind,
10353 range: symbol.range,
10354 label: CodeLabel::default(),
10355 },
10356 cx,
10357 )
10358 })?
10359 .await?;
10360
10361 this.update(&mut cx, |this, cx| {
10362 let is_private = buffer
10363 .read(cx)
10364 .file()
10365 .map(|f| f.is_private())
10366 .unwrap_or_default();
10367 if is_private {
10368 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10369 } else {
10370 this.buffer_store
10371 .update(cx, |buffer_store, cx| {
10372 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10373 })
10374 .detach_and_log_err(cx);
10375 let buffer_id = buffer.read(cx).remote_id().to_proto();
10376 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10377 }
10378 })?
10379 }
10380
10381 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10382 let mut hasher = Sha256::new();
10383 hasher.update(abs_path.to_string_lossy().as_bytes());
10384 hasher.update(self.nonce.to_be_bytes());
10385 hasher.finalize().as_slice().try_into().unwrap()
10386 }
10387
10388 pub async fn handle_get_project_symbols(
10389 this: Entity<Self>,
10390 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10391 mut cx: AsyncApp,
10392 ) -> Result<proto::GetProjectSymbolsResponse> {
10393 let symbols = this
10394 .update(&mut cx, |this, cx| {
10395 this.symbols(&envelope.payload.query, cx)
10396 })?
10397 .await?;
10398
10399 Ok(proto::GetProjectSymbolsResponse {
10400 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10401 })
10402 }
10403
10404 pub async fn handle_restart_language_servers(
10405 this: Entity<Self>,
10406 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10407 mut cx: AsyncApp,
10408 ) -> Result<proto::Ack> {
10409 this.update(&mut cx, |lsp_store, cx| {
10410 let buffers =
10411 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10412 lsp_store.restart_language_servers_for_buffers(
10413 buffers,
10414 envelope
10415 .payload
10416 .only_servers
10417 .into_iter()
10418 .filter_map(|selector| {
10419 Some(match selector.selector? {
10420 proto::language_server_selector::Selector::ServerId(server_id) => {
10421 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10422 }
10423 proto::language_server_selector::Selector::Name(name) => {
10424 LanguageServerSelector::Name(LanguageServerName(
10425 SharedString::from(name),
10426 ))
10427 }
10428 })
10429 })
10430 .collect(),
10431 cx,
10432 );
10433 })?;
10434
10435 Ok(proto::Ack {})
10436 }
10437
10438 pub async fn handle_stop_language_servers(
10439 lsp_store: Entity<Self>,
10440 envelope: TypedEnvelope<proto::StopLanguageServers>,
10441 mut cx: AsyncApp,
10442 ) -> Result<proto::Ack> {
10443 lsp_store.update(&mut cx, |lsp_store, cx| {
10444 if envelope.payload.all
10445 && envelope.payload.also_servers.is_empty()
10446 && envelope.payload.buffer_ids.is_empty()
10447 {
10448 lsp_store.stop_all_language_servers(cx);
10449 } else {
10450 let buffers =
10451 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10452 lsp_store
10453 .stop_language_servers_for_buffers(
10454 buffers,
10455 envelope
10456 .payload
10457 .also_servers
10458 .into_iter()
10459 .filter_map(|selector| {
10460 Some(match selector.selector? {
10461 proto::language_server_selector::Selector::ServerId(
10462 server_id,
10463 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10464 server_id,
10465 )),
10466 proto::language_server_selector::Selector::Name(name) => {
10467 LanguageServerSelector::Name(LanguageServerName(
10468 SharedString::from(name),
10469 ))
10470 }
10471 })
10472 })
10473 .collect(),
10474 cx,
10475 )
10476 .detach_and_log_err(cx);
10477 }
10478 })?;
10479
10480 Ok(proto::Ack {})
10481 }
10482
10483 pub async fn handle_cancel_language_server_work(
10484 lsp_store: Entity<Self>,
10485 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10486 mut cx: AsyncApp,
10487 ) -> Result<proto::Ack> {
10488 lsp_store.update(&mut cx, |lsp_store, cx| {
10489 if let Some(work) = envelope.payload.work {
10490 match work {
10491 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10492 let buffers =
10493 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10494 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10495 }
10496 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10497 let server_id = LanguageServerId::from_proto(work.language_server_id);
10498 let token = work
10499 .token
10500 .map(|token| {
10501 ProgressToken::from_proto(token)
10502 .context("invalid work progress token")
10503 })
10504 .transpose()?;
10505 lsp_store.cancel_language_server_work(server_id, token, cx);
10506 }
10507 }
10508 }
10509 anyhow::Ok(())
10510 })??;
10511
10512 Ok(proto::Ack {})
10513 }
10514
10515 fn buffer_ids_to_buffers(
10516 &mut self,
10517 buffer_ids: impl Iterator<Item = u64>,
10518 cx: &mut Context<Self>,
10519 ) -> Vec<Entity<Buffer>> {
10520 buffer_ids
10521 .into_iter()
10522 .flat_map(|buffer_id| {
10523 self.buffer_store
10524 .read(cx)
10525 .get(BufferId::new(buffer_id).log_err()?)
10526 })
10527 .collect::<Vec<_>>()
10528 }
10529
10530 async fn handle_apply_additional_edits_for_completion(
10531 this: Entity<Self>,
10532 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10533 mut cx: AsyncApp,
10534 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10535 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10536 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10537 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10538 let completion = Self::deserialize_completion(
10539 envelope.payload.completion.context("invalid completion")?,
10540 )?;
10541 anyhow::Ok((buffer, completion))
10542 })??;
10543
10544 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10545 this.apply_additional_edits_for_completion(
10546 buffer,
10547 Rc::new(RefCell::new(Box::new([Completion {
10548 replace_range: completion.replace_range,
10549 new_text: completion.new_text,
10550 source: completion.source,
10551 documentation: None,
10552 label: CodeLabel::default(),
10553 match_start: None,
10554 snippet_deduplication_key: None,
10555 insert_text_mode: None,
10556 icon_path: None,
10557 confirm: None,
10558 }]))),
10559 0,
10560 false,
10561 cx,
10562 )
10563 })?;
10564
10565 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10566 transaction: apply_additional_edits
10567 .await?
10568 .as_ref()
10569 .map(language::proto::serialize_transaction),
10570 })
10571 }
10572
10573 pub fn last_formatting_failure(&self) -> Option<&str> {
10574 self.last_formatting_failure.as_deref()
10575 }
10576
10577 pub fn reset_last_formatting_failure(&mut self) {
10578 self.last_formatting_failure = None;
10579 }
10580
10581 pub fn environment_for_buffer(
10582 &self,
10583 buffer: &Entity<Buffer>,
10584 cx: &mut Context<Self>,
10585 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10586 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10587 environment.update(cx, |env, cx| {
10588 env.buffer_environment(buffer, &self.worktree_store, cx)
10589 })
10590 } else {
10591 Task::ready(None).shared()
10592 }
10593 }
10594
10595 pub fn format(
10596 &mut self,
10597 buffers: HashSet<Entity<Buffer>>,
10598 target: LspFormatTarget,
10599 push_to_history: bool,
10600 trigger: FormatTrigger,
10601 cx: &mut Context<Self>,
10602 ) -> Task<anyhow::Result<ProjectTransaction>> {
10603 let logger = zlog::scoped!("format");
10604 if self.as_local().is_some() {
10605 zlog::trace!(logger => "Formatting locally");
10606 let logger = zlog::scoped!(logger => "local");
10607 let buffers = buffers
10608 .into_iter()
10609 .map(|buffer_handle| {
10610 let buffer = buffer_handle.read(cx);
10611 let buffer_abs_path = File::from_dyn(buffer.file())
10612 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10613
10614 (buffer_handle, buffer_abs_path, buffer.remote_id())
10615 })
10616 .collect::<Vec<_>>();
10617
10618 cx.spawn(async move |lsp_store, cx| {
10619 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10620
10621 for (handle, abs_path, id) in buffers {
10622 let env = lsp_store
10623 .update(cx, |lsp_store, cx| {
10624 lsp_store.environment_for_buffer(&handle, cx)
10625 })?
10626 .await;
10627
10628 let ranges = match &target {
10629 LspFormatTarget::Buffers => None,
10630 LspFormatTarget::Ranges(ranges) => {
10631 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10632 }
10633 };
10634
10635 formattable_buffers.push(FormattableBuffer {
10636 handle,
10637 abs_path,
10638 env,
10639 ranges,
10640 });
10641 }
10642 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10643
10644 let format_timer = zlog::time!(logger => "Formatting buffers");
10645 let result = LocalLspStore::format_locally(
10646 lsp_store.clone(),
10647 formattable_buffers,
10648 push_to_history,
10649 trigger,
10650 logger,
10651 cx,
10652 )
10653 .await;
10654 format_timer.end();
10655
10656 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10657
10658 lsp_store.update(cx, |lsp_store, _| {
10659 lsp_store.update_last_formatting_failure(&result);
10660 })?;
10661
10662 result
10663 })
10664 } else if let Some((client, project_id)) = self.upstream_client() {
10665 zlog::trace!(logger => "Formatting remotely");
10666 let logger = zlog::scoped!(logger => "remote");
10667 // Don't support formatting ranges via remote
10668 match target {
10669 LspFormatTarget::Buffers => {}
10670 LspFormatTarget::Ranges(_) => {
10671 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10672 return Task::ready(Ok(ProjectTransaction::default()));
10673 }
10674 }
10675
10676 let buffer_store = self.buffer_store();
10677 cx.spawn(async move |lsp_store, cx| {
10678 zlog::trace!(logger => "Sending remote format request");
10679 let request_timer = zlog::time!(logger => "remote format request");
10680 let result = client
10681 .request(proto::FormatBuffers {
10682 project_id,
10683 trigger: trigger as i32,
10684 buffer_ids: buffers
10685 .iter()
10686 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10687 .collect::<Result<_>>()?,
10688 })
10689 .await
10690 .and_then(|result| result.transaction.context("missing transaction"));
10691 request_timer.end();
10692
10693 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10694
10695 lsp_store.update(cx, |lsp_store, _| {
10696 lsp_store.update_last_formatting_failure(&result);
10697 })?;
10698
10699 let transaction_response = result?;
10700 let _timer = zlog::time!(logger => "deserializing project transaction");
10701 buffer_store
10702 .update(cx, |buffer_store, cx| {
10703 buffer_store.deserialize_project_transaction(
10704 transaction_response,
10705 push_to_history,
10706 cx,
10707 )
10708 })?
10709 .await
10710 })
10711 } else {
10712 zlog::trace!(logger => "Not formatting");
10713 Task::ready(Ok(ProjectTransaction::default()))
10714 }
10715 }
10716
10717 async fn handle_format_buffers(
10718 this: Entity<Self>,
10719 envelope: TypedEnvelope<proto::FormatBuffers>,
10720 mut cx: AsyncApp,
10721 ) -> Result<proto::FormatBuffersResponse> {
10722 let sender_id = envelope.original_sender_id().unwrap_or_default();
10723 let format = this.update(&mut cx, |this, cx| {
10724 let mut buffers = HashSet::default();
10725 for buffer_id in &envelope.payload.buffer_ids {
10726 let buffer_id = BufferId::new(*buffer_id)?;
10727 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10728 }
10729 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10730 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10731 })??;
10732
10733 let project_transaction = format.await?;
10734 let project_transaction = this.update(&mut cx, |this, cx| {
10735 this.buffer_store.update(cx, |buffer_store, cx| {
10736 buffer_store.serialize_project_transaction_for_peer(
10737 project_transaction,
10738 sender_id,
10739 cx,
10740 )
10741 })
10742 })?;
10743 Ok(proto::FormatBuffersResponse {
10744 transaction: Some(project_transaction),
10745 })
10746 }
10747
10748 async fn handle_apply_code_action_kind(
10749 this: Entity<Self>,
10750 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10751 mut cx: AsyncApp,
10752 ) -> Result<proto::ApplyCodeActionKindResponse> {
10753 let sender_id = envelope.original_sender_id().unwrap_or_default();
10754 let format = this.update(&mut cx, |this, cx| {
10755 let mut buffers = HashSet::default();
10756 for buffer_id in &envelope.payload.buffer_ids {
10757 let buffer_id = BufferId::new(*buffer_id)?;
10758 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10759 }
10760 let kind = match envelope.payload.kind.as_str() {
10761 "" => CodeActionKind::EMPTY,
10762 "quickfix" => CodeActionKind::QUICKFIX,
10763 "refactor" => CodeActionKind::REFACTOR,
10764 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10765 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10766 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10767 "source" => CodeActionKind::SOURCE,
10768 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10769 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10770 _ => anyhow::bail!(
10771 "Invalid code action kind {}",
10772 envelope.payload.kind.as_str()
10773 ),
10774 };
10775 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10776 })??;
10777
10778 let project_transaction = format.await?;
10779 let project_transaction = this.update(&mut cx, |this, cx| {
10780 this.buffer_store.update(cx, |buffer_store, cx| {
10781 buffer_store.serialize_project_transaction_for_peer(
10782 project_transaction,
10783 sender_id,
10784 cx,
10785 )
10786 })
10787 })?;
10788 Ok(proto::ApplyCodeActionKindResponse {
10789 transaction: Some(project_transaction),
10790 })
10791 }
10792
10793 async fn shutdown_language_server(
10794 server_state: Option<LanguageServerState>,
10795 name: LanguageServerName,
10796 cx: &mut AsyncApp,
10797 ) {
10798 let server = match server_state {
10799 Some(LanguageServerState::Starting { startup, .. }) => {
10800 let mut timer = cx
10801 .background_executor()
10802 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10803 .fuse();
10804
10805 select! {
10806 server = startup.fuse() => server,
10807 () = timer => {
10808 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10809 None
10810 },
10811 }
10812 }
10813
10814 Some(LanguageServerState::Running { server, .. }) => Some(server),
10815
10816 None => None,
10817 };
10818
10819 if let Some(server) = server
10820 && let Some(shutdown) = server.shutdown()
10821 {
10822 shutdown.await;
10823 }
10824 }
10825
10826 // Returns a list of all of the worktrees which no longer have a language server and the root path
10827 // for the stopped server
10828 fn stop_local_language_server(
10829 &mut self,
10830 server_id: LanguageServerId,
10831 cx: &mut Context<Self>,
10832 ) -> Task<()> {
10833 let local = match &mut self.mode {
10834 LspStoreMode::Local(local) => local,
10835 _ => {
10836 return Task::ready(());
10837 }
10838 };
10839
10840 // Remove this server ID from all entries in the given worktree.
10841 local
10842 .language_server_ids
10843 .retain(|_, state| state.id != server_id);
10844 self.buffer_store.update(cx, |buffer_store, cx| {
10845 for buffer in buffer_store.buffers() {
10846 buffer.update(cx, |buffer, cx| {
10847 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10848 buffer.set_completion_triggers(server_id, Default::default(), cx);
10849 });
10850 }
10851 });
10852
10853 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10854 summaries.retain(|path, summaries_by_server_id| {
10855 if summaries_by_server_id.remove(&server_id).is_some() {
10856 if let Some((client, project_id)) = self.downstream_client.clone() {
10857 client
10858 .send(proto::UpdateDiagnosticSummary {
10859 project_id,
10860 worktree_id: worktree_id.to_proto(),
10861 summary: Some(proto::DiagnosticSummary {
10862 path: path.as_ref().to_proto(),
10863 language_server_id: server_id.0 as u64,
10864 error_count: 0,
10865 warning_count: 0,
10866 }),
10867 more_summaries: Vec::new(),
10868 })
10869 .log_err();
10870 }
10871 !summaries_by_server_id.is_empty()
10872 } else {
10873 true
10874 }
10875 });
10876 }
10877
10878 let local = self.as_local_mut().unwrap();
10879 for diagnostics in local.diagnostics.values_mut() {
10880 diagnostics.retain(|_, diagnostics_by_server_id| {
10881 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10882 diagnostics_by_server_id.remove(ix);
10883 !diagnostics_by_server_id.is_empty()
10884 } else {
10885 true
10886 }
10887 });
10888 }
10889 local.language_server_watched_paths.remove(&server_id);
10890
10891 let server_state = local.language_servers.remove(&server_id);
10892 self.cleanup_lsp_data(server_id);
10893 let name = self
10894 .language_server_statuses
10895 .remove(&server_id)
10896 .map(|status| status.name)
10897 .or_else(|| {
10898 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10899 Some(adapter.name())
10900 } else {
10901 None
10902 }
10903 });
10904
10905 if let Some(name) = name {
10906 log::info!("stopping language server {name}");
10907 self.languages
10908 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10909 cx.notify();
10910
10911 return cx.spawn(async move |lsp_store, cx| {
10912 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10913 lsp_store
10914 .update(cx, |lsp_store, cx| {
10915 lsp_store
10916 .languages
10917 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10918 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10919 cx.notify();
10920 })
10921 .ok();
10922 });
10923 }
10924
10925 if server_state.is_some() {
10926 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10927 }
10928 Task::ready(())
10929 }
10930
10931 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10932 if let Some((client, project_id)) = self.upstream_client() {
10933 let request = client.request(proto::StopLanguageServers {
10934 project_id,
10935 buffer_ids: Vec::new(),
10936 also_servers: Vec::new(),
10937 all: true,
10938 });
10939 cx.background_spawn(request).detach_and_log_err(cx);
10940 } else {
10941 let Some(local) = self.as_local_mut() else {
10942 return;
10943 };
10944 let language_servers_to_stop = local
10945 .language_server_ids
10946 .values()
10947 .map(|state| state.id)
10948 .collect();
10949 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10950 let tasks = language_servers_to_stop
10951 .into_iter()
10952 .map(|server| self.stop_local_language_server(server, cx))
10953 .collect::<Vec<_>>();
10954 cx.background_spawn(async move {
10955 futures::future::join_all(tasks).await;
10956 })
10957 .detach();
10958 }
10959 }
10960
10961 pub fn restart_language_servers_for_buffers(
10962 &mut self,
10963 buffers: Vec<Entity<Buffer>>,
10964 only_restart_servers: HashSet<LanguageServerSelector>,
10965 cx: &mut Context<Self>,
10966 ) {
10967 if let Some((client, project_id)) = self.upstream_client() {
10968 let request = client.request(proto::RestartLanguageServers {
10969 project_id,
10970 buffer_ids: buffers
10971 .into_iter()
10972 .map(|b| b.read(cx).remote_id().to_proto())
10973 .collect(),
10974 only_servers: only_restart_servers
10975 .into_iter()
10976 .map(|selector| {
10977 let selector = match selector {
10978 LanguageServerSelector::Id(language_server_id) => {
10979 proto::language_server_selector::Selector::ServerId(
10980 language_server_id.to_proto(),
10981 )
10982 }
10983 LanguageServerSelector::Name(language_server_name) => {
10984 proto::language_server_selector::Selector::Name(
10985 language_server_name.to_string(),
10986 )
10987 }
10988 };
10989 proto::LanguageServerSelector {
10990 selector: Some(selector),
10991 }
10992 })
10993 .collect(),
10994 all: false,
10995 });
10996 cx.background_spawn(request).detach_and_log_err(cx);
10997 } else {
10998 let stop_task = if only_restart_servers.is_empty() {
10999 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11000 } else {
11001 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11002 };
11003 cx.spawn(async move |lsp_store, cx| {
11004 stop_task.await;
11005 lsp_store
11006 .update(cx, |lsp_store, cx| {
11007 for buffer in buffers {
11008 lsp_store.register_buffer_with_language_servers(
11009 &buffer,
11010 only_restart_servers.clone(),
11011 true,
11012 cx,
11013 );
11014 }
11015 })
11016 .ok()
11017 })
11018 .detach();
11019 }
11020 }
11021
11022 pub fn stop_language_servers_for_buffers(
11023 &mut self,
11024 buffers: Vec<Entity<Buffer>>,
11025 also_stop_servers: HashSet<LanguageServerSelector>,
11026 cx: &mut Context<Self>,
11027 ) -> Task<Result<()>> {
11028 if let Some((client, project_id)) = self.upstream_client() {
11029 let request = client.request(proto::StopLanguageServers {
11030 project_id,
11031 buffer_ids: buffers
11032 .into_iter()
11033 .map(|b| b.read(cx).remote_id().to_proto())
11034 .collect(),
11035 also_servers: also_stop_servers
11036 .into_iter()
11037 .map(|selector| {
11038 let selector = match selector {
11039 LanguageServerSelector::Id(language_server_id) => {
11040 proto::language_server_selector::Selector::ServerId(
11041 language_server_id.to_proto(),
11042 )
11043 }
11044 LanguageServerSelector::Name(language_server_name) => {
11045 proto::language_server_selector::Selector::Name(
11046 language_server_name.to_string(),
11047 )
11048 }
11049 };
11050 proto::LanguageServerSelector {
11051 selector: Some(selector),
11052 }
11053 })
11054 .collect(),
11055 all: false,
11056 });
11057 cx.background_spawn(async move {
11058 let _ = request.await?;
11059 Ok(())
11060 })
11061 } else {
11062 let task =
11063 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11064 cx.background_spawn(async move {
11065 task.await;
11066 Ok(())
11067 })
11068 }
11069 }
11070
11071 fn stop_local_language_servers_for_buffers(
11072 &mut self,
11073 buffers: &[Entity<Buffer>],
11074 also_stop_servers: HashSet<LanguageServerSelector>,
11075 cx: &mut Context<Self>,
11076 ) -> Task<()> {
11077 let Some(local) = self.as_local_mut() else {
11078 return Task::ready(());
11079 };
11080 let mut language_server_names_to_stop = BTreeSet::default();
11081 let mut language_servers_to_stop = also_stop_servers
11082 .into_iter()
11083 .flat_map(|selector| match selector {
11084 LanguageServerSelector::Id(id) => Some(id),
11085 LanguageServerSelector::Name(name) => {
11086 language_server_names_to_stop.insert(name);
11087 None
11088 }
11089 })
11090 .collect::<BTreeSet<_>>();
11091
11092 let mut covered_worktrees = HashSet::default();
11093 for buffer in buffers {
11094 buffer.update(cx, |buffer, cx| {
11095 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11096 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11097 && covered_worktrees.insert(worktree_id)
11098 {
11099 language_server_names_to_stop.retain(|name| {
11100 let old_ids_count = language_servers_to_stop.len();
11101 let all_language_servers_with_this_name = local
11102 .language_server_ids
11103 .iter()
11104 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11105 language_servers_to_stop.extend(all_language_servers_with_this_name);
11106 old_ids_count == language_servers_to_stop.len()
11107 });
11108 }
11109 });
11110 }
11111 for name in language_server_names_to_stop {
11112 language_servers_to_stop.extend(
11113 local
11114 .language_server_ids
11115 .iter()
11116 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11117 );
11118 }
11119
11120 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11121 let tasks = language_servers_to_stop
11122 .into_iter()
11123 .map(|server| self.stop_local_language_server(server, cx))
11124 .collect::<Vec<_>>();
11125
11126 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11127 }
11128
11129 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11130 let (worktree, relative_path) =
11131 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11132
11133 let project_path = ProjectPath {
11134 worktree_id: worktree.read(cx).id(),
11135 path: relative_path,
11136 };
11137
11138 Some(
11139 self.buffer_store()
11140 .read(cx)
11141 .get_by_path(&project_path)?
11142 .read(cx),
11143 )
11144 }
11145
11146 #[cfg(any(test, feature = "test-support"))]
11147 pub fn update_diagnostics(
11148 &mut self,
11149 server_id: LanguageServerId,
11150 diagnostics: lsp::PublishDiagnosticsParams,
11151 result_id: Option<SharedString>,
11152 source_kind: DiagnosticSourceKind,
11153 disk_based_sources: &[String],
11154 cx: &mut Context<Self>,
11155 ) -> Result<()> {
11156 self.merge_lsp_diagnostics(
11157 source_kind,
11158 vec![DocumentDiagnosticsUpdate {
11159 diagnostics,
11160 result_id,
11161 server_id,
11162 disk_based_sources: Cow::Borrowed(disk_based_sources),
11163 registration_id: None,
11164 }],
11165 |_, _, _| false,
11166 cx,
11167 )
11168 }
11169
11170 pub fn merge_lsp_diagnostics(
11171 &mut self,
11172 source_kind: DiagnosticSourceKind,
11173 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11174 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11175 cx: &mut Context<Self>,
11176 ) -> Result<()> {
11177 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11178 let updates = lsp_diagnostics
11179 .into_iter()
11180 .filter_map(|update| {
11181 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11182 Some(DocumentDiagnosticsUpdate {
11183 diagnostics: self.lsp_to_document_diagnostics(
11184 abs_path,
11185 source_kind,
11186 update.server_id,
11187 update.diagnostics,
11188 &update.disk_based_sources,
11189 update.registration_id.clone(),
11190 ),
11191 result_id: update.result_id,
11192 server_id: update.server_id,
11193 disk_based_sources: update.disk_based_sources,
11194 registration_id: update.registration_id,
11195 })
11196 })
11197 .collect();
11198 self.merge_diagnostic_entries(updates, merge, cx)?;
11199 Ok(())
11200 }
11201
11202 fn lsp_to_document_diagnostics(
11203 &mut self,
11204 document_abs_path: PathBuf,
11205 source_kind: DiagnosticSourceKind,
11206 server_id: LanguageServerId,
11207 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11208 disk_based_sources: &[String],
11209 registration_id: Option<SharedString>,
11210 ) -> DocumentDiagnostics {
11211 let mut diagnostics = Vec::default();
11212 let mut primary_diagnostic_group_ids = HashMap::default();
11213 let mut sources_by_group_id = HashMap::default();
11214 let mut supporting_diagnostics = HashMap::default();
11215
11216 let adapter = self.language_server_adapter_for_id(server_id);
11217
11218 // Ensure that primary diagnostics are always the most severe
11219 lsp_diagnostics
11220 .diagnostics
11221 .sort_by_key(|item| item.severity);
11222
11223 for diagnostic in &lsp_diagnostics.diagnostics {
11224 let source = diagnostic.source.as_ref();
11225 let range = range_from_lsp(diagnostic.range);
11226 let is_supporting = diagnostic
11227 .related_information
11228 .as_ref()
11229 .is_some_and(|infos| {
11230 infos.iter().any(|info| {
11231 primary_diagnostic_group_ids.contains_key(&(
11232 source,
11233 diagnostic.code.clone(),
11234 range_from_lsp(info.location.range),
11235 ))
11236 })
11237 });
11238
11239 let is_unnecessary = diagnostic
11240 .tags
11241 .as_ref()
11242 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11243
11244 let underline = self
11245 .language_server_adapter_for_id(server_id)
11246 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11247
11248 if is_supporting {
11249 supporting_diagnostics.insert(
11250 (source, diagnostic.code.clone(), range),
11251 (diagnostic.severity, is_unnecessary),
11252 );
11253 } else {
11254 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11255 let is_disk_based =
11256 source.is_some_and(|source| disk_based_sources.contains(source));
11257
11258 sources_by_group_id.insert(group_id, source);
11259 primary_diagnostic_group_ids
11260 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11261
11262 diagnostics.push(DiagnosticEntry {
11263 range,
11264 diagnostic: Diagnostic {
11265 source: diagnostic.source.clone(),
11266 source_kind,
11267 code: diagnostic.code.clone(),
11268 code_description: diagnostic
11269 .code_description
11270 .as_ref()
11271 .and_then(|d| d.href.clone()),
11272 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11273 markdown: adapter.as_ref().and_then(|adapter| {
11274 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11275 }),
11276 message: diagnostic.message.trim().to_string(),
11277 group_id,
11278 is_primary: true,
11279 is_disk_based,
11280 is_unnecessary,
11281 underline,
11282 data: diagnostic.data.clone(),
11283 registration_id: registration_id.clone(),
11284 },
11285 });
11286 if let Some(infos) = &diagnostic.related_information {
11287 for info in infos {
11288 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11289 let range = range_from_lsp(info.location.range);
11290 diagnostics.push(DiagnosticEntry {
11291 range,
11292 diagnostic: Diagnostic {
11293 source: diagnostic.source.clone(),
11294 source_kind,
11295 code: diagnostic.code.clone(),
11296 code_description: diagnostic
11297 .code_description
11298 .as_ref()
11299 .and_then(|d| d.href.clone()),
11300 severity: DiagnosticSeverity::INFORMATION,
11301 markdown: adapter.as_ref().and_then(|adapter| {
11302 adapter.diagnostic_message_to_markdown(&info.message)
11303 }),
11304 message: info.message.trim().to_string(),
11305 group_id,
11306 is_primary: false,
11307 is_disk_based,
11308 is_unnecessary: false,
11309 underline,
11310 data: diagnostic.data.clone(),
11311 registration_id: registration_id.clone(),
11312 },
11313 });
11314 }
11315 }
11316 }
11317 }
11318 }
11319
11320 for entry in &mut diagnostics {
11321 let diagnostic = &mut entry.diagnostic;
11322 if !diagnostic.is_primary {
11323 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11324 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11325 source,
11326 diagnostic.code.clone(),
11327 entry.range.clone(),
11328 )) {
11329 if let Some(severity) = severity {
11330 diagnostic.severity = severity;
11331 }
11332 diagnostic.is_unnecessary = is_unnecessary;
11333 }
11334 }
11335 }
11336
11337 DocumentDiagnostics {
11338 diagnostics,
11339 document_abs_path,
11340 version: lsp_diagnostics.version,
11341 }
11342 }
11343
11344 fn insert_newly_running_language_server(
11345 &mut self,
11346 adapter: Arc<CachedLspAdapter>,
11347 language_server: Arc<LanguageServer>,
11348 server_id: LanguageServerId,
11349 key: LanguageServerSeed,
11350 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11351 cx: &mut Context<Self>,
11352 ) {
11353 let Some(local) = self.as_local_mut() else {
11354 return;
11355 };
11356 // If the language server for this key doesn't match the server id, don't store the
11357 // server. Which will cause it to be dropped, killing the process
11358 if local
11359 .language_server_ids
11360 .get(&key)
11361 .map(|state| state.id != server_id)
11362 .unwrap_or(false)
11363 {
11364 return;
11365 }
11366
11367 // Update language_servers collection with Running variant of LanguageServerState
11368 // indicating that the server is up and running and ready
11369 let workspace_folders = workspace_folders.lock().clone();
11370 language_server.set_workspace_folders(workspace_folders);
11371
11372 let workspace_diagnostics_refresh_tasks = language_server
11373 .capabilities()
11374 .diagnostic_provider
11375 .and_then(|provider| {
11376 local
11377 .language_server_dynamic_registrations
11378 .entry(server_id)
11379 .or_default()
11380 .diagnostics
11381 .entry(None)
11382 .or_insert(provider.clone());
11383 let workspace_refresher =
11384 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11385
11386 Some((None, workspace_refresher))
11387 })
11388 .into_iter()
11389 .collect();
11390 local.language_servers.insert(
11391 server_id,
11392 LanguageServerState::Running {
11393 workspace_diagnostics_refresh_tasks,
11394 adapter: adapter.clone(),
11395 server: language_server.clone(),
11396 simulate_disk_based_diagnostics_completion: None,
11397 },
11398 );
11399 local
11400 .languages
11401 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11402 if let Some(file_ops_caps) = language_server
11403 .capabilities()
11404 .workspace
11405 .as_ref()
11406 .and_then(|ws| ws.file_operations.as_ref())
11407 {
11408 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11409 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11410 if did_rename_caps.or(will_rename_caps).is_some() {
11411 let watcher = RenamePathsWatchedForServer::default()
11412 .with_did_rename_patterns(did_rename_caps)
11413 .with_will_rename_patterns(will_rename_caps);
11414 local
11415 .language_server_paths_watched_for_rename
11416 .insert(server_id, watcher);
11417 }
11418 }
11419
11420 self.language_server_statuses.insert(
11421 server_id,
11422 LanguageServerStatus {
11423 name: language_server.name(),
11424 pending_work: Default::default(),
11425 has_pending_diagnostic_updates: false,
11426 progress_tokens: Default::default(),
11427 worktree: Some(key.worktree_id),
11428 binary: Some(language_server.binary().clone()),
11429 configuration: Some(language_server.configuration().clone()),
11430 workspace_folders: language_server.workspace_folders(),
11431 },
11432 );
11433
11434 cx.emit(LspStoreEvent::LanguageServerAdded(
11435 server_id,
11436 language_server.name(),
11437 Some(key.worktree_id),
11438 ));
11439
11440 let server_capabilities = language_server.capabilities();
11441 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11442 downstream_client
11443 .send(proto::StartLanguageServer {
11444 project_id: *project_id,
11445 server: Some(proto::LanguageServer {
11446 id: server_id.to_proto(),
11447 name: language_server.name().to_string(),
11448 worktree_id: Some(key.worktree_id.to_proto()),
11449 }),
11450 capabilities: serde_json::to_string(&server_capabilities)
11451 .expect("serializing server LSP capabilities"),
11452 })
11453 .log_err();
11454 }
11455 self.lsp_server_capabilities
11456 .insert(server_id, server_capabilities);
11457
11458 // Tell the language server about every open buffer in the worktree that matches the language.
11459 // Also check for buffers in worktrees that reused this server
11460 let mut worktrees_using_server = vec![key.worktree_id];
11461 if let Some(local) = self.as_local() {
11462 // Find all worktrees that have this server in their language server tree
11463 for (worktree_id, servers) in &local.lsp_tree.instances {
11464 if *worktree_id != key.worktree_id {
11465 for server_map in servers.roots.values() {
11466 if server_map
11467 .values()
11468 .any(|(node, _)| node.id() == Some(server_id))
11469 {
11470 worktrees_using_server.push(*worktree_id);
11471 }
11472 }
11473 }
11474 }
11475 }
11476
11477 let mut buffer_paths_registered = Vec::new();
11478 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11479 let mut lsp_adapters = HashMap::default();
11480 for buffer_handle in buffer_store.buffers() {
11481 let buffer = buffer_handle.read(cx);
11482 let file = match File::from_dyn(buffer.file()) {
11483 Some(file) => file,
11484 None => continue,
11485 };
11486 let language = match buffer.language() {
11487 Some(language) => language,
11488 None => continue,
11489 };
11490
11491 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11492 || !lsp_adapters
11493 .entry(language.name())
11494 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11495 .iter()
11496 .any(|a| a.name == key.name)
11497 {
11498 continue;
11499 }
11500 // didOpen
11501 let file = match file.as_local() {
11502 Some(file) => file,
11503 None => continue,
11504 };
11505
11506 let local = self.as_local_mut().unwrap();
11507
11508 let buffer_id = buffer.remote_id();
11509 if local.registered_buffers.contains_key(&buffer_id) {
11510 let versions = local
11511 .buffer_snapshots
11512 .entry(buffer_id)
11513 .or_default()
11514 .entry(server_id)
11515 .and_modify(|_| {
11516 assert!(
11517 false,
11518 "There should not be an existing snapshot for a newly inserted buffer"
11519 )
11520 })
11521 .or_insert_with(|| {
11522 vec![LspBufferSnapshot {
11523 version: 0,
11524 snapshot: buffer.text_snapshot(),
11525 }]
11526 });
11527
11528 let snapshot = versions.last().unwrap();
11529 let version = snapshot.version;
11530 let initial_snapshot = &snapshot.snapshot;
11531 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11532 language_server.register_buffer(
11533 uri,
11534 adapter.language_id(&language.name()),
11535 version,
11536 initial_snapshot.text(),
11537 );
11538 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11539 local
11540 .buffers_opened_in_servers
11541 .entry(buffer_id)
11542 .or_default()
11543 .insert(server_id);
11544 }
11545 buffer_handle.update(cx, |buffer, cx| {
11546 buffer.set_completion_triggers(
11547 server_id,
11548 language_server
11549 .capabilities()
11550 .completion_provider
11551 .as_ref()
11552 .and_then(|provider| {
11553 provider
11554 .trigger_characters
11555 .as_ref()
11556 .map(|characters| characters.iter().cloned().collect())
11557 })
11558 .unwrap_or_default(),
11559 cx,
11560 )
11561 });
11562 }
11563 });
11564
11565 for (buffer_id, abs_path) in buffer_paths_registered {
11566 cx.emit(LspStoreEvent::LanguageServerUpdate {
11567 language_server_id: server_id,
11568 name: Some(adapter.name()),
11569 message: proto::update_language_server::Variant::RegisteredForBuffer(
11570 proto::RegisteredForBuffer {
11571 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11572 buffer_id: buffer_id.to_proto(),
11573 },
11574 ),
11575 });
11576 }
11577
11578 cx.notify();
11579 }
11580
11581 pub fn language_servers_running_disk_based_diagnostics(
11582 &self,
11583 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11584 self.language_server_statuses
11585 .iter()
11586 .filter_map(|(id, status)| {
11587 if status.has_pending_diagnostic_updates {
11588 Some(*id)
11589 } else {
11590 None
11591 }
11592 })
11593 }
11594
11595 pub(crate) fn cancel_language_server_work_for_buffers(
11596 &mut self,
11597 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11598 cx: &mut Context<Self>,
11599 ) {
11600 if let Some((client, project_id)) = self.upstream_client() {
11601 let request = client.request(proto::CancelLanguageServerWork {
11602 project_id,
11603 work: Some(proto::cancel_language_server_work::Work::Buffers(
11604 proto::cancel_language_server_work::Buffers {
11605 buffer_ids: buffers
11606 .into_iter()
11607 .map(|b| b.read(cx).remote_id().to_proto())
11608 .collect(),
11609 },
11610 )),
11611 });
11612 cx.background_spawn(request).detach_and_log_err(cx);
11613 } else if let Some(local) = self.as_local() {
11614 let servers = buffers
11615 .into_iter()
11616 .flat_map(|buffer| {
11617 buffer.update(cx, |buffer, cx| {
11618 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11619 })
11620 })
11621 .collect::<HashSet<_>>();
11622 for server_id in servers {
11623 self.cancel_language_server_work(server_id, None, cx);
11624 }
11625 }
11626 }
11627
11628 pub(crate) fn cancel_language_server_work(
11629 &mut self,
11630 server_id: LanguageServerId,
11631 token_to_cancel: Option<ProgressToken>,
11632 cx: &mut Context<Self>,
11633 ) {
11634 if let Some(local) = self.as_local() {
11635 let status = self.language_server_statuses.get(&server_id);
11636 let server = local.language_servers.get(&server_id);
11637 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11638 {
11639 for (token, progress) in &status.pending_work {
11640 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11641 && token != token_to_cancel
11642 {
11643 continue;
11644 }
11645 if progress.is_cancellable {
11646 server
11647 .notify::<lsp::notification::WorkDoneProgressCancel>(
11648 WorkDoneProgressCancelParams {
11649 token: token.to_lsp(),
11650 },
11651 )
11652 .ok();
11653 }
11654 }
11655 }
11656 } else if let Some((client, project_id)) = self.upstream_client() {
11657 let request = client.request(proto::CancelLanguageServerWork {
11658 project_id,
11659 work: Some(
11660 proto::cancel_language_server_work::Work::LanguageServerWork(
11661 proto::cancel_language_server_work::LanguageServerWork {
11662 language_server_id: server_id.to_proto(),
11663 token: token_to_cancel.map(|token| token.to_proto()),
11664 },
11665 ),
11666 ),
11667 });
11668 cx.background_spawn(request).detach_and_log_err(cx);
11669 }
11670 }
11671
11672 fn register_supplementary_language_server(
11673 &mut self,
11674 id: LanguageServerId,
11675 name: LanguageServerName,
11676 server: Arc<LanguageServer>,
11677 cx: &mut Context<Self>,
11678 ) {
11679 if let Some(local) = self.as_local_mut() {
11680 local
11681 .supplementary_language_servers
11682 .insert(id, (name.clone(), server));
11683 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11684 }
11685 }
11686
11687 fn unregister_supplementary_language_server(
11688 &mut self,
11689 id: LanguageServerId,
11690 cx: &mut Context<Self>,
11691 ) {
11692 if let Some(local) = self.as_local_mut() {
11693 local.supplementary_language_servers.remove(&id);
11694 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11695 }
11696 }
11697
11698 pub(crate) fn supplementary_language_servers(
11699 &self,
11700 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11701 self.as_local().into_iter().flat_map(|local| {
11702 local
11703 .supplementary_language_servers
11704 .iter()
11705 .map(|(id, (name, _))| (*id, name.clone()))
11706 })
11707 }
11708
11709 pub fn language_server_adapter_for_id(
11710 &self,
11711 id: LanguageServerId,
11712 ) -> Option<Arc<CachedLspAdapter>> {
11713 self.as_local()
11714 .and_then(|local| local.language_servers.get(&id))
11715 .and_then(|language_server_state| match language_server_state {
11716 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11717 _ => None,
11718 })
11719 }
11720
11721 pub(super) fn update_local_worktree_language_servers(
11722 &mut self,
11723 worktree_handle: &Entity<Worktree>,
11724 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11725 cx: &mut Context<Self>,
11726 ) {
11727 if changes.is_empty() {
11728 return;
11729 }
11730
11731 let Some(local) = self.as_local() else { return };
11732
11733 local.prettier_store.update(cx, |prettier_store, cx| {
11734 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11735 });
11736
11737 let worktree_id = worktree_handle.read(cx).id();
11738 let mut language_server_ids = local
11739 .language_server_ids
11740 .iter()
11741 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11742 .collect::<Vec<_>>();
11743 language_server_ids.sort();
11744 language_server_ids.dedup();
11745
11746 // let abs_path = worktree_handle.read(cx).abs_path();
11747 for server_id in &language_server_ids {
11748 if let Some(LanguageServerState::Running { server, .. }) =
11749 local.language_servers.get(server_id)
11750 && let Some(watched_paths) = local
11751 .language_server_watched_paths
11752 .get(server_id)
11753 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11754 {
11755 let params = lsp::DidChangeWatchedFilesParams {
11756 changes: changes
11757 .iter()
11758 .filter_map(|(path, _, change)| {
11759 if !watched_paths.is_match(path.as_std_path()) {
11760 return None;
11761 }
11762 let typ = match change {
11763 PathChange::Loaded => return None,
11764 PathChange::Added => lsp::FileChangeType::CREATED,
11765 PathChange::Removed => lsp::FileChangeType::DELETED,
11766 PathChange::Updated => lsp::FileChangeType::CHANGED,
11767 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11768 };
11769 let uri = lsp::Uri::from_file_path(
11770 worktree_handle.read(cx).absolutize(&path),
11771 )
11772 .ok()?;
11773 Some(lsp::FileEvent { uri, typ })
11774 })
11775 .collect(),
11776 };
11777 if !params.changes.is_empty() {
11778 server
11779 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11780 .ok();
11781 }
11782 }
11783 }
11784 for (path, _, _) in changes {
11785 if let Some(file_name) = path.file_name()
11786 && local.watched_manifest_filenames.contains(file_name)
11787 {
11788 self.request_workspace_config_refresh();
11789 break;
11790 }
11791 }
11792 }
11793
11794 pub fn wait_for_remote_buffer(
11795 &mut self,
11796 id: BufferId,
11797 cx: &mut Context<Self>,
11798 ) -> Task<Result<Entity<Buffer>>> {
11799 self.buffer_store.update(cx, |buffer_store, cx| {
11800 buffer_store.wait_for_remote_buffer(id, cx)
11801 })
11802 }
11803
11804 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11805 let mut result = proto::Symbol {
11806 language_server_name: symbol.language_server_name.0.to_string(),
11807 source_worktree_id: symbol.source_worktree_id.to_proto(),
11808 language_server_id: symbol.source_language_server_id.to_proto(),
11809 name: symbol.name.clone(),
11810 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11811 start: Some(proto::PointUtf16 {
11812 row: symbol.range.start.0.row,
11813 column: symbol.range.start.0.column,
11814 }),
11815 end: Some(proto::PointUtf16 {
11816 row: symbol.range.end.0.row,
11817 column: symbol.range.end.0.column,
11818 }),
11819 worktree_id: Default::default(),
11820 path: Default::default(),
11821 signature: Default::default(),
11822 };
11823 match &symbol.path {
11824 SymbolLocation::InProject(path) => {
11825 result.worktree_id = path.worktree_id.to_proto();
11826 result.path = path.path.to_proto();
11827 }
11828 SymbolLocation::OutsideProject {
11829 abs_path,
11830 signature,
11831 } => {
11832 result.path = abs_path.to_string_lossy().into_owned();
11833 result.signature = signature.to_vec();
11834 }
11835 }
11836 result
11837 }
11838
11839 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11840 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11841 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11842 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11843
11844 let path = if serialized_symbol.signature.is_empty() {
11845 SymbolLocation::InProject(ProjectPath {
11846 worktree_id,
11847 path: RelPath::from_proto(&serialized_symbol.path)
11848 .context("invalid symbol path")?,
11849 })
11850 } else {
11851 SymbolLocation::OutsideProject {
11852 abs_path: Path::new(&serialized_symbol.path).into(),
11853 signature: serialized_symbol
11854 .signature
11855 .try_into()
11856 .map_err(|_| anyhow!("invalid signature"))?,
11857 }
11858 };
11859
11860 let start = serialized_symbol.start.context("invalid start")?;
11861 let end = serialized_symbol.end.context("invalid end")?;
11862 Ok(CoreSymbol {
11863 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11864 source_worktree_id,
11865 source_language_server_id: LanguageServerId::from_proto(
11866 serialized_symbol.language_server_id,
11867 ),
11868 path,
11869 name: serialized_symbol.name,
11870 range: Unclipped(PointUtf16::new(start.row, start.column))
11871 ..Unclipped(PointUtf16::new(end.row, end.column)),
11872 kind,
11873 })
11874 }
11875
11876 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11877 let mut serialized_completion = proto::Completion {
11878 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11879 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11880 new_text: completion.new_text.clone(),
11881 ..proto::Completion::default()
11882 };
11883 match &completion.source {
11884 CompletionSource::Lsp {
11885 insert_range,
11886 server_id,
11887 lsp_completion,
11888 lsp_defaults,
11889 resolved,
11890 } => {
11891 let (old_insert_start, old_insert_end) = insert_range
11892 .as_ref()
11893 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11894 .unzip();
11895
11896 serialized_completion.old_insert_start = old_insert_start;
11897 serialized_completion.old_insert_end = old_insert_end;
11898 serialized_completion.source = proto::completion::Source::Lsp as i32;
11899 serialized_completion.server_id = server_id.0 as u64;
11900 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11901 serialized_completion.lsp_defaults = lsp_defaults
11902 .as_deref()
11903 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11904 serialized_completion.resolved = *resolved;
11905 }
11906 CompletionSource::BufferWord {
11907 word_range,
11908 resolved,
11909 } => {
11910 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11911 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11912 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11913 serialized_completion.resolved = *resolved;
11914 }
11915 CompletionSource::Custom => {
11916 serialized_completion.source = proto::completion::Source::Custom as i32;
11917 serialized_completion.resolved = true;
11918 }
11919 CompletionSource::Dap { sort_text } => {
11920 serialized_completion.source = proto::completion::Source::Dap as i32;
11921 serialized_completion.sort_text = Some(sort_text.clone());
11922 }
11923 }
11924
11925 serialized_completion
11926 }
11927
11928 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11929 let old_replace_start = completion
11930 .old_replace_start
11931 .and_then(deserialize_anchor)
11932 .context("invalid old start")?;
11933 let old_replace_end = completion
11934 .old_replace_end
11935 .and_then(deserialize_anchor)
11936 .context("invalid old end")?;
11937 let insert_range = {
11938 match completion.old_insert_start.zip(completion.old_insert_end) {
11939 Some((start, end)) => {
11940 let start = deserialize_anchor(start).context("invalid insert old start")?;
11941 let end = deserialize_anchor(end).context("invalid insert old end")?;
11942 Some(start..end)
11943 }
11944 None => None,
11945 }
11946 };
11947 Ok(CoreCompletion {
11948 replace_range: old_replace_start..old_replace_end,
11949 new_text: completion.new_text,
11950 source: match proto::completion::Source::from_i32(completion.source) {
11951 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11952 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11953 insert_range,
11954 server_id: LanguageServerId::from_proto(completion.server_id),
11955 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11956 lsp_defaults: completion
11957 .lsp_defaults
11958 .as_deref()
11959 .map(serde_json::from_slice)
11960 .transpose()?,
11961 resolved: completion.resolved,
11962 },
11963 Some(proto::completion::Source::BufferWord) => {
11964 let word_range = completion
11965 .buffer_word_start
11966 .and_then(deserialize_anchor)
11967 .context("invalid buffer word start")?
11968 ..completion
11969 .buffer_word_end
11970 .and_then(deserialize_anchor)
11971 .context("invalid buffer word end")?;
11972 CompletionSource::BufferWord {
11973 word_range,
11974 resolved: completion.resolved,
11975 }
11976 }
11977 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11978 sort_text: completion
11979 .sort_text
11980 .context("expected sort text to exist")?,
11981 },
11982 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11983 },
11984 })
11985 }
11986
11987 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11988 let (kind, lsp_action) = match &action.lsp_action {
11989 LspAction::Action(code_action) => (
11990 proto::code_action::Kind::Action as i32,
11991 serde_json::to_vec(code_action).unwrap(),
11992 ),
11993 LspAction::Command(command) => (
11994 proto::code_action::Kind::Command as i32,
11995 serde_json::to_vec(command).unwrap(),
11996 ),
11997 LspAction::CodeLens(code_lens) => (
11998 proto::code_action::Kind::CodeLens as i32,
11999 serde_json::to_vec(code_lens).unwrap(),
12000 ),
12001 };
12002
12003 proto::CodeAction {
12004 server_id: action.server_id.0 as u64,
12005 start: Some(serialize_anchor(&action.range.start)),
12006 end: Some(serialize_anchor(&action.range.end)),
12007 lsp_action,
12008 kind,
12009 resolved: action.resolved,
12010 }
12011 }
12012
12013 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12014 let start = action
12015 .start
12016 .and_then(deserialize_anchor)
12017 .context("invalid start")?;
12018 let end = action
12019 .end
12020 .and_then(deserialize_anchor)
12021 .context("invalid end")?;
12022 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12023 Some(proto::code_action::Kind::Action) => {
12024 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12025 }
12026 Some(proto::code_action::Kind::Command) => {
12027 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12028 }
12029 Some(proto::code_action::Kind::CodeLens) => {
12030 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12031 }
12032 None => anyhow::bail!("Unknown action kind {}", action.kind),
12033 };
12034 Ok(CodeAction {
12035 server_id: LanguageServerId(action.server_id as usize),
12036 range: start..end,
12037 resolved: action.resolved,
12038 lsp_action,
12039 })
12040 }
12041
12042 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12043 match &formatting_result {
12044 Ok(_) => self.last_formatting_failure = None,
12045 Err(error) => {
12046 let error_string = format!("{error:#}");
12047 log::error!("Formatting failed: {error_string}");
12048 self.last_formatting_failure
12049 .replace(error_string.lines().join(" "));
12050 }
12051 }
12052 }
12053
12054 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12055 self.lsp_server_capabilities.remove(&for_server);
12056 for lsp_data in self.lsp_data.values_mut() {
12057 lsp_data.remove_server_data(for_server);
12058 }
12059 if let Some(local) = self.as_local_mut() {
12060 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12061 local
12062 .workspace_pull_diagnostics_result_ids
12063 .remove(&for_server);
12064 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12065 buffer_servers.remove(&for_server);
12066 }
12067 }
12068 }
12069
12070 pub fn result_id_for_buffer_pull(
12071 &self,
12072 server_id: LanguageServerId,
12073 buffer_id: BufferId,
12074 registration_id: &Option<SharedString>,
12075 cx: &App,
12076 ) -> Option<SharedString> {
12077 let abs_path = self
12078 .buffer_store
12079 .read(cx)
12080 .get(buffer_id)
12081 .and_then(|b| File::from_dyn(b.read(cx).file()))
12082 .map(|f| f.abs_path(cx))?;
12083 self.as_local()?
12084 .buffer_pull_diagnostics_result_ids
12085 .get(&server_id)?
12086 .get(registration_id)?
12087 .get(&abs_path)?
12088 .clone()
12089 }
12090
12091 /// Gets all result_ids for a workspace diagnostics pull request.
12092 /// 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.
12093 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12094 pub fn result_ids_for_workspace_refresh(
12095 &self,
12096 server_id: LanguageServerId,
12097 registration_id: &Option<SharedString>,
12098 ) -> HashMap<PathBuf, SharedString> {
12099 let Some(local) = self.as_local() else {
12100 return HashMap::default();
12101 };
12102 local
12103 .workspace_pull_diagnostics_result_ids
12104 .get(&server_id)
12105 .into_iter()
12106 .filter_map(|diagnostics| diagnostics.get(registration_id))
12107 .flatten()
12108 .filter_map(|(abs_path, result_id)| {
12109 let result_id = local
12110 .buffer_pull_diagnostics_result_ids
12111 .get(&server_id)
12112 .and_then(|buffer_ids_result_ids| {
12113 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12114 })
12115 .cloned()
12116 .flatten()
12117 .or_else(|| result_id.clone())?;
12118 Some((abs_path.clone(), result_id))
12119 })
12120 .collect()
12121 }
12122
12123 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12124 if let Some(LanguageServerState::Running {
12125 workspace_diagnostics_refresh_tasks,
12126 ..
12127 }) = self
12128 .as_local_mut()
12129 .and_then(|local| local.language_servers.get_mut(&server_id))
12130 {
12131 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12132 diagnostics.refresh_tx.try_send(()).ok();
12133 }
12134 }
12135 }
12136
12137 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12138 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12139 return;
12140 };
12141 let Some(local) = self.as_local_mut() else {
12142 return;
12143 };
12144
12145 for server_id in buffer.update(cx, |buffer, cx| {
12146 local.language_server_ids_for_buffer(buffer, cx)
12147 }) {
12148 if let Some(LanguageServerState::Running {
12149 workspace_diagnostics_refresh_tasks,
12150 ..
12151 }) = local.language_servers.get_mut(&server_id)
12152 {
12153 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12154 diagnostics.refresh_tx.try_send(()).ok();
12155 }
12156 }
12157 }
12158 }
12159
12160 fn apply_workspace_diagnostic_report(
12161 &mut self,
12162 server_id: LanguageServerId,
12163 report: lsp::WorkspaceDiagnosticReportResult,
12164 registration_id: Option<SharedString>,
12165 cx: &mut Context<Self>,
12166 ) {
12167 let mut workspace_diagnostics =
12168 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12169 report,
12170 server_id,
12171 registration_id,
12172 );
12173 workspace_diagnostics.retain(|d| match &d.diagnostics {
12174 LspPullDiagnostics::Response {
12175 server_id,
12176 registration_id,
12177 ..
12178 } => self.diagnostic_registration_exists(*server_id, registration_id),
12179 LspPullDiagnostics::Default => false,
12180 });
12181 let mut unchanged_buffers = HashMap::default();
12182 let workspace_diagnostics_updates = workspace_diagnostics
12183 .into_iter()
12184 .filter_map(
12185 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12186 LspPullDiagnostics::Response {
12187 server_id,
12188 uri,
12189 diagnostics,
12190 registration_id,
12191 } => Some((
12192 server_id,
12193 uri,
12194 diagnostics,
12195 workspace_diagnostics.version,
12196 registration_id,
12197 )),
12198 LspPullDiagnostics::Default => None,
12199 },
12200 )
12201 .fold(
12202 HashMap::default(),
12203 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12204 let (result_id, diagnostics) = match diagnostics {
12205 PulledDiagnostics::Unchanged { result_id } => {
12206 unchanged_buffers
12207 .entry(new_registration_id.clone())
12208 .or_insert_with(HashSet::default)
12209 .insert(uri.clone());
12210 (Some(result_id), Vec::new())
12211 }
12212 PulledDiagnostics::Changed {
12213 result_id,
12214 diagnostics,
12215 } => (result_id, diagnostics),
12216 };
12217 let disk_based_sources = Cow::Owned(
12218 self.language_server_adapter_for_id(server_id)
12219 .as_ref()
12220 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12221 .unwrap_or(&[])
12222 .to_vec(),
12223 );
12224
12225 let Some(abs_path) = uri.to_file_path().ok() else {
12226 return acc;
12227 };
12228 let Some((worktree, relative_path)) =
12229 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12230 else {
12231 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12232 return acc;
12233 };
12234 let worktree_id = worktree.read(cx).id();
12235 let project_path = ProjectPath {
12236 worktree_id,
12237 path: relative_path,
12238 };
12239 if let Some(local_lsp_store) = self.as_local_mut() {
12240 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12241 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12242 }
12243 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12244 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12245 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12246 acc.entry(server_id)
12247 .or_insert_with(HashMap::default)
12248 .entry(new_registration_id.clone())
12249 .or_insert_with(Vec::new)
12250 .push(DocumentDiagnosticsUpdate {
12251 server_id,
12252 diagnostics: lsp::PublishDiagnosticsParams {
12253 uri,
12254 diagnostics,
12255 version,
12256 },
12257 result_id,
12258 disk_based_sources,
12259 registration_id: new_registration_id,
12260 });
12261 }
12262 acc
12263 },
12264 );
12265
12266 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12267 for (registration_id, diagnostic_updates) in diagnostic_updates {
12268 self.merge_lsp_diagnostics(
12269 DiagnosticSourceKind::Pulled,
12270 diagnostic_updates,
12271 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12272 DiagnosticSourceKind::Pulled => {
12273 old_diagnostic.registration_id != registration_id
12274 || unchanged_buffers
12275 .get(&old_diagnostic.registration_id)
12276 .is_some_and(|unchanged_buffers| {
12277 unchanged_buffers.contains(&document_uri)
12278 })
12279 }
12280 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12281 },
12282 cx,
12283 )
12284 .log_err();
12285 }
12286 }
12287 }
12288
12289 fn register_server_capabilities(
12290 &mut self,
12291 server_id: LanguageServerId,
12292 params: lsp::RegistrationParams,
12293 cx: &mut Context<Self>,
12294 ) -> anyhow::Result<()> {
12295 let server = self
12296 .language_server_for_id(server_id)
12297 .with_context(|| format!("no server {server_id} found"))?;
12298 for reg in params.registrations {
12299 match reg.method.as_str() {
12300 "workspace/didChangeWatchedFiles" => {
12301 if let Some(options) = reg.register_options {
12302 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12303 let caps = serde_json::from_value(options)?;
12304 local_lsp_store
12305 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12306 true
12307 } else {
12308 false
12309 };
12310 if notify {
12311 notify_server_capabilities_updated(&server, cx);
12312 }
12313 }
12314 }
12315 "workspace/didChangeConfiguration" => {
12316 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12317 }
12318 "workspace/didChangeWorkspaceFolders" => {
12319 // In this case register options is an empty object, we can ignore it
12320 let caps = lsp::WorkspaceFoldersServerCapabilities {
12321 supported: Some(true),
12322 change_notifications: Some(OneOf::Right(reg.id)),
12323 };
12324 server.update_capabilities(|capabilities| {
12325 capabilities
12326 .workspace
12327 .get_or_insert_default()
12328 .workspace_folders = Some(caps);
12329 });
12330 notify_server_capabilities_updated(&server, cx);
12331 }
12332 "workspace/symbol" => {
12333 let options = parse_register_capabilities(reg)?;
12334 server.update_capabilities(|capabilities| {
12335 capabilities.workspace_symbol_provider = Some(options);
12336 });
12337 notify_server_capabilities_updated(&server, cx);
12338 }
12339 "workspace/fileOperations" => {
12340 if let Some(options) = reg.register_options {
12341 let caps = serde_json::from_value(options)?;
12342 server.update_capabilities(|capabilities| {
12343 capabilities
12344 .workspace
12345 .get_or_insert_default()
12346 .file_operations = Some(caps);
12347 });
12348 notify_server_capabilities_updated(&server, cx);
12349 }
12350 }
12351 "workspace/executeCommand" => {
12352 if let Some(options) = reg.register_options {
12353 let options = serde_json::from_value(options)?;
12354 server.update_capabilities(|capabilities| {
12355 capabilities.execute_command_provider = Some(options);
12356 });
12357 notify_server_capabilities_updated(&server, cx);
12358 }
12359 }
12360 "textDocument/rangeFormatting" => {
12361 let options = parse_register_capabilities(reg)?;
12362 server.update_capabilities(|capabilities| {
12363 capabilities.document_range_formatting_provider = Some(options);
12364 });
12365 notify_server_capabilities_updated(&server, cx);
12366 }
12367 "textDocument/onTypeFormatting" => {
12368 if let Some(options) = reg
12369 .register_options
12370 .map(serde_json::from_value)
12371 .transpose()?
12372 {
12373 server.update_capabilities(|capabilities| {
12374 capabilities.document_on_type_formatting_provider = Some(options);
12375 });
12376 notify_server_capabilities_updated(&server, cx);
12377 }
12378 }
12379 "textDocument/formatting" => {
12380 let options = parse_register_capabilities(reg)?;
12381 server.update_capabilities(|capabilities| {
12382 capabilities.document_formatting_provider = Some(options);
12383 });
12384 notify_server_capabilities_updated(&server, cx);
12385 }
12386 "textDocument/rename" => {
12387 let options = parse_register_capabilities(reg)?;
12388 server.update_capabilities(|capabilities| {
12389 capabilities.rename_provider = Some(options);
12390 });
12391 notify_server_capabilities_updated(&server, cx);
12392 }
12393 "textDocument/inlayHint" => {
12394 let options = parse_register_capabilities(reg)?;
12395 server.update_capabilities(|capabilities| {
12396 capabilities.inlay_hint_provider = Some(options);
12397 });
12398 notify_server_capabilities_updated(&server, cx);
12399 }
12400 "textDocument/documentSymbol" => {
12401 let options = parse_register_capabilities(reg)?;
12402 server.update_capabilities(|capabilities| {
12403 capabilities.document_symbol_provider = Some(options);
12404 });
12405 notify_server_capabilities_updated(&server, cx);
12406 }
12407 "textDocument/codeAction" => {
12408 let options = parse_register_capabilities(reg)?;
12409 let provider = match options {
12410 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12411 OneOf::Right(caps) => caps,
12412 };
12413 server.update_capabilities(|capabilities| {
12414 capabilities.code_action_provider = Some(provider);
12415 });
12416 notify_server_capabilities_updated(&server, cx);
12417 }
12418 "textDocument/definition" => {
12419 let options = parse_register_capabilities(reg)?;
12420 server.update_capabilities(|capabilities| {
12421 capabilities.definition_provider = Some(options);
12422 });
12423 notify_server_capabilities_updated(&server, cx);
12424 }
12425 "textDocument/completion" => {
12426 if let Some(caps) = reg
12427 .register_options
12428 .map(serde_json::from_value::<CompletionOptions>)
12429 .transpose()?
12430 {
12431 server.update_capabilities(|capabilities| {
12432 capabilities.completion_provider = Some(caps.clone());
12433 });
12434
12435 if let Some(local) = self.as_local() {
12436 let mut buffers_with_language_server = Vec::new();
12437 for handle in self.buffer_store.read(cx).buffers() {
12438 let buffer_id = handle.read(cx).remote_id();
12439 if local
12440 .buffers_opened_in_servers
12441 .get(&buffer_id)
12442 .filter(|s| s.contains(&server_id))
12443 .is_some()
12444 {
12445 buffers_with_language_server.push(handle);
12446 }
12447 }
12448 let triggers = caps
12449 .trigger_characters
12450 .unwrap_or_default()
12451 .into_iter()
12452 .collect::<BTreeSet<_>>();
12453 for handle in buffers_with_language_server {
12454 let triggers = triggers.clone();
12455 let _ = handle.update(cx, move |buffer, cx| {
12456 buffer.set_completion_triggers(server_id, triggers, cx);
12457 });
12458 }
12459 }
12460 notify_server_capabilities_updated(&server, cx);
12461 }
12462 }
12463 "textDocument/hover" => {
12464 let options = parse_register_capabilities(reg)?;
12465 let provider = match options {
12466 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12467 OneOf::Right(caps) => caps,
12468 };
12469 server.update_capabilities(|capabilities| {
12470 capabilities.hover_provider = Some(provider);
12471 });
12472 notify_server_capabilities_updated(&server, cx);
12473 }
12474 "textDocument/signatureHelp" => {
12475 if let Some(caps) = reg
12476 .register_options
12477 .map(serde_json::from_value)
12478 .transpose()?
12479 {
12480 server.update_capabilities(|capabilities| {
12481 capabilities.signature_help_provider = Some(caps);
12482 });
12483 notify_server_capabilities_updated(&server, cx);
12484 }
12485 }
12486 "textDocument/didChange" => {
12487 if let Some(sync_kind) = reg
12488 .register_options
12489 .and_then(|opts| opts.get("syncKind").cloned())
12490 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12491 .transpose()?
12492 {
12493 server.update_capabilities(|capabilities| {
12494 let mut sync_options =
12495 Self::take_text_document_sync_options(capabilities);
12496 sync_options.change = Some(sync_kind);
12497 capabilities.text_document_sync =
12498 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12499 });
12500 notify_server_capabilities_updated(&server, cx);
12501 }
12502 }
12503 "textDocument/didSave" => {
12504 if let Some(include_text) = reg
12505 .register_options
12506 .map(|opts| {
12507 let transpose = opts
12508 .get("includeText")
12509 .cloned()
12510 .map(serde_json::from_value::<Option<bool>>)
12511 .transpose();
12512 match transpose {
12513 Ok(value) => Ok(value.flatten()),
12514 Err(e) => Err(e),
12515 }
12516 })
12517 .transpose()?
12518 {
12519 server.update_capabilities(|capabilities| {
12520 let mut sync_options =
12521 Self::take_text_document_sync_options(capabilities);
12522 sync_options.save =
12523 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12524 include_text,
12525 }));
12526 capabilities.text_document_sync =
12527 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12528 });
12529 notify_server_capabilities_updated(&server, cx);
12530 }
12531 }
12532 "textDocument/codeLens" => {
12533 if let Some(caps) = reg
12534 .register_options
12535 .map(serde_json::from_value)
12536 .transpose()?
12537 {
12538 server.update_capabilities(|capabilities| {
12539 capabilities.code_lens_provider = Some(caps);
12540 });
12541 notify_server_capabilities_updated(&server, cx);
12542 }
12543 }
12544 "textDocument/diagnostic" => {
12545 if let Some(caps) = reg
12546 .register_options
12547 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12548 .transpose()?
12549 {
12550 let local = self
12551 .as_local_mut()
12552 .context("Expected LSP Store to be local")?;
12553 let state = local
12554 .language_servers
12555 .get_mut(&server_id)
12556 .context("Could not obtain Language Servers state")?;
12557 local
12558 .language_server_dynamic_registrations
12559 .entry(server_id)
12560 .or_default()
12561 .diagnostics
12562 .insert(Some(reg.id.clone()), caps.clone());
12563
12564 let supports_workspace_diagnostics =
12565 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12566 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12567 diagnostic_options.workspace_diagnostics
12568 }
12569 DiagnosticServerCapabilities::RegistrationOptions(
12570 diagnostic_registration_options,
12571 ) => {
12572 diagnostic_registration_options
12573 .diagnostic_options
12574 .workspace_diagnostics
12575 }
12576 };
12577
12578 if supports_workspace_diagnostics(&caps) {
12579 if let LanguageServerState::Running {
12580 workspace_diagnostics_refresh_tasks,
12581 ..
12582 } = state
12583 && let Some(task) = lsp_workspace_diagnostics_refresh(
12584 Some(reg.id.clone()),
12585 caps.clone(),
12586 server.clone(),
12587 cx,
12588 )
12589 {
12590 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12591 }
12592 }
12593
12594 server.update_capabilities(|capabilities| {
12595 capabilities.diagnostic_provider = Some(caps);
12596 });
12597
12598 notify_server_capabilities_updated(&server, cx);
12599
12600 let buffers_to_pull: Vec<_> = self
12601 .as_local()
12602 .into_iter()
12603 .flat_map(|local| {
12604 self.buffer_store.read(cx).buffers().filter(|buffer| {
12605 let buffer_id = buffer.read(cx).remote_id();
12606 local
12607 .buffers_opened_in_servers
12608 .get(&buffer_id)
12609 .is_some_and(|servers| servers.contains(&server_id))
12610 })
12611 })
12612 .collect();
12613 for buffer in buffers_to_pull {
12614 self.pull_diagnostics_for_buffer(buffer, cx).detach();
12615 }
12616 }
12617 }
12618 "textDocument/documentColor" => {
12619 let options = parse_register_capabilities(reg)?;
12620 let provider = match options {
12621 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12622 OneOf::Right(caps) => caps,
12623 };
12624 server.update_capabilities(|capabilities| {
12625 capabilities.color_provider = Some(provider);
12626 });
12627 notify_server_capabilities_updated(&server, cx);
12628 }
12629 _ => log::warn!("unhandled capability registration: {reg:?}"),
12630 }
12631 }
12632
12633 Ok(())
12634 }
12635
12636 fn unregister_server_capabilities(
12637 &mut self,
12638 server_id: LanguageServerId,
12639 params: lsp::UnregistrationParams,
12640 cx: &mut Context<Self>,
12641 ) -> anyhow::Result<()> {
12642 let server = self
12643 .language_server_for_id(server_id)
12644 .with_context(|| format!("no server {server_id} found"))?;
12645 for unreg in params.unregisterations.iter() {
12646 match unreg.method.as_str() {
12647 "workspace/didChangeWatchedFiles" => {
12648 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12649 local_lsp_store
12650 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12651 true
12652 } else {
12653 false
12654 };
12655 if notify {
12656 notify_server_capabilities_updated(&server, cx);
12657 }
12658 }
12659 "workspace/didChangeConfiguration" => {
12660 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12661 }
12662 "workspace/didChangeWorkspaceFolders" => {
12663 server.update_capabilities(|capabilities| {
12664 capabilities
12665 .workspace
12666 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12667 workspace_folders: None,
12668 file_operations: None,
12669 })
12670 .workspace_folders = None;
12671 });
12672 notify_server_capabilities_updated(&server, cx);
12673 }
12674 "workspace/symbol" => {
12675 server.update_capabilities(|capabilities| {
12676 capabilities.workspace_symbol_provider = None
12677 });
12678 notify_server_capabilities_updated(&server, cx);
12679 }
12680 "workspace/fileOperations" => {
12681 server.update_capabilities(|capabilities| {
12682 capabilities
12683 .workspace
12684 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12685 workspace_folders: None,
12686 file_operations: None,
12687 })
12688 .file_operations = None;
12689 });
12690 notify_server_capabilities_updated(&server, cx);
12691 }
12692 "workspace/executeCommand" => {
12693 server.update_capabilities(|capabilities| {
12694 capabilities.execute_command_provider = None;
12695 });
12696 notify_server_capabilities_updated(&server, cx);
12697 }
12698 "textDocument/rangeFormatting" => {
12699 server.update_capabilities(|capabilities| {
12700 capabilities.document_range_formatting_provider = None
12701 });
12702 notify_server_capabilities_updated(&server, cx);
12703 }
12704 "textDocument/onTypeFormatting" => {
12705 server.update_capabilities(|capabilities| {
12706 capabilities.document_on_type_formatting_provider = None;
12707 });
12708 notify_server_capabilities_updated(&server, cx);
12709 }
12710 "textDocument/formatting" => {
12711 server.update_capabilities(|capabilities| {
12712 capabilities.document_formatting_provider = None;
12713 });
12714 notify_server_capabilities_updated(&server, cx);
12715 }
12716 "textDocument/rename" => {
12717 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12718 notify_server_capabilities_updated(&server, cx);
12719 }
12720 "textDocument/codeAction" => {
12721 server.update_capabilities(|capabilities| {
12722 capabilities.code_action_provider = None;
12723 });
12724 notify_server_capabilities_updated(&server, cx);
12725 }
12726 "textDocument/definition" => {
12727 server.update_capabilities(|capabilities| {
12728 capabilities.definition_provider = None;
12729 });
12730 notify_server_capabilities_updated(&server, cx);
12731 }
12732 "textDocument/completion" => {
12733 server.update_capabilities(|capabilities| {
12734 capabilities.completion_provider = None;
12735 });
12736 notify_server_capabilities_updated(&server, cx);
12737 }
12738 "textDocument/hover" => {
12739 server.update_capabilities(|capabilities| {
12740 capabilities.hover_provider = None;
12741 });
12742 notify_server_capabilities_updated(&server, cx);
12743 }
12744 "textDocument/signatureHelp" => {
12745 server.update_capabilities(|capabilities| {
12746 capabilities.signature_help_provider = None;
12747 });
12748 notify_server_capabilities_updated(&server, cx);
12749 }
12750 "textDocument/didChange" => {
12751 server.update_capabilities(|capabilities| {
12752 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12753 sync_options.change = None;
12754 capabilities.text_document_sync =
12755 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12756 });
12757 notify_server_capabilities_updated(&server, cx);
12758 }
12759 "textDocument/didSave" => {
12760 server.update_capabilities(|capabilities| {
12761 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12762 sync_options.save = None;
12763 capabilities.text_document_sync =
12764 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12765 });
12766 notify_server_capabilities_updated(&server, cx);
12767 }
12768 "textDocument/codeLens" => {
12769 server.update_capabilities(|capabilities| {
12770 capabilities.code_lens_provider = None;
12771 });
12772 notify_server_capabilities_updated(&server, cx);
12773 }
12774 "textDocument/diagnostic" => {
12775 let local = self
12776 .as_local_mut()
12777 .context("Expected LSP Store to be local")?;
12778
12779 let state = local
12780 .language_servers
12781 .get_mut(&server_id)
12782 .context("Could not obtain Language Servers state")?;
12783 let registrations = local
12784 .language_server_dynamic_registrations
12785 .get_mut(&server_id)
12786 .with_context(|| {
12787 format!("Expected dynamic registration to exist for server {server_id}")
12788 })?;
12789 registrations.diagnostics
12790 .remove(&Some(unreg.id.clone()))
12791 .with_context(|| format!(
12792 "Attempted to unregister non-existent diagnostic registration with ID {}",
12793 unreg.id)
12794 )?;
12795 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12796
12797 if let LanguageServerState::Running {
12798 workspace_diagnostics_refresh_tasks,
12799 ..
12800 } = state
12801 {
12802 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12803 }
12804
12805 self.clear_unregistered_diagnostics(
12806 server_id,
12807 SharedString::from(unreg.id.clone()),
12808 cx,
12809 )?;
12810
12811 if removed_last_diagnostic_provider {
12812 server.update_capabilities(|capabilities| {
12813 debug_assert!(capabilities.diagnostic_provider.is_some());
12814 capabilities.diagnostic_provider = None;
12815 });
12816 }
12817
12818 notify_server_capabilities_updated(&server, cx);
12819 }
12820 "textDocument/documentColor" => {
12821 server.update_capabilities(|capabilities| {
12822 capabilities.color_provider = None;
12823 });
12824 notify_server_capabilities_updated(&server, cx);
12825 }
12826 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12827 }
12828 }
12829
12830 Ok(())
12831 }
12832
12833 fn clear_unregistered_diagnostics(
12834 &mut self,
12835 server_id: LanguageServerId,
12836 cleared_registration_id: SharedString,
12837 cx: &mut Context<Self>,
12838 ) -> anyhow::Result<()> {
12839 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12840
12841 self.buffer_store.update(cx, |buffer_store, cx| {
12842 for buffer_handle in buffer_store.buffers() {
12843 let buffer = buffer_handle.read(cx);
12844 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12845 let Some(abs_path) = abs_path else {
12846 continue;
12847 };
12848 affected_abs_paths.insert(abs_path);
12849 }
12850 });
12851
12852 let local = self.as_local().context("Expected LSP Store to be local")?;
12853 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12854 let Some(worktree) = self
12855 .worktree_store
12856 .read(cx)
12857 .worktree_for_id(*worktree_id, cx)
12858 else {
12859 continue;
12860 };
12861
12862 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12863 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12864 let has_matching_registration =
12865 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12866 entry.diagnostic.registration_id.as_ref()
12867 == Some(&cleared_registration_id)
12868 });
12869 if has_matching_registration {
12870 let abs_path = worktree.read(cx).absolutize(rel_path);
12871 affected_abs_paths.insert(abs_path);
12872 }
12873 }
12874 }
12875 }
12876
12877 if affected_abs_paths.is_empty() {
12878 return Ok(());
12879 }
12880
12881 // Send a fake diagnostic update which clears the state for the registration ID
12882 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12883 affected_abs_paths
12884 .into_iter()
12885 .map(|abs_path| DocumentDiagnosticsUpdate {
12886 diagnostics: DocumentDiagnostics {
12887 diagnostics: Vec::new(),
12888 document_abs_path: abs_path,
12889 version: None,
12890 },
12891 result_id: None,
12892 registration_id: Some(cleared_registration_id.clone()),
12893 server_id,
12894 disk_based_sources: Cow::Borrowed(&[]),
12895 })
12896 .collect();
12897
12898 let merge_registration_id = cleared_registration_id.clone();
12899 self.merge_diagnostic_entries(
12900 clears,
12901 move |_, diagnostic, _| {
12902 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12903 diagnostic.registration_id != Some(merge_registration_id.clone())
12904 } else {
12905 true
12906 }
12907 },
12908 cx,
12909 )?;
12910
12911 Ok(())
12912 }
12913
12914 async fn deduplicate_range_based_lsp_requests<T>(
12915 lsp_store: &Entity<Self>,
12916 server_id: Option<LanguageServerId>,
12917 lsp_request_id: LspRequestId,
12918 proto_request: &T::ProtoRequest,
12919 range: Range<Anchor>,
12920 cx: &mut AsyncApp,
12921 ) -> Result<()>
12922 where
12923 T: LspCommand,
12924 T::ProtoRequest: proto::LspRequestMessage,
12925 {
12926 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12927 let version = deserialize_version(proto_request.buffer_version());
12928 let buffer = lsp_store.update(cx, |this, cx| {
12929 this.buffer_store.read(cx).get_existing(buffer_id)
12930 })??;
12931 buffer
12932 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12933 .await?;
12934 lsp_store.update(cx, |lsp_store, cx| {
12935 let buffer_snapshot = buffer.read(cx).snapshot();
12936 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12937 let chunks_queried_for = lsp_data
12938 .inlay_hints
12939 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12940 .collect::<Vec<_>>();
12941 match chunks_queried_for.as_slice() {
12942 &[chunk] => {
12943 let key = LspKey {
12944 request_type: TypeId::of::<T>(),
12945 server_queried: server_id,
12946 };
12947 let previous_request = lsp_data
12948 .chunk_lsp_requests
12949 .entry(key)
12950 .or_default()
12951 .insert(chunk, lsp_request_id);
12952 if let Some((previous_request, running_requests)) =
12953 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12954 {
12955 running_requests.remove(&previous_request);
12956 }
12957 }
12958 _ambiguous_chunks => {
12959 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12960 // there, a buffer version-based check will be performed and outdated requests discarded.
12961 }
12962 }
12963 anyhow::Ok(())
12964 })??;
12965
12966 Ok(())
12967 }
12968
12969 async fn query_lsp_locally<T>(
12970 lsp_store: Entity<Self>,
12971 for_server_id: Option<LanguageServerId>,
12972 sender_id: proto::PeerId,
12973 lsp_request_id: LspRequestId,
12974 proto_request: T::ProtoRequest,
12975 position: Option<Anchor>,
12976 cx: &mut AsyncApp,
12977 ) -> Result<()>
12978 where
12979 T: LspCommand + Clone,
12980 T::ProtoRequest: proto::LspRequestMessage,
12981 <T::ProtoRequest as proto::RequestMessage>::Response:
12982 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12983 {
12984 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12985 let version = deserialize_version(proto_request.buffer_version());
12986 let buffer = lsp_store.update(cx, |this, cx| {
12987 this.buffer_store.read(cx).get_existing(buffer_id)
12988 })??;
12989 buffer
12990 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12991 .await?;
12992 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12993 let request =
12994 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12995 let key = LspKey {
12996 request_type: TypeId::of::<T>(),
12997 server_queried: for_server_id,
12998 };
12999 lsp_store.update(cx, |lsp_store, cx| {
13000 let request_task = match for_server_id {
13001 Some(server_id) => {
13002 let server_task = lsp_store.request_lsp(
13003 buffer.clone(),
13004 LanguageServerToQuery::Other(server_id),
13005 request.clone(),
13006 cx,
13007 );
13008 cx.background_spawn(async move {
13009 let mut responses = Vec::new();
13010 match server_task.await {
13011 Ok(response) => responses.push((server_id, response)),
13012 // rust-analyzer likes to error with this when its still loading up
13013 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13014 Err(e) => log::error!(
13015 "Error handling response for request {request:?}: {e:#}"
13016 ),
13017 }
13018 responses
13019 })
13020 }
13021 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13022 };
13023 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13024 if T::ProtoRequest::stop_previous_requests() {
13025 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13026 lsp_requests.clear();
13027 }
13028 }
13029 lsp_data.lsp_requests.entry(key).or_default().insert(
13030 lsp_request_id,
13031 cx.spawn(async move |lsp_store, cx| {
13032 let response = request_task.await;
13033 lsp_store
13034 .update(cx, |lsp_store, cx| {
13035 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13036 {
13037 let response = response
13038 .into_iter()
13039 .map(|(server_id, response)| {
13040 (
13041 server_id.to_proto(),
13042 T::response_to_proto(
13043 response,
13044 lsp_store,
13045 sender_id,
13046 &buffer_version,
13047 cx,
13048 )
13049 .into(),
13050 )
13051 })
13052 .collect::<HashMap<_, _>>();
13053 match client.send_lsp_response::<T::ProtoRequest>(
13054 project_id,
13055 lsp_request_id,
13056 response,
13057 ) {
13058 Ok(()) => {}
13059 Err(e) => {
13060 log::error!("Failed to send LSP response: {e:#}",)
13061 }
13062 }
13063 }
13064 })
13065 .ok();
13066 }),
13067 );
13068 })?;
13069 Ok(())
13070 }
13071
13072 fn take_text_document_sync_options(
13073 capabilities: &mut lsp::ServerCapabilities,
13074 ) -> lsp::TextDocumentSyncOptions {
13075 match capabilities.text_document_sync.take() {
13076 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13077 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13078 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13079 sync_options.change = Some(sync_kind);
13080 sync_options
13081 }
13082 None => lsp::TextDocumentSyncOptions::default(),
13083 }
13084 }
13085
13086 #[cfg(any(test, feature = "test-support"))]
13087 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13088 Some(
13089 self.lsp_data
13090 .get_mut(&buffer_id)?
13091 .code_lens
13092 .take()?
13093 .update
13094 .take()?
13095 .1,
13096 )
13097 }
13098
13099 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13100 self.downstream_client.clone()
13101 }
13102
13103 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13104 self.worktree_store.clone()
13105 }
13106
13107 /// Gets what's stored in the LSP data for the given buffer.
13108 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13109 self.lsp_data.get_mut(&buffer_id)
13110 }
13111
13112 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13113 /// new [`BufferLspData`] will be created to replace the previous state.
13114 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13115 let (buffer_id, buffer_version) =
13116 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13117 let lsp_data = self
13118 .lsp_data
13119 .entry(buffer_id)
13120 .or_insert_with(|| BufferLspData::new(buffer, cx));
13121 if buffer_version.changed_since(&lsp_data.buffer_version) {
13122 *lsp_data = BufferLspData::new(buffer, cx);
13123 }
13124 lsp_data
13125 }
13126}
13127
13128// Registration with registerOptions as null, should fallback to true.
13129// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13130fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13131 reg: lsp::Registration,
13132) -> Result<OneOf<bool, T>> {
13133 Ok(match reg.register_options {
13134 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13135 None => OneOf::Left(true),
13136 })
13137}
13138
13139fn subscribe_to_binary_statuses(
13140 languages: &Arc<LanguageRegistry>,
13141 cx: &mut Context<'_, LspStore>,
13142) -> Task<()> {
13143 let mut server_statuses = languages.language_server_binary_statuses();
13144 cx.spawn(async move |lsp_store, cx| {
13145 while let Some((server_name, binary_status)) = server_statuses.next().await {
13146 if lsp_store
13147 .update(cx, |_, cx| {
13148 let mut message = None;
13149 let binary_status = match binary_status {
13150 BinaryStatus::None => proto::ServerBinaryStatus::None,
13151 BinaryStatus::CheckingForUpdate => {
13152 proto::ServerBinaryStatus::CheckingForUpdate
13153 }
13154 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13155 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13156 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13157 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13158 BinaryStatus::Failed { error } => {
13159 message = Some(error);
13160 proto::ServerBinaryStatus::Failed
13161 }
13162 };
13163 cx.emit(LspStoreEvent::LanguageServerUpdate {
13164 // Binary updates are about the binary that might not have any language server id at that point.
13165 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13166 language_server_id: LanguageServerId(0),
13167 name: Some(server_name),
13168 message: proto::update_language_server::Variant::StatusUpdate(
13169 proto::StatusUpdate {
13170 message,
13171 status: Some(proto::status_update::Status::Binary(
13172 binary_status as i32,
13173 )),
13174 },
13175 ),
13176 });
13177 })
13178 .is_err()
13179 {
13180 break;
13181 }
13182 }
13183 })
13184}
13185
13186fn lsp_workspace_diagnostics_refresh(
13187 registration_id: Option<String>,
13188 options: DiagnosticServerCapabilities,
13189 server: Arc<LanguageServer>,
13190 cx: &mut Context<'_, LspStore>,
13191) -> Option<WorkspaceRefreshTask> {
13192 let identifier = workspace_diagnostic_identifier(&options)?;
13193 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13194
13195 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13196 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13197 refresh_tx.try_send(()).ok();
13198
13199 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13200 let mut attempts = 0;
13201 let max_attempts = 50;
13202 let mut requests = 0;
13203
13204 loop {
13205 let Some(()) = refresh_rx.recv().await else {
13206 return;
13207 };
13208
13209 'request: loop {
13210 requests += 1;
13211 if attempts > max_attempts {
13212 log::error!(
13213 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13214 );
13215 return;
13216 }
13217 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13218 cx.background_executor()
13219 .timer(Duration::from_millis(backoff_millis))
13220 .await;
13221 attempts += 1;
13222
13223 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13224 lsp_store
13225 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13226 .into_iter()
13227 .filter_map(|(abs_path, result_id)| {
13228 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13229 Some(lsp::PreviousResultId {
13230 uri,
13231 value: result_id.to_string(),
13232 })
13233 })
13234 .collect()
13235 }) else {
13236 return;
13237 };
13238
13239 let token = if let Some(registration_id) = ®istration_id {
13240 format!(
13241 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13242 server.server_id(),
13243 )
13244 } else {
13245 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13246 };
13247
13248 progress_rx.try_recv().ok();
13249 let timer =
13250 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13251 let progress = pin!(progress_rx.recv().fuse());
13252 let response_result = server
13253 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13254 lsp::WorkspaceDiagnosticParams {
13255 previous_result_ids,
13256 identifier: identifier.clone(),
13257 work_done_progress_params: Default::default(),
13258 partial_result_params: lsp::PartialResultParams {
13259 partial_result_token: Some(lsp::ProgressToken::String(token)),
13260 },
13261 },
13262 select(timer, progress).then(|either| match either {
13263 Either::Left((message, ..)) => ready(message).left_future(),
13264 Either::Right(..) => pending::<String>().right_future(),
13265 }),
13266 )
13267 .await;
13268
13269 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13270 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13271 match response_result {
13272 ConnectionResult::Timeout => {
13273 log::error!("Timeout during workspace diagnostics pull");
13274 continue 'request;
13275 }
13276 ConnectionResult::ConnectionReset => {
13277 log::error!("Server closed a workspace diagnostics pull request");
13278 continue 'request;
13279 }
13280 ConnectionResult::Result(Err(e)) => {
13281 log::error!("Error during workspace diagnostics pull: {e:#}");
13282 break 'request;
13283 }
13284 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13285 attempts = 0;
13286 if lsp_store
13287 .update(cx, |lsp_store, cx| {
13288 lsp_store.apply_workspace_diagnostic_report(
13289 server.server_id(),
13290 pulled_diagnostics,
13291 registration_id_shared.clone(),
13292 cx,
13293 )
13294 })
13295 .is_err()
13296 {
13297 return;
13298 }
13299 break 'request;
13300 }
13301 }
13302 }
13303 }
13304 });
13305
13306 Some(WorkspaceRefreshTask {
13307 refresh_tx,
13308 progress_tx,
13309 task: workspace_query_language_server,
13310 })
13311}
13312
13313fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13314 match &options {
13315 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13316 diagnostic_options.identifier.clone()
13317 }
13318 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13319 let diagnostic_options = ®istration_options.diagnostic_options;
13320 diagnostic_options.identifier.clone()
13321 }
13322 }
13323}
13324
13325fn workspace_diagnostic_identifier(
13326 options: &DiagnosticServerCapabilities,
13327) -> Option<Option<String>> {
13328 match &options {
13329 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13330 if !diagnostic_options.workspace_diagnostics {
13331 return None;
13332 }
13333 Some(diagnostic_options.identifier.clone())
13334 }
13335 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13336 let diagnostic_options = ®istration_options.diagnostic_options;
13337 if !diagnostic_options.workspace_diagnostics {
13338 return None;
13339 }
13340 Some(diagnostic_options.identifier.clone())
13341 }
13342 }
13343}
13344
13345fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13346 let CompletionSource::BufferWord {
13347 word_range,
13348 resolved,
13349 } = &mut completion.source
13350 else {
13351 return;
13352 };
13353 if *resolved {
13354 return;
13355 }
13356
13357 if completion.new_text
13358 != snapshot
13359 .text_for_range(word_range.clone())
13360 .collect::<String>()
13361 {
13362 return;
13363 }
13364
13365 let mut offset = 0;
13366 for chunk in snapshot.chunks(word_range.clone(), true) {
13367 let end_offset = offset + chunk.text.len();
13368 if let Some(highlight_id) = chunk.syntax_highlight_id {
13369 completion
13370 .label
13371 .runs
13372 .push((offset..end_offset, highlight_id));
13373 }
13374 offset = end_offset;
13375 }
13376 *resolved = true;
13377}
13378
13379impl EventEmitter<LspStoreEvent> for LspStore {}
13380
13381fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13382 hover
13383 .contents
13384 .retain(|hover_block| !hover_block.text.trim().is_empty());
13385 if hover.contents.is_empty() {
13386 None
13387 } else {
13388 Some(hover)
13389 }
13390}
13391
13392async fn populate_labels_for_completions(
13393 new_completions: Vec<CoreCompletion>,
13394 language: Option<Arc<Language>>,
13395 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13396) -> Vec<Completion> {
13397 let lsp_completions = new_completions
13398 .iter()
13399 .filter_map(|new_completion| {
13400 new_completion
13401 .source
13402 .lsp_completion(true)
13403 .map(|lsp_completion| lsp_completion.into_owned())
13404 })
13405 .collect::<Vec<_>>();
13406
13407 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13408 lsp_adapter
13409 .labels_for_completions(&lsp_completions, language)
13410 .await
13411 .log_err()
13412 .unwrap_or_default()
13413 } else {
13414 Vec::new()
13415 }
13416 .into_iter()
13417 .fuse();
13418
13419 let mut completions = Vec::new();
13420 for completion in new_completions {
13421 match completion.source.lsp_completion(true) {
13422 Some(lsp_completion) => {
13423 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13424
13425 let mut label = labels.next().flatten().unwrap_or_else(|| {
13426 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13427 });
13428 ensure_uniform_list_compatible_label(&mut label);
13429 completions.push(Completion {
13430 label,
13431 documentation,
13432 replace_range: completion.replace_range,
13433 new_text: completion.new_text,
13434 insert_text_mode: lsp_completion.insert_text_mode,
13435 source: completion.source,
13436 icon_path: None,
13437 confirm: None,
13438 match_start: None,
13439 snippet_deduplication_key: None,
13440 });
13441 }
13442 None => {
13443 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13444 ensure_uniform_list_compatible_label(&mut label);
13445 completions.push(Completion {
13446 label,
13447 documentation: None,
13448 replace_range: completion.replace_range,
13449 new_text: completion.new_text,
13450 source: completion.source,
13451 insert_text_mode: None,
13452 icon_path: None,
13453 confirm: None,
13454 match_start: None,
13455 snippet_deduplication_key: None,
13456 });
13457 }
13458 }
13459 }
13460 completions
13461}
13462
13463#[derive(Debug)]
13464pub enum LanguageServerToQuery {
13465 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13466 FirstCapable,
13467 /// Query a specific language server.
13468 Other(LanguageServerId),
13469}
13470
13471#[derive(Default)]
13472struct RenamePathsWatchedForServer {
13473 did_rename: Vec<RenameActionPredicate>,
13474 will_rename: Vec<RenameActionPredicate>,
13475}
13476
13477impl RenamePathsWatchedForServer {
13478 fn with_did_rename_patterns(
13479 mut self,
13480 did_rename: Option<&FileOperationRegistrationOptions>,
13481 ) -> Self {
13482 if let Some(did_rename) = did_rename {
13483 self.did_rename = did_rename
13484 .filters
13485 .iter()
13486 .filter_map(|filter| filter.try_into().log_err())
13487 .collect();
13488 }
13489 self
13490 }
13491 fn with_will_rename_patterns(
13492 mut self,
13493 will_rename: Option<&FileOperationRegistrationOptions>,
13494 ) -> Self {
13495 if let Some(will_rename) = will_rename {
13496 self.will_rename = will_rename
13497 .filters
13498 .iter()
13499 .filter_map(|filter| filter.try_into().log_err())
13500 .collect();
13501 }
13502 self
13503 }
13504
13505 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13506 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13507 }
13508 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13509 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13510 }
13511}
13512
13513impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13514 type Error = globset::Error;
13515 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13516 Ok(Self {
13517 kind: ops.pattern.matches.clone(),
13518 glob: GlobBuilder::new(&ops.pattern.glob)
13519 .case_insensitive(
13520 ops.pattern
13521 .options
13522 .as_ref()
13523 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13524 )
13525 .build()?
13526 .compile_matcher(),
13527 })
13528 }
13529}
13530struct RenameActionPredicate {
13531 glob: GlobMatcher,
13532 kind: Option<FileOperationPatternKind>,
13533}
13534
13535impl RenameActionPredicate {
13536 // Returns true if language server should be notified
13537 fn eval(&self, path: &str, is_dir: bool) -> bool {
13538 self.kind.as_ref().is_none_or(|kind| {
13539 let expected_kind = if is_dir {
13540 FileOperationPatternKind::Folder
13541 } else {
13542 FileOperationPatternKind::File
13543 };
13544 kind == &expected_kind
13545 }) && self.glob.is_match(path)
13546 }
13547}
13548
13549#[derive(Default)]
13550struct LanguageServerWatchedPaths {
13551 worktree_paths: HashMap<WorktreeId, GlobSet>,
13552 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13553}
13554
13555#[derive(Default)]
13556struct LanguageServerWatchedPathsBuilder {
13557 worktree_paths: HashMap<WorktreeId, GlobSet>,
13558 abs_paths: HashMap<Arc<Path>, GlobSet>,
13559}
13560
13561impl LanguageServerWatchedPathsBuilder {
13562 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13563 self.worktree_paths.insert(worktree_id, glob_set);
13564 }
13565 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13566 self.abs_paths.insert(path, glob_set);
13567 }
13568 fn build(
13569 self,
13570 fs: Arc<dyn Fs>,
13571 language_server_id: LanguageServerId,
13572 cx: &mut Context<LspStore>,
13573 ) -> LanguageServerWatchedPaths {
13574 let lsp_store = cx.weak_entity();
13575
13576 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13577 let abs_paths = self
13578 .abs_paths
13579 .into_iter()
13580 .map(|(abs_path, globset)| {
13581 let task = cx.spawn({
13582 let abs_path = abs_path.clone();
13583 let fs = fs.clone();
13584
13585 let lsp_store = lsp_store.clone();
13586 async move |_, cx| {
13587 maybe!(async move {
13588 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13589 while let Some(update) = push_updates.0.next().await {
13590 let action = lsp_store
13591 .update(cx, |this, _| {
13592 let Some(local) = this.as_local() else {
13593 return ControlFlow::Break(());
13594 };
13595 let Some(watcher) = local
13596 .language_server_watched_paths
13597 .get(&language_server_id)
13598 else {
13599 return ControlFlow::Break(());
13600 };
13601 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13602 "Watched abs path is not registered with a watcher",
13603 );
13604 let matching_entries = update
13605 .into_iter()
13606 .filter(|event| globs.is_match(&event.path))
13607 .collect::<Vec<_>>();
13608 this.lsp_notify_abs_paths_changed(
13609 language_server_id,
13610 matching_entries,
13611 );
13612 ControlFlow::Continue(())
13613 })
13614 .ok()?;
13615
13616 if action.is_break() {
13617 break;
13618 }
13619 }
13620 Some(())
13621 })
13622 .await;
13623 }
13624 });
13625 (abs_path, (globset, task))
13626 })
13627 .collect();
13628 LanguageServerWatchedPaths {
13629 worktree_paths: self.worktree_paths,
13630 abs_paths,
13631 }
13632 }
13633}
13634
13635struct LspBufferSnapshot {
13636 version: i32,
13637 snapshot: TextBufferSnapshot,
13638}
13639
13640/// A prompt requested by LSP server.
13641#[derive(Clone, Debug)]
13642pub struct LanguageServerPromptRequest {
13643 pub level: PromptLevel,
13644 pub message: String,
13645 pub actions: Vec<MessageActionItem>,
13646 pub lsp_name: String,
13647 pub(crate) response_channel: Sender<MessageActionItem>,
13648}
13649
13650impl LanguageServerPromptRequest {
13651 pub async fn respond(self, index: usize) -> Option<()> {
13652 if let Some(response) = self.actions.into_iter().nth(index) {
13653 self.response_channel.send(response).await.ok()
13654 } else {
13655 None
13656 }
13657 }
13658}
13659impl PartialEq for LanguageServerPromptRequest {
13660 fn eq(&self, other: &Self) -> bool {
13661 self.message == other.message && self.actions == other.actions
13662 }
13663}
13664
13665#[derive(Clone, Debug, PartialEq)]
13666pub enum LanguageServerLogType {
13667 Log(MessageType),
13668 Trace { verbose_info: Option<String> },
13669 Rpc { received: bool },
13670}
13671
13672impl LanguageServerLogType {
13673 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13674 match self {
13675 Self::Log(log_type) => {
13676 use proto::log_message::LogLevel;
13677 let level = match *log_type {
13678 MessageType::ERROR => LogLevel::Error,
13679 MessageType::WARNING => LogLevel::Warning,
13680 MessageType::INFO => LogLevel::Info,
13681 MessageType::LOG => LogLevel::Log,
13682 other => {
13683 log::warn!("Unknown lsp log message type: {other:?}");
13684 LogLevel::Log
13685 }
13686 };
13687 proto::language_server_log::LogType::Log(proto::LogMessage {
13688 level: level as i32,
13689 })
13690 }
13691 Self::Trace { verbose_info } => {
13692 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13693 verbose_info: verbose_info.to_owned(),
13694 })
13695 }
13696 Self::Rpc { received } => {
13697 let kind = if *received {
13698 proto::rpc_message::Kind::Received
13699 } else {
13700 proto::rpc_message::Kind::Sent
13701 };
13702 let kind = kind as i32;
13703 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13704 }
13705 }
13706 }
13707
13708 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13709 use proto::log_message::LogLevel;
13710 use proto::rpc_message;
13711 match log_type {
13712 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13713 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13714 LogLevel::Error => MessageType::ERROR,
13715 LogLevel::Warning => MessageType::WARNING,
13716 LogLevel::Info => MessageType::INFO,
13717 LogLevel::Log => MessageType::LOG,
13718 },
13719 ),
13720 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13721 verbose_info: trace_message.verbose_info,
13722 },
13723 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13724 received: match rpc_message::Kind::from_i32(message.kind)
13725 .unwrap_or(rpc_message::Kind::Received)
13726 {
13727 rpc_message::Kind::Received => true,
13728 rpc_message::Kind::Sent => false,
13729 },
13730 },
13731 }
13732 }
13733}
13734
13735pub struct WorkspaceRefreshTask {
13736 refresh_tx: mpsc::Sender<()>,
13737 progress_tx: mpsc::Sender<()>,
13738 #[allow(dead_code)]
13739 task: Task<()>,
13740}
13741
13742pub enum LanguageServerState {
13743 Starting {
13744 startup: Task<Option<Arc<LanguageServer>>>,
13745 /// List of language servers that will be added to the workspace once it's initialization completes.
13746 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13747 },
13748
13749 Running {
13750 adapter: Arc<CachedLspAdapter>,
13751 server: Arc<LanguageServer>,
13752 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13753 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13754 },
13755}
13756
13757impl LanguageServerState {
13758 fn add_workspace_folder(&self, uri: Uri) {
13759 match self {
13760 LanguageServerState::Starting {
13761 pending_workspace_folders,
13762 ..
13763 } => {
13764 pending_workspace_folders.lock().insert(uri);
13765 }
13766 LanguageServerState::Running { server, .. } => {
13767 server.add_workspace_folder(uri);
13768 }
13769 }
13770 }
13771 fn _remove_workspace_folder(&self, uri: Uri) {
13772 match self {
13773 LanguageServerState::Starting {
13774 pending_workspace_folders,
13775 ..
13776 } => {
13777 pending_workspace_folders.lock().remove(&uri);
13778 }
13779 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13780 }
13781 }
13782}
13783
13784impl std::fmt::Debug for LanguageServerState {
13785 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13786 match self {
13787 LanguageServerState::Starting { .. } => {
13788 f.debug_struct("LanguageServerState::Starting").finish()
13789 }
13790 LanguageServerState::Running { .. } => {
13791 f.debug_struct("LanguageServerState::Running").finish()
13792 }
13793 }
13794 }
13795}
13796
13797#[derive(Clone, Debug, Serialize)]
13798pub struct LanguageServerProgress {
13799 pub is_disk_based_diagnostics_progress: bool,
13800 pub is_cancellable: bool,
13801 pub title: Option<String>,
13802 pub message: Option<String>,
13803 pub percentage: Option<usize>,
13804 #[serde(skip_serializing)]
13805 pub last_update_at: Instant,
13806}
13807
13808#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13809pub struct DiagnosticSummary {
13810 pub error_count: usize,
13811 pub warning_count: usize,
13812}
13813
13814impl DiagnosticSummary {
13815 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13816 let mut this = Self {
13817 error_count: 0,
13818 warning_count: 0,
13819 };
13820
13821 for entry in diagnostics {
13822 if entry.diagnostic.is_primary {
13823 match entry.diagnostic.severity {
13824 DiagnosticSeverity::ERROR => this.error_count += 1,
13825 DiagnosticSeverity::WARNING => this.warning_count += 1,
13826 _ => {}
13827 }
13828 }
13829 }
13830
13831 this
13832 }
13833
13834 pub fn is_empty(&self) -> bool {
13835 self.error_count == 0 && self.warning_count == 0
13836 }
13837
13838 pub fn to_proto(
13839 self,
13840 language_server_id: LanguageServerId,
13841 path: &RelPath,
13842 ) -> proto::DiagnosticSummary {
13843 proto::DiagnosticSummary {
13844 path: path.to_proto(),
13845 language_server_id: language_server_id.0 as u64,
13846 error_count: self.error_count as u32,
13847 warning_count: self.warning_count as u32,
13848 }
13849 }
13850}
13851
13852#[derive(Clone, Debug)]
13853pub enum CompletionDocumentation {
13854 /// There is no documentation for this completion.
13855 Undocumented,
13856 /// A single line of documentation.
13857 SingleLine(SharedString),
13858 /// Multiple lines of plain text documentation.
13859 MultiLinePlainText(SharedString),
13860 /// Markdown documentation.
13861 MultiLineMarkdown(SharedString),
13862 /// Both single line and multiple lines of plain text documentation.
13863 SingleLineAndMultiLinePlainText {
13864 single_line: SharedString,
13865 plain_text: Option<SharedString>,
13866 },
13867}
13868
13869impl CompletionDocumentation {
13870 #[cfg(any(test, feature = "test-support"))]
13871 pub fn text(&self) -> SharedString {
13872 match self {
13873 CompletionDocumentation::Undocumented => "".into(),
13874 CompletionDocumentation::SingleLine(s) => s.clone(),
13875 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13876 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13877 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13878 single_line.clone()
13879 }
13880 }
13881 }
13882}
13883
13884impl From<lsp::Documentation> for CompletionDocumentation {
13885 fn from(docs: lsp::Documentation) -> Self {
13886 match docs {
13887 lsp::Documentation::String(text) => {
13888 if text.lines().count() <= 1 {
13889 CompletionDocumentation::SingleLine(text.into())
13890 } else {
13891 CompletionDocumentation::MultiLinePlainText(text.into())
13892 }
13893 }
13894
13895 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13896 lsp::MarkupKind::PlainText => {
13897 if value.lines().count() <= 1 {
13898 CompletionDocumentation::SingleLine(value.into())
13899 } else {
13900 CompletionDocumentation::MultiLinePlainText(value.into())
13901 }
13902 }
13903
13904 lsp::MarkupKind::Markdown => {
13905 CompletionDocumentation::MultiLineMarkdown(value.into())
13906 }
13907 },
13908 }
13909 }
13910}
13911
13912pub enum ResolvedHint {
13913 Resolved(InlayHint),
13914 Resolving(Shared<Task<()>>),
13915}
13916
13917fn glob_literal_prefix(glob: &Path) -> PathBuf {
13918 glob.components()
13919 .take_while(|component| match component {
13920 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13921 _ => true,
13922 })
13923 .collect()
13924}
13925
13926pub struct SshLspAdapter {
13927 name: LanguageServerName,
13928 binary: LanguageServerBinary,
13929 initialization_options: Option<String>,
13930 code_action_kinds: Option<Vec<CodeActionKind>>,
13931}
13932
13933impl SshLspAdapter {
13934 pub fn new(
13935 name: LanguageServerName,
13936 binary: LanguageServerBinary,
13937 initialization_options: Option<String>,
13938 code_action_kinds: Option<String>,
13939 ) -> Self {
13940 Self {
13941 name,
13942 binary,
13943 initialization_options,
13944 code_action_kinds: code_action_kinds
13945 .as_ref()
13946 .and_then(|c| serde_json::from_str(c).ok()),
13947 }
13948 }
13949}
13950
13951impl LspInstaller for SshLspAdapter {
13952 type BinaryVersion = ();
13953 async fn check_if_user_installed(
13954 &self,
13955 _: &dyn LspAdapterDelegate,
13956 _: Option<Toolchain>,
13957 _: &AsyncApp,
13958 ) -> Option<LanguageServerBinary> {
13959 Some(self.binary.clone())
13960 }
13961
13962 async fn cached_server_binary(
13963 &self,
13964 _: PathBuf,
13965 _: &dyn LspAdapterDelegate,
13966 ) -> Option<LanguageServerBinary> {
13967 None
13968 }
13969
13970 async fn fetch_latest_server_version(
13971 &self,
13972 _: &dyn LspAdapterDelegate,
13973 _: bool,
13974 _: &mut AsyncApp,
13975 ) -> Result<()> {
13976 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13977 }
13978
13979 async fn fetch_server_binary(
13980 &self,
13981 _: (),
13982 _: PathBuf,
13983 _: &dyn LspAdapterDelegate,
13984 ) -> Result<LanguageServerBinary> {
13985 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13986 }
13987}
13988
13989#[async_trait(?Send)]
13990impl LspAdapter for SshLspAdapter {
13991 fn name(&self) -> LanguageServerName {
13992 self.name.clone()
13993 }
13994
13995 async fn initialization_options(
13996 self: Arc<Self>,
13997 _: &Arc<dyn LspAdapterDelegate>,
13998 ) -> Result<Option<serde_json::Value>> {
13999 let Some(options) = &self.initialization_options else {
14000 return Ok(None);
14001 };
14002 let result = serde_json::from_str(options)?;
14003 Ok(result)
14004 }
14005
14006 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14007 self.code_action_kinds.clone()
14008 }
14009}
14010
14011pub fn language_server_settings<'a>(
14012 delegate: &'a dyn LspAdapterDelegate,
14013 language: &LanguageServerName,
14014 cx: &'a App,
14015) -> Option<&'a LspSettings> {
14016 language_server_settings_for(
14017 SettingsLocation {
14018 worktree_id: delegate.worktree_id(),
14019 path: RelPath::empty(),
14020 },
14021 language,
14022 cx,
14023 )
14024}
14025
14026pub fn language_server_settings_for<'a>(
14027 location: SettingsLocation<'a>,
14028 language: &LanguageServerName,
14029 cx: &'a App,
14030) -> Option<&'a LspSettings> {
14031 ProjectSettings::get(Some(location), cx).lsp.get(language)
14032}
14033
14034pub struct LocalLspAdapterDelegate {
14035 lsp_store: WeakEntity<LspStore>,
14036 worktree: worktree::Snapshot,
14037 fs: Arc<dyn Fs>,
14038 http_client: Arc<dyn HttpClient>,
14039 language_registry: Arc<LanguageRegistry>,
14040 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14041}
14042
14043impl LocalLspAdapterDelegate {
14044 pub fn new(
14045 language_registry: Arc<LanguageRegistry>,
14046 environment: &Entity<ProjectEnvironment>,
14047 lsp_store: WeakEntity<LspStore>,
14048 worktree: &Entity<Worktree>,
14049 http_client: Arc<dyn HttpClient>,
14050 fs: Arc<dyn Fs>,
14051 cx: &mut App,
14052 ) -> Arc<Self> {
14053 let load_shell_env_task =
14054 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14055
14056 Arc::new(Self {
14057 lsp_store,
14058 worktree: worktree.read(cx).snapshot(),
14059 fs,
14060 http_client,
14061 language_registry,
14062 load_shell_env_task,
14063 })
14064 }
14065
14066 fn from_local_lsp(
14067 local: &LocalLspStore,
14068 worktree: &Entity<Worktree>,
14069 cx: &mut App,
14070 ) -> Arc<Self> {
14071 Self::new(
14072 local.languages.clone(),
14073 &local.environment,
14074 local.weak.clone(),
14075 worktree,
14076 local.http_client.clone(),
14077 local.fs.clone(),
14078 cx,
14079 )
14080 }
14081}
14082
14083#[async_trait]
14084impl LspAdapterDelegate for LocalLspAdapterDelegate {
14085 fn show_notification(&self, message: &str, cx: &mut App) {
14086 self.lsp_store
14087 .update(cx, |_, cx| {
14088 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14089 })
14090 .ok();
14091 }
14092
14093 fn http_client(&self) -> Arc<dyn HttpClient> {
14094 self.http_client.clone()
14095 }
14096
14097 fn worktree_id(&self) -> WorktreeId {
14098 self.worktree.id()
14099 }
14100
14101 fn worktree_root_path(&self) -> &Path {
14102 self.worktree.abs_path().as_ref()
14103 }
14104
14105 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14106 self.worktree.resolve_executable_path(path)
14107 }
14108
14109 async fn shell_env(&self) -> HashMap<String, String> {
14110 let task = self.load_shell_env_task.clone();
14111 task.await.unwrap_or_default()
14112 }
14113
14114 async fn npm_package_installed_version(
14115 &self,
14116 package_name: &str,
14117 ) -> Result<Option<(PathBuf, String)>> {
14118 let local_package_directory = self.worktree_root_path();
14119 let node_modules_directory = local_package_directory.join("node_modules");
14120
14121 if let Some(version) =
14122 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14123 {
14124 return Ok(Some((node_modules_directory, version)));
14125 }
14126 let Some(npm) = self.which("npm".as_ref()).await else {
14127 log::warn!(
14128 "Failed to find npm executable for {:?}",
14129 local_package_directory
14130 );
14131 return Ok(None);
14132 };
14133
14134 let env = self.shell_env().await;
14135 let output = util::command::new_smol_command(&npm)
14136 .args(["root", "-g"])
14137 .envs(env)
14138 .current_dir(local_package_directory)
14139 .output()
14140 .await?;
14141 let global_node_modules =
14142 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14143
14144 if let Some(version) =
14145 read_package_installed_version(global_node_modules.clone(), package_name).await?
14146 {
14147 return Ok(Some((global_node_modules, version)));
14148 }
14149 return Ok(None);
14150 }
14151
14152 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14153 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14154 if self.fs.is_file(&worktree_abs_path).await {
14155 worktree_abs_path.pop();
14156 }
14157
14158 let env = self.shell_env().await;
14159
14160 let shell_path = env.get("PATH").cloned();
14161
14162 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14163 }
14164
14165 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14166 let mut working_dir = self.worktree_root_path().to_path_buf();
14167 if self.fs.is_file(&working_dir).await {
14168 working_dir.pop();
14169 }
14170 let output = util::command::new_smol_command(&command.path)
14171 .args(command.arguments)
14172 .envs(command.env.clone().unwrap_or_default())
14173 .current_dir(working_dir)
14174 .output()
14175 .await?;
14176
14177 anyhow::ensure!(
14178 output.status.success(),
14179 "{}, stdout: {:?}, stderr: {:?}",
14180 output.status,
14181 String::from_utf8_lossy(&output.stdout),
14182 String::from_utf8_lossy(&output.stderr)
14183 );
14184 Ok(())
14185 }
14186
14187 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14188 self.language_registry
14189 .update_lsp_binary_status(server_name, status);
14190 }
14191
14192 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14193 self.language_registry
14194 .all_lsp_adapters()
14195 .into_iter()
14196 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14197 .collect()
14198 }
14199
14200 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14201 let dir = self.language_registry.language_server_download_dir(name)?;
14202
14203 if !dir.exists() {
14204 smol::fs::create_dir_all(&dir)
14205 .await
14206 .context("failed to create container directory")
14207 .log_err()?;
14208 }
14209
14210 Some(dir)
14211 }
14212
14213 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14214 let entry = self
14215 .worktree
14216 .entry_for_path(path)
14217 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14218 let abs_path = self.worktree.absolutize(&entry.path);
14219 self.fs.load(&abs_path).await
14220 }
14221}
14222
14223async fn populate_labels_for_symbols(
14224 symbols: Vec<CoreSymbol>,
14225 language_registry: &Arc<LanguageRegistry>,
14226 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14227 output: &mut Vec<Symbol>,
14228) {
14229 #[allow(clippy::mutable_key_type)]
14230 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14231
14232 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14233 for symbol in symbols {
14234 let Some(file_name) = symbol.path.file_name() else {
14235 continue;
14236 };
14237 let language = language_registry
14238 .load_language_for_file_path(Path::new(file_name))
14239 .await
14240 .ok()
14241 .or_else(|| {
14242 unknown_paths.insert(file_name.into());
14243 None
14244 });
14245 symbols_by_language
14246 .entry(language)
14247 .or_default()
14248 .push(symbol);
14249 }
14250
14251 for unknown_path in unknown_paths {
14252 log::info!("no language found for symbol in file {unknown_path:?}");
14253 }
14254
14255 let mut label_params = Vec::new();
14256 for (language, mut symbols) in symbols_by_language {
14257 label_params.clear();
14258 label_params.extend(
14259 symbols
14260 .iter_mut()
14261 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14262 );
14263
14264 let mut labels = Vec::new();
14265 if let Some(language) = language {
14266 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14267 language_registry
14268 .lsp_adapters(&language.name())
14269 .first()
14270 .cloned()
14271 });
14272 if let Some(lsp_adapter) = lsp_adapter {
14273 labels = lsp_adapter
14274 .labels_for_symbols(&label_params, &language)
14275 .await
14276 .log_err()
14277 .unwrap_or_default();
14278 }
14279 }
14280
14281 for ((symbol, (name, _)), label) in symbols
14282 .into_iter()
14283 .zip(label_params.drain(..))
14284 .zip(labels.into_iter().chain(iter::repeat(None)))
14285 {
14286 output.push(Symbol {
14287 language_server_name: symbol.language_server_name,
14288 source_worktree_id: symbol.source_worktree_id,
14289 source_language_server_id: symbol.source_language_server_id,
14290 path: symbol.path,
14291 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14292 name,
14293 kind: symbol.kind,
14294 range: symbol.range,
14295 });
14296 }
14297 }
14298}
14299
14300fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14301 match server.capabilities().text_document_sync.as_ref()? {
14302 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14303 // Server wants didSave but didn't specify includeText.
14304 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14305 // Server doesn't want didSave at all.
14306 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14307 // Server provided SaveOptions.
14308 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14309 Some(save_options.include_text.unwrap_or(false))
14310 }
14311 },
14312 // We do not have any save info. Kind affects didChange only.
14313 lsp::TextDocumentSyncCapability::Kind(_) => None,
14314 }
14315}
14316
14317/// Completion items are displayed in a `UniformList`.
14318/// Usually, those items are single-line strings, but in LSP responses,
14319/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14320/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14321/// 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,
14322/// breaking the completions menu presentation.
14323///
14324/// 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.
14325fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14326 let mut new_text = String::with_capacity(label.text.len());
14327 let mut offset_map = vec![0; label.text.len() + 1];
14328 let mut last_char_was_space = false;
14329 let mut new_idx = 0;
14330 let chars = label.text.char_indices().fuse();
14331 let mut newlines_removed = false;
14332
14333 for (idx, c) in chars {
14334 offset_map[idx] = new_idx;
14335
14336 match c {
14337 '\n' if last_char_was_space => {
14338 newlines_removed = true;
14339 }
14340 '\t' | ' ' if last_char_was_space => {}
14341 '\n' if !last_char_was_space => {
14342 new_text.push(' ');
14343 new_idx += 1;
14344 last_char_was_space = true;
14345 newlines_removed = true;
14346 }
14347 ' ' | '\t' => {
14348 new_text.push(' ');
14349 new_idx += 1;
14350 last_char_was_space = true;
14351 }
14352 _ => {
14353 new_text.push(c);
14354 new_idx += c.len_utf8();
14355 last_char_was_space = false;
14356 }
14357 }
14358 }
14359 offset_map[label.text.len()] = new_idx;
14360
14361 // Only modify the label if newlines were removed.
14362 if !newlines_removed {
14363 return;
14364 }
14365
14366 let last_index = new_idx;
14367 let mut run_ranges_errors = Vec::new();
14368 label.runs.retain_mut(|(range, _)| {
14369 match offset_map.get(range.start) {
14370 Some(&start) => range.start = start,
14371 None => {
14372 run_ranges_errors.push(range.clone());
14373 return false;
14374 }
14375 }
14376
14377 match offset_map.get(range.end) {
14378 Some(&end) => range.end = end,
14379 None => {
14380 run_ranges_errors.push(range.clone());
14381 range.end = last_index;
14382 }
14383 }
14384 true
14385 });
14386 if !run_ranges_errors.is_empty() {
14387 log::error!(
14388 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14389 label.text
14390 );
14391 }
14392
14393 let mut wrong_filter_range = None;
14394 if label.filter_range == (0..label.text.len()) {
14395 label.filter_range = 0..new_text.len();
14396 } else {
14397 let mut original_filter_range = Some(label.filter_range.clone());
14398 match offset_map.get(label.filter_range.start) {
14399 Some(&start) => label.filter_range.start = start,
14400 None => {
14401 wrong_filter_range = original_filter_range.take();
14402 label.filter_range.start = last_index;
14403 }
14404 }
14405
14406 match offset_map.get(label.filter_range.end) {
14407 Some(&end) => label.filter_range.end = end,
14408 None => {
14409 wrong_filter_range = original_filter_range.take();
14410 label.filter_range.end = last_index;
14411 }
14412 }
14413 }
14414 if let Some(wrong_filter_range) = wrong_filter_range {
14415 log::error!(
14416 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14417 label.text
14418 );
14419 }
14420
14421 label.text = new_text;
14422}
14423
14424#[cfg(test)]
14425mod tests {
14426 use language::HighlightId;
14427
14428 use super::*;
14429
14430 #[test]
14431 fn test_glob_literal_prefix() {
14432 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14433 assert_eq!(
14434 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14435 Path::new("node_modules")
14436 );
14437 assert_eq!(
14438 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14439 Path::new("foo")
14440 );
14441 assert_eq!(
14442 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14443 Path::new("foo/bar/baz.js")
14444 );
14445
14446 #[cfg(target_os = "windows")]
14447 {
14448 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14449 assert_eq!(
14450 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14451 Path::new("node_modules")
14452 );
14453 assert_eq!(
14454 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14455 Path::new("foo")
14456 );
14457 assert_eq!(
14458 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14459 Path::new("foo/bar/baz.js")
14460 );
14461 }
14462 }
14463
14464 #[test]
14465 fn test_multi_len_chars_normalization() {
14466 let mut label = CodeLabel::new(
14467 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14468 0..6,
14469 vec![(0..6, HighlightId(1))],
14470 );
14471 ensure_uniform_list_compatible_label(&mut label);
14472 assert_eq!(
14473 label,
14474 CodeLabel::new(
14475 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14476 0..6,
14477 vec![(0..6, HighlightId(1))],
14478 )
14479 );
14480 }
14481}