1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13pub mod json_language_server_ext;
14pub mod log_store;
15pub mod lsp_ext_command;
16pub mod rust_analyzer_ext;
17pub mod vue_language_server_ext;
18
19mod inlay_hint_cache;
20
21use self::inlay_hint_cache::BufferInlayHints;
22use crate::{
23 CodeAction, ColorPresentation, Completion, CompletionDisplayOptions, CompletionResponse,
24 CompletionSource, CoreCompletion, DocumentColor, Hover, InlayHint, InlayId, LocationLink,
25 LspAction, LspPullDiagnostics, ManifestProvidersStore, Project, ProjectItem, ProjectPath,
26 ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
27 buffer_store::{BufferStore, BufferStoreEvent},
28 environment::ProjectEnvironment,
29 lsp_command::{self, *},
30 lsp_store::{
31 self,
32 log_store::{GlobalLogStore, LanguageServerKind},
33 },
34 manifest_tree::{
35 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
36 ManifestTree,
37 },
38 prettier_store::{self, PrettierStore, PrettierStoreEvent},
39 project_settings::{LspSettings, ProjectSettings},
40 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
41 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
42 worktree_store::{WorktreeStore, WorktreeStoreEvent},
43 yarn::YarnPathStore,
44};
45use anyhow::{Context as _, Result, anyhow};
46use async_trait::async_trait;
47use client::{TypedEnvelope, proto};
48use clock::Global;
49use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
50use futures::{
51 AsyncWriteExt, Future, FutureExt, StreamExt,
52 future::{Either, Shared, join_all, pending, select},
53 select, select_biased,
54 stream::FuturesUnordered,
55};
56use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
57use gpui::{
58 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
59 Subscription, Task, WeakEntity,
60};
61use http_client::HttpClient;
62use itertools::Itertools as _;
63use language::{
64 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, CodeLabel, Diagnostic,
65 DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language, LanguageName,
66 LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate,
67 ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Toolchain,
68 Transaction, Unclipped,
69 language_settings::{FormatOnSave, Formatter, LanguageSettings, language_settings},
70 point_to_lsp,
71 proto::{
72 deserialize_anchor, deserialize_lsp_edit, deserialize_version, serialize_anchor,
73 serialize_lsp_edit, serialize_version,
74 },
75 range_from_lsp, range_to_lsp,
76 row_chunk::RowChunk,
77};
78use lsp::{
79 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
80 DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
81 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
82 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LSP_REQUEST_TIMEOUT,
83 LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId,
84 LanguageServerName, LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType,
85 OneOf, RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri,
86 WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
87};
88use node_runtime::read_package_installed_version;
89use parking_lot::Mutex;
90use postage::{mpsc, sink::Sink, stream::Stream, watch};
91use rand::prelude::*;
92use rpc::{
93 AnyProtoClient, ErrorCode, ErrorExt as _,
94 proto::{LspRequestId, LspRequestMessage as _},
95};
96use semver::Version;
97use serde::Serialize;
98use serde_json::Value;
99use settings::{Settings, SettingsLocation, SettingsStore};
100use sha2::{Digest, Sha256};
101use smol::channel::{Receiver, Sender};
102use snippet::Snippet;
103use std::{
104 any::TypeId,
105 borrow::Cow,
106 cell::RefCell,
107 cmp::{Ordering, Reverse},
108 collections::hash_map,
109 convert::TryInto,
110 ffi::OsStr,
111 future::ready,
112 iter, mem,
113 ops::{ControlFlow, Range},
114 path::{self, Path, PathBuf},
115 pin::pin,
116 rc::Rc,
117 sync::{
118 Arc,
119 atomic::{self, AtomicUsize},
120 },
121 time::{Duration, Instant},
122 vec,
123};
124use sum_tree::Dimensions;
125use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
126
127use util::{
128 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
129 paths::{PathStyle, SanitizedPath},
130 post_inc,
131 rel_path::RelPath,
132};
133
134pub use fs::*;
135pub use language::Location;
136pub use lsp_store::inlay_hint_cache::{CacheInlayHints, InvalidationStrategy};
137#[cfg(any(test, feature = "test-support"))]
138pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
139pub use worktree::{
140 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
141 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
142};
143
144const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
145pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
146const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
147const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
148
149#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
150pub enum ProgressToken {
151 Number(i32),
152 String(SharedString),
153}
154
155impl std::fmt::Display for ProgressToken {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 match self {
158 Self::Number(number) => write!(f, "{number}"),
159 Self::String(string) => write!(f, "{string}"),
160 }
161 }
162}
163
164impl ProgressToken {
165 fn from_lsp(value: lsp::NumberOrString) -> Self {
166 match value {
167 lsp::NumberOrString::Number(number) => Self::Number(number),
168 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
169 }
170 }
171
172 fn to_lsp(&self) -> lsp::NumberOrString {
173 match self {
174 Self::Number(number) => lsp::NumberOrString::Number(*number),
175 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
176 }
177 }
178
179 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
180 Some(match value.value? {
181 proto::progress_token::Value::Number(number) => Self::Number(number),
182 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
183 })
184 }
185
186 fn to_proto(&self) -> proto::ProgressToken {
187 proto::ProgressToken {
188 value: Some(match self {
189 Self::Number(number) => proto::progress_token::Value::Number(*number),
190 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
191 }),
192 }
193 }
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197pub enum FormatTrigger {
198 Save,
199 Manual,
200}
201
202pub enum LspFormatTarget {
203 Buffers,
204 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
205}
206
207#[derive(Clone, PartialEq, Eq, Hash)]
208pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
209
210struct OpenLspBuffer(Entity<Buffer>);
211
212impl FormatTrigger {
213 fn from_proto(value: i32) -> FormatTrigger {
214 match value {
215 0 => FormatTrigger::Save,
216 1 => FormatTrigger::Manual,
217 _ => FormatTrigger::Save,
218 }
219 }
220}
221
222#[derive(Clone)]
223struct UnifiedLanguageServer {
224 id: LanguageServerId,
225 project_roots: HashSet<Arc<RelPath>>,
226}
227
228#[derive(Clone, Debug, Hash, PartialEq, Eq)]
229struct LanguageServerSeed {
230 worktree_id: WorktreeId,
231 name: LanguageServerName,
232 toolchain: Option<Toolchain>,
233 settings: Arc<LspSettings>,
234}
235
236#[derive(Debug)]
237pub struct DocumentDiagnosticsUpdate<'a, D> {
238 pub diagnostics: D,
239 pub result_id: Option<SharedString>,
240 pub registration_id: Option<SharedString>,
241 pub server_id: LanguageServerId,
242 pub disk_based_sources: Cow<'a, [String]>,
243}
244
245pub struct DocumentDiagnostics {
246 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
247 document_abs_path: PathBuf,
248 version: Option<i32>,
249}
250
251#[derive(Default, Debug)]
252struct DynamicRegistrations {
253 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
254 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
255}
256
257pub struct LocalLspStore {
258 weak: WeakEntity<LspStore>,
259 worktree_store: Entity<WorktreeStore>,
260 toolchain_store: Entity<LocalToolchainStore>,
261 http_client: Arc<dyn HttpClient>,
262 environment: Entity<ProjectEnvironment>,
263 fs: Arc<dyn Fs>,
264 languages: Arc<LanguageRegistry>,
265 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
266 yarn: Entity<YarnPathStore>,
267 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
268 buffers_being_formatted: HashSet<BufferId>,
269 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
270 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
271 watched_manifest_filenames: HashSet<ManifestName>,
272 language_server_paths_watched_for_rename:
273 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
274 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
275 supplementary_language_servers:
276 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
277 prettier_store: Entity<PrettierStore>,
278 next_diagnostic_group_id: usize,
279 diagnostics: HashMap<
280 WorktreeId,
281 HashMap<
282 Arc<RelPath>,
283 Vec<(
284 LanguageServerId,
285 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
286 )>,
287 >,
288 >,
289 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
290 _subscription: gpui::Subscription,
291 lsp_tree: LanguageServerTree,
292 registered_buffers: HashMap<BufferId, usize>,
293 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
294 buffer_pull_diagnostics_result_ids: HashMap<
295 LanguageServerId,
296 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
297 >,
298 workspace_pull_diagnostics_result_ids: HashMap<
299 LanguageServerId,
300 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
301 >,
302 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, Receiver<()>)>,
303}
304
305impl LocalLspStore {
306 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
307 pub fn running_language_server_for_id(
308 &self,
309 id: LanguageServerId,
310 ) -> Option<&Arc<LanguageServer>> {
311 let language_server_state = self.language_servers.get(&id)?;
312
313 match language_server_state {
314 LanguageServerState::Running { server, .. } => Some(server),
315 LanguageServerState::Starting { .. } => None,
316 }
317 }
318
319 fn get_or_insert_language_server(
320 &mut self,
321 worktree_handle: &Entity<Worktree>,
322 delegate: Arc<LocalLspAdapterDelegate>,
323 disposition: &Arc<LaunchDisposition>,
324 language_name: &LanguageName,
325 cx: &mut App,
326 ) -> LanguageServerId {
327 let key = LanguageServerSeed {
328 worktree_id: worktree_handle.read(cx).id(),
329 name: disposition.server_name.clone(),
330 settings: disposition.settings.clone(),
331 toolchain: disposition.toolchain.clone(),
332 };
333 if let Some(state) = self.language_server_ids.get_mut(&key) {
334 state.project_roots.insert(disposition.path.path.clone());
335 state.id
336 } else {
337 let adapter = self
338 .languages
339 .lsp_adapters(language_name)
340 .into_iter()
341 .find(|adapter| adapter.name() == disposition.server_name)
342 .expect("To find LSP adapter");
343 let new_language_server_id = self.start_language_server(
344 worktree_handle,
345 delegate,
346 adapter,
347 disposition.settings.clone(),
348 key.clone(),
349 cx,
350 );
351 if let Some(state) = self.language_server_ids.get_mut(&key) {
352 state.project_roots.insert(disposition.path.path.clone());
353 } else {
354 debug_assert!(
355 false,
356 "Expected `start_language_server` to ensure that `key` exists in a map"
357 );
358 }
359 new_language_server_id
360 }
361 }
362
363 fn start_language_server(
364 &mut self,
365 worktree_handle: &Entity<Worktree>,
366 delegate: Arc<LocalLspAdapterDelegate>,
367 adapter: Arc<CachedLspAdapter>,
368 settings: Arc<LspSettings>,
369 key: LanguageServerSeed,
370 cx: &mut App,
371 ) -> LanguageServerId {
372 let worktree = worktree_handle.read(cx);
373
374 let worktree_id = worktree.id();
375 let worktree_abs_path = worktree.abs_path();
376 let toolchain = key.toolchain.clone();
377 let override_options = settings.initialization_options.clone();
378
379 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
380
381 let server_id = self.languages.next_language_server_id();
382 log::trace!(
383 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
384 adapter.name.0
385 );
386
387 let untrusted_worktree_task =
388 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
389 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
390 trusted_worktrees.can_trust(worktree_id, cx)
391 });
392 if can_trust {
393 self.restricted_worktrees_tasks.remove(&worktree_id);
394 None
395 } else {
396 match self.restricted_worktrees_tasks.entry(worktree_id) {
397 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
398 hash_map::Entry::Vacant(v) => {
399 let (tx, rx) = smol::channel::bounded::<()>(1);
400 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, _| {
401 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
402 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
403 tx.send_blocking(()).ok();
404 }
405 }
406 });
407 v.insert((subscription, rx.clone()));
408 Some(rx)
409 }
410 }
411 }
412 });
413 let update_binary_status = untrusted_worktree_task.is_none();
414
415 let binary = self.get_language_server_binary(
416 worktree_abs_path.clone(),
417 adapter.clone(),
418 settings,
419 toolchain.clone(),
420 delegate.clone(),
421 true,
422 untrusted_worktree_task,
423 cx,
424 );
425 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
426
427 let pending_server = cx.spawn({
428 let adapter = adapter.clone();
429 let server_name = adapter.name.clone();
430 let stderr_capture = stderr_capture.clone();
431 #[cfg(any(test, feature = "test-support"))]
432 let lsp_store = self.weak.clone();
433 let pending_workspace_folders = pending_workspace_folders.clone();
434 async move |cx| {
435 let binary = binary.await?;
436 #[cfg(any(test, feature = "test-support"))]
437 if let Some(server) = lsp_store
438 .update(&mut cx.clone(), |this, cx| {
439 this.languages.create_fake_language_server(
440 server_id,
441 &server_name,
442 binary.clone(),
443 &mut cx.to_async(),
444 )
445 })
446 .ok()
447 .flatten()
448 {
449 return Ok(server);
450 }
451
452 let code_action_kinds = adapter.code_action_kinds();
453 lsp::LanguageServer::new(
454 stderr_capture,
455 server_id,
456 server_name,
457 binary,
458 &worktree_abs_path,
459 code_action_kinds,
460 Some(pending_workspace_folders),
461 cx,
462 )
463 }
464 });
465
466 let startup = {
467 let server_name = adapter.name.0.clone();
468 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
469 let key = key.clone();
470 let adapter = adapter.clone();
471 let lsp_store = self.weak.clone();
472 let pending_workspace_folders = pending_workspace_folders.clone();
473
474 let pull_diagnostics = ProjectSettings::get_global(cx)
475 .diagnostics
476 .lsp_pull_diagnostics
477 .enabled;
478 cx.spawn(async move |cx| {
479 let result = async {
480 let language_server = pending_server.await?;
481
482 let workspace_config = Self::workspace_configuration_for_adapter(
483 adapter.adapter.clone(),
484 &delegate,
485 toolchain,
486 None,
487 cx,
488 )
489 .await?;
490
491 let mut initialization_options = Self::initialization_options_for_adapter(
492 adapter.adapter.clone(),
493 &delegate,
494 )
495 .await?;
496
497 match (&mut initialization_options, override_options) {
498 (Some(initialization_options), Some(override_options)) => {
499 merge_json_value_into(override_options, initialization_options);
500 }
501 (None, override_options) => initialization_options = override_options,
502 _ => {}
503 }
504
505 let initialization_params = cx.update(|cx| {
506 let mut params =
507 language_server.default_initialize_params(pull_diagnostics, cx);
508 params.initialization_options = initialization_options;
509 adapter.adapter.prepare_initialize_params(params, cx)
510 })??;
511
512 Self::setup_lsp_messages(
513 lsp_store.clone(),
514 &language_server,
515 delegate.clone(),
516 adapter.clone(),
517 );
518
519 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
520 settings: workspace_config,
521 };
522 let language_server = cx
523 .update(|cx| {
524 language_server.initialize(
525 initialization_params,
526 Arc::new(did_change_configuration_params.clone()),
527 cx,
528 )
529 })?
530 .await
531 .inspect_err(|_| {
532 if let Some(lsp_store) = lsp_store.upgrade() {
533 lsp_store
534 .update(cx, |lsp_store, cx| {
535 lsp_store.cleanup_lsp_data(server_id);
536 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
537 })
538 .ok();
539 }
540 })?;
541
542 language_server.notify::<lsp::notification::DidChangeConfiguration>(
543 did_change_configuration_params,
544 )?;
545
546 anyhow::Ok(language_server)
547 }
548 .await;
549
550 match result {
551 Ok(server) => {
552 lsp_store
553 .update(cx, |lsp_store, cx| {
554 lsp_store.insert_newly_running_language_server(
555 adapter,
556 server.clone(),
557 server_id,
558 key,
559 pending_workspace_folders,
560 cx,
561 );
562 })
563 .ok();
564 stderr_capture.lock().take();
565 Some(server)
566 }
567
568 Err(err) => {
569 let log = stderr_capture.lock().take().unwrap_or_default();
570 delegate.update_status(
571 adapter.name(),
572 BinaryStatus::Failed {
573 error: if log.is_empty() {
574 format!("{err:#}")
575 } else {
576 format!("{err:#}\n-- stderr --\n{log}")
577 },
578 },
579 );
580 log::error!("Failed to start language server {server_name:?}: {err:?}");
581 if !log.is_empty() {
582 log::error!("server stderr: {log}");
583 }
584 None
585 }
586 }
587 })
588 };
589 let state = LanguageServerState::Starting {
590 startup,
591 pending_workspace_folders,
592 };
593
594 if update_binary_status {
595 self.languages
596 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
597 }
598
599 self.language_servers.insert(server_id, state);
600 self.language_server_ids
601 .entry(key)
602 .or_insert(UnifiedLanguageServer {
603 id: server_id,
604 project_roots: Default::default(),
605 });
606 server_id
607 }
608
609 fn get_language_server_binary(
610 &self,
611 worktree_abs_path: Arc<Path>,
612 adapter: Arc<CachedLspAdapter>,
613 settings: Arc<LspSettings>,
614 toolchain: Option<Toolchain>,
615 delegate: Arc<dyn LspAdapterDelegate>,
616 allow_binary_download: bool,
617 untrusted_worktree_task: Option<Receiver<()>>,
618 cx: &mut App,
619 ) -> Task<Result<LanguageServerBinary>> {
620 if let Some(settings) = &settings.binary
621 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
622 {
623 let settings = settings.clone();
624 let languages = self.languages.clone();
625 return cx.background_spawn(async move {
626 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
627 log::info!(
628 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
629 adapter.name(),
630 );
631 untrusted_worktree_task.recv().await.ok();
632 log::info!(
633 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
634 adapter.name(),
635 );
636 languages
637 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
638 }
639 let mut env = delegate.shell_env().await;
640 env.extend(settings.env.unwrap_or_default());
641
642 Ok(LanguageServerBinary {
643 path: delegate.resolve_executable_path(path),
644 env: Some(env),
645 arguments: settings
646 .arguments
647 .unwrap_or_default()
648 .iter()
649 .map(Into::into)
650 .collect(),
651 })
652 });
653 }
654 let lsp_binary_options = LanguageServerBinaryOptions {
655 allow_path_lookup: !settings
656 .binary
657 .as_ref()
658 .and_then(|b| b.ignore_system_version)
659 .unwrap_or_default(),
660 allow_binary_download,
661 pre_release: settings
662 .fetch
663 .as_ref()
664 .and_then(|f| f.pre_release)
665 .unwrap_or(false),
666 };
667
668 cx.spawn(async move |cx| {
669 if let Some(untrusted_worktree_task) = untrusted_worktree_task {
670 log::info!(
671 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
672 adapter.name(),
673 );
674 untrusted_worktree_task.recv().await.ok();
675 log::info!(
676 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
677 adapter.name(),
678 );
679 }
680
681 let (existing_binary, maybe_download_binary) = adapter
682 .clone()
683 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
684 .await
685 .await;
686
687 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
688
689 let mut binary = match (existing_binary, maybe_download_binary) {
690 (binary, None) => binary?,
691 (Err(_), Some(downloader)) => downloader.await?,
692 (Ok(existing_binary), Some(downloader)) => {
693 let mut download_timeout = cx
694 .background_executor()
695 .timer(SERVER_DOWNLOAD_TIMEOUT)
696 .fuse();
697 let mut downloader = downloader.fuse();
698 futures::select! {
699 _ = download_timeout => {
700 // Return existing binary and kick the existing work to the background.
701 cx.spawn(async move |_| downloader.await).detach();
702 Ok(existing_binary)
703 },
704 downloaded_or_existing_binary = downloader => {
705 // If download fails, this results in the existing binary.
706 downloaded_or_existing_binary
707 }
708 }?
709 }
710 };
711 let mut shell_env = delegate.shell_env().await;
712
713 shell_env.extend(binary.env.unwrap_or_default());
714
715 if let Some(settings) = settings.binary.as_ref() {
716 if let Some(arguments) = &settings.arguments {
717 binary.arguments = arguments.iter().map(Into::into).collect();
718 }
719 if let Some(env) = &settings.env {
720 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
721 }
722 }
723
724 binary.env = Some(shell_env);
725 Ok(binary)
726 })
727 }
728
729 fn setup_lsp_messages(
730 lsp_store: WeakEntity<LspStore>,
731 language_server: &LanguageServer,
732 delegate: Arc<dyn LspAdapterDelegate>,
733 adapter: Arc<CachedLspAdapter>,
734 ) {
735 let name = language_server.name();
736 let server_id = language_server.server_id();
737 language_server
738 .on_notification::<lsp::notification::PublishDiagnostics, _>({
739 let adapter = adapter.clone();
740 let this = lsp_store.clone();
741 move |mut params, cx| {
742 let adapter = adapter.clone();
743 if let Some(this) = this.upgrade() {
744 this.update(cx, |this, cx| {
745 {
746 let buffer = params
747 .uri
748 .to_file_path()
749 .map(|file_path| this.get_buffer(&file_path, cx))
750 .ok()
751 .flatten();
752 adapter.process_diagnostics(&mut params, server_id, buffer);
753 }
754
755 this.merge_lsp_diagnostics(
756 DiagnosticSourceKind::Pushed,
757 vec![DocumentDiagnosticsUpdate {
758 server_id,
759 diagnostics: params,
760 result_id: None,
761 disk_based_sources: Cow::Borrowed(
762 &adapter.disk_based_diagnostic_sources,
763 ),
764 registration_id: None,
765 }],
766 |_, diagnostic, cx| match diagnostic.source_kind {
767 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
768 adapter.retain_old_diagnostic(diagnostic, cx)
769 }
770 DiagnosticSourceKind::Pulled => true,
771 },
772 cx,
773 )
774 .log_err();
775 })
776 .ok();
777 }
778 }
779 })
780 .detach();
781 language_server
782 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
783 let adapter = adapter.adapter.clone();
784 let delegate = delegate.clone();
785 let this = lsp_store.clone();
786 move |params, cx| {
787 let adapter = adapter.clone();
788 let delegate = delegate.clone();
789 let this = this.clone();
790 let mut cx = cx.clone();
791 async move {
792 let toolchain_for_id = this
793 .update(&mut cx, |this, _| {
794 this.as_local()?.language_server_ids.iter().find_map(
795 |(seed, value)| {
796 (value.id == server_id).then(|| seed.toolchain.clone())
797 },
798 )
799 })?
800 .context("Expected the LSP store to be in a local mode")?;
801
802 let mut scope_uri_to_workspace_config = BTreeMap::new();
803 for item in ¶ms.items {
804 let scope_uri = item.scope_uri.clone();
805 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
806 scope_uri_to_workspace_config.entry(scope_uri.clone())
807 else {
808 // We've already queried workspace configuration of this URI.
809 continue;
810 };
811 let workspace_config = Self::workspace_configuration_for_adapter(
812 adapter.clone(),
813 &delegate,
814 toolchain_for_id.clone(),
815 scope_uri,
816 &mut cx,
817 )
818 .await?;
819 new_scope_uri.insert(workspace_config);
820 }
821
822 Ok(params
823 .items
824 .into_iter()
825 .filter_map(|item| {
826 let workspace_config =
827 scope_uri_to_workspace_config.get(&item.scope_uri)?;
828 if let Some(section) = &item.section {
829 Some(
830 workspace_config
831 .get(section)
832 .cloned()
833 .unwrap_or(serde_json::Value::Null),
834 )
835 } else {
836 Some(workspace_config.clone())
837 }
838 })
839 .collect())
840 }
841 }
842 })
843 .detach();
844
845 language_server
846 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
847 let this = lsp_store.clone();
848 move |_, cx| {
849 let this = this.clone();
850 let cx = cx.clone();
851 async move {
852 let Some(server) =
853 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
854 else {
855 return Ok(None);
856 };
857 let root = server.workspace_folders();
858 Ok(Some(
859 root.into_iter()
860 .map(|uri| WorkspaceFolder {
861 uri,
862 name: Default::default(),
863 })
864 .collect(),
865 ))
866 }
867 }
868 })
869 .detach();
870 // Even though we don't have handling for these requests, respond to them to
871 // avoid stalling any language server like `gopls` which waits for a response
872 // to these requests when initializing.
873 language_server
874 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
875 let this = lsp_store.clone();
876 move |params, cx| {
877 let this = this.clone();
878 let mut cx = cx.clone();
879 async move {
880 this.update(&mut cx, |this, _| {
881 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
882 {
883 status
884 .progress_tokens
885 .insert(ProgressToken::from_lsp(params.token));
886 }
887 })?;
888
889 Ok(())
890 }
891 }
892 })
893 .detach();
894
895 language_server
896 .on_request::<lsp::request::RegisterCapability, _, _>({
897 let lsp_store = lsp_store.clone();
898 move |params, cx| {
899 let lsp_store = lsp_store.clone();
900 let mut cx = cx.clone();
901 async move {
902 lsp_store
903 .update(&mut cx, |lsp_store, cx| {
904 if lsp_store.as_local().is_some() {
905 match lsp_store
906 .register_server_capabilities(server_id, params, cx)
907 {
908 Ok(()) => {}
909 Err(e) => {
910 log::error!(
911 "Failed to register server capabilities: {e:#}"
912 );
913 }
914 };
915 }
916 })
917 .ok();
918 Ok(())
919 }
920 }
921 })
922 .detach();
923
924 language_server
925 .on_request::<lsp::request::UnregisterCapability, _, _>({
926 let lsp_store = lsp_store.clone();
927 move |params, cx| {
928 let lsp_store = lsp_store.clone();
929 let mut cx = cx.clone();
930 async move {
931 lsp_store
932 .update(&mut cx, |lsp_store, cx| {
933 if lsp_store.as_local().is_some() {
934 match lsp_store
935 .unregister_server_capabilities(server_id, params, cx)
936 {
937 Ok(()) => {}
938 Err(e) => {
939 log::error!(
940 "Failed to unregister server capabilities: {e:#}"
941 );
942 }
943 }
944 }
945 })
946 .ok();
947 Ok(())
948 }
949 }
950 })
951 .detach();
952
953 language_server
954 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
955 let this = lsp_store.clone();
956 move |params, cx| {
957 let mut cx = cx.clone();
958 let this = this.clone();
959 async move {
960 LocalLspStore::on_lsp_workspace_edit(
961 this.clone(),
962 params,
963 server_id,
964 &mut cx,
965 )
966 .await
967 }
968 }
969 })
970 .detach();
971
972 language_server
973 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
974 let lsp_store = lsp_store.clone();
975 let request_id = Arc::new(AtomicUsize::new(0));
976 move |(), cx| {
977 let lsp_store = lsp_store.clone();
978 let request_id = request_id.clone();
979 let mut cx = cx.clone();
980 async move {
981 lsp_store
982 .update(&mut cx, |lsp_store, cx| {
983 let request_id =
984 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
985 cx.emit(LspStoreEvent::RefreshInlayHints {
986 server_id,
987 request_id,
988 });
989 lsp_store
990 .downstream_client
991 .as_ref()
992 .map(|(client, project_id)| {
993 client.send(proto::RefreshInlayHints {
994 project_id: *project_id,
995 server_id: server_id.to_proto(),
996 request_id: request_id.map(|id| id as u64),
997 })
998 })
999 })?
1000 .transpose()?;
1001 Ok(())
1002 }
1003 }
1004 })
1005 .detach();
1006
1007 language_server
1008 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1009 let this = lsp_store.clone();
1010 move |(), cx| {
1011 let this = this.clone();
1012 let mut cx = cx.clone();
1013 async move {
1014 this.update(&mut cx, |this, cx| {
1015 cx.emit(LspStoreEvent::RefreshCodeLens);
1016 this.downstream_client.as_ref().map(|(client, project_id)| {
1017 client.send(proto::RefreshCodeLens {
1018 project_id: *project_id,
1019 })
1020 })
1021 })?
1022 .transpose()?;
1023 Ok(())
1024 }
1025 }
1026 })
1027 .detach();
1028
1029 language_server
1030 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1031 let this = lsp_store.clone();
1032 move |(), cx| {
1033 let this = this.clone();
1034 let mut cx = cx.clone();
1035 async move {
1036 this.update(&mut cx, |lsp_store, _| {
1037 lsp_store.pull_workspace_diagnostics(server_id);
1038 lsp_store
1039 .downstream_client
1040 .as_ref()
1041 .map(|(client, project_id)| {
1042 client.send(proto::PullWorkspaceDiagnostics {
1043 project_id: *project_id,
1044 server_id: server_id.to_proto(),
1045 })
1046 })
1047 })?
1048 .transpose()?;
1049 Ok(())
1050 }
1051 }
1052 })
1053 .detach();
1054
1055 language_server
1056 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1057 let this = lsp_store.clone();
1058 let name = name.to_string();
1059 move |params, cx| {
1060 let this = this.clone();
1061 let name = name.to_string();
1062 let mut cx = cx.clone();
1063 async move {
1064 let actions = params.actions.unwrap_or_default();
1065 let (tx, rx) = smol::channel::bounded(1);
1066 let request = LanguageServerPromptRequest {
1067 level: match params.typ {
1068 lsp::MessageType::ERROR => PromptLevel::Critical,
1069 lsp::MessageType::WARNING => PromptLevel::Warning,
1070 _ => PromptLevel::Info,
1071 },
1072 message: params.message,
1073 actions,
1074 response_channel: tx,
1075 lsp_name: name.clone(),
1076 };
1077
1078 let did_update = this
1079 .update(&mut cx, |_, cx| {
1080 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1081 })
1082 .is_ok();
1083 if did_update {
1084 let response = rx.recv().await.ok();
1085 Ok(response)
1086 } else {
1087 Ok(None)
1088 }
1089 }
1090 }
1091 })
1092 .detach();
1093 language_server
1094 .on_notification::<lsp::notification::ShowMessage, _>({
1095 let this = lsp_store.clone();
1096 let name = name.to_string();
1097 move |params, cx| {
1098 let this = this.clone();
1099 let name = name.to_string();
1100 let mut cx = cx.clone();
1101
1102 let (tx, _) = smol::channel::bounded(1);
1103 let request = LanguageServerPromptRequest {
1104 level: match params.typ {
1105 lsp::MessageType::ERROR => PromptLevel::Critical,
1106 lsp::MessageType::WARNING => PromptLevel::Warning,
1107 _ => PromptLevel::Info,
1108 },
1109 message: params.message,
1110 actions: vec![],
1111 response_channel: tx,
1112 lsp_name: name,
1113 };
1114
1115 let _ = this.update(&mut cx, |_, cx| {
1116 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1117 });
1118 }
1119 })
1120 .detach();
1121
1122 let disk_based_diagnostics_progress_token =
1123 adapter.disk_based_diagnostics_progress_token.clone();
1124
1125 language_server
1126 .on_notification::<lsp::notification::Progress, _>({
1127 let this = lsp_store.clone();
1128 move |params, cx| {
1129 if let Some(this) = this.upgrade() {
1130 this.update(cx, |this, cx| {
1131 this.on_lsp_progress(
1132 params,
1133 server_id,
1134 disk_based_diagnostics_progress_token.clone(),
1135 cx,
1136 );
1137 })
1138 .ok();
1139 }
1140 }
1141 })
1142 .detach();
1143
1144 language_server
1145 .on_notification::<lsp::notification::LogMessage, _>({
1146 let this = lsp_store.clone();
1147 move |params, cx| {
1148 if let Some(this) = this.upgrade() {
1149 this.update(cx, |_, cx| {
1150 cx.emit(LspStoreEvent::LanguageServerLog(
1151 server_id,
1152 LanguageServerLogType::Log(params.typ),
1153 params.message,
1154 ));
1155 })
1156 .ok();
1157 }
1158 }
1159 })
1160 .detach();
1161
1162 language_server
1163 .on_notification::<lsp::notification::LogTrace, _>({
1164 let this = lsp_store.clone();
1165 move |params, cx| {
1166 let mut cx = cx.clone();
1167 if let Some(this) = this.upgrade() {
1168 this.update(&mut cx, |_, cx| {
1169 cx.emit(LspStoreEvent::LanguageServerLog(
1170 server_id,
1171 LanguageServerLogType::Trace {
1172 verbose_info: params.verbose,
1173 },
1174 params.message,
1175 ));
1176 })
1177 .ok();
1178 }
1179 }
1180 })
1181 .detach();
1182
1183 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1184 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1185 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1186 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1187 }
1188
1189 fn shutdown_language_servers_on_quit(
1190 &mut self,
1191 _: &mut Context<LspStore>,
1192 ) -> impl Future<Output = ()> + use<> {
1193 let shutdown_futures = self
1194 .language_servers
1195 .drain()
1196 .map(|(_, server_state)| Self::shutdown_server(server_state))
1197 .collect::<Vec<_>>();
1198
1199 async move {
1200 join_all(shutdown_futures).await;
1201 }
1202 }
1203
1204 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1205 match server_state {
1206 LanguageServerState::Running { server, .. } => {
1207 if let Some(shutdown) = server.shutdown() {
1208 shutdown.await;
1209 }
1210 }
1211 LanguageServerState::Starting { startup, .. } => {
1212 if let Some(server) = startup.await
1213 && let Some(shutdown) = server.shutdown()
1214 {
1215 shutdown.await;
1216 }
1217 }
1218 }
1219 Ok(())
1220 }
1221
1222 fn language_servers_for_worktree(
1223 &self,
1224 worktree_id: WorktreeId,
1225 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1226 self.language_server_ids
1227 .iter()
1228 .filter_map(move |(seed, state)| {
1229 if seed.worktree_id != worktree_id {
1230 return None;
1231 }
1232
1233 if let Some(LanguageServerState::Running { server, .. }) =
1234 self.language_servers.get(&state.id)
1235 {
1236 Some(server)
1237 } else {
1238 None
1239 }
1240 })
1241 }
1242
1243 fn language_server_ids_for_project_path(
1244 &self,
1245 project_path: ProjectPath,
1246 language: &Language,
1247 cx: &mut App,
1248 ) -> Vec<LanguageServerId> {
1249 let Some(worktree) = self
1250 .worktree_store
1251 .read(cx)
1252 .worktree_for_id(project_path.worktree_id, cx)
1253 else {
1254 return Vec::new();
1255 };
1256 let delegate: Arc<dyn ManifestDelegate> =
1257 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1258
1259 self.lsp_tree
1260 .get(
1261 project_path,
1262 language.name(),
1263 language.manifest(),
1264 &delegate,
1265 cx,
1266 )
1267 .collect::<Vec<_>>()
1268 }
1269
1270 fn language_server_ids_for_buffer(
1271 &self,
1272 buffer: &Buffer,
1273 cx: &mut App,
1274 ) -> Vec<LanguageServerId> {
1275 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1276 let worktree_id = file.worktree_id(cx);
1277
1278 let path: Arc<RelPath> = file
1279 .path()
1280 .parent()
1281 .map(Arc::from)
1282 .unwrap_or_else(|| file.path().clone());
1283 let worktree_path = ProjectPath { worktree_id, path };
1284 self.language_server_ids_for_project_path(worktree_path, language, cx)
1285 } else {
1286 Vec::new()
1287 }
1288 }
1289
1290 fn language_servers_for_buffer<'a>(
1291 &'a self,
1292 buffer: &'a Buffer,
1293 cx: &'a mut App,
1294 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1295 self.language_server_ids_for_buffer(buffer, cx)
1296 .into_iter()
1297 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1298 LanguageServerState::Running {
1299 adapter, server, ..
1300 } => Some((adapter, server)),
1301 _ => None,
1302 })
1303 }
1304
1305 async fn execute_code_action_kind_locally(
1306 lsp_store: WeakEntity<LspStore>,
1307 mut buffers: Vec<Entity<Buffer>>,
1308 kind: CodeActionKind,
1309 push_to_history: bool,
1310 cx: &mut AsyncApp,
1311 ) -> anyhow::Result<ProjectTransaction> {
1312 // Do not allow multiple concurrent code actions requests for the
1313 // same buffer.
1314 lsp_store.update(cx, |this, cx| {
1315 let this = this.as_local_mut().unwrap();
1316 buffers.retain(|buffer| {
1317 this.buffers_being_formatted
1318 .insert(buffer.read(cx).remote_id())
1319 });
1320 })?;
1321 let _cleanup = defer({
1322 let this = lsp_store.clone();
1323 let mut cx = cx.clone();
1324 let buffers = &buffers;
1325 move || {
1326 this.update(&mut cx, |this, cx| {
1327 let this = this.as_local_mut().unwrap();
1328 for buffer in buffers {
1329 this.buffers_being_formatted
1330 .remove(&buffer.read(cx).remote_id());
1331 }
1332 })
1333 .ok();
1334 }
1335 });
1336 let mut project_transaction = ProjectTransaction::default();
1337
1338 for buffer in &buffers {
1339 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1340 buffer.update(cx, |buffer, cx| {
1341 lsp_store
1342 .as_local()
1343 .unwrap()
1344 .language_servers_for_buffer(buffer, cx)
1345 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1346 .collect::<Vec<_>>()
1347 })
1348 })?;
1349 for (_, language_server) in adapters_and_servers.iter() {
1350 let actions = Self::get_server_code_actions_from_action_kinds(
1351 &lsp_store,
1352 language_server.server_id(),
1353 vec![kind.clone()],
1354 buffer,
1355 cx,
1356 )
1357 .await?;
1358 Self::execute_code_actions_on_server(
1359 &lsp_store,
1360 language_server,
1361 actions,
1362 push_to_history,
1363 &mut project_transaction,
1364 cx,
1365 )
1366 .await?;
1367 }
1368 }
1369 Ok(project_transaction)
1370 }
1371
1372 async fn format_locally(
1373 lsp_store: WeakEntity<LspStore>,
1374 mut buffers: Vec<FormattableBuffer>,
1375 push_to_history: bool,
1376 trigger: FormatTrigger,
1377 logger: zlog::Logger,
1378 cx: &mut AsyncApp,
1379 ) -> anyhow::Result<ProjectTransaction> {
1380 // Do not allow multiple concurrent formatting requests for the
1381 // same buffer.
1382 lsp_store.update(cx, |this, cx| {
1383 let this = this.as_local_mut().unwrap();
1384 buffers.retain(|buffer| {
1385 this.buffers_being_formatted
1386 .insert(buffer.handle.read(cx).remote_id())
1387 });
1388 })?;
1389
1390 let _cleanup = defer({
1391 let this = lsp_store.clone();
1392 let mut cx = cx.clone();
1393 let buffers = &buffers;
1394 move || {
1395 this.update(&mut cx, |this, cx| {
1396 let this = this.as_local_mut().unwrap();
1397 for buffer in buffers {
1398 this.buffers_being_formatted
1399 .remove(&buffer.handle.read(cx).remote_id());
1400 }
1401 })
1402 .ok();
1403 }
1404 });
1405
1406 let mut project_transaction = ProjectTransaction::default();
1407
1408 for buffer in &buffers {
1409 zlog::debug!(
1410 logger =>
1411 "formatting buffer '{:?}'",
1412 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1413 );
1414 // Create an empty transaction to hold all of the formatting edits.
1415 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1416 // ensure no transactions created while formatting are
1417 // grouped with the previous transaction in the history
1418 // based on the transaction group interval
1419 buffer.finalize_last_transaction();
1420 buffer
1421 .start_transaction()
1422 .context("transaction already open")?;
1423 buffer.end_transaction(cx);
1424 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1425 buffer.finalize_last_transaction();
1426 anyhow::Ok(transaction_id)
1427 })??;
1428
1429 let result = Self::format_buffer_locally(
1430 lsp_store.clone(),
1431 buffer,
1432 formatting_transaction_id,
1433 trigger,
1434 logger,
1435 cx,
1436 )
1437 .await;
1438
1439 buffer.handle.update(cx, |buffer, cx| {
1440 let Some(formatting_transaction) =
1441 buffer.get_transaction(formatting_transaction_id).cloned()
1442 else {
1443 zlog::warn!(logger => "no formatting transaction");
1444 return;
1445 };
1446 if formatting_transaction.edit_ids.is_empty() {
1447 zlog::debug!(logger => "no changes made while formatting");
1448 buffer.forget_transaction(formatting_transaction_id);
1449 return;
1450 }
1451 if !push_to_history {
1452 zlog::trace!(logger => "forgetting format transaction");
1453 buffer.forget_transaction(formatting_transaction.id);
1454 }
1455 project_transaction
1456 .0
1457 .insert(cx.entity(), formatting_transaction);
1458 })?;
1459
1460 result?;
1461 }
1462
1463 Ok(project_transaction)
1464 }
1465
1466 async fn format_buffer_locally(
1467 lsp_store: WeakEntity<LspStore>,
1468 buffer: &FormattableBuffer,
1469 formatting_transaction_id: clock::Lamport,
1470 trigger: FormatTrigger,
1471 logger: zlog::Logger,
1472 cx: &mut AsyncApp,
1473 ) -> Result<()> {
1474 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1475 buffer.handle.update(cx, |buffer, cx| {
1476 let adapters_and_servers = lsp_store
1477 .as_local()
1478 .unwrap()
1479 .language_servers_for_buffer(buffer, cx)
1480 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1481 .collect::<Vec<_>>();
1482 let settings =
1483 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1484 .into_owned();
1485 (adapters_and_servers, settings)
1486 })
1487 })?;
1488
1489 /// Apply edits to the buffer that will become part of the formatting transaction.
1490 /// Fails if the buffer has been edited since the start of that transaction.
1491 fn extend_formatting_transaction(
1492 buffer: &FormattableBuffer,
1493 formatting_transaction_id: text::TransactionId,
1494 cx: &mut AsyncApp,
1495 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1496 ) -> anyhow::Result<()> {
1497 buffer.handle.update(cx, |buffer, cx| {
1498 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1499 if last_transaction_id != Some(formatting_transaction_id) {
1500 anyhow::bail!("Buffer edited while formatting. Aborting")
1501 }
1502 buffer.start_transaction();
1503 operation(buffer, cx);
1504 if let Some(transaction_id) = buffer.end_transaction(cx) {
1505 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1506 }
1507 Ok(())
1508 })?
1509 }
1510
1511 // handle whitespace formatting
1512 if settings.remove_trailing_whitespace_on_save {
1513 zlog::trace!(logger => "removing trailing whitespace");
1514 let diff = buffer
1515 .handle
1516 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1517 .await;
1518 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1519 buffer.apply_diff(diff, cx);
1520 })?;
1521 }
1522
1523 if settings.ensure_final_newline_on_save {
1524 zlog::trace!(logger => "ensuring final newline");
1525 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1526 buffer.ensure_final_newline(cx);
1527 })?;
1528 }
1529
1530 // Formatter for `code_actions_on_format` that runs before
1531 // the rest of the formatters
1532 let mut code_actions_on_format_formatters = None;
1533 let should_run_code_actions_on_format = !matches!(
1534 (trigger, &settings.format_on_save),
1535 (FormatTrigger::Save, &FormatOnSave::Off)
1536 );
1537 if should_run_code_actions_on_format {
1538 let have_code_actions_to_run_on_format = settings
1539 .code_actions_on_format
1540 .values()
1541 .any(|enabled| *enabled);
1542 if have_code_actions_to_run_on_format {
1543 zlog::trace!(logger => "going to run code actions on format");
1544 code_actions_on_format_formatters = Some(
1545 settings
1546 .code_actions_on_format
1547 .iter()
1548 .filter_map(|(action, enabled)| enabled.then_some(action))
1549 .cloned()
1550 .map(Formatter::CodeAction)
1551 .collect::<Vec<_>>(),
1552 );
1553 }
1554 }
1555
1556 let formatters = match (trigger, &settings.format_on_save) {
1557 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1558 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1559 settings.formatter.as_ref()
1560 }
1561 };
1562
1563 let formatters = code_actions_on_format_formatters
1564 .iter()
1565 .flatten()
1566 .chain(formatters);
1567
1568 for formatter in formatters {
1569 let formatter = if formatter == &Formatter::Auto {
1570 if settings.prettier.allowed {
1571 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1572 &Formatter::Prettier
1573 } else {
1574 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1575 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1576 }
1577 } else {
1578 formatter
1579 };
1580 match formatter {
1581 Formatter::Auto => unreachable!("Auto resolved above"),
1582 Formatter::Prettier => {
1583 let logger = zlog::scoped!(logger => "prettier");
1584 zlog::trace!(logger => "formatting");
1585 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1586
1587 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1588 lsp_store.prettier_store().unwrap().downgrade()
1589 })?;
1590 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1591 .await
1592 .transpose()?;
1593 let Some(diff) = diff else {
1594 zlog::trace!(logger => "No changes");
1595 continue;
1596 };
1597
1598 extend_formatting_transaction(
1599 buffer,
1600 formatting_transaction_id,
1601 cx,
1602 |buffer, cx| {
1603 buffer.apply_diff(diff, cx);
1604 },
1605 )?;
1606 }
1607 Formatter::External { command, arguments } => {
1608 let logger = zlog::scoped!(logger => "command");
1609 zlog::trace!(logger => "formatting");
1610 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1611
1612 let diff = Self::format_via_external_command(
1613 buffer,
1614 command.as_ref(),
1615 arguments.as_deref(),
1616 cx,
1617 )
1618 .await
1619 .with_context(|| {
1620 format!("Failed to format buffer via external command: {}", command)
1621 })?;
1622 let Some(diff) = diff else {
1623 zlog::trace!(logger => "No changes");
1624 continue;
1625 };
1626
1627 extend_formatting_transaction(
1628 buffer,
1629 formatting_transaction_id,
1630 cx,
1631 |buffer, cx| {
1632 buffer.apply_diff(diff, cx);
1633 },
1634 )?;
1635 }
1636 Formatter::LanguageServer(specifier) => {
1637 let logger = zlog::scoped!(logger => "language-server");
1638 zlog::trace!(logger => "formatting");
1639 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1640
1641 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1642 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1643 continue;
1644 };
1645
1646 let language_server = match specifier {
1647 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1648 adapters_and_servers.iter().find_map(|(adapter, server)| {
1649 if adapter.name.0.as_ref() == name {
1650 Some(server.clone())
1651 } else {
1652 None
1653 }
1654 })
1655 }
1656 settings::LanguageServerFormatterSpecifier::Current => {
1657 adapters_and_servers.first().map(|e| e.1.clone())
1658 }
1659 };
1660
1661 let Some(language_server) = language_server else {
1662 log::debug!(
1663 "No language server found to format buffer '{:?}'. Skipping",
1664 buffer_path_abs.as_path().to_string_lossy()
1665 );
1666 continue;
1667 };
1668
1669 zlog::trace!(
1670 logger =>
1671 "Formatting buffer '{:?}' using language server '{:?}'",
1672 buffer_path_abs.as_path().to_string_lossy(),
1673 language_server.name()
1674 );
1675
1676 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1677 zlog::trace!(logger => "formatting ranges");
1678 Self::format_ranges_via_lsp(
1679 &lsp_store,
1680 &buffer.handle,
1681 ranges,
1682 buffer_path_abs,
1683 &language_server,
1684 &settings,
1685 cx,
1686 )
1687 .await
1688 .context("Failed to format ranges via language server")?
1689 } else {
1690 zlog::trace!(logger => "formatting full");
1691 Self::format_via_lsp(
1692 &lsp_store,
1693 &buffer.handle,
1694 buffer_path_abs,
1695 &language_server,
1696 &settings,
1697 cx,
1698 )
1699 .await
1700 .context("failed to format via language server")?
1701 };
1702
1703 if edits.is_empty() {
1704 zlog::trace!(logger => "No changes");
1705 continue;
1706 }
1707 extend_formatting_transaction(
1708 buffer,
1709 formatting_transaction_id,
1710 cx,
1711 |buffer, cx| {
1712 buffer.edit(edits, None, cx);
1713 },
1714 )?;
1715 }
1716 Formatter::CodeAction(code_action_name) => {
1717 let logger = zlog::scoped!(logger => "code-actions");
1718 zlog::trace!(logger => "formatting");
1719 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1720
1721 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1722 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1723 continue;
1724 };
1725
1726 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1727 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1728
1729 let mut actions_and_servers = Vec::new();
1730
1731 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1732 let actions_result = Self::get_server_code_actions_from_action_kinds(
1733 &lsp_store,
1734 language_server.server_id(),
1735 vec![code_action_kind.clone()],
1736 &buffer.handle,
1737 cx,
1738 )
1739 .await
1740 .with_context(|| {
1741 format!(
1742 "Failed to resolve code action {:?} with language server {}",
1743 code_action_kind,
1744 language_server.name()
1745 )
1746 });
1747 let Ok(actions) = actions_result else {
1748 // note: it may be better to set result to the error and break formatters here
1749 // but for now we try to execute the actions that we can resolve and skip the rest
1750 zlog::error!(
1751 logger =>
1752 "Failed to resolve code action {:?} with language server {}",
1753 code_action_kind,
1754 language_server.name()
1755 );
1756 continue;
1757 };
1758 for action in actions {
1759 actions_and_servers.push((action, index));
1760 }
1761 }
1762
1763 if actions_and_servers.is_empty() {
1764 zlog::warn!(logger => "No code actions were resolved, continuing");
1765 continue;
1766 }
1767
1768 'actions: for (mut action, server_index) in actions_and_servers {
1769 let server = &adapters_and_servers[server_index].1;
1770
1771 let describe_code_action = |action: &CodeAction| {
1772 format!(
1773 "code action '{}' with title \"{}\" on server {}",
1774 action
1775 .lsp_action
1776 .action_kind()
1777 .unwrap_or("unknown".into())
1778 .as_str(),
1779 action.lsp_action.title(),
1780 server.name(),
1781 )
1782 };
1783
1784 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1785
1786 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1787 zlog::error!(
1788 logger =>
1789 "Failed to resolve {}. Error: {}",
1790 describe_code_action(&action),
1791 err
1792 );
1793 continue;
1794 }
1795
1796 if let Some(edit) = action.lsp_action.edit().cloned() {
1797 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1798 // but filters out and logs warnings for code actions that require unreasonably
1799 // difficult handling on our part, such as:
1800 // - applying edits that call commands
1801 // which can result in arbitrary workspace edits being sent from the server that
1802 // have no way of being tied back to the command that initiated them (i.e. we
1803 // can't know which edits are part of the format request, or if the server is done sending
1804 // actions in response to the command)
1805 // - actions that create/delete/modify/rename files other than the one we are formatting
1806 // as we then would need to handle such changes correctly in the local history as well
1807 // as the remote history through the ProjectTransaction
1808 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1809 // Supporting these actions is not impossible, but not supported as of yet.
1810 if edit.changes.is_none() && edit.document_changes.is_none() {
1811 zlog::trace!(
1812 logger =>
1813 "No changes for code action. Skipping {}",
1814 describe_code_action(&action),
1815 );
1816 continue;
1817 }
1818
1819 let mut operations = Vec::new();
1820 if let Some(document_changes) = edit.document_changes {
1821 match document_changes {
1822 lsp::DocumentChanges::Edits(edits) => operations.extend(
1823 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1824 ),
1825 lsp::DocumentChanges::Operations(ops) => operations = ops,
1826 }
1827 } else if let Some(changes) = edit.changes {
1828 operations.extend(changes.into_iter().map(|(uri, edits)| {
1829 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1830 text_document:
1831 lsp::OptionalVersionedTextDocumentIdentifier {
1832 uri,
1833 version: None,
1834 },
1835 edits: edits.into_iter().map(Edit::Plain).collect(),
1836 })
1837 }));
1838 }
1839
1840 let mut edits = Vec::with_capacity(operations.len());
1841
1842 if operations.is_empty() {
1843 zlog::trace!(
1844 logger =>
1845 "No changes for code action. Skipping {}",
1846 describe_code_action(&action),
1847 );
1848 continue;
1849 }
1850 for operation in operations {
1851 let op = match operation {
1852 lsp::DocumentChangeOperation::Edit(op) => op,
1853 lsp::DocumentChangeOperation::Op(_) => {
1854 zlog::warn!(
1855 logger =>
1856 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1857 describe_code_action(&action),
1858 );
1859 continue 'actions;
1860 }
1861 };
1862 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1863 zlog::warn!(
1864 logger =>
1865 "Failed to convert URI '{:?}' to file path. Skipping {}",
1866 &op.text_document.uri,
1867 describe_code_action(&action),
1868 );
1869 continue 'actions;
1870 };
1871 if &file_path != buffer_path_abs {
1872 zlog::warn!(
1873 logger =>
1874 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1875 file_path,
1876 buffer_path_abs,
1877 describe_code_action(&action),
1878 );
1879 continue 'actions;
1880 }
1881
1882 let mut lsp_edits = Vec::new();
1883 for edit in op.edits {
1884 match edit {
1885 Edit::Plain(edit) => {
1886 if !lsp_edits.contains(&edit) {
1887 lsp_edits.push(edit);
1888 }
1889 }
1890 Edit::Annotated(edit) => {
1891 if !lsp_edits.contains(&edit.text_edit) {
1892 lsp_edits.push(edit.text_edit);
1893 }
1894 }
1895 Edit::Snippet(_) => {
1896 zlog::warn!(
1897 logger =>
1898 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1899 describe_code_action(&action),
1900 );
1901 continue 'actions;
1902 }
1903 }
1904 }
1905 let edits_result = lsp_store
1906 .update(cx, |lsp_store, cx| {
1907 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1908 &buffer.handle,
1909 lsp_edits,
1910 server.server_id(),
1911 op.text_document.version,
1912 cx,
1913 )
1914 })?
1915 .await;
1916 let Ok(resolved_edits) = edits_result else {
1917 zlog::warn!(
1918 logger =>
1919 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1920 buffer_path_abs.as_path(),
1921 describe_code_action(&action),
1922 );
1923 continue 'actions;
1924 };
1925 edits.extend(resolved_edits);
1926 }
1927
1928 if edits.is_empty() {
1929 zlog::warn!(logger => "No edits resolved from LSP");
1930 continue;
1931 }
1932
1933 extend_formatting_transaction(
1934 buffer,
1935 formatting_transaction_id,
1936 cx,
1937 |buffer, cx| {
1938 zlog::info!(
1939 "Applying edits {edits:?}. Content: {:?}",
1940 buffer.text()
1941 );
1942 buffer.edit(edits, None, cx);
1943 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1944 },
1945 )?;
1946 }
1947
1948 if let Some(command) = action.lsp_action.command() {
1949 zlog::warn!(
1950 logger =>
1951 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1952 &command.command,
1953 );
1954
1955 // bail early if command is invalid
1956 let server_capabilities = server.capabilities();
1957 let available_commands = server_capabilities
1958 .execute_command_provider
1959 .as_ref()
1960 .map(|options| options.commands.as_slice())
1961 .unwrap_or_default();
1962 if !available_commands.contains(&command.command) {
1963 zlog::warn!(
1964 logger =>
1965 "Cannot execute a command {} not listed in the language server capabilities of server {}",
1966 command.command,
1967 server.name(),
1968 );
1969 continue;
1970 }
1971
1972 // noop so we just ensure buffer hasn't been edited since resolving code actions
1973 extend_formatting_transaction(
1974 buffer,
1975 formatting_transaction_id,
1976 cx,
1977 |_, _| {},
1978 )?;
1979 zlog::info!(logger => "Executing command {}", &command.command);
1980
1981 lsp_store.update(cx, |this, _| {
1982 this.as_local_mut()
1983 .unwrap()
1984 .last_workspace_edits_by_language_server
1985 .remove(&server.server_id());
1986 })?;
1987
1988 let execute_command_result = server
1989 .request::<lsp::request::ExecuteCommand>(
1990 lsp::ExecuteCommandParams {
1991 command: command.command.clone(),
1992 arguments: command.arguments.clone().unwrap_or_default(),
1993 ..Default::default()
1994 },
1995 )
1996 .await
1997 .into_response();
1998
1999 if execute_command_result.is_err() {
2000 zlog::error!(
2001 logger =>
2002 "Failed to execute command '{}' as part of {}",
2003 &command.command,
2004 describe_code_action(&action),
2005 );
2006 continue 'actions;
2007 }
2008
2009 let mut project_transaction_command =
2010 lsp_store.update(cx, |this, _| {
2011 this.as_local_mut()
2012 .unwrap()
2013 .last_workspace_edits_by_language_server
2014 .remove(&server.server_id())
2015 .unwrap_or_default()
2016 })?;
2017
2018 if let Some(transaction) =
2019 project_transaction_command.0.remove(&buffer.handle)
2020 {
2021 zlog::trace!(
2022 logger =>
2023 "Successfully captured {} edits that resulted from command {}",
2024 transaction.edit_ids.len(),
2025 &command.command,
2026 );
2027 let transaction_id_project_transaction = transaction.id;
2028 buffer.handle.update(cx, |buffer, _| {
2029 // it may have been removed from history if push_to_history was
2030 // false in deserialize_workspace_edit. If so push it so we
2031 // can merge it with the format transaction
2032 // and pop the combined transaction off the history stack
2033 // later if push_to_history is false
2034 if buffer.get_transaction(transaction.id).is_none() {
2035 buffer.push_transaction(transaction, Instant::now());
2036 }
2037 buffer.merge_transactions(
2038 transaction_id_project_transaction,
2039 formatting_transaction_id,
2040 );
2041 })?;
2042 }
2043
2044 if !project_transaction_command.0.is_empty() {
2045 let mut extra_buffers = String::new();
2046 for buffer in project_transaction_command.0.keys() {
2047 buffer
2048 .read_with(cx, |b, cx| {
2049 if let Some(path) = b.project_path(cx) {
2050 if !extra_buffers.is_empty() {
2051 extra_buffers.push_str(", ");
2052 }
2053 extra_buffers.push_str(path.path.as_unix_str());
2054 }
2055 })
2056 .ok();
2057 }
2058 zlog::warn!(
2059 logger =>
2060 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2061 &command.command,
2062 extra_buffers,
2063 );
2064 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2065 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2066 // add it so it's included, and merge it into the format transaction when its created later
2067 }
2068 }
2069 }
2070 }
2071 }
2072 }
2073
2074 Ok(())
2075 }
2076
2077 pub async fn format_ranges_via_lsp(
2078 this: &WeakEntity<LspStore>,
2079 buffer_handle: &Entity<Buffer>,
2080 ranges: &[Range<Anchor>],
2081 abs_path: &Path,
2082 language_server: &Arc<LanguageServer>,
2083 settings: &LanguageSettings,
2084 cx: &mut AsyncApp,
2085 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2086 let capabilities = &language_server.capabilities();
2087 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2088 if range_formatting_provider == Some(&OneOf::Left(false)) {
2089 anyhow::bail!(
2090 "{} language server does not support range formatting",
2091 language_server.name()
2092 );
2093 }
2094
2095 let uri = file_path_to_lsp_url(abs_path)?;
2096 let text_document = lsp::TextDocumentIdentifier::new(uri);
2097
2098 let lsp_edits = {
2099 let mut lsp_ranges = Vec::new();
2100 this.update(cx, |_this, cx| {
2101 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2102 // not have been sent to the language server. This seems like a fairly systemic
2103 // issue, though, the resolution probably is not specific to formatting.
2104 //
2105 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2106 // LSP.
2107 let snapshot = buffer_handle.read(cx).snapshot();
2108 for range in ranges {
2109 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2110 }
2111 anyhow::Ok(())
2112 })??;
2113
2114 let mut edits = None;
2115 for range in lsp_ranges {
2116 if let Some(mut edit) = language_server
2117 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2118 text_document: text_document.clone(),
2119 range,
2120 options: lsp_command::lsp_formatting_options(settings),
2121 work_done_progress_params: Default::default(),
2122 })
2123 .await
2124 .into_response()?
2125 {
2126 edits.get_or_insert_with(Vec::new).append(&mut edit);
2127 }
2128 }
2129 edits
2130 };
2131
2132 if let Some(lsp_edits) = lsp_edits {
2133 this.update(cx, |this, cx| {
2134 this.as_local_mut().unwrap().edits_from_lsp(
2135 buffer_handle,
2136 lsp_edits,
2137 language_server.server_id(),
2138 None,
2139 cx,
2140 )
2141 })?
2142 .await
2143 } else {
2144 Ok(Vec::with_capacity(0))
2145 }
2146 }
2147
2148 async fn format_via_lsp(
2149 this: &WeakEntity<LspStore>,
2150 buffer: &Entity<Buffer>,
2151 abs_path: &Path,
2152 language_server: &Arc<LanguageServer>,
2153 settings: &LanguageSettings,
2154 cx: &mut AsyncApp,
2155 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2156 let logger = zlog::scoped!("lsp_format");
2157 zlog::debug!(logger => "Formatting via LSP");
2158
2159 let uri = file_path_to_lsp_url(abs_path)?;
2160 let text_document = lsp::TextDocumentIdentifier::new(uri);
2161 let capabilities = &language_server.capabilities();
2162
2163 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2164 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2165
2166 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2167 let _timer = zlog::time!(logger => "format-full");
2168 language_server
2169 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2170 text_document,
2171 options: lsp_command::lsp_formatting_options(settings),
2172 work_done_progress_params: Default::default(),
2173 })
2174 .await
2175 .into_response()?
2176 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2177 let _timer = zlog::time!(logger => "format-range");
2178 let buffer_start = lsp::Position::new(0, 0);
2179 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2180 language_server
2181 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2182 text_document: text_document.clone(),
2183 range: lsp::Range::new(buffer_start, buffer_end),
2184 options: lsp_command::lsp_formatting_options(settings),
2185 work_done_progress_params: Default::default(),
2186 })
2187 .await
2188 .into_response()?
2189 } else {
2190 None
2191 };
2192
2193 if let Some(lsp_edits) = lsp_edits {
2194 this.update(cx, |this, cx| {
2195 this.as_local_mut().unwrap().edits_from_lsp(
2196 buffer,
2197 lsp_edits,
2198 language_server.server_id(),
2199 None,
2200 cx,
2201 )
2202 })?
2203 .await
2204 } else {
2205 Ok(Vec::with_capacity(0))
2206 }
2207 }
2208
2209 async fn format_via_external_command(
2210 buffer: &FormattableBuffer,
2211 command: &str,
2212 arguments: Option<&[String]>,
2213 cx: &mut AsyncApp,
2214 ) -> Result<Option<Diff>> {
2215 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2216 let file = File::from_dyn(buffer.file())?;
2217 let worktree = file.worktree.read(cx);
2218 let mut worktree_path = worktree.abs_path().to_path_buf();
2219 if worktree.root_entry()?.is_file() {
2220 worktree_path.pop();
2221 }
2222 Some(worktree_path)
2223 })?;
2224
2225 let mut child = util::command::new_smol_command(command);
2226
2227 if let Some(buffer_env) = buffer.env.as_ref() {
2228 child.envs(buffer_env);
2229 }
2230
2231 if let Some(working_dir_path) = working_dir_path {
2232 child.current_dir(working_dir_path);
2233 }
2234
2235 if let Some(arguments) = arguments {
2236 child.args(arguments.iter().map(|arg| {
2237 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2238 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2239 } else {
2240 arg.replace("{buffer_path}", "Untitled")
2241 }
2242 }));
2243 }
2244
2245 let mut child = child
2246 .stdin(smol::process::Stdio::piped())
2247 .stdout(smol::process::Stdio::piped())
2248 .stderr(smol::process::Stdio::piped())
2249 .spawn()?;
2250
2251 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2252 let text = buffer
2253 .handle
2254 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2255 for chunk in text.chunks() {
2256 stdin.write_all(chunk.as_bytes()).await?;
2257 }
2258 stdin.flush().await?;
2259
2260 let output = child.output().await?;
2261 anyhow::ensure!(
2262 output.status.success(),
2263 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2264 output.status.code(),
2265 String::from_utf8_lossy(&output.stdout),
2266 String::from_utf8_lossy(&output.stderr),
2267 );
2268
2269 let stdout = String::from_utf8(output.stdout)?;
2270 Ok(Some(
2271 buffer
2272 .handle
2273 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2274 .await,
2275 ))
2276 }
2277
2278 async fn try_resolve_code_action(
2279 lang_server: &LanguageServer,
2280 action: &mut CodeAction,
2281 ) -> anyhow::Result<()> {
2282 match &mut action.lsp_action {
2283 LspAction::Action(lsp_action) => {
2284 if !action.resolved
2285 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2286 && lsp_action.data.is_some()
2287 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2288 {
2289 **lsp_action = lang_server
2290 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2291 .await
2292 .into_response()?;
2293 }
2294 }
2295 LspAction::CodeLens(lens) => {
2296 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2297 *lens = lang_server
2298 .request::<lsp::request::CodeLensResolve>(lens.clone())
2299 .await
2300 .into_response()?;
2301 }
2302 }
2303 LspAction::Command(_) => {}
2304 }
2305
2306 action.resolved = true;
2307 anyhow::Ok(())
2308 }
2309
2310 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2311 let buffer = buffer_handle.read(cx);
2312
2313 let file = buffer.file().cloned();
2314
2315 let Some(file) = File::from_dyn(file.as_ref()) else {
2316 return;
2317 };
2318 if !file.is_local() {
2319 return;
2320 }
2321 let path = ProjectPath::from_file(file, cx);
2322 let worktree_id = file.worktree_id(cx);
2323 let language = buffer.language().cloned();
2324
2325 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2326 for (server_id, diagnostics) in
2327 diagnostics.get(file.path()).cloned().unwrap_or_default()
2328 {
2329 self.update_buffer_diagnostics(
2330 buffer_handle,
2331 server_id,
2332 None,
2333 None,
2334 None,
2335 Vec::new(),
2336 diagnostics,
2337 cx,
2338 )
2339 .log_err();
2340 }
2341 }
2342 let Some(language) = language else {
2343 return;
2344 };
2345 let Some(snapshot) = self
2346 .worktree_store
2347 .read(cx)
2348 .worktree_for_id(worktree_id, cx)
2349 .map(|worktree| worktree.read(cx).snapshot())
2350 else {
2351 return;
2352 };
2353 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2354
2355 for server_id in
2356 self.lsp_tree
2357 .get(path, language.name(), language.manifest(), &delegate, cx)
2358 {
2359 let server = self
2360 .language_servers
2361 .get(&server_id)
2362 .and_then(|server_state| {
2363 if let LanguageServerState::Running { server, .. } = server_state {
2364 Some(server.clone())
2365 } else {
2366 None
2367 }
2368 });
2369 let server = match server {
2370 Some(server) => server,
2371 None => continue,
2372 };
2373
2374 buffer_handle.update(cx, |buffer, cx| {
2375 buffer.set_completion_triggers(
2376 server.server_id(),
2377 server
2378 .capabilities()
2379 .completion_provider
2380 .as_ref()
2381 .and_then(|provider| {
2382 provider
2383 .trigger_characters
2384 .as_ref()
2385 .map(|characters| characters.iter().cloned().collect())
2386 })
2387 .unwrap_or_default(),
2388 cx,
2389 );
2390 });
2391 }
2392 }
2393
2394 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2395 buffer.update(cx, |buffer, cx| {
2396 let Some(language) = buffer.language() else {
2397 return;
2398 };
2399 let path = ProjectPath {
2400 worktree_id: old_file.worktree_id(cx),
2401 path: old_file.path.clone(),
2402 };
2403 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2404 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2405 buffer.set_completion_triggers(server_id, Default::default(), cx);
2406 }
2407 });
2408 }
2409
2410 fn update_buffer_diagnostics(
2411 &mut self,
2412 buffer: &Entity<Buffer>,
2413 server_id: LanguageServerId,
2414 registration_id: Option<Option<SharedString>>,
2415 result_id: Option<SharedString>,
2416 version: Option<i32>,
2417 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2418 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2419 cx: &mut Context<LspStore>,
2420 ) -> Result<()> {
2421 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2422 Ordering::Equal
2423 .then_with(|| b.is_primary.cmp(&a.is_primary))
2424 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2425 .then_with(|| a.severity.cmp(&b.severity))
2426 .then_with(|| a.message.cmp(&b.message))
2427 }
2428
2429 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2430 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2431 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2432
2433 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2434 Ordering::Equal
2435 .then_with(|| a.range.start.cmp(&b.range.start))
2436 .then_with(|| b.range.end.cmp(&a.range.end))
2437 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2438 });
2439
2440 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2441
2442 let edits_since_save = std::cell::LazyCell::new(|| {
2443 let saved_version = buffer.read(cx).saved_version();
2444 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2445 });
2446
2447 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2448
2449 for (new_diagnostic, entry) in diagnostics {
2450 let start;
2451 let end;
2452 if new_diagnostic && entry.diagnostic.is_disk_based {
2453 // Some diagnostics are based on files on disk instead of buffers'
2454 // current contents. Adjust these diagnostics' ranges to reflect
2455 // any unsaved edits.
2456 // Do not alter the reused ones though, as their coordinates were stored as anchors
2457 // and were properly adjusted on reuse.
2458 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2459 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2460 } else {
2461 start = entry.range.start;
2462 end = entry.range.end;
2463 }
2464
2465 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2466 ..snapshot.clip_point_utf16(end, Bias::Right);
2467
2468 // Expand empty ranges by one codepoint
2469 if range.start == range.end {
2470 // This will be go to the next boundary when being clipped
2471 range.end.column += 1;
2472 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2473 if range.start == range.end && range.end.column > 0 {
2474 range.start.column -= 1;
2475 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2476 }
2477 }
2478
2479 sanitized_diagnostics.push(DiagnosticEntry {
2480 range,
2481 diagnostic: entry.diagnostic,
2482 });
2483 }
2484 drop(edits_since_save);
2485
2486 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2487 buffer.update(cx, |buffer, cx| {
2488 if let Some(registration_id) = registration_id {
2489 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2490 self.buffer_pull_diagnostics_result_ids
2491 .entry(server_id)
2492 .or_default()
2493 .entry(registration_id)
2494 .or_default()
2495 .insert(abs_path, result_id);
2496 }
2497 }
2498
2499 buffer.update_diagnostics(server_id, set, cx)
2500 });
2501
2502 Ok(())
2503 }
2504
2505 fn register_language_server_for_invisible_worktree(
2506 &mut self,
2507 worktree: &Entity<Worktree>,
2508 language_server_id: LanguageServerId,
2509 cx: &mut App,
2510 ) {
2511 let worktree = worktree.read(cx);
2512 let worktree_id = worktree.id();
2513 debug_assert!(!worktree.is_visible());
2514 let Some(mut origin_seed) = self
2515 .language_server_ids
2516 .iter()
2517 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2518 else {
2519 return;
2520 };
2521 origin_seed.worktree_id = worktree_id;
2522 self.language_server_ids
2523 .entry(origin_seed)
2524 .or_insert_with(|| UnifiedLanguageServer {
2525 id: language_server_id,
2526 project_roots: Default::default(),
2527 });
2528 }
2529
2530 fn register_buffer_with_language_servers(
2531 &mut self,
2532 buffer_handle: &Entity<Buffer>,
2533 only_register_servers: HashSet<LanguageServerSelector>,
2534 cx: &mut Context<LspStore>,
2535 ) {
2536 let buffer = buffer_handle.read(cx);
2537 let buffer_id = buffer.remote_id();
2538
2539 let Some(file) = File::from_dyn(buffer.file()) else {
2540 return;
2541 };
2542 if !file.is_local() {
2543 return;
2544 }
2545
2546 let abs_path = file.abs_path(cx);
2547 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2548 return;
2549 };
2550 let initial_snapshot = buffer.text_snapshot();
2551 let worktree_id = file.worktree_id(cx);
2552
2553 let Some(language) = buffer.language().cloned() else {
2554 return;
2555 };
2556 let path: Arc<RelPath> = file
2557 .path()
2558 .parent()
2559 .map(Arc::from)
2560 .unwrap_or_else(|| file.path().clone());
2561 let Some(worktree) = self
2562 .worktree_store
2563 .read(cx)
2564 .worktree_for_id(worktree_id, cx)
2565 else {
2566 return;
2567 };
2568 let language_name = language.name();
2569 let (reused, delegate, servers) = self
2570 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2571 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2572 .unwrap_or_else(|| {
2573 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2574 let delegate: Arc<dyn ManifestDelegate> =
2575 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2576
2577 let servers = self
2578 .lsp_tree
2579 .walk(
2580 ProjectPath { worktree_id, path },
2581 language.name(),
2582 language.manifest(),
2583 &delegate,
2584 cx,
2585 )
2586 .collect::<Vec<_>>();
2587 (false, lsp_delegate, servers)
2588 });
2589 let servers_and_adapters = servers
2590 .into_iter()
2591 .filter_map(|server_node| {
2592 if reused && server_node.server_id().is_none() {
2593 return None;
2594 }
2595 if !only_register_servers.is_empty() {
2596 if let Some(server_id) = server_node.server_id()
2597 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2598 {
2599 return None;
2600 }
2601 if let Some(name) = server_node.name()
2602 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2603 {
2604 return None;
2605 }
2606 }
2607
2608 let server_id = server_node.server_id_or_init(|disposition| {
2609 let path = &disposition.path;
2610
2611 {
2612 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2613
2614 let server_id = self.get_or_insert_language_server(
2615 &worktree,
2616 delegate.clone(),
2617 disposition,
2618 &language_name,
2619 cx,
2620 );
2621
2622 if let Some(state) = self.language_servers.get(&server_id)
2623 && let Ok(uri) = uri
2624 {
2625 state.add_workspace_folder(uri);
2626 };
2627 server_id
2628 }
2629 })?;
2630 let server_state = self.language_servers.get(&server_id)?;
2631 if let LanguageServerState::Running {
2632 server, adapter, ..
2633 } = server_state
2634 {
2635 Some((server.clone(), adapter.clone()))
2636 } else {
2637 None
2638 }
2639 })
2640 .collect::<Vec<_>>();
2641 for (server, adapter) in servers_and_adapters {
2642 buffer_handle.update(cx, |buffer, cx| {
2643 buffer.set_completion_triggers(
2644 server.server_id(),
2645 server
2646 .capabilities()
2647 .completion_provider
2648 .as_ref()
2649 .and_then(|provider| {
2650 provider
2651 .trigger_characters
2652 .as_ref()
2653 .map(|characters| characters.iter().cloned().collect())
2654 })
2655 .unwrap_or_default(),
2656 cx,
2657 );
2658 });
2659
2660 let snapshot = LspBufferSnapshot {
2661 version: 0,
2662 snapshot: initial_snapshot.clone(),
2663 };
2664
2665 let mut registered = false;
2666 self.buffer_snapshots
2667 .entry(buffer_id)
2668 .or_default()
2669 .entry(server.server_id())
2670 .or_insert_with(|| {
2671 registered = true;
2672 server.register_buffer(
2673 uri.clone(),
2674 adapter.language_id(&language.name()),
2675 0,
2676 initial_snapshot.text(),
2677 );
2678
2679 vec![snapshot]
2680 });
2681
2682 self.buffers_opened_in_servers
2683 .entry(buffer_id)
2684 .or_default()
2685 .insert(server.server_id());
2686 if registered {
2687 cx.emit(LspStoreEvent::LanguageServerUpdate {
2688 language_server_id: server.server_id(),
2689 name: None,
2690 message: proto::update_language_server::Variant::RegisteredForBuffer(
2691 proto::RegisteredForBuffer {
2692 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2693 buffer_id: buffer_id.to_proto(),
2694 },
2695 ),
2696 });
2697 }
2698 }
2699 }
2700
2701 fn reuse_existing_language_server<'lang_name>(
2702 &self,
2703 server_tree: &LanguageServerTree,
2704 worktree: &Entity<Worktree>,
2705 language_name: &'lang_name LanguageName,
2706 cx: &mut App,
2707 ) -> Option<(
2708 Arc<LocalLspAdapterDelegate>,
2709 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2710 )> {
2711 if worktree.read(cx).is_visible() {
2712 return None;
2713 }
2714
2715 let worktree_store = self.worktree_store.read(cx);
2716 let servers = server_tree
2717 .instances
2718 .iter()
2719 .filter(|(worktree_id, _)| {
2720 worktree_store
2721 .worktree_for_id(**worktree_id, cx)
2722 .is_some_and(|worktree| worktree.read(cx).is_visible())
2723 })
2724 .flat_map(|(worktree_id, servers)| {
2725 servers
2726 .roots
2727 .iter()
2728 .flat_map(|(_, language_servers)| language_servers)
2729 .map(move |(_, (server_node, server_languages))| {
2730 (worktree_id, server_node, server_languages)
2731 })
2732 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2733 .map(|(worktree_id, server_node, _)| {
2734 (
2735 *worktree_id,
2736 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2737 )
2738 })
2739 })
2740 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2741 acc.entry(worktree_id)
2742 .or_insert_with(Vec::new)
2743 .push(server_node);
2744 acc
2745 })
2746 .into_values()
2747 .max_by_key(|servers| servers.len())?;
2748
2749 let worktree_id = worktree.read(cx).id();
2750 let apply = move |tree: &mut LanguageServerTree| {
2751 for server_node in &servers {
2752 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2753 }
2754 servers
2755 };
2756
2757 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2758 Some((delegate, apply))
2759 }
2760
2761 pub(crate) fn unregister_old_buffer_from_language_servers(
2762 &mut self,
2763 buffer: &Entity<Buffer>,
2764 old_file: &File,
2765 cx: &mut App,
2766 ) {
2767 let old_path = match old_file.as_local() {
2768 Some(local) => local.abs_path(cx),
2769 None => return,
2770 };
2771
2772 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2773 debug_panic!("{old_path:?} is not parseable as an URI");
2774 return;
2775 };
2776 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2777 }
2778
2779 pub(crate) fn unregister_buffer_from_language_servers(
2780 &mut self,
2781 buffer: &Entity<Buffer>,
2782 file_url: &lsp::Uri,
2783 cx: &mut App,
2784 ) {
2785 buffer.update(cx, |buffer, cx| {
2786 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2787
2788 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2789 if snapshots
2790 .as_mut()
2791 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2792 {
2793 language_server.unregister_buffer(file_url.clone());
2794 }
2795 }
2796 });
2797 }
2798
2799 fn buffer_snapshot_for_lsp_version(
2800 &mut self,
2801 buffer: &Entity<Buffer>,
2802 server_id: LanguageServerId,
2803 version: Option<i32>,
2804 cx: &App,
2805 ) -> Result<TextBufferSnapshot> {
2806 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2807
2808 if let Some(version) = version {
2809 let buffer_id = buffer.read(cx).remote_id();
2810 let snapshots = if let Some(snapshots) = self
2811 .buffer_snapshots
2812 .get_mut(&buffer_id)
2813 .and_then(|m| m.get_mut(&server_id))
2814 {
2815 snapshots
2816 } else if version == 0 {
2817 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2818 // We detect this case and treat it as if the version was `None`.
2819 return Ok(buffer.read(cx).text_snapshot());
2820 } else {
2821 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2822 };
2823
2824 let found_snapshot = snapshots
2825 .binary_search_by_key(&version, |e| e.version)
2826 .map(|ix| snapshots[ix].snapshot.clone())
2827 .map_err(|_| {
2828 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2829 })?;
2830
2831 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2832 Ok(found_snapshot)
2833 } else {
2834 Ok((buffer.read(cx)).text_snapshot())
2835 }
2836 }
2837
2838 async fn get_server_code_actions_from_action_kinds(
2839 lsp_store: &WeakEntity<LspStore>,
2840 language_server_id: LanguageServerId,
2841 code_action_kinds: Vec<lsp::CodeActionKind>,
2842 buffer: &Entity<Buffer>,
2843 cx: &mut AsyncApp,
2844 ) -> Result<Vec<CodeAction>> {
2845 let actions = lsp_store
2846 .update(cx, move |this, cx| {
2847 let request = GetCodeActions {
2848 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2849 kinds: Some(code_action_kinds),
2850 };
2851 let server = LanguageServerToQuery::Other(language_server_id);
2852 this.request_lsp(buffer.clone(), server, request, cx)
2853 })?
2854 .await?;
2855 Ok(actions)
2856 }
2857
2858 pub async fn execute_code_actions_on_server(
2859 lsp_store: &WeakEntity<LspStore>,
2860 language_server: &Arc<LanguageServer>,
2861
2862 actions: Vec<CodeAction>,
2863 push_to_history: bool,
2864 project_transaction: &mut ProjectTransaction,
2865 cx: &mut AsyncApp,
2866 ) -> anyhow::Result<()> {
2867 for mut action in actions {
2868 Self::try_resolve_code_action(language_server, &mut action)
2869 .await
2870 .context("resolving a formatting code action")?;
2871
2872 if let Some(edit) = action.lsp_action.edit() {
2873 if edit.changes.is_none() && edit.document_changes.is_none() {
2874 continue;
2875 }
2876
2877 let new = Self::deserialize_workspace_edit(
2878 lsp_store.upgrade().context("project dropped")?,
2879 edit.clone(),
2880 push_to_history,
2881 language_server.clone(),
2882 cx,
2883 )
2884 .await?;
2885 project_transaction.0.extend(new.0);
2886 }
2887
2888 if let Some(command) = action.lsp_action.command() {
2889 let server_capabilities = language_server.capabilities();
2890 let available_commands = server_capabilities
2891 .execute_command_provider
2892 .as_ref()
2893 .map(|options| options.commands.as_slice())
2894 .unwrap_or_default();
2895 if available_commands.contains(&command.command) {
2896 lsp_store.update(cx, |lsp_store, _| {
2897 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2898 mode.last_workspace_edits_by_language_server
2899 .remove(&language_server.server_id());
2900 }
2901 })?;
2902
2903 language_server
2904 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2905 command: command.command.clone(),
2906 arguments: command.arguments.clone().unwrap_or_default(),
2907 ..Default::default()
2908 })
2909 .await
2910 .into_response()
2911 .context("execute command")?;
2912
2913 lsp_store.update(cx, |this, _| {
2914 if let LspStoreMode::Local(mode) = &mut this.mode {
2915 project_transaction.0.extend(
2916 mode.last_workspace_edits_by_language_server
2917 .remove(&language_server.server_id())
2918 .unwrap_or_default()
2919 .0,
2920 )
2921 }
2922 })?;
2923 } else {
2924 log::warn!(
2925 "Cannot execute a command {} not listed in the language server capabilities",
2926 command.command
2927 )
2928 }
2929 }
2930 }
2931 Ok(())
2932 }
2933
2934 pub async fn deserialize_text_edits(
2935 this: Entity<LspStore>,
2936 buffer_to_edit: Entity<Buffer>,
2937 edits: Vec<lsp::TextEdit>,
2938 push_to_history: bool,
2939 _: Arc<CachedLspAdapter>,
2940 language_server: Arc<LanguageServer>,
2941 cx: &mut AsyncApp,
2942 ) -> Result<Option<Transaction>> {
2943 let edits = this
2944 .update(cx, |this, cx| {
2945 this.as_local_mut().unwrap().edits_from_lsp(
2946 &buffer_to_edit,
2947 edits,
2948 language_server.server_id(),
2949 None,
2950 cx,
2951 )
2952 })?
2953 .await?;
2954
2955 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2956 buffer.finalize_last_transaction();
2957 buffer.start_transaction();
2958 for (range, text) in edits {
2959 buffer.edit([(range, text)], None, cx);
2960 }
2961
2962 if buffer.end_transaction(cx).is_some() {
2963 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2964 if !push_to_history {
2965 buffer.forget_transaction(transaction.id);
2966 }
2967 Some(transaction)
2968 } else {
2969 None
2970 }
2971 })?;
2972
2973 Ok(transaction)
2974 }
2975
2976 #[allow(clippy::type_complexity)]
2977 pub(crate) fn edits_from_lsp(
2978 &mut self,
2979 buffer: &Entity<Buffer>,
2980 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
2981 server_id: LanguageServerId,
2982 version: Option<i32>,
2983 cx: &mut Context<LspStore>,
2984 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
2985 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
2986 cx.background_spawn(async move {
2987 let snapshot = snapshot?;
2988 let mut lsp_edits = lsp_edits
2989 .into_iter()
2990 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
2991 .collect::<Vec<_>>();
2992
2993 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
2994
2995 let mut lsp_edits = lsp_edits.into_iter().peekable();
2996 let mut edits = Vec::new();
2997 while let Some((range, mut new_text)) = lsp_edits.next() {
2998 // Clip invalid ranges provided by the language server.
2999 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3000 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3001
3002 // Combine any LSP edits that are adjacent.
3003 //
3004 // Also, combine LSP edits that are separated from each other by only
3005 // a newline. This is important because for some code actions,
3006 // Rust-analyzer rewrites the entire buffer via a series of edits that
3007 // are separated by unchanged newline characters.
3008 //
3009 // In order for the diffing logic below to work properly, any edits that
3010 // cancel each other out must be combined into one.
3011 while let Some((next_range, next_text)) = lsp_edits.peek() {
3012 if next_range.start.0 > range.end {
3013 if next_range.start.0.row > range.end.row + 1
3014 || next_range.start.0.column > 0
3015 || snapshot.clip_point_utf16(
3016 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3017 Bias::Left,
3018 ) > range.end
3019 {
3020 break;
3021 }
3022 new_text.push('\n');
3023 }
3024 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3025 new_text.push_str(next_text);
3026 lsp_edits.next();
3027 }
3028
3029 // For multiline edits, perform a diff of the old and new text so that
3030 // we can identify the changes more precisely, preserving the locations
3031 // of any anchors positioned in the unchanged regions.
3032 if range.end.row > range.start.row {
3033 let offset = range.start.to_offset(&snapshot);
3034 let old_text = snapshot.text_for_range(range).collect::<String>();
3035 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3036 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3037 (
3038 snapshot.anchor_after(offset + range.start)
3039 ..snapshot.anchor_before(offset + range.end),
3040 replacement,
3041 )
3042 }));
3043 } else if range.end == range.start {
3044 let anchor = snapshot.anchor_after(range.start);
3045 edits.push((anchor..anchor, new_text.into()));
3046 } else {
3047 let edit_start = snapshot.anchor_after(range.start);
3048 let edit_end = snapshot.anchor_before(range.end);
3049 edits.push((edit_start..edit_end, new_text.into()));
3050 }
3051 }
3052
3053 Ok(edits)
3054 })
3055 }
3056
3057 pub(crate) async fn deserialize_workspace_edit(
3058 this: Entity<LspStore>,
3059 edit: lsp::WorkspaceEdit,
3060 push_to_history: bool,
3061 language_server: Arc<LanguageServer>,
3062 cx: &mut AsyncApp,
3063 ) -> Result<ProjectTransaction> {
3064 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3065
3066 let mut operations = Vec::new();
3067 if let Some(document_changes) = edit.document_changes {
3068 match document_changes {
3069 lsp::DocumentChanges::Edits(edits) => {
3070 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3071 }
3072 lsp::DocumentChanges::Operations(ops) => operations = ops,
3073 }
3074 } else if let Some(changes) = edit.changes {
3075 operations.extend(changes.into_iter().map(|(uri, edits)| {
3076 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3077 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3078 uri,
3079 version: None,
3080 },
3081 edits: edits.into_iter().map(Edit::Plain).collect(),
3082 })
3083 }));
3084 }
3085
3086 let mut project_transaction = ProjectTransaction::default();
3087 for operation in operations {
3088 match operation {
3089 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3090 let abs_path = op
3091 .uri
3092 .to_file_path()
3093 .map_err(|()| anyhow!("can't convert URI to path"))?;
3094
3095 if let Some(parent_path) = abs_path.parent() {
3096 fs.create_dir(parent_path).await?;
3097 }
3098 if abs_path.ends_with("/") {
3099 fs.create_dir(&abs_path).await?;
3100 } else {
3101 fs.create_file(
3102 &abs_path,
3103 op.options
3104 .map(|options| fs::CreateOptions {
3105 overwrite: options.overwrite.unwrap_or(false),
3106 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3107 })
3108 .unwrap_or_default(),
3109 )
3110 .await?;
3111 }
3112 }
3113
3114 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3115 let source_abs_path = op
3116 .old_uri
3117 .to_file_path()
3118 .map_err(|()| anyhow!("can't convert URI to path"))?;
3119 let target_abs_path = op
3120 .new_uri
3121 .to_file_path()
3122 .map_err(|()| anyhow!("can't convert URI to path"))?;
3123
3124 let options = fs::RenameOptions {
3125 overwrite: op
3126 .options
3127 .as_ref()
3128 .and_then(|options| options.overwrite)
3129 .unwrap_or(false),
3130 ignore_if_exists: op
3131 .options
3132 .as_ref()
3133 .and_then(|options| options.ignore_if_exists)
3134 .unwrap_or(false),
3135 create_parents: true,
3136 };
3137
3138 fs.rename(&source_abs_path, &target_abs_path, options)
3139 .await?;
3140 }
3141
3142 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3143 let abs_path = op
3144 .uri
3145 .to_file_path()
3146 .map_err(|()| anyhow!("can't convert URI to path"))?;
3147 let options = op
3148 .options
3149 .map(|options| fs::RemoveOptions {
3150 recursive: options.recursive.unwrap_or(false),
3151 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3152 })
3153 .unwrap_or_default();
3154 if abs_path.ends_with("/") {
3155 fs.remove_dir(&abs_path, options).await?;
3156 } else {
3157 fs.remove_file(&abs_path, options).await?;
3158 }
3159 }
3160
3161 lsp::DocumentChangeOperation::Edit(op) => {
3162 let buffer_to_edit = this
3163 .update(cx, |this, cx| {
3164 this.open_local_buffer_via_lsp(
3165 op.text_document.uri.clone(),
3166 language_server.server_id(),
3167 cx,
3168 )
3169 })?
3170 .await?;
3171
3172 let edits = this
3173 .update(cx, |this, cx| {
3174 let path = buffer_to_edit.read(cx).project_path(cx);
3175 let active_entry = this.active_entry;
3176 let is_active_entry = path.is_some_and(|project_path| {
3177 this.worktree_store
3178 .read(cx)
3179 .entry_for_path(&project_path, cx)
3180 .is_some_and(|entry| Some(entry.id) == active_entry)
3181 });
3182 let local = this.as_local_mut().unwrap();
3183
3184 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3185 for edit in op.edits {
3186 match edit {
3187 Edit::Plain(edit) => {
3188 if !edits.contains(&edit) {
3189 edits.push(edit)
3190 }
3191 }
3192 Edit::Annotated(edit) => {
3193 if !edits.contains(&edit.text_edit) {
3194 edits.push(edit.text_edit)
3195 }
3196 }
3197 Edit::Snippet(edit) => {
3198 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3199 else {
3200 continue;
3201 };
3202
3203 if is_active_entry {
3204 snippet_edits.push((edit.range, snippet));
3205 } else {
3206 // Since this buffer is not focused, apply a normal edit.
3207 let new_edit = TextEdit {
3208 range: edit.range,
3209 new_text: snippet.text,
3210 };
3211 if !edits.contains(&new_edit) {
3212 edits.push(new_edit);
3213 }
3214 }
3215 }
3216 }
3217 }
3218 if !snippet_edits.is_empty() {
3219 let buffer_id = buffer_to_edit.read(cx).remote_id();
3220 let version = if let Some(buffer_version) = op.text_document.version
3221 {
3222 local
3223 .buffer_snapshot_for_lsp_version(
3224 &buffer_to_edit,
3225 language_server.server_id(),
3226 Some(buffer_version),
3227 cx,
3228 )
3229 .ok()
3230 .map(|snapshot| snapshot.version)
3231 } else {
3232 Some(buffer_to_edit.read(cx).saved_version().clone())
3233 };
3234
3235 let most_recent_edit =
3236 version.and_then(|version| version.most_recent());
3237 // Check if the edit that triggered that edit has been made by this participant.
3238
3239 if let Some(most_recent_edit) = most_recent_edit {
3240 cx.emit(LspStoreEvent::SnippetEdit {
3241 buffer_id,
3242 edits: snippet_edits,
3243 most_recent_edit,
3244 });
3245 }
3246 }
3247
3248 local.edits_from_lsp(
3249 &buffer_to_edit,
3250 edits,
3251 language_server.server_id(),
3252 op.text_document.version,
3253 cx,
3254 )
3255 })?
3256 .await?;
3257
3258 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3259 buffer.finalize_last_transaction();
3260 buffer.start_transaction();
3261 for (range, text) in edits {
3262 buffer.edit([(range, text)], None, cx);
3263 }
3264
3265 buffer.end_transaction(cx).and_then(|transaction_id| {
3266 if push_to_history {
3267 buffer.finalize_last_transaction();
3268 buffer.get_transaction(transaction_id).cloned()
3269 } else {
3270 buffer.forget_transaction(transaction_id)
3271 }
3272 })
3273 })?;
3274 if let Some(transaction) = transaction {
3275 project_transaction.0.insert(buffer_to_edit, transaction);
3276 }
3277 }
3278 }
3279 }
3280
3281 Ok(project_transaction)
3282 }
3283
3284 async fn on_lsp_workspace_edit(
3285 this: WeakEntity<LspStore>,
3286 params: lsp::ApplyWorkspaceEditParams,
3287 server_id: LanguageServerId,
3288 cx: &mut AsyncApp,
3289 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3290 let this = this.upgrade().context("project project closed")?;
3291 let language_server = this
3292 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3293 .context("language server not found")?;
3294 let transaction = Self::deserialize_workspace_edit(
3295 this.clone(),
3296 params.edit,
3297 true,
3298 language_server.clone(),
3299 cx,
3300 )
3301 .await
3302 .log_err();
3303 this.update(cx, |this, _| {
3304 if let Some(transaction) = transaction {
3305 this.as_local_mut()
3306 .unwrap()
3307 .last_workspace_edits_by_language_server
3308 .insert(server_id, transaction);
3309 }
3310 })?;
3311 Ok(lsp::ApplyWorkspaceEditResponse {
3312 applied: true,
3313 failed_change: None,
3314 failure_reason: None,
3315 })
3316 }
3317
3318 fn remove_worktree(
3319 &mut self,
3320 id_to_remove: WorktreeId,
3321 cx: &mut Context<LspStore>,
3322 ) -> Vec<LanguageServerId> {
3323 self.restricted_worktrees_tasks.remove(&id_to_remove);
3324 self.diagnostics.remove(&id_to_remove);
3325 self.prettier_store.update(cx, |prettier_store, cx| {
3326 prettier_store.remove_worktree(id_to_remove, cx);
3327 });
3328
3329 let mut servers_to_remove = BTreeSet::default();
3330 let mut servers_to_preserve = HashSet::default();
3331 for (seed, state) in &self.language_server_ids {
3332 if seed.worktree_id == id_to_remove {
3333 servers_to_remove.insert(state.id);
3334 } else {
3335 servers_to_preserve.insert(state.id);
3336 }
3337 }
3338 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3339 self.language_server_ids
3340 .retain(|_, state| !servers_to_remove.contains(&state.id));
3341 for server_id_to_remove in &servers_to_remove {
3342 self.language_server_watched_paths
3343 .remove(server_id_to_remove);
3344 self.language_server_paths_watched_for_rename
3345 .remove(server_id_to_remove);
3346 self.last_workspace_edits_by_language_server
3347 .remove(server_id_to_remove);
3348 self.language_servers.remove(server_id_to_remove);
3349 self.buffer_pull_diagnostics_result_ids
3350 .remove(server_id_to_remove);
3351 self.workspace_pull_diagnostics_result_ids
3352 .remove(server_id_to_remove);
3353 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3354 buffer_servers.remove(server_id_to_remove);
3355 }
3356 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3357 }
3358 servers_to_remove.into_iter().collect()
3359 }
3360
3361 fn rebuild_watched_paths_inner<'a>(
3362 &'a self,
3363 language_server_id: LanguageServerId,
3364 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3365 cx: &mut Context<LspStore>,
3366 ) -> LanguageServerWatchedPathsBuilder {
3367 let worktrees = self
3368 .worktree_store
3369 .read(cx)
3370 .worktrees()
3371 .filter_map(|worktree| {
3372 self.language_servers_for_worktree(worktree.read(cx).id())
3373 .find(|server| server.server_id() == language_server_id)
3374 .map(|_| worktree)
3375 })
3376 .collect::<Vec<_>>();
3377
3378 let mut worktree_globs = HashMap::default();
3379 let mut abs_globs = HashMap::default();
3380 log::trace!(
3381 "Processing new watcher paths for language server with id {}",
3382 language_server_id
3383 );
3384
3385 for watcher in watchers {
3386 if let Some((worktree, literal_prefix, pattern)) =
3387 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3388 {
3389 worktree.update(cx, |worktree, _| {
3390 if let Some((tree, glob)) =
3391 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3392 {
3393 tree.add_path_prefix_to_scan(literal_prefix);
3394 worktree_globs
3395 .entry(tree.id())
3396 .or_insert_with(GlobSetBuilder::new)
3397 .add(glob);
3398 }
3399 });
3400 } else {
3401 let (path, pattern) = match &watcher.glob_pattern {
3402 lsp::GlobPattern::String(s) => {
3403 let watcher_path = SanitizedPath::new(s);
3404 let path = glob_literal_prefix(watcher_path.as_path());
3405 let pattern = watcher_path
3406 .as_path()
3407 .strip_prefix(&path)
3408 .map(|p| p.to_string_lossy().into_owned())
3409 .unwrap_or_else(|e| {
3410 debug_panic!(
3411 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3412 s,
3413 path.display(),
3414 e
3415 );
3416 watcher_path.as_path().to_string_lossy().into_owned()
3417 });
3418 (path, pattern)
3419 }
3420 lsp::GlobPattern::Relative(rp) => {
3421 let Ok(mut base_uri) = match &rp.base_uri {
3422 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3423 lsp::OneOf::Right(base_uri) => base_uri,
3424 }
3425 .to_file_path() else {
3426 continue;
3427 };
3428
3429 let path = glob_literal_prefix(Path::new(&rp.pattern));
3430 let pattern = Path::new(&rp.pattern)
3431 .strip_prefix(&path)
3432 .map(|p| p.to_string_lossy().into_owned())
3433 .unwrap_or_else(|e| {
3434 debug_panic!(
3435 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3436 rp.pattern,
3437 path.display(),
3438 e
3439 );
3440 rp.pattern.clone()
3441 });
3442 base_uri.push(path);
3443 (base_uri, pattern)
3444 }
3445 };
3446
3447 if let Some(glob) = Glob::new(&pattern).log_err() {
3448 if !path
3449 .components()
3450 .any(|c| matches!(c, path::Component::Normal(_)))
3451 {
3452 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3453 // rather than adding a new watcher for `/`.
3454 for worktree in &worktrees {
3455 worktree_globs
3456 .entry(worktree.read(cx).id())
3457 .or_insert_with(GlobSetBuilder::new)
3458 .add(glob.clone());
3459 }
3460 } else {
3461 abs_globs
3462 .entry(path.into())
3463 .or_insert_with(GlobSetBuilder::new)
3464 .add(glob);
3465 }
3466 }
3467 }
3468 }
3469
3470 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3471 for (worktree_id, builder) in worktree_globs {
3472 if let Ok(globset) = builder.build() {
3473 watch_builder.watch_worktree(worktree_id, globset);
3474 }
3475 }
3476 for (abs_path, builder) in abs_globs {
3477 if let Ok(globset) = builder.build() {
3478 watch_builder.watch_abs_path(abs_path, globset);
3479 }
3480 }
3481 watch_builder
3482 }
3483
3484 fn worktree_and_path_for_file_watcher(
3485 worktrees: &[Entity<Worktree>],
3486 watcher: &FileSystemWatcher,
3487 cx: &App,
3488 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3489 worktrees.iter().find_map(|worktree| {
3490 let tree = worktree.read(cx);
3491 let worktree_root_path = tree.abs_path();
3492 let path_style = tree.path_style();
3493 match &watcher.glob_pattern {
3494 lsp::GlobPattern::String(s) => {
3495 let watcher_path = SanitizedPath::new(s);
3496 let relative = watcher_path
3497 .as_path()
3498 .strip_prefix(&worktree_root_path)
3499 .ok()?;
3500 let literal_prefix = glob_literal_prefix(relative);
3501 Some((
3502 worktree.clone(),
3503 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3504 relative.to_string_lossy().into_owned(),
3505 ))
3506 }
3507 lsp::GlobPattern::Relative(rp) => {
3508 let base_uri = match &rp.base_uri {
3509 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3510 lsp::OneOf::Right(base_uri) => base_uri,
3511 }
3512 .to_file_path()
3513 .ok()?;
3514 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3515 let mut literal_prefix = relative.to_owned();
3516 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3517 Some((
3518 worktree.clone(),
3519 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3520 rp.pattern.clone(),
3521 ))
3522 }
3523 }
3524 })
3525 }
3526
3527 fn rebuild_watched_paths(
3528 &mut self,
3529 language_server_id: LanguageServerId,
3530 cx: &mut Context<LspStore>,
3531 ) {
3532 let Some(registrations) = self
3533 .language_server_dynamic_registrations
3534 .get(&language_server_id)
3535 else {
3536 return;
3537 };
3538
3539 let watch_builder = self.rebuild_watched_paths_inner(
3540 language_server_id,
3541 registrations.did_change_watched_files.values().flatten(),
3542 cx,
3543 );
3544 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3545 self.language_server_watched_paths
3546 .insert(language_server_id, watcher);
3547
3548 cx.notify();
3549 }
3550
3551 fn on_lsp_did_change_watched_files(
3552 &mut self,
3553 language_server_id: LanguageServerId,
3554 registration_id: &str,
3555 params: DidChangeWatchedFilesRegistrationOptions,
3556 cx: &mut Context<LspStore>,
3557 ) {
3558 let registrations = self
3559 .language_server_dynamic_registrations
3560 .entry(language_server_id)
3561 .or_default();
3562
3563 registrations
3564 .did_change_watched_files
3565 .insert(registration_id.to_string(), params.watchers);
3566
3567 self.rebuild_watched_paths(language_server_id, cx);
3568 }
3569
3570 fn on_lsp_unregister_did_change_watched_files(
3571 &mut self,
3572 language_server_id: LanguageServerId,
3573 registration_id: &str,
3574 cx: &mut Context<LspStore>,
3575 ) {
3576 let registrations = self
3577 .language_server_dynamic_registrations
3578 .entry(language_server_id)
3579 .or_default();
3580
3581 if registrations
3582 .did_change_watched_files
3583 .remove(registration_id)
3584 .is_some()
3585 {
3586 log::info!(
3587 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3588 language_server_id,
3589 registration_id
3590 );
3591 } else {
3592 log::warn!(
3593 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3594 language_server_id,
3595 registration_id
3596 );
3597 }
3598
3599 self.rebuild_watched_paths(language_server_id, cx);
3600 }
3601
3602 async fn initialization_options_for_adapter(
3603 adapter: Arc<dyn LspAdapter>,
3604 delegate: &Arc<dyn LspAdapterDelegate>,
3605 ) -> Result<Option<serde_json::Value>> {
3606 let Some(mut initialization_config) =
3607 adapter.clone().initialization_options(delegate).await?
3608 else {
3609 return Ok(None);
3610 };
3611
3612 for other_adapter in delegate.registered_lsp_adapters() {
3613 if other_adapter.name() == adapter.name() {
3614 continue;
3615 }
3616 if let Ok(Some(target_config)) = other_adapter
3617 .clone()
3618 .additional_initialization_options(adapter.name(), delegate)
3619 .await
3620 {
3621 merge_json_value_into(target_config.clone(), &mut initialization_config);
3622 }
3623 }
3624
3625 Ok(Some(initialization_config))
3626 }
3627
3628 async fn workspace_configuration_for_adapter(
3629 adapter: Arc<dyn LspAdapter>,
3630 delegate: &Arc<dyn LspAdapterDelegate>,
3631 toolchain: Option<Toolchain>,
3632 requested_uri: Option<Uri>,
3633 cx: &mut AsyncApp,
3634 ) -> Result<serde_json::Value> {
3635 let mut workspace_config = adapter
3636 .clone()
3637 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3638 .await?;
3639
3640 for other_adapter in delegate.registered_lsp_adapters() {
3641 if other_adapter.name() == adapter.name() {
3642 continue;
3643 }
3644 if let Ok(Some(target_config)) = other_adapter
3645 .clone()
3646 .additional_workspace_configuration(adapter.name(), delegate, cx)
3647 .await
3648 {
3649 merge_json_value_into(target_config.clone(), &mut workspace_config);
3650 }
3651 }
3652
3653 Ok(workspace_config)
3654 }
3655
3656 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3657 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3658 Some(server.clone())
3659 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3660 Some(Arc::clone(server))
3661 } else {
3662 None
3663 }
3664 }
3665}
3666
3667fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3668 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3669 cx.emit(LspStoreEvent::LanguageServerUpdate {
3670 language_server_id: server.server_id(),
3671 name: Some(server.name()),
3672 message: proto::update_language_server::Variant::MetadataUpdated(
3673 proto::ServerMetadataUpdated {
3674 capabilities: Some(capabilities),
3675 binary: Some(proto::LanguageServerBinaryInfo {
3676 path: server.binary().path.to_string_lossy().into_owned(),
3677 arguments: server
3678 .binary()
3679 .arguments
3680 .iter()
3681 .map(|arg| arg.to_string_lossy().into_owned())
3682 .collect(),
3683 }),
3684 configuration: serde_json::to_string(server.configuration()).ok(),
3685 workspace_folders: server
3686 .workspace_folders()
3687 .iter()
3688 .map(|uri| uri.to_string())
3689 .collect(),
3690 },
3691 ),
3692 });
3693 }
3694}
3695
3696#[derive(Debug)]
3697pub struct FormattableBuffer {
3698 handle: Entity<Buffer>,
3699 abs_path: Option<PathBuf>,
3700 env: Option<HashMap<String, String>>,
3701 ranges: Option<Vec<Range<Anchor>>>,
3702}
3703
3704pub struct RemoteLspStore {
3705 upstream_client: Option<AnyProtoClient>,
3706 upstream_project_id: u64,
3707}
3708
3709pub(crate) enum LspStoreMode {
3710 Local(LocalLspStore), // ssh host and collab host
3711 Remote(RemoteLspStore), // collab guest
3712}
3713
3714impl LspStoreMode {
3715 fn is_local(&self) -> bool {
3716 matches!(self, LspStoreMode::Local(_))
3717 }
3718}
3719
3720pub struct LspStore {
3721 mode: LspStoreMode,
3722 last_formatting_failure: Option<String>,
3723 downstream_client: Option<(AnyProtoClient, u64)>,
3724 nonce: u128,
3725 buffer_store: Entity<BufferStore>,
3726 worktree_store: Entity<WorktreeStore>,
3727 pub languages: Arc<LanguageRegistry>,
3728 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3729 active_entry: Option<ProjectEntryId>,
3730 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3731 _maintain_buffer_languages: Task<()>,
3732 diagnostic_summaries:
3733 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3734 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3735 lsp_data: HashMap<BufferId, BufferLspData>,
3736 next_hint_id: Arc<AtomicUsize>,
3737}
3738
3739#[derive(Debug)]
3740pub struct BufferLspData {
3741 buffer_version: Global,
3742 document_colors: Option<DocumentColorData>,
3743 code_lens: Option<CodeLensData>,
3744 inlay_hints: BufferInlayHints,
3745 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3746 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3747}
3748
3749#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3750struct LspKey {
3751 request_type: TypeId,
3752 server_queried: Option<LanguageServerId>,
3753}
3754
3755impl BufferLspData {
3756 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3757 Self {
3758 buffer_version: buffer.read(cx).version(),
3759 document_colors: None,
3760 code_lens: None,
3761 inlay_hints: BufferInlayHints::new(buffer, cx),
3762 lsp_requests: HashMap::default(),
3763 chunk_lsp_requests: HashMap::default(),
3764 }
3765 }
3766
3767 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3768 if let Some(document_colors) = &mut self.document_colors {
3769 document_colors.colors.remove(&for_server);
3770 document_colors.cache_version += 1;
3771 }
3772
3773 if let Some(code_lens) = &mut self.code_lens {
3774 code_lens.lens.remove(&for_server);
3775 }
3776
3777 self.inlay_hints.remove_server_data(for_server);
3778 }
3779
3780 #[cfg(any(test, feature = "test-support"))]
3781 pub fn inlay_hints(&self) -> &BufferInlayHints {
3782 &self.inlay_hints
3783 }
3784}
3785
3786#[derive(Debug, Default, Clone)]
3787pub struct DocumentColors {
3788 pub colors: HashSet<DocumentColor>,
3789 pub cache_version: Option<usize>,
3790}
3791
3792type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3793type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3794
3795#[derive(Debug, Default)]
3796struct DocumentColorData {
3797 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3798 cache_version: usize,
3799 colors_update: Option<(Global, DocumentColorTask)>,
3800}
3801
3802#[derive(Debug, Default)]
3803struct CodeLensData {
3804 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3805 update: Option<(Global, CodeLensTask)>,
3806}
3807
3808#[derive(Debug)]
3809pub enum LspStoreEvent {
3810 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3811 LanguageServerRemoved(LanguageServerId),
3812 LanguageServerUpdate {
3813 language_server_id: LanguageServerId,
3814 name: Option<LanguageServerName>,
3815 message: proto::update_language_server::Variant,
3816 },
3817 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3818 LanguageServerPrompt(LanguageServerPromptRequest),
3819 LanguageDetected {
3820 buffer: Entity<Buffer>,
3821 new_language: Option<Arc<Language>>,
3822 },
3823 Notification(String),
3824 RefreshInlayHints {
3825 server_id: LanguageServerId,
3826 request_id: Option<usize>,
3827 },
3828 RefreshCodeLens,
3829 DiagnosticsUpdated {
3830 server_id: LanguageServerId,
3831 paths: Vec<ProjectPath>,
3832 },
3833 DiskBasedDiagnosticsStarted {
3834 language_server_id: LanguageServerId,
3835 },
3836 DiskBasedDiagnosticsFinished {
3837 language_server_id: LanguageServerId,
3838 },
3839 SnippetEdit {
3840 buffer_id: BufferId,
3841 edits: Vec<(lsp::Range, Snippet)>,
3842 most_recent_edit: clock::Lamport,
3843 },
3844}
3845
3846#[derive(Clone, Debug, Serialize)]
3847pub struct LanguageServerStatus {
3848 pub name: LanguageServerName,
3849 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3850 pub has_pending_diagnostic_updates: bool,
3851 pub progress_tokens: HashSet<ProgressToken>,
3852 pub worktree: Option<WorktreeId>,
3853 pub binary: Option<LanguageServerBinary>,
3854 pub configuration: Option<Value>,
3855 pub workspace_folders: BTreeSet<Uri>,
3856}
3857
3858#[derive(Clone, Debug)]
3859struct CoreSymbol {
3860 pub language_server_name: LanguageServerName,
3861 pub source_worktree_id: WorktreeId,
3862 pub source_language_server_id: LanguageServerId,
3863 pub path: SymbolLocation,
3864 pub name: String,
3865 pub kind: lsp::SymbolKind,
3866 pub range: Range<Unclipped<PointUtf16>>,
3867}
3868
3869#[derive(Clone, Debug, PartialEq, Eq)]
3870pub enum SymbolLocation {
3871 InProject(ProjectPath),
3872 OutsideProject {
3873 abs_path: Arc<Path>,
3874 signature: [u8; 32],
3875 },
3876}
3877
3878impl SymbolLocation {
3879 fn file_name(&self) -> Option<&str> {
3880 match self {
3881 Self::InProject(path) => path.path.file_name(),
3882 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3883 }
3884 }
3885}
3886
3887impl LspStore {
3888 pub fn init(client: &AnyProtoClient) {
3889 client.add_entity_request_handler(Self::handle_lsp_query);
3890 client.add_entity_message_handler(Self::handle_lsp_query_response);
3891 client.add_entity_request_handler(Self::handle_restart_language_servers);
3892 client.add_entity_request_handler(Self::handle_stop_language_servers);
3893 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3894 client.add_entity_message_handler(Self::handle_start_language_server);
3895 client.add_entity_message_handler(Self::handle_update_language_server);
3896 client.add_entity_message_handler(Self::handle_language_server_log);
3897 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3898 client.add_entity_request_handler(Self::handle_format_buffers);
3899 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3900 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3901 client.add_entity_request_handler(Self::handle_apply_code_action);
3902 client.add_entity_request_handler(Self::handle_get_project_symbols);
3903 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3904 client.add_entity_request_handler(Self::handle_get_color_presentation);
3905 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3906 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3907 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3908 client.add_entity_request_handler(Self::handle_on_type_formatting);
3909 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3910 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3911 client.add_entity_request_handler(Self::handle_rename_project_entry);
3912 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3913 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3914 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3915 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3916 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3917 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3918 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3919
3920 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3921 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3922 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3923 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3924 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3925 client.add_entity_request_handler(
3926 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3927 );
3928 client.add_entity_request_handler(
3929 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3930 );
3931 client.add_entity_request_handler(
3932 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3933 );
3934 }
3935
3936 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3937 match &self.mode {
3938 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3939 _ => None,
3940 }
3941 }
3942
3943 pub fn as_local(&self) -> Option<&LocalLspStore> {
3944 match &self.mode {
3945 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3946 _ => None,
3947 }
3948 }
3949
3950 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3951 match &mut self.mode {
3952 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3953 _ => None,
3954 }
3955 }
3956
3957 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3958 match &self.mode {
3959 LspStoreMode::Remote(RemoteLspStore {
3960 upstream_client: Some(upstream_client),
3961 upstream_project_id,
3962 ..
3963 }) => Some((upstream_client.clone(), *upstream_project_id)),
3964
3965 LspStoreMode::Remote(RemoteLspStore {
3966 upstream_client: None,
3967 ..
3968 }) => None,
3969 LspStoreMode::Local(_) => None,
3970 }
3971 }
3972
3973 pub fn new_local(
3974 buffer_store: Entity<BufferStore>,
3975 worktree_store: Entity<WorktreeStore>,
3976 prettier_store: Entity<PrettierStore>,
3977 toolchain_store: Entity<LocalToolchainStore>,
3978 environment: Entity<ProjectEnvironment>,
3979 manifest_tree: Entity<ManifestTree>,
3980 languages: Arc<LanguageRegistry>,
3981 http_client: Arc<dyn HttpClient>,
3982 fs: Arc<dyn Fs>,
3983 cx: &mut Context<Self>,
3984 ) -> Self {
3985 let yarn = YarnPathStore::new(fs.clone(), cx);
3986 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
3987 .detach();
3988 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
3989 .detach();
3990 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
3991 .detach();
3992 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
3993 .detach();
3994 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
3995 .detach();
3996 subscribe_to_binary_statuses(&languages, cx).detach();
3997
3998 let _maintain_workspace_config = {
3999 let (sender, receiver) = watch::channel();
4000 (Self::maintain_workspace_config(receiver, cx), sender)
4001 };
4002
4003 Self {
4004 mode: LspStoreMode::Local(LocalLspStore {
4005 weak: cx.weak_entity(),
4006 worktree_store: worktree_store.clone(),
4007
4008 supplementary_language_servers: Default::default(),
4009 languages: languages.clone(),
4010 language_server_ids: Default::default(),
4011 language_servers: Default::default(),
4012 last_workspace_edits_by_language_server: Default::default(),
4013 language_server_watched_paths: Default::default(),
4014 language_server_paths_watched_for_rename: Default::default(),
4015 language_server_dynamic_registrations: Default::default(),
4016 buffers_being_formatted: Default::default(),
4017 buffer_snapshots: Default::default(),
4018 prettier_store,
4019 environment,
4020 http_client,
4021 fs,
4022 yarn,
4023 next_diagnostic_group_id: Default::default(),
4024 diagnostics: Default::default(),
4025 _subscription: cx.on_app_quit(|this, cx| {
4026 this.as_local_mut()
4027 .unwrap()
4028 .shutdown_language_servers_on_quit(cx)
4029 }),
4030 lsp_tree: LanguageServerTree::new(
4031 manifest_tree,
4032 languages.clone(),
4033 toolchain_store.clone(),
4034 ),
4035 toolchain_store,
4036 registered_buffers: HashMap::default(),
4037 buffers_opened_in_servers: HashMap::default(),
4038 buffer_pull_diagnostics_result_ids: HashMap::default(),
4039 workspace_pull_diagnostics_result_ids: HashMap::default(),
4040 restricted_worktrees_tasks: HashMap::default(),
4041 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4042 .manifest_file_names(),
4043 }),
4044 last_formatting_failure: None,
4045 downstream_client: None,
4046 buffer_store,
4047 worktree_store,
4048 languages: languages.clone(),
4049 language_server_statuses: Default::default(),
4050 nonce: StdRng::from_os_rng().random(),
4051 diagnostic_summaries: HashMap::default(),
4052 lsp_server_capabilities: HashMap::default(),
4053 lsp_data: HashMap::default(),
4054 next_hint_id: Arc::default(),
4055 active_entry: None,
4056 _maintain_workspace_config,
4057 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4058 }
4059 }
4060
4061 fn send_lsp_proto_request<R: LspCommand>(
4062 &self,
4063 buffer: Entity<Buffer>,
4064 client: AnyProtoClient,
4065 upstream_project_id: u64,
4066 request: R,
4067 cx: &mut Context<LspStore>,
4068 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4069 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4070 return Task::ready(Ok(R::Response::default()));
4071 }
4072 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4073 cx.spawn(async move |this, cx| {
4074 let response = client.request(message).await?;
4075 let this = this.upgrade().context("project dropped")?;
4076 request
4077 .response_from_proto(response, this, buffer, cx.clone())
4078 .await
4079 })
4080 }
4081
4082 pub(super) fn new_remote(
4083 buffer_store: Entity<BufferStore>,
4084 worktree_store: Entity<WorktreeStore>,
4085 languages: Arc<LanguageRegistry>,
4086 upstream_client: AnyProtoClient,
4087 project_id: u64,
4088 cx: &mut Context<Self>,
4089 ) -> Self {
4090 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4091 .detach();
4092 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4093 .detach();
4094 subscribe_to_binary_statuses(&languages, cx).detach();
4095 let _maintain_workspace_config = {
4096 let (sender, receiver) = watch::channel();
4097 (Self::maintain_workspace_config(receiver, cx), sender)
4098 };
4099 Self {
4100 mode: LspStoreMode::Remote(RemoteLspStore {
4101 upstream_client: Some(upstream_client),
4102 upstream_project_id: project_id,
4103 }),
4104 downstream_client: None,
4105 last_formatting_failure: None,
4106 buffer_store,
4107 worktree_store,
4108 languages: languages.clone(),
4109 language_server_statuses: Default::default(),
4110 nonce: StdRng::from_os_rng().random(),
4111 diagnostic_summaries: HashMap::default(),
4112 lsp_server_capabilities: HashMap::default(),
4113 next_hint_id: Arc::default(),
4114 lsp_data: HashMap::default(),
4115 active_entry: None,
4116
4117 _maintain_workspace_config,
4118 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4119 }
4120 }
4121
4122 fn on_buffer_store_event(
4123 &mut self,
4124 _: Entity<BufferStore>,
4125 event: &BufferStoreEvent,
4126 cx: &mut Context<Self>,
4127 ) {
4128 match event {
4129 BufferStoreEvent::BufferAdded(buffer) => {
4130 self.on_buffer_added(buffer, cx).log_err();
4131 }
4132 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4133 let buffer_id = buffer.read(cx).remote_id();
4134 if let Some(local) = self.as_local_mut()
4135 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4136 {
4137 local.reset_buffer(buffer, old_file, cx);
4138
4139 if local.registered_buffers.contains_key(&buffer_id) {
4140 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4141 }
4142 }
4143
4144 self.detect_language_for_buffer(buffer, cx);
4145 if let Some(local) = self.as_local_mut() {
4146 local.initialize_buffer(buffer, cx);
4147 if local.registered_buffers.contains_key(&buffer_id) {
4148 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4149 }
4150 }
4151 }
4152 _ => {}
4153 }
4154 }
4155
4156 fn on_worktree_store_event(
4157 &mut self,
4158 _: Entity<WorktreeStore>,
4159 event: &WorktreeStoreEvent,
4160 cx: &mut Context<Self>,
4161 ) {
4162 match event {
4163 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4164 if !worktree.read(cx).is_local() {
4165 return;
4166 }
4167 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4168 worktree::Event::UpdatedEntries(changes) => {
4169 this.update_local_worktree_language_servers(&worktree, changes, cx);
4170 }
4171 worktree::Event::UpdatedGitRepositories(_)
4172 | worktree::Event::DeletedEntry(_) => {}
4173 })
4174 .detach()
4175 }
4176 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4177 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4178 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4179 }
4180 WorktreeStoreEvent::WorktreeReleased(..)
4181 | WorktreeStoreEvent::WorktreeOrderChanged
4182 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4183 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4184 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4185 }
4186 }
4187
4188 fn on_prettier_store_event(
4189 &mut self,
4190 _: Entity<PrettierStore>,
4191 event: &PrettierStoreEvent,
4192 cx: &mut Context<Self>,
4193 ) {
4194 match event {
4195 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4196 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4197 }
4198 PrettierStoreEvent::LanguageServerAdded {
4199 new_server_id,
4200 name,
4201 prettier_server,
4202 } => {
4203 self.register_supplementary_language_server(
4204 *new_server_id,
4205 name.clone(),
4206 prettier_server.clone(),
4207 cx,
4208 );
4209 }
4210 }
4211 }
4212
4213 fn on_toolchain_store_event(
4214 &mut self,
4215 _: Entity<LocalToolchainStore>,
4216 event: &ToolchainStoreEvent,
4217 _: &mut Context<Self>,
4218 ) {
4219 if let ToolchainStoreEvent::ToolchainActivated = event {
4220 self.request_workspace_config_refresh()
4221 }
4222 }
4223
4224 fn request_workspace_config_refresh(&mut self) {
4225 *self._maintain_workspace_config.1.borrow_mut() = ();
4226 }
4227
4228 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4229 self.as_local().map(|local| local.prettier_store.clone())
4230 }
4231
4232 fn on_buffer_event(
4233 &mut self,
4234 buffer: Entity<Buffer>,
4235 event: &language::BufferEvent,
4236 cx: &mut Context<Self>,
4237 ) {
4238 match event {
4239 language::BufferEvent::Edited => {
4240 self.on_buffer_edited(buffer, cx);
4241 }
4242
4243 language::BufferEvent::Saved => {
4244 self.on_buffer_saved(buffer, cx);
4245 }
4246
4247 _ => {}
4248 }
4249 }
4250
4251 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4252 buffer
4253 .read(cx)
4254 .set_language_registry(self.languages.clone());
4255
4256 cx.subscribe(buffer, |this, buffer, event, cx| {
4257 this.on_buffer_event(buffer, event, cx);
4258 })
4259 .detach();
4260
4261 self.detect_language_for_buffer(buffer, cx);
4262 if let Some(local) = self.as_local_mut() {
4263 local.initialize_buffer(buffer, cx);
4264 }
4265
4266 Ok(())
4267 }
4268
4269 pub(crate) fn register_buffer_with_language_servers(
4270 &mut self,
4271 buffer: &Entity<Buffer>,
4272 only_register_servers: HashSet<LanguageServerSelector>,
4273 ignore_refcounts: bool,
4274 cx: &mut Context<Self>,
4275 ) -> OpenLspBufferHandle {
4276 let buffer_id = buffer.read(cx).remote_id();
4277 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4278 if let Some(local) = self.as_local_mut() {
4279 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4280 if !ignore_refcounts {
4281 *refcount += 1;
4282 }
4283
4284 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4285 // 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
4286 // 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
4287 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4288 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4289 return handle;
4290 };
4291 if !file.is_local() {
4292 return handle;
4293 }
4294
4295 if ignore_refcounts || *refcount == 1 {
4296 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4297 }
4298 if !ignore_refcounts {
4299 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4300 let refcount = {
4301 let local = lsp_store.as_local_mut().unwrap();
4302 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4303 debug_panic!("bad refcounting");
4304 return;
4305 };
4306
4307 *refcount -= 1;
4308 *refcount
4309 };
4310 if refcount == 0 {
4311 lsp_store.lsp_data.remove(&buffer_id);
4312 let local = lsp_store.as_local_mut().unwrap();
4313 local.registered_buffers.remove(&buffer_id);
4314
4315 local.buffers_opened_in_servers.remove(&buffer_id);
4316 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4317 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4318
4319 let buffer_abs_path = file.abs_path(cx);
4320 for (_, buffer_pull_diagnostics_result_ids) in
4321 &mut local.buffer_pull_diagnostics_result_ids
4322 {
4323 buffer_pull_diagnostics_result_ids.retain(
4324 |_, buffer_result_ids| {
4325 buffer_result_ids.remove(&buffer_abs_path);
4326 !buffer_result_ids.is_empty()
4327 },
4328 );
4329 }
4330
4331 let diagnostic_updates = local
4332 .language_servers
4333 .keys()
4334 .cloned()
4335 .map(|server_id| DocumentDiagnosticsUpdate {
4336 diagnostics: DocumentDiagnostics {
4337 document_abs_path: buffer_abs_path.clone(),
4338 version: None,
4339 diagnostics: Vec::new(),
4340 },
4341 result_id: None,
4342 registration_id: None,
4343 server_id: server_id,
4344 disk_based_sources: Cow::Borrowed(&[]),
4345 })
4346 .collect::<Vec<_>>();
4347
4348 lsp_store
4349 .merge_diagnostic_entries(
4350 diagnostic_updates,
4351 |_, diagnostic, _| {
4352 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4353 },
4354 cx,
4355 )
4356 .context("Clearing diagnostics for the closed buffer")
4357 .log_err();
4358 }
4359 }
4360 })
4361 .detach();
4362 }
4363 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4364 let buffer_id = buffer.read(cx).remote_id().to_proto();
4365 cx.background_spawn(async move {
4366 upstream_client
4367 .request(proto::RegisterBufferWithLanguageServers {
4368 project_id: upstream_project_id,
4369 buffer_id,
4370 only_servers: only_register_servers
4371 .into_iter()
4372 .map(|selector| {
4373 let selector = match selector {
4374 LanguageServerSelector::Id(language_server_id) => {
4375 proto::language_server_selector::Selector::ServerId(
4376 language_server_id.to_proto(),
4377 )
4378 }
4379 LanguageServerSelector::Name(language_server_name) => {
4380 proto::language_server_selector::Selector::Name(
4381 language_server_name.to_string(),
4382 )
4383 }
4384 };
4385 proto::LanguageServerSelector {
4386 selector: Some(selector),
4387 }
4388 })
4389 .collect(),
4390 })
4391 .await
4392 })
4393 .detach();
4394 } else {
4395 // Our remote connection got closed
4396 }
4397 handle
4398 }
4399
4400 fn maintain_buffer_languages(
4401 languages: Arc<LanguageRegistry>,
4402 cx: &mut Context<Self>,
4403 ) -> Task<()> {
4404 let mut subscription = languages.subscribe();
4405 let mut prev_reload_count = languages.reload_count();
4406 cx.spawn(async move |this, cx| {
4407 while let Some(()) = subscription.next().await {
4408 if let Some(this) = this.upgrade() {
4409 // If the language registry has been reloaded, then remove and
4410 // re-assign the languages on all open buffers.
4411 let reload_count = languages.reload_count();
4412 if reload_count > prev_reload_count {
4413 prev_reload_count = reload_count;
4414 this.update(cx, |this, cx| {
4415 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4416 for buffer in buffer_store.buffers() {
4417 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4418 {
4419 buffer.update(cx, |buffer, cx| {
4420 buffer.set_language_async(None, cx)
4421 });
4422 if let Some(local) = this.as_local_mut() {
4423 local.reset_buffer(&buffer, &f, cx);
4424
4425 if local
4426 .registered_buffers
4427 .contains_key(&buffer.read(cx).remote_id())
4428 && let Some(file_url) =
4429 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4430 {
4431 local.unregister_buffer_from_language_servers(
4432 &buffer, &file_url, cx,
4433 );
4434 }
4435 }
4436 }
4437 }
4438 });
4439 })
4440 .ok();
4441 }
4442
4443 this.update(cx, |this, cx| {
4444 let mut plain_text_buffers = Vec::new();
4445 let mut buffers_with_unknown_injections = Vec::new();
4446 for handle in this.buffer_store.read(cx).buffers() {
4447 let buffer = handle.read(cx);
4448 if buffer.language().is_none()
4449 || buffer.language() == Some(&*language::PLAIN_TEXT)
4450 {
4451 plain_text_buffers.push(handle);
4452 } else if buffer.contains_unknown_injections() {
4453 buffers_with_unknown_injections.push(handle);
4454 }
4455 }
4456
4457 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4458 // and reused later in the invisible worktrees.
4459 plain_text_buffers.sort_by_key(|buffer| {
4460 Reverse(
4461 File::from_dyn(buffer.read(cx).file())
4462 .map(|file| file.worktree.read(cx).is_visible()),
4463 )
4464 });
4465
4466 for buffer in plain_text_buffers {
4467 this.detect_language_for_buffer(&buffer, cx);
4468 if let Some(local) = this.as_local_mut() {
4469 local.initialize_buffer(&buffer, cx);
4470 if local
4471 .registered_buffers
4472 .contains_key(&buffer.read(cx).remote_id())
4473 {
4474 local.register_buffer_with_language_servers(
4475 &buffer,
4476 HashSet::default(),
4477 cx,
4478 );
4479 }
4480 }
4481 }
4482
4483 for buffer in buffers_with_unknown_injections {
4484 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4485 }
4486 })
4487 .ok();
4488 }
4489 }
4490 })
4491 }
4492
4493 fn detect_language_for_buffer(
4494 &mut self,
4495 buffer_handle: &Entity<Buffer>,
4496 cx: &mut Context<Self>,
4497 ) -> Option<language::AvailableLanguage> {
4498 // If the buffer has a language, set it and start the language server if we haven't already.
4499 let buffer = buffer_handle.read(cx);
4500 let file = buffer.file()?;
4501
4502 let content = buffer.as_rope();
4503 let available_language = self.languages.language_for_file(file, Some(content), cx);
4504 if let Some(available_language) = &available_language {
4505 if let Some(Ok(Ok(new_language))) = self
4506 .languages
4507 .load_language(available_language)
4508 .now_or_never()
4509 {
4510 self.set_language_for_buffer(buffer_handle, new_language, cx);
4511 }
4512 } else {
4513 cx.emit(LspStoreEvent::LanguageDetected {
4514 buffer: buffer_handle.clone(),
4515 new_language: None,
4516 });
4517 }
4518
4519 available_language
4520 }
4521
4522 pub(crate) fn set_language_for_buffer(
4523 &mut self,
4524 buffer_entity: &Entity<Buffer>,
4525 new_language: Arc<Language>,
4526 cx: &mut Context<Self>,
4527 ) {
4528 let buffer = buffer_entity.read(cx);
4529 let buffer_file = buffer.file().cloned();
4530 let buffer_id = buffer.remote_id();
4531 if let Some(local_store) = self.as_local_mut()
4532 && local_store.registered_buffers.contains_key(&buffer_id)
4533 && let Some(abs_path) =
4534 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4535 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4536 {
4537 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4538 }
4539 buffer_entity.update(cx, |buffer, cx| {
4540 if buffer
4541 .language()
4542 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4543 {
4544 buffer.set_language_async(Some(new_language.clone()), cx);
4545 }
4546 });
4547
4548 let settings =
4549 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4550 let buffer_file = File::from_dyn(buffer_file.as_ref());
4551
4552 let worktree_id = if let Some(file) = buffer_file {
4553 let worktree = file.worktree.clone();
4554
4555 if let Some(local) = self.as_local_mut()
4556 && local.registered_buffers.contains_key(&buffer_id)
4557 {
4558 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4559 }
4560 Some(worktree.read(cx).id())
4561 } else {
4562 None
4563 };
4564
4565 if settings.prettier.allowed
4566 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4567 {
4568 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4569 if let Some(prettier_store) = prettier_store {
4570 prettier_store.update(cx, |prettier_store, cx| {
4571 prettier_store.install_default_prettier(
4572 worktree_id,
4573 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4574 cx,
4575 )
4576 })
4577 }
4578 }
4579
4580 cx.emit(LspStoreEvent::LanguageDetected {
4581 buffer: buffer_entity.clone(),
4582 new_language: Some(new_language),
4583 })
4584 }
4585
4586 pub fn buffer_store(&self) -> Entity<BufferStore> {
4587 self.buffer_store.clone()
4588 }
4589
4590 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4591 self.active_entry = active_entry;
4592 }
4593
4594 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4595 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4596 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4597 {
4598 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4599 summaries
4600 .iter()
4601 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4602 });
4603 if let Some(summary) = summaries.next() {
4604 client
4605 .send(proto::UpdateDiagnosticSummary {
4606 project_id: downstream_project_id,
4607 worktree_id: worktree.id().to_proto(),
4608 summary: Some(summary),
4609 more_summaries: summaries.collect(),
4610 })
4611 .log_err();
4612 }
4613 }
4614 }
4615
4616 fn is_capable_for_proto_request<R>(
4617 &self,
4618 buffer: &Entity<Buffer>,
4619 request: &R,
4620 cx: &App,
4621 ) -> bool
4622 where
4623 R: LspCommand,
4624 {
4625 self.check_if_capable_for_proto_request(
4626 buffer,
4627 |capabilities| {
4628 request.check_capabilities(AdapterServerCapabilities {
4629 server_capabilities: capabilities.clone(),
4630 code_action_kinds: None,
4631 })
4632 },
4633 cx,
4634 )
4635 }
4636
4637 fn check_if_capable_for_proto_request<F>(
4638 &self,
4639 buffer: &Entity<Buffer>,
4640 check: F,
4641 cx: &App,
4642 ) -> bool
4643 where
4644 F: FnMut(&lsp::ServerCapabilities) -> bool,
4645 {
4646 let Some(language) = buffer.read(cx).language().cloned() else {
4647 return false;
4648 };
4649 let relevant_language_servers = self
4650 .languages
4651 .lsp_adapters(&language.name())
4652 .into_iter()
4653 .map(|lsp_adapter| lsp_adapter.name())
4654 .collect::<HashSet<_>>();
4655 self.language_server_statuses
4656 .iter()
4657 .filter_map(|(server_id, server_status)| {
4658 relevant_language_servers
4659 .contains(&server_status.name)
4660 .then_some(server_id)
4661 })
4662 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4663 .any(check)
4664 }
4665
4666 fn all_capable_for_proto_request<F>(
4667 &self,
4668 buffer: &Entity<Buffer>,
4669 mut check: F,
4670 cx: &App,
4671 ) -> Vec<lsp::LanguageServerId>
4672 where
4673 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4674 {
4675 let Some(language) = buffer.read(cx).language().cloned() else {
4676 return Vec::default();
4677 };
4678 let relevant_language_servers = self
4679 .languages
4680 .lsp_adapters(&language.name())
4681 .into_iter()
4682 .map(|lsp_adapter| lsp_adapter.name())
4683 .collect::<HashSet<_>>();
4684 self.language_server_statuses
4685 .iter()
4686 .filter_map(|(server_id, server_status)| {
4687 relevant_language_servers
4688 .contains(&server_status.name)
4689 .then_some((server_id, &server_status.name))
4690 })
4691 .filter_map(|(server_id, server_name)| {
4692 self.lsp_server_capabilities
4693 .get(server_id)
4694 .map(|c| (server_id, server_name, c))
4695 })
4696 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4697 .map(|(server_id, _, _)| *server_id)
4698 .collect()
4699 }
4700
4701 pub fn request_lsp<R>(
4702 &mut self,
4703 buffer: Entity<Buffer>,
4704 server: LanguageServerToQuery,
4705 request: R,
4706 cx: &mut Context<Self>,
4707 ) -> Task<Result<R::Response>>
4708 where
4709 R: LspCommand,
4710 <R::LspRequest as lsp::request::Request>::Result: Send,
4711 <R::LspRequest as lsp::request::Request>::Params: Send,
4712 {
4713 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4714 return self.send_lsp_proto_request(
4715 buffer,
4716 upstream_client,
4717 upstream_project_id,
4718 request,
4719 cx,
4720 );
4721 }
4722
4723 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4724 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4725 local
4726 .language_servers_for_buffer(buffer, cx)
4727 .find(|(_, server)| {
4728 request.check_capabilities(server.adapter_server_capabilities())
4729 })
4730 .map(|(_, server)| server.clone())
4731 }),
4732 LanguageServerToQuery::Other(id) => self
4733 .language_server_for_local_buffer(buffer, id, cx)
4734 .and_then(|(_, server)| {
4735 request
4736 .check_capabilities(server.adapter_server_capabilities())
4737 .then(|| Arc::clone(server))
4738 }),
4739 }) else {
4740 return Task::ready(Ok(Default::default()));
4741 };
4742
4743 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4744
4745 let Some(file) = file else {
4746 return Task::ready(Ok(Default::default()));
4747 };
4748
4749 let lsp_params = match request.to_lsp_params_or_response(
4750 &file.abs_path(cx),
4751 buffer.read(cx),
4752 &language_server,
4753 cx,
4754 ) {
4755 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4756 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4757 Err(err) => {
4758 let message = format!(
4759 "{} via {} failed: {}",
4760 request.display_name(),
4761 language_server.name(),
4762 err
4763 );
4764 // rust-analyzer likes to error with this when its still loading up
4765 if !message.ends_with("content modified") {
4766 log::warn!("{message}");
4767 }
4768 return Task::ready(Err(anyhow!(message)));
4769 }
4770 };
4771
4772 let status = request.status();
4773 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4774 return Task::ready(Ok(Default::default()));
4775 }
4776 cx.spawn(async move |this, cx| {
4777 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4778
4779 let id = lsp_request.id();
4780 let _cleanup = if status.is_some() {
4781 cx.update(|cx| {
4782 this.update(cx, |this, cx| {
4783 this.on_lsp_work_start(
4784 language_server.server_id(),
4785 ProgressToken::Number(id),
4786 LanguageServerProgress {
4787 is_disk_based_diagnostics_progress: false,
4788 is_cancellable: false,
4789 title: None,
4790 message: status.clone(),
4791 percentage: None,
4792 last_update_at: cx.background_executor().now(),
4793 },
4794 cx,
4795 );
4796 })
4797 })
4798 .log_err();
4799
4800 Some(defer(|| {
4801 cx.update(|cx| {
4802 this.update(cx, |this, cx| {
4803 this.on_lsp_work_end(
4804 language_server.server_id(),
4805 ProgressToken::Number(id),
4806 cx,
4807 );
4808 })
4809 })
4810 .log_err();
4811 }))
4812 } else {
4813 None
4814 };
4815
4816 let result = lsp_request.await.into_response();
4817
4818 let response = result.map_err(|err| {
4819 let message = format!(
4820 "{} via {} failed: {}",
4821 request.display_name(),
4822 language_server.name(),
4823 err
4824 );
4825 // rust-analyzer likes to error with this when its still loading up
4826 if !message.ends_with("content modified") {
4827 log::warn!("{message}");
4828 }
4829 anyhow::anyhow!(message)
4830 })?;
4831
4832 request
4833 .response_from_lsp(
4834 response,
4835 this.upgrade().context("no app context")?,
4836 buffer,
4837 language_server.server_id(),
4838 cx.clone(),
4839 )
4840 .await
4841 })
4842 }
4843
4844 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4845 let mut language_formatters_to_check = Vec::new();
4846 for buffer in self.buffer_store.read(cx).buffers() {
4847 let buffer = buffer.read(cx);
4848 let buffer_file = File::from_dyn(buffer.file());
4849 let buffer_language = buffer.language();
4850 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4851 if buffer_language.is_some() {
4852 language_formatters_to_check.push((
4853 buffer_file.map(|f| f.worktree_id(cx)),
4854 settings.into_owned(),
4855 ));
4856 }
4857 }
4858
4859 self.request_workspace_config_refresh();
4860
4861 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4862 prettier_store.update(cx, |prettier_store, cx| {
4863 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4864 })
4865 }
4866
4867 cx.notify();
4868 }
4869
4870 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4871 let buffer_store = self.buffer_store.clone();
4872 let Some(local) = self.as_local_mut() else {
4873 return;
4874 };
4875 let mut adapters = BTreeMap::default();
4876 let get_adapter = {
4877 let languages = local.languages.clone();
4878 let environment = local.environment.clone();
4879 let weak = local.weak.clone();
4880 let worktree_store = local.worktree_store.clone();
4881 let http_client = local.http_client.clone();
4882 let fs = local.fs.clone();
4883 move |worktree_id, cx: &mut App| {
4884 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4885 Some(LocalLspAdapterDelegate::new(
4886 languages.clone(),
4887 &environment,
4888 weak.clone(),
4889 &worktree,
4890 http_client.clone(),
4891 fs.clone(),
4892 cx,
4893 ))
4894 }
4895 };
4896
4897 let mut messages_to_report = Vec::new();
4898 let (new_tree, to_stop) = {
4899 let mut rebase = local.lsp_tree.rebase();
4900 let buffers = buffer_store
4901 .read(cx)
4902 .buffers()
4903 .filter_map(|buffer| {
4904 let raw_buffer = buffer.read(cx);
4905 if !local
4906 .registered_buffers
4907 .contains_key(&raw_buffer.remote_id())
4908 {
4909 return None;
4910 }
4911 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4912 let language = raw_buffer.language().cloned()?;
4913 Some((file, language, raw_buffer.remote_id()))
4914 })
4915 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4916 for (file, language, buffer_id) in buffers {
4917 let worktree_id = file.worktree_id(cx);
4918 let Some(worktree) = local
4919 .worktree_store
4920 .read(cx)
4921 .worktree_for_id(worktree_id, cx)
4922 else {
4923 continue;
4924 };
4925
4926 if let Some((_, apply)) = local.reuse_existing_language_server(
4927 rebase.server_tree(),
4928 &worktree,
4929 &language.name(),
4930 cx,
4931 ) {
4932 (apply)(rebase.server_tree());
4933 } else if let Some(lsp_delegate) = adapters
4934 .entry(worktree_id)
4935 .or_insert_with(|| get_adapter(worktree_id, cx))
4936 .clone()
4937 {
4938 let delegate =
4939 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4940 let path = file
4941 .path()
4942 .parent()
4943 .map(Arc::from)
4944 .unwrap_or_else(|| file.path().clone());
4945 let worktree_path = ProjectPath { worktree_id, path };
4946 let abs_path = file.abs_path(cx);
4947 let nodes = rebase
4948 .walk(
4949 worktree_path,
4950 language.name(),
4951 language.manifest(),
4952 delegate.clone(),
4953 cx,
4954 )
4955 .collect::<Vec<_>>();
4956 for node in nodes {
4957 let server_id = node.server_id_or_init(|disposition| {
4958 let path = &disposition.path;
4959 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
4960 let key = LanguageServerSeed {
4961 worktree_id,
4962 name: disposition.server_name.clone(),
4963 settings: disposition.settings.clone(),
4964 toolchain: local.toolchain_store.read(cx).active_toolchain(
4965 path.worktree_id,
4966 &path.path,
4967 language.name(),
4968 ),
4969 };
4970 local.language_server_ids.remove(&key);
4971
4972 let server_id = local.get_or_insert_language_server(
4973 &worktree,
4974 lsp_delegate.clone(),
4975 disposition,
4976 &language.name(),
4977 cx,
4978 );
4979 if let Some(state) = local.language_servers.get(&server_id)
4980 && let Ok(uri) = uri
4981 {
4982 state.add_workspace_folder(uri);
4983 };
4984 server_id
4985 });
4986
4987 if let Some(language_server_id) = server_id {
4988 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
4989 language_server_id,
4990 name: node.name(),
4991 message:
4992 proto::update_language_server::Variant::RegisteredForBuffer(
4993 proto::RegisteredForBuffer {
4994 buffer_abs_path: abs_path
4995 .to_string_lossy()
4996 .into_owned(),
4997 buffer_id: buffer_id.to_proto(),
4998 },
4999 ),
5000 });
5001 }
5002 }
5003 } else {
5004 continue;
5005 }
5006 }
5007 rebase.finish()
5008 };
5009 for message in messages_to_report {
5010 cx.emit(message);
5011 }
5012 local.lsp_tree = new_tree;
5013 for (id, _) in to_stop {
5014 self.stop_local_language_server(id, cx).detach();
5015 }
5016 }
5017
5018 pub fn apply_code_action(
5019 &self,
5020 buffer_handle: Entity<Buffer>,
5021 mut action: CodeAction,
5022 push_to_history: bool,
5023 cx: &mut Context<Self>,
5024 ) -> Task<Result<ProjectTransaction>> {
5025 if let Some((upstream_client, project_id)) = self.upstream_client() {
5026 let request = proto::ApplyCodeAction {
5027 project_id,
5028 buffer_id: buffer_handle.read(cx).remote_id().into(),
5029 action: Some(Self::serialize_code_action(&action)),
5030 };
5031 let buffer_store = self.buffer_store();
5032 cx.spawn(async move |_, cx| {
5033 let response = upstream_client
5034 .request(request)
5035 .await?
5036 .transaction
5037 .context("missing transaction")?;
5038
5039 buffer_store
5040 .update(cx, |buffer_store, cx| {
5041 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5042 })?
5043 .await
5044 })
5045 } else if self.mode.is_local() {
5046 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5047 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5048 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5049 }) else {
5050 return Task::ready(Ok(ProjectTransaction::default()));
5051 };
5052 cx.spawn(async move |this, cx| {
5053 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5054 .await
5055 .context("resolving a code action")?;
5056 if let Some(edit) = action.lsp_action.edit()
5057 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5058 return LocalLspStore::deserialize_workspace_edit(
5059 this.upgrade().context("no app present")?,
5060 edit.clone(),
5061 push_to_history,
5062
5063 lang_server.clone(),
5064 cx,
5065 )
5066 .await;
5067 }
5068
5069 if let Some(command) = action.lsp_action.command() {
5070 let server_capabilities = lang_server.capabilities();
5071 let available_commands = server_capabilities
5072 .execute_command_provider
5073 .as_ref()
5074 .map(|options| options.commands.as_slice())
5075 .unwrap_or_default();
5076 if available_commands.contains(&command.command) {
5077 this.update(cx, |this, _| {
5078 this.as_local_mut()
5079 .unwrap()
5080 .last_workspace_edits_by_language_server
5081 .remove(&lang_server.server_id());
5082 })?;
5083
5084 let _result = lang_server
5085 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5086 command: command.command.clone(),
5087 arguments: command.arguments.clone().unwrap_or_default(),
5088 ..lsp::ExecuteCommandParams::default()
5089 })
5090 .await.into_response()
5091 .context("execute command")?;
5092
5093 return this.update(cx, |this, _| {
5094 this.as_local_mut()
5095 .unwrap()
5096 .last_workspace_edits_by_language_server
5097 .remove(&lang_server.server_id())
5098 .unwrap_or_default()
5099 });
5100 } else {
5101 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5102 }
5103 }
5104
5105 Ok(ProjectTransaction::default())
5106 })
5107 } else {
5108 Task::ready(Err(anyhow!("no upstream client and not local")))
5109 }
5110 }
5111
5112 pub fn apply_code_action_kind(
5113 &mut self,
5114 buffers: HashSet<Entity<Buffer>>,
5115 kind: CodeActionKind,
5116 push_to_history: bool,
5117 cx: &mut Context<Self>,
5118 ) -> Task<anyhow::Result<ProjectTransaction>> {
5119 if self.as_local().is_some() {
5120 cx.spawn(async move |lsp_store, cx| {
5121 let buffers = buffers.into_iter().collect::<Vec<_>>();
5122 let result = LocalLspStore::execute_code_action_kind_locally(
5123 lsp_store.clone(),
5124 buffers,
5125 kind,
5126 push_to_history,
5127 cx,
5128 )
5129 .await;
5130 lsp_store.update(cx, |lsp_store, _| {
5131 lsp_store.update_last_formatting_failure(&result);
5132 })?;
5133 result
5134 })
5135 } else if let Some((client, project_id)) = self.upstream_client() {
5136 let buffer_store = self.buffer_store();
5137 cx.spawn(async move |lsp_store, cx| {
5138 let result = client
5139 .request(proto::ApplyCodeActionKind {
5140 project_id,
5141 kind: kind.as_str().to_owned(),
5142 buffer_ids: buffers
5143 .iter()
5144 .map(|buffer| {
5145 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5146 })
5147 .collect::<Result<_>>()?,
5148 })
5149 .await
5150 .and_then(|result| result.transaction.context("missing transaction"));
5151 lsp_store.update(cx, |lsp_store, _| {
5152 lsp_store.update_last_formatting_failure(&result);
5153 })?;
5154
5155 let transaction_response = result?;
5156 buffer_store
5157 .update(cx, |buffer_store, cx| {
5158 buffer_store.deserialize_project_transaction(
5159 transaction_response,
5160 push_to_history,
5161 cx,
5162 )
5163 })?
5164 .await
5165 })
5166 } else {
5167 Task::ready(Ok(ProjectTransaction::default()))
5168 }
5169 }
5170
5171 pub fn resolved_hint(
5172 &mut self,
5173 buffer_id: BufferId,
5174 id: InlayId,
5175 cx: &mut Context<Self>,
5176 ) -> Option<ResolvedHint> {
5177 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5178
5179 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5180 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5181 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5182 let (server_id, resolve_data) = match &hint.resolve_state {
5183 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5184 ResolveState::Resolving => {
5185 return Some(ResolvedHint::Resolving(
5186 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5187 ));
5188 }
5189 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5190 };
5191
5192 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5193 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5194 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5195 id,
5196 cx.spawn(async move |lsp_store, cx| {
5197 let resolved_hint = resolve_task.await;
5198 lsp_store
5199 .update(cx, |lsp_store, _| {
5200 if let Some(old_inlay_hint) = lsp_store
5201 .lsp_data
5202 .get_mut(&buffer_id)
5203 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5204 {
5205 match resolved_hint {
5206 Ok(resolved_hint) => {
5207 *old_inlay_hint = resolved_hint;
5208 }
5209 Err(e) => {
5210 old_inlay_hint.resolve_state =
5211 ResolveState::CanResolve(server_id, resolve_data);
5212 log::error!("Inlay hint resolve failed: {e:#}");
5213 }
5214 }
5215 }
5216 })
5217 .ok();
5218 })
5219 .shared(),
5220 );
5221 debug_assert!(
5222 previous_task.is_none(),
5223 "Did not change hint's resolve state after spawning its resolve"
5224 );
5225 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5226 None
5227 }
5228
5229 fn resolve_inlay_hint(
5230 &self,
5231 mut hint: InlayHint,
5232 buffer: Entity<Buffer>,
5233 server_id: LanguageServerId,
5234 cx: &mut Context<Self>,
5235 ) -> Task<anyhow::Result<InlayHint>> {
5236 if let Some((upstream_client, project_id)) = self.upstream_client() {
5237 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5238 {
5239 hint.resolve_state = ResolveState::Resolved;
5240 return Task::ready(Ok(hint));
5241 }
5242 let request = proto::ResolveInlayHint {
5243 project_id,
5244 buffer_id: buffer.read(cx).remote_id().into(),
5245 language_server_id: server_id.0 as u64,
5246 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5247 };
5248 cx.background_spawn(async move {
5249 let response = upstream_client
5250 .request(request)
5251 .await
5252 .context("inlay hints proto request")?;
5253 match response.hint {
5254 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5255 .context("inlay hints proto resolve response conversion"),
5256 None => Ok(hint),
5257 }
5258 })
5259 } else {
5260 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5261 self.language_server_for_local_buffer(buffer, server_id, cx)
5262 .map(|(_, server)| server.clone())
5263 }) else {
5264 return Task::ready(Ok(hint));
5265 };
5266 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5267 return Task::ready(Ok(hint));
5268 }
5269 let buffer_snapshot = buffer.read(cx).snapshot();
5270 cx.spawn(async move |_, cx| {
5271 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5272 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5273 );
5274 let resolved_hint = resolve_task
5275 .await
5276 .into_response()
5277 .context("inlay hint resolve LSP request")?;
5278 let resolved_hint = InlayHints::lsp_to_project_hint(
5279 resolved_hint,
5280 &buffer,
5281 server_id,
5282 ResolveState::Resolved,
5283 false,
5284 cx,
5285 )
5286 .await?;
5287 Ok(resolved_hint)
5288 })
5289 }
5290 }
5291
5292 pub fn resolve_color_presentation(
5293 &mut self,
5294 mut color: DocumentColor,
5295 buffer: Entity<Buffer>,
5296 server_id: LanguageServerId,
5297 cx: &mut Context<Self>,
5298 ) -> Task<Result<DocumentColor>> {
5299 if color.resolved {
5300 return Task::ready(Ok(color));
5301 }
5302
5303 if let Some((upstream_client, project_id)) = self.upstream_client() {
5304 let start = color.lsp_range.start;
5305 let end = color.lsp_range.end;
5306 let request = proto::GetColorPresentation {
5307 project_id,
5308 server_id: server_id.to_proto(),
5309 buffer_id: buffer.read(cx).remote_id().into(),
5310 color: Some(proto::ColorInformation {
5311 red: color.color.red,
5312 green: color.color.green,
5313 blue: color.color.blue,
5314 alpha: color.color.alpha,
5315 lsp_range_start: Some(proto::PointUtf16 {
5316 row: start.line,
5317 column: start.character,
5318 }),
5319 lsp_range_end: Some(proto::PointUtf16 {
5320 row: end.line,
5321 column: end.character,
5322 }),
5323 }),
5324 };
5325 cx.background_spawn(async move {
5326 let response = upstream_client
5327 .request(request)
5328 .await
5329 .context("color presentation proto request")?;
5330 color.resolved = true;
5331 color.color_presentations = response
5332 .presentations
5333 .into_iter()
5334 .map(|presentation| ColorPresentation {
5335 label: SharedString::from(presentation.label),
5336 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5337 additional_text_edits: presentation
5338 .additional_text_edits
5339 .into_iter()
5340 .filter_map(deserialize_lsp_edit)
5341 .collect(),
5342 })
5343 .collect();
5344 Ok(color)
5345 })
5346 } else {
5347 let path = match buffer
5348 .update(cx, |buffer, cx| {
5349 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5350 })
5351 .context("buffer with the missing path")
5352 {
5353 Ok(path) => path,
5354 Err(e) => return Task::ready(Err(e)),
5355 };
5356 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5357 self.language_server_for_local_buffer(buffer, server_id, cx)
5358 .map(|(_, server)| server.clone())
5359 }) else {
5360 return Task::ready(Ok(color));
5361 };
5362 cx.background_spawn(async move {
5363 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5364 lsp::ColorPresentationParams {
5365 text_document: make_text_document_identifier(&path)?,
5366 color: color.color,
5367 range: color.lsp_range,
5368 work_done_progress_params: Default::default(),
5369 partial_result_params: Default::default(),
5370 },
5371 );
5372 color.color_presentations = resolve_task
5373 .await
5374 .into_response()
5375 .context("color presentation resolve LSP request")?
5376 .into_iter()
5377 .map(|presentation| ColorPresentation {
5378 label: SharedString::from(presentation.label),
5379 text_edit: presentation.text_edit,
5380 additional_text_edits: presentation
5381 .additional_text_edits
5382 .unwrap_or_default(),
5383 })
5384 .collect();
5385 color.resolved = true;
5386 Ok(color)
5387 })
5388 }
5389 }
5390
5391 pub(crate) fn linked_edits(
5392 &mut self,
5393 buffer: &Entity<Buffer>,
5394 position: Anchor,
5395 cx: &mut Context<Self>,
5396 ) -> Task<Result<Vec<Range<Anchor>>>> {
5397 let snapshot = buffer.read(cx).snapshot();
5398 let scope = snapshot.language_scope_at(position);
5399 let Some(server_id) = self
5400 .as_local()
5401 .and_then(|local| {
5402 buffer.update(cx, |buffer, cx| {
5403 local
5404 .language_servers_for_buffer(buffer, cx)
5405 .filter(|(_, server)| {
5406 LinkedEditingRange::check_server_capabilities(server.capabilities())
5407 })
5408 .filter(|(adapter, _)| {
5409 scope
5410 .as_ref()
5411 .map(|scope| scope.language_allowed(&adapter.name))
5412 .unwrap_or(true)
5413 })
5414 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5415 .next()
5416 })
5417 })
5418 .or_else(|| {
5419 self.upstream_client()
5420 .is_some()
5421 .then_some(LanguageServerToQuery::FirstCapable)
5422 })
5423 .filter(|_| {
5424 maybe!({
5425 let language = buffer.read(cx).language_at(position)?;
5426 Some(
5427 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5428 .linked_edits,
5429 )
5430 }) == Some(true)
5431 })
5432 else {
5433 return Task::ready(Ok(Vec::new()));
5434 };
5435
5436 self.request_lsp(
5437 buffer.clone(),
5438 server_id,
5439 LinkedEditingRange { position },
5440 cx,
5441 )
5442 }
5443
5444 fn apply_on_type_formatting(
5445 &mut self,
5446 buffer: Entity<Buffer>,
5447 position: Anchor,
5448 trigger: String,
5449 cx: &mut Context<Self>,
5450 ) -> Task<Result<Option<Transaction>>> {
5451 if let Some((client, project_id)) = self.upstream_client() {
5452 if !self.check_if_capable_for_proto_request(
5453 &buffer,
5454 |capabilities| {
5455 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5456 },
5457 cx,
5458 ) {
5459 return Task::ready(Ok(None));
5460 }
5461 let request = proto::OnTypeFormatting {
5462 project_id,
5463 buffer_id: buffer.read(cx).remote_id().into(),
5464 position: Some(serialize_anchor(&position)),
5465 trigger,
5466 version: serialize_version(&buffer.read(cx).version()),
5467 };
5468 cx.background_spawn(async move {
5469 client
5470 .request(request)
5471 .await?
5472 .transaction
5473 .map(language::proto::deserialize_transaction)
5474 .transpose()
5475 })
5476 } else if let Some(local) = self.as_local_mut() {
5477 let buffer_id = buffer.read(cx).remote_id();
5478 local.buffers_being_formatted.insert(buffer_id);
5479 cx.spawn(async move |this, cx| {
5480 let _cleanup = defer({
5481 let this = this.clone();
5482 let mut cx = cx.clone();
5483 move || {
5484 this.update(&mut cx, |this, _| {
5485 if let Some(local) = this.as_local_mut() {
5486 local.buffers_being_formatted.remove(&buffer_id);
5487 }
5488 })
5489 .ok();
5490 }
5491 });
5492
5493 buffer
5494 .update(cx, |buffer, _| {
5495 buffer.wait_for_edits(Some(position.timestamp))
5496 })?
5497 .await?;
5498 this.update(cx, |this, cx| {
5499 let position = position.to_point_utf16(buffer.read(cx));
5500 this.on_type_format(buffer, position, trigger, false, cx)
5501 })?
5502 .await
5503 })
5504 } else {
5505 Task::ready(Err(anyhow!("No upstream client or local language server")))
5506 }
5507 }
5508
5509 pub fn on_type_format<T: ToPointUtf16>(
5510 &mut self,
5511 buffer: Entity<Buffer>,
5512 position: T,
5513 trigger: String,
5514 push_to_history: bool,
5515 cx: &mut Context<Self>,
5516 ) -> Task<Result<Option<Transaction>>> {
5517 let position = position.to_point_utf16(buffer.read(cx));
5518 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5519 }
5520
5521 fn on_type_format_impl(
5522 &mut self,
5523 buffer: Entity<Buffer>,
5524 position: PointUtf16,
5525 trigger: String,
5526 push_to_history: bool,
5527 cx: &mut Context<Self>,
5528 ) -> Task<Result<Option<Transaction>>> {
5529 let options = buffer.update(cx, |buffer, cx| {
5530 lsp_command::lsp_formatting_options(
5531 language_settings(
5532 buffer.language_at(position).map(|l| l.name()),
5533 buffer.file(),
5534 cx,
5535 )
5536 .as_ref(),
5537 )
5538 });
5539
5540 cx.spawn(async move |this, cx| {
5541 if let Some(waiter) =
5542 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5543 {
5544 waiter.await?;
5545 }
5546 cx.update(|cx| {
5547 this.update(cx, |this, cx| {
5548 this.request_lsp(
5549 buffer.clone(),
5550 LanguageServerToQuery::FirstCapable,
5551 OnTypeFormatting {
5552 position,
5553 trigger,
5554 options,
5555 push_to_history,
5556 },
5557 cx,
5558 )
5559 })
5560 })??
5561 .await
5562 })
5563 }
5564
5565 pub fn definitions(
5566 &mut self,
5567 buffer: &Entity<Buffer>,
5568 position: PointUtf16,
5569 cx: &mut Context<Self>,
5570 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5571 if let Some((upstream_client, project_id)) = self.upstream_client() {
5572 let request = GetDefinitions { position };
5573 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5574 return Task::ready(Ok(None));
5575 }
5576 let request_task = upstream_client.request_lsp(
5577 project_id,
5578 None,
5579 LSP_REQUEST_TIMEOUT,
5580 cx.background_executor().clone(),
5581 request.to_proto(project_id, buffer.read(cx)),
5582 );
5583 let buffer = buffer.clone();
5584 cx.spawn(async move |weak_lsp_store, cx| {
5585 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5586 return Ok(None);
5587 };
5588 let Some(responses) = request_task.await? else {
5589 return Ok(None);
5590 };
5591 let actions = join_all(responses.payload.into_iter().map(|response| {
5592 GetDefinitions { position }.response_from_proto(
5593 response.response,
5594 lsp_store.clone(),
5595 buffer.clone(),
5596 cx.clone(),
5597 )
5598 }))
5599 .await;
5600
5601 Ok(Some(
5602 actions
5603 .into_iter()
5604 .collect::<Result<Vec<Vec<_>>>>()?
5605 .into_iter()
5606 .flatten()
5607 .dedup()
5608 .collect(),
5609 ))
5610 })
5611 } else {
5612 let definitions_task = self.request_multiple_lsp_locally(
5613 buffer,
5614 Some(position),
5615 GetDefinitions { position },
5616 cx,
5617 );
5618 cx.background_spawn(async move {
5619 Ok(Some(
5620 definitions_task
5621 .await
5622 .into_iter()
5623 .flat_map(|(_, definitions)| definitions)
5624 .dedup()
5625 .collect(),
5626 ))
5627 })
5628 }
5629 }
5630
5631 pub fn declarations(
5632 &mut self,
5633 buffer: &Entity<Buffer>,
5634 position: PointUtf16,
5635 cx: &mut Context<Self>,
5636 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5637 if let Some((upstream_client, project_id)) = self.upstream_client() {
5638 let request = GetDeclarations { position };
5639 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5640 return Task::ready(Ok(None));
5641 }
5642 let request_task = upstream_client.request_lsp(
5643 project_id,
5644 None,
5645 LSP_REQUEST_TIMEOUT,
5646 cx.background_executor().clone(),
5647 request.to_proto(project_id, buffer.read(cx)),
5648 );
5649 let buffer = buffer.clone();
5650 cx.spawn(async move |weak_lsp_store, cx| {
5651 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5652 return Ok(None);
5653 };
5654 let Some(responses) = request_task.await? else {
5655 return Ok(None);
5656 };
5657 let actions = join_all(responses.payload.into_iter().map(|response| {
5658 GetDeclarations { position }.response_from_proto(
5659 response.response,
5660 lsp_store.clone(),
5661 buffer.clone(),
5662 cx.clone(),
5663 )
5664 }))
5665 .await;
5666
5667 Ok(Some(
5668 actions
5669 .into_iter()
5670 .collect::<Result<Vec<Vec<_>>>>()?
5671 .into_iter()
5672 .flatten()
5673 .dedup()
5674 .collect(),
5675 ))
5676 })
5677 } else {
5678 let declarations_task = self.request_multiple_lsp_locally(
5679 buffer,
5680 Some(position),
5681 GetDeclarations { position },
5682 cx,
5683 );
5684 cx.background_spawn(async move {
5685 Ok(Some(
5686 declarations_task
5687 .await
5688 .into_iter()
5689 .flat_map(|(_, declarations)| declarations)
5690 .dedup()
5691 .collect(),
5692 ))
5693 })
5694 }
5695 }
5696
5697 pub fn type_definitions(
5698 &mut self,
5699 buffer: &Entity<Buffer>,
5700 position: PointUtf16,
5701 cx: &mut Context<Self>,
5702 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5703 if let Some((upstream_client, project_id)) = self.upstream_client() {
5704 let request = GetTypeDefinitions { position };
5705 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5706 return Task::ready(Ok(None));
5707 }
5708 let request_task = upstream_client.request_lsp(
5709 project_id,
5710 None,
5711 LSP_REQUEST_TIMEOUT,
5712 cx.background_executor().clone(),
5713 request.to_proto(project_id, buffer.read(cx)),
5714 );
5715 let buffer = buffer.clone();
5716 cx.spawn(async move |weak_lsp_store, cx| {
5717 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5718 return Ok(None);
5719 };
5720 let Some(responses) = request_task.await? else {
5721 return Ok(None);
5722 };
5723 let actions = join_all(responses.payload.into_iter().map(|response| {
5724 GetTypeDefinitions { position }.response_from_proto(
5725 response.response,
5726 lsp_store.clone(),
5727 buffer.clone(),
5728 cx.clone(),
5729 )
5730 }))
5731 .await;
5732
5733 Ok(Some(
5734 actions
5735 .into_iter()
5736 .collect::<Result<Vec<Vec<_>>>>()?
5737 .into_iter()
5738 .flatten()
5739 .dedup()
5740 .collect(),
5741 ))
5742 })
5743 } else {
5744 let type_definitions_task = self.request_multiple_lsp_locally(
5745 buffer,
5746 Some(position),
5747 GetTypeDefinitions { position },
5748 cx,
5749 );
5750 cx.background_spawn(async move {
5751 Ok(Some(
5752 type_definitions_task
5753 .await
5754 .into_iter()
5755 .flat_map(|(_, type_definitions)| type_definitions)
5756 .dedup()
5757 .collect(),
5758 ))
5759 })
5760 }
5761 }
5762
5763 pub fn implementations(
5764 &mut self,
5765 buffer: &Entity<Buffer>,
5766 position: PointUtf16,
5767 cx: &mut Context<Self>,
5768 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5769 if let Some((upstream_client, project_id)) = self.upstream_client() {
5770 let request = GetImplementations { position };
5771 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5772 return Task::ready(Ok(None));
5773 }
5774 let request_task = upstream_client.request_lsp(
5775 project_id,
5776 None,
5777 LSP_REQUEST_TIMEOUT,
5778 cx.background_executor().clone(),
5779 request.to_proto(project_id, buffer.read(cx)),
5780 );
5781 let buffer = buffer.clone();
5782 cx.spawn(async move |weak_lsp_store, cx| {
5783 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5784 return Ok(None);
5785 };
5786 let Some(responses) = request_task.await? else {
5787 return Ok(None);
5788 };
5789 let actions = join_all(responses.payload.into_iter().map(|response| {
5790 GetImplementations { position }.response_from_proto(
5791 response.response,
5792 lsp_store.clone(),
5793 buffer.clone(),
5794 cx.clone(),
5795 )
5796 }))
5797 .await;
5798
5799 Ok(Some(
5800 actions
5801 .into_iter()
5802 .collect::<Result<Vec<Vec<_>>>>()?
5803 .into_iter()
5804 .flatten()
5805 .dedup()
5806 .collect(),
5807 ))
5808 })
5809 } else {
5810 let implementations_task = self.request_multiple_lsp_locally(
5811 buffer,
5812 Some(position),
5813 GetImplementations { position },
5814 cx,
5815 );
5816 cx.background_spawn(async move {
5817 Ok(Some(
5818 implementations_task
5819 .await
5820 .into_iter()
5821 .flat_map(|(_, implementations)| implementations)
5822 .dedup()
5823 .collect(),
5824 ))
5825 })
5826 }
5827 }
5828
5829 pub fn references(
5830 &mut self,
5831 buffer: &Entity<Buffer>,
5832 position: PointUtf16,
5833 cx: &mut Context<Self>,
5834 ) -> Task<Result<Option<Vec<Location>>>> {
5835 if let Some((upstream_client, project_id)) = self.upstream_client() {
5836 let request = GetReferences { position };
5837 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5838 return Task::ready(Ok(None));
5839 }
5840
5841 let request_task = upstream_client.request_lsp(
5842 project_id,
5843 None,
5844 LSP_REQUEST_TIMEOUT,
5845 cx.background_executor().clone(),
5846 request.to_proto(project_id, buffer.read(cx)),
5847 );
5848 let buffer = buffer.clone();
5849 cx.spawn(async move |weak_lsp_store, cx| {
5850 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5851 return Ok(None);
5852 };
5853 let Some(responses) = request_task.await? else {
5854 return Ok(None);
5855 };
5856
5857 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5858 GetReferences { position }.response_from_proto(
5859 lsp_response.response,
5860 lsp_store.clone(),
5861 buffer.clone(),
5862 cx.clone(),
5863 )
5864 }))
5865 .await
5866 .into_iter()
5867 .collect::<Result<Vec<Vec<_>>>>()?
5868 .into_iter()
5869 .flatten()
5870 .dedup()
5871 .collect();
5872 Ok(Some(locations))
5873 })
5874 } else {
5875 let references_task = self.request_multiple_lsp_locally(
5876 buffer,
5877 Some(position),
5878 GetReferences { position },
5879 cx,
5880 );
5881 cx.background_spawn(async move {
5882 Ok(Some(
5883 references_task
5884 .await
5885 .into_iter()
5886 .flat_map(|(_, references)| references)
5887 .dedup()
5888 .collect(),
5889 ))
5890 })
5891 }
5892 }
5893
5894 pub fn code_actions(
5895 &mut self,
5896 buffer: &Entity<Buffer>,
5897 range: Range<Anchor>,
5898 kinds: Option<Vec<CodeActionKind>>,
5899 cx: &mut Context<Self>,
5900 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5901 if let Some((upstream_client, project_id)) = self.upstream_client() {
5902 let request = GetCodeActions {
5903 range: range.clone(),
5904 kinds: kinds.clone(),
5905 };
5906 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5907 return Task::ready(Ok(None));
5908 }
5909 let request_task = upstream_client.request_lsp(
5910 project_id,
5911 None,
5912 LSP_REQUEST_TIMEOUT,
5913 cx.background_executor().clone(),
5914 request.to_proto(project_id, buffer.read(cx)),
5915 );
5916 let buffer = buffer.clone();
5917 cx.spawn(async move |weak_lsp_store, cx| {
5918 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5919 return Ok(None);
5920 };
5921 let Some(responses) = request_task.await? else {
5922 return Ok(None);
5923 };
5924 let actions = join_all(responses.payload.into_iter().map(|response| {
5925 GetCodeActions {
5926 range: range.clone(),
5927 kinds: kinds.clone(),
5928 }
5929 .response_from_proto(
5930 response.response,
5931 lsp_store.clone(),
5932 buffer.clone(),
5933 cx.clone(),
5934 )
5935 }))
5936 .await;
5937
5938 Ok(Some(
5939 actions
5940 .into_iter()
5941 .collect::<Result<Vec<Vec<_>>>>()?
5942 .into_iter()
5943 .flatten()
5944 .collect(),
5945 ))
5946 })
5947 } else {
5948 let all_actions_task = self.request_multiple_lsp_locally(
5949 buffer,
5950 Some(range.start),
5951 GetCodeActions { range, kinds },
5952 cx,
5953 );
5954 cx.background_spawn(async move {
5955 Ok(Some(
5956 all_actions_task
5957 .await
5958 .into_iter()
5959 .flat_map(|(_, actions)| actions)
5960 .collect(),
5961 ))
5962 })
5963 }
5964 }
5965
5966 pub fn code_lens_actions(
5967 &mut self,
5968 buffer: &Entity<Buffer>,
5969 cx: &mut Context<Self>,
5970 ) -> CodeLensTask {
5971 let version_queried_for = buffer.read(cx).version();
5972 let buffer_id = buffer.read(cx).remote_id();
5973 let existing_servers = self.as_local().map(|local| {
5974 local
5975 .buffers_opened_in_servers
5976 .get(&buffer_id)
5977 .cloned()
5978 .unwrap_or_default()
5979 });
5980
5981 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
5982 if let Some(cached_lens) = &lsp_data.code_lens {
5983 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
5984 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
5985 existing_servers != cached_lens.lens.keys().copied().collect()
5986 });
5987 if !has_different_servers {
5988 return Task::ready(Ok(Some(
5989 cached_lens.lens.values().flatten().cloned().collect(),
5990 )))
5991 .shared();
5992 }
5993 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
5994 if !version_queried_for.changed_since(updating_for) {
5995 return running_update.clone();
5996 }
5997 }
5998 }
5999 }
6000
6001 let lens_lsp_data = self
6002 .latest_lsp_data(buffer, cx)
6003 .code_lens
6004 .get_or_insert_default();
6005 let buffer = buffer.clone();
6006 let query_version_queried_for = version_queried_for.clone();
6007 let new_task = cx
6008 .spawn(async move |lsp_store, cx| {
6009 cx.background_executor()
6010 .timer(Duration::from_millis(30))
6011 .await;
6012 let fetched_lens = lsp_store
6013 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6014 .map_err(Arc::new)?
6015 .await
6016 .context("fetching code lens")
6017 .map_err(Arc::new);
6018 let fetched_lens = match fetched_lens {
6019 Ok(fetched_lens) => fetched_lens,
6020 Err(e) => {
6021 lsp_store
6022 .update(cx, |lsp_store, _| {
6023 if let Some(lens_lsp_data) = lsp_store
6024 .lsp_data
6025 .get_mut(&buffer_id)
6026 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6027 {
6028 lens_lsp_data.update = None;
6029 }
6030 })
6031 .ok();
6032 return Err(e);
6033 }
6034 };
6035
6036 lsp_store
6037 .update(cx, |lsp_store, _| {
6038 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6039 let code_lens = lsp_data.code_lens.as_mut()?;
6040 if let Some(fetched_lens) = fetched_lens {
6041 if lsp_data.buffer_version == query_version_queried_for {
6042 code_lens.lens.extend(fetched_lens);
6043 } else if !lsp_data
6044 .buffer_version
6045 .changed_since(&query_version_queried_for)
6046 {
6047 lsp_data.buffer_version = query_version_queried_for;
6048 code_lens.lens = fetched_lens;
6049 }
6050 }
6051 code_lens.update = None;
6052 Some(code_lens.lens.values().flatten().cloned().collect())
6053 })
6054 .map_err(Arc::new)
6055 })
6056 .shared();
6057 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6058 new_task
6059 }
6060
6061 fn fetch_code_lens(
6062 &mut self,
6063 buffer: &Entity<Buffer>,
6064 cx: &mut Context<Self>,
6065 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6066 if let Some((upstream_client, project_id)) = self.upstream_client() {
6067 let request = GetCodeLens;
6068 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6069 return Task::ready(Ok(None));
6070 }
6071 let request_task = upstream_client.request_lsp(
6072 project_id,
6073 None,
6074 LSP_REQUEST_TIMEOUT,
6075 cx.background_executor().clone(),
6076 request.to_proto(project_id, buffer.read(cx)),
6077 );
6078 let buffer = buffer.clone();
6079 cx.spawn(async move |weak_lsp_store, cx| {
6080 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6081 return Ok(None);
6082 };
6083 let Some(responses) = request_task.await? else {
6084 return Ok(None);
6085 };
6086
6087 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6088 let lsp_store = lsp_store.clone();
6089 let buffer = buffer.clone();
6090 let cx = cx.clone();
6091 async move {
6092 (
6093 LanguageServerId::from_proto(response.server_id),
6094 GetCodeLens
6095 .response_from_proto(response.response, lsp_store, buffer, cx)
6096 .await,
6097 )
6098 }
6099 }))
6100 .await;
6101
6102 let mut has_errors = false;
6103 let code_lens_actions = code_lens_actions
6104 .into_iter()
6105 .filter_map(|(server_id, code_lens)| match code_lens {
6106 Ok(code_lens) => Some((server_id, code_lens)),
6107 Err(e) => {
6108 has_errors = true;
6109 log::error!("{e:#}");
6110 None
6111 }
6112 })
6113 .collect::<HashMap<_, _>>();
6114 anyhow::ensure!(
6115 !has_errors || !code_lens_actions.is_empty(),
6116 "Failed to fetch code lens"
6117 );
6118 Ok(Some(code_lens_actions))
6119 })
6120 } else {
6121 let code_lens_actions_task =
6122 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6123 cx.background_spawn(async move {
6124 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6125 })
6126 }
6127 }
6128
6129 #[inline(never)]
6130 pub fn completions(
6131 &self,
6132 buffer: &Entity<Buffer>,
6133 position: PointUtf16,
6134 context: CompletionContext,
6135 cx: &mut Context<Self>,
6136 ) -> Task<Result<Vec<CompletionResponse>>> {
6137 let language_registry = self.languages.clone();
6138
6139 if let Some((upstream_client, project_id)) = self.upstream_client() {
6140 let snapshot = buffer.read(cx).snapshot();
6141 let offset = position.to_offset(&snapshot);
6142 let scope = snapshot.language_scope_at(offset);
6143 let capable_lsps = self.all_capable_for_proto_request(
6144 buffer,
6145 |server_name, capabilities| {
6146 capabilities.completion_provider.is_some()
6147 && scope
6148 .as_ref()
6149 .map(|scope| scope.language_allowed(server_name))
6150 .unwrap_or(true)
6151 },
6152 cx,
6153 );
6154 if capable_lsps.is_empty() {
6155 return Task::ready(Ok(Vec::new()));
6156 }
6157
6158 let language = buffer.read(cx).language().cloned();
6159
6160 // In the future, we should provide project guests with the names of LSP adapters,
6161 // so that they can use the correct LSP adapter when computing labels. For now,
6162 // guests just use the first LSP adapter associated with the buffer's language.
6163 let lsp_adapter = language.as_ref().and_then(|language| {
6164 language_registry
6165 .lsp_adapters(&language.name())
6166 .first()
6167 .cloned()
6168 });
6169
6170 let buffer = buffer.clone();
6171
6172 cx.spawn(async move |this, cx| {
6173 let requests = join_all(
6174 capable_lsps
6175 .into_iter()
6176 .map(|id| {
6177 let request = GetCompletions {
6178 position,
6179 context: context.clone(),
6180 server_id: Some(id),
6181 };
6182 let buffer = buffer.clone();
6183 let language = language.clone();
6184 let lsp_adapter = lsp_adapter.clone();
6185 let upstream_client = upstream_client.clone();
6186 let response = this
6187 .update(cx, |this, cx| {
6188 this.send_lsp_proto_request(
6189 buffer,
6190 upstream_client,
6191 project_id,
6192 request,
6193 cx,
6194 )
6195 })
6196 .log_err();
6197 async move {
6198 let response = response?.await.log_err()?;
6199
6200 let completions = populate_labels_for_completions(
6201 response.completions,
6202 language,
6203 lsp_adapter,
6204 )
6205 .await;
6206
6207 Some(CompletionResponse {
6208 completions,
6209 display_options: CompletionDisplayOptions::default(),
6210 is_incomplete: response.is_incomplete,
6211 })
6212 }
6213 })
6214 .collect::<Vec<_>>(),
6215 );
6216 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6217 })
6218 } else if let Some(local) = self.as_local() {
6219 let snapshot = buffer.read(cx).snapshot();
6220 let offset = position.to_offset(&snapshot);
6221 let scope = snapshot.language_scope_at(offset);
6222 let language = snapshot.language().cloned();
6223 let completion_settings = language_settings(
6224 language.as_ref().map(|language| language.name()),
6225 buffer.read(cx).file(),
6226 cx,
6227 )
6228 .completions
6229 .clone();
6230 if !completion_settings.lsp {
6231 return Task::ready(Ok(Vec::new()));
6232 }
6233
6234 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6235 local
6236 .language_servers_for_buffer(buffer, cx)
6237 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6238 .filter(|(adapter, _)| {
6239 scope
6240 .as_ref()
6241 .map(|scope| scope.language_allowed(&adapter.name))
6242 .unwrap_or(true)
6243 })
6244 .map(|(_, server)| server.server_id())
6245 .collect()
6246 });
6247
6248 let buffer = buffer.clone();
6249 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6250 let lsp_timeout = if lsp_timeout > 0 {
6251 Some(Duration::from_millis(lsp_timeout))
6252 } else {
6253 None
6254 };
6255 cx.spawn(async move |this, cx| {
6256 let mut tasks = Vec::with_capacity(server_ids.len());
6257 this.update(cx, |lsp_store, cx| {
6258 for server_id in server_ids {
6259 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6260 let lsp_timeout = lsp_timeout
6261 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6262 let mut timeout = cx.background_spawn(async move {
6263 match lsp_timeout {
6264 Some(lsp_timeout) => {
6265 lsp_timeout.await;
6266 true
6267 },
6268 None => false,
6269 }
6270 }).fuse();
6271 let mut lsp_request = lsp_store.request_lsp(
6272 buffer.clone(),
6273 LanguageServerToQuery::Other(server_id),
6274 GetCompletions {
6275 position,
6276 context: context.clone(),
6277 server_id: Some(server_id),
6278 },
6279 cx,
6280 ).fuse();
6281 let new_task = cx.background_spawn(async move {
6282 select_biased! {
6283 response = lsp_request => anyhow::Ok(Some(response?)),
6284 timeout_happened = timeout => {
6285 if timeout_happened {
6286 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6287 Ok(None)
6288 } else {
6289 let completions = lsp_request.await?;
6290 Ok(Some(completions))
6291 }
6292 },
6293 }
6294 });
6295 tasks.push((lsp_adapter, new_task));
6296 }
6297 })?;
6298
6299 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6300 let completion_response = task.await.ok()??;
6301 let completions = populate_labels_for_completions(
6302 completion_response.completions,
6303 language.clone(),
6304 lsp_adapter,
6305 )
6306 .await;
6307 Some(CompletionResponse {
6308 completions,
6309 display_options: CompletionDisplayOptions::default(),
6310 is_incomplete: completion_response.is_incomplete,
6311 })
6312 });
6313
6314 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6315
6316 Ok(responses.into_iter().flatten().collect())
6317 })
6318 } else {
6319 Task::ready(Err(anyhow!("No upstream client or local language server")))
6320 }
6321 }
6322
6323 pub fn resolve_completions(
6324 &self,
6325 buffer: Entity<Buffer>,
6326 completion_indices: Vec<usize>,
6327 completions: Rc<RefCell<Box<[Completion]>>>,
6328 cx: &mut Context<Self>,
6329 ) -> Task<Result<bool>> {
6330 let client = self.upstream_client();
6331 let buffer_id = buffer.read(cx).remote_id();
6332 let buffer_snapshot = buffer.read(cx).snapshot();
6333
6334 if !self.check_if_capable_for_proto_request(
6335 &buffer,
6336 GetCompletions::can_resolve_completions,
6337 cx,
6338 ) {
6339 return Task::ready(Ok(false));
6340 }
6341 cx.spawn(async move |lsp_store, cx| {
6342 let mut did_resolve = false;
6343 if let Some((client, project_id)) = client {
6344 for completion_index in completion_indices {
6345 let server_id = {
6346 let completion = &completions.borrow()[completion_index];
6347 completion.source.server_id()
6348 };
6349 if let Some(server_id) = server_id {
6350 if Self::resolve_completion_remote(
6351 project_id,
6352 server_id,
6353 buffer_id,
6354 completions.clone(),
6355 completion_index,
6356 client.clone(),
6357 )
6358 .await
6359 .log_err()
6360 .is_some()
6361 {
6362 did_resolve = true;
6363 }
6364 } else {
6365 resolve_word_completion(
6366 &buffer_snapshot,
6367 &mut completions.borrow_mut()[completion_index],
6368 );
6369 }
6370 }
6371 } else {
6372 for completion_index in completion_indices {
6373 let server_id = {
6374 let completion = &completions.borrow()[completion_index];
6375 completion.source.server_id()
6376 };
6377 if let Some(server_id) = server_id {
6378 let server_and_adapter = lsp_store
6379 .read_with(cx, |lsp_store, _| {
6380 let server = lsp_store.language_server_for_id(server_id)?;
6381 let adapter =
6382 lsp_store.language_server_adapter_for_id(server.server_id())?;
6383 Some((server, adapter))
6384 })
6385 .ok()
6386 .flatten();
6387 let Some((server, adapter)) = server_and_adapter else {
6388 continue;
6389 };
6390
6391 let resolved = Self::resolve_completion_local(
6392 server,
6393 completions.clone(),
6394 completion_index,
6395 )
6396 .await
6397 .log_err()
6398 .is_some();
6399 if resolved {
6400 Self::regenerate_completion_labels(
6401 adapter,
6402 &buffer_snapshot,
6403 completions.clone(),
6404 completion_index,
6405 )
6406 .await
6407 .log_err();
6408 did_resolve = true;
6409 }
6410 } else {
6411 resolve_word_completion(
6412 &buffer_snapshot,
6413 &mut completions.borrow_mut()[completion_index],
6414 );
6415 }
6416 }
6417 }
6418
6419 Ok(did_resolve)
6420 })
6421 }
6422
6423 async fn resolve_completion_local(
6424 server: Arc<lsp::LanguageServer>,
6425 completions: Rc<RefCell<Box<[Completion]>>>,
6426 completion_index: usize,
6427 ) -> Result<()> {
6428 let server_id = server.server_id();
6429 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6430 return Ok(());
6431 }
6432
6433 let request = {
6434 let completion = &completions.borrow()[completion_index];
6435 match &completion.source {
6436 CompletionSource::Lsp {
6437 lsp_completion,
6438 resolved,
6439 server_id: completion_server_id,
6440 ..
6441 } => {
6442 if *resolved {
6443 return Ok(());
6444 }
6445 anyhow::ensure!(
6446 server_id == *completion_server_id,
6447 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6448 );
6449 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6450 }
6451 CompletionSource::BufferWord { .. }
6452 | CompletionSource::Dap { .. }
6453 | CompletionSource::Custom => {
6454 return Ok(());
6455 }
6456 }
6457 };
6458 let resolved_completion = request
6459 .await
6460 .into_response()
6461 .context("resolve completion")?;
6462
6463 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6464 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6465
6466 let mut completions = completions.borrow_mut();
6467 let completion = &mut completions[completion_index];
6468 if let CompletionSource::Lsp {
6469 lsp_completion,
6470 resolved,
6471 server_id: completion_server_id,
6472 ..
6473 } = &mut completion.source
6474 {
6475 if *resolved {
6476 return Ok(());
6477 }
6478 anyhow::ensure!(
6479 server_id == *completion_server_id,
6480 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6481 );
6482 **lsp_completion = resolved_completion;
6483 *resolved = true;
6484 }
6485 Ok(())
6486 }
6487
6488 async fn regenerate_completion_labels(
6489 adapter: Arc<CachedLspAdapter>,
6490 snapshot: &BufferSnapshot,
6491 completions: Rc<RefCell<Box<[Completion]>>>,
6492 completion_index: usize,
6493 ) -> Result<()> {
6494 let completion_item = completions.borrow()[completion_index]
6495 .source
6496 .lsp_completion(true)
6497 .map(Cow::into_owned);
6498 if let Some(lsp_documentation) = completion_item
6499 .as_ref()
6500 .and_then(|completion_item| completion_item.documentation.clone())
6501 {
6502 let mut completions = completions.borrow_mut();
6503 let completion = &mut completions[completion_index];
6504 completion.documentation = Some(lsp_documentation.into());
6505 } else {
6506 let mut completions = completions.borrow_mut();
6507 let completion = &mut completions[completion_index];
6508 completion.documentation = Some(CompletionDocumentation::Undocumented);
6509 }
6510
6511 let mut new_label = match completion_item {
6512 Some(completion_item) => {
6513 // 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
6514 // So we have to update the label here anyway...
6515 let language = snapshot.language();
6516 match language {
6517 Some(language) => {
6518 adapter
6519 .labels_for_completions(
6520 std::slice::from_ref(&completion_item),
6521 language,
6522 )
6523 .await?
6524 }
6525 None => Vec::new(),
6526 }
6527 .pop()
6528 .flatten()
6529 .unwrap_or_else(|| {
6530 CodeLabel::fallback_for_completion(
6531 &completion_item,
6532 language.map(|language| language.as_ref()),
6533 )
6534 })
6535 }
6536 None => CodeLabel::plain(
6537 completions.borrow()[completion_index].new_text.clone(),
6538 None,
6539 ),
6540 };
6541 ensure_uniform_list_compatible_label(&mut new_label);
6542
6543 let mut completions = completions.borrow_mut();
6544 let completion = &mut completions[completion_index];
6545 if completion.label.filter_text() == new_label.filter_text() {
6546 completion.label = new_label;
6547 } else {
6548 log::error!(
6549 "Resolved completion changed display label from {} to {}. \
6550 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6551 completion.label.text(),
6552 new_label.text(),
6553 completion.label.filter_text(),
6554 new_label.filter_text()
6555 );
6556 }
6557
6558 Ok(())
6559 }
6560
6561 async fn resolve_completion_remote(
6562 project_id: u64,
6563 server_id: LanguageServerId,
6564 buffer_id: BufferId,
6565 completions: Rc<RefCell<Box<[Completion]>>>,
6566 completion_index: usize,
6567 client: AnyProtoClient,
6568 ) -> Result<()> {
6569 let lsp_completion = {
6570 let completion = &completions.borrow()[completion_index];
6571 match &completion.source {
6572 CompletionSource::Lsp {
6573 lsp_completion,
6574 resolved,
6575 server_id: completion_server_id,
6576 ..
6577 } => {
6578 anyhow::ensure!(
6579 server_id == *completion_server_id,
6580 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6581 );
6582 if *resolved {
6583 return Ok(());
6584 }
6585 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6586 }
6587 CompletionSource::Custom
6588 | CompletionSource::Dap { .. }
6589 | CompletionSource::BufferWord { .. } => {
6590 return Ok(());
6591 }
6592 }
6593 };
6594 let request = proto::ResolveCompletionDocumentation {
6595 project_id,
6596 language_server_id: server_id.0 as u64,
6597 lsp_completion,
6598 buffer_id: buffer_id.into(),
6599 };
6600
6601 let response = client
6602 .request(request)
6603 .await
6604 .context("completion documentation resolve proto request")?;
6605 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6606
6607 let documentation = if response.documentation.is_empty() {
6608 CompletionDocumentation::Undocumented
6609 } else if response.documentation_is_markdown {
6610 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6611 } else if response.documentation.lines().count() <= 1 {
6612 CompletionDocumentation::SingleLine(response.documentation.into())
6613 } else {
6614 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6615 };
6616
6617 let mut completions = completions.borrow_mut();
6618 let completion = &mut completions[completion_index];
6619 completion.documentation = Some(documentation);
6620 if let CompletionSource::Lsp {
6621 insert_range,
6622 lsp_completion,
6623 resolved,
6624 server_id: completion_server_id,
6625 lsp_defaults: _,
6626 } = &mut completion.source
6627 {
6628 let completion_insert_range = response
6629 .old_insert_start
6630 .and_then(deserialize_anchor)
6631 .zip(response.old_insert_end.and_then(deserialize_anchor));
6632 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6633
6634 if *resolved {
6635 return Ok(());
6636 }
6637 anyhow::ensure!(
6638 server_id == *completion_server_id,
6639 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6640 );
6641 **lsp_completion = resolved_lsp_completion;
6642 *resolved = true;
6643 }
6644
6645 let replace_range = response
6646 .old_replace_start
6647 .and_then(deserialize_anchor)
6648 .zip(response.old_replace_end.and_then(deserialize_anchor));
6649 if let Some((old_replace_start, old_replace_end)) = replace_range
6650 && !response.new_text.is_empty()
6651 {
6652 completion.new_text = response.new_text;
6653 completion.replace_range = old_replace_start..old_replace_end;
6654 }
6655
6656 Ok(())
6657 }
6658
6659 pub fn apply_additional_edits_for_completion(
6660 &self,
6661 buffer_handle: Entity<Buffer>,
6662 completions: Rc<RefCell<Box<[Completion]>>>,
6663 completion_index: usize,
6664 push_to_history: bool,
6665 cx: &mut Context<Self>,
6666 ) -> Task<Result<Option<Transaction>>> {
6667 if let Some((client, project_id)) = self.upstream_client() {
6668 let buffer = buffer_handle.read(cx);
6669 let buffer_id = buffer.remote_id();
6670 cx.spawn(async move |_, cx| {
6671 let request = {
6672 let completion = completions.borrow()[completion_index].clone();
6673 proto::ApplyCompletionAdditionalEdits {
6674 project_id,
6675 buffer_id: buffer_id.into(),
6676 completion: Some(Self::serialize_completion(&CoreCompletion {
6677 replace_range: completion.replace_range,
6678 new_text: completion.new_text,
6679 source: completion.source,
6680 })),
6681 }
6682 };
6683
6684 if let Some(transaction) = client.request(request).await?.transaction {
6685 let transaction = language::proto::deserialize_transaction(transaction)?;
6686 buffer_handle
6687 .update(cx, |buffer, _| {
6688 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6689 })?
6690 .await?;
6691 if push_to_history {
6692 buffer_handle.update(cx, |buffer, _| {
6693 buffer.push_transaction(transaction.clone(), Instant::now());
6694 buffer.finalize_last_transaction();
6695 })?;
6696 }
6697 Ok(Some(transaction))
6698 } else {
6699 Ok(None)
6700 }
6701 })
6702 } else {
6703 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6704 let completion = &completions.borrow()[completion_index];
6705 let server_id = completion.source.server_id()?;
6706 Some(
6707 self.language_server_for_local_buffer(buffer, server_id, cx)?
6708 .1
6709 .clone(),
6710 )
6711 }) else {
6712 return Task::ready(Ok(None));
6713 };
6714
6715 cx.spawn(async move |this, cx| {
6716 Self::resolve_completion_local(
6717 server.clone(),
6718 completions.clone(),
6719 completion_index,
6720 )
6721 .await
6722 .context("resolving completion")?;
6723 let completion = completions.borrow()[completion_index].clone();
6724 let additional_text_edits = completion
6725 .source
6726 .lsp_completion(true)
6727 .as_ref()
6728 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6729 if let Some(edits) = additional_text_edits {
6730 let edits = this
6731 .update(cx, |this, cx| {
6732 this.as_local_mut().unwrap().edits_from_lsp(
6733 &buffer_handle,
6734 edits,
6735 server.server_id(),
6736 None,
6737 cx,
6738 )
6739 })?
6740 .await?;
6741
6742 buffer_handle.update(cx, |buffer, cx| {
6743 buffer.finalize_last_transaction();
6744 buffer.start_transaction();
6745
6746 for (range, text) in edits {
6747 let primary = &completion.replace_range;
6748
6749 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6750 // and the primary completion is just an insertion (empty range), then this is likely
6751 // an auto-import scenario and should not be considered overlapping
6752 // https://github.com/zed-industries/zed/issues/26136
6753 let is_file_start_auto_import = {
6754 let snapshot = buffer.snapshot();
6755 let primary_start_point = primary.start.to_point(&snapshot);
6756 let range_start_point = range.start.to_point(&snapshot);
6757
6758 let result = primary_start_point.row == 0
6759 && primary_start_point.column == 0
6760 && range_start_point.row == 0
6761 && range_start_point.column == 0;
6762
6763 result
6764 };
6765
6766 let has_overlap = if is_file_start_auto_import {
6767 false
6768 } else {
6769 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6770 && primary.end.cmp(&range.start, buffer).is_ge();
6771 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6772 && range.end.cmp(&primary.end, buffer).is_ge();
6773 let result = start_within || end_within;
6774 result
6775 };
6776
6777 //Skip additional edits which overlap with the primary completion edit
6778 //https://github.com/zed-industries/zed/pull/1871
6779 if !has_overlap {
6780 buffer.edit([(range, text)], None, cx);
6781 }
6782 }
6783
6784 let transaction = if buffer.end_transaction(cx).is_some() {
6785 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6786 if !push_to_history {
6787 buffer.forget_transaction(transaction.id);
6788 }
6789 Some(transaction)
6790 } else {
6791 None
6792 };
6793 Ok(transaction)
6794 })?
6795 } else {
6796 Ok(None)
6797 }
6798 })
6799 }
6800 }
6801
6802 pub fn pull_diagnostics(
6803 &mut self,
6804 buffer: Entity<Buffer>,
6805 cx: &mut Context<Self>,
6806 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6807 let buffer_id = buffer.read(cx).remote_id();
6808
6809 if let Some((client, upstream_project_id)) = self.upstream_client() {
6810 let mut suitable_capabilities = None;
6811 // Are we capable for proto request?
6812 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6813 &buffer,
6814 |capabilities| {
6815 if let Some(caps) = &capabilities.diagnostic_provider {
6816 suitable_capabilities = Some(caps.clone());
6817 true
6818 } else {
6819 false
6820 }
6821 },
6822 cx,
6823 );
6824 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6825 let Some(dynamic_caps) = suitable_capabilities else {
6826 return Task::ready(Ok(None));
6827 };
6828 assert!(any_server_has_diagnostics_provider);
6829
6830 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6831 let request = GetDocumentDiagnostics {
6832 previous_result_id: None,
6833 identifier,
6834 registration_id: None,
6835 };
6836 let request_task = client.request_lsp(
6837 upstream_project_id,
6838 None,
6839 LSP_REQUEST_TIMEOUT,
6840 cx.background_executor().clone(),
6841 request.to_proto(upstream_project_id, buffer.read(cx)),
6842 );
6843 cx.background_spawn(async move {
6844 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6845 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6846 // Do not attempt to further process the dummy responses here.
6847 let _response = request_task.await?;
6848 Ok(None)
6849 })
6850 } else {
6851 let servers = buffer.update(cx, |buffer, cx| {
6852 self.running_language_servers_for_local_buffer(buffer, cx)
6853 .map(|(_, server)| server.clone())
6854 .collect::<Vec<_>>()
6855 });
6856
6857 let pull_diagnostics = servers
6858 .into_iter()
6859 .flat_map(|server| {
6860 let result = maybe!({
6861 let local = self.as_local()?;
6862 let server_id = server.server_id();
6863 let providers_with_identifiers = local
6864 .language_server_dynamic_registrations
6865 .get(&server_id)
6866 .into_iter()
6867 .flat_map(|registrations| registrations.diagnostics.clone())
6868 .collect::<Vec<_>>();
6869 Some(
6870 providers_with_identifiers
6871 .into_iter()
6872 .map(|(registration_id, dynamic_caps)| {
6873 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6874 let registration_id = registration_id.map(SharedString::from);
6875 let result_id = self.result_id_for_buffer_pull(
6876 server_id,
6877 buffer_id,
6878 ®istration_id,
6879 cx,
6880 );
6881 self.request_lsp(
6882 buffer.clone(),
6883 LanguageServerToQuery::Other(server_id),
6884 GetDocumentDiagnostics {
6885 previous_result_id: result_id,
6886 registration_id,
6887 identifier,
6888 },
6889 cx,
6890 )
6891 })
6892 .collect::<Vec<_>>(),
6893 )
6894 });
6895
6896 result.unwrap_or_default()
6897 })
6898 .collect::<Vec<_>>();
6899
6900 cx.background_spawn(async move {
6901 let mut responses = Vec::new();
6902 for diagnostics in join_all(pull_diagnostics).await {
6903 responses.extend(diagnostics?);
6904 }
6905 Ok(Some(responses))
6906 })
6907 }
6908 }
6909
6910 pub fn applicable_inlay_chunks(
6911 &mut self,
6912 buffer: &Entity<Buffer>,
6913 ranges: &[Range<text::Anchor>],
6914 cx: &mut Context<Self>,
6915 ) -> Vec<Range<BufferRow>> {
6916 let buffer_snapshot = buffer.read(cx).snapshot();
6917 let ranges = ranges
6918 .iter()
6919 .map(|range| range.to_point(&buffer_snapshot))
6920 .collect::<Vec<_>>();
6921
6922 self.latest_lsp_data(buffer, cx)
6923 .inlay_hints
6924 .applicable_chunks(ranges.as_slice())
6925 .map(|chunk| chunk.row_range())
6926 .collect()
6927 }
6928
6929 pub fn invalidate_inlay_hints<'a>(
6930 &'a mut self,
6931 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6932 ) {
6933 for buffer_id in for_buffers {
6934 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6935 lsp_data.inlay_hints.clear();
6936 }
6937 }
6938 }
6939
6940 pub fn inlay_hints(
6941 &mut self,
6942 invalidate: InvalidationStrategy,
6943 buffer: Entity<Buffer>,
6944 ranges: Vec<Range<text::Anchor>>,
6945 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6946 cx: &mut Context<Self>,
6947 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6948 let next_hint_id = self.next_hint_id.clone();
6949 let lsp_data = self.latest_lsp_data(&buffer, cx);
6950 let query_version = lsp_data.buffer_version.clone();
6951 let mut lsp_refresh_requested = false;
6952 let for_server = if let InvalidationStrategy::RefreshRequested {
6953 server_id,
6954 request_id,
6955 } = invalidate
6956 {
6957 let invalidated = lsp_data
6958 .inlay_hints
6959 .invalidate_for_server_refresh(server_id, request_id);
6960 lsp_refresh_requested = invalidated;
6961 Some(server_id)
6962 } else {
6963 None
6964 };
6965 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6966 let known_chunks = known_chunks
6967 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6968 .map(|(_, known_chunks)| known_chunks)
6969 .unwrap_or_default();
6970
6971 let buffer_snapshot = buffer.read(cx).snapshot();
6972 let ranges = ranges
6973 .iter()
6974 .map(|range| range.to_point(&buffer_snapshot))
6975 .collect::<Vec<_>>();
6976
6977 let mut hint_fetch_tasks = Vec::new();
6978 let mut cached_inlay_hints = None;
6979 let mut ranges_to_query = None;
6980 let applicable_chunks = existing_inlay_hints
6981 .applicable_chunks(ranges.as_slice())
6982 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6983 .collect::<Vec<_>>();
6984 if applicable_chunks.is_empty() {
6985 return HashMap::default();
6986 }
6987
6988 for row_chunk in applicable_chunks {
6989 match (
6990 existing_inlay_hints
6991 .cached_hints(&row_chunk)
6992 .filter(|_| !lsp_refresh_requested)
6993 .cloned(),
6994 existing_inlay_hints
6995 .fetched_hints(&row_chunk)
6996 .as_ref()
6997 .filter(|_| !lsp_refresh_requested)
6998 .cloned(),
6999 ) {
7000 (None, None) => {
7001 let chunk_range = row_chunk.anchor_range();
7002 ranges_to_query
7003 .get_or_insert_with(Vec::new)
7004 .push((row_chunk, chunk_range));
7005 }
7006 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7007 (Some(cached_hints), None) => {
7008 for (server_id, cached_hints) in cached_hints {
7009 if for_server.is_none_or(|for_server| for_server == server_id) {
7010 cached_inlay_hints
7011 .get_or_insert_with(HashMap::default)
7012 .entry(row_chunk.row_range())
7013 .or_insert_with(HashMap::default)
7014 .entry(server_id)
7015 .or_insert_with(Vec::new)
7016 .extend(cached_hints);
7017 }
7018 }
7019 }
7020 (Some(cached_hints), Some(fetched_hints)) => {
7021 hint_fetch_tasks.push((row_chunk, fetched_hints));
7022 for (server_id, cached_hints) in cached_hints {
7023 if for_server.is_none_or(|for_server| for_server == server_id) {
7024 cached_inlay_hints
7025 .get_or_insert_with(HashMap::default)
7026 .entry(row_chunk.row_range())
7027 .or_insert_with(HashMap::default)
7028 .entry(server_id)
7029 .or_insert_with(Vec::new)
7030 .extend(cached_hints);
7031 }
7032 }
7033 }
7034 }
7035 }
7036
7037 if hint_fetch_tasks.is_empty()
7038 && ranges_to_query
7039 .as_ref()
7040 .is_none_or(|ranges| ranges.is_empty())
7041 && let Some(cached_inlay_hints) = cached_inlay_hints
7042 {
7043 cached_inlay_hints
7044 .into_iter()
7045 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7046 .collect()
7047 } else {
7048 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7049 let next_hint_id = next_hint_id.clone();
7050 let buffer = buffer.clone();
7051 let query_version = query_version.clone();
7052 let new_inlay_hints = cx
7053 .spawn(async move |lsp_store, cx| {
7054 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7055 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7056 })?;
7057 new_fetch_task
7058 .await
7059 .and_then(|new_hints_by_server| {
7060 lsp_store.update(cx, |lsp_store, cx| {
7061 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7062 let update_cache = lsp_data.buffer_version == query_version;
7063 if new_hints_by_server.is_empty() {
7064 if update_cache {
7065 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7066 }
7067 HashMap::default()
7068 } else {
7069 new_hints_by_server
7070 .into_iter()
7071 .map(|(server_id, new_hints)| {
7072 let new_hints = new_hints
7073 .into_iter()
7074 .map(|new_hint| {
7075 (
7076 InlayId::Hint(next_hint_id.fetch_add(
7077 1,
7078 atomic::Ordering::AcqRel,
7079 )),
7080 new_hint,
7081 )
7082 })
7083 .collect::<Vec<_>>();
7084 if update_cache {
7085 lsp_data.inlay_hints.insert_new_hints(
7086 chunk,
7087 server_id,
7088 new_hints.clone(),
7089 );
7090 }
7091 (server_id, new_hints)
7092 })
7093 .collect()
7094 }
7095 })
7096 })
7097 .map_err(Arc::new)
7098 })
7099 .shared();
7100
7101 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7102 *fetch_task = Some(new_inlay_hints.clone());
7103 hint_fetch_tasks.push((chunk, new_inlay_hints));
7104 }
7105
7106 cached_inlay_hints
7107 .unwrap_or_default()
7108 .into_iter()
7109 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7110 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7111 (
7112 chunk.row_range(),
7113 cx.spawn(async move |_, _| {
7114 hints_fetch.await.map_err(|e| {
7115 if e.error_code() != ErrorCode::Internal {
7116 anyhow!(e.error_code())
7117 } else {
7118 anyhow!("{e:#}")
7119 }
7120 })
7121 }),
7122 )
7123 }))
7124 .collect()
7125 }
7126 }
7127
7128 fn fetch_inlay_hints(
7129 &mut self,
7130 for_server: Option<LanguageServerId>,
7131 buffer: &Entity<Buffer>,
7132 range: Range<Anchor>,
7133 cx: &mut Context<Self>,
7134 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7135 let request = InlayHints {
7136 range: range.clone(),
7137 };
7138 if let Some((upstream_client, project_id)) = self.upstream_client() {
7139 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7140 return Task::ready(Ok(HashMap::default()));
7141 }
7142 let request_task = upstream_client.request_lsp(
7143 project_id,
7144 for_server.map(|id| id.to_proto()),
7145 LSP_REQUEST_TIMEOUT,
7146 cx.background_executor().clone(),
7147 request.to_proto(project_id, buffer.read(cx)),
7148 );
7149 let buffer = buffer.clone();
7150 cx.spawn(async move |weak_lsp_store, cx| {
7151 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7152 return Ok(HashMap::default());
7153 };
7154 let Some(responses) = request_task.await? else {
7155 return Ok(HashMap::default());
7156 };
7157
7158 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7159 let lsp_store = lsp_store.clone();
7160 let buffer = buffer.clone();
7161 let cx = cx.clone();
7162 let request = request.clone();
7163 async move {
7164 (
7165 LanguageServerId::from_proto(response.server_id),
7166 request
7167 .response_from_proto(response.response, lsp_store, buffer, cx)
7168 .await,
7169 )
7170 }
7171 }))
7172 .await;
7173
7174 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7175 let mut has_errors = false;
7176 let inlay_hints = inlay_hints
7177 .into_iter()
7178 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7179 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7180 Err(e) => {
7181 has_errors = true;
7182 log::error!("{e:#}");
7183 None
7184 }
7185 })
7186 .map(|(server_id, mut new_hints)| {
7187 new_hints.retain(|hint| {
7188 hint.position.is_valid(&buffer_snapshot)
7189 && range.start.is_valid(&buffer_snapshot)
7190 && range.end.is_valid(&buffer_snapshot)
7191 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7192 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7193 });
7194 (server_id, new_hints)
7195 })
7196 .collect::<HashMap<_, _>>();
7197 anyhow::ensure!(
7198 !has_errors || !inlay_hints.is_empty(),
7199 "Failed to fetch inlay hints"
7200 );
7201 Ok(inlay_hints)
7202 })
7203 } else {
7204 let inlay_hints_task = match for_server {
7205 Some(server_id) => {
7206 let server_task = self.request_lsp(
7207 buffer.clone(),
7208 LanguageServerToQuery::Other(server_id),
7209 request,
7210 cx,
7211 );
7212 cx.background_spawn(async move {
7213 let mut responses = Vec::new();
7214 match server_task.await {
7215 Ok(response) => responses.push((server_id, response)),
7216 // rust-analyzer likes to error with this when its still loading up
7217 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7218 Err(e) => log::error!(
7219 "Error handling response for inlay hints request: {e:#}"
7220 ),
7221 }
7222 responses
7223 })
7224 }
7225 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7226 };
7227 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7228 cx.background_spawn(async move {
7229 Ok(inlay_hints_task
7230 .await
7231 .into_iter()
7232 .map(|(server_id, mut new_hints)| {
7233 new_hints.retain(|hint| {
7234 hint.position.is_valid(&buffer_snapshot)
7235 && range.start.is_valid(&buffer_snapshot)
7236 && range.end.is_valid(&buffer_snapshot)
7237 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7238 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7239 });
7240 (server_id, new_hints)
7241 })
7242 .collect())
7243 })
7244 }
7245 }
7246
7247 pub fn pull_diagnostics_for_buffer(
7248 &mut self,
7249 buffer: Entity<Buffer>,
7250 cx: &mut Context<Self>,
7251 ) -> Task<anyhow::Result<()>> {
7252 let diagnostics = self.pull_diagnostics(buffer, cx);
7253 cx.spawn(async move |lsp_store, cx| {
7254 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7255 return Ok(());
7256 };
7257 lsp_store.update(cx, |lsp_store, cx| {
7258 if lsp_store.as_local().is_none() {
7259 return;
7260 }
7261
7262 let mut unchanged_buffers = HashMap::default();
7263 let server_diagnostics_updates = diagnostics
7264 .into_iter()
7265 .filter_map(|diagnostics_set| match diagnostics_set {
7266 LspPullDiagnostics::Response {
7267 server_id,
7268 uri,
7269 diagnostics,
7270 registration_id,
7271 } => Some((server_id, uri, diagnostics, registration_id)),
7272 LspPullDiagnostics::Default => None,
7273 })
7274 .fold(
7275 HashMap::default(),
7276 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7277 let (result_id, diagnostics) = match diagnostics {
7278 PulledDiagnostics::Unchanged { result_id } => {
7279 unchanged_buffers
7280 .entry(new_registration_id.clone())
7281 .or_insert_with(HashSet::default)
7282 .insert(uri.clone());
7283 (Some(result_id), Vec::new())
7284 }
7285 PulledDiagnostics::Changed {
7286 result_id,
7287 diagnostics,
7288 } => (result_id, diagnostics),
7289 };
7290 let disk_based_sources = Cow::Owned(
7291 lsp_store
7292 .language_server_adapter_for_id(server_id)
7293 .as_ref()
7294 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7295 .unwrap_or(&[])
7296 .to_vec(),
7297 );
7298 acc.entry(server_id)
7299 .or_insert_with(HashMap::default)
7300 .entry(new_registration_id.clone())
7301 .or_insert_with(Vec::new)
7302 .push(DocumentDiagnosticsUpdate {
7303 server_id,
7304 diagnostics: lsp::PublishDiagnosticsParams {
7305 uri,
7306 diagnostics,
7307 version: None,
7308 },
7309 result_id,
7310 disk_based_sources,
7311 registration_id: new_registration_id,
7312 });
7313 acc
7314 },
7315 );
7316
7317 for diagnostic_updates in server_diagnostics_updates.into_values() {
7318 for (registration_id, diagnostic_updates) in diagnostic_updates {
7319 lsp_store
7320 .merge_lsp_diagnostics(
7321 DiagnosticSourceKind::Pulled,
7322 diagnostic_updates,
7323 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7324 DiagnosticSourceKind::Pulled => {
7325 old_diagnostic.registration_id != registration_id
7326 || unchanged_buffers
7327 .get(&old_diagnostic.registration_id)
7328 .is_some_and(|unchanged_buffers| {
7329 unchanged_buffers.contains(&document_uri)
7330 })
7331 }
7332 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7333 true
7334 }
7335 },
7336 cx,
7337 )
7338 .log_err();
7339 }
7340 }
7341 })
7342 })
7343 }
7344
7345 pub fn document_colors(
7346 &mut self,
7347 known_cache_version: Option<usize>,
7348 buffer: Entity<Buffer>,
7349 cx: &mut Context<Self>,
7350 ) -> Option<DocumentColorTask> {
7351 let version_queried_for = buffer.read(cx).version();
7352 let buffer_id = buffer.read(cx).remote_id();
7353
7354 let current_language_servers = self.as_local().map(|local| {
7355 local
7356 .buffers_opened_in_servers
7357 .get(&buffer_id)
7358 .cloned()
7359 .unwrap_or_default()
7360 });
7361
7362 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7363 if let Some(cached_colors) = &lsp_data.document_colors {
7364 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7365 let has_different_servers =
7366 current_language_servers.is_some_and(|current_language_servers| {
7367 current_language_servers
7368 != cached_colors.colors.keys().copied().collect()
7369 });
7370 if !has_different_servers {
7371 let cache_version = cached_colors.cache_version;
7372 if Some(cache_version) == known_cache_version {
7373 return None;
7374 } else {
7375 return Some(
7376 Task::ready(Ok(DocumentColors {
7377 colors: cached_colors
7378 .colors
7379 .values()
7380 .flatten()
7381 .cloned()
7382 .collect(),
7383 cache_version: Some(cache_version),
7384 }))
7385 .shared(),
7386 );
7387 }
7388 }
7389 }
7390 }
7391 }
7392
7393 let color_lsp_data = self
7394 .latest_lsp_data(&buffer, cx)
7395 .document_colors
7396 .get_or_insert_default();
7397 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7398 && !version_queried_for.changed_since(updating_for)
7399 {
7400 return Some(running_update.clone());
7401 }
7402 let buffer_version_queried_for = version_queried_for.clone();
7403 let new_task = cx
7404 .spawn(async move |lsp_store, cx| {
7405 cx.background_executor()
7406 .timer(Duration::from_millis(30))
7407 .await;
7408 let fetched_colors = lsp_store
7409 .update(cx, |lsp_store, cx| {
7410 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7411 })?
7412 .await
7413 .context("fetching document colors")
7414 .map_err(Arc::new);
7415 let fetched_colors = match fetched_colors {
7416 Ok(fetched_colors) => {
7417 if Some(true)
7418 == buffer
7419 .update(cx, |buffer, _| {
7420 buffer.version() != buffer_version_queried_for
7421 })
7422 .ok()
7423 {
7424 return Ok(DocumentColors::default());
7425 }
7426 fetched_colors
7427 }
7428 Err(e) => {
7429 lsp_store
7430 .update(cx, |lsp_store, _| {
7431 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7432 if let Some(document_colors) = &mut lsp_data.document_colors {
7433 document_colors.colors_update = None;
7434 }
7435 }
7436 })
7437 .ok();
7438 return Err(e);
7439 }
7440 };
7441
7442 lsp_store
7443 .update(cx, |lsp_store, cx| {
7444 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7445 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7446
7447 if let Some(fetched_colors) = fetched_colors {
7448 if lsp_data.buffer_version == buffer_version_queried_for {
7449 lsp_colors.colors.extend(fetched_colors);
7450 lsp_colors.cache_version += 1;
7451 } else if !lsp_data
7452 .buffer_version
7453 .changed_since(&buffer_version_queried_for)
7454 {
7455 lsp_data.buffer_version = buffer_version_queried_for;
7456 lsp_colors.colors = fetched_colors;
7457 lsp_colors.cache_version += 1;
7458 }
7459 }
7460 lsp_colors.colors_update = None;
7461 let colors = lsp_colors
7462 .colors
7463 .values()
7464 .flatten()
7465 .cloned()
7466 .collect::<HashSet<_>>();
7467 DocumentColors {
7468 colors,
7469 cache_version: Some(lsp_colors.cache_version),
7470 }
7471 })
7472 .map_err(Arc::new)
7473 })
7474 .shared();
7475 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7476 Some(new_task)
7477 }
7478
7479 fn fetch_document_colors_for_buffer(
7480 &mut self,
7481 buffer: &Entity<Buffer>,
7482 cx: &mut Context<Self>,
7483 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7484 if let Some((client, project_id)) = self.upstream_client() {
7485 let request = GetDocumentColor {};
7486 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7487 return Task::ready(Ok(None));
7488 }
7489
7490 let request_task = client.request_lsp(
7491 project_id,
7492 None,
7493 LSP_REQUEST_TIMEOUT,
7494 cx.background_executor().clone(),
7495 request.to_proto(project_id, buffer.read(cx)),
7496 );
7497 let buffer = buffer.clone();
7498 cx.spawn(async move |lsp_store, cx| {
7499 let Some(lsp_store) = lsp_store.upgrade() else {
7500 return Ok(None);
7501 };
7502 let colors = join_all(
7503 request_task
7504 .await
7505 .log_err()
7506 .flatten()
7507 .map(|response| response.payload)
7508 .unwrap_or_default()
7509 .into_iter()
7510 .map(|color_response| {
7511 let response = request.response_from_proto(
7512 color_response.response,
7513 lsp_store.clone(),
7514 buffer.clone(),
7515 cx.clone(),
7516 );
7517 async move {
7518 (
7519 LanguageServerId::from_proto(color_response.server_id),
7520 response.await.log_err().unwrap_or_default(),
7521 )
7522 }
7523 }),
7524 )
7525 .await
7526 .into_iter()
7527 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7528 acc.entry(server_id)
7529 .or_insert_with(HashSet::default)
7530 .extend(colors);
7531 acc
7532 });
7533 Ok(Some(colors))
7534 })
7535 } else {
7536 let document_colors_task =
7537 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7538 cx.background_spawn(async move {
7539 Ok(Some(
7540 document_colors_task
7541 .await
7542 .into_iter()
7543 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7544 acc.entry(server_id)
7545 .or_insert_with(HashSet::default)
7546 .extend(colors);
7547 acc
7548 })
7549 .into_iter()
7550 .collect(),
7551 ))
7552 })
7553 }
7554 }
7555
7556 pub fn signature_help<T: ToPointUtf16>(
7557 &mut self,
7558 buffer: &Entity<Buffer>,
7559 position: T,
7560 cx: &mut Context<Self>,
7561 ) -> Task<Option<Vec<SignatureHelp>>> {
7562 let position = position.to_point_utf16(buffer.read(cx));
7563
7564 if let Some((client, upstream_project_id)) = self.upstream_client() {
7565 let request = GetSignatureHelp { position };
7566 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7567 return Task::ready(None);
7568 }
7569 let request_task = client.request_lsp(
7570 upstream_project_id,
7571 None,
7572 LSP_REQUEST_TIMEOUT,
7573 cx.background_executor().clone(),
7574 request.to_proto(upstream_project_id, buffer.read(cx)),
7575 );
7576 let buffer = buffer.clone();
7577 cx.spawn(async move |weak_lsp_store, cx| {
7578 let lsp_store = weak_lsp_store.upgrade()?;
7579 let signatures = join_all(
7580 request_task
7581 .await
7582 .log_err()
7583 .flatten()
7584 .map(|response| response.payload)
7585 .unwrap_or_default()
7586 .into_iter()
7587 .map(|response| {
7588 let response = GetSignatureHelp { position }.response_from_proto(
7589 response.response,
7590 lsp_store.clone(),
7591 buffer.clone(),
7592 cx.clone(),
7593 );
7594 async move { response.await.log_err().flatten() }
7595 }),
7596 )
7597 .await
7598 .into_iter()
7599 .flatten()
7600 .collect();
7601 Some(signatures)
7602 })
7603 } else {
7604 let all_actions_task = self.request_multiple_lsp_locally(
7605 buffer,
7606 Some(position),
7607 GetSignatureHelp { position },
7608 cx,
7609 );
7610 cx.background_spawn(async move {
7611 Some(
7612 all_actions_task
7613 .await
7614 .into_iter()
7615 .flat_map(|(_, actions)| actions)
7616 .collect::<Vec<_>>(),
7617 )
7618 })
7619 }
7620 }
7621
7622 pub fn hover(
7623 &mut self,
7624 buffer: &Entity<Buffer>,
7625 position: PointUtf16,
7626 cx: &mut Context<Self>,
7627 ) -> Task<Option<Vec<Hover>>> {
7628 if let Some((client, upstream_project_id)) = self.upstream_client() {
7629 let request = GetHover { position };
7630 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7631 return Task::ready(None);
7632 }
7633 let request_task = client.request_lsp(
7634 upstream_project_id,
7635 None,
7636 LSP_REQUEST_TIMEOUT,
7637 cx.background_executor().clone(),
7638 request.to_proto(upstream_project_id, buffer.read(cx)),
7639 );
7640 let buffer = buffer.clone();
7641 cx.spawn(async move |weak_lsp_store, cx| {
7642 let lsp_store = weak_lsp_store.upgrade()?;
7643 let hovers = join_all(
7644 request_task
7645 .await
7646 .log_err()
7647 .flatten()
7648 .map(|response| response.payload)
7649 .unwrap_or_default()
7650 .into_iter()
7651 .map(|response| {
7652 let response = GetHover { position }.response_from_proto(
7653 response.response,
7654 lsp_store.clone(),
7655 buffer.clone(),
7656 cx.clone(),
7657 );
7658 async move {
7659 response
7660 .await
7661 .log_err()
7662 .flatten()
7663 .and_then(remove_empty_hover_blocks)
7664 }
7665 }),
7666 )
7667 .await
7668 .into_iter()
7669 .flatten()
7670 .collect();
7671 Some(hovers)
7672 })
7673 } else {
7674 let all_actions_task = self.request_multiple_lsp_locally(
7675 buffer,
7676 Some(position),
7677 GetHover { position },
7678 cx,
7679 );
7680 cx.background_spawn(async move {
7681 Some(
7682 all_actions_task
7683 .await
7684 .into_iter()
7685 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7686 .collect::<Vec<Hover>>(),
7687 )
7688 })
7689 }
7690 }
7691
7692 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7693 let language_registry = self.languages.clone();
7694
7695 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7696 let request = upstream_client.request(proto::GetProjectSymbols {
7697 project_id: *project_id,
7698 query: query.to_string(),
7699 });
7700 cx.foreground_executor().spawn(async move {
7701 let response = request.await?;
7702 let mut symbols = Vec::new();
7703 let core_symbols = response
7704 .symbols
7705 .into_iter()
7706 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7707 .collect::<Vec<_>>();
7708 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7709 .await;
7710 Ok(symbols)
7711 })
7712 } else if let Some(local) = self.as_local() {
7713 struct WorkspaceSymbolsResult {
7714 server_id: LanguageServerId,
7715 lsp_adapter: Arc<CachedLspAdapter>,
7716 worktree: WeakEntity<Worktree>,
7717 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7718 }
7719
7720 let mut requests = Vec::new();
7721 let mut requested_servers = BTreeSet::new();
7722 for (seed, state) in local.language_server_ids.iter() {
7723 let Some(worktree_handle) = self
7724 .worktree_store
7725 .read(cx)
7726 .worktree_for_id(seed.worktree_id, cx)
7727 else {
7728 continue;
7729 };
7730 let worktree = worktree_handle.read(cx);
7731 if !worktree.is_visible() {
7732 continue;
7733 }
7734
7735 if !requested_servers.insert(state.id) {
7736 continue;
7737 }
7738
7739 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7740 Some(LanguageServerState::Running {
7741 adapter, server, ..
7742 }) => (adapter.clone(), server),
7743
7744 _ => continue,
7745 };
7746 let supports_workspace_symbol_request =
7747 match server.capabilities().workspace_symbol_provider {
7748 Some(OneOf::Left(supported)) => supported,
7749 Some(OneOf::Right(_)) => true,
7750 None => false,
7751 };
7752 if !supports_workspace_symbol_request {
7753 continue;
7754 }
7755 let worktree_handle = worktree_handle.clone();
7756 let server_id = server.server_id();
7757 requests.push(
7758 server
7759 .request::<lsp::request::WorkspaceSymbolRequest>(
7760 lsp::WorkspaceSymbolParams {
7761 query: query.to_string(),
7762 ..Default::default()
7763 },
7764 )
7765 .map(move |response| {
7766 let lsp_symbols = response.into_response()
7767 .context("workspace symbols request")
7768 .log_err()
7769 .flatten()
7770 .map(|symbol_response| match symbol_response {
7771 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7772 flat_responses.into_iter().map(|lsp_symbol| {
7773 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7774 }).collect::<Vec<_>>()
7775 }
7776 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7777 nested_responses.into_iter().filter_map(|lsp_symbol| {
7778 let location = match lsp_symbol.location {
7779 OneOf::Left(location) => location,
7780 OneOf::Right(_) => {
7781 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7782 return None
7783 }
7784 };
7785 Some((lsp_symbol.name, lsp_symbol.kind, location))
7786 }).collect::<Vec<_>>()
7787 }
7788 }).unwrap_or_default();
7789
7790 WorkspaceSymbolsResult {
7791 server_id,
7792 lsp_adapter,
7793 worktree: worktree_handle.downgrade(),
7794 lsp_symbols,
7795 }
7796 }),
7797 );
7798 }
7799
7800 cx.spawn(async move |this, cx| {
7801 let responses = futures::future::join_all(requests).await;
7802 let this = match this.upgrade() {
7803 Some(this) => this,
7804 None => return Ok(Vec::new()),
7805 };
7806
7807 let mut symbols = Vec::new();
7808 for result in responses {
7809 let core_symbols = this.update(cx, |this, cx| {
7810 result
7811 .lsp_symbols
7812 .into_iter()
7813 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7814 let abs_path = symbol_location.uri.to_file_path().ok()?;
7815 let source_worktree = result.worktree.upgrade()?;
7816 let source_worktree_id = source_worktree.read(cx).id();
7817
7818 let path = if let Some((tree, rel_path)) =
7819 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7820 {
7821 let worktree_id = tree.read(cx).id();
7822 SymbolLocation::InProject(ProjectPath {
7823 worktree_id,
7824 path: rel_path,
7825 })
7826 } else {
7827 SymbolLocation::OutsideProject {
7828 signature: this.symbol_signature(&abs_path),
7829 abs_path: abs_path.into(),
7830 }
7831 };
7832
7833 Some(CoreSymbol {
7834 source_language_server_id: result.server_id,
7835 language_server_name: result.lsp_adapter.name.clone(),
7836 source_worktree_id,
7837 path,
7838 kind: symbol_kind,
7839 name: symbol_name,
7840 range: range_from_lsp(symbol_location.range),
7841 })
7842 })
7843 .collect()
7844 })?;
7845
7846 populate_labels_for_symbols(
7847 core_symbols,
7848 &language_registry,
7849 Some(result.lsp_adapter),
7850 &mut symbols,
7851 )
7852 .await;
7853 }
7854
7855 Ok(symbols)
7856 })
7857 } else {
7858 Task::ready(Err(anyhow!("No upstream client or local language server")))
7859 }
7860 }
7861
7862 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7863 let mut summary = DiagnosticSummary::default();
7864 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7865 summary.error_count += path_summary.error_count;
7866 summary.warning_count += path_summary.warning_count;
7867 }
7868 summary
7869 }
7870
7871 /// Returns the diagnostic summary for a specific project path.
7872 pub fn diagnostic_summary_for_path(
7873 &self,
7874 project_path: &ProjectPath,
7875 _: &App,
7876 ) -> DiagnosticSummary {
7877 if let Some(summaries) = self
7878 .diagnostic_summaries
7879 .get(&project_path.worktree_id)
7880 .and_then(|map| map.get(&project_path.path))
7881 {
7882 let (error_count, warning_count) = summaries.iter().fold(
7883 (0, 0),
7884 |(error_count, warning_count), (_language_server_id, summary)| {
7885 (
7886 error_count + summary.error_count,
7887 warning_count + summary.warning_count,
7888 )
7889 },
7890 );
7891
7892 DiagnosticSummary {
7893 error_count,
7894 warning_count,
7895 }
7896 } else {
7897 DiagnosticSummary::default()
7898 }
7899 }
7900
7901 pub fn diagnostic_summaries<'a>(
7902 &'a self,
7903 include_ignored: bool,
7904 cx: &'a App,
7905 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7906 self.worktree_store
7907 .read(cx)
7908 .visible_worktrees(cx)
7909 .filter_map(|worktree| {
7910 let worktree = worktree.read(cx);
7911 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7912 })
7913 .flat_map(move |(worktree, summaries)| {
7914 let worktree_id = worktree.id();
7915 summaries
7916 .iter()
7917 .filter(move |(path, _)| {
7918 include_ignored
7919 || worktree
7920 .entry_for_path(path.as_ref())
7921 .is_some_and(|entry| !entry.is_ignored)
7922 })
7923 .flat_map(move |(path, summaries)| {
7924 summaries.iter().map(move |(server_id, summary)| {
7925 (
7926 ProjectPath {
7927 worktree_id,
7928 path: path.clone(),
7929 },
7930 *server_id,
7931 *summary,
7932 )
7933 })
7934 })
7935 })
7936 }
7937
7938 pub fn on_buffer_edited(
7939 &mut self,
7940 buffer: Entity<Buffer>,
7941 cx: &mut Context<Self>,
7942 ) -> Option<()> {
7943 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7944 Some(
7945 self.as_local()?
7946 .language_servers_for_buffer(buffer, cx)
7947 .map(|i| i.1.clone())
7948 .collect(),
7949 )
7950 })?;
7951
7952 let buffer = buffer.read(cx);
7953 let file = File::from_dyn(buffer.file())?;
7954 let abs_path = file.as_local()?.abs_path(cx);
7955 let uri = lsp::Uri::from_file_path(&abs_path)
7956 .ok()
7957 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7958 .log_err()?;
7959 let next_snapshot = buffer.text_snapshot();
7960 for language_server in language_servers {
7961 let language_server = language_server.clone();
7962
7963 let buffer_snapshots = self
7964 .as_local_mut()?
7965 .buffer_snapshots
7966 .get_mut(&buffer.remote_id())
7967 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7968 let previous_snapshot = buffer_snapshots.last()?;
7969
7970 let build_incremental_change = || {
7971 buffer
7972 .edits_since::<Dimensions<PointUtf16, usize>>(
7973 previous_snapshot.snapshot.version(),
7974 )
7975 .map(|edit| {
7976 let edit_start = edit.new.start.0;
7977 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7978 let new_text = next_snapshot
7979 .text_for_range(edit.new.start.1..edit.new.end.1)
7980 .collect();
7981 lsp::TextDocumentContentChangeEvent {
7982 range: Some(lsp::Range::new(
7983 point_to_lsp(edit_start),
7984 point_to_lsp(edit_end),
7985 )),
7986 range_length: None,
7987 text: new_text,
7988 }
7989 })
7990 .collect()
7991 };
7992
7993 let document_sync_kind = language_server
7994 .capabilities()
7995 .text_document_sync
7996 .as_ref()
7997 .and_then(|sync| match sync {
7998 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7999 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8000 });
8001
8002 let content_changes: Vec<_> = match document_sync_kind {
8003 Some(lsp::TextDocumentSyncKind::FULL) => {
8004 vec![lsp::TextDocumentContentChangeEvent {
8005 range: None,
8006 range_length: None,
8007 text: next_snapshot.text(),
8008 }]
8009 }
8010 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8011 _ => {
8012 #[cfg(any(test, feature = "test-support"))]
8013 {
8014 build_incremental_change()
8015 }
8016
8017 #[cfg(not(any(test, feature = "test-support")))]
8018 {
8019 continue;
8020 }
8021 }
8022 };
8023
8024 let next_version = previous_snapshot.version + 1;
8025 buffer_snapshots.push(LspBufferSnapshot {
8026 version: next_version,
8027 snapshot: next_snapshot.clone(),
8028 });
8029
8030 language_server
8031 .notify::<lsp::notification::DidChangeTextDocument>(
8032 lsp::DidChangeTextDocumentParams {
8033 text_document: lsp::VersionedTextDocumentIdentifier::new(
8034 uri.clone(),
8035 next_version,
8036 ),
8037 content_changes,
8038 },
8039 )
8040 .ok();
8041 self.pull_workspace_diagnostics(language_server.server_id());
8042 }
8043
8044 None
8045 }
8046
8047 pub fn on_buffer_saved(
8048 &mut self,
8049 buffer: Entity<Buffer>,
8050 cx: &mut Context<Self>,
8051 ) -> Option<()> {
8052 let file = File::from_dyn(buffer.read(cx).file())?;
8053 let worktree_id = file.worktree_id(cx);
8054 let abs_path = file.as_local()?.abs_path(cx);
8055 let text_document = lsp::TextDocumentIdentifier {
8056 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8057 };
8058 let local = self.as_local()?;
8059
8060 for server in local.language_servers_for_worktree(worktree_id) {
8061 if let Some(include_text) = include_text(server.as_ref()) {
8062 let text = if include_text {
8063 Some(buffer.read(cx).text())
8064 } else {
8065 None
8066 };
8067 server
8068 .notify::<lsp::notification::DidSaveTextDocument>(
8069 lsp::DidSaveTextDocumentParams {
8070 text_document: text_document.clone(),
8071 text,
8072 },
8073 )
8074 .ok();
8075 }
8076 }
8077
8078 let language_servers = buffer.update(cx, |buffer, cx| {
8079 local.language_server_ids_for_buffer(buffer, cx)
8080 });
8081 for language_server_id in language_servers {
8082 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8083 }
8084
8085 None
8086 }
8087
8088 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8089 maybe!(async move {
8090 let mut refreshed_servers = HashSet::default();
8091 let servers = lsp_store
8092 .update(cx, |lsp_store, cx| {
8093 let local = lsp_store.as_local()?;
8094
8095 let servers = local
8096 .language_server_ids
8097 .iter()
8098 .filter_map(|(seed, state)| {
8099 let worktree = lsp_store
8100 .worktree_store
8101 .read(cx)
8102 .worktree_for_id(seed.worktree_id, cx);
8103 let delegate: Arc<dyn LspAdapterDelegate> =
8104 worktree.map(|worktree| {
8105 LocalLspAdapterDelegate::new(
8106 local.languages.clone(),
8107 &local.environment,
8108 cx.weak_entity(),
8109 &worktree,
8110 local.http_client.clone(),
8111 local.fs.clone(),
8112 cx,
8113 )
8114 })?;
8115 let server_id = state.id;
8116
8117 let states = local.language_servers.get(&server_id)?;
8118
8119 match states {
8120 LanguageServerState::Starting { .. } => None,
8121 LanguageServerState::Running {
8122 adapter, server, ..
8123 } => {
8124 let adapter = adapter.clone();
8125 let server = server.clone();
8126 refreshed_servers.insert(server.name());
8127 let toolchain = seed.toolchain.clone();
8128 Some(cx.spawn(async move |_, cx| {
8129 let settings =
8130 LocalLspStore::workspace_configuration_for_adapter(
8131 adapter.adapter.clone(),
8132 &delegate,
8133 toolchain,
8134 None,
8135 cx,
8136 )
8137 .await
8138 .ok()?;
8139 server
8140 .notify::<lsp::notification::DidChangeConfiguration>(
8141 lsp::DidChangeConfigurationParams { settings },
8142 )
8143 .ok()?;
8144 Some(())
8145 }))
8146 }
8147 }
8148 })
8149 .collect::<Vec<_>>();
8150
8151 Some(servers)
8152 })
8153 .ok()
8154 .flatten()?;
8155
8156 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8157 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8158 // to stop and unregister its language server wrapper.
8159 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8160 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8161 let _: Vec<Option<()>> = join_all(servers).await;
8162
8163 Some(())
8164 })
8165 .await;
8166 }
8167
8168 fn maintain_workspace_config(
8169 external_refresh_requests: watch::Receiver<()>,
8170 cx: &mut Context<Self>,
8171 ) -> Task<Result<()>> {
8172 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8173 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8174
8175 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8176 *settings_changed_tx.borrow_mut() = ();
8177 });
8178
8179 let mut joint_future =
8180 futures::stream::select(settings_changed_rx, external_refresh_requests);
8181 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8182 // - 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).
8183 // - 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.
8184 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8185 // - 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,
8186 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8187 cx.spawn(async move |this, cx| {
8188 while let Some(()) = joint_future.next().await {
8189 this.update(cx, |this, cx| {
8190 this.refresh_server_tree(cx);
8191 })
8192 .ok();
8193
8194 Self::refresh_workspace_configurations(&this, cx).await;
8195 }
8196
8197 drop(settings_observation);
8198 anyhow::Ok(())
8199 })
8200 }
8201
8202 pub fn running_language_servers_for_local_buffer<'a>(
8203 &'a self,
8204 buffer: &Buffer,
8205 cx: &mut App,
8206 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8207 let local = self.as_local();
8208 let language_server_ids = local
8209 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8210 .unwrap_or_default();
8211
8212 language_server_ids
8213 .into_iter()
8214 .filter_map(
8215 move |server_id| match local?.language_servers.get(&server_id)? {
8216 LanguageServerState::Running {
8217 adapter, server, ..
8218 } => Some((adapter, server)),
8219 _ => None,
8220 },
8221 )
8222 }
8223
8224 pub fn language_servers_for_local_buffer(
8225 &self,
8226 buffer: &Buffer,
8227 cx: &mut App,
8228 ) -> Vec<LanguageServerId> {
8229 let local = self.as_local();
8230 local
8231 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8232 .unwrap_or_default()
8233 }
8234
8235 pub fn language_server_for_local_buffer<'a>(
8236 &'a self,
8237 buffer: &'a Buffer,
8238 server_id: LanguageServerId,
8239 cx: &'a mut App,
8240 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8241 self.as_local()?
8242 .language_servers_for_buffer(buffer, cx)
8243 .find(|(_, s)| s.server_id() == server_id)
8244 }
8245
8246 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8247 self.diagnostic_summaries.remove(&id_to_remove);
8248 if let Some(local) = self.as_local_mut() {
8249 let to_remove = local.remove_worktree(id_to_remove, cx);
8250 for server in to_remove {
8251 self.language_server_statuses.remove(&server);
8252 }
8253 }
8254 }
8255
8256 pub fn shared(
8257 &mut self,
8258 project_id: u64,
8259 downstream_client: AnyProtoClient,
8260 _: &mut Context<Self>,
8261 ) {
8262 self.downstream_client = Some((downstream_client.clone(), project_id));
8263
8264 for (server_id, status) in &self.language_server_statuses {
8265 if let Some(server) = self.language_server_for_id(*server_id) {
8266 downstream_client
8267 .send(proto::StartLanguageServer {
8268 project_id,
8269 server: Some(proto::LanguageServer {
8270 id: server_id.to_proto(),
8271 name: status.name.to_string(),
8272 worktree_id: status.worktree.map(|id| id.to_proto()),
8273 }),
8274 capabilities: serde_json::to_string(&server.capabilities())
8275 .expect("serializing server LSP capabilities"),
8276 })
8277 .log_err();
8278 }
8279 }
8280 }
8281
8282 pub fn disconnected_from_host(&mut self) {
8283 self.downstream_client.take();
8284 }
8285
8286 pub fn disconnected_from_ssh_remote(&mut self) {
8287 if let LspStoreMode::Remote(RemoteLspStore {
8288 upstream_client, ..
8289 }) = &mut self.mode
8290 {
8291 upstream_client.take();
8292 }
8293 }
8294
8295 pub(crate) fn set_language_server_statuses_from_proto(
8296 &mut self,
8297 project: WeakEntity<Project>,
8298 language_servers: Vec<proto::LanguageServer>,
8299 server_capabilities: Vec<String>,
8300 cx: &mut Context<Self>,
8301 ) {
8302 let lsp_logs = cx
8303 .try_global::<GlobalLogStore>()
8304 .map(|lsp_store| lsp_store.0.clone());
8305
8306 self.language_server_statuses = language_servers
8307 .into_iter()
8308 .zip(server_capabilities)
8309 .map(|(server, server_capabilities)| {
8310 let server_id = LanguageServerId(server.id as usize);
8311 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8312 self.lsp_server_capabilities
8313 .insert(server_id, server_capabilities);
8314 }
8315
8316 let name = LanguageServerName::from_proto(server.name);
8317 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8318
8319 if let Some(lsp_logs) = &lsp_logs {
8320 lsp_logs.update(cx, |lsp_logs, cx| {
8321 lsp_logs.add_language_server(
8322 // Only remote clients get their language servers set from proto
8323 LanguageServerKind::Remote {
8324 project: project.clone(),
8325 },
8326 server_id,
8327 Some(name.clone()),
8328 worktree,
8329 None,
8330 cx,
8331 );
8332 });
8333 }
8334
8335 (
8336 server_id,
8337 LanguageServerStatus {
8338 name,
8339 pending_work: Default::default(),
8340 has_pending_diagnostic_updates: false,
8341 progress_tokens: Default::default(),
8342 worktree,
8343 binary: None,
8344 configuration: None,
8345 workspace_folders: BTreeSet::new(),
8346 },
8347 )
8348 })
8349 .collect();
8350 }
8351
8352 #[cfg(test)]
8353 pub fn update_diagnostic_entries(
8354 &mut self,
8355 server_id: LanguageServerId,
8356 abs_path: PathBuf,
8357 result_id: Option<SharedString>,
8358 version: Option<i32>,
8359 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8360 cx: &mut Context<Self>,
8361 ) -> anyhow::Result<()> {
8362 self.merge_diagnostic_entries(
8363 vec![DocumentDiagnosticsUpdate {
8364 diagnostics: DocumentDiagnostics {
8365 diagnostics,
8366 document_abs_path: abs_path,
8367 version,
8368 },
8369 result_id,
8370 server_id,
8371 disk_based_sources: Cow::Borrowed(&[]),
8372 registration_id: None,
8373 }],
8374 |_, _, _| false,
8375 cx,
8376 )?;
8377 Ok(())
8378 }
8379
8380 pub fn merge_diagnostic_entries<'a>(
8381 &mut self,
8382 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8383 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8384 cx: &mut Context<Self>,
8385 ) -> anyhow::Result<()> {
8386 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8387 let mut updated_diagnostics_paths = HashMap::default();
8388 for mut update in diagnostic_updates {
8389 let abs_path = &update.diagnostics.document_abs_path;
8390 let server_id = update.server_id;
8391 let Some((worktree, relative_path)) =
8392 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8393 else {
8394 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8395 return Ok(());
8396 };
8397
8398 let worktree_id = worktree.read(cx).id();
8399 let project_path = ProjectPath {
8400 worktree_id,
8401 path: relative_path,
8402 };
8403
8404 let document_uri = lsp::Uri::from_file_path(abs_path)
8405 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8406 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8407 let snapshot = buffer_handle.read(cx).snapshot();
8408 let buffer = buffer_handle.read(cx);
8409 let reused_diagnostics = buffer
8410 .buffer_diagnostics(Some(server_id))
8411 .iter()
8412 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8413 .map(|v| {
8414 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8415 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8416 DiagnosticEntry {
8417 range: start..end,
8418 diagnostic: v.diagnostic.clone(),
8419 }
8420 })
8421 .collect::<Vec<_>>();
8422
8423 self.as_local_mut()
8424 .context("cannot merge diagnostics on a remote LspStore")?
8425 .update_buffer_diagnostics(
8426 &buffer_handle,
8427 server_id,
8428 Some(update.registration_id),
8429 update.result_id,
8430 update.diagnostics.version,
8431 update.diagnostics.diagnostics.clone(),
8432 reused_diagnostics.clone(),
8433 cx,
8434 )?;
8435
8436 update.diagnostics.diagnostics.extend(reused_diagnostics);
8437 } else if let Some(local) = self.as_local() {
8438 let reused_diagnostics = local
8439 .diagnostics
8440 .get(&worktree_id)
8441 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8442 .and_then(|diagnostics_by_server_id| {
8443 diagnostics_by_server_id
8444 .binary_search_by_key(&server_id, |e| e.0)
8445 .ok()
8446 .map(|ix| &diagnostics_by_server_id[ix].1)
8447 })
8448 .into_iter()
8449 .flatten()
8450 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8451
8452 update
8453 .diagnostics
8454 .diagnostics
8455 .extend(reused_diagnostics.cloned());
8456 }
8457
8458 let updated = worktree.update(cx, |worktree, cx| {
8459 self.update_worktree_diagnostics(
8460 worktree.id(),
8461 server_id,
8462 project_path.path.clone(),
8463 update.diagnostics.diagnostics,
8464 cx,
8465 )
8466 })?;
8467 match updated {
8468 ControlFlow::Continue(new_summary) => {
8469 if let Some((project_id, new_summary)) = new_summary {
8470 match &mut diagnostics_summary {
8471 Some(diagnostics_summary) => {
8472 diagnostics_summary
8473 .more_summaries
8474 .push(proto::DiagnosticSummary {
8475 path: project_path.path.as_ref().to_proto(),
8476 language_server_id: server_id.0 as u64,
8477 error_count: new_summary.error_count,
8478 warning_count: new_summary.warning_count,
8479 })
8480 }
8481 None => {
8482 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8483 project_id,
8484 worktree_id: worktree_id.to_proto(),
8485 summary: Some(proto::DiagnosticSummary {
8486 path: project_path.path.as_ref().to_proto(),
8487 language_server_id: server_id.0 as u64,
8488 error_count: new_summary.error_count,
8489 warning_count: new_summary.warning_count,
8490 }),
8491 more_summaries: Vec::new(),
8492 })
8493 }
8494 }
8495 }
8496 updated_diagnostics_paths
8497 .entry(server_id)
8498 .or_insert_with(Vec::new)
8499 .push(project_path);
8500 }
8501 ControlFlow::Break(()) => {}
8502 }
8503 }
8504
8505 if let Some((diagnostics_summary, (downstream_client, _))) =
8506 diagnostics_summary.zip(self.downstream_client.as_ref())
8507 {
8508 downstream_client.send(diagnostics_summary).log_err();
8509 }
8510 for (server_id, paths) in updated_diagnostics_paths {
8511 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8512 }
8513 Ok(())
8514 }
8515
8516 fn update_worktree_diagnostics(
8517 &mut self,
8518 worktree_id: WorktreeId,
8519 server_id: LanguageServerId,
8520 path_in_worktree: Arc<RelPath>,
8521 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8522 _: &mut Context<Worktree>,
8523 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8524 let local = match &mut self.mode {
8525 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8526 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8527 };
8528
8529 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8530 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8531 let summaries_by_server_id = summaries_for_tree
8532 .entry(path_in_worktree.clone())
8533 .or_default();
8534
8535 let old_summary = summaries_by_server_id
8536 .remove(&server_id)
8537 .unwrap_or_default();
8538
8539 let new_summary = DiagnosticSummary::new(&diagnostics);
8540 if diagnostics.is_empty() {
8541 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8542 {
8543 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8544 diagnostics_by_server_id.remove(ix);
8545 }
8546 if diagnostics_by_server_id.is_empty() {
8547 diagnostics_for_tree.remove(&path_in_worktree);
8548 }
8549 }
8550 } else {
8551 summaries_by_server_id.insert(server_id, new_summary);
8552 let diagnostics_by_server_id = diagnostics_for_tree
8553 .entry(path_in_worktree.clone())
8554 .or_default();
8555 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8556 Ok(ix) => {
8557 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8558 }
8559 Err(ix) => {
8560 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8561 }
8562 }
8563 }
8564
8565 if !old_summary.is_empty() || !new_summary.is_empty() {
8566 if let Some((_, project_id)) = &self.downstream_client {
8567 Ok(ControlFlow::Continue(Some((
8568 *project_id,
8569 proto::DiagnosticSummary {
8570 path: path_in_worktree.to_proto(),
8571 language_server_id: server_id.0 as u64,
8572 error_count: new_summary.error_count as u32,
8573 warning_count: new_summary.warning_count as u32,
8574 },
8575 ))))
8576 } else {
8577 Ok(ControlFlow::Continue(None))
8578 }
8579 } else {
8580 Ok(ControlFlow::Break(()))
8581 }
8582 }
8583
8584 pub fn open_buffer_for_symbol(
8585 &mut self,
8586 symbol: &Symbol,
8587 cx: &mut Context<Self>,
8588 ) -> Task<Result<Entity<Buffer>>> {
8589 if let Some((client, project_id)) = self.upstream_client() {
8590 let request = client.request(proto::OpenBufferForSymbol {
8591 project_id,
8592 symbol: Some(Self::serialize_symbol(symbol)),
8593 });
8594 cx.spawn(async move |this, cx| {
8595 let response = request.await?;
8596 let buffer_id = BufferId::new(response.buffer_id)?;
8597 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8598 .await
8599 })
8600 } else if let Some(local) = self.as_local() {
8601 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8602 seed.worktree_id == symbol.source_worktree_id
8603 && state.id == symbol.source_language_server_id
8604 && symbol.language_server_name == seed.name
8605 });
8606 if !is_valid {
8607 return Task::ready(Err(anyhow!(
8608 "language server for worktree and language not found"
8609 )));
8610 };
8611
8612 let symbol_abs_path = match &symbol.path {
8613 SymbolLocation::InProject(project_path) => self
8614 .worktree_store
8615 .read(cx)
8616 .absolutize(&project_path, cx)
8617 .context("no such worktree"),
8618 SymbolLocation::OutsideProject {
8619 abs_path,
8620 signature: _,
8621 } => Ok(abs_path.to_path_buf()),
8622 };
8623 let symbol_abs_path = match symbol_abs_path {
8624 Ok(abs_path) => abs_path,
8625 Err(err) => return Task::ready(Err(err)),
8626 };
8627 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8628 uri
8629 } else {
8630 return Task::ready(Err(anyhow!("invalid symbol path")));
8631 };
8632
8633 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8634 } else {
8635 Task::ready(Err(anyhow!("no upstream client or local store")))
8636 }
8637 }
8638
8639 pub(crate) fn open_local_buffer_via_lsp(
8640 &mut self,
8641 abs_path: lsp::Uri,
8642 language_server_id: LanguageServerId,
8643 cx: &mut Context<Self>,
8644 ) -> Task<Result<Entity<Buffer>>> {
8645 cx.spawn(async move |lsp_store, cx| {
8646 // Escape percent-encoded string.
8647 let current_scheme = abs_path.scheme().to_owned();
8648 // Uri is immutable, so we can't modify the scheme
8649
8650 let abs_path = abs_path
8651 .to_file_path()
8652 .map_err(|()| anyhow!("can't convert URI to path"))?;
8653 let p = abs_path.clone();
8654 let yarn_worktree = lsp_store
8655 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8656 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8657 cx.spawn(async move |this, cx| {
8658 let t = this
8659 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8660 .ok()?;
8661 t.await
8662 })
8663 }),
8664 None => Task::ready(None),
8665 })?
8666 .await;
8667 let (worktree_root_target, known_relative_path) =
8668 if let Some((zip_root, relative_path)) = yarn_worktree {
8669 (zip_root, Some(relative_path))
8670 } else {
8671 (Arc::<Path>::from(abs_path.as_path()), None)
8672 };
8673 let (worktree, relative_path) = if let Some(result) =
8674 lsp_store.update(cx, |lsp_store, cx| {
8675 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8676 worktree_store.find_worktree(&worktree_root_target, cx)
8677 })
8678 })? {
8679 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8680 (result.0, relative_path)
8681 } else {
8682 let worktree = lsp_store
8683 .update(cx, |lsp_store, cx| {
8684 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8685 worktree_store.create_worktree(&worktree_root_target, false, cx)
8686 })
8687 })?
8688 .await?;
8689 if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8690 lsp_store
8691 .update(cx, |lsp_store, cx| {
8692 if let Some(local) = lsp_store.as_local_mut() {
8693 local.register_language_server_for_invisible_worktree(
8694 &worktree,
8695 language_server_id,
8696 cx,
8697 )
8698 }
8699 })
8700 .ok();
8701 }
8702 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8703 let relative_path = if let Some(known_path) = known_relative_path {
8704 known_path
8705 } else {
8706 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8707 .into_arc()
8708 };
8709 (worktree, relative_path)
8710 };
8711 let project_path = ProjectPath {
8712 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8713 path: relative_path,
8714 };
8715 lsp_store
8716 .update(cx, |lsp_store, cx| {
8717 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8718 buffer_store.open_buffer(project_path, cx)
8719 })
8720 })?
8721 .await
8722 })
8723 }
8724
8725 fn request_multiple_lsp_locally<P, R>(
8726 &mut self,
8727 buffer: &Entity<Buffer>,
8728 position: Option<P>,
8729 request: R,
8730 cx: &mut Context<Self>,
8731 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8732 where
8733 P: ToOffset,
8734 R: LspCommand + Clone,
8735 <R::LspRequest as lsp::request::Request>::Result: Send,
8736 <R::LspRequest as lsp::request::Request>::Params: Send,
8737 {
8738 let Some(local) = self.as_local() else {
8739 return Task::ready(Vec::new());
8740 };
8741
8742 let snapshot = buffer.read(cx).snapshot();
8743 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8744
8745 let server_ids = buffer.update(cx, |buffer, cx| {
8746 local
8747 .language_servers_for_buffer(buffer, cx)
8748 .filter(|(adapter, _)| {
8749 scope
8750 .as_ref()
8751 .map(|scope| scope.language_allowed(&adapter.name))
8752 .unwrap_or(true)
8753 })
8754 .map(|(_, server)| server.server_id())
8755 .filter(|server_id| {
8756 self.as_local().is_none_or(|local| {
8757 local
8758 .buffers_opened_in_servers
8759 .get(&snapshot.remote_id())
8760 .is_some_and(|servers| servers.contains(server_id))
8761 })
8762 })
8763 .collect::<Vec<_>>()
8764 });
8765
8766 let mut response_results = server_ids
8767 .into_iter()
8768 .map(|server_id| {
8769 let task = self.request_lsp(
8770 buffer.clone(),
8771 LanguageServerToQuery::Other(server_id),
8772 request.clone(),
8773 cx,
8774 );
8775 async move { (server_id, task.await) }
8776 })
8777 .collect::<FuturesUnordered<_>>();
8778
8779 cx.background_spawn(async move {
8780 let mut responses = Vec::with_capacity(response_results.len());
8781 while let Some((server_id, response_result)) = response_results.next().await {
8782 match response_result {
8783 Ok(response) => responses.push((server_id, response)),
8784 // rust-analyzer likes to error with this when its still loading up
8785 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8786 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8787 }
8788 }
8789 responses
8790 })
8791 }
8792
8793 async fn handle_lsp_get_completions(
8794 this: Entity<Self>,
8795 envelope: TypedEnvelope<proto::GetCompletions>,
8796 mut cx: AsyncApp,
8797 ) -> Result<proto::GetCompletionsResponse> {
8798 let sender_id = envelope.original_sender_id().unwrap_or_default();
8799
8800 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8801 let buffer_handle = this.update(&mut cx, |this, cx| {
8802 this.buffer_store.read(cx).get_existing(buffer_id)
8803 })??;
8804 let request = GetCompletions::from_proto(
8805 envelope.payload,
8806 this.clone(),
8807 buffer_handle.clone(),
8808 cx.clone(),
8809 )
8810 .await?;
8811
8812 let server_to_query = match request.server_id {
8813 Some(server_id) => LanguageServerToQuery::Other(server_id),
8814 None => LanguageServerToQuery::FirstCapable,
8815 };
8816
8817 let response = this
8818 .update(&mut cx, |this, cx| {
8819 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8820 })?
8821 .await?;
8822 this.update(&mut cx, |this, cx| {
8823 Ok(GetCompletions::response_to_proto(
8824 response,
8825 this,
8826 sender_id,
8827 &buffer_handle.read(cx).version(),
8828 cx,
8829 ))
8830 })?
8831 }
8832
8833 async fn handle_lsp_command<T: LspCommand>(
8834 this: Entity<Self>,
8835 envelope: TypedEnvelope<T::ProtoRequest>,
8836 mut cx: AsyncApp,
8837 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8838 where
8839 <T::LspRequest as lsp::request::Request>::Params: Send,
8840 <T::LspRequest as lsp::request::Request>::Result: Send,
8841 {
8842 let sender_id = envelope.original_sender_id().unwrap_or_default();
8843 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8844 let buffer_handle = this.update(&mut cx, |this, cx| {
8845 this.buffer_store.read(cx).get_existing(buffer_id)
8846 })??;
8847 let request = T::from_proto(
8848 envelope.payload,
8849 this.clone(),
8850 buffer_handle.clone(),
8851 cx.clone(),
8852 )
8853 .await?;
8854 let response = this
8855 .update(&mut cx, |this, cx| {
8856 this.request_lsp(
8857 buffer_handle.clone(),
8858 LanguageServerToQuery::FirstCapable,
8859 request,
8860 cx,
8861 )
8862 })?
8863 .await?;
8864 this.update(&mut cx, |this, cx| {
8865 Ok(T::response_to_proto(
8866 response,
8867 this,
8868 sender_id,
8869 &buffer_handle.read(cx).version(),
8870 cx,
8871 ))
8872 })?
8873 }
8874
8875 async fn handle_lsp_query(
8876 lsp_store: Entity<Self>,
8877 envelope: TypedEnvelope<proto::LspQuery>,
8878 mut cx: AsyncApp,
8879 ) -> Result<proto::Ack> {
8880 use proto::lsp_query::Request;
8881 let sender_id = envelope.original_sender_id().unwrap_or_default();
8882 let lsp_query = envelope.payload;
8883 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8884 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8885 match lsp_query.request.context("invalid LSP query request")? {
8886 Request::GetReferences(get_references) => {
8887 let position = get_references.position.clone().and_then(deserialize_anchor);
8888 Self::query_lsp_locally::<GetReferences>(
8889 lsp_store,
8890 server_id,
8891 sender_id,
8892 lsp_request_id,
8893 get_references,
8894 position,
8895 &mut cx,
8896 )
8897 .await?;
8898 }
8899 Request::GetDocumentColor(get_document_color) => {
8900 Self::query_lsp_locally::<GetDocumentColor>(
8901 lsp_store,
8902 server_id,
8903 sender_id,
8904 lsp_request_id,
8905 get_document_color,
8906 None,
8907 &mut cx,
8908 )
8909 .await?;
8910 }
8911 Request::GetHover(get_hover) => {
8912 let position = get_hover.position.clone().and_then(deserialize_anchor);
8913 Self::query_lsp_locally::<GetHover>(
8914 lsp_store,
8915 server_id,
8916 sender_id,
8917 lsp_request_id,
8918 get_hover,
8919 position,
8920 &mut cx,
8921 )
8922 .await?;
8923 }
8924 Request::GetCodeActions(get_code_actions) => {
8925 Self::query_lsp_locally::<GetCodeActions>(
8926 lsp_store,
8927 server_id,
8928 sender_id,
8929 lsp_request_id,
8930 get_code_actions,
8931 None,
8932 &mut cx,
8933 )
8934 .await?;
8935 }
8936 Request::GetSignatureHelp(get_signature_help) => {
8937 let position = get_signature_help
8938 .position
8939 .clone()
8940 .and_then(deserialize_anchor);
8941 Self::query_lsp_locally::<GetSignatureHelp>(
8942 lsp_store,
8943 server_id,
8944 sender_id,
8945 lsp_request_id,
8946 get_signature_help,
8947 position,
8948 &mut cx,
8949 )
8950 .await?;
8951 }
8952 Request::GetCodeLens(get_code_lens) => {
8953 Self::query_lsp_locally::<GetCodeLens>(
8954 lsp_store,
8955 server_id,
8956 sender_id,
8957 lsp_request_id,
8958 get_code_lens,
8959 None,
8960 &mut cx,
8961 )
8962 .await?;
8963 }
8964 Request::GetDefinition(get_definition) => {
8965 let position = get_definition.position.clone().and_then(deserialize_anchor);
8966 Self::query_lsp_locally::<GetDefinitions>(
8967 lsp_store,
8968 server_id,
8969 sender_id,
8970 lsp_request_id,
8971 get_definition,
8972 position,
8973 &mut cx,
8974 )
8975 .await?;
8976 }
8977 Request::GetDeclaration(get_declaration) => {
8978 let position = get_declaration
8979 .position
8980 .clone()
8981 .and_then(deserialize_anchor);
8982 Self::query_lsp_locally::<GetDeclarations>(
8983 lsp_store,
8984 server_id,
8985 sender_id,
8986 lsp_request_id,
8987 get_declaration,
8988 position,
8989 &mut cx,
8990 )
8991 .await?;
8992 }
8993 Request::GetTypeDefinition(get_type_definition) => {
8994 let position = get_type_definition
8995 .position
8996 .clone()
8997 .and_then(deserialize_anchor);
8998 Self::query_lsp_locally::<GetTypeDefinitions>(
8999 lsp_store,
9000 server_id,
9001 sender_id,
9002 lsp_request_id,
9003 get_type_definition,
9004 position,
9005 &mut cx,
9006 )
9007 .await?;
9008 }
9009 Request::GetImplementation(get_implementation) => {
9010 let position = get_implementation
9011 .position
9012 .clone()
9013 .and_then(deserialize_anchor);
9014 Self::query_lsp_locally::<GetImplementations>(
9015 lsp_store,
9016 server_id,
9017 sender_id,
9018 lsp_request_id,
9019 get_implementation,
9020 position,
9021 &mut cx,
9022 )
9023 .await?;
9024 }
9025 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9026 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9027 let version = deserialize_version(get_document_diagnostics.buffer_version());
9028 let buffer = lsp_store.update(&mut cx, |this, cx| {
9029 this.buffer_store.read(cx).get_existing(buffer_id)
9030 })??;
9031 buffer
9032 .update(&mut cx, |buffer, _| {
9033 buffer.wait_for_version(version.clone())
9034 })?
9035 .await?;
9036 lsp_store.update(&mut cx, |lsp_store, cx| {
9037 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9038 let key = LspKey {
9039 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9040 server_queried: server_id,
9041 };
9042 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9043 ) {
9044 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9045 lsp_requests.clear();
9046 };
9047 }
9048
9049 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9050 existing_queries.insert(
9051 lsp_request_id,
9052 cx.spawn(async move |lsp_store, cx| {
9053 let diagnostics_pull = lsp_store
9054 .update(cx, |lsp_store, cx| {
9055 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9056 })
9057 .ok();
9058 if let Some(diagnostics_pull) = diagnostics_pull {
9059 match diagnostics_pull.await {
9060 Ok(()) => {}
9061 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9062 };
9063 }
9064 }),
9065 );
9066 })?;
9067 }
9068 Request::InlayHints(inlay_hints) => {
9069 let query_start = inlay_hints
9070 .start
9071 .clone()
9072 .and_then(deserialize_anchor)
9073 .context("invalid inlay hints range start")?;
9074 let query_end = inlay_hints
9075 .end
9076 .clone()
9077 .and_then(deserialize_anchor)
9078 .context("invalid inlay hints range end")?;
9079 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9080 &lsp_store,
9081 server_id,
9082 lsp_request_id,
9083 &inlay_hints,
9084 query_start..query_end,
9085 &mut cx,
9086 )
9087 .await
9088 .context("preparing inlay hints request")?;
9089 Self::query_lsp_locally::<InlayHints>(
9090 lsp_store,
9091 server_id,
9092 sender_id,
9093 lsp_request_id,
9094 inlay_hints,
9095 None,
9096 &mut cx,
9097 )
9098 .await
9099 .context("querying for inlay hints")?
9100 }
9101 }
9102 Ok(proto::Ack {})
9103 }
9104
9105 async fn handle_lsp_query_response(
9106 lsp_store: Entity<Self>,
9107 envelope: TypedEnvelope<proto::LspQueryResponse>,
9108 cx: AsyncApp,
9109 ) -> Result<()> {
9110 lsp_store.read_with(&cx, |lsp_store, _| {
9111 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9112 upstream_client.handle_lsp_response(envelope.clone());
9113 }
9114 })?;
9115 Ok(())
9116 }
9117
9118 async fn handle_apply_code_action(
9119 this: Entity<Self>,
9120 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9121 mut cx: AsyncApp,
9122 ) -> Result<proto::ApplyCodeActionResponse> {
9123 let sender_id = envelope.original_sender_id().unwrap_or_default();
9124 let action =
9125 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9126 let apply_code_action = this.update(&mut cx, |this, cx| {
9127 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9128 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9129 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9130 })??;
9131
9132 let project_transaction = apply_code_action.await?;
9133 let project_transaction = this.update(&mut cx, |this, cx| {
9134 this.buffer_store.update(cx, |buffer_store, cx| {
9135 buffer_store.serialize_project_transaction_for_peer(
9136 project_transaction,
9137 sender_id,
9138 cx,
9139 )
9140 })
9141 })?;
9142 Ok(proto::ApplyCodeActionResponse {
9143 transaction: Some(project_transaction),
9144 })
9145 }
9146
9147 async fn handle_register_buffer_with_language_servers(
9148 this: Entity<Self>,
9149 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9150 mut cx: AsyncApp,
9151 ) -> Result<proto::Ack> {
9152 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9153 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9154 this.update(&mut cx, |this, cx| {
9155 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9156 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9157 project_id: upstream_project_id,
9158 buffer_id: buffer_id.to_proto(),
9159 only_servers: envelope.payload.only_servers,
9160 });
9161 }
9162
9163 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9164 anyhow::bail!("buffer is not open");
9165 };
9166
9167 let handle = this.register_buffer_with_language_servers(
9168 &buffer,
9169 envelope
9170 .payload
9171 .only_servers
9172 .into_iter()
9173 .filter_map(|selector| {
9174 Some(match selector.selector? {
9175 proto::language_server_selector::Selector::ServerId(server_id) => {
9176 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9177 }
9178 proto::language_server_selector::Selector::Name(name) => {
9179 LanguageServerSelector::Name(LanguageServerName(
9180 SharedString::from(name),
9181 ))
9182 }
9183 })
9184 })
9185 .collect(),
9186 false,
9187 cx,
9188 );
9189 this.buffer_store().update(cx, |buffer_store, _| {
9190 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9191 });
9192
9193 Ok(())
9194 })??;
9195 Ok(proto::Ack {})
9196 }
9197
9198 async fn handle_rename_project_entry(
9199 this: Entity<Self>,
9200 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9201 mut cx: AsyncApp,
9202 ) -> Result<proto::ProjectEntryResponse> {
9203 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9204 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9205 let new_path =
9206 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9207
9208 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9209 .update(&mut cx, |this, cx| {
9210 let (worktree, entry) = this
9211 .worktree_store
9212 .read(cx)
9213 .worktree_and_entry_for_id(entry_id, cx)?;
9214 let new_worktree = this
9215 .worktree_store
9216 .read(cx)
9217 .worktree_for_id(new_worktree_id, cx)?;
9218 Some((
9219 this.worktree_store.clone(),
9220 worktree,
9221 new_worktree,
9222 entry.clone(),
9223 ))
9224 })?
9225 .context("worktree not found")?;
9226 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9227 (worktree.absolutize(&old_entry.path), worktree.id())
9228 })?;
9229 let new_abs_path =
9230 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9231
9232 let _transaction = Self::will_rename_entry(
9233 this.downgrade(),
9234 old_worktree_id,
9235 &old_abs_path,
9236 &new_abs_path,
9237 old_entry.is_dir(),
9238 cx.clone(),
9239 )
9240 .await;
9241 let response = WorktreeStore::handle_rename_project_entry(
9242 worktree_store,
9243 envelope.payload,
9244 cx.clone(),
9245 )
9246 .await;
9247 this.read_with(&cx, |this, _| {
9248 this.did_rename_entry(
9249 old_worktree_id,
9250 &old_abs_path,
9251 &new_abs_path,
9252 old_entry.is_dir(),
9253 );
9254 })
9255 .ok();
9256 response
9257 }
9258
9259 async fn handle_update_diagnostic_summary(
9260 this: Entity<Self>,
9261 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9262 mut cx: AsyncApp,
9263 ) -> Result<()> {
9264 this.update(&mut cx, |lsp_store, cx| {
9265 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9266 let mut updated_diagnostics_paths = HashMap::default();
9267 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9268 for message_summary in envelope
9269 .payload
9270 .summary
9271 .into_iter()
9272 .chain(envelope.payload.more_summaries)
9273 {
9274 let project_path = ProjectPath {
9275 worktree_id,
9276 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9277 };
9278 let path = project_path.path.clone();
9279 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9280 let summary = DiagnosticSummary {
9281 error_count: message_summary.error_count as usize,
9282 warning_count: message_summary.warning_count as usize,
9283 };
9284
9285 if summary.is_empty() {
9286 if let Some(worktree_summaries) =
9287 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9288 && let Some(summaries) = worktree_summaries.get_mut(&path)
9289 {
9290 summaries.remove(&server_id);
9291 if summaries.is_empty() {
9292 worktree_summaries.remove(&path);
9293 }
9294 }
9295 } else {
9296 lsp_store
9297 .diagnostic_summaries
9298 .entry(worktree_id)
9299 .or_default()
9300 .entry(path)
9301 .or_default()
9302 .insert(server_id, summary);
9303 }
9304
9305 if let Some((_, project_id)) = &lsp_store.downstream_client {
9306 match &mut diagnostics_summary {
9307 Some(diagnostics_summary) => {
9308 diagnostics_summary
9309 .more_summaries
9310 .push(proto::DiagnosticSummary {
9311 path: project_path.path.as_ref().to_proto(),
9312 language_server_id: server_id.0 as u64,
9313 error_count: summary.error_count as u32,
9314 warning_count: summary.warning_count as u32,
9315 })
9316 }
9317 None => {
9318 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9319 project_id: *project_id,
9320 worktree_id: worktree_id.to_proto(),
9321 summary: Some(proto::DiagnosticSummary {
9322 path: project_path.path.as_ref().to_proto(),
9323 language_server_id: server_id.0 as u64,
9324 error_count: summary.error_count as u32,
9325 warning_count: summary.warning_count as u32,
9326 }),
9327 more_summaries: Vec::new(),
9328 })
9329 }
9330 }
9331 }
9332 updated_diagnostics_paths
9333 .entry(server_id)
9334 .or_insert_with(Vec::new)
9335 .push(project_path);
9336 }
9337
9338 if let Some((diagnostics_summary, (downstream_client, _))) =
9339 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9340 {
9341 downstream_client.send(diagnostics_summary).log_err();
9342 }
9343 for (server_id, paths) in updated_diagnostics_paths {
9344 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9345 }
9346 Ok(())
9347 })?
9348 }
9349
9350 async fn handle_start_language_server(
9351 lsp_store: Entity<Self>,
9352 envelope: TypedEnvelope<proto::StartLanguageServer>,
9353 mut cx: AsyncApp,
9354 ) -> Result<()> {
9355 let server = envelope.payload.server.context("invalid server")?;
9356 let server_capabilities =
9357 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9358 .with_context(|| {
9359 format!(
9360 "incorrect server capabilities {}",
9361 envelope.payload.capabilities
9362 )
9363 })?;
9364 lsp_store.update(&mut cx, |lsp_store, cx| {
9365 let server_id = LanguageServerId(server.id as usize);
9366 let server_name = LanguageServerName::from_proto(server.name.clone());
9367 lsp_store
9368 .lsp_server_capabilities
9369 .insert(server_id, server_capabilities);
9370 lsp_store.language_server_statuses.insert(
9371 server_id,
9372 LanguageServerStatus {
9373 name: server_name.clone(),
9374 pending_work: Default::default(),
9375 has_pending_diagnostic_updates: false,
9376 progress_tokens: Default::default(),
9377 worktree: server.worktree_id.map(WorktreeId::from_proto),
9378 binary: None,
9379 configuration: None,
9380 workspace_folders: BTreeSet::new(),
9381 },
9382 );
9383 cx.emit(LspStoreEvent::LanguageServerAdded(
9384 server_id,
9385 server_name,
9386 server.worktree_id.map(WorktreeId::from_proto),
9387 ));
9388 cx.notify();
9389 })?;
9390 Ok(())
9391 }
9392
9393 async fn handle_update_language_server(
9394 lsp_store: Entity<Self>,
9395 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9396 mut cx: AsyncApp,
9397 ) -> Result<()> {
9398 lsp_store.update(&mut cx, |lsp_store, cx| {
9399 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9400
9401 match envelope.payload.variant.context("invalid variant")? {
9402 proto::update_language_server::Variant::WorkStart(payload) => {
9403 lsp_store.on_lsp_work_start(
9404 language_server_id,
9405 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9406 .context("invalid progress token value")?,
9407 LanguageServerProgress {
9408 title: payload.title,
9409 is_disk_based_diagnostics_progress: false,
9410 is_cancellable: payload.is_cancellable.unwrap_or(false),
9411 message: payload.message,
9412 percentage: payload.percentage.map(|p| p as usize),
9413 last_update_at: cx.background_executor().now(),
9414 },
9415 cx,
9416 );
9417 }
9418 proto::update_language_server::Variant::WorkProgress(payload) => {
9419 lsp_store.on_lsp_work_progress(
9420 language_server_id,
9421 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9422 .context("invalid progress token value")?,
9423 LanguageServerProgress {
9424 title: None,
9425 is_disk_based_diagnostics_progress: false,
9426 is_cancellable: payload.is_cancellable.unwrap_or(false),
9427 message: payload.message,
9428 percentage: payload.percentage.map(|p| p as usize),
9429 last_update_at: cx.background_executor().now(),
9430 },
9431 cx,
9432 );
9433 }
9434
9435 proto::update_language_server::Variant::WorkEnd(payload) => {
9436 lsp_store.on_lsp_work_end(
9437 language_server_id,
9438 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9439 .context("invalid progress token value")?,
9440 cx,
9441 );
9442 }
9443
9444 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9445 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9446 }
9447
9448 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9449 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9450 }
9451
9452 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9453 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9454 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9455 cx.emit(LspStoreEvent::LanguageServerUpdate {
9456 language_server_id,
9457 name: envelope
9458 .payload
9459 .server_name
9460 .map(SharedString::new)
9461 .map(LanguageServerName),
9462 message: non_lsp,
9463 });
9464 }
9465 }
9466
9467 Ok(())
9468 })?
9469 }
9470
9471 async fn handle_language_server_log(
9472 this: Entity<Self>,
9473 envelope: TypedEnvelope<proto::LanguageServerLog>,
9474 mut cx: AsyncApp,
9475 ) -> Result<()> {
9476 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9477 let log_type = envelope
9478 .payload
9479 .log_type
9480 .map(LanguageServerLogType::from_proto)
9481 .context("invalid language server log type")?;
9482
9483 let message = envelope.payload.message;
9484
9485 this.update(&mut cx, |_, cx| {
9486 cx.emit(LspStoreEvent::LanguageServerLog(
9487 language_server_id,
9488 log_type,
9489 message,
9490 ));
9491 })
9492 }
9493
9494 async fn handle_lsp_ext_cancel_flycheck(
9495 lsp_store: Entity<Self>,
9496 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9497 cx: AsyncApp,
9498 ) -> Result<proto::Ack> {
9499 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9500 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9501 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9502 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9503 } else {
9504 None
9505 }
9506 })?;
9507 if let Some(task) = task {
9508 task.context("handling lsp ext cancel flycheck")?;
9509 }
9510
9511 Ok(proto::Ack {})
9512 }
9513
9514 async fn handle_lsp_ext_run_flycheck(
9515 lsp_store: Entity<Self>,
9516 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9517 mut cx: AsyncApp,
9518 ) -> Result<proto::Ack> {
9519 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9520 lsp_store.update(&mut cx, |lsp_store, cx| {
9521 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9522 let text_document = if envelope.payload.current_file_only {
9523 let buffer_id = envelope
9524 .payload
9525 .buffer_id
9526 .map(|id| BufferId::new(id))
9527 .transpose()?;
9528 buffer_id
9529 .and_then(|buffer_id| {
9530 lsp_store
9531 .buffer_store()
9532 .read(cx)
9533 .get(buffer_id)
9534 .and_then(|buffer| {
9535 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9536 })
9537 .map(|path| make_text_document_identifier(&path))
9538 })
9539 .transpose()?
9540 } else {
9541 None
9542 };
9543 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9544 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9545 )?;
9546 }
9547 anyhow::Ok(())
9548 })??;
9549
9550 Ok(proto::Ack {})
9551 }
9552
9553 async fn handle_lsp_ext_clear_flycheck(
9554 lsp_store: Entity<Self>,
9555 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9556 cx: AsyncApp,
9557 ) -> Result<proto::Ack> {
9558 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9559 lsp_store
9560 .read_with(&cx, |lsp_store, _| {
9561 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9562 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9563 } else {
9564 None
9565 }
9566 })
9567 .context("handling lsp ext clear flycheck")?;
9568
9569 Ok(proto::Ack {})
9570 }
9571
9572 pub fn disk_based_diagnostics_started(
9573 &mut self,
9574 language_server_id: LanguageServerId,
9575 cx: &mut Context<Self>,
9576 ) {
9577 if let Some(language_server_status) =
9578 self.language_server_statuses.get_mut(&language_server_id)
9579 {
9580 language_server_status.has_pending_diagnostic_updates = true;
9581 }
9582
9583 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9584 cx.emit(LspStoreEvent::LanguageServerUpdate {
9585 language_server_id,
9586 name: self
9587 .language_server_adapter_for_id(language_server_id)
9588 .map(|adapter| adapter.name()),
9589 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9590 Default::default(),
9591 ),
9592 })
9593 }
9594
9595 pub fn disk_based_diagnostics_finished(
9596 &mut self,
9597 language_server_id: LanguageServerId,
9598 cx: &mut Context<Self>,
9599 ) {
9600 if let Some(language_server_status) =
9601 self.language_server_statuses.get_mut(&language_server_id)
9602 {
9603 language_server_status.has_pending_diagnostic_updates = false;
9604 }
9605
9606 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9607 cx.emit(LspStoreEvent::LanguageServerUpdate {
9608 language_server_id,
9609 name: self
9610 .language_server_adapter_for_id(language_server_id)
9611 .map(|adapter| adapter.name()),
9612 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9613 Default::default(),
9614 ),
9615 })
9616 }
9617
9618 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9619 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9620 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9621 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9622 // the language server might take some time to publish diagnostics.
9623 fn simulate_disk_based_diagnostics_events_if_needed(
9624 &mut self,
9625 language_server_id: LanguageServerId,
9626 cx: &mut Context<Self>,
9627 ) {
9628 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9629
9630 let Some(LanguageServerState::Running {
9631 simulate_disk_based_diagnostics_completion,
9632 adapter,
9633 ..
9634 }) = self
9635 .as_local_mut()
9636 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9637 else {
9638 return;
9639 };
9640
9641 if adapter.disk_based_diagnostics_progress_token.is_some() {
9642 return;
9643 }
9644
9645 let prev_task =
9646 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9647 cx.background_executor()
9648 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9649 .await;
9650
9651 this.update(cx, |this, cx| {
9652 this.disk_based_diagnostics_finished(language_server_id, cx);
9653
9654 if let Some(LanguageServerState::Running {
9655 simulate_disk_based_diagnostics_completion,
9656 ..
9657 }) = this.as_local_mut().and_then(|local_store| {
9658 local_store.language_servers.get_mut(&language_server_id)
9659 }) {
9660 *simulate_disk_based_diagnostics_completion = None;
9661 }
9662 })
9663 .ok();
9664 }));
9665
9666 if prev_task.is_none() {
9667 self.disk_based_diagnostics_started(language_server_id, cx);
9668 }
9669 }
9670
9671 pub fn language_server_statuses(
9672 &self,
9673 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9674 self.language_server_statuses
9675 .iter()
9676 .map(|(key, value)| (*key, value))
9677 }
9678
9679 pub(super) fn did_rename_entry(
9680 &self,
9681 worktree_id: WorktreeId,
9682 old_path: &Path,
9683 new_path: &Path,
9684 is_dir: bool,
9685 ) {
9686 maybe!({
9687 let local_store = self.as_local()?;
9688
9689 let old_uri = lsp::Uri::from_file_path(old_path)
9690 .ok()
9691 .map(|uri| uri.to_string())?;
9692 let new_uri = lsp::Uri::from_file_path(new_path)
9693 .ok()
9694 .map(|uri| uri.to_string())?;
9695
9696 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9697 let Some(filter) = local_store
9698 .language_server_paths_watched_for_rename
9699 .get(&language_server.server_id())
9700 else {
9701 continue;
9702 };
9703
9704 if filter.should_send_did_rename(&old_uri, is_dir) {
9705 language_server
9706 .notify::<DidRenameFiles>(RenameFilesParams {
9707 files: vec![FileRename {
9708 old_uri: old_uri.clone(),
9709 new_uri: new_uri.clone(),
9710 }],
9711 })
9712 .ok();
9713 }
9714 }
9715 Some(())
9716 });
9717 }
9718
9719 pub(super) fn will_rename_entry(
9720 this: WeakEntity<Self>,
9721 worktree_id: WorktreeId,
9722 old_path: &Path,
9723 new_path: &Path,
9724 is_dir: bool,
9725 cx: AsyncApp,
9726 ) -> Task<ProjectTransaction> {
9727 let old_uri = lsp::Uri::from_file_path(old_path)
9728 .ok()
9729 .map(|uri| uri.to_string());
9730 let new_uri = lsp::Uri::from_file_path(new_path)
9731 .ok()
9732 .map(|uri| uri.to_string());
9733 cx.spawn(async move |cx| {
9734 let mut tasks = vec![];
9735 this.update(cx, |this, cx| {
9736 let local_store = this.as_local()?;
9737 let old_uri = old_uri?;
9738 let new_uri = new_uri?;
9739 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9740 let Some(filter) = local_store
9741 .language_server_paths_watched_for_rename
9742 .get(&language_server.server_id())
9743 else {
9744 continue;
9745 };
9746
9747 if filter.should_send_will_rename(&old_uri, is_dir) {
9748 let apply_edit = cx.spawn({
9749 let old_uri = old_uri.clone();
9750 let new_uri = new_uri.clone();
9751 let language_server = language_server.clone();
9752 async move |this, cx| {
9753 let edit = language_server
9754 .request::<WillRenameFiles>(RenameFilesParams {
9755 files: vec![FileRename { old_uri, new_uri }],
9756 })
9757 .await
9758 .into_response()
9759 .context("will rename files")
9760 .log_err()
9761 .flatten()?;
9762
9763 let transaction = LocalLspStore::deserialize_workspace_edit(
9764 this.upgrade()?,
9765 edit,
9766 false,
9767 language_server.clone(),
9768 cx,
9769 )
9770 .await
9771 .ok()?;
9772 Some(transaction)
9773 }
9774 });
9775 tasks.push(apply_edit);
9776 }
9777 }
9778 Some(())
9779 })
9780 .ok()
9781 .flatten();
9782 let mut merged_transaction = ProjectTransaction::default();
9783 for task in tasks {
9784 // Await on tasks sequentially so that the order of application of edits is deterministic
9785 // (at least with regards to the order of registration of language servers)
9786 if let Some(transaction) = task.await {
9787 for (buffer, buffer_transaction) in transaction.0 {
9788 merged_transaction.0.insert(buffer, buffer_transaction);
9789 }
9790 }
9791 }
9792 merged_transaction
9793 })
9794 }
9795
9796 fn lsp_notify_abs_paths_changed(
9797 &mut self,
9798 server_id: LanguageServerId,
9799 changes: Vec<PathEvent>,
9800 ) {
9801 maybe!({
9802 let server = self.language_server_for_id(server_id)?;
9803 let changes = changes
9804 .into_iter()
9805 .filter_map(|event| {
9806 let typ = match event.kind? {
9807 PathEventKind::Created => lsp::FileChangeType::CREATED,
9808 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9809 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9810 };
9811 Some(lsp::FileEvent {
9812 uri: file_path_to_lsp_url(&event.path).log_err()?,
9813 typ,
9814 })
9815 })
9816 .collect::<Vec<_>>();
9817 if !changes.is_empty() {
9818 server
9819 .notify::<lsp::notification::DidChangeWatchedFiles>(
9820 lsp::DidChangeWatchedFilesParams { changes },
9821 )
9822 .ok();
9823 }
9824 Some(())
9825 });
9826 }
9827
9828 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9829 self.as_local()?.language_server_for_id(id)
9830 }
9831
9832 fn on_lsp_progress(
9833 &mut self,
9834 progress_params: lsp::ProgressParams,
9835 language_server_id: LanguageServerId,
9836 disk_based_diagnostics_progress_token: Option<String>,
9837 cx: &mut Context<Self>,
9838 ) {
9839 match progress_params.value {
9840 lsp::ProgressParamsValue::WorkDone(progress) => {
9841 self.handle_work_done_progress(
9842 progress,
9843 language_server_id,
9844 disk_based_diagnostics_progress_token,
9845 ProgressToken::from_lsp(progress_params.token),
9846 cx,
9847 );
9848 }
9849 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9850 let registration_id = match progress_params.token {
9851 lsp::NumberOrString::Number(_) => None,
9852 lsp::NumberOrString::String(token) => token
9853 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9854 .map(|(_, id)| id.to_owned()),
9855 };
9856 if let Some(LanguageServerState::Running {
9857 workspace_diagnostics_refresh_tasks,
9858 ..
9859 }) = self
9860 .as_local_mut()
9861 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9862 && let Some(workspace_diagnostics) =
9863 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9864 {
9865 workspace_diagnostics.progress_tx.try_send(()).ok();
9866 self.apply_workspace_diagnostic_report(
9867 language_server_id,
9868 report,
9869 registration_id.map(SharedString::from),
9870 cx,
9871 )
9872 }
9873 }
9874 }
9875 }
9876
9877 fn handle_work_done_progress(
9878 &mut self,
9879 progress: lsp::WorkDoneProgress,
9880 language_server_id: LanguageServerId,
9881 disk_based_diagnostics_progress_token: Option<String>,
9882 token: ProgressToken,
9883 cx: &mut Context<Self>,
9884 ) {
9885 let language_server_status =
9886 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9887 status
9888 } else {
9889 return;
9890 };
9891
9892 if !language_server_status.progress_tokens.contains(&token) {
9893 return;
9894 }
9895
9896 let is_disk_based_diagnostics_progress =
9897 if let (Some(disk_based_token), ProgressToken::String(token)) =
9898 (&disk_based_diagnostics_progress_token, &token)
9899 {
9900 token.starts_with(disk_based_token)
9901 } else {
9902 false
9903 };
9904
9905 match progress {
9906 lsp::WorkDoneProgress::Begin(report) => {
9907 if is_disk_based_diagnostics_progress {
9908 self.disk_based_diagnostics_started(language_server_id, cx);
9909 }
9910 self.on_lsp_work_start(
9911 language_server_id,
9912 token.clone(),
9913 LanguageServerProgress {
9914 title: Some(report.title),
9915 is_disk_based_diagnostics_progress,
9916 is_cancellable: report.cancellable.unwrap_or(false),
9917 message: report.message.clone(),
9918 percentage: report.percentage.map(|p| p as usize),
9919 last_update_at: cx.background_executor().now(),
9920 },
9921 cx,
9922 );
9923 }
9924 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9925 language_server_id,
9926 token,
9927 LanguageServerProgress {
9928 title: None,
9929 is_disk_based_diagnostics_progress,
9930 is_cancellable: report.cancellable.unwrap_or(false),
9931 message: report.message,
9932 percentage: report.percentage.map(|p| p as usize),
9933 last_update_at: cx.background_executor().now(),
9934 },
9935 cx,
9936 ),
9937 lsp::WorkDoneProgress::End(_) => {
9938 language_server_status.progress_tokens.remove(&token);
9939 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9940 if is_disk_based_diagnostics_progress {
9941 self.disk_based_diagnostics_finished(language_server_id, cx);
9942 }
9943 }
9944 }
9945 }
9946
9947 fn on_lsp_work_start(
9948 &mut self,
9949 language_server_id: LanguageServerId,
9950 token: ProgressToken,
9951 progress: LanguageServerProgress,
9952 cx: &mut Context<Self>,
9953 ) {
9954 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9955 status.pending_work.insert(token.clone(), progress.clone());
9956 cx.notify();
9957 }
9958 cx.emit(LspStoreEvent::LanguageServerUpdate {
9959 language_server_id,
9960 name: self
9961 .language_server_adapter_for_id(language_server_id)
9962 .map(|adapter| adapter.name()),
9963 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9964 token: Some(token.to_proto()),
9965 title: progress.title,
9966 message: progress.message,
9967 percentage: progress.percentage.map(|p| p as u32),
9968 is_cancellable: Some(progress.is_cancellable),
9969 }),
9970 })
9971 }
9972
9973 fn on_lsp_work_progress(
9974 &mut self,
9975 language_server_id: LanguageServerId,
9976 token: ProgressToken,
9977 progress: LanguageServerProgress,
9978 cx: &mut Context<Self>,
9979 ) {
9980 let mut did_update = false;
9981 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9982 match status.pending_work.entry(token.clone()) {
9983 btree_map::Entry::Vacant(entry) => {
9984 entry.insert(progress.clone());
9985 did_update = true;
9986 }
9987 btree_map::Entry::Occupied(mut entry) => {
9988 let entry = entry.get_mut();
9989 if (progress.last_update_at - entry.last_update_at)
9990 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9991 {
9992 entry.last_update_at = progress.last_update_at;
9993 if progress.message.is_some() {
9994 entry.message = progress.message.clone();
9995 }
9996 if progress.percentage.is_some() {
9997 entry.percentage = progress.percentage;
9998 }
9999 if progress.is_cancellable != entry.is_cancellable {
10000 entry.is_cancellable = progress.is_cancellable;
10001 }
10002 did_update = true;
10003 }
10004 }
10005 }
10006 }
10007
10008 if did_update {
10009 cx.emit(LspStoreEvent::LanguageServerUpdate {
10010 language_server_id,
10011 name: self
10012 .language_server_adapter_for_id(language_server_id)
10013 .map(|adapter| adapter.name()),
10014 message: proto::update_language_server::Variant::WorkProgress(
10015 proto::LspWorkProgress {
10016 token: Some(token.to_proto()),
10017 message: progress.message,
10018 percentage: progress.percentage.map(|p| p as u32),
10019 is_cancellable: Some(progress.is_cancellable),
10020 },
10021 ),
10022 })
10023 }
10024 }
10025
10026 fn on_lsp_work_end(
10027 &mut self,
10028 language_server_id: LanguageServerId,
10029 token: ProgressToken,
10030 cx: &mut Context<Self>,
10031 ) {
10032 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10033 if let Some(work) = status.pending_work.remove(&token)
10034 && !work.is_disk_based_diagnostics_progress
10035 {
10036 cx.emit(LspStoreEvent::RefreshInlayHints {
10037 server_id: language_server_id,
10038 request_id: None,
10039 });
10040 }
10041 cx.notify();
10042 }
10043
10044 cx.emit(LspStoreEvent::LanguageServerUpdate {
10045 language_server_id,
10046 name: self
10047 .language_server_adapter_for_id(language_server_id)
10048 .map(|adapter| adapter.name()),
10049 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10050 token: Some(token.to_proto()),
10051 }),
10052 })
10053 }
10054
10055 pub async fn handle_resolve_completion_documentation(
10056 this: Entity<Self>,
10057 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10058 mut cx: AsyncApp,
10059 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10060 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10061
10062 let completion = this
10063 .read_with(&cx, |this, cx| {
10064 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10065 let server = this
10066 .language_server_for_id(id)
10067 .with_context(|| format!("No language server {id}"))?;
10068
10069 anyhow::Ok(cx.background_spawn(async move {
10070 let can_resolve = server
10071 .capabilities()
10072 .completion_provider
10073 .as_ref()
10074 .and_then(|options| options.resolve_provider)
10075 .unwrap_or(false);
10076 if can_resolve {
10077 server
10078 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10079 .await
10080 .into_response()
10081 .context("resolve completion item")
10082 } else {
10083 anyhow::Ok(lsp_completion)
10084 }
10085 }))
10086 })??
10087 .await?;
10088
10089 let mut documentation_is_markdown = false;
10090 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10091 let documentation = match completion.documentation {
10092 Some(lsp::Documentation::String(text)) => text,
10093
10094 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10095 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10096 value
10097 }
10098
10099 _ => String::new(),
10100 };
10101
10102 // If we have a new buffer_id, that means we're talking to a new client
10103 // and want to check for new text_edits in the completion too.
10104 let mut old_replace_start = None;
10105 let mut old_replace_end = None;
10106 let mut old_insert_start = None;
10107 let mut old_insert_end = None;
10108 let mut new_text = String::default();
10109 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10110 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10111 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10112 anyhow::Ok(buffer.read(cx).snapshot())
10113 })??;
10114
10115 if let Some(text_edit) = completion.text_edit.as_ref() {
10116 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10117
10118 if let Some(mut edit) = edit {
10119 LineEnding::normalize(&mut edit.new_text);
10120
10121 new_text = edit.new_text;
10122 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10123 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10124 if let Some(insert_range) = edit.insert_range {
10125 old_insert_start = Some(serialize_anchor(&insert_range.start));
10126 old_insert_end = Some(serialize_anchor(&insert_range.end));
10127 }
10128 }
10129 }
10130 }
10131
10132 Ok(proto::ResolveCompletionDocumentationResponse {
10133 documentation,
10134 documentation_is_markdown,
10135 old_replace_start,
10136 old_replace_end,
10137 new_text,
10138 lsp_completion,
10139 old_insert_start,
10140 old_insert_end,
10141 })
10142 }
10143
10144 async fn handle_on_type_formatting(
10145 this: Entity<Self>,
10146 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10147 mut cx: AsyncApp,
10148 ) -> Result<proto::OnTypeFormattingResponse> {
10149 let on_type_formatting = this.update(&mut cx, |this, cx| {
10150 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10151 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10152 let position = envelope
10153 .payload
10154 .position
10155 .and_then(deserialize_anchor)
10156 .context("invalid position")?;
10157 anyhow::Ok(this.apply_on_type_formatting(
10158 buffer,
10159 position,
10160 envelope.payload.trigger.clone(),
10161 cx,
10162 ))
10163 })??;
10164
10165 let transaction = on_type_formatting
10166 .await?
10167 .as_ref()
10168 .map(language::proto::serialize_transaction);
10169 Ok(proto::OnTypeFormattingResponse { transaction })
10170 }
10171
10172 async fn handle_refresh_inlay_hints(
10173 lsp_store: Entity<Self>,
10174 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10175 mut cx: AsyncApp,
10176 ) -> Result<proto::Ack> {
10177 lsp_store.update(&mut cx, |_, cx| {
10178 cx.emit(LspStoreEvent::RefreshInlayHints {
10179 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10180 request_id: envelope.payload.request_id.map(|id| id as usize),
10181 });
10182 })?;
10183 Ok(proto::Ack {})
10184 }
10185
10186 async fn handle_pull_workspace_diagnostics(
10187 lsp_store: Entity<Self>,
10188 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10189 mut cx: AsyncApp,
10190 ) -> Result<proto::Ack> {
10191 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10192 lsp_store.update(&mut cx, |lsp_store, _| {
10193 lsp_store.pull_workspace_diagnostics(server_id);
10194 })?;
10195 Ok(proto::Ack {})
10196 }
10197
10198 async fn handle_get_color_presentation(
10199 lsp_store: Entity<Self>,
10200 envelope: TypedEnvelope<proto::GetColorPresentation>,
10201 mut cx: AsyncApp,
10202 ) -> Result<proto::GetColorPresentationResponse> {
10203 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10204 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10205 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10206 })??;
10207
10208 let color = envelope
10209 .payload
10210 .color
10211 .context("invalid color resolve request")?;
10212 let start = color
10213 .lsp_range_start
10214 .context("invalid color resolve request")?;
10215 let end = color
10216 .lsp_range_end
10217 .context("invalid color resolve request")?;
10218
10219 let color = DocumentColor {
10220 lsp_range: lsp::Range {
10221 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10222 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10223 },
10224 color: lsp::Color {
10225 red: color.red,
10226 green: color.green,
10227 blue: color.blue,
10228 alpha: color.alpha,
10229 },
10230 resolved: false,
10231 color_presentations: Vec::new(),
10232 };
10233 let resolved_color = lsp_store
10234 .update(&mut cx, |lsp_store, cx| {
10235 lsp_store.resolve_color_presentation(
10236 color,
10237 buffer.clone(),
10238 LanguageServerId(envelope.payload.server_id as usize),
10239 cx,
10240 )
10241 })?
10242 .await
10243 .context("resolving color presentation")?;
10244
10245 Ok(proto::GetColorPresentationResponse {
10246 presentations: resolved_color
10247 .color_presentations
10248 .into_iter()
10249 .map(|presentation| proto::ColorPresentation {
10250 label: presentation.label.to_string(),
10251 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10252 additional_text_edits: presentation
10253 .additional_text_edits
10254 .into_iter()
10255 .map(serialize_lsp_edit)
10256 .collect(),
10257 })
10258 .collect(),
10259 })
10260 }
10261
10262 async fn handle_resolve_inlay_hint(
10263 lsp_store: Entity<Self>,
10264 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10265 mut cx: AsyncApp,
10266 ) -> Result<proto::ResolveInlayHintResponse> {
10267 let proto_hint = envelope
10268 .payload
10269 .hint
10270 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10271 let hint = InlayHints::proto_to_project_hint(proto_hint)
10272 .context("resolved proto inlay hint conversion")?;
10273 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10274 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10275 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10276 })??;
10277 let response_hint = lsp_store
10278 .update(&mut cx, |lsp_store, cx| {
10279 lsp_store.resolve_inlay_hint(
10280 hint,
10281 buffer,
10282 LanguageServerId(envelope.payload.language_server_id as usize),
10283 cx,
10284 )
10285 })?
10286 .await
10287 .context("inlay hints fetch")?;
10288 Ok(proto::ResolveInlayHintResponse {
10289 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10290 })
10291 }
10292
10293 async fn handle_refresh_code_lens(
10294 this: Entity<Self>,
10295 _: TypedEnvelope<proto::RefreshCodeLens>,
10296 mut cx: AsyncApp,
10297 ) -> Result<proto::Ack> {
10298 this.update(&mut cx, |_, cx| {
10299 cx.emit(LspStoreEvent::RefreshCodeLens);
10300 })?;
10301 Ok(proto::Ack {})
10302 }
10303
10304 async fn handle_open_buffer_for_symbol(
10305 this: Entity<Self>,
10306 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10307 mut cx: AsyncApp,
10308 ) -> Result<proto::OpenBufferForSymbolResponse> {
10309 let peer_id = envelope.original_sender_id().unwrap_or_default();
10310 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10311 let symbol = Self::deserialize_symbol(symbol)?;
10312 this.read_with(&cx, |this, _| {
10313 if let SymbolLocation::OutsideProject {
10314 abs_path,
10315 signature,
10316 } = &symbol.path
10317 {
10318 let new_signature = this.symbol_signature(&abs_path);
10319 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10320 }
10321 Ok(())
10322 })??;
10323 let buffer = this
10324 .update(&mut cx, |this, cx| {
10325 this.open_buffer_for_symbol(
10326 &Symbol {
10327 language_server_name: symbol.language_server_name,
10328 source_worktree_id: symbol.source_worktree_id,
10329 source_language_server_id: symbol.source_language_server_id,
10330 path: symbol.path,
10331 name: symbol.name,
10332 kind: symbol.kind,
10333 range: symbol.range,
10334 label: CodeLabel::default(),
10335 },
10336 cx,
10337 )
10338 })?
10339 .await?;
10340
10341 this.update(&mut cx, |this, cx| {
10342 let is_private = buffer
10343 .read(cx)
10344 .file()
10345 .map(|f| f.is_private())
10346 .unwrap_or_default();
10347 if is_private {
10348 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10349 } else {
10350 this.buffer_store
10351 .update(cx, |buffer_store, cx| {
10352 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10353 })
10354 .detach_and_log_err(cx);
10355 let buffer_id = buffer.read(cx).remote_id().to_proto();
10356 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10357 }
10358 })?
10359 }
10360
10361 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10362 let mut hasher = Sha256::new();
10363 hasher.update(abs_path.to_string_lossy().as_bytes());
10364 hasher.update(self.nonce.to_be_bytes());
10365 hasher.finalize().as_slice().try_into().unwrap()
10366 }
10367
10368 pub async fn handle_get_project_symbols(
10369 this: Entity<Self>,
10370 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10371 mut cx: AsyncApp,
10372 ) -> Result<proto::GetProjectSymbolsResponse> {
10373 let symbols = this
10374 .update(&mut cx, |this, cx| {
10375 this.symbols(&envelope.payload.query, cx)
10376 })?
10377 .await?;
10378
10379 Ok(proto::GetProjectSymbolsResponse {
10380 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10381 })
10382 }
10383
10384 pub async fn handle_restart_language_servers(
10385 this: Entity<Self>,
10386 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10387 mut cx: AsyncApp,
10388 ) -> Result<proto::Ack> {
10389 this.update(&mut cx, |lsp_store, cx| {
10390 let buffers =
10391 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10392 lsp_store.restart_language_servers_for_buffers(
10393 buffers,
10394 envelope
10395 .payload
10396 .only_servers
10397 .into_iter()
10398 .filter_map(|selector| {
10399 Some(match selector.selector? {
10400 proto::language_server_selector::Selector::ServerId(server_id) => {
10401 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10402 }
10403 proto::language_server_selector::Selector::Name(name) => {
10404 LanguageServerSelector::Name(LanguageServerName(
10405 SharedString::from(name),
10406 ))
10407 }
10408 })
10409 })
10410 .collect(),
10411 cx,
10412 );
10413 })?;
10414
10415 Ok(proto::Ack {})
10416 }
10417
10418 pub async fn handle_stop_language_servers(
10419 lsp_store: Entity<Self>,
10420 envelope: TypedEnvelope<proto::StopLanguageServers>,
10421 mut cx: AsyncApp,
10422 ) -> Result<proto::Ack> {
10423 lsp_store.update(&mut cx, |lsp_store, cx| {
10424 if envelope.payload.all
10425 && envelope.payload.also_servers.is_empty()
10426 && envelope.payload.buffer_ids.is_empty()
10427 {
10428 lsp_store.stop_all_language_servers(cx);
10429 } else {
10430 let buffers =
10431 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10432 lsp_store
10433 .stop_language_servers_for_buffers(
10434 buffers,
10435 envelope
10436 .payload
10437 .also_servers
10438 .into_iter()
10439 .filter_map(|selector| {
10440 Some(match selector.selector? {
10441 proto::language_server_selector::Selector::ServerId(
10442 server_id,
10443 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10444 server_id,
10445 )),
10446 proto::language_server_selector::Selector::Name(name) => {
10447 LanguageServerSelector::Name(LanguageServerName(
10448 SharedString::from(name),
10449 ))
10450 }
10451 })
10452 })
10453 .collect(),
10454 cx,
10455 )
10456 .detach_and_log_err(cx);
10457 }
10458 })?;
10459
10460 Ok(proto::Ack {})
10461 }
10462
10463 pub async fn handle_cancel_language_server_work(
10464 lsp_store: Entity<Self>,
10465 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10466 mut cx: AsyncApp,
10467 ) -> Result<proto::Ack> {
10468 lsp_store.update(&mut cx, |lsp_store, cx| {
10469 if let Some(work) = envelope.payload.work {
10470 match work {
10471 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10472 let buffers =
10473 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10474 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10475 }
10476 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10477 let server_id = LanguageServerId::from_proto(work.language_server_id);
10478 let token = work
10479 .token
10480 .map(|token| {
10481 ProgressToken::from_proto(token)
10482 .context("invalid work progress token")
10483 })
10484 .transpose()?;
10485 lsp_store.cancel_language_server_work(server_id, token, cx);
10486 }
10487 }
10488 }
10489 anyhow::Ok(())
10490 })??;
10491
10492 Ok(proto::Ack {})
10493 }
10494
10495 fn buffer_ids_to_buffers(
10496 &mut self,
10497 buffer_ids: impl Iterator<Item = u64>,
10498 cx: &mut Context<Self>,
10499 ) -> Vec<Entity<Buffer>> {
10500 buffer_ids
10501 .into_iter()
10502 .flat_map(|buffer_id| {
10503 self.buffer_store
10504 .read(cx)
10505 .get(BufferId::new(buffer_id).log_err()?)
10506 })
10507 .collect::<Vec<_>>()
10508 }
10509
10510 async fn handle_apply_additional_edits_for_completion(
10511 this: Entity<Self>,
10512 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10513 mut cx: AsyncApp,
10514 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10515 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10516 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10517 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10518 let completion = Self::deserialize_completion(
10519 envelope.payload.completion.context("invalid completion")?,
10520 )?;
10521 anyhow::Ok((buffer, completion))
10522 })??;
10523
10524 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10525 this.apply_additional_edits_for_completion(
10526 buffer,
10527 Rc::new(RefCell::new(Box::new([Completion {
10528 replace_range: completion.replace_range,
10529 new_text: completion.new_text,
10530 source: completion.source,
10531 documentation: None,
10532 label: CodeLabel::default(),
10533 match_start: None,
10534 snippet_deduplication_key: None,
10535 insert_text_mode: None,
10536 icon_path: None,
10537 confirm: None,
10538 }]))),
10539 0,
10540 false,
10541 cx,
10542 )
10543 })?;
10544
10545 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10546 transaction: apply_additional_edits
10547 .await?
10548 .as_ref()
10549 .map(language::proto::serialize_transaction),
10550 })
10551 }
10552
10553 pub fn last_formatting_failure(&self) -> Option<&str> {
10554 self.last_formatting_failure.as_deref()
10555 }
10556
10557 pub fn reset_last_formatting_failure(&mut self) {
10558 self.last_formatting_failure = None;
10559 }
10560
10561 pub fn environment_for_buffer(
10562 &self,
10563 buffer: &Entity<Buffer>,
10564 cx: &mut Context<Self>,
10565 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10566 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10567 environment.update(cx, |env, cx| {
10568 env.buffer_environment(buffer, &self.worktree_store, cx)
10569 })
10570 } else {
10571 Task::ready(None).shared()
10572 }
10573 }
10574
10575 pub fn format(
10576 &mut self,
10577 buffers: HashSet<Entity<Buffer>>,
10578 target: LspFormatTarget,
10579 push_to_history: bool,
10580 trigger: FormatTrigger,
10581 cx: &mut Context<Self>,
10582 ) -> Task<anyhow::Result<ProjectTransaction>> {
10583 let logger = zlog::scoped!("format");
10584 if self.as_local().is_some() {
10585 zlog::trace!(logger => "Formatting locally");
10586 let logger = zlog::scoped!(logger => "local");
10587 let buffers = buffers
10588 .into_iter()
10589 .map(|buffer_handle| {
10590 let buffer = buffer_handle.read(cx);
10591 let buffer_abs_path = File::from_dyn(buffer.file())
10592 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10593
10594 (buffer_handle, buffer_abs_path, buffer.remote_id())
10595 })
10596 .collect::<Vec<_>>();
10597
10598 cx.spawn(async move |lsp_store, cx| {
10599 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10600
10601 for (handle, abs_path, id) in buffers {
10602 let env = lsp_store
10603 .update(cx, |lsp_store, cx| {
10604 lsp_store.environment_for_buffer(&handle, cx)
10605 })?
10606 .await;
10607
10608 let ranges = match &target {
10609 LspFormatTarget::Buffers => None,
10610 LspFormatTarget::Ranges(ranges) => {
10611 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10612 }
10613 };
10614
10615 formattable_buffers.push(FormattableBuffer {
10616 handle,
10617 abs_path,
10618 env,
10619 ranges,
10620 });
10621 }
10622 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10623
10624 let format_timer = zlog::time!(logger => "Formatting buffers");
10625 let result = LocalLspStore::format_locally(
10626 lsp_store.clone(),
10627 formattable_buffers,
10628 push_to_history,
10629 trigger,
10630 logger,
10631 cx,
10632 )
10633 .await;
10634 format_timer.end();
10635
10636 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10637
10638 lsp_store.update(cx, |lsp_store, _| {
10639 lsp_store.update_last_formatting_failure(&result);
10640 })?;
10641
10642 result
10643 })
10644 } else if let Some((client, project_id)) = self.upstream_client() {
10645 zlog::trace!(logger => "Formatting remotely");
10646 let logger = zlog::scoped!(logger => "remote");
10647 // Don't support formatting ranges via remote
10648 match target {
10649 LspFormatTarget::Buffers => {}
10650 LspFormatTarget::Ranges(_) => {
10651 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10652 return Task::ready(Ok(ProjectTransaction::default()));
10653 }
10654 }
10655
10656 let buffer_store = self.buffer_store();
10657 cx.spawn(async move |lsp_store, cx| {
10658 zlog::trace!(logger => "Sending remote format request");
10659 let request_timer = zlog::time!(logger => "remote format request");
10660 let result = client
10661 .request(proto::FormatBuffers {
10662 project_id,
10663 trigger: trigger as i32,
10664 buffer_ids: buffers
10665 .iter()
10666 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10667 .collect::<Result<_>>()?,
10668 })
10669 .await
10670 .and_then(|result| result.transaction.context("missing transaction"));
10671 request_timer.end();
10672
10673 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10674
10675 lsp_store.update(cx, |lsp_store, _| {
10676 lsp_store.update_last_formatting_failure(&result);
10677 })?;
10678
10679 let transaction_response = result?;
10680 let _timer = zlog::time!(logger => "deserializing project transaction");
10681 buffer_store
10682 .update(cx, |buffer_store, cx| {
10683 buffer_store.deserialize_project_transaction(
10684 transaction_response,
10685 push_to_history,
10686 cx,
10687 )
10688 })?
10689 .await
10690 })
10691 } else {
10692 zlog::trace!(logger => "Not formatting");
10693 Task::ready(Ok(ProjectTransaction::default()))
10694 }
10695 }
10696
10697 async fn handle_format_buffers(
10698 this: Entity<Self>,
10699 envelope: TypedEnvelope<proto::FormatBuffers>,
10700 mut cx: AsyncApp,
10701 ) -> Result<proto::FormatBuffersResponse> {
10702 let sender_id = envelope.original_sender_id().unwrap_or_default();
10703 let format = this.update(&mut cx, |this, cx| {
10704 let mut buffers = HashSet::default();
10705 for buffer_id in &envelope.payload.buffer_ids {
10706 let buffer_id = BufferId::new(*buffer_id)?;
10707 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10708 }
10709 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10710 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10711 })??;
10712
10713 let project_transaction = format.await?;
10714 let project_transaction = this.update(&mut cx, |this, cx| {
10715 this.buffer_store.update(cx, |buffer_store, cx| {
10716 buffer_store.serialize_project_transaction_for_peer(
10717 project_transaction,
10718 sender_id,
10719 cx,
10720 )
10721 })
10722 })?;
10723 Ok(proto::FormatBuffersResponse {
10724 transaction: Some(project_transaction),
10725 })
10726 }
10727
10728 async fn handle_apply_code_action_kind(
10729 this: Entity<Self>,
10730 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10731 mut cx: AsyncApp,
10732 ) -> Result<proto::ApplyCodeActionKindResponse> {
10733 let sender_id = envelope.original_sender_id().unwrap_or_default();
10734 let format = this.update(&mut cx, |this, cx| {
10735 let mut buffers = HashSet::default();
10736 for buffer_id in &envelope.payload.buffer_ids {
10737 let buffer_id = BufferId::new(*buffer_id)?;
10738 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10739 }
10740 let kind = match envelope.payload.kind.as_str() {
10741 "" => CodeActionKind::EMPTY,
10742 "quickfix" => CodeActionKind::QUICKFIX,
10743 "refactor" => CodeActionKind::REFACTOR,
10744 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10745 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10746 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10747 "source" => CodeActionKind::SOURCE,
10748 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10749 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10750 _ => anyhow::bail!(
10751 "Invalid code action kind {}",
10752 envelope.payload.kind.as_str()
10753 ),
10754 };
10755 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10756 })??;
10757
10758 let project_transaction = format.await?;
10759 let project_transaction = this.update(&mut cx, |this, cx| {
10760 this.buffer_store.update(cx, |buffer_store, cx| {
10761 buffer_store.serialize_project_transaction_for_peer(
10762 project_transaction,
10763 sender_id,
10764 cx,
10765 )
10766 })
10767 })?;
10768 Ok(proto::ApplyCodeActionKindResponse {
10769 transaction: Some(project_transaction),
10770 })
10771 }
10772
10773 async fn shutdown_language_server(
10774 server_state: Option<LanguageServerState>,
10775 name: LanguageServerName,
10776 cx: &mut AsyncApp,
10777 ) {
10778 let server = match server_state {
10779 Some(LanguageServerState::Starting { startup, .. }) => {
10780 let mut timer = cx
10781 .background_executor()
10782 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10783 .fuse();
10784
10785 select! {
10786 server = startup.fuse() => server,
10787 () = timer => {
10788 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10789 None
10790 },
10791 }
10792 }
10793
10794 Some(LanguageServerState::Running { server, .. }) => Some(server),
10795
10796 None => None,
10797 };
10798
10799 if let Some(server) = server
10800 && let Some(shutdown) = server.shutdown()
10801 {
10802 shutdown.await;
10803 }
10804 }
10805
10806 // Returns a list of all of the worktrees which no longer have a language server and the root path
10807 // for the stopped server
10808 fn stop_local_language_server(
10809 &mut self,
10810 server_id: LanguageServerId,
10811 cx: &mut Context<Self>,
10812 ) -> Task<()> {
10813 let local = match &mut self.mode {
10814 LspStoreMode::Local(local) => local,
10815 _ => {
10816 return Task::ready(());
10817 }
10818 };
10819
10820 // Remove this server ID from all entries in the given worktree.
10821 local
10822 .language_server_ids
10823 .retain(|_, state| state.id != server_id);
10824 self.buffer_store.update(cx, |buffer_store, cx| {
10825 for buffer in buffer_store.buffers() {
10826 buffer.update(cx, |buffer, cx| {
10827 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10828 buffer.set_completion_triggers(server_id, Default::default(), cx);
10829 });
10830 }
10831 });
10832
10833 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10834 summaries.retain(|path, summaries_by_server_id| {
10835 if summaries_by_server_id.remove(&server_id).is_some() {
10836 if let Some((client, project_id)) = self.downstream_client.clone() {
10837 client
10838 .send(proto::UpdateDiagnosticSummary {
10839 project_id,
10840 worktree_id: worktree_id.to_proto(),
10841 summary: Some(proto::DiagnosticSummary {
10842 path: path.as_ref().to_proto(),
10843 language_server_id: server_id.0 as u64,
10844 error_count: 0,
10845 warning_count: 0,
10846 }),
10847 more_summaries: Vec::new(),
10848 })
10849 .log_err();
10850 }
10851 !summaries_by_server_id.is_empty()
10852 } else {
10853 true
10854 }
10855 });
10856 }
10857
10858 let local = self.as_local_mut().unwrap();
10859 for diagnostics in local.diagnostics.values_mut() {
10860 diagnostics.retain(|_, diagnostics_by_server_id| {
10861 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10862 diagnostics_by_server_id.remove(ix);
10863 !diagnostics_by_server_id.is_empty()
10864 } else {
10865 true
10866 }
10867 });
10868 }
10869 local.language_server_watched_paths.remove(&server_id);
10870
10871 let server_state = local.language_servers.remove(&server_id);
10872 self.cleanup_lsp_data(server_id);
10873 let name = self
10874 .language_server_statuses
10875 .remove(&server_id)
10876 .map(|status| status.name)
10877 .or_else(|| {
10878 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10879 Some(adapter.name())
10880 } else {
10881 None
10882 }
10883 });
10884
10885 if let Some(name) = name {
10886 log::info!("stopping language server {name}");
10887 self.languages
10888 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10889 cx.notify();
10890
10891 return cx.spawn(async move |lsp_store, cx| {
10892 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10893 lsp_store
10894 .update(cx, |lsp_store, cx| {
10895 lsp_store
10896 .languages
10897 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10898 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10899 cx.notify();
10900 })
10901 .ok();
10902 });
10903 }
10904
10905 if server_state.is_some() {
10906 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10907 }
10908 Task::ready(())
10909 }
10910
10911 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10912 if let Some((client, project_id)) = self.upstream_client() {
10913 let request = client.request(proto::StopLanguageServers {
10914 project_id,
10915 buffer_ids: Vec::new(),
10916 also_servers: Vec::new(),
10917 all: true,
10918 });
10919 cx.background_spawn(request).detach_and_log_err(cx);
10920 } else {
10921 let Some(local) = self.as_local_mut() else {
10922 return;
10923 };
10924 let language_servers_to_stop = local
10925 .language_server_ids
10926 .values()
10927 .map(|state| state.id)
10928 .collect();
10929 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10930 let tasks = language_servers_to_stop
10931 .into_iter()
10932 .map(|server| self.stop_local_language_server(server, cx))
10933 .collect::<Vec<_>>();
10934 cx.background_spawn(async move {
10935 futures::future::join_all(tasks).await;
10936 })
10937 .detach();
10938 }
10939 }
10940
10941 pub fn restart_language_servers_for_buffers(
10942 &mut self,
10943 buffers: Vec<Entity<Buffer>>,
10944 only_restart_servers: HashSet<LanguageServerSelector>,
10945 cx: &mut Context<Self>,
10946 ) {
10947 if let Some((client, project_id)) = self.upstream_client() {
10948 let request = client.request(proto::RestartLanguageServers {
10949 project_id,
10950 buffer_ids: buffers
10951 .into_iter()
10952 .map(|b| b.read(cx).remote_id().to_proto())
10953 .collect(),
10954 only_servers: only_restart_servers
10955 .into_iter()
10956 .map(|selector| {
10957 let selector = match selector {
10958 LanguageServerSelector::Id(language_server_id) => {
10959 proto::language_server_selector::Selector::ServerId(
10960 language_server_id.to_proto(),
10961 )
10962 }
10963 LanguageServerSelector::Name(language_server_name) => {
10964 proto::language_server_selector::Selector::Name(
10965 language_server_name.to_string(),
10966 )
10967 }
10968 };
10969 proto::LanguageServerSelector {
10970 selector: Some(selector),
10971 }
10972 })
10973 .collect(),
10974 all: false,
10975 });
10976 cx.background_spawn(request).detach_and_log_err(cx);
10977 } else {
10978 let stop_task = if only_restart_servers.is_empty() {
10979 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10980 } else {
10981 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10982 };
10983 cx.spawn(async move |lsp_store, cx| {
10984 stop_task.await;
10985 lsp_store
10986 .update(cx, |lsp_store, cx| {
10987 for buffer in buffers {
10988 lsp_store.register_buffer_with_language_servers(
10989 &buffer,
10990 only_restart_servers.clone(),
10991 true,
10992 cx,
10993 );
10994 }
10995 })
10996 .ok()
10997 })
10998 .detach();
10999 }
11000 }
11001
11002 pub fn stop_language_servers_for_buffers(
11003 &mut self,
11004 buffers: Vec<Entity<Buffer>>,
11005 also_stop_servers: HashSet<LanguageServerSelector>,
11006 cx: &mut Context<Self>,
11007 ) -> Task<Result<()>> {
11008 if let Some((client, project_id)) = self.upstream_client() {
11009 let request = client.request(proto::StopLanguageServers {
11010 project_id,
11011 buffer_ids: buffers
11012 .into_iter()
11013 .map(|b| b.read(cx).remote_id().to_proto())
11014 .collect(),
11015 also_servers: also_stop_servers
11016 .into_iter()
11017 .map(|selector| {
11018 let selector = match selector {
11019 LanguageServerSelector::Id(language_server_id) => {
11020 proto::language_server_selector::Selector::ServerId(
11021 language_server_id.to_proto(),
11022 )
11023 }
11024 LanguageServerSelector::Name(language_server_name) => {
11025 proto::language_server_selector::Selector::Name(
11026 language_server_name.to_string(),
11027 )
11028 }
11029 };
11030 proto::LanguageServerSelector {
11031 selector: Some(selector),
11032 }
11033 })
11034 .collect(),
11035 all: false,
11036 });
11037 cx.background_spawn(async move {
11038 let _ = request.await?;
11039 Ok(())
11040 })
11041 } else {
11042 let task =
11043 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11044 cx.background_spawn(async move {
11045 task.await;
11046 Ok(())
11047 })
11048 }
11049 }
11050
11051 fn stop_local_language_servers_for_buffers(
11052 &mut self,
11053 buffers: &[Entity<Buffer>],
11054 also_stop_servers: HashSet<LanguageServerSelector>,
11055 cx: &mut Context<Self>,
11056 ) -> Task<()> {
11057 let Some(local) = self.as_local_mut() else {
11058 return Task::ready(());
11059 };
11060 let mut language_server_names_to_stop = BTreeSet::default();
11061 let mut language_servers_to_stop = also_stop_servers
11062 .into_iter()
11063 .flat_map(|selector| match selector {
11064 LanguageServerSelector::Id(id) => Some(id),
11065 LanguageServerSelector::Name(name) => {
11066 language_server_names_to_stop.insert(name);
11067 None
11068 }
11069 })
11070 .collect::<BTreeSet<_>>();
11071
11072 let mut covered_worktrees = HashSet::default();
11073 for buffer in buffers {
11074 buffer.update(cx, |buffer, cx| {
11075 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11076 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11077 && covered_worktrees.insert(worktree_id)
11078 {
11079 language_server_names_to_stop.retain(|name| {
11080 let old_ids_count = language_servers_to_stop.len();
11081 let all_language_servers_with_this_name = local
11082 .language_server_ids
11083 .iter()
11084 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11085 language_servers_to_stop.extend(all_language_servers_with_this_name);
11086 old_ids_count == language_servers_to_stop.len()
11087 });
11088 }
11089 });
11090 }
11091 for name in language_server_names_to_stop {
11092 language_servers_to_stop.extend(
11093 local
11094 .language_server_ids
11095 .iter()
11096 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11097 );
11098 }
11099
11100 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11101 let tasks = language_servers_to_stop
11102 .into_iter()
11103 .map(|server| self.stop_local_language_server(server, cx))
11104 .collect::<Vec<_>>();
11105
11106 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11107 }
11108
11109 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11110 let (worktree, relative_path) =
11111 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11112
11113 let project_path = ProjectPath {
11114 worktree_id: worktree.read(cx).id(),
11115 path: relative_path,
11116 };
11117
11118 Some(
11119 self.buffer_store()
11120 .read(cx)
11121 .get_by_path(&project_path)?
11122 .read(cx),
11123 )
11124 }
11125
11126 #[cfg(any(test, feature = "test-support"))]
11127 pub fn update_diagnostics(
11128 &mut self,
11129 server_id: LanguageServerId,
11130 diagnostics: lsp::PublishDiagnosticsParams,
11131 result_id: Option<SharedString>,
11132 source_kind: DiagnosticSourceKind,
11133 disk_based_sources: &[String],
11134 cx: &mut Context<Self>,
11135 ) -> Result<()> {
11136 self.merge_lsp_diagnostics(
11137 source_kind,
11138 vec![DocumentDiagnosticsUpdate {
11139 diagnostics,
11140 result_id,
11141 server_id,
11142 disk_based_sources: Cow::Borrowed(disk_based_sources),
11143 registration_id: None,
11144 }],
11145 |_, _, _| false,
11146 cx,
11147 )
11148 }
11149
11150 pub fn merge_lsp_diagnostics(
11151 &mut self,
11152 source_kind: DiagnosticSourceKind,
11153 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11154 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11155 cx: &mut Context<Self>,
11156 ) -> Result<()> {
11157 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11158 let updates = lsp_diagnostics
11159 .into_iter()
11160 .filter_map(|update| {
11161 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11162 Some(DocumentDiagnosticsUpdate {
11163 diagnostics: self.lsp_to_document_diagnostics(
11164 abs_path,
11165 source_kind,
11166 update.server_id,
11167 update.diagnostics,
11168 &update.disk_based_sources,
11169 update.registration_id.clone(),
11170 ),
11171 result_id: update.result_id,
11172 server_id: update.server_id,
11173 disk_based_sources: update.disk_based_sources,
11174 registration_id: update.registration_id,
11175 })
11176 })
11177 .collect();
11178 self.merge_diagnostic_entries(updates, merge, cx)?;
11179 Ok(())
11180 }
11181
11182 fn lsp_to_document_diagnostics(
11183 &mut self,
11184 document_abs_path: PathBuf,
11185 source_kind: DiagnosticSourceKind,
11186 server_id: LanguageServerId,
11187 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11188 disk_based_sources: &[String],
11189 registration_id: Option<SharedString>,
11190 ) -> DocumentDiagnostics {
11191 let mut diagnostics = Vec::default();
11192 let mut primary_diagnostic_group_ids = HashMap::default();
11193 let mut sources_by_group_id = HashMap::default();
11194 let mut supporting_diagnostics = HashMap::default();
11195
11196 let adapter = self.language_server_adapter_for_id(server_id);
11197
11198 // Ensure that primary diagnostics are always the most severe
11199 lsp_diagnostics
11200 .diagnostics
11201 .sort_by_key(|item| item.severity);
11202
11203 for diagnostic in &lsp_diagnostics.diagnostics {
11204 let source = diagnostic.source.as_ref();
11205 let range = range_from_lsp(diagnostic.range);
11206 let is_supporting = diagnostic
11207 .related_information
11208 .as_ref()
11209 .is_some_and(|infos| {
11210 infos.iter().any(|info| {
11211 primary_diagnostic_group_ids.contains_key(&(
11212 source,
11213 diagnostic.code.clone(),
11214 range_from_lsp(info.location.range),
11215 ))
11216 })
11217 });
11218
11219 let is_unnecessary = diagnostic
11220 .tags
11221 .as_ref()
11222 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11223
11224 let underline = self
11225 .language_server_adapter_for_id(server_id)
11226 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11227
11228 if is_supporting {
11229 supporting_diagnostics.insert(
11230 (source, diagnostic.code.clone(), range),
11231 (diagnostic.severity, is_unnecessary),
11232 );
11233 } else {
11234 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11235 let is_disk_based =
11236 source.is_some_and(|source| disk_based_sources.contains(source));
11237
11238 sources_by_group_id.insert(group_id, source);
11239 primary_diagnostic_group_ids
11240 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11241
11242 diagnostics.push(DiagnosticEntry {
11243 range,
11244 diagnostic: Diagnostic {
11245 source: diagnostic.source.clone(),
11246 source_kind,
11247 code: diagnostic.code.clone(),
11248 code_description: diagnostic
11249 .code_description
11250 .as_ref()
11251 .and_then(|d| d.href.clone()),
11252 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11253 markdown: adapter.as_ref().and_then(|adapter| {
11254 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11255 }),
11256 message: diagnostic.message.trim().to_string(),
11257 group_id,
11258 is_primary: true,
11259 is_disk_based,
11260 is_unnecessary,
11261 underline,
11262 data: diagnostic.data.clone(),
11263 registration_id: registration_id.clone(),
11264 },
11265 });
11266 if let Some(infos) = &diagnostic.related_information {
11267 for info in infos {
11268 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11269 let range = range_from_lsp(info.location.range);
11270 diagnostics.push(DiagnosticEntry {
11271 range,
11272 diagnostic: Diagnostic {
11273 source: diagnostic.source.clone(),
11274 source_kind,
11275 code: diagnostic.code.clone(),
11276 code_description: diagnostic
11277 .code_description
11278 .as_ref()
11279 .and_then(|d| d.href.clone()),
11280 severity: DiagnosticSeverity::INFORMATION,
11281 markdown: adapter.as_ref().and_then(|adapter| {
11282 adapter.diagnostic_message_to_markdown(&info.message)
11283 }),
11284 message: info.message.trim().to_string(),
11285 group_id,
11286 is_primary: false,
11287 is_disk_based,
11288 is_unnecessary: false,
11289 underline,
11290 data: diagnostic.data.clone(),
11291 registration_id: registration_id.clone(),
11292 },
11293 });
11294 }
11295 }
11296 }
11297 }
11298 }
11299
11300 for entry in &mut diagnostics {
11301 let diagnostic = &mut entry.diagnostic;
11302 if !diagnostic.is_primary {
11303 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11304 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11305 source,
11306 diagnostic.code.clone(),
11307 entry.range.clone(),
11308 )) {
11309 if let Some(severity) = severity {
11310 diagnostic.severity = severity;
11311 }
11312 diagnostic.is_unnecessary = is_unnecessary;
11313 }
11314 }
11315 }
11316
11317 DocumentDiagnostics {
11318 diagnostics,
11319 document_abs_path,
11320 version: lsp_diagnostics.version,
11321 }
11322 }
11323
11324 fn insert_newly_running_language_server(
11325 &mut self,
11326 adapter: Arc<CachedLspAdapter>,
11327 language_server: Arc<LanguageServer>,
11328 server_id: LanguageServerId,
11329 key: LanguageServerSeed,
11330 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11331 cx: &mut Context<Self>,
11332 ) {
11333 let Some(local) = self.as_local_mut() else {
11334 return;
11335 };
11336 // If the language server for this key doesn't match the server id, don't store the
11337 // server. Which will cause it to be dropped, killing the process
11338 if local
11339 .language_server_ids
11340 .get(&key)
11341 .map(|state| state.id != server_id)
11342 .unwrap_or(false)
11343 {
11344 return;
11345 }
11346
11347 // Update language_servers collection with Running variant of LanguageServerState
11348 // indicating that the server is up and running and ready
11349 let workspace_folders = workspace_folders.lock().clone();
11350 language_server.set_workspace_folders(workspace_folders);
11351
11352 let workspace_diagnostics_refresh_tasks = language_server
11353 .capabilities()
11354 .diagnostic_provider
11355 .and_then(|provider| {
11356 local
11357 .language_server_dynamic_registrations
11358 .entry(server_id)
11359 .or_default()
11360 .diagnostics
11361 .entry(None)
11362 .or_insert(provider.clone());
11363 let workspace_refresher =
11364 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11365
11366 Some((None, workspace_refresher))
11367 })
11368 .into_iter()
11369 .collect();
11370 local.language_servers.insert(
11371 server_id,
11372 LanguageServerState::Running {
11373 workspace_diagnostics_refresh_tasks,
11374 adapter: adapter.clone(),
11375 server: language_server.clone(),
11376 simulate_disk_based_diagnostics_completion: None,
11377 },
11378 );
11379 local
11380 .languages
11381 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11382 if let Some(file_ops_caps) = language_server
11383 .capabilities()
11384 .workspace
11385 .as_ref()
11386 .and_then(|ws| ws.file_operations.as_ref())
11387 {
11388 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11389 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11390 if did_rename_caps.or(will_rename_caps).is_some() {
11391 let watcher = RenamePathsWatchedForServer::default()
11392 .with_did_rename_patterns(did_rename_caps)
11393 .with_will_rename_patterns(will_rename_caps);
11394 local
11395 .language_server_paths_watched_for_rename
11396 .insert(server_id, watcher);
11397 }
11398 }
11399
11400 self.language_server_statuses.insert(
11401 server_id,
11402 LanguageServerStatus {
11403 name: language_server.name(),
11404 pending_work: Default::default(),
11405 has_pending_diagnostic_updates: false,
11406 progress_tokens: Default::default(),
11407 worktree: Some(key.worktree_id),
11408 binary: Some(language_server.binary().clone()),
11409 configuration: Some(language_server.configuration().clone()),
11410 workspace_folders: language_server.workspace_folders(),
11411 },
11412 );
11413
11414 cx.emit(LspStoreEvent::LanguageServerAdded(
11415 server_id,
11416 language_server.name(),
11417 Some(key.worktree_id),
11418 ));
11419
11420 let server_capabilities = language_server.capabilities();
11421 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11422 downstream_client
11423 .send(proto::StartLanguageServer {
11424 project_id: *project_id,
11425 server: Some(proto::LanguageServer {
11426 id: server_id.to_proto(),
11427 name: language_server.name().to_string(),
11428 worktree_id: Some(key.worktree_id.to_proto()),
11429 }),
11430 capabilities: serde_json::to_string(&server_capabilities)
11431 .expect("serializing server LSP capabilities"),
11432 })
11433 .log_err();
11434 }
11435 self.lsp_server_capabilities
11436 .insert(server_id, server_capabilities);
11437
11438 // Tell the language server about every open buffer in the worktree that matches the language.
11439 // Also check for buffers in worktrees that reused this server
11440 let mut worktrees_using_server = vec![key.worktree_id];
11441 if let Some(local) = self.as_local() {
11442 // Find all worktrees that have this server in their language server tree
11443 for (worktree_id, servers) in &local.lsp_tree.instances {
11444 if *worktree_id != key.worktree_id {
11445 for server_map in servers.roots.values() {
11446 if server_map
11447 .values()
11448 .any(|(node, _)| node.id() == Some(server_id))
11449 {
11450 worktrees_using_server.push(*worktree_id);
11451 }
11452 }
11453 }
11454 }
11455 }
11456
11457 let mut buffer_paths_registered = Vec::new();
11458 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11459 let mut lsp_adapters = HashMap::default();
11460 for buffer_handle in buffer_store.buffers() {
11461 let buffer = buffer_handle.read(cx);
11462 let file = match File::from_dyn(buffer.file()) {
11463 Some(file) => file,
11464 None => continue,
11465 };
11466 let language = match buffer.language() {
11467 Some(language) => language,
11468 None => continue,
11469 };
11470
11471 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11472 || !lsp_adapters
11473 .entry(language.name())
11474 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11475 .iter()
11476 .any(|a| a.name == key.name)
11477 {
11478 continue;
11479 }
11480 // didOpen
11481 let file = match file.as_local() {
11482 Some(file) => file,
11483 None => continue,
11484 };
11485
11486 let local = self.as_local_mut().unwrap();
11487
11488 let buffer_id = buffer.remote_id();
11489 if local.registered_buffers.contains_key(&buffer_id) {
11490 let versions = local
11491 .buffer_snapshots
11492 .entry(buffer_id)
11493 .or_default()
11494 .entry(server_id)
11495 .and_modify(|_| {
11496 assert!(
11497 false,
11498 "There should not be an existing snapshot for a newly inserted buffer"
11499 )
11500 })
11501 .or_insert_with(|| {
11502 vec![LspBufferSnapshot {
11503 version: 0,
11504 snapshot: buffer.text_snapshot(),
11505 }]
11506 });
11507
11508 let snapshot = versions.last().unwrap();
11509 let version = snapshot.version;
11510 let initial_snapshot = &snapshot.snapshot;
11511 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11512 language_server.register_buffer(
11513 uri,
11514 adapter.language_id(&language.name()),
11515 version,
11516 initial_snapshot.text(),
11517 );
11518 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11519 local
11520 .buffers_opened_in_servers
11521 .entry(buffer_id)
11522 .or_default()
11523 .insert(server_id);
11524 }
11525 buffer_handle.update(cx, |buffer, cx| {
11526 buffer.set_completion_triggers(
11527 server_id,
11528 language_server
11529 .capabilities()
11530 .completion_provider
11531 .as_ref()
11532 .and_then(|provider| {
11533 provider
11534 .trigger_characters
11535 .as_ref()
11536 .map(|characters| characters.iter().cloned().collect())
11537 })
11538 .unwrap_or_default(),
11539 cx,
11540 )
11541 });
11542 }
11543 });
11544
11545 for (buffer_id, abs_path) in buffer_paths_registered {
11546 cx.emit(LspStoreEvent::LanguageServerUpdate {
11547 language_server_id: server_id,
11548 name: Some(adapter.name()),
11549 message: proto::update_language_server::Variant::RegisteredForBuffer(
11550 proto::RegisteredForBuffer {
11551 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11552 buffer_id: buffer_id.to_proto(),
11553 },
11554 ),
11555 });
11556 }
11557
11558 cx.notify();
11559 }
11560
11561 pub fn language_servers_running_disk_based_diagnostics(
11562 &self,
11563 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11564 self.language_server_statuses
11565 .iter()
11566 .filter_map(|(id, status)| {
11567 if status.has_pending_diagnostic_updates {
11568 Some(*id)
11569 } else {
11570 None
11571 }
11572 })
11573 }
11574
11575 pub(crate) fn cancel_language_server_work_for_buffers(
11576 &mut self,
11577 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11578 cx: &mut Context<Self>,
11579 ) {
11580 if let Some((client, project_id)) = self.upstream_client() {
11581 let request = client.request(proto::CancelLanguageServerWork {
11582 project_id,
11583 work: Some(proto::cancel_language_server_work::Work::Buffers(
11584 proto::cancel_language_server_work::Buffers {
11585 buffer_ids: buffers
11586 .into_iter()
11587 .map(|b| b.read(cx).remote_id().to_proto())
11588 .collect(),
11589 },
11590 )),
11591 });
11592 cx.background_spawn(request).detach_and_log_err(cx);
11593 } else if let Some(local) = self.as_local() {
11594 let servers = buffers
11595 .into_iter()
11596 .flat_map(|buffer| {
11597 buffer.update(cx, |buffer, cx| {
11598 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11599 })
11600 })
11601 .collect::<HashSet<_>>();
11602 for server_id in servers {
11603 self.cancel_language_server_work(server_id, None, cx);
11604 }
11605 }
11606 }
11607
11608 pub(crate) fn cancel_language_server_work(
11609 &mut self,
11610 server_id: LanguageServerId,
11611 token_to_cancel: Option<ProgressToken>,
11612 cx: &mut Context<Self>,
11613 ) {
11614 if let Some(local) = self.as_local() {
11615 let status = self.language_server_statuses.get(&server_id);
11616 let server = local.language_servers.get(&server_id);
11617 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11618 {
11619 for (token, progress) in &status.pending_work {
11620 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11621 && token != token_to_cancel
11622 {
11623 continue;
11624 }
11625 if progress.is_cancellable {
11626 server
11627 .notify::<lsp::notification::WorkDoneProgressCancel>(
11628 WorkDoneProgressCancelParams {
11629 token: token.to_lsp(),
11630 },
11631 )
11632 .ok();
11633 }
11634 }
11635 }
11636 } else if let Some((client, project_id)) = self.upstream_client() {
11637 let request = client.request(proto::CancelLanguageServerWork {
11638 project_id,
11639 work: Some(
11640 proto::cancel_language_server_work::Work::LanguageServerWork(
11641 proto::cancel_language_server_work::LanguageServerWork {
11642 language_server_id: server_id.to_proto(),
11643 token: token_to_cancel.map(|token| token.to_proto()),
11644 },
11645 ),
11646 ),
11647 });
11648 cx.background_spawn(request).detach_and_log_err(cx);
11649 }
11650 }
11651
11652 fn register_supplementary_language_server(
11653 &mut self,
11654 id: LanguageServerId,
11655 name: LanguageServerName,
11656 server: Arc<LanguageServer>,
11657 cx: &mut Context<Self>,
11658 ) {
11659 if let Some(local) = self.as_local_mut() {
11660 local
11661 .supplementary_language_servers
11662 .insert(id, (name.clone(), server));
11663 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11664 }
11665 }
11666
11667 fn unregister_supplementary_language_server(
11668 &mut self,
11669 id: LanguageServerId,
11670 cx: &mut Context<Self>,
11671 ) {
11672 if let Some(local) = self.as_local_mut() {
11673 local.supplementary_language_servers.remove(&id);
11674 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11675 }
11676 }
11677
11678 pub(crate) fn supplementary_language_servers(
11679 &self,
11680 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11681 self.as_local().into_iter().flat_map(|local| {
11682 local
11683 .supplementary_language_servers
11684 .iter()
11685 .map(|(id, (name, _))| (*id, name.clone()))
11686 })
11687 }
11688
11689 pub fn language_server_adapter_for_id(
11690 &self,
11691 id: LanguageServerId,
11692 ) -> Option<Arc<CachedLspAdapter>> {
11693 self.as_local()
11694 .and_then(|local| local.language_servers.get(&id))
11695 .and_then(|language_server_state| match language_server_state {
11696 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11697 _ => None,
11698 })
11699 }
11700
11701 pub(super) fn update_local_worktree_language_servers(
11702 &mut self,
11703 worktree_handle: &Entity<Worktree>,
11704 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11705 cx: &mut Context<Self>,
11706 ) {
11707 if changes.is_empty() {
11708 return;
11709 }
11710
11711 let Some(local) = self.as_local() else { return };
11712
11713 local.prettier_store.update(cx, |prettier_store, cx| {
11714 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11715 });
11716
11717 let worktree_id = worktree_handle.read(cx).id();
11718 let mut language_server_ids = local
11719 .language_server_ids
11720 .iter()
11721 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11722 .collect::<Vec<_>>();
11723 language_server_ids.sort();
11724 language_server_ids.dedup();
11725
11726 // let abs_path = worktree_handle.read(cx).abs_path();
11727 for server_id in &language_server_ids {
11728 if let Some(LanguageServerState::Running { server, .. }) =
11729 local.language_servers.get(server_id)
11730 && let Some(watched_paths) = local
11731 .language_server_watched_paths
11732 .get(server_id)
11733 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11734 {
11735 let params = lsp::DidChangeWatchedFilesParams {
11736 changes: changes
11737 .iter()
11738 .filter_map(|(path, _, change)| {
11739 if !watched_paths.is_match(path.as_std_path()) {
11740 return None;
11741 }
11742 let typ = match change {
11743 PathChange::Loaded => return None,
11744 PathChange::Added => lsp::FileChangeType::CREATED,
11745 PathChange::Removed => lsp::FileChangeType::DELETED,
11746 PathChange::Updated => lsp::FileChangeType::CHANGED,
11747 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11748 };
11749 let uri = lsp::Uri::from_file_path(
11750 worktree_handle.read(cx).absolutize(&path),
11751 )
11752 .ok()?;
11753 Some(lsp::FileEvent { uri, typ })
11754 })
11755 .collect(),
11756 };
11757 if !params.changes.is_empty() {
11758 server
11759 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11760 .ok();
11761 }
11762 }
11763 }
11764 for (path, _, _) in changes {
11765 if let Some(file_name) = path.file_name()
11766 && local.watched_manifest_filenames.contains(file_name)
11767 {
11768 self.request_workspace_config_refresh();
11769 break;
11770 }
11771 }
11772 }
11773
11774 pub fn wait_for_remote_buffer(
11775 &mut self,
11776 id: BufferId,
11777 cx: &mut Context<Self>,
11778 ) -> Task<Result<Entity<Buffer>>> {
11779 self.buffer_store.update(cx, |buffer_store, cx| {
11780 buffer_store.wait_for_remote_buffer(id, cx)
11781 })
11782 }
11783
11784 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11785 let mut result = proto::Symbol {
11786 language_server_name: symbol.language_server_name.0.to_string(),
11787 source_worktree_id: symbol.source_worktree_id.to_proto(),
11788 language_server_id: symbol.source_language_server_id.to_proto(),
11789 name: symbol.name.clone(),
11790 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11791 start: Some(proto::PointUtf16 {
11792 row: symbol.range.start.0.row,
11793 column: symbol.range.start.0.column,
11794 }),
11795 end: Some(proto::PointUtf16 {
11796 row: symbol.range.end.0.row,
11797 column: symbol.range.end.0.column,
11798 }),
11799 worktree_id: Default::default(),
11800 path: Default::default(),
11801 signature: Default::default(),
11802 };
11803 match &symbol.path {
11804 SymbolLocation::InProject(path) => {
11805 result.worktree_id = path.worktree_id.to_proto();
11806 result.path = path.path.to_proto();
11807 }
11808 SymbolLocation::OutsideProject {
11809 abs_path,
11810 signature,
11811 } => {
11812 result.path = abs_path.to_string_lossy().into_owned();
11813 result.signature = signature.to_vec();
11814 }
11815 }
11816 result
11817 }
11818
11819 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11820 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11821 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11822 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11823
11824 let path = if serialized_symbol.signature.is_empty() {
11825 SymbolLocation::InProject(ProjectPath {
11826 worktree_id,
11827 path: RelPath::from_proto(&serialized_symbol.path)
11828 .context("invalid symbol path")?,
11829 })
11830 } else {
11831 SymbolLocation::OutsideProject {
11832 abs_path: Path::new(&serialized_symbol.path).into(),
11833 signature: serialized_symbol
11834 .signature
11835 .try_into()
11836 .map_err(|_| anyhow!("invalid signature"))?,
11837 }
11838 };
11839
11840 let start = serialized_symbol.start.context("invalid start")?;
11841 let end = serialized_symbol.end.context("invalid end")?;
11842 Ok(CoreSymbol {
11843 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11844 source_worktree_id,
11845 source_language_server_id: LanguageServerId::from_proto(
11846 serialized_symbol.language_server_id,
11847 ),
11848 path,
11849 name: serialized_symbol.name,
11850 range: Unclipped(PointUtf16::new(start.row, start.column))
11851 ..Unclipped(PointUtf16::new(end.row, end.column)),
11852 kind,
11853 })
11854 }
11855
11856 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11857 let mut serialized_completion = proto::Completion {
11858 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11859 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11860 new_text: completion.new_text.clone(),
11861 ..proto::Completion::default()
11862 };
11863 match &completion.source {
11864 CompletionSource::Lsp {
11865 insert_range,
11866 server_id,
11867 lsp_completion,
11868 lsp_defaults,
11869 resolved,
11870 } => {
11871 let (old_insert_start, old_insert_end) = insert_range
11872 .as_ref()
11873 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11874 .unzip();
11875
11876 serialized_completion.old_insert_start = old_insert_start;
11877 serialized_completion.old_insert_end = old_insert_end;
11878 serialized_completion.source = proto::completion::Source::Lsp as i32;
11879 serialized_completion.server_id = server_id.0 as u64;
11880 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11881 serialized_completion.lsp_defaults = lsp_defaults
11882 .as_deref()
11883 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11884 serialized_completion.resolved = *resolved;
11885 }
11886 CompletionSource::BufferWord {
11887 word_range,
11888 resolved,
11889 } => {
11890 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11891 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11892 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11893 serialized_completion.resolved = *resolved;
11894 }
11895 CompletionSource::Custom => {
11896 serialized_completion.source = proto::completion::Source::Custom as i32;
11897 serialized_completion.resolved = true;
11898 }
11899 CompletionSource::Dap { sort_text } => {
11900 serialized_completion.source = proto::completion::Source::Dap as i32;
11901 serialized_completion.sort_text = Some(sort_text.clone());
11902 }
11903 }
11904
11905 serialized_completion
11906 }
11907
11908 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11909 let old_replace_start = completion
11910 .old_replace_start
11911 .and_then(deserialize_anchor)
11912 .context("invalid old start")?;
11913 let old_replace_end = completion
11914 .old_replace_end
11915 .and_then(deserialize_anchor)
11916 .context("invalid old end")?;
11917 let insert_range = {
11918 match completion.old_insert_start.zip(completion.old_insert_end) {
11919 Some((start, end)) => {
11920 let start = deserialize_anchor(start).context("invalid insert old start")?;
11921 let end = deserialize_anchor(end).context("invalid insert old end")?;
11922 Some(start..end)
11923 }
11924 None => None,
11925 }
11926 };
11927 Ok(CoreCompletion {
11928 replace_range: old_replace_start..old_replace_end,
11929 new_text: completion.new_text,
11930 source: match proto::completion::Source::from_i32(completion.source) {
11931 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11932 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11933 insert_range,
11934 server_id: LanguageServerId::from_proto(completion.server_id),
11935 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11936 lsp_defaults: completion
11937 .lsp_defaults
11938 .as_deref()
11939 .map(serde_json::from_slice)
11940 .transpose()?,
11941 resolved: completion.resolved,
11942 },
11943 Some(proto::completion::Source::BufferWord) => {
11944 let word_range = completion
11945 .buffer_word_start
11946 .and_then(deserialize_anchor)
11947 .context("invalid buffer word start")?
11948 ..completion
11949 .buffer_word_end
11950 .and_then(deserialize_anchor)
11951 .context("invalid buffer word end")?;
11952 CompletionSource::BufferWord {
11953 word_range,
11954 resolved: completion.resolved,
11955 }
11956 }
11957 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11958 sort_text: completion
11959 .sort_text
11960 .context("expected sort text to exist")?,
11961 },
11962 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11963 },
11964 })
11965 }
11966
11967 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11968 let (kind, lsp_action) = match &action.lsp_action {
11969 LspAction::Action(code_action) => (
11970 proto::code_action::Kind::Action as i32,
11971 serde_json::to_vec(code_action).unwrap(),
11972 ),
11973 LspAction::Command(command) => (
11974 proto::code_action::Kind::Command as i32,
11975 serde_json::to_vec(command).unwrap(),
11976 ),
11977 LspAction::CodeLens(code_lens) => (
11978 proto::code_action::Kind::CodeLens as i32,
11979 serde_json::to_vec(code_lens).unwrap(),
11980 ),
11981 };
11982
11983 proto::CodeAction {
11984 server_id: action.server_id.0 as u64,
11985 start: Some(serialize_anchor(&action.range.start)),
11986 end: Some(serialize_anchor(&action.range.end)),
11987 lsp_action,
11988 kind,
11989 resolved: action.resolved,
11990 }
11991 }
11992
11993 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11994 let start = action
11995 .start
11996 .and_then(deserialize_anchor)
11997 .context("invalid start")?;
11998 let end = action
11999 .end
12000 .and_then(deserialize_anchor)
12001 .context("invalid end")?;
12002 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12003 Some(proto::code_action::Kind::Action) => {
12004 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12005 }
12006 Some(proto::code_action::Kind::Command) => {
12007 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12008 }
12009 Some(proto::code_action::Kind::CodeLens) => {
12010 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12011 }
12012 None => anyhow::bail!("Unknown action kind {}", action.kind),
12013 };
12014 Ok(CodeAction {
12015 server_id: LanguageServerId(action.server_id as usize),
12016 range: start..end,
12017 resolved: action.resolved,
12018 lsp_action,
12019 })
12020 }
12021
12022 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12023 match &formatting_result {
12024 Ok(_) => self.last_formatting_failure = None,
12025 Err(error) => {
12026 let error_string = format!("{error:#}");
12027 log::error!("Formatting failed: {error_string}");
12028 self.last_formatting_failure
12029 .replace(error_string.lines().join(" "));
12030 }
12031 }
12032 }
12033
12034 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12035 self.lsp_server_capabilities.remove(&for_server);
12036 for lsp_data in self.lsp_data.values_mut() {
12037 lsp_data.remove_server_data(for_server);
12038 }
12039 if let Some(local) = self.as_local_mut() {
12040 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12041 local
12042 .workspace_pull_diagnostics_result_ids
12043 .remove(&for_server);
12044 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12045 buffer_servers.remove(&for_server);
12046 }
12047 }
12048 }
12049
12050 pub fn result_id_for_buffer_pull(
12051 &self,
12052 server_id: LanguageServerId,
12053 buffer_id: BufferId,
12054 registration_id: &Option<SharedString>,
12055 cx: &App,
12056 ) -> Option<SharedString> {
12057 let abs_path = self
12058 .buffer_store
12059 .read(cx)
12060 .get(buffer_id)
12061 .and_then(|b| File::from_dyn(b.read(cx).file()))
12062 .map(|f| f.abs_path(cx))?;
12063 self.as_local()?
12064 .buffer_pull_diagnostics_result_ids
12065 .get(&server_id)?
12066 .get(registration_id)?
12067 .get(&abs_path)?
12068 .clone()
12069 }
12070
12071 /// Gets all result_ids for a workspace diagnostics pull request.
12072 /// 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.
12073 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12074 pub fn result_ids_for_workspace_refresh(
12075 &self,
12076 server_id: LanguageServerId,
12077 registration_id: &Option<SharedString>,
12078 ) -> HashMap<PathBuf, SharedString> {
12079 let Some(local) = self.as_local() else {
12080 return HashMap::default();
12081 };
12082 local
12083 .workspace_pull_diagnostics_result_ids
12084 .get(&server_id)
12085 .into_iter()
12086 .filter_map(|diagnostics| diagnostics.get(registration_id))
12087 .flatten()
12088 .filter_map(|(abs_path, result_id)| {
12089 let result_id = local
12090 .buffer_pull_diagnostics_result_ids
12091 .get(&server_id)
12092 .and_then(|buffer_ids_result_ids| {
12093 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12094 })
12095 .cloned()
12096 .flatten()
12097 .or_else(|| result_id.clone())?;
12098 Some((abs_path.clone(), result_id))
12099 })
12100 .collect()
12101 }
12102
12103 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12104 if let Some(LanguageServerState::Running {
12105 workspace_diagnostics_refresh_tasks,
12106 ..
12107 }) = self
12108 .as_local_mut()
12109 .and_then(|local| local.language_servers.get_mut(&server_id))
12110 {
12111 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12112 diagnostics.refresh_tx.try_send(()).ok();
12113 }
12114 }
12115 }
12116
12117 pub fn pull_workspace_diagnostics_for_buffer(&mut self, buffer_id: BufferId, cx: &mut App) {
12118 let Some(buffer) = self.buffer_store().read(cx).get_existing(buffer_id).ok() else {
12119 return;
12120 };
12121 let Some(local) = self.as_local_mut() else {
12122 return;
12123 };
12124
12125 for server_id in buffer.update(cx, |buffer, cx| {
12126 local.language_server_ids_for_buffer(buffer, cx)
12127 }) {
12128 if let Some(LanguageServerState::Running {
12129 workspace_diagnostics_refresh_tasks,
12130 ..
12131 }) = local.language_servers.get_mut(&server_id)
12132 {
12133 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12134 diagnostics.refresh_tx.try_send(()).ok();
12135 }
12136 }
12137 }
12138 }
12139
12140 fn apply_workspace_diagnostic_report(
12141 &mut self,
12142 server_id: LanguageServerId,
12143 report: lsp::WorkspaceDiagnosticReportResult,
12144 registration_id: Option<SharedString>,
12145 cx: &mut Context<Self>,
12146 ) {
12147 let workspace_diagnostics =
12148 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12149 report,
12150 server_id,
12151 registration_id,
12152 );
12153 let mut unchanged_buffers = HashMap::default();
12154 let workspace_diagnostics_updates = workspace_diagnostics
12155 .into_iter()
12156 .filter_map(
12157 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12158 LspPullDiagnostics::Response {
12159 server_id,
12160 uri,
12161 diagnostics,
12162 registration_id,
12163 } => Some((
12164 server_id,
12165 uri,
12166 diagnostics,
12167 workspace_diagnostics.version,
12168 registration_id,
12169 )),
12170 LspPullDiagnostics::Default => None,
12171 },
12172 )
12173 .fold(
12174 HashMap::default(),
12175 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12176 let (result_id, diagnostics) = match diagnostics {
12177 PulledDiagnostics::Unchanged { result_id } => {
12178 unchanged_buffers
12179 .entry(new_registration_id.clone())
12180 .or_insert_with(HashSet::default)
12181 .insert(uri.clone());
12182 (Some(result_id), Vec::new())
12183 }
12184 PulledDiagnostics::Changed {
12185 result_id,
12186 diagnostics,
12187 } => (result_id, diagnostics),
12188 };
12189 let disk_based_sources = Cow::Owned(
12190 self.language_server_adapter_for_id(server_id)
12191 .as_ref()
12192 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12193 .unwrap_or(&[])
12194 .to_vec(),
12195 );
12196
12197 let Some(abs_path) = uri.to_file_path().ok() else {
12198 return acc;
12199 };
12200 let Some((worktree, relative_path)) =
12201 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12202 else {
12203 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12204 return acc;
12205 };
12206 let worktree_id = worktree.read(cx).id();
12207 let project_path = ProjectPath {
12208 worktree_id,
12209 path: relative_path,
12210 };
12211 if let Some(local_lsp_store) = self.as_local_mut() {
12212 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12213 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12214 }
12215 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12216 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12217 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12218 acc.entry(server_id)
12219 .or_insert_with(HashMap::default)
12220 .entry(new_registration_id.clone())
12221 .or_insert_with(Vec::new)
12222 .push(DocumentDiagnosticsUpdate {
12223 server_id,
12224 diagnostics: lsp::PublishDiagnosticsParams {
12225 uri,
12226 diagnostics,
12227 version,
12228 },
12229 result_id,
12230 disk_based_sources,
12231 registration_id: new_registration_id,
12232 });
12233 }
12234 acc
12235 },
12236 );
12237
12238 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12239 for (registration_id, diagnostic_updates) in diagnostic_updates {
12240 self.merge_lsp_diagnostics(
12241 DiagnosticSourceKind::Pulled,
12242 diagnostic_updates,
12243 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12244 DiagnosticSourceKind::Pulled => {
12245 old_diagnostic.registration_id != registration_id
12246 || unchanged_buffers
12247 .get(&old_diagnostic.registration_id)
12248 .is_some_and(|unchanged_buffers| {
12249 unchanged_buffers.contains(&document_uri)
12250 })
12251 }
12252 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12253 },
12254 cx,
12255 )
12256 .log_err();
12257 }
12258 }
12259 }
12260
12261 fn register_server_capabilities(
12262 &mut self,
12263 server_id: LanguageServerId,
12264 params: lsp::RegistrationParams,
12265 cx: &mut Context<Self>,
12266 ) -> anyhow::Result<()> {
12267 let server = self
12268 .language_server_for_id(server_id)
12269 .with_context(|| format!("no server {server_id} found"))?;
12270 for reg in params.registrations {
12271 match reg.method.as_str() {
12272 "workspace/didChangeWatchedFiles" => {
12273 if let Some(options) = reg.register_options {
12274 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12275 let caps = serde_json::from_value(options)?;
12276 local_lsp_store
12277 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12278 true
12279 } else {
12280 false
12281 };
12282 if notify {
12283 notify_server_capabilities_updated(&server, cx);
12284 }
12285 }
12286 }
12287 "workspace/didChangeConfiguration" => {
12288 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12289 }
12290 "workspace/didChangeWorkspaceFolders" => {
12291 // In this case register options is an empty object, we can ignore it
12292 let caps = lsp::WorkspaceFoldersServerCapabilities {
12293 supported: Some(true),
12294 change_notifications: Some(OneOf::Right(reg.id)),
12295 };
12296 server.update_capabilities(|capabilities| {
12297 capabilities
12298 .workspace
12299 .get_or_insert_default()
12300 .workspace_folders = Some(caps);
12301 });
12302 notify_server_capabilities_updated(&server, cx);
12303 }
12304 "workspace/symbol" => {
12305 let options = parse_register_capabilities(reg)?;
12306 server.update_capabilities(|capabilities| {
12307 capabilities.workspace_symbol_provider = Some(options);
12308 });
12309 notify_server_capabilities_updated(&server, cx);
12310 }
12311 "workspace/fileOperations" => {
12312 if let Some(options) = reg.register_options {
12313 let caps = serde_json::from_value(options)?;
12314 server.update_capabilities(|capabilities| {
12315 capabilities
12316 .workspace
12317 .get_or_insert_default()
12318 .file_operations = Some(caps);
12319 });
12320 notify_server_capabilities_updated(&server, cx);
12321 }
12322 }
12323 "workspace/executeCommand" => {
12324 if let Some(options) = reg.register_options {
12325 let options = serde_json::from_value(options)?;
12326 server.update_capabilities(|capabilities| {
12327 capabilities.execute_command_provider = Some(options);
12328 });
12329 notify_server_capabilities_updated(&server, cx);
12330 }
12331 }
12332 "textDocument/rangeFormatting" => {
12333 let options = parse_register_capabilities(reg)?;
12334 server.update_capabilities(|capabilities| {
12335 capabilities.document_range_formatting_provider = Some(options);
12336 });
12337 notify_server_capabilities_updated(&server, cx);
12338 }
12339 "textDocument/onTypeFormatting" => {
12340 if let Some(options) = reg
12341 .register_options
12342 .map(serde_json::from_value)
12343 .transpose()?
12344 {
12345 server.update_capabilities(|capabilities| {
12346 capabilities.document_on_type_formatting_provider = Some(options);
12347 });
12348 notify_server_capabilities_updated(&server, cx);
12349 }
12350 }
12351 "textDocument/formatting" => {
12352 let options = parse_register_capabilities(reg)?;
12353 server.update_capabilities(|capabilities| {
12354 capabilities.document_formatting_provider = Some(options);
12355 });
12356 notify_server_capabilities_updated(&server, cx);
12357 }
12358 "textDocument/rename" => {
12359 let options = parse_register_capabilities(reg)?;
12360 server.update_capabilities(|capabilities| {
12361 capabilities.rename_provider = Some(options);
12362 });
12363 notify_server_capabilities_updated(&server, cx);
12364 }
12365 "textDocument/inlayHint" => {
12366 let options = parse_register_capabilities(reg)?;
12367 server.update_capabilities(|capabilities| {
12368 capabilities.inlay_hint_provider = Some(options);
12369 });
12370 notify_server_capabilities_updated(&server, cx);
12371 }
12372 "textDocument/documentSymbol" => {
12373 let options = parse_register_capabilities(reg)?;
12374 server.update_capabilities(|capabilities| {
12375 capabilities.document_symbol_provider = Some(options);
12376 });
12377 notify_server_capabilities_updated(&server, cx);
12378 }
12379 "textDocument/codeAction" => {
12380 let options = parse_register_capabilities(reg)?;
12381 let provider = match options {
12382 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12383 OneOf::Right(caps) => caps,
12384 };
12385 server.update_capabilities(|capabilities| {
12386 capabilities.code_action_provider = Some(provider);
12387 });
12388 notify_server_capabilities_updated(&server, cx);
12389 }
12390 "textDocument/definition" => {
12391 let options = parse_register_capabilities(reg)?;
12392 server.update_capabilities(|capabilities| {
12393 capabilities.definition_provider = Some(options);
12394 });
12395 notify_server_capabilities_updated(&server, cx);
12396 }
12397 "textDocument/completion" => {
12398 if let Some(caps) = reg
12399 .register_options
12400 .map(serde_json::from_value::<CompletionOptions>)
12401 .transpose()?
12402 {
12403 server.update_capabilities(|capabilities| {
12404 capabilities.completion_provider = Some(caps.clone());
12405 });
12406
12407 if let Some(local) = self.as_local() {
12408 let mut buffers_with_language_server = Vec::new();
12409 for handle in self.buffer_store.read(cx).buffers() {
12410 let buffer_id = handle.read(cx).remote_id();
12411 if local
12412 .buffers_opened_in_servers
12413 .get(&buffer_id)
12414 .filter(|s| s.contains(&server_id))
12415 .is_some()
12416 {
12417 buffers_with_language_server.push(handle);
12418 }
12419 }
12420 let triggers = caps
12421 .trigger_characters
12422 .unwrap_or_default()
12423 .into_iter()
12424 .collect::<BTreeSet<_>>();
12425 for handle in buffers_with_language_server {
12426 let triggers = triggers.clone();
12427 let _ = handle.update(cx, move |buffer, cx| {
12428 buffer.set_completion_triggers(server_id, triggers, cx);
12429 });
12430 }
12431 }
12432 notify_server_capabilities_updated(&server, cx);
12433 }
12434 }
12435 "textDocument/hover" => {
12436 let options = parse_register_capabilities(reg)?;
12437 let provider = match options {
12438 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12439 OneOf::Right(caps) => caps,
12440 };
12441 server.update_capabilities(|capabilities| {
12442 capabilities.hover_provider = Some(provider);
12443 });
12444 notify_server_capabilities_updated(&server, cx);
12445 }
12446 "textDocument/signatureHelp" => {
12447 if let Some(caps) = reg
12448 .register_options
12449 .map(serde_json::from_value)
12450 .transpose()?
12451 {
12452 server.update_capabilities(|capabilities| {
12453 capabilities.signature_help_provider = Some(caps);
12454 });
12455 notify_server_capabilities_updated(&server, cx);
12456 }
12457 }
12458 "textDocument/didChange" => {
12459 if let Some(sync_kind) = reg
12460 .register_options
12461 .and_then(|opts| opts.get("syncKind").cloned())
12462 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12463 .transpose()?
12464 {
12465 server.update_capabilities(|capabilities| {
12466 let mut sync_options =
12467 Self::take_text_document_sync_options(capabilities);
12468 sync_options.change = Some(sync_kind);
12469 capabilities.text_document_sync =
12470 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12471 });
12472 notify_server_capabilities_updated(&server, cx);
12473 }
12474 }
12475 "textDocument/didSave" => {
12476 if let Some(include_text) = reg
12477 .register_options
12478 .map(|opts| {
12479 let transpose = opts
12480 .get("includeText")
12481 .cloned()
12482 .map(serde_json::from_value::<Option<bool>>)
12483 .transpose();
12484 match transpose {
12485 Ok(value) => Ok(value.flatten()),
12486 Err(e) => Err(e),
12487 }
12488 })
12489 .transpose()?
12490 {
12491 server.update_capabilities(|capabilities| {
12492 let mut sync_options =
12493 Self::take_text_document_sync_options(capabilities);
12494 sync_options.save =
12495 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12496 include_text,
12497 }));
12498 capabilities.text_document_sync =
12499 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12500 });
12501 notify_server_capabilities_updated(&server, cx);
12502 }
12503 }
12504 "textDocument/codeLens" => {
12505 if let Some(caps) = reg
12506 .register_options
12507 .map(serde_json::from_value)
12508 .transpose()?
12509 {
12510 server.update_capabilities(|capabilities| {
12511 capabilities.code_lens_provider = Some(caps);
12512 });
12513 notify_server_capabilities_updated(&server, cx);
12514 }
12515 }
12516 "textDocument/diagnostic" => {
12517 if let Some(caps) = reg
12518 .register_options
12519 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12520 .transpose()?
12521 {
12522 let local = self
12523 .as_local_mut()
12524 .context("Expected LSP Store to be local")?;
12525 let state = local
12526 .language_servers
12527 .get_mut(&server_id)
12528 .context("Could not obtain Language Servers state")?;
12529 local
12530 .language_server_dynamic_registrations
12531 .entry(server_id)
12532 .or_default()
12533 .diagnostics
12534 .insert(Some(reg.id.clone()), caps.clone());
12535
12536 let supports_workspace_diagnostics =
12537 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12538 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12539 diagnostic_options.workspace_diagnostics
12540 }
12541 DiagnosticServerCapabilities::RegistrationOptions(
12542 diagnostic_registration_options,
12543 ) => {
12544 diagnostic_registration_options
12545 .diagnostic_options
12546 .workspace_diagnostics
12547 }
12548 };
12549
12550 if supports_workspace_diagnostics(&caps) {
12551 if let LanguageServerState::Running {
12552 workspace_diagnostics_refresh_tasks,
12553 ..
12554 } = state
12555 && let Some(task) = lsp_workspace_diagnostics_refresh(
12556 Some(reg.id.clone()),
12557 caps.clone(),
12558 server.clone(),
12559 cx,
12560 )
12561 {
12562 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12563 }
12564 }
12565
12566 server.update_capabilities(|capabilities| {
12567 capabilities.diagnostic_provider = Some(caps);
12568 });
12569
12570 notify_server_capabilities_updated(&server, cx);
12571 }
12572 }
12573 "textDocument/documentColor" => {
12574 let options = parse_register_capabilities(reg)?;
12575 let provider = match options {
12576 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12577 OneOf::Right(caps) => caps,
12578 };
12579 server.update_capabilities(|capabilities| {
12580 capabilities.color_provider = Some(provider);
12581 });
12582 notify_server_capabilities_updated(&server, cx);
12583 }
12584 _ => log::warn!("unhandled capability registration: {reg:?}"),
12585 }
12586 }
12587
12588 Ok(())
12589 }
12590
12591 fn unregister_server_capabilities(
12592 &mut self,
12593 server_id: LanguageServerId,
12594 params: lsp::UnregistrationParams,
12595 cx: &mut Context<Self>,
12596 ) -> anyhow::Result<()> {
12597 let server = self
12598 .language_server_for_id(server_id)
12599 .with_context(|| format!("no server {server_id} found"))?;
12600 for unreg in params.unregisterations.iter() {
12601 match unreg.method.as_str() {
12602 "workspace/didChangeWatchedFiles" => {
12603 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12604 local_lsp_store
12605 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12606 true
12607 } else {
12608 false
12609 };
12610 if notify {
12611 notify_server_capabilities_updated(&server, cx);
12612 }
12613 }
12614 "workspace/didChangeConfiguration" => {
12615 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12616 }
12617 "workspace/didChangeWorkspaceFolders" => {
12618 server.update_capabilities(|capabilities| {
12619 capabilities
12620 .workspace
12621 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12622 workspace_folders: None,
12623 file_operations: None,
12624 })
12625 .workspace_folders = None;
12626 });
12627 notify_server_capabilities_updated(&server, cx);
12628 }
12629 "workspace/symbol" => {
12630 server.update_capabilities(|capabilities| {
12631 capabilities.workspace_symbol_provider = None
12632 });
12633 notify_server_capabilities_updated(&server, cx);
12634 }
12635 "workspace/fileOperations" => {
12636 server.update_capabilities(|capabilities| {
12637 capabilities
12638 .workspace
12639 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12640 workspace_folders: None,
12641 file_operations: None,
12642 })
12643 .file_operations = None;
12644 });
12645 notify_server_capabilities_updated(&server, cx);
12646 }
12647 "workspace/executeCommand" => {
12648 server.update_capabilities(|capabilities| {
12649 capabilities.execute_command_provider = None;
12650 });
12651 notify_server_capabilities_updated(&server, cx);
12652 }
12653 "textDocument/rangeFormatting" => {
12654 server.update_capabilities(|capabilities| {
12655 capabilities.document_range_formatting_provider = None
12656 });
12657 notify_server_capabilities_updated(&server, cx);
12658 }
12659 "textDocument/onTypeFormatting" => {
12660 server.update_capabilities(|capabilities| {
12661 capabilities.document_on_type_formatting_provider = None;
12662 });
12663 notify_server_capabilities_updated(&server, cx);
12664 }
12665 "textDocument/formatting" => {
12666 server.update_capabilities(|capabilities| {
12667 capabilities.document_formatting_provider = None;
12668 });
12669 notify_server_capabilities_updated(&server, cx);
12670 }
12671 "textDocument/rename" => {
12672 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12673 notify_server_capabilities_updated(&server, cx);
12674 }
12675 "textDocument/codeAction" => {
12676 server.update_capabilities(|capabilities| {
12677 capabilities.code_action_provider = None;
12678 });
12679 notify_server_capabilities_updated(&server, cx);
12680 }
12681 "textDocument/definition" => {
12682 server.update_capabilities(|capabilities| {
12683 capabilities.definition_provider = None;
12684 });
12685 notify_server_capabilities_updated(&server, cx);
12686 }
12687 "textDocument/completion" => {
12688 server.update_capabilities(|capabilities| {
12689 capabilities.completion_provider = None;
12690 });
12691 notify_server_capabilities_updated(&server, cx);
12692 }
12693 "textDocument/hover" => {
12694 server.update_capabilities(|capabilities| {
12695 capabilities.hover_provider = None;
12696 });
12697 notify_server_capabilities_updated(&server, cx);
12698 }
12699 "textDocument/signatureHelp" => {
12700 server.update_capabilities(|capabilities| {
12701 capabilities.signature_help_provider = None;
12702 });
12703 notify_server_capabilities_updated(&server, cx);
12704 }
12705 "textDocument/didChange" => {
12706 server.update_capabilities(|capabilities| {
12707 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12708 sync_options.change = None;
12709 capabilities.text_document_sync =
12710 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12711 });
12712 notify_server_capabilities_updated(&server, cx);
12713 }
12714 "textDocument/didSave" => {
12715 server.update_capabilities(|capabilities| {
12716 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12717 sync_options.save = None;
12718 capabilities.text_document_sync =
12719 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12720 });
12721 notify_server_capabilities_updated(&server, cx);
12722 }
12723 "textDocument/codeLens" => {
12724 server.update_capabilities(|capabilities| {
12725 capabilities.code_lens_provider = None;
12726 });
12727 notify_server_capabilities_updated(&server, cx);
12728 }
12729 "textDocument/diagnostic" => {
12730 let local = self
12731 .as_local_mut()
12732 .context("Expected LSP Store to be local")?;
12733
12734 let state = local
12735 .language_servers
12736 .get_mut(&server_id)
12737 .context("Could not obtain Language Servers state")?;
12738 let registrations = local
12739 .language_server_dynamic_registrations
12740 .get_mut(&server_id)
12741 .with_context(|| {
12742 format!("Expected dynamic registration to exist for server {server_id}")
12743 })?;
12744 registrations.diagnostics
12745 .remove(&Some(unreg.id.clone()))
12746 .with_context(|| format!(
12747 "Attempted to unregister non-existent diagnostic registration with ID {}",
12748 unreg.id)
12749 )?;
12750 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12751
12752 if let LanguageServerState::Running {
12753 workspace_diagnostics_refresh_tasks,
12754 ..
12755 } = state
12756 {
12757 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12758 }
12759
12760 if removed_last_diagnostic_provider {
12761 server.update_capabilities(|capabilities| {
12762 debug_assert!(capabilities.diagnostic_provider.is_some());
12763 capabilities.diagnostic_provider = None;
12764 });
12765 }
12766
12767 notify_server_capabilities_updated(&server, cx);
12768 }
12769 "textDocument/documentColor" => {
12770 server.update_capabilities(|capabilities| {
12771 capabilities.color_provider = None;
12772 });
12773 notify_server_capabilities_updated(&server, cx);
12774 }
12775 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12776 }
12777 }
12778
12779 Ok(())
12780 }
12781
12782 async fn deduplicate_range_based_lsp_requests<T>(
12783 lsp_store: &Entity<Self>,
12784 server_id: Option<LanguageServerId>,
12785 lsp_request_id: LspRequestId,
12786 proto_request: &T::ProtoRequest,
12787 range: Range<Anchor>,
12788 cx: &mut AsyncApp,
12789 ) -> Result<()>
12790 where
12791 T: LspCommand,
12792 T::ProtoRequest: proto::LspRequestMessage,
12793 {
12794 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12795 let version = deserialize_version(proto_request.buffer_version());
12796 let buffer = lsp_store.update(cx, |this, cx| {
12797 this.buffer_store.read(cx).get_existing(buffer_id)
12798 })??;
12799 buffer
12800 .update(cx, |buffer, _| buffer.wait_for_version(version))?
12801 .await?;
12802 lsp_store.update(cx, |lsp_store, cx| {
12803 let buffer_snapshot = buffer.read(cx).snapshot();
12804 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12805 let chunks_queried_for = lsp_data
12806 .inlay_hints
12807 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12808 .collect::<Vec<_>>();
12809 match chunks_queried_for.as_slice() {
12810 &[chunk] => {
12811 let key = LspKey {
12812 request_type: TypeId::of::<T>(),
12813 server_queried: server_id,
12814 };
12815 let previous_request = lsp_data
12816 .chunk_lsp_requests
12817 .entry(key)
12818 .or_default()
12819 .insert(chunk, lsp_request_id);
12820 if let Some((previous_request, running_requests)) =
12821 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12822 {
12823 running_requests.remove(&previous_request);
12824 }
12825 }
12826 _ambiguous_chunks => {
12827 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12828 // there, a buffer version-based check will be performed and outdated requests discarded.
12829 }
12830 }
12831 anyhow::Ok(())
12832 })??;
12833
12834 Ok(())
12835 }
12836
12837 async fn query_lsp_locally<T>(
12838 lsp_store: Entity<Self>,
12839 for_server_id: Option<LanguageServerId>,
12840 sender_id: proto::PeerId,
12841 lsp_request_id: LspRequestId,
12842 proto_request: T::ProtoRequest,
12843 position: Option<Anchor>,
12844 cx: &mut AsyncApp,
12845 ) -> Result<()>
12846 where
12847 T: LspCommand + Clone,
12848 T::ProtoRequest: proto::LspRequestMessage,
12849 <T::ProtoRequest as proto::RequestMessage>::Response:
12850 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12851 {
12852 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12853 let version = deserialize_version(proto_request.buffer_version());
12854 let buffer = lsp_store.update(cx, |this, cx| {
12855 this.buffer_store.read(cx).get_existing(buffer_id)
12856 })??;
12857 buffer
12858 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
12859 .await?;
12860 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
12861 let request =
12862 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12863 let key = LspKey {
12864 request_type: TypeId::of::<T>(),
12865 server_queried: for_server_id,
12866 };
12867 lsp_store.update(cx, |lsp_store, cx| {
12868 let request_task = match for_server_id {
12869 Some(server_id) => {
12870 let server_task = lsp_store.request_lsp(
12871 buffer.clone(),
12872 LanguageServerToQuery::Other(server_id),
12873 request.clone(),
12874 cx,
12875 );
12876 cx.background_spawn(async move {
12877 let mut responses = Vec::new();
12878 match server_task.await {
12879 Ok(response) => responses.push((server_id, response)),
12880 // rust-analyzer likes to error with this when its still loading up
12881 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12882 Err(e) => log::error!(
12883 "Error handling response for request {request:?}: {e:#}"
12884 ),
12885 }
12886 responses
12887 })
12888 }
12889 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12890 };
12891 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12892 if T::ProtoRequest::stop_previous_requests() {
12893 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12894 lsp_requests.clear();
12895 }
12896 }
12897 lsp_data.lsp_requests.entry(key).or_default().insert(
12898 lsp_request_id,
12899 cx.spawn(async move |lsp_store, cx| {
12900 let response = request_task.await;
12901 lsp_store
12902 .update(cx, |lsp_store, cx| {
12903 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12904 {
12905 let response = response
12906 .into_iter()
12907 .map(|(server_id, response)| {
12908 (
12909 server_id.to_proto(),
12910 T::response_to_proto(
12911 response,
12912 lsp_store,
12913 sender_id,
12914 &buffer_version,
12915 cx,
12916 )
12917 .into(),
12918 )
12919 })
12920 .collect::<HashMap<_, _>>();
12921 match client.send_lsp_response::<T::ProtoRequest>(
12922 project_id,
12923 lsp_request_id,
12924 response,
12925 ) {
12926 Ok(()) => {}
12927 Err(e) => {
12928 log::error!("Failed to send LSP response: {e:#}",)
12929 }
12930 }
12931 }
12932 })
12933 .ok();
12934 }),
12935 );
12936 })?;
12937 Ok(())
12938 }
12939
12940 fn take_text_document_sync_options(
12941 capabilities: &mut lsp::ServerCapabilities,
12942 ) -> lsp::TextDocumentSyncOptions {
12943 match capabilities.text_document_sync.take() {
12944 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
12945 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
12946 let mut sync_options = lsp::TextDocumentSyncOptions::default();
12947 sync_options.change = Some(sync_kind);
12948 sync_options
12949 }
12950 None => lsp::TextDocumentSyncOptions::default(),
12951 }
12952 }
12953
12954 #[cfg(any(test, feature = "test-support"))]
12955 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
12956 Some(
12957 self.lsp_data
12958 .get_mut(&buffer_id)?
12959 .code_lens
12960 .take()?
12961 .update
12962 .take()?
12963 .1,
12964 )
12965 }
12966
12967 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
12968 self.downstream_client.clone()
12969 }
12970
12971 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
12972 self.worktree_store.clone()
12973 }
12974
12975 /// Gets what's stored in the LSP data for the given buffer.
12976 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
12977 self.lsp_data.get_mut(&buffer_id)
12978 }
12979
12980 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
12981 /// new [`BufferLspData`] will be created to replace the previous state.
12982 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
12983 let (buffer_id, buffer_version) =
12984 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
12985 let lsp_data = self
12986 .lsp_data
12987 .entry(buffer_id)
12988 .or_insert_with(|| BufferLspData::new(buffer, cx));
12989 if buffer_version.changed_since(&lsp_data.buffer_version) {
12990 *lsp_data = BufferLspData::new(buffer, cx);
12991 }
12992 lsp_data
12993 }
12994}
12995
12996// Registration with registerOptions as null, should fallback to true.
12997// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
12998fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
12999 reg: lsp::Registration,
13000) -> Result<OneOf<bool, T>> {
13001 Ok(match reg.register_options {
13002 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13003 None => OneOf::Left(true),
13004 })
13005}
13006
13007fn subscribe_to_binary_statuses(
13008 languages: &Arc<LanguageRegistry>,
13009 cx: &mut Context<'_, LspStore>,
13010) -> Task<()> {
13011 let mut server_statuses = languages.language_server_binary_statuses();
13012 cx.spawn(async move |lsp_store, cx| {
13013 while let Some((server_name, binary_status)) = server_statuses.next().await {
13014 if lsp_store
13015 .update(cx, |_, cx| {
13016 let mut message = None;
13017 let binary_status = match binary_status {
13018 BinaryStatus::None => proto::ServerBinaryStatus::None,
13019 BinaryStatus::CheckingForUpdate => {
13020 proto::ServerBinaryStatus::CheckingForUpdate
13021 }
13022 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13023 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13024 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13025 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13026 BinaryStatus::Failed { error } => {
13027 message = Some(error);
13028 proto::ServerBinaryStatus::Failed
13029 }
13030 };
13031 cx.emit(LspStoreEvent::LanguageServerUpdate {
13032 // Binary updates are about the binary that might not have any language server id at that point.
13033 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13034 language_server_id: LanguageServerId(0),
13035 name: Some(server_name),
13036 message: proto::update_language_server::Variant::StatusUpdate(
13037 proto::StatusUpdate {
13038 message,
13039 status: Some(proto::status_update::Status::Binary(
13040 binary_status as i32,
13041 )),
13042 },
13043 ),
13044 });
13045 })
13046 .is_err()
13047 {
13048 break;
13049 }
13050 }
13051 })
13052}
13053
13054fn lsp_workspace_diagnostics_refresh(
13055 registration_id: Option<String>,
13056 options: DiagnosticServerCapabilities,
13057 server: Arc<LanguageServer>,
13058 cx: &mut Context<'_, LspStore>,
13059) -> Option<WorkspaceRefreshTask> {
13060 let identifier = workspace_diagnostic_identifier(&options)?;
13061 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13062
13063 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13064 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13065 refresh_tx.try_send(()).ok();
13066
13067 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13068 let mut attempts = 0;
13069 let max_attempts = 50;
13070 let mut requests = 0;
13071
13072 loop {
13073 let Some(()) = refresh_rx.recv().await else {
13074 return;
13075 };
13076
13077 'request: loop {
13078 requests += 1;
13079 if attempts > max_attempts {
13080 log::error!(
13081 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13082 );
13083 return;
13084 }
13085 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13086 cx.background_executor()
13087 .timer(Duration::from_millis(backoff_millis))
13088 .await;
13089 attempts += 1;
13090
13091 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13092 lsp_store
13093 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13094 .into_iter()
13095 .filter_map(|(abs_path, result_id)| {
13096 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13097 Some(lsp::PreviousResultId {
13098 uri,
13099 value: result_id.to_string(),
13100 })
13101 })
13102 .collect()
13103 }) else {
13104 return;
13105 };
13106
13107 let token = if let Some(registration_id) = ®istration_id {
13108 format!(
13109 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13110 server.server_id(),
13111 )
13112 } else {
13113 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13114 };
13115
13116 progress_rx.try_recv().ok();
13117 let timer =
13118 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13119 let progress = pin!(progress_rx.recv().fuse());
13120 let response_result = server
13121 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13122 lsp::WorkspaceDiagnosticParams {
13123 previous_result_ids,
13124 identifier: identifier.clone(),
13125 work_done_progress_params: Default::default(),
13126 partial_result_params: lsp::PartialResultParams {
13127 partial_result_token: Some(lsp::ProgressToken::String(token)),
13128 },
13129 },
13130 select(timer, progress).then(|either| match either {
13131 Either::Left((message, ..)) => ready(message).left_future(),
13132 Either::Right(..) => pending::<String>().right_future(),
13133 }),
13134 )
13135 .await;
13136
13137 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13138 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13139 match response_result {
13140 ConnectionResult::Timeout => {
13141 log::error!("Timeout during workspace diagnostics pull");
13142 continue 'request;
13143 }
13144 ConnectionResult::ConnectionReset => {
13145 log::error!("Server closed a workspace diagnostics pull request");
13146 continue 'request;
13147 }
13148 ConnectionResult::Result(Err(e)) => {
13149 log::error!("Error during workspace diagnostics pull: {e:#}");
13150 break 'request;
13151 }
13152 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13153 attempts = 0;
13154 if lsp_store
13155 .update(cx, |lsp_store, cx| {
13156 lsp_store.apply_workspace_diagnostic_report(
13157 server.server_id(),
13158 pulled_diagnostics,
13159 registration_id_shared.clone(),
13160 cx,
13161 )
13162 })
13163 .is_err()
13164 {
13165 return;
13166 }
13167 break 'request;
13168 }
13169 }
13170 }
13171 }
13172 });
13173
13174 Some(WorkspaceRefreshTask {
13175 refresh_tx,
13176 progress_tx,
13177 task: workspace_query_language_server,
13178 })
13179}
13180
13181fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13182 match &options {
13183 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13184 diagnostic_options.identifier.clone()
13185 }
13186 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13187 let diagnostic_options = ®istration_options.diagnostic_options;
13188 diagnostic_options.identifier.clone()
13189 }
13190 }
13191}
13192
13193fn workspace_diagnostic_identifier(
13194 options: &DiagnosticServerCapabilities,
13195) -> Option<Option<String>> {
13196 match &options {
13197 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13198 if !diagnostic_options.workspace_diagnostics {
13199 return None;
13200 }
13201 Some(diagnostic_options.identifier.clone())
13202 }
13203 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13204 let diagnostic_options = ®istration_options.diagnostic_options;
13205 if !diagnostic_options.workspace_diagnostics {
13206 return None;
13207 }
13208 Some(diagnostic_options.identifier.clone())
13209 }
13210 }
13211}
13212
13213fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13214 let CompletionSource::BufferWord {
13215 word_range,
13216 resolved,
13217 } = &mut completion.source
13218 else {
13219 return;
13220 };
13221 if *resolved {
13222 return;
13223 }
13224
13225 if completion.new_text
13226 != snapshot
13227 .text_for_range(word_range.clone())
13228 .collect::<String>()
13229 {
13230 return;
13231 }
13232
13233 let mut offset = 0;
13234 for chunk in snapshot.chunks(word_range.clone(), true) {
13235 let end_offset = offset + chunk.text.len();
13236 if let Some(highlight_id) = chunk.syntax_highlight_id {
13237 completion
13238 .label
13239 .runs
13240 .push((offset..end_offset, highlight_id));
13241 }
13242 offset = end_offset;
13243 }
13244 *resolved = true;
13245}
13246
13247impl EventEmitter<LspStoreEvent> for LspStore {}
13248
13249fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13250 hover
13251 .contents
13252 .retain(|hover_block| !hover_block.text.trim().is_empty());
13253 if hover.contents.is_empty() {
13254 None
13255 } else {
13256 Some(hover)
13257 }
13258}
13259
13260async fn populate_labels_for_completions(
13261 new_completions: Vec<CoreCompletion>,
13262 language: Option<Arc<Language>>,
13263 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13264) -> Vec<Completion> {
13265 let lsp_completions = new_completions
13266 .iter()
13267 .filter_map(|new_completion| {
13268 new_completion
13269 .source
13270 .lsp_completion(true)
13271 .map(|lsp_completion| lsp_completion.into_owned())
13272 })
13273 .collect::<Vec<_>>();
13274
13275 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13276 lsp_adapter
13277 .labels_for_completions(&lsp_completions, language)
13278 .await
13279 .log_err()
13280 .unwrap_or_default()
13281 } else {
13282 Vec::new()
13283 }
13284 .into_iter()
13285 .fuse();
13286
13287 let mut completions = Vec::new();
13288 for completion in new_completions {
13289 match completion.source.lsp_completion(true) {
13290 Some(lsp_completion) => {
13291 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13292
13293 let mut label = labels.next().flatten().unwrap_or_else(|| {
13294 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13295 });
13296 ensure_uniform_list_compatible_label(&mut label);
13297 completions.push(Completion {
13298 label,
13299 documentation,
13300 replace_range: completion.replace_range,
13301 new_text: completion.new_text,
13302 insert_text_mode: lsp_completion.insert_text_mode,
13303 source: completion.source,
13304 icon_path: None,
13305 confirm: None,
13306 match_start: None,
13307 snippet_deduplication_key: None,
13308 });
13309 }
13310 None => {
13311 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13312 ensure_uniform_list_compatible_label(&mut label);
13313 completions.push(Completion {
13314 label,
13315 documentation: None,
13316 replace_range: completion.replace_range,
13317 new_text: completion.new_text,
13318 source: completion.source,
13319 insert_text_mode: None,
13320 icon_path: None,
13321 confirm: None,
13322 match_start: None,
13323 snippet_deduplication_key: None,
13324 });
13325 }
13326 }
13327 }
13328 completions
13329}
13330
13331#[derive(Debug)]
13332pub enum LanguageServerToQuery {
13333 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13334 FirstCapable,
13335 /// Query a specific language server.
13336 Other(LanguageServerId),
13337}
13338
13339#[derive(Default)]
13340struct RenamePathsWatchedForServer {
13341 did_rename: Vec<RenameActionPredicate>,
13342 will_rename: Vec<RenameActionPredicate>,
13343}
13344
13345impl RenamePathsWatchedForServer {
13346 fn with_did_rename_patterns(
13347 mut self,
13348 did_rename: Option<&FileOperationRegistrationOptions>,
13349 ) -> Self {
13350 if let Some(did_rename) = did_rename {
13351 self.did_rename = did_rename
13352 .filters
13353 .iter()
13354 .filter_map(|filter| filter.try_into().log_err())
13355 .collect();
13356 }
13357 self
13358 }
13359 fn with_will_rename_patterns(
13360 mut self,
13361 will_rename: Option<&FileOperationRegistrationOptions>,
13362 ) -> Self {
13363 if let Some(will_rename) = will_rename {
13364 self.will_rename = will_rename
13365 .filters
13366 .iter()
13367 .filter_map(|filter| filter.try_into().log_err())
13368 .collect();
13369 }
13370 self
13371 }
13372
13373 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13374 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13375 }
13376 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13377 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13378 }
13379}
13380
13381impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13382 type Error = globset::Error;
13383 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13384 Ok(Self {
13385 kind: ops.pattern.matches.clone(),
13386 glob: GlobBuilder::new(&ops.pattern.glob)
13387 .case_insensitive(
13388 ops.pattern
13389 .options
13390 .as_ref()
13391 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13392 )
13393 .build()?
13394 .compile_matcher(),
13395 })
13396 }
13397}
13398struct RenameActionPredicate {
13399 glob: GlobMatcher,
13400 kind: Option<FileOperationPatternKind>,
13401}
13402
13403impl RenameActionPredicate {
13404 // Returns true if language server should be notified
13405 fn eval(&self, path: &str, is_dir: bool) -> bool {
13406 self.kind.as_ref().is_none_or(|kind| {
13407 let expected_kind = if is_dir {
13408 FileOperationPatternKind::Folder
13409 } else {
13410 FileOperationPatternKind::File
13411 };
13412 kind == &expected_kind
13413 }) && self.glob.is_match(path)
13414 }
13415}
13416
13417#[derive(Default)]
13418struct LanguageServerWatchedPaths {
13419 worktree_paths: HashMap<WorktreeId, GlobSet>,
13420 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13421}
13422
13423#[derive(Default)]
13424struct LanguageServerWatchedPathsBuilder {
13425 worktree_paths: HashMap<WorktreeId, GlobSet>,
13426 abs_paths: HashMap<Arc<Path>, GlobSet>,
13427}
13428
13429impl LanguageServerWatchedPathsBuilder {
13430 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13431 self.worktree_paths.insert(worktree_id, glob_set);
13432 }
13433 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13434 self.abs_paths.insert(path, glob_set);
13435 }
13436 fn build(
13437 self,
13438 fs: Arc<dyn Fs>,
13439 language_server_id: LanguageServerId,
13440 cx: &mut Context<LspStore>,
13441 ) -> LanguageServerWatchedPaths {
13442 let lsp_store = cx.weak_entity();
13443
13444 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13445 let abs_paths = self
13446 .abs_paths
13447 .into_iter()
13448 .map(|(abs_path, globset)| {
13449 let task = cx.spawn({
13450 let abs_path = abs_path.clone();
13451 let fs = fs.clone();
13452
13453 let lsp_store = lsp_store.clone();
13454 async move |_, cx| {
13455 maybe!(async move {
13456 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13457 while let Some(update) = push_updates.0.next().await {
13458 let action = lsp_store
13459 .update(cx, |this, _| {
13460 let Some(local) = this.as_local() else {
13461 return ControlFlow::Break(());
13462 };
13463 let Some(watcher) = local
13464 .language_server_watched_paths
13465 .get(&language_server_id)
13466 else {
13467 return ControlFlow::Break(());
13468 };
13469 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13470 "Watched abs path is not registered with a watcher",
13471 );
13472 let matching_entries = update
13473 .into_iter()
13474 .filter(|event| globs.is_match(&event.path))
13475 .collect::<Vec<_>>();
13476 this.lsp_notify_abs_paths_changed(
13477 language_server_id,
13478 matching_entries,
13479 );
13480 ControlFlow::Continue(())
13481 })
13482 .ok()?;
13483
13484 if action.is_break() {
13485 break;
13486 }
13487 }
13488 Some(())
13489 })
13490 .await;
13491 }
13492 });
13493 (abs_path, (globset, task))
13494 })
13495 .collect();
13496 LanguageServerWatchedPaths {
13497 worktree_paths: self.worktree_paths,
13498 abs_paths,
13499 }
13500 }
13501}
13502
13503struct LspBufferSnapshot {
13504 version: i32,
13505 snapshot: TextBufferSnapshot,
13506}
13507
13508/// A prompt requested by LSP server.
13509#[derive(Clone, Debug)]
13510pub struct LanguageServerPromptRequest {
13511 pub level: PromptLevel,
13512 pub message: String,
13513 pub actions: Vec<MessageActionItem>,
13514 pub lsp_name: String,
13515 pub(crate) response_channel: Sender<MessageActionItem>,
13516}
13517
13518impl LanguageServerPromptRequest {
13519 pub async fn respond(self, index: usize) -> Option<()> {
13520 if let Some(response) = self.actions.into_iter().nth(index) {
13521 self.response_channel.send(response).await.ok()
13522 } else {
13523 None
13524 }
13525 }
13526}
13527impl PartialEq for LanguageServerPromptRequest {
13528 fn eq(&self, other: &Self) -> bool {
13529 self.message == other.message && self.actions == other.actions
13530 }
13531}
13532
13533#[derive(Clone, Debug, PartialEq)]
13534pub enum LanguageServerLogType {
13535 Log(MessageType),
13536 Trace { verbose_info: Option<String> },
13537 Rpc { received: bool },
13538}
13539
13540impl LanguageServerLogType {
13541 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13542 match self {
13543 Self::Log(log_type) => {
13544 use proto::log_message::LogLevel;
13545 let level = match *log_type {
13546 MessageType::ERROR => LogLevel::Error,
13547 MessageType::WARNING => LogLevel::Warning,
13548 MessageType::INFO => LogLevel::Info,
13549 MessageType::LOG => LogLevel::Log,
13550 other => {
13551 log::warn!("Unknown lsp log message type: {other:?}");
13552 LogLevel::Log
13553 }
13554 };
13555 proto::language_server_log::LogType::Log(proto::LogMessage {
13556 level: level as i32,
13557 })
13558 }
13559 Self::Trace { verbose_info } => {
13560 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13561 verbose_info: verbose_info.to_owned(),
13562 })
13563 }
13564 Self::Rpc { received } => {
13565 let kind = if *received {
13566 proto::rpc_message::Kind::Received
13567 } else {
13568 proto::rpc_message::Kind::Sent
13569 };
13570 let kind = kind as i32;
13571 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13572 }
13573 }
13574 }
13575
13576 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13577 use proto::log_message::LogLevel;
13578 use proto::rpc_message;
13579 match log_type {
13580 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13581 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13582 LogLevel::Error => MessageType::ERROR,
13583 LogLevel::Warning => MessageType::WARNING,
13584 LogLevel::Info => MessageType::INFO,
13585 LogLevel::Log => MessageType::LOG,
13586 },
13587 ),
13588 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13589 verbose_info: trace_message.verbose_info,
13590 },
13591 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13592 received: match rpc_message::Kind::from_i32(message.kind)
13593 .unwrap_or(rpc_message::Kind::Received)
13594 {
13595 rpc_message::Kind::Received => true,
13596 rpc_message::Kind::Sent => false,
13597 },
13598 },
13599 }
13600 }
13601}
13602
13603pub struct WorkspaceRefreshTask {
13604 refresh_tx: mpsc::Sender<()>,
13605 progress_tx: mpsc::Sender<()>,
13606 #[allow(dead_code)]
13607 task: Task<()>,
13608}
13609
13610pub enum LanguageServerState {
13611 Starting {
13612 startup: Task<Option<Arc<LanguageServer>>>,
13613 /// List of language servers that will be added to the workspace once it's initialization completes.
13614 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13615 },
13616
13617 Running {
13618 adapter: Arc<CachedLspAdapter>,
13619 server: Arc<LanguageServer>,
13620 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13621 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13622 },
13623}
13624
13625impl LanguageServerState {
13626 fn add_workspace_folder(&self, uri: Uri) {
13627 match self {
13628 LanguageServerState::Starting {
13629 pending_workspace_folders,
13630 ..
13631 } => {
13632 pending_workspace_folders.lock().insert(uri);
13633 }
13634 LanguageServerState::Running { server, .. } => {
13635 server.add_workspace_folder(uri);
13636 }
13637 }
13638 }
13639 fn _remove_workspace_folder(&self, uri: Uri) {
13640 match self {
13641 LanguageServerState::Starting {
13642 pending_workspace_folders,
13643 ..
13644 } => {
13645 pending_workspace_folders.lock().remove(&uri);
13646 }
13647 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13648 }
13649 }
13650}
13651
13652impl std::fmt::Debug for LanguageServerState {
13653 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13654 match self {
13655 LanguageServerState::Starting { .. } => {
13656 f.debug_struct("LanguageServerState::Starting").finish()
13657 }
13658 LanguageServerState::Running { .. } => {
13659 f.debug_struct("LanguageServerState::Running").finish()
13660 }
13661 }
13662 }
13663}
13664
13665#[derive(Clone, Debug, Serialize)]
13666pub struct LanguageServerProgress {
13667 pub is_disk_based_diagnostics_progress: bool,
13668 pub is_cancellable: bool,
13669 pub title: Option<String>,
13670 pub message: Option<String>,
13671 pub percentage: Option<usize>,
13672 #[serde(skip_serializing)]
13673 pub last_update_at: Instant,
13674}
13675
13676#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13677pub struct DiagnosticSummary {
13678 pub error_count: usize,
13679 pub warning_count: usize,
13680}
13681
13682impl DiagnosticSummary {
13683 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13684 let mut this = Self {
13685 error_count: 0,
13686 warning_count: 0,
13687 };
13688
13689 for entry in diagnostics {
13690 if entry.diagnostic.is_primary {
13691 match entry.diagnostic.severity {
13692 DiagnosticSeverity::ERROR => this.error_count += 1,
13693 DiagnosticSeverity::WARNING => this.warning_count += 1,
13694 _ => {}
13695 }
13696 }
13697 }
13698
13699 this
13700 }
13701
13702 pub fn is_empty(&self) -> bool {
13703 self.error_count == 0 && self.warning_count == 0
13704 }
13705
13706 pub fn to_proto(
13707 self,
13708 language_server_id: LanguageServerId,
13709 path: &RelPath,
13710 ) -> proto::DiagnosticSummary {
13711 proto::DiagnosticSummary {
13712 path: path.to_proto(),
13713 language_server_id: language_server_id.0 as u64,
13714 error_count: self.error_count as u32,
13715 warning_count: self.warning_count as u32,
13716 }
13717 }
13718}
13719
13720#[derive(Clone, Debug)]
13721pub enum CompletionDocumentation {
13722 /// There is no documentation for this completion.
13723 Undocumented,
13724 /// A single line of documentation.
13725 SingleLine(SharedString),
13726 /// Multiple lines of plain text documentation.
13727 MultiLinePlainText(SharedString),
13728 /// Markdown documentation.
13729 MultiLineMarkdown(SharedString),
13730 /// Both single line and multiple lines of plain text documentation.
13731 SingleLineAndMultiLinePlainText {
13732 single_line: SharedString,
13733 plain_text: Option<SharedString>,
13734 },
13735}
13736
13737impl CompletionDocumentation {
13738 #[cfg(any(test, feature = "test-support"))]
13739 pub fn text(&self) -> SharedString {
13740 match self {
13741 CompletionDocumentation::Undocumented => "".into(),
13742 CompletionDocumentation::SingleLine(s) => s.clone(),
13743 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13744 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13745 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13746 single_line.clone()
13747 }
13748 }
13749 }
13750}
13751
13752impl From<lsp::Documentation> for CompletionDocumentation {
13753 fn from(docs: lsp::Documentation) -> Self {
13754 match docs {
13755 lsp::Documentation::String(text) => {
13756 if text.lines().count() <= 1 {
13757 CompletionDocumentation::SingleLine(text.into())
13758 } else {
13759 CompletionDocumentation::MultiLinePlainText(text.into())
13760 }
13761 }
13762
13763 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13764 lsp::MarkupKind::PlainText => {
13765 if value.lines().count() <= 1 {
13766 CompletionDocumentation::SingleLine(value.into())
13767 } else {
13768 CompletionDocumentation::MultiLinePlainText(value.into())
13769 }
13770 }
13771
13772 lsp::MarkupKind::Markdown => {
13773 CompletionDocumentation::MultiLineMarkdown(value.into())
13774 }
13775 },
13776 }
13777 }
13778}
13779
13780pub enum ResolvedHint {
13781 Resolved(InlayHint),
13782 Resolving(Shared<Task<()>>),
13783}
13784
13785fn glob_literal_prefix(glob: &Path) -> PathBuf {
13786 glob.components()
13787 .take_while(|component| match component {
13788 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13789 _ => true,
13790 })
13791 .collect()
13792}
13793
13794pub struct SshLspAdapter {
13795 name: LanguageServerName,
13796 binary: LanguageServerBinary,
13797 initialization_options: Option<String>,
13798 code_action_kinds: Option<Vec<CodeActionKind>>,
13799}
13800
13801impl SshLspAdapter {
13802 pub fn new(
13803 name: LanguageServerName,
13804 binary: LanguageServerBinary,
13805 initialization_options: Option<String>,
13806 code_action_kinds: Option<String>,
13807 ) -> Self {
13808 Self {
13809 name,
13810 binary,
13811 initialization_options,
13812 code_action_kinds: code_action_kinds
13813 .as_ref()
13814 .and_then(|c| serde_json::from_str(c).ok()),
13815 }
13816 }
13817}
13818
13819impl LspInstaller for SshLspAdapter {
13820 type BinaryVersion = ();
13821 async fn check_if_user_installed(
13822 &self,
13823 _: &dyn LspAdapterDelegate,
13824 _: Option<Toolchain>,
13825 _: &AsyncApp,
13826 ) -> Option<LanguageServerBinary> {
13827 Some(self.binary.clone())
13828 }
13829
13830 async fn cached_server_binary(
13831 &self,
13832 _: PathBuf,
13833 _: &dyn LspAdapterDelegate,
13834 ) -> Option<LanguageServerBinary> {
13835 None
13836 }
13837
13838 async fn fetch_latest_server_version(
13839 &self,
13840 _: &dyn LspAdapterDelegate,
13841 _: bool,
13842 _: &mut AsyncApp,
13843 ) -> Result<()> {
13844 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13845 }
13846
13847 async fn fetch_server_binary(
13848 &self,
13849 _: (),
13850 _: PathBuf,
13851 _: &dyn LspAdapterDelegate,
13852 ) -> Result<LanguageServerBinary> {
13853 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13854 }
13855}
13856
13857#[async_trait(?Send)]
13858impl LspAdapter for SshLspAdapter {
13859 fn name(&self) -> LanguageServerName {
13860 self.name.clone()
13861 }
13862
13863 async fn initialization_options(
13864 self: Arc<Self>,
13865 _: &Arc<dyn LspAdapterDelegate>,
13866 ) -> Result<Option<serde_json::Value>> {
13867 let Some(options) = &self.initialization_options else {
13868 return Ok(None);
13869 };
13870 let result = serde_json::from_str(options)?;
13871 Ok(result)
13872 }
13873
13874 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13875 self.code_action_kinds.clone()
13876 }
13877}
13878
13879pub fn language_server_settings<'a>(
13880 delegate: &'a dyn LspAdapterDelegate,
13881 language: &LanguageServerName,
13882 cx: &'a App,
13883) -> Option<&'a LspSettings> {
13884 language_server_settings_for(
13885 SettingsLocation {
13886 worktree_id: delegate.worktree_id(),
13887 path: RelPath::empty(),
13888 },
13889 language,
13890 cx,
13891 )
13892}
13893
13894pub fn language_server_settings_for<'a>(
13895 location: SettingsLocation<'a>,
13896 language: &LanguageServerName,
13897 cx: &'a App,
13898) -> Option<&'a LspSettings> {
13899 ProjectSettings::get(Some(location), cx).lsp.get(language)
13900}
13901
13902pub struct LocalLspAdapterDelegate {
13903 lsp_store: WeakEntity<LspStore>,
13904 worktree: worktree::Snapshot,
13905 fs: Arc<dyn Fs>,
13906 http_client: Arc<dyn HttpClient>,
13907 language_registry: Arc<LanguageRegistry>,
13908 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13909}
13910
13911impl LocalLspAdapterDelegate {
13912 pub fn new(
13913 language_registry: Arc<LanguageRegistry>,
13914 environment: &Entity<ProjectEnvironment>,
13915 lsp_store: WeakEntity<LspStore>,
13916 worktree: &Entity<Worktree>,
13917 http_client: Arc<dyn HttpClient>,
13918 fs: Arc<dyn Fs>,
13919 cx: &mut App,
13920 ) -> Arc<Self> {
13921 let load_shell_env_task =
13922 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
13923
13924 Arc::new(Self {
13925 lsp_store,
13926 worktree: worktree.read(cx).snapshot(),
13927 fs,
13928 http_client,
13929 language_registry,
13930 load_shell_env_task,
13931 })
13932 }
13933
13934 fn from_local_lsp(
13935 local: &LocalLspStore,
13936 worktree: &Entity<Worktree>,
13937 cx: &mut App,
13938 ) -> Arc<Self> {
13939 Self::new(
13940 local.languages.clone(),
13941 &local.environment,
13942 local.weak.clone(),
13943 worktree,
13944 local.http_client.clone(),
13945 local.fs.clone(),
13946 cx,
13947 )
13948 }
13949}
13950
13951#[async_trait]
13952impl LspAdapterDelegate for LocalLspAdapterDelegate {
13953 fn show_notification(&self, message: &str, cx: &mut App) {
13954 self.lsp_store
13955 .update(cx, |_, cx| {
13956 cx.emit(LspStoreEvent::Notification(message.to_owned()))
13957 })
13958 .ok();
13959 }
13960
13961 fn http_client(&self) -> Arc<dyn HttpClient> {
13962 self.http_client.clone()
13963 }
13964
13965 fn worktree_id(&self) -> WorktreeId {
13966 self.worktree.id()
13967 }
13968
13969 fn worktree_root_path(&self) -> &Path {
13970 self.worktree.abs_path().as_ref()
13971 }
13972
13973 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
13974 self.worktree.resolve_executable_path(path)
13975 }
13976
13977 async fn shell_env(&self) -> HashMap<String, String> {
13978 let task = self.load_shell_env_task.clone();
13979 task.await.unwrap_or_default()
13980 }
13981
13982 async fn npm_package_installed_version(
13983 &self,
13984 package_name: &str,
13985 ) -> Result<Option<(PathBuf, Version)>> {
13986 let local_package_directory = self.worktree_root_path();
13987 let node_modules_directory = local_package_directory.join("node_modules");
13988
13989 if let Some(version) =
13990 read_package_installed_version(node_modules_directory.clone(), package_name).await?
13991 {
13992 return Ok(Some((node_modules_directory, version)));
13993 }
13994 let Some(npm) = self.which("npm".as_ref()).await else {
13995 log::warn!(
13996 "Failed to find npm executable for {:?}",
13997 local_package_directory
13998 );
13999 return Ok(None);
14000 };
14001
14002 let env = self.shell_env().await;
14003 let output = util::command::new_smol_command(&npm)
14004 .args(["root", "-g"])
14005 .envs(env)
14006 .current_dir(local_package_directory)
14007 .output()
14008 .await?;
14009 let global_node_modules =
14010 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14011
14012 if let Some(version) =
14013 read_package_installed_version(global_node_modules.clone(), package_name).await?
14014 {
14015 return Ok(Some((global_node_modules, version)));
14016 }
14017 return Ok(None);
14018 }
14019
14020 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14021 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14022 if self.fs.is_file(&worktree_abs_path).await {
14023 worktree_abs_path.pop();
14024 }
14025
14026 let env = self.shell_env().await;
14027
14028 let shell_path = env.get("PATH").cloned();
14029
14030 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14031 }
14032
14033 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14034 let mut working_dir = self.worktree_root_path().to_path_buf();
14035 if self.fs.is_file(&working_dir).await {
14036 working_dir.pop();
14037 }
14038 let output = util::command::new_smol_command(&command.path)
14039 .args(command.arguments)
14040 .envs(command.env.clone().unwrap_or_default())
14041 .current_dir(working_dir)
14042 .output()
14043 .await?;
14044
14045 anyhow::ensure!(
14046 output.status.success(),
14047 "{}, stdout: {:?}, stderr: {:?}",
14048 output.status,
14049 String::from_utf8_lossy(&output.stdout),
14050 String::from_utf8_lossy(&output.stderr)
14051 );
14052 Ok(())
14053 }
14054
14055 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14056 self.language_registry
14057 .update_lsp_binary_status(server_name, status);
14058 }
14059
14060 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14061 self.language_registry
14062 .all_lsp_adapters()
14063 .into_iter()
14064 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14065 .collect()
14066 }
14067
14068 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14069 let dir = self.language_registry.language_server_download_dir(name)?;
14070
14071 if !dir.exists() {
14072 smol::fs::create_dir_all(&dir)
14073 .await
14074 .context("failed to create container directory")
14075 .log_err()?;
14076 }
14077
14078 Some(dir)
14079 }
14080
14081 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14082 let entry = self
14083 .worktree
14084 .entry_for_path(path)
14085 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14086 let abs_path = self.worktree.absolutize(&entry.path);
14087 self.fs.load(&abs_path).await
14088 }
14089}
14090
14091async fn populate_labels_for_symbols(
14092 symbols: Vec<CoreSymbol>,
14093 language_registry: &Arc<LanguageRegistry>,
14094 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14095 output: &mut Vec<Symbol>,
14096) {
14097 #[allow(clippy::mutable_key_type)]
14098 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14099
14100 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14101 for symbol in symbols {
14102 let Some(file_name) = symbol.path.file_name() else {
14103 continue;
14104 };
14105 let language = language_registry
14106 .load_language_for_file_path(Path::new(file_name))
14107 .await
14108 .ok()
14109 .or_else(|| {
14110 unknown_paths.insert(file_name.into());
14111 None
14112 });
14113 symbols_by_language
14114 .entry(language)
14115 .or_default()
14116 .push(symbol);
14117 }
14118
14119 for unknown_path in unknown_paths {
14120 log::info!("no language found for symbol in file {unknown_path:?}");
14121 }
14122
14123 let mut label_params = Vec::new();
14124 for (language, mut symbols) in symbols_by_language {
14125 label_params.clear();
14126 label_params.extend(
14127 symbols
14128 .iter_mut()
14129 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14130 );
14131
14132 let mut labels = Vec::new();
14133 if let Some(language) = language {
14134 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14135 language_registry
14136 .lsp_adapters(&language.name())
14137 .first()
14138 .cloned()
14139 });
14140 if let Some(lsp_adapter) = lsp_adapter {
14141 labels = lsp_adapter
14142 .labels_for_symbols(&label_params, &language)
14143 .await
14144 .log_err()
14145 .unwrap_or_default();
14146 }
14147 }
14148
14149 for ((symbol, (name, _)), label) in symbols
14150 .into_iter()
14151 .zip(label_params.drain(..))
14152 .zip(labels.into_iter().chain(iter::repeat(None)))
14153 {
14154 output.push(Symbol {
14155 language_server_name: symbol.language_server_name,
14156 source_worktree_id: symbol.source_worktree_id,
14157 source_language_server_id: symbol.source_language_server_id,
14158 path: symbol.path,
14159 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14160 name,
14161 kind: symbol.kind,
14162 range: symbol.range,
14163 });
14164 }
14165 }
14166}
14167
14168fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14169 match server.capabilities().text_document_sync.as_ref()? {
14170 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14171 // Server wants didSave but didn't specify includeText.
14172 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14173 // Server doesn't want didSave at all.
14174 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14175 // Server provided SaveOptions.
14176 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14177 Some(save_options.include_text.unwrap_or(false))
14178 }
14179 },
14180 // We do not have any save info. Kind affects didChange only.
14181 lsp::TextDocumentSyncCapability::Kind(_) => None,
14182 }
14183}
14184
14185/// Completion items are displayed in a `UniformList`.
14186/// Usually, those items are single-line strings, but in LSP responses,
14187/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14188/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14189/// 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,
14190/// breaking the completions menu presentation.
14191///
14192/// 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.
14193fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14194 let mut new_text = String::with_capacity(label.text.len());
14195 let mut offset_map = vec![0; label.text.len() + 1];
14196 let mut last_char_was_space = false;
14197 let mut new_idx = 0;
14198 let chars = label.text.char_indices().fuse();
14199 let mut newlines_removed = false;
14200
14201 for (idx, c) in chars {
14202 offset_map[idx] = new_idx;
14203
14204 match c {
14205 '\n' if last_char_was_space => {
14206 newlines_removed = true;
14207 }
14208 '\t' | ' ' if last_char_was_space => {}
14209 '\n' if !last_char_was_space => {
14210 new_text.push(' ');
14211 new_idx += 1;
14212 last_char_was_space = true;
14213 newlines_removed = true;
14214 }
14215 ' ' | '\t' => {
14216 new_text.push(' ');
14217 new_idx += 1;
14218 last_char_was_space = true;
14219 }
14220 _ => {
14221 new_text.push(c);
14222 new_idx += c.len_utf8();
14223 last_char_was_space = false;
14224 }
14225 }
14226 }
14227 offset_map[label.text.len()] = new_idx;
14228
14229 // Only modify the label if newlines were removed.
14230 if !newlines_removed {
14231 return;
14232 }
14233
14234 let last_index = new_idx;
14235 let mut run_ranges_errors = Vec::new();
14236 label.runs.retain_mut(|(range, _)| {
14237 match offset_map.get(range.start) {
14238 Some(&start) => range.start = start,
14239 None => {
14240 run_ranges_errors.push(range.clone());
14241 return false;
14242 }
14243 }
14244
14245 match offset_map.get(range.end) {
14246 Some(&end) => range.end = end,
14247 None => {
14248 run_ranges_errors.push(range.clone());
14249 range.end = last_index;
14250 }
14251 }
14252 true
14253 });
14254 if !run_ranges_errors.is_empty() {
14255 log::error!(
14256 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14257 label.text
14258 );
14259 }
14260
14261 let mut wrong_filter_range = None;
14262 if label.filter_range == (0..label.text.len()) {
14263 label.filter_range = 0..new_text.len();
14264 } else {
14265 let mut original_filter_range = Some(label.filter_range.clone());
14266 match offset_map.get(label.filter_range.start) {
14267 Some(&start) => label.filter_range.start = start,
14268 None => {
14269 wrong_filter_range = original_filter_range.take();
14270 label.filter_range.start = last_index;
14271 }
14272 }
14273
14274 match offset_map.get(label.filter_range.end) {
14275 Some(&end) => label.filter_range.end = end,
14276 None => {
14277 wrong_filter_range = original_filter_range.take();
14278 label.filter_range.end = last_index;
14279 }
14280 }
14281 }
14282 if let Some(wrong_filter_range) = wrong_filter_range {
14283 log::error!(
14284 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14285 label.text
14286 );
14287 }
14288
14289 label.text = new_text;
14290}
14291
14292#[cfg(test)]
14293mod tests {
14294 use language::HighlightId;
14295
14296 use super::*;
14297
14298 #[test]
14299 fn test_glob_literal_prefix() {
14300 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14301 assert_eq!(
14302 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14303 Path::new("node_modules")
14304 );
14305 assert_eq!(
14306 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14307 Path::new("foo")
14308 );
14309 assert_eq!(
14310 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14311 Path::new("foo/bar/baz.js")
14312 );
14313
14314 #[cfg(target_os = "windows")]
14315 {
14316 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14317 assert_eq!(
14318 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14319 Path::new("node_modules")
14320 );
14321 assert_eq!(
14322 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14323 Path::new("foo")
14324 );
14325 assert_eq!(
14326 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14327 Path::new("foo/bar/baz.js")
14328 );
14329 }
14330 }
14331
14332 #[test]
14333 fn test_multi_len_chars_normalization() {
14334 let mut label = CodeLabel::new(
14335 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14336 0..6,
14337 vec![(0..6, HighlightId(1))],
14338 );
14339 ensure_uniform_list_compatible_label(&mut label);
14340 assert_eq!(
14341 label,
14342 CodeLabel::new(
14343 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14344 0..6,
14345 vec![(0..6, HighlightId(1))],
14346 )
14347 );
14348 }
14349}