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