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