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