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