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, Capability, CodeLabel,
65 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
66 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
67 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
68 Toolchain, 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 snippet::Snippet;
102use std::{
103 any::TypeId,
104 borrow::Cow,
105 cell::RefCell,
106 cmp::{Ordering, Reverse},
107 collections::hash_map,
108 convert::TryInto,
109 ffi::OsStr,
110 future::ready,
111 iter, mem,
112 ops::{ControlFlow, Range},
113 path::{self, Path, PathBuf},
114 pin::pin,
115 rc::Rc,
116 sync::{
117 Arc,
118 atomic::{self, AtomicUsize},
119 },
120 time::{Duration, Instant},
121 vec,
122};
123use sum_tree::Dimensions;
124use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
125
126use util::{
127 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
128 paths::{PathStyle, SanitizedPath},
129 post_inc,
130 redact::redact_command,
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 pub 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, watch::Receiver<bool>)>,
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 wait_until_worktree_trust =
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(&self.worktree_store, 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 (mut tx, rx) = watch::channel::<bool>();
400 let lsp_store = self.weak.clone();
401 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
402 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
403 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
404 tx.blocking_send(true).ok();
405 lsp_store
406 .update(cx, |lsp_store, _| {
407 if let Some(local_lsp_store) =
408 lsp_store.as_local_mut()
409 {
410 local_lsp_store
411 .restricted_worktrees_tasks
412 .remove(&worktree_id);
413 }
414 })
415 .ok();
416 }
417 }
418 });
419 v.insert((subscription, rx.clone()));
420 Some(rx)
421 }
422 }
423 }
424 });
425 let update_binary_status = wait_until_worktree_trust.is_none();
426
427 let binary = self.get_language_server_binary(
428 worktree_abs_path.clone(),
429 adapter.clone(),
430 settings,
431 toolchain.clone(),
432 delegate.clone(),
433 true,
434 wait_until_worktree_trust,
435 cx,
436 );
437 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
438
439 let pending_server = cx.spawn({
440 let adapter = adapter.clone();
441 let server_name = adapter.name.clone();
442 let stderr_capture = stderr_capture.clone();
443 #[cfg(any(test, feature = "test-support"))]
444 let lsp_store = self.weak.clone();
445 let pending_workspace_folders = pending_workspace_folders.clone();
446 async move |cx| {
447 let binary = binary.await?;
448 #[cfg(any(test, feature = "test-support"))]
449 if let Some(server) = lsp_store
450 .update(&mut cx.clone(), |this, cx| {
451 this.languages.create_fake_language_server(
452 server_id,
453 &server_name,
454 binary.clone(),
455 &mut cx.to_async(),
456 )
457 })
458 .ok()
459 .flatten()
460 {
461 return Ok(server);
462 }
463
464 let code_action_kinds = adapter.code_action_kinds();
465 lsp::LanguageServer::new(
466 stderr_capture,
467 server_id,
468 server_name,
469 binary,
470 &worktree_abs_path,
471 code_action_kinds,
472 Some(pending_workspace_folders),
473 cx,
474 )
475 }
476 });
477
478 let startup = {
479 let server_name = adapter.name.0.clone();
480 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
481 let key = key.clone();
482 let adapter = adapter.clone();
483 let lsp_store = self.weak.clone();
484 let pending_workspace_folders = pending_workspace_folders.clone();
485
486 let pull_diagnostics = ProjectSettings::get_global(cx)
487 .diagnostics
488 .lsp_pull_diagnostics
489 .enabled;
490 cx.spawn(async move |cx| {
491 let result = async {
492 let language_server = pending_server.await?;
493
494 let workspace_config = Self::workspace_configuration_for_adapter(
495 adapter.adapter.clone(),
496 &delegate,
497 toolchain,
498 None,
499 cx,
500 )
501 .await?;
502
503 let mut initialization_options = Self::initialization_options_for_adapter(
504 adapter.adapter.clone(),
505 &delegate,
506 )
507 .await?;
508
509 match (&mut initialization_options, override_options) {
510 (Some(initialization_options), Some(override_options)) => {
511 merge_json_value_into(override_options, initialization_options);
512 }
513 (None, override_options) => initialization_options = override_options,
514 _ => {}
515 }
516
517 let initialization_params = cx.update(|cx| {
518 let mut params =
519 language_server.default_initialize_params(pull_diagnostics, cx);
520 params.initialization_options = initialization_options;
521 adapter.adapter.prepare_initialize_params(params, cx)
522 })??;
523
524 Self::setup_lsp_messages(
525 lsp_store.clone(),
526 &language_server,
527 delegate.clone(),
528 adapter.clone(),
529 );
530
531 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
532 settings: workspace_config,
533 };
534 let language_server = cx
535 .update(|cx| {
536 language_server.initialize(
537 initialization_params,
538 Arc::new(did_change_configuration_params.clone()),
539 cx,
540 )
541 })?
542 .await
543 .inspect_err(|_| {
544 if let Some(lsp_store) = lsp_store.upgrade() {
545 lsp_store
546 .update(cx, |lsp_store, cx| {
547 lsp_store.cleanup_lsp_data(server_id);
548 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
549 })
550 .ok();
551 }
552 })?;
553
554 language_server.notify::<lsp::notification::DidChangeConfiguration>(
555 did_change_configuration_params,
556 )?;
557
558 anyhow::Ok(language_server)
559 }
560 .await;
561
562 match result {
563 Ok(server) => {
564 lsp_store
565 .update(cx, |lsp_store, cx| {
566 lsp_store.insert_newly_running_language_server(
567 adapter,
568 server.clone(),
569 server_id,
570 key,
571 pending_workspace_folders,
572 cx,
573 );
574 })
575 .ok();
576 stderr_capture.lock().take();
577 Some(server)
578 }
579
580 Err(err) => {
581 let log = stderr_capture.lock().take().unwrap_or_default();
582 delegate.update_status(
583 adapter.name(),
584 BinaryStatus::Failed {
585 error: if log.is_empty() {
586 format!("{err:#}")
587 } else {
588 format!("{err:#}\n-- stderr --\n{log}")
589 },
590 },
591 );
592 log::error!(
593 "Failed to start language server {server_name:?}: {}",
594 redact_command(&format!("{err:?}"))
595 );
596 if !log.is_empty() {
597 log::error!("server stderr: {}", redact_command(&log));
598 }
599 None
600 }
601 }
602 })
603 };
604 let state = LanguageServerState::Starting {
605 startup,
606 pending_workspace_folders,
607 };
608
609 if update_binary_status {
610 self.languages
611 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
612 }
613
614 self.language_servers.insert(server_id, state);
615 self.language_server_ids
616 .entry(key)
617 .or_insert(UnifiedLanguageServer {
618 id: server_id,
619 project_roots: Default::default(),
620 });
621 server_id
622 }
623
624 fn get_language_server_binary(
625 &self,
626 worktree_abs_path: Arc<Path>,
627 adapter: Arc<CachedLspAdapter>,
628 settings: Arc<LspSettings>,
629 toolchain: Option<Toolchain>,
630 delegate: Arc<dyn LspAdapterDelegate>,
631 allow_binary_download: bool,
632 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
633 cx: &mut App,
634 ) -> Task<Result<LanguageServerBinary>> {
635 if let Some(settings) = &settings.binary
636 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
637 {
638 let settings = settings.clone();
639 let languages = self.languages.clone();
640 return cx.background_spawn(async move {
641 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
642 let already_trusted = *wait_until_worktree_trust.borrow();
643 if !already_trusted {
644 log::info!(
645 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
646 adapter.name(),
647 );
648 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
649 if worktree_trusted {
650 break;
651 }
652 }
653 log::info!(
654 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
655 adapter.name(),
656 );
657 }
658 languages
659 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
660 }
661 let mut env = delegate.shell_env().await;
662 env.extend(settings.env.unwrap_or_default());
663
664 Ok(LanguageServerBinary {
665 path: delegate.resolve_executable_path(path),
666 env: Some(env),
667 arguments: settings
668 .arguments
669 .unwrap_or_default()
670 .iter()
671 .map(Into::into)
672 .collect(),
673 })
674 });
675 }
676 let lsp_binary_options = LanguageServerBinaryOptions {
677 allow_path_lookup: !settings
678 .binary
679 .as_ref()
680 .and_then(|b| b.ignore_system_version)
681 .unwrap_or_default(),
682 allow_binary_download,
683 pre_release: settings
684 .fetch
685 .as_ref()
686 .and_then(|f| f.pre_release)
687 .unwrap_or(false),
688 };
689
690 cx.spawn(async move |cx| {
691 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
692 let already_trusted = *wait_until_worktree_trust.borrow();
693 if !already_trusted {
694 log::info!(
695 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
696 adapter.name(),
697 );
698 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
699 if worktree_trusted {
700 break;
701 }
702 }
703 log::info!(
704 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
705 adapter.name(),
706 );
707 }
708 }
709
710 let (existing_binary, maybe_download_binary) = adapter
711 .clone()
712 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
713 .await
714 .await;
715
716 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
717
718 let mut binary = match (existing_binary, maybe_download_binary) {
719 (binary, None) => binary?,
720 (Err(_), Some(downloader)) => downloader.await?,
721 (Ok(existing_binary), Some(downloader)) => {
722 let mut download_timeout = cx
723 .background_executor()
724 .timer(SERVER_DOWNLOAD_TIMEOUT)
725 .fuse();
726 let mut downloader = downloader.fuse();
727 futures::select! {
728 _ = download_timeout => {
729 // Return existing binary and kick the existing work to the background.
730 cx.spawn(async move |_| downloader.await).detach();
731 Ok(existing_binary)
732 },
733 downloaded_or_existing_binary = downloader => {
734 // If download fails, this results in the existing binary.
735 downloaded_or_existing_binary
736 }
737 }?
738 }
739 };
740 let mut shell_env = delegate.shell_env().await;
741
742 shell_env.extend(binary.env.unwrap_or_default());
743
744 if let Some(settings) = settings.binary.as_ref() {
745 if let Some(arguments) = &settings.arguments {
746 binary.arguments = arguments.iter().map(Into::into).collect();
747 }
748 if let Some(env) = &settings.env {
749 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
750 }
751 }
752
753 binary.env = Some(shell_env);
754 Ok(binary)
755 })
756 }
757
758 fn setup_lsp_messages(
759 lsp_store: WeakEntity<LspStore>,
760 language_server: &LanguageServer,
761 delegate: Arc<dyn LspAdapterDelegate>,
762 adapter: Arc<CachedLspAdapter>,
763 ) {
764 let name = language_server.name();
765 let server_id = language_server.server_id();
766 language_server
767 .on_notification::<lsp::notification::PublishDiagnostics, _>({
768 let adapter = adapter.clone();
769 let this = lsp_store.clone();
770 move |mut params, cx| {
771 let adapter = adapter.clone();
772 if let Some(this) = this.upgrade() {
773 this.update(cx, |this, cx| {
774 {
775 let buffer = params
776 .uri
777 .to_file_path()
778 .map(|file_path| this.get_buffer(&file_path, cx))
779 .ok()
780 .flatten();
781 adapter.process_diagnostics(&mut params, server_id, buffer);
782 }
783
784 this.merge_lsp_diagnostics(
785 DiagnosticSourceKind::Pushed,
786 vec![DocumentDiagnosticsUpdate {
787 server_id,
788 diagnostics: params,
789 result_id: None,
790 disk_based_sources: Cow::Borrowed(
791 &adapter.disk_based_diagnostic_sources,
792 ),
793 registration_id: None,
794 }],
795 |_, diagnostic, cx| match diagnostic.source_kind {
796 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
797 adapter.retain_old_diagnostic(diagnostic, cx)
798 }
799 DiagnosticSourceKind::Pulled => true,
800 },
801 cx,
802 )
803 .log_err();
804 })
805 .ok();
806 }
807 }
808 })
809 .detach();
810 language_server
811 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
812 let adapter = adapter.adapter.clone();
813 let delegate = delegate.clone();
814 let this = lsp_store.clone();
815 move |params, cx| {
816 let adapter = adapter.clone();
817 let delegate = delegate.clone();
818 let this = this.clone();
819 let mut cx = cx.clone();
820 async move {
821 let toolchain_for_id = this
822 .update(&mut cx, |this, _| {
823 this.as_local()?.language_server_ids.iter().find_map(
824 |(seed, value)| {
825 (value.id == server_id).then(|| seed.toolchain.clone())
826 },
827 )
828 })?
829 .context("Expected the LSP store to be in a local mode")?;
830
831 let mut scope_uri_to_workspace_config = BTreeMap::new();
832 for item in ¶ms.items {
833 let scope_uri = item.scope_uri.clone();
834 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
835 scope_uri_to_workspace_config.entry(scope_uri.clone())
836 else {
837 // We've already queried workspace configuration of this URI.
838 continue;
839 };
840 let workspace_config = Self::workspace_configuration_for_adapter(
841 adapter.clone(),
842 &delegate,
843 toolchain_for_id.clone(),
844 scope_uri,
845 &mut cx,
846 )
847 .await?;
848 new_scope_uri.insert(workspace_config);
849 }
850
851 Ok(params
852 .items
853 .into_iter()
854 .filter_map(|item| {
855 let workspace_config =
856 scope_uri_to_workspace_config.get(&item.scope_uri)?;
857 if let Some(section) = &item.section {
858 Some(
859 workspace_config
860 .get(section)
861 .cloned()
862 .unwrap_or(serde_json::Value::Null),
863 )
864 } else {
865 Some(workspace_config.clone())
866 }
867 })
868 .collect())
869 }
870 }
871 })
872 .detach();
873
874 language_server
875 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
876 let this = lsp_store.clone();
877 move |_, cx| {
878 let this = this.clone();
879 let cx = cx.clone();
880 async move {
881 let Some(server) =
882 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
883 else {
884 return Ok(None);
885 };
886 let root = server.workspace_folders();
887 Ok(Some(
888 root.into_iter()
889 .map(|uri| WorkspaceFolder {
890 uri,
891 name: Default::default(),
892 })
893 .collect(),
894 ))
895 }
896 }
897 })
898 .detach();
899 // Even though we don't have handling for these requests, respond to them to
900 // avoid stalling any language server like `gopls` which waits for a response
901 // to these requests when initializing.
902 language_server
903 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
904 let this = lsp_store.clone();
905 move |params, cx| {
906 let this = this.clone();
907 let mut cx = cx.clone();
908 async move {
909 this.update(&mut cx, |this, _| {
910 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
911 {
912 status
913 .progress_tokens
914 .insert(ProgressToken::from_lsp(params.token));
915 }
916 })?;
917
918 Ok(())
919 }
920 }
921 })
922 .detach();
923
924 language_server
925 .on_request::<lsp::request::RegisterCapability, _, _>({
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 .register_server_capabilities(server_id, params, cx)
936 {
937 Ok(()) => {}
938 Err(e) => {
939 log::error!(
940 "Failed to register 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::UnregisterCapability, _, _>({
955 let lsp_store = lsp_store.clone();
956 move |params, cx| {
957 let lsp_store = lsp_store.clone();
958 let mut cx = cx.clone();
959 async move {
960 lsp_store
961 .update(&mut cx, |lsp_store, cx| {
962 if lsp_store.as_local().is_some() {
963 match lsp_store
964 .unregister_server_capabilities(server_id, params, cx)
965 {
966 Ok(()) => {}
967 Err(e) => {
968 log::error!(
969 "Failed to unregister server capabilities: {e:#}"
970 );
971 }
972 }
973 }
974 })
975 .ok();
976 Ok(())
977 }
978 }
979 })
980 .detach();
981
982 language_server
983 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
984 let this = lsp_store.clone();
985 move |params, cx| {
986 let mut cx = cx.clone();
987 let this = this.clone();
988 async move {
989 LocalLspStore::on_lsp_workspace_edit(
990 this.clone(),
991 params,
992 server_id,
993 &mut cx,
994 )
995 .await
996 }
997 }
998 })
999 .detach();
1000
1001 language_server
1002 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1003 let lsp_store = lsp_store.clone();
1004 let request_id = Arc::new(AtomicUsize::new(0));
1005 move |(), cx| {
1006 let lsp_store = lsp_store.clone();
1007 let request_id = request_id.clone();
1008 let mut cx = cx.clone();
1009 async move {
1010 lsp_store
1011 .update(&mut cx, |lsp_store, cx| {
1012 let request_id =
1013 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1014 cx.emit(LspStoreEvent::RefreshInlayHints {
1015 server_id,
1016 request_id,
1017 });
1018 lsp_store
1019 .downstream_client
1020 .as_ref()
1021 .map(|(client, project_id)| {
1022 client.send(proto::RefreshInlayHints {
1023 project_id: *project_id,
1024 server_id: server_id.to_proto(),
1025 request_id: request_id.map(|id| id as u64),
1026 })
1027 })
1028 })?
1029 .transpose()?;
1030 Ok(())
1031 }
1032 }
1033 })
1034 .detach();
1035
1036 language_server
1037 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1038 let this = lsp_store.clone();
1039 move |(), cx| {
1040 let this = this.clone();
1041 let mut cx = cx.clone();
1042 async move {
1043 this.update(&mut cx, |this, cx| {
1044 cx.emit(LspStoreEvent::RefreshCodeLens);
1045 this.downstream_client.as_ref().map(|(client, project_id)| {
1046 client.send(proto::RefreshCodeLens {
1047 project_id: *project_id,
1048 })
1049 })
1050 })?
1051 .transpose()?;
1052 Ok(())
1053 }
1054 }
1055 })
1056 .detach();
1057
1058 language_server
1059 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1060 let this = lsp_store.clone();
1061 move |(), cx| {
1062 let this = this.clone();
1063 let mut cx = cx.clone();
1064 async move {
1065 this.update(&mut cx, |lsp_store, cx| {
1066 lsp_store.pull_workspace_diagnostics(server_id);
1067 lsp_store.pull_document_diagnostics_for_server(server_id, cx);
1068 lsp_store
1069 .downstream_client
1070 .as_ref()
1071 .map(|(client, project_id)| {
1072 client.send(proto::PullWorkspaceDiagnostics {
1073 project_id: *project_id,
1074 server_id: server_id.to_proto(),
1075 })
1076 })
1077 })?
1078 .transpose()?;
1079 Ok(())
1080 }
1081 }
1082 })
1083 .detach();
1084
1085 language_server
1086 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1087 let this = lsp_store.clone();
1088 let name = name.to_string();
1089 let adapter = adapter.clone();
1090 move |params, cx| {
1091 let this = this.clone();
1092 let name = name.to_string();
1093 let adapter = adapter.clone();
1094 let mut cx = cx.clone();
1095 async move {
1096 let actions = params.actions.unwrap_or_default();
1097 let message = params.message.clone();
1098 let (tx, rx) = smol::channel::bounded(1);
1099 let request = LanguageServerPromptRequest {
1100 level: match params.typ {
1101 lsp::MessageType::ERROR => PromptLevel::Critical,
1102 lsp::MessageType::WARNING => PromptLevel::Warning,
1103 _ => PromptLevel::Info,
1104 },
1105 message: params.message,
1106 actions,
1107 response_channel: tx,
1108 lsp_name: name.clone(),
1109 };
1110
1111 let did_update = this
1112 .update(&mut cx, |_, cx| {
1113 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1114 })
1115 .is_ok();
1116 if did_update {
1117 let response = rx.recv().await.ok();
1118 if let Some(ref selected_action) = response {
1119 let context = language::PromptResponseContext {
1120 message,
1121 selected_action: selected_action.clone(),
1122 };
1123 adapter.process_prompt_response(&context, &mut cx)
1124 }
1125
1126 Ok(response)
1127 } else {
1128 Ok(None)
1129 }
1130 }
1131 }
1132 })
1133 .detach();
1134 language_server
1135 .on_notification::<lsp::notification::ShowMessage, _>({
1136 let this = lsp_store.clone();
1137 let name = name.to_string();
1138 move |params, cx| {
1139 let this = this.clone();
1140 let name = name.to_string();
1141 let mut cx = cx.clone();
1142
1143 let (tx, _) = smol::channel::bounded(1);
1144 let request = LanguageServerPromptRequest {
1145 level: match params.typ {
1146 lsp::MessageType::ERROR => PromptLevel::Critical,
1147 lsp::MessageType::WARNING => PromptLevel::Warning,
1148 _ => PromptLevel::Info,
1149 },
1150 message: params.message,
1151 actions: vec![],
1152 response_channel: tx,
1153 lsp_name: name,
1154 };
1155
1156 let _ = this.update(&mut cx, |_, cx| {
1157 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1158 });
1159 }
1160 })
1161 .detach();
1162
1163 let disk_based_diagnostics_progress_token =
1164 adapter.disk_based_diagnostics_progress_token.clone();
1165
1166 language_server
1167 .on_notification::<lsp::notification::Progress, _>({
1168 let this = lsp_store.clone();
1169 move |params, cx| {
1170 if let Some(this) = this.upgrade() {
1171 this.update(cx, |this, cx| {
1172 this.on_lsp_progress(
1173 params,
1174 server_id,
1175 disk_based_diagnostics_progress_token.clone(),
1176 cx,
1177 );
1178 })
1179 .ok();
1180 }
1181 }
1182 })
1183 .detach();
1184
1185 language_server
1186 .on_notification::<lsp::notification::LogMessage, _>({
1187 let this = lsp_store.clone();
1188 move |params, cx| {
1189 if let Some(this) = this.upgrade() {
1190 this.update(cx, |_, cx| {
1191 cx.emit(LspStoreEvent::LanguageServerLog(
1192 server_id,
1193 LanguageServerLogType::Log(params.typ),
1194 params.message,
1195 ));
1196 })
1197 .ok();
1198 }
1199 }
1200 })
1201 .detach();
1202
1203 language_server
1204 .on_notification::<lsp::notification::LogTrace, _>({
1205 let this = lsp_store.clone();
1206 move |params, cx| {
1207 let mut cx = cx.clone();
1208 if let Some(this) = this.upgrade() {
1209 this.update(&mut cx, |_, cx| {
1210 cx.emit(LspStoreEvent::LanguageServerLog(
1211 server_id,
1212 LanguageServerLogType::Trace {
1213 verbose_info: params.verbose,
1214 },
1215 params.message,
1216 ));
1217 })
1218 .ok();
1219 }
1220 }
1221 })
1222 .detach();
1223
1224 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1225 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1226 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1227 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1228 }
1229
1230 fn shutdown_language_servers_on_quit(
1231 &mut self,
1232 _: &mut Context<LspStore>,
1233 ) -> impl Future<Output = ()> + use<> {
1234 let shutdown_futures = self
1235 .language_servers
1236 .drain()
1237 .map(|(_, server_state)| Self::shutdown_server(server_state))
1238 .collect::<Vec<_>>();
1239
1240 async move {
1241 join_all(shutdown_futures).await;
1242 }
1243 }
1244
1245 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1246 match server_state {
1247 LanguageServerState::Running { server, .. } => {
1248 if let Some(shutdown) = server.shutdown() {
1249 shutdown.await;
1250 }
1251 }
1252 LanguageServerState::Starting { startup, .. } => {
1253 if let Some(server) = startup.await
1254 && let Some(shutdown) = server.shutdown()
1255 {
1256 shutdown.await;
1257 }
1258 }
1259 }
1260 Ok(())
1261 }
1262
1263 fn language_servers_for_worktree(
1264 &self,
1265 worktree_id: WorktreeId,
1266 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1267 self.language_server_ids
1268 .iter()
1269 .filter_map(move |(seed, state)| {
1270 if seed.worktree_id != worktree_id {
1271 return None;
1272 }
1273
1274 if let Some(LanguageServerState::Running { server, .. }) =
1275 self.language_servers.get(&state.id)
1276 {
1277 Some(server)
1278 } else {
1279 None
1280 }
1281 })
1282 }
1283
1284 fn language_server_ids_for_project_path(
1285 &self,
1286 project_path: ProjectPath,
1287 language: &Language,
1288 cx: &mut App,
1289 ) -> Vec<LanguageServerId> {
1290 let Some(worktree) = self
1291 .worktree_store
1292 .read(cx)
1293 .worktree_for_id(project_path.worktree_id, cx)
1294 else {
1295 return Vec::new();
1296 };
1297 let delegate: Arc<dyn ManifestDelegate> =
1298 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1299
1300 self.lsp_tree
1301 .get(
1302 project_path,
1303 language.name(),
1304 language.manifest(),
1305 &delegate,
1306 cx,
1307 )
1308 .collect::<Vec<_>>()
1309 }
1310
1311 fn language_server_ids_for_buffer(
1312 &self,
1313 buffer: &Buffer,
1314 cx: &mut App,
1315 ) -> Vec<LanguageServerId> {
1316 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1317 let worktree_id = file.worktree_id(cx);
1318
1319 let path: Arc<RelPath> = file
1320 .path()
1321 .parent()
1322 .map(Arc::from)
1323 .unwrap_or_else(|| file.path().clone());
1324 let worktree_path = ProjectPath { worktree_id, path };
1325 self.language_server_ids_for_project_path(worktree_path, language, cx)
1326 } else {
1327 Vec::new()
1328 }
1329 }
1330
1331 fn language_servers_for_buffer<'a>(
1332 &'a self,
1333 buffer: &'a Buffer,
1334 cx: &'a mut App,
1335 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1336 self.language_server_ids_for_buffer(buffer, cx)
1337 .into_iter()
1338 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1339 LanguageServerState::Running {
1340 adapter, server, ..
1341 } => Some((adapter, server)),
1342 _ => None,
1343 })
1344 }
1345
1346 async fn execute_code_action_kind_locally(
1347 lsp_store: WeakEntity<LspStore>,
1348 mut buffers: Vec<Entity<Buffer>>,
1349 kind: CodeActionKind,
1350 push_to_history: bool,
1351 cx: &mut AsyncApp,
1352 ) -> anyhow::Result<ProjectTransaction> {
1353 // Do not allow multiple concurrent code actions requests for the
1354 // same buffer.
1355 lsp_store.update(cx, |this, cx| {
1356 let this = this.as_local_mut().unwrap();
1357 buffers.retain(|buffer| {
1358 this.buffers_being_formatted
1359 .insert(buffer.read(cx).remote_id())
1360 });
1361 })?;
1362 let _cleanup = defer({
1363 let this = lsp_store.clone();
1364 let mut cx = cx.clone();
1365 let buffers = &buffers;
1366 move || {
1367 this.update(&mut cx, |this, cx| {
1368 let this = this.as_local_mut().unwrap();
1369 for buffer in buffers {
1370 this.buffers_being_formatted
1371 .remove(&buffer.read(cx).remote_id());
1372 }
1373 })
1374 .ok();
1375 }
1376 });
1377 let mut project_transaction = ProjectTransaction::default();
1378
1379 for buffer in &buffers {
1380 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1381 buffer.update(cx, |buffer, cx| {
1382 lsp_store
1383 .as_local()
1384 .unwrap()
1385 .language_servers_for_buffer(buffer, cx)
1386 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1387 .collect::<Vec<_>>()
1388 })
1389 })?;
1390 for (_, language_server) in adapters_and_servers.iter() {
1391 let actions = Self::get_server_code_actions_from_action_kinds(
1392 &lsp_store,
1393 language_server.server_id(),
1394 vec![kind.clone()],
1395 buffer,
1396 cx,
1397 )
1398 .await?;
1399 Self::execute_code_actions_on_server(
1400 &lsp_store,
1401 language_server,
1402 actions,
1403 push_to_history,
1404 &mut project_transaction,
1405 cx,
1406 )
1407 .await?;
1408 }
1409 }
1410 Ok(project_transaction)
1411 }
1412
1413 async fn format_locally(
1414 lsp_store: WeakEntity<LspStore>,
1415 mut buffers: Vec<FormattableBuffer>,
1416 push_to_history: bool,
1417 trigger: FormatTrigger,
1418 logger: zlog::Logger,
1419 cx: &mut AsyncApp,
1420 ) -> anyhow::Result<ProjectTransaction> {
1421 // Do not allow multiple concurrent formatting requests for the
1422 // same buffer.
1423 lsp_store.update(cx, |this, cx| {
1424 let this = this.as_local_mut().unwrap();
1425 buffers.retain(|buffer| {
1426 this.buffers_being_formatted
1427 .insert(buffer.handle.read(cx).remote_id())
1428 });
1429 })?;
1430
1431 let _cleanup = defer({
1432 let this = lsp_store.clone();
1433 let mut cx = cx.clone();
1434 let buffers = &buffers;
1435 move || {
1436 this.update(&mut cx, |this, cx| {
1437 let this = this.as_local_mut().unwrap();
1438 for buffer in buffers {
1439 this.buffers_being_formatted
1440 .remove(&buffer.handle.read(cx).remote_id());
1441 }
1442 })
1443 .ok();
1444 }
1445 });
1446
1447 let mut project_transaction = ProjectTransaction::default();
1448
1449 for buffer in &buffers {
1450 zlog::debug!(
1451 logger =>
1452 "formatting buffer '{:?}'",
1453 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1454 );
1455 // Create an empty transaction to hold all of the formatting edits.
1456 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1457 // ensure no transactions created while formatting are
1458 // grouped with the previous transaction in the history
1459 // based on the transaction group interval
1460 buffer.finalize_last_transaction();
1461 buffer
1462 .start_transaction()
1463 .context("transaction already open")?;
1464 buffer.end_transaction(cx);
1465 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1466 buffer.finalize_last_transaction();
1467 anyhow::Ok(transaction_id)
1468 })??;
1469
1470 let result = Self::format_buffer_locally(
1471 lsp_store.clone(),
1472 buffer,
1473 formatting_transaction_id,
1474 trigger,
1475 logger,
1476 cx,
1477 )
1478 .await;
1479
1480 buffer.handle.update(cx, |buffer, cx| {
1481 let Some(formatting_transaction) =
1482 buffer.get_transaction(formatting_transaction_id).cloned()
1483 else {
1484 zlog::warn!(logger => "no formatting transaction");
1485 return;
1486 };
1487 if formatting_transaction.edit_ids.is_empty() {
1488 zlog::debug!(logger => "no changes made while formatting");
1489 buffer.forget_transaction(formatting_transaction_id);
1490 return;
1491 }
1492 if !push_to_history {
1493 zlog::trace!(logger => "forgetting format transaction");
1494 buffer.forget_transaction(formatting_transaction.id);
1495 }
1496 project_transaction
1497 .0
1498 .insert(cx.entity(), formatting_transaction);
1499 })?;
1500
1501 result?;
1502 }
1503
1504 Ok(project_transaction)
1505 }
1506
1507 async fn format_buffer_locally(
1508 lsp_store: WeakEntity<LspStore>,
1509 buffer: &FormattableBuffer,
1510 formatting_transaction_id: clock::Lamport,
1511 trigger: FormatTrigger,
1512 logger: zlog::Logger,
1513 cx: &mut AsyncApp,
1514 ) -> Result<()> {
1515 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1516 buffer.handle.update(cx, |buffer, cx| {
1517 let adapters_and_servers = lsp_store
1518 .as_local()
1519 .unwrap()
1520 .language_servers_for_buffer(buffer, cx)
1521 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1522 .collect::<Vec<_>>();
1523 let settings =
1524 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1525 .into_owned();
1526 (adapters_and_servers, settings)
1527 })
1528 })?;
1529
1530 /// Apply edits to the buffer that will become part of the formatting transaction.
1531 /// Fails if the buffer has been edited since the start of that transaction.
1532 fn extend_formatting_transaction(
1533 buffer: &FormattableBuffer,
1534 formatting_transaction_id: text::TransactionId,
1535 cx: &mut AsyncApp,
1536 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1537 ) -> anyhow::Result<()> {
1538 buffer.handle.update(cx, |buffer, cx| {
1539 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1540 if last_transaction_id != Some(formatting_transaction_id) {
1541 anyhow::bail!("Buffer edited while formatting. Aborting")
1542 }
1543 buffer.start_transaction();
1544 operation(buffer, cx);
1545 if let Some(transaction_id) = buffer.end_transaction(cx) {
1546 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1547 }
1548 Ok(())
1549 })?
1550 }
1551
1552 // handle whitespace formatting
1553 if settings.remove_trailing_whitespace_on_save {
1554 zlog::trace!(logger => "removing trailing whitespace");
1555 let diff = buffer
1556 .handle
1557 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))?
1558 .await;
1559 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1560 buffer.apply_diff(diff, cx);
1561 })?;
1562 }
1563
1564 if settings.ensure_final_newline_on_save {
1565 zlog::trace!(logger => "ensuring final newline");
1566 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1567 buffer.ensure_final_newline(cx);
1568 })?;
1569 }
1570
1571 // Formatter for `code_actions_on_format` that runs before
1572 // the rest of the formatters
1573 let mut code_actions_on_format_formatters = None;
1574 let should_run_code_actions_on_format = !matches!(
1575 (trigger, &settings.format_on_save),
1576 (FormatTrigger::Save, &FormatOnSave::Off)
1577 );
1578 if should_run_code_actions_on_format {
1579 let have_code_actions_to_run_on_format = settings
1580 .code_actions_on_format
1581 .values()
1582 .any(|enabled| *enabled);
1583 if have_code_actions_to_run_on_format {
1584 zlog::trace!(logger => "going to run code actions on format");
1585 code_actions_on_format_formatters = Some(
1586 settings
1587 .code_actions_on_format
1588 .iter()
1589 .filter_map(|(action, enabled)| enabled.then_some(action))
1590 .cloned()
1591 .map(Formatter::CodeAction)
1592 .collect::<Vec<_>>(),
1593 );
1594 }
1595 }
1596
1597 let formatters = match (trigger, &settings.format_on_save) {
1598 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1599 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1600 settings.formatter.as_ref()
1601 }
1602 };
1603
1604 let formatters = code_actions_on_format_formatters
1605 .iter()
1606 .flatten()
1607 .chain(formatters);
1608
1609 for formatter in formatters {
1610 let formatter = if formatter == &Formatter::Auto {
1611 if settings.prettier.allowed {
1612 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1613 &Formatter::Prettier
1614 } else {
1615 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1616 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1617 }
1618 } else {
1619 formatter
1620 };
1621 match formatter {
1622 Formatter::Auto => unreachable!("Auto resolved above"),
1623 Formatter::Prettier => {
1624 let logger = zlog::scoped!(logger => "prettier");
1625 zlog::trace!(logger => "formatting");
1626 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1627
1628 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1629 lsp_store.prettier_store().unwrap().downgrade()
1630 })?;
1631 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1632 .await
1633 .transpose()?;
1634 let Some(diff) = diff else {
1635 zlog::trace!(logger => "No changes");
1636 continue;
1637 };
1638
1639 extend_formatting_transaction(
1640 buffer,
1641 formatting_transaction_id,
1642 cx,
1643 |buffer, cx| {
1644 buffer.apply_diff(diff, cx);
1645 },
1646 )?;
1647 }
1648 Formatter::External { command, arguments } => {
1649 let logger = zlog::scoped!(logger => "command");
1650 zlog::trace!(logger => "formatting");
1651 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1652
1653 let diff = Self::format_via_external_command(
1654 buffer,
1655 command.as_ref(),
1656 arguments.as_deref(),
1657 cx,
1658 )
1659 .await
1660 .with_context(|| {
1661 format!("Failed to format buffer via external command: {}", command)
1662 })?;
1663 let Some(diff) = diff else {
1664 zlog::trace!(logger => "No changes");
1665 continue;
1666 };
1667
1668 extend_formatting_transaction(
1669 buffer,
1670 formatting_transaction_id,
1671 cx,
1672 |buffer, cx| {
1673 buffer.apply_diff(diff, cx);
1674 },
1675 )?;
1676 }
1677 Formatter::LanguageServer(specifier) => {
1678 let logger = zlog::scoped!(logger => "language-server");
1679 zlog::trace!(logger => "formatting");
1680 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1681
1682 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1683 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1684 continue;
1685 };
1686
1687 let language_server = match specifier {
1688 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1689 adapters_and_servers.iter().find_map(|(adapter, server)| {
1690 if adapter.name.0.as_ref() == name {
1691 Some(server.clone())
1692 } else {
1693 None
1694 }
1695 })
1696 }
1697 settings::LanguageServerFormatterSpecifier::Current => {
1698 adapters_and_servers.first().map(|e| e.1.clone())
1699 }
1700 };
1701
1702 let Some(language_server) = language_server else {
1703 log::debug!(
1704 "No language server found to format buffer '{:?}'. Skipping",
1705 buffer_path_abs.as_path().to_string_lossy()
1706 );
1707 continue;
1708 };
1709
1710 zlog::trace!(
1711 logger =>
1712 "Formatting buffer '{:?}' using language server '{:?}'",
1713 buffer_path_abs.as_path().to_string_lossy(),
1714 language_server.name()
1715 );
1716
1717 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1718 zlog::trace!(logger => "formatting ranges");
1719 Self::format_ranges_via_lsp(
1720 &lsp_store,
1721 &buffer.handle,
1722 ranges,
1723 buffer_path_abs,
1724 &language_server,
1725 &settings,
1726 cx,
1727 )
1728 .await
1729 .context("Failed to format ranges via language server")?
1730 } else {
1731 zlog::trace!(logger => "formatting full");
1732 Self::format_via_lsp(
1733 &lsp_store,
1734 &buffer.handle,
1735 buffer_path_abs,
1736 &language_server,
1737 &settings,
1738 cx,
1739 )
1740 .await
1741 .context("failed to format via language server")?
1742 };
1743
1744 if edits.is_empty() {
1745 zlog::trace!(logger => "No changes");
1746 continue;
1747 }
1748 extend_formatting_transaction(
1749 buffer,
1750 formatting_transaction_id,
1751 cx,
1752 |buffer, cx| {
1753 buffer.edit(edits, None, cx);
1754 },
1755 )?;
1756 }
1757 Formatter::CodeAction(code_action_name) => {
1758 let logger = zlog::scoped!(logger => "code-actions");
1759 zlog::trace!(logger => "formatting");
1760 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1761
1762 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1763 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1764 continue;
1765 };
1766
1767 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1768 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1769
1770 let mut actions_and_servers = Vec::new();
1771
1772 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1773 let actions_result = Self::get_server_code_actions_from_action_kinds(
1774 &lsp_store,
1775 language_server.server_id(),
1776 vec![code_action_kind.clone()],
1777 &buffer.handle,
1778 cx,
1779 )
1780 .await
1781 .with_context(|| {
1782 format!(
1783 "Failed to resolve code action {:?} with language server {}",
1784 code_action_kind,
1785 language_server.name()
1786 )
1787 });
1788 let Ok(actions) = actions_result else {
1789 // note: it may be better to set result to the error and break formatters here
1790 // but for now we try to execute the actions that we can resolve and skip the rest
1791 zlog::error!(
1792 logger =>
1793 "Failed to resolve code action {:?} with language server {}",
1794 code_action_kind,
1795 language_server.name()
1796 );
1797 continue;
1798 };
1799 for action in actions {
1800 actions_and_servers.push((action, index));
1801 }
1802 }
1803
1804 if actions_and_servers.is_empty() {
1805 zlog::warn!(logger => "No code actions were resolved, continuing");
1806 continue;
1807 }
1808
1809 'actions: for (mut action, server_index) in actions_and_servers {
1810 let server = &adapters_and_servers[server_index].1;
1811
1812 let describe_code_action = |action: &CodeAction| {
1813 format!(
1814 "code action '{}' with title \"{}\" on server {}",
1815 action
1816 .lsp_action
1817 .action_kind()
1818 .unwrap_or("unknown".into())
1819 .as_str(),
1820 action.lsp_action.title(),
1821 server.name(),
1822 )
1823 };
1824
1825 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1826
1827 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1828 zlog::error!(
1829 logger =>
1830 "Failed to resolve {}. Error: {}",
1831 describe_code_action(&action),
1832 err
1833 );
1834 continue;
1835 }
1836
1837 if let Some(edit) = action.lsp_action.edit().cloned() {
1838 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1839 // but filters out and logs warnings for code actions that require unreasonably
1840 // difficult handling on our part, such as:
1841 // - applying edits that call commands
1842 // which can result in arbitrary workspace edits being sent from the server that
1843 // have no way of being tied back to the command that initiated them (i.e. we
1844 // can't know which edits are part of the format request, or if the server is done sending
1845 // actions in response to the command)
1846 // - actions that create/delete/modify/rename files other than the one we are formatting
1847 // as we then would need to handle such changes correctly in the local history as well
1848 // as the remote history through the ProjectTransaction
1849 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1850 // Supporting these actions is not impossible, but not supported as of yet.
1851 if edit.changes.is_none() && edit.document_changes.is_none() {
1852 zlog::trace!(
1853 logger =>
1854 "No changes for code action. Skipping {}",
1855 describe_code_action(&action),
1856 );
1857 continue;
1858 }
1859
1860 let mut operations = Vec::new();
1861 if let Some(document_changes) = edit.document_changes {
1862 match document_changes {
1863 lsp::DocumentChanges::Edits(edits) => operations.extend(
1864 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1865 ),
1866 lsp::DocumentChanges::Operations(ops) => operations = ops,
1867 }
1868 } else if let Some(changes) = edit.changes {
1869 operations.extend(changes.into_iter().map(|(uri, edits)| {
1870 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1871 text_document:
1872 lsp::OptionalVersionedTextDocumentIdentifier {
1873 uri,
1874 version: None,
1875 },
1876 edits: edits.into_iter().map(Edit::Plain).collect(),
1877 })
1878 }));
1879 }
1880
1881 let mut edits = Vec::with_capacity(operations.len());
1882
1883 if operations.is_empty() {
1884 zlog::trace!(
1885 logger =>
1886 "No changes for code action. Skipping {}",
1887 describe_code_action(&action),
1888 );
1889 continue;
1890 }
1891 for operation in operations {
1892 let op = match operation {
1893 lsp::DocumentChangeOperation::Edit(op) => op,
1894 lsp::DocumentChangeOperation::Op(_) => {
1895 zlog::warn!(
1896 logger =>
1897 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1898 describe_code_action(&action),
1899 );
1900 continue 'actions;
1901 }
1902 };
1903 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1904 zlog::warn!(
1905 logger =>
1906 "Failed to convert URI '{:?}' to file path. Skipping {}",
1907 &op.text_document.uri,
1908 describe_code_action(&action),
1909 );
1910 continue 'actions;
1911 };
1912 if &file_path != buffer_path_abs {
1913 zlog::warn!(
1914 logger =>
1915 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1916 file_path,
1917 buffer_path_abs,
1918 describe_code_action(&action),
1919 );
1920 continue 'actions;
1921 }
1922
1923 let mut lsp_edits = Vec::new();
1924 for edit in op.edits {
1925 match edit {
1926 Edit::Plain(edit) => {
1927 if !lsp_edits.contains(&edit) {
1928 lsp_edits.push(edit);
1929 }
1930 }
1931 Edit::Annotated(edit) => {
1932 if !lsp_edits.contains(&edit.text_edit) {
1933 lsp_edits.push(edit.text_edit);
1934 }
1935 }
1936 Edit::Snippet(_) => {
1937 zlog::warn!(
1938 logger =>
1939 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1940 describe_code_action(&action),
1941 );
1942 continue 'actions;
1943 }
1944 }
1945 }
1946 let edits_result = lsp_store
1947 .update(cx, |lsp_store, cx| {
1948 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1949 &buffer.handle,
1950 lsp_edits,
1951 server.server_id(),
1952 op.text_document.version,
1953 cx,
1954 )
1955 })?
1956 .await;
1957 let Ok(resolved_edits) = edits_result else {
1958 zlog::warn!(
1959 logger =>
1960 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1961 buffer_path_abs.as_path(),
1962 describe_code_action(&action),
1963 );
1964 continue 'actions;
1965 };
1966 edits.extend(resolved_edits);
1967 }
1968
1969 if edits.is_empty() {
1970 zlog::warn!(logger => "No edits resolved from LSP");
1971 continue;
1972 }
1973
1974 extend_formatting_transaction(
1975 buffer,
1976 formatting_transaction_id,
1977 cx,
1978 |buffer, cx| {
1979 zlog::info!(
1980 "Applying edits {edits:?}. Content: {:?}",
1981 buffer.text()
1982 );
1983 buffer.edit(edits, None, cx);
1984 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1985 },
1986 )?;
1987 }
1988
1989 if let Some(command) = action.lsp_action.command() {
1990 zlog::warn!(
1991 logger =>
1992 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1993 &command.command,
1994 );
1995
1996 // bail early if command is invalid
1997 let server_capabilities = server.capabilities();
1998 let available_commands = server_capabilities
1999 .execute_command_provider
2000 .as_ref()
2001 .map(|options| options.commands.as_slice())
2002 .unwrap_or_default();
2003 if !available_commands.contains(&command.command) {
2004 zlog::warn!(
2005 logger =>
2006 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2007 command.command,
2008 server.name(),
2009 );
2010 continue;
2011 }
2012
2013 // noop so we just ensure buffer hasn't been edited since resolving code actions
2014 extend_formatting_transaction(
2015 buffer,
2016 formatting_transaction_id,
2017 cx,
2018 |_, _| {},
2019 )?;
2020 zlog::info!(logger => "Executing command {}", &command.command);
2021
2022 lsp_store.update(cx, |this, _| {
2023 this.as_local_mut()
2024 .unwrap()
2025 .last_workspace_edits_by_language_server
2026 .remove(&server.server_id());
2027 })?;
2028
2029 let execute_command_result = server
2030 .request::<lsp::request::ExecuteCommand>(
2031 lsp::ExecuteCommandParams {
2032 command: command.command.clone(),
2033 arguments: command.arguments.clone().unwrap_or_default(),
2034 ..Default::default()
2035 },
2036 )
2037 .await
2038 .into_response();
2039
2040 if execute_command_result.is_err() {
2041 zlog::error!(
2042 logger =>
2043 "Failed to execute command '{}' as part of {}",
2044 &command.command,
2045 describe_code_action(&action),
2046 );
2047 continue 'actions;
2048 }
2049
2050 let mut project_transaction_command =
2051 lsp_store.update(cx, |this, _| {
2052 this.as_local_mut()
2053 .unwrap()
2054 .last_workspace_edits_by_language_server
2055 .remove(&server.server_id())
2056 .unwrap_or_default()
2057 })?;
2058
2059 if let Some(transaction) =
2060 project_transaction_command.0.remove(&buffer.handle)
2061 {
2062 zlog::trace!(
2063 logger =>
2064 "Successfully captured {} edits that resulted from command {}",
2065 transaction.edit_ids.len(),
2066 &command.command,
2067 );
2068 let transaction_id_project_transaction = transaction.id;
2069 buffer.handle.update(cx, |buffer, _| {
2070 // it may have been removed from history if push_to_history was
2071 // false in deserialize_workspace_edit. If so push it so we
2072 // can merge it with the format transaction
2073 // and pop the combined transaction off the history stack
2074 // later if push_to_history is false
2075 if buffer.get_transaction(transaction.id).is_none() {
2076 buffer.push_transaction(transaction, Instant::now());
2077 }
2078 buffer.merge_transactions(
2079 transaction_id_project_transaction,
2080 formatting_transaction_id,
2081 );
2082 })?;
2083 }
2084
2085 if !project_transaction_command.0.is_empty() {
2086 let mut extra_buffers = String::new();
2087 for buffer in project_transaction_command.0.keys() {
2088 buffer
2089 .read_with(cx, |b, cx| {
2090 if let Some(path) = b.project_path(cx) {
2091 if !extra_buffers.is_empty() {
2092 extra_buffers.push_str(", ");
2093 }
2094 extra_buffers.push_str(path.path.as_unix_str());
2095 }
2096 })
2097 .ok();
2098 }
2099 zlog::warn!(
2100 logger =>
2101 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2102 &command.command,
2103 extra_buffers,
2104 );
2105 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2106 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2107 // add it so it's included, and merge it into the format transaction when its created later
2108 }
2109 }
2110 }
2111 }
2112 }
2113 }
2114
2115 Ok(())
2116 }
2117
2118 pub async fn format_ranges_via_lsp(
2119 this: &WeakEntity<LspStore>,
2120 buffer_handle: &Entity<Buffer>,
2121 ranges: &[Range<Anchor>],
2122 abs_path: &Path,
2123 language_server: &Arc<LanguageServer>,
2124 settings: &LanguageSettings,
2125 cx: &mut AsyncApp,
2126 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2127 let capabilities = &language_server.capabilities();
2128 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2129 if range_formatting_provider == Some(&OneOf::Left(false)) {
2130 anyhow::bail!(
2131 "{} language server does not support range formatting",
2132 language_server.name()
2133 );
2134 }
2135
2136 let uri = file_path_to_lsp_url(abs_path)?;
2137 let text_document = lsp::TextDocumentIdentifier::new(uri);
2138
2139 let lsp_edits = {
2140 let mut lsp_ranges = Vec::new();
2141 this.update(cx, |_this, cx| {
2142 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2143 // not have been sent to the language server. This seems like a fairly systemic
2144 // issue, though, the resolution probably is not specific to formatting.
2145 //
2146 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2147 // LSP.
2148 let snapshot = buffer_handle.read(cx).snapshot();
2149 for range in ranges {
2150 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2151 }
2152 anyhow::Ok(())
2153 })??;
2154
2155 let mut edits = None;
2156 for range in lsp_ranges {
2157 if let Some(mut edit) = language_server
2158 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2159 text_document: text_document.clone(),
2160 range,
2161 options: lsp_command::lsp_formatting_options(settings),
2162 work_done_progress_params: Default::default(),
2163 })
2164 .await
2165 .into_response()?
2166 {
2167 edits.get_or_insert_with(Vec::new).append(&mut edit);
2168 }
2169 }
2170 edits
2171 };
2172
2173 if let Some(lsp_edits) = lsp_edits {
2174 this.update(cx, |this, cx| {
2175 this.as_local_mut().unwrap().edits_from_lsp(
2176 buffer_handle,
2177 lsp_edits,
2178 language_server.server_id(),
2179 None,
2180 cx,
2181 )
2182 })?
2183 .await
2184 } else {
2185 Ok(Vec::with_capacity(0))
2186 }
2187 }
2188
2189 async fn format_via_lsp(
2190 this: &WeakEntity<LspStore>,
2191 buffer: &Entity<Buffer>,
2192 abs_path: &Path,
2193 language_server: &Arc<LanguageServer>,
2194 settings: &LanguageSettings,
2195 cx: &mut AsyncApp,
2196 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2197 let logger = zlog::scoped!("lsp_format");
2198 zlog::debug!(logger => "Formatting via LSP");
2199
2200 let uri = file_path_to_lsp_url(abs_path)?;
2201 let text_document = lsp::TextDocumentIdentifier::new(uri);
2202 let capabilities = &language_server.capabilities();
2203
2204 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2205 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2206
2207 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2208 let _timer = zlog::time!(logger => "format-full");
2209 language_server
2210 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2211 text_document,
2212 options: lsp_command::lsp_formatting_options(settings),
2213 work_done_progress_params: Default::default(),
2214 })
2215 .await
2216 .into_response()?
2217 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2218 let _timer = zlog::time!(logger => "format-range");
2219 let buffer_start = lsp::Position::new(0, 0);
2220 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()))?;
2221 language_server
2222 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2223 text_document: text_document.clone(),
2224 range: lsp::Range::new(buffer_start, buffer_end),
2225 options: lsp_command::lsp_formatting_options(settings),
2226 work_done_progress_params: Default::default(),
2227 })
2228 .await
2229 .into_response()?
2230 } else {
2231 None
2232 };
2233
2234 if let Some(lsp_edits) = lsp_edits {
2235 this.update(cx, |this, cx| {
2236 this.as_local_mut().unwrap().edits_from_lsp(
2237 buffer,
2238 lsp_edits,
2239 language_server.server_id(),
2240 None,
2241 cx,
2242 )
2243 })?
2244 .await
2245 } else {
2246 Ok(Vec::with_capacity(0))
2247 }
2248 }
2249
2250 async fn format_via_external_command(
2251 buffer: &FormattableBuffer,
2252 command: &str,
2253 arguments: Option<&[String]>,
2254 cx: &mut AsyncApp,
2255 ) -> Result<Option<Diff>> {
2256 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2257 let file = File::from_dyn(buffer.file())?;
2258 let worktree = file.worktree.read(cx);
2259 let mut worktree_path = worktree.abs_path().to_path_buf();
2260 if worktree.root_entry()?.is_file() {
2261 worktree_path.pop();
2262 }
2263 Some(worktree_path)
2264 })?;
2265
2266 let mut child = util::command::new_smol_command(command);
2267
2268 if let Some(buffer_env) = buffer.env.as_ref() {
2269 child.envs(buffer_env);
2270 }
2271
2272 if let Some(working_dir_path) = working_dir_path {
2273 child.current_dir(working_dir_path);
2274 }
2275
2276 if let Some(arguments) = arguments {
2277 child.args(arguments.iter().map(|arg| {
2278 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2279 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2280 } else {
2281 arg.replace("{buffer_path}", "Untitled")
2282 }
2283 }));
2284 }
2285
2286 let mut child = child
2287 .stdin(smol::process::Stdio::piped())
2288 .stdout(smol::process::Stdio::piped())
2289 .stderr(smol::process::Stdio::piped())
2290 .spawn()?;
2291
2292 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2293 let text = buffer
2294 .handle
2295 .read_with(cx, |buffer, _| buffer.as_rope().clone())?;
2296 for chunk in text.chunks() {
2297 stdin.write_all(chunk.as_bytes()).await?;
2298 }
2299 stdin.flush().await?;
2300
2301 let output = child.output().await?;
2302 anyhow::ensure!(
2303 output.status.success(),
2304 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2305 output.status.code(),
2306 String::from_utf8_lossy(&output.stdout),
2307 String::from_utf8_lossy(&output.stderr),
2308 );
2309
2310 let stdout = String::from_utf8(output.stdout)?;
2311 Ok(Some(
2312 buffer
2313 .handle
2314 .update(cx, |buffer, cx| buffer.diff(stdout, cx))?
2315 .await,
2316 ))
2317 }
2318
2319 async fn try_resolve_code_action(
2320 lang_server: &LanguageServer,
2321 action: &mut CodeAction,
2322 ) -> anyhow::Result<()> {
2323 match &mut action.lsp_action {
2324 LspAction::Action(lsp_action) => {
2325 if !action.resolved
2326 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2327 && lsp_action.data.is_some()
2328 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2329 {
2330 **lsp_action = lang_server
2331 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2332 .await
2333 .into_response()?;
2334 }
2335 }
2336 LspAction::CodeLens(lens) => {
2337 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2338 *lens = lang_server
2339 .request::<lsp::request::CodeLensResolve>(lens.clone())
2340 .await
2341 .into_response()?;
2342 }
2343 }
2344 LspAction::Command(_) => {}
2345 }
2346
2347 action.resolved = true;
2348 anyhow::Ok(())
2349 }
2350
2351 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2352 let buffer = buffer_handle.read(cx);
2353
2354 let file = buffer.file().cloned();
2355
2356 let Some(file) = File::from_dyn(file.as_ref()) else {
2357 return;
2358 };
2359 if !file.is_local() {
2360 return;
2361 }
2362 let path = ProjectPath::from_file(file, cx);
2363 let worktree_id = file.worktree_id(cx);
2364 let language = buffer.language().cloned();
2365
2366 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2367 for (server_id, diagnostics) in
2368 diagnostics.get(file.path()).cloned().unwrap_or_default()
2369 {
2370 self.update_buffer_diagnostics(
2371 buffer_handle,
2372 server_id,
2373 None,
2374 None,
2375 None,
2376 Vec::new(),
2377 diagnostics,
2378 cx,
2379 )
2380 .log_err();
2381 }
2382 }
2383 let Some(language) = language else {
2384 return;
2385 };
2386 let Some(snapshot) = self
2387 .worktree_store
2388 .read(cx)
2389 .worktree_for_id(worktree_id, cx)
2390 .map(|worktree| worktree.read(cx).snapshot())
2391 else {
2392 return;
2393 };
2394 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2395
2396 for server_id in
2397 self.lsp_tree
2398 .get(path, language.name(), language.manifest(), &delegate, cx)
2399 {
2400 let server = self
2401 .language_servers
2402 .get(&server_id)
2403 .and_then(|server_state| {
2404 if let LanguageServerState::Running { server, .. } = server_state {
2405 Some(server.clone())
2406 } else {
2407 None
2408 }
2409 });
2410 let server = match server {
2411 Some(server) => server,
2412 None => continue,
2413 };
2414
2415 buffer_handle.update(cx, |buffer, cx| {
2416 buffer.set_completion_triggers(
2417 server.server_id(),
2418 server
2419 .capabilities()
2420 .completion_provider
2421 .as_ref()
2422 .and_then(|provider| {
2423 provider
2424 .trigger_characters
2425 .as_ref()
2426 .map(|characters| characters.iter().cloned().collect())
2427 })
2428 .unwrap_or_default(),
2429 cx,
2430 );
2431 });
2432 }
2433 }
2434
2435 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2436 buffer.update(cx, |buffer, cx| {
2437 let Some(language) = buffer.language() else {
2438 return;
2439 };
2440 let path = ProjectPath {
2441 worktree_id: old_file.worktree_id(cx),
2442 path: old_file.path.clone(),
2443 };
2444 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2445 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2446 buffer.set_completion_triggers(server_id, Default::default(), cx);
2447 }
2448 });
2449 }
2450
2451 fn update_buffer_diagnostics(
2452 &mut self,
2453 buffer: &Entity<Buffer>,
2454 server_id: LanguageServerId,
2455 registration_id: Option<Option<SharedString>>,
2456 result_id: Option<SharedString>,
2457 version: Option<i32>,
2458 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2459 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2460 cx: &mut Context<LspStore>,
2461 ) -> Result<()> {
2462 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2463 Ordering::Equal
2464 .then_with(|| b.is_primary.cmp(&a.is_primary))
2465 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2466 .then_with(|| a.severity.cmp(&b.severity))
2467 .then_with(|| a.message.cmp(&b.message))
2468 }
2469
2470 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2471 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2472 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2473
2474 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2475 Ordering::Equal
2476 .then_with(|| a.range.start.cmp(&b.range.start))
2477 .then_with(|| b.range.end.cmp(&a.range.end))
2478 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2479 });
2480
2481 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2482
2483 let edits_since_save = std::cell::LazyCell::new(|| {
2484 let saved_version = buffer.read(cx).saved_version();
2485 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2486 });
2487
2488 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2489
2490 for (new_diagnostic, entry) in diagnostics {
2491 let start;
2492 let end;
2493 if new_diagnostic && entry.diagnostic.is_disk_based {
2494 // Some diagnostics are based on files on disk instead of buffers'
2495 // current contents. Adjust these diagnostics' ranges to reflect
2496 // any unsaved edits.
2497 // Do not alter the reused ones though, as their coordinates were stored as anchors
2498 // and were properly adjusted on reuse.
2499 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2500 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2501 } else {
2502 start = entry.range.start;
2503 end = entry.range.end;
2504 }
2505
2506 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2507 ..snapshot.clip_point_utf16(end, Bias::Right);
2508
2509 // Expand empty ranges by one codepoint
2510 if range.start == range.end {
2511 // This will be go to the next boundary when being clipped
2512 range.end.column += 1;
2513 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2514 if range.start == range.end && range.end.column > 0 {
2515 range.start.column -= 1;
2516 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2517 }
2518 }
2519
2520 sanitized_diagnostics.push(DiagnosticEntry {
2521 range,
2522 diagnostic: entry.diagnostic,
2523 });
2524 }
2525 drop(edits_since_save);
2526
2527 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2528 buffer.update(cx, |buffer, cx| {
2529 if let Some(registration_id) = registration_id {
2530 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2531 self.buffer_pull_diagnostics_result_ids
2532 .entry(server_id)
2533 .or_default()
2534 .entry(registration_id)
2535 .or_default()
2536 .insert(abs_path, result_id);
2537 }
2538 }
2539
2540 buffer.update_diagnostics(server_id, set, cx)
2541 });
2542
2543 Ok(())
2544 }
2545
2546 fn register_language_server_for_invisible_worktree(
2547 &mut self,
2548 worktree: &Entity<Worktree>,
2549 language_server_id: LanguageServerId,
2550 cx: &mut App,
2551 ) {
2552 let worktree = worktree.read(cx);
2553 let worktree_id = worktree.id();
2554 debug_assert!(!worktree.is_visible());
2555 let Some(mut origin_seed) = self
2556 .language_server_ids
2557 .iter()
2558 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2559 else {
2560 return;
2561 };
2562 origin_seed.worktree_id = worktree_id;
2563 self.language_server_ids
2564 .entry(origin_seed)
2565 .or_insert_with(|| UnifiedLanguageServer {
2566 id: language_server_id,
2567 project_roots: Default::default(),
2568 });
2569 }
2570
2571 fn register_buffer_with_language_servers(
2572 &mut self,
2573 buffer_handle: &Entity<Buffer>,
2574 only_register_servers: HashSet<LanguageServerSelector>,
2575 cx: &mut Context<LspStore>,
2576 ) {
2577 let buffer = buffer_handle.read(cx);
2578 let buffer_id = buffer.remote_id();
2579
2580 let Some(file) = File::from_dyn(buffer.file()) else {
2581 return;
2582 };
2583 if !file.is_local() {
2584 return;
2585 }
2586
2587 let abs_path = file.abs_path(cx);
2588 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2589 return;
2590 };
2591 let initial_snapshot = buffer.text_snapshot();
2592 let worktree_id = file.worktree_id(cx);
2593
2594 let Some(language) = buffer.language().cloned() else {
2595 return;
2596 };
2597 let path: Arc<RelPath> = file
2598 .path()
2599 .parent()
2600 .map(Arc::from)
2601 .unwrap_or_else(|| file.path().clone());
2602 let Some(worktree) = self
2603 .worktree_store
2604 .read(cx)
2605 .worktree_for_id(worktree_id, cx)
2606 else {
2607 return;
2608 };
2609 let language_name = language.name();
2610 let (reused, delegate, servers) = self
2611 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2612 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2613 .unwrap_or_else(|| {
2614 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2615 let delegate: Arc<dyn ManifestDelegate> =
2616 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2617
2618 let servers = self
2619 .lsp_tree
2620 .walk(
2621 ProjectPath { worktree_id, path },
2622 language.name(),
2623 language.manifest(),
2624 &delegate,
2625 cx,
2626 )
2627 .collect::<Vec<_>>();
2628 (false, lsp_delegate, servers)
2629 });
2630 let servers_and_adapters = servers
2631 .into_iter()
2632 .filter_map(|server_node| {
2633 if reused && server_node.server_id().is_none() {
2634 return None;
2635 }
2636 if !only_register_servers.is_empty() {
2637 if let Some(server_id) = server_node.server_id()
2638 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2639 {
2640 return None;
2641 }
2642 if let Some(name) = server_node.name()
2643 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2644 {
2645 return None;
2646 }
2647 }
2648
2649 let server_id = server_node.server_id_or_init(|disposition| {
2650 let path = &disposition.path;
2651
2652 {
2653 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2654
2655 let server_id = self.get_or_insert_language_server(
2656 &worktree,
2657 delegate.clone(),
2658 disposition,
2659 &language_name,
2660 cx,
2661 );
2662
2663 if let Some(state) = self.language_servers.get(&server_id)
2664 && let Ok(uri) = uri
2665 {
2666 state.add_workspace_folder(uri);
2667 };
2668 server_id
2669 }
2670 })?;
2671 let server_state = self.language_servers.get(&server_id)?;
2672 if let LanguageServerState::Running {
2673 server, adapter, ..
2674 } = server_state
2675 {
2676 Some((server.clone(), adapter.clone()))
2677 } else {
2678 None
2679 }
2680 })
2681 .collect::<Vec<_>>();
2682 for (server, adapter) in servers_and_adapters {
2683 buffer_handle.update(cx, |buffer, cx| {
2684 buffer.set_completion_triggers(
2685 server.server_id(),
2686 server
2687 .capabilities()
2688 .completion_provider
2689 .as_ref()
2690 .and_then(|provider| {
2691 provider
2692 .trigger_characters
2693 .as_ref()
2694 .map(|characters| characters.iter().cloned().collect())
2695 })
2696 .unwrap_or_default(),
2697 cx,
2698 );
2699 });
2700
2701 let snapshot = LspBufferSnapshot {
2702 version: 0,
2703 snapshot: initial_snapshot.clone(),
2704 };
2705
2706 let mut registered = false;
2707 self.buffer_snapshots
2708 .entry(buffer_id)
2709 .or_default()
2710 .entry(server.server_id())
2711 .or_insert_with(|| {
2712 registered = true;
2713 server.register_buffer(
2714 uri.clone(),
2715 adapter.language_id(&language.name()),
2716 0,
2717 initial_snapshot.text(),
2718 );
2719
2720 vec![snapshot]
2721 });
2722
2723 self.buffers_opened_in_servers
2724 .entry(buffer_id)
2725 .or_default()
2726 .insert(server.server_id());
2727 if registered {
2728 cx.emit(LspStoreEvent::LanguageServerUpdate {
2729 language_server_id: server.server_id(),
2730 name: None,
2731 message: proto::update_language_server::Variant::RegisteredForBuffer(
2732 proto::RegisteredForBuffer {
2733 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2734 buffer_id: buffer_id.to_proto(),
2735 },
2736 ),
2737 });
2738 }
2739 }
2740 }
2741
2742 fn reuse_existing_language_server<'lang_name>(
2743 &self,
2744 server_tree: &LanguageServerTree,
2745 worktree: &Entity<Worktree>,
2746 language_name: &'lang_name LanguageName,
2747 cx: &mut App,
2748 ) -> Option<(
2749 Arc<LocalLspAdapterDelegate>,
2750 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2751 )> {
2752 if worktree.read(cx).is_visible() {
2753 return None;
2754 }
2755
2756 let worktree_store = self.worktree_store.read(cx);
2757 let servers = server_tree
2758 .instances
2759 .iter()
2760 .filter(|(worktree_id, _)| {
2761 worktree_store
2762 .worktree_for_id(**worktree_id, cx)
2763 .is_some_and(|worktree| worktree.read(cx).is_visible())
2764 })
2765 .flat_map(|(worktree_id, servers)| {
2766 servers
2767 .roots
2768 .iter()
2769 .flat_map(|(_, language_servers)| language_servers)
2770 .map(move |(_, (server_node, server_languages))| {
2771 (worktree_id, server_node, server_languages)
2772 })
2773 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2774 .map(|(worktree_id, server_node, _)| {
2775 (
2776 *worktree_id,
2777 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2778 )
2779 })
2780 })
2781 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2782 acc.entry(worktree_id)
2783 .or_insert_with(Vec::new)
2784 .push(server_node);
2785 acc
2786 })
2787 .into_values()
2788 .max_by_key(|servers| servers.len())?;
2789
2790 let worktree_id = worktree.read(cx).id();
2791 let apply = move |tree: &mut LanguageServerTree| {
2792 for server_node in &servers {
2793 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2794 }
2795 servers
2796 };
2797
2798 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2799 Some((delegate, apply))
2800 }
2801
2802 pub(crate) fn unregister_old_buffer_from_language_servers(
2803 &mut self,
2804 buffer: &Entity<Buffer>,
2805 old_file: &File,
2806 cx: &mut App,
2807 ) {
2808 let old_path = match old_file.as_local() {
2809 Some(local) => local.abs_path(cx),
2810 None => return,
2811 };
2812
2813 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2814 debug_panic!("{old_path:?} is not parseable as an URI");
2815 return;
2816 };
2817 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2818 }
2819
2820 pub(crate) fn unregister_buffer_from_language_servers(
2821 &mut self,
2822 buffer: &Entity<Buffer>,
2823 file_url: &lsp::Uri,
2824 cx: &mut App,
2825 ) {
2826 buffer.update(cx, |buffer, cx| {
2827 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2828
2829 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2830 if snapshots
2831 .as_mut()
2832 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2833 {
2834 language_server.unregister_buffer(file_url.clone());
2835 }
2836 }
2837 });
2838 }
2839
2840 fn buffer_snapshot_for_lsp_version(
2841 &mut self,
2842 buffer: &Entity<Buffer>,
2843 server_id: LanguageServerId,
2844 version: Option<i32>,
2845 cx: &App,
2846 ) -> Result<TextBufferSnapshot> {
2847 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2848
2849 if let Some(version) = version {
2850 let buffer_id = buffer.read(cx).remote_id();
2851 let snapshots = if let Some(snapshots) = self
2852 .buffer_snapshots
2853 .get_mut(&buffer_id)
2854 .and_then(|m| m.get_mut(&server_id))
2855 {
2856 snapshots
2857 } else if version == 0 {
2858 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2859 // We detect this case and treat it as if the version was `None`.
2860 return Ok(buffer.read(cx).text_snapshot());
2861 } else {
2862 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2863 };
2864
2865 let found_snapshot = snapshots
2866 .binary_search_by_key(&version, |e| e.version)
2867 .map(|ix| snapshots[ix].snapshot.clone())
2868 .map_err(|_| {
2869 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2870 })?;
2871
2872 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2873 Ok(found_snapshot)
2874 } else {
2875 Ok((buffer.read(cx)).text_snapshot())
2876 }
2877 }
2878
2879 async fn get_server_code_actions_from_action_kinds(
2880 lsp_store: &WeakEntity<LspStore>,
2881 language_server_id: LanguageServerId,
2882 code_action_kinds: Vec<lsp::CodeActionKind>,
2883 buffer: &Entity<Buffer>,
2884 cx: &mut AsyncApp,
2885 ) -> Result<Vec<CodeAction>> {
2886 let actions = lsp_store
2887 .update(cx, move |this, cx| {
2888 let request = GetCodeActions {
2889 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2890 kinds: Some(code_action_kinds),
2891 };
2892 let server = LanguageServerToQuery::Other(language_server_id);
2893 this.request_lsp(buffer.clone(), server, request, cx)
2894 })?
2895 .await?;
2896 Ok(actions)
2897 }
2898
2899 pub async fn execute_code_actions_on_server(
2900 lsp_store: &WeakEntity<LspStore>,
2901 language_server: &Arc<LanguageServer>,
2902
2903 actions: Vec<CodeAction>,
2904 push_to_history: bool,
2905 project_transaction: &mut ProjectTransaction,
2906 cx: &mut AsyncApp,
2907 ) -> anyhow::Result<()> {
2908 for mut action in actions {
2909 Self::try_resolve_code_action(language_server, &mut action)
2910 .await
2911 .context("resolving a formatting code action")?;
2912
2913 if let Some(edit) = action.lsp_action.edit() {
2914 if edit.changes.is_none() && edit.document_changes.is_none() {
2915 continue;
2916 }
2917
2918 let new = Self::deserialize_workspace_edit(
2919 lsp_store.upgrade().context("project dropped")?,
2920 edit.clone(),
2921 push_to_history,
2922 language_server.clone(),
2923 cx,
2924 )
2925 .await?;
2926 project_transaction.0.extend(new.0);
2927 }
2928
2929 if let Some(command) = action.lsp_action.command() {
2930 let server_capabilities = language_server.capabilities();
2931 let available_commands = server_capabilities
2932 .execute_command_provider
2933 .as_ref()
2934 .map(|options| options.commands.as_slice())
2935 .unwrap_or_default();
2936 if available_commands.contains(&command.command) {
2937 lsp_store.update(cx, |lsp_store, _| {
2938 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2939 mode.last_workspace_edits_by_language_server
2940 .remove(&language_server.server_id());
2941 }
2942 })?;
2943
2944 language_server
2945 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2946 command: command.command.clone(),
2947 arguments: command.arguments.clone().unwrap_or_default(),
2948 ..Default::default()
2949 })
2950 .await
2951 .into_response()
2952 .context("execute command")?;
2953
2954 lsp_store.update(cx, |this, _| {
2955 if let LspStoreMode::Local(mode) = &mut this.mode {
2956 project_transaction.0.extend(
2957 mode.last_workspace_edits_by_language_server
2958 .remove(&language_server.server_id())
2959 .unwrap_or_default()
2960 .0,
2961 )
2962 }
2963 })?;
2964 } else {
2965 log::warn!(
2966 "Cannot execute a command {} not listed in the language server capabilities",
2967 command.command
2968 )
2969 }
2970 }
2971 }
2972 Ok(())
2973 }
2974
2975 pub async fn deserialize_text_edits(
2976 this: Entity<LspStore>,
2977 buffer_to_edit: Entity<Buffer>,
2978 edits: Vec<lsp::TextEdit>,
2979 push_to_history: bool,
2980 _: Arc<CachedLspAdapter>,
2981 language_server: Arc<LanguageServer>,
2982 cx: &mut AsyncApp,
2983 ) -> Result<Option<Transaction>> {
2984 let edits = this
2985 .update(cx, |this, cx| {
2986 this.as_local_mut().unwrap().edits_from_lsp(
2987 &buffer_to_edit,
2988 edits,
2989 language_server.server_id(),
2990 None,
2991 cx,
2992 )
2993 })?
2994 .await?;
2995
2996 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2997 buffer.finalize_last_transaction();
2998 buffer.start_transaction();
2999 for (range, text) in edits {
3000 buffer.edit([(range, text)], None, cx);
3001 }
3002
3003 if buffer.end_transaction(cx).is_some() {
3004 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3005 if !push_to_history {
3006 buffer.forget_transaction(transaction.id);
3007 }
3008 Some(transaction)
3009 } else {
3010 None
3011 }
3012 })?;
3013
3014 Ok(transaction)
3015 }
3016
3017 #[allow(clippy::type_complexity)]
3018 pub(crate) fn edits_from_lsp(
3019 &mut self,
3020 buffer: &Entity<Buffer>,
3021 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3022 server_id: LanguageServerId,
3023 version: Option<i32>,
3024 cx: &mut Context<LspStore>,
3025 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3026 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3027 cx.background_spawn(async move {
3028 let snapshot = snapshot?;
3029 let mut lsp_edits = lsp_edits
3030 .into_iter()
3031 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3032 .collect::<Vec<_>>();
3033
3034 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3035
3036 let mut lsp_edits = lsp_edits.into_iter().peekable();
3037 let mut edits = Vec::new();
3038 while let Some((range, mut new_text)) = lsp_edits.next() {
3039 // Clip invalid ranges provided by the language server.
3040 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3041 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3042
3043 // Combine any LSP edits that are adjacent.
3044 //
3045 // Also, combine LSP edits that are separated from each other by only
3046 // a newline. This is important because for some code actions,
3047 // Rust-analyzer rewrites the entire buffer via a series of edits that
3048 // are separated by unchanged newline characters.
3049 //
3050 // In order for the diffing logic below to work properly, any edits that
3051 // cancel each other out must be combined into one.
3052 while let Some((next_range, next_text)) = lsp_edits.peek() {
3053 if next_range.start.0 > range.end {
3054 if next_range.start.0.row > range.end.row + 1
3055 || next_range.start.0.column > 0
3056 || snapshot.clip_point_utf16(
3057 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3058 Bias::Left,
3059 ) > range.end
3060 {
3061 break;
3062 }
3063 new_text.push('\n');
3064 }
3065 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3066 new_text.push_str(next_text);
3067 lsp_edits.next();
3068 }
3069
3070 // For multiline edits, perform a diff of the old and new text so that
3071 // we can identify the changes more precisely, preserving the locations
3072 // of any anchors positioned in the unchanged regions.
3073 if range.end.row > range.start.row {
3074 let offset = range.start.to_offset(&snapshot);
3075 let old_text = snapshot.text_for_range(range).collect::<String>();
3076 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3077 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3078 (
3079 snapshot.anchor_after(offset + range.start)
3080 ..snapshot.anchor_before(offset + range.end),
3081 replacement,
3082 )
3083 }));
3084 } else if range.end == range.start {
3085 let anchor = snapshot.anchor_after(range.start);
3086 edits.push((anchor..anchor, new_text.into()));
3087 } else {
3088 let edit_start = snapshot.anchor_after(range.start);
3089 let edit_end = snapshot.anchor_before(range.end);
3090 edits.push((edit_start..edit_end, new_text.into()));
3091 }
3092 }
3093
3094 Ok(edits)
3095 })
3096 }
3097
3098 pub(crate) async fn deserialize_workspace_edit(
3099 this: Entity<LspStore>,
3100 edit: lsp::WorkspaceEdit,
3101 push_to_history: bool,
3102 language_server: Arc<LanguageServer>,
3103 cx: &mut AsyncApp,
3104 ) -> Result<ProjectTransaction> {
3105 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
3106
3107 let mut operations = Vec::new();
3108 if let Some(document_changes) = edit.document_changes {
3109 match document_changes {
3110 lsp::DocumentChanges::Edits(edits) => {
3111 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3112 }
3113 lsp::DocumentChanges::Operations(ops) => operations = ops,
3114 }
3115 } else if let Some(changes) = edit.changes {
3116 operations.extend(changes.into_iter().map(|(uri, edits)| {
3117 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3118 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3119 uri,
3120 version: None,
3121 },
3122 edits: edits.into_iter().map(Edit::Plain).collect(),
3123 })
3124 }));
3125 }
3126
3127 let mut project_transaction = ProjectTransaction::default();
3128 for operation in operations {
3129 match operation {
3130 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3131 let abs_path = op
3132 .uri
3133 .to_file_path()
3134 .map_err(|()| anyhow!("can't convert URI to path"))?;
3135
3136 if let Some(parent_path) = abs_path.parent() {
3137 fs.create_dir(parent_path).await?;
3138 }
3139 if abs_path.ends_with("/") {
3140 fs.create_dir(&abs_path).await?;
3141 } else {
3142 fs.create_file(
3143 &abs_path,
3144 op.options
3145 .map(|options| fs::CreateOptions {
3146 overwrite: options.overwrite.unwrap_or(false),
3147 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3148 })
3149 .unwrap_or_default(),
3150 )
3151 .await?;
3152 }
3153 }
3154
3155 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3156 let source_abs_path = op
3157 .old_uri
3158 .to_file_path()
3159 .map_err(|()| anyhow!("can't convert URI to path"))?;
3160 let target_abs_path = op
3161 .new_uri
3162 .to_file_path()
3163 .map_err(|()| anyhow!("can't convert URI to path"))?;
3164
3165 let options = fs::RenameOptions {
3166 overwrite: op
3167 .options
3168 .as_ref()
3169 .and_then(|options| options.overwrite)
3170 .unwrap_or(false),
3171 ignore_if_exists: op
3172 .options
3173 .as_ref()
3174 .and_then(|options| options.ignore_if_exists)
3175 .unwrap_or(false),
3176 create_parents: true,
3177 };
3178
3179 fs.rename(&source_abs_path, &target_abs_path, options)
3180 .await?;
3181 }
3182
3183 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3184 let abs_path = op
3185 .uri
3186 .to_file_path()
3187 .map_err(|()| anyhow!("can't convert URI to path"))?;
3188 let options = op
3189 .options
3190 .map(|options| fs::RemoveOptions {
3191 recursive: options.recursive.unwrap_or(false),
3192 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3193 })
3194 .unwrap_or_default();
3195 if abs_path.ends_with("/") {
3196 fs.remove_dir(&abs_path, options).await?;
3197 } else {
3198 fs.remove_file(&abs_path, options).await?;
3199 }
3200 }
3201
3202 lsp::DocumentChangeOperation::Edit(op) => {
3203 let buffer_to_edit = this
3204 .update(cx, |this, cx| {
3205 this.open_local_buffer_via_lsp(
3206 op.text_document.uri.clone(),
3207 language_server.server_id(),
3208 cx,
3209 )
3210 })?
3211 .await?;
3212
3213 let edits = this
3214 .update(cx, |this, cx| {
3215 let path = buffer_to_edit.read(cx).project_path(cx);
3216 let active_entry = this.active_entry;
3217 let is_active_entry = path.is_some_and(|project_path| {
3218 this.worktree_store
3219 .read(cx)
3220 .entry_for_path(&project_path, cx)
3221 .is_some_and(|entry| Some(entry.id) == active_entry)
3222 });
3223 let local = this.as_local_mut().unwrap();
3224
3225 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3226 for edit in op.edits {
3227 match edit {
3228 Edit::Plain(edit) => {
3229 if !edits.contains(&edit) {
3230 edits.push(edit)
3231 }
3232 }
3233 Edit::Annotated(edit) => {
3234 if !edits.contains(&edit.text_edit) {
3235 edits.push(edit.text_edit)
3236 }
3237 }
3238 Edit::Snippet(edit) => {
3239 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3240 else {
3241 continue;
3242 };
3243
3244 if is_active_entry {
3245 snippet_edits.push((edit.range, snippet));
3246 } else {
3247 // Since this buffer is not focused, apply a normal edit.
3248 let new_edit = TextEdit {
3249 range: edit.range,
3250 new_text: snippet.text,
3251 };
3252 if !edits.contains(&new_edit) {
3253 edits.push(new_edit);
3254 }
3255 }
3256 }
3257 }
3258 }
3259 if !snippet_edits.is_empty() {
3260 let buffer_id = buffer_to_edit.read(cx).remote_id();
3261 let version = if let Some(buffer_version) = op.text_document.version
3262 {
3263 local
3264 .buffer_snapshot_for_lsp_version(
3265 &buffer_to_edit,
3266 language_server.server_id(),
3267 Some(buffer_version),
3268 cx,
3269 )
3270 .ok()
3271 .map(|snapshot| snapshot.version)
3272 } else {
3273 Some(buffer_to_edit.read(cx).saved_version().clone())
3274 };
3275
3276 let most_recent_edit =
3277 version.and_then(|version| version.most_recent());
3278 // Check if the edit that triggered that edit has been made by this participant.
3279
3280 if let Some(most_recent_edit) = most_recent_edit {
3281 cx.emit(LspStoreEvent::SnippetEdit {
3282 buffer_id,
3283 edits: snippet_edits,
3284 most_recent_edit,
3285 });
3286 }
3287 }
3288
3289 local.edits_from_lsp(
3290 &buffer_to_edit,
3291 edits,
3292 language_server.server_id(),
3293 op.text_document.version,
3294 cx,
3295 )
3296 })?
3297 .await?;
3298
3299 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3300 buffer.finalize_last_transaction();
3301 buffer.start_transaction();
3302 for (range, text) in edits {
3303 buffer.edit([(range, text)], None, cx);
3304 }
3305
3306 buffer.end_transaction(cx).and_then(|transaction_id| {
3307 if push_to_history {
3308 buffer.finalize_last_transaction();
3309 buffer.get_transaction(transaction_id).cloned()
3310 } else {
3311 buffer.forget_transaction(transaction_id)
3312 }
3313 })
3314 })?;
3315 if let Some(transaction) = transaction {
3316 project_transaction.0.insert(buffer_to_edit, transaction);
3317 }
3318 }
3319 }
3320 }
3321
3322 Ok(project_transaction)
3323 }
3324
3325 async fn on_lsp_workspace_edit(
3326 this: WeakEntity<LspStore>,
3327 params: lsp::ApplyWorkspaceEditParams,
3328 server_id: LanguageServerId,
3329 cx: &mut AsyncApp,
3330 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3331 let this = this.upgrade().context("project project closed")?;
3332 let language_server = this
3333 .read_with(cx, |this, _| this.language_server_for_id(server_id))?
3334 .context("language server not found")?;
3335 let transaction = Self::deserialize_workspace_edit(
3336 this.clone(),
3337 params.edit,
3338 true,
3339 language_server.clone(),
3340 cx,
3341 )
3342 .await
3343 .log_err();
3344 this.update(cx, |this, cx| {
3345 if let Some(transaction) = transaction {
3346 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3347
3348 this.as_local_mut()
3349 .unwrap()
3350 .last_workspace_edits_by_language_server
3351 .insert(server_id, transaction);
3352 }
3353 })?;
3354 Ok(lsp::ApplyWorkspaceEditResponse {
3355 applied: true,
3356 failed_change: None,
3357 failure_reason: None,
3358 })
3359 }
3360
3361 fn remove_worktree(
3362 &mut self,
3363 id_to_remove: WorktreeId,
3364 cx: &mut Context<LspStore>,
3365 ) -> Vec<LanguageServerId> {
3366 self.restricted_worktrees_tasks.remove(&id_to_remove);
3367 self.diagnostics.remove(&id_to_remove);
3368 self.prettier_store.update(cx, |prettier_store, cx| {
3369 prettier_store.remove_worktree(id_to_remove, cx);
3370 });
3371
3372 let mut servers_to_remove = BTreeSet::default();
3373 let mut servers_to_preserve = HashSet::default();
3374 for (seed, state) in &self.language_server_ids {
3375 if seed.worktree_id == id_to_remove {
3376 servers_to_remove.insert(state.id);
3377 } else {
3378 servers_to_preserve.insert(state.id);
3379 }
3380 }
3381 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3382 self.language_server_ids
3383 .retain(|_, state| !servers_to_remove.contains(&state.id));
3384 for server_id_to_remove in &servers_to_remove {
3385 self.language_server_watched_paths
3386 .remove(server_id_to_remove);
3387 self.language_server_paths_watched_for_rename
3388 .remove(server_id_to_remove);
3389 self.last_workspace_edits_by_language_server
3390 .remove(server_id_to_remove);
3391 self.language_servers.remove(server_id_to_remove);
3392 self.buffer_pull_diagnostics_result_ids
3393 .remove(server_id_to_remove);
3394 self.workspace_pull_diagnostics_result_ids
3395 .remove(server_id_to_remove);
3396 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3397 buffer_servers.remove(server_id_to_remove);
3398 }
3399 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3400 }
3401 servers_to_remove.into_iter().collect()
3402 }
3403
3404 fn rebuild_watched_paths_inner<'a>(
3405 &'a self,
3406 language_server_id: LanguageServerId,
3407 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3408 cx: &mut Context<LspStore>,
3409 ) -> LanguageServerWatchedPathsBuilder {
3410 let worktrees = self
3411 .worktree_store
3412 .read(cx)
3413 .worktrees()
3414 .filter_map(|worktree| {
3415 self.language_servers_for_worktree(worktree.read(cx).id())
3416 .find(|server| server.server_id() == language_server_id)
3417 .map(|_| worktree)
3418 })
3419 .collect::<Vec<_>>();
3420
3421 let mut worktree_globs = HashMap::default();
3422 let mut abs_globs = HashMap::default();
3423 log::trace!(
3424 "Processing new watcher paths for language server with id {}",
3425 language_server_id
3426 );
3427
3428 for watcher in watchers {
3429 if let Some((worktree, literal_prefix, pattern)) =
3430 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3431 {
3432 worktree.update(cx, |worktree, _| {
3433 if let Some((tree, glob)) =
3434 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3435 {
3436 tree.add_path_prefix_to_scan(literal_prefix);
3437 worktree_globs
3438 .entry(tree.id())
3439 .or_insert_with(GlobSetBuilder::new)
3440 .add(glob);
3441 }
3442 });
3443 } else {
3444 let (path, pattern) = match &watcher.glob_pattern {
3445 lsp::GlobPattern::String(s) => {
3446 let watcher_path = SanitizedPath::new(s);
3447 let path = glob_literal_prefix(watcher_path.as_path());
3448 let pattern = watcher_path
3449 .as_path()
3450 .strip_prefix(&path)
3451 .map(|p| p.to_string_lossy().into_owned())
3452 .unwrap_or_else(|e| {
3453 debug_panic!(
3454 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3455 s,
3456 path.display(),
3457 e
3458 );
3459 watcher_path.as_path().to_string_lossy().into_owned()
3460 });
3461 (path, pattern)
3462 }
3463 lsp::GlobPattern::Relative(rp) => {
3464 let Ok(mut base_uri) = match &rp.base_uri {
3465 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3466 lsp::OneOf::Right(base_uri) => base_uri,
3467 }
3468 .to_file_path() else {
3469 continue;
3470 };
3471
3472 let path = glob_literal_prefix(Path::new(&rp.pattern));
3473 let pattern = Path::new(&rp.pattern)
3474 .strip_prefix(&path)
3475 .map(|p| p.to_string_lossy().into_owned())
3476 .unwrap_or_else(|e| {
3477 debug_panic!(
3478 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3479 rp.pattern,
3480 path.display(),
3481 e
3482 );
3483 rp.pattern.clone()
3484 });
3485 base_uri.push(path);
3486 (base_uri, pattern)
3487 }
3488 };
3489
3490 if let Some(glob) = Glob::new(&pattern).log_err() {
3491 if !path
3492 .components()
3493 .any(|c| matches!(c, path::Component::Normal(_)))
3494 {
3495 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3496 // rather than adding a new watcher for `/`.
3497 for worktree in &worktrees {
3498 worktree_globs
3499 .entry(worktree.read(cx).id())
3500 .or_insert_with(GlobSetBuilder::new)
3501 .add(glob.clone());
3502 }
3503 } else {
3504 abs_globs
3505 .entry(path.into())
3506 .or_insert_with(GlobSetBuilder::new)
3507 .add(glob);
3508 }
3509 }
3510 }
3511 }
3512
3513 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3514 for (worktree_id, builder) in worktree_globs {
3515 if let Ok(globset) = builder.build() {
3516 watch_builder.watch_worktree(worktree_id, globset);
3517 }
3518 }
3519 for (abs_path, builder) in abs_globs {
3520 if let Ok(globset) = builder.build() {
3521 watch_builder.watch_abs_path(abs_path, globset);
3522 }
3523 }
3524 watch_builder
3525 }
3526
3527 fn worktree_and_path_for_file_watcher(
3528 worktrees: &[Entity<Worktree>],
3529 watcher: &FileSystemWatcher,
3530 cx: &App,
3531 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3532 worktrees.iter().find_map(|worktree| {
3533 let tree = worktree.read(cx);
3534 let worktree_root_path = tree.abs_path();
3535 let path_style = tree.path_style();
3536 match &watcher.glob_pattern {
3537 lsp::GlobPattern::String(s) => {
3538 let watcher_path = SanitizedPath::new(s);
3539 let relative = watcher_path
3540 .as_path()
3541 .strip_prefix(&worktree_root_path)
3542 .ok()?;
3543 let literal_prefix = glob_literal_prefix(relative);
3544 Some((
3545 worktree.clone(),
3546 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3547 relative.to_string_lossy().into_owned(),
3548 ))
3549 }
3550 lsp::GlobPattern::Relative(rp) => {
3551 let base_uri = match &rp.base_uri {
3552 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3553 lsp::OneOf::Right(base_uri) => base_uri,
3554 }
3555 .to_file_path()
3556 .ok()?;
3557 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3558 let mut literal_prefix = relative.to_owned();
3559 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3560 Some((
3561 worktree.clone(),
3562 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3563 rp.pattern.clone(),
3564 ))
3565 }
3566 }
3567 })
3568 }
3569
3570 fn rebuild_watched_paths(
3571 &mut self,
3572 language_server_id: LanguageServerId,
3573 cx: &mut Context<LspStore>,
3574 ) {
3575 let Some(registrations) = self
3576 .language_server_dynamic_registrations
3577 .get(&language_server_id)
3578 else {
3579 return;
3580 };
3581
3582 let watch_builder = self.rebuild_watched_paths_inner(
3583 language_server_id,
3584 registrations.did_change_watched_files.values().flatten(),
3585 cx,
3586 );
3587 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3588 self.language_server_watched_paths
3589 .insert(language_server_id, watcher);
3590
3591 cx.notify();
3592 }
3593
3594 fn on_lsp_did_change_watched_files(
3595 &mut self,
3596 language_server_id: LanguageServerId,
3597 registration_id: &str,
3598 params: DidChangeWatchedFilesRegistrationOptions,
3599 cx: &mut Context<LspStore>,
3600 ) {
3601 let registrations = self
3602 .language_server_dynamic_registrations
3603 .entry(language_server_id)
3604 .or_default();
3605
3606 registrations
3607 .did_change_watched_files
3608 .insert(registration_id.to_string(), params.watchers);
3609
3610 self.rebuild_watched_paths(language_server_id, cx);
3611 }
3612
3613 fn on_lsp_unregister_did_change_watched_files(
3614 &mut self,
3615 language_server_id: LanguageServerId,
3616 registration_id: &str,
3617 cx: &mut Context<LspStore>,
3618 ) {
3619 let registrations = self
3620 .language_server_dynamic_registrations
3621 .entry(language_server_id)
3622 .or_default();
3623
3624 if registrations
3625 .did_change_watched_files
3626 .remove(registration_id)
3627 .is_some()
3628 {
3629 log::info!(
3630 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3631 language_server_id,
3632 registration_id
3633 );
3634 } else {
3635 log::warn!(
3636 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3637 language_server_id,
3638 registration_id
3639 );
3640 }
3641
3642 self.rebuild_watched_paths(language_server_id, cx);
3643 }
3644
3645 async fn initialization_options_for_adapter(
3646 adapter: Arc<dyn LspAdapter>,
3647 delegate: &Arc<dyn LspAdapterDelegate>,
3648 ) -> Result<Option<serde_json::Value>> {
3649 let Some(mut initialization_config) =
3650 adapter.clone().initialization_options(delegate).await?
3651 else {
3652 return Ok(None);
3653 };
3654
3655 for other_adapter in delegate.registered_lsp_adapters() {
3656 if other_adapter.name() == adapter.name() {
3657 continue;
3658 }
3659 if let Ok(Some(target_config)) = other_adapter
3660 .clone()
3661 .additional_initialization_options(adapter.name(), delegate)
3662 .await
3663 {
3664 merge_json_value_into(target_config.clone(), &mut initialization_config);
3665 }
3666 }
3667
3668 Ok(Some(initialization_config))
3669 }
3670
3671 async fn workspace_configuration_for_adapter(
3672 adapter: Arc<dyn LspAdapter>,
3673 delegate: &Arc<dyn LspAdapterDelegate>,
3674 toolchain: Option<Toolchain>,
3675 requested_uri: Option<Uri>,
3676 cx: &mut AsyncApp,
3677 ) -> Result<serde_json::Value> {
3678 let mut workspace_config = adapter
3679 .clone()
3680 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3681 .await?;
3682
3683 for other_adapter in delegate.registered_lsp_adapters() {
3684 if other_adapter.name() == adapter.name() {
3685 continue;
3686 }
3687 if let Ok(Some(target_config)) = other_adapter
3688 .clone()
3689 .additional_workspace_configuration(adapter.name(), delegate, cx)
3690 .await
3691 {
3692 merge_json_value_into(target_config.clone(), &mut workspace_config);
3693 }
3694 }
3695
3696 Ok(workspace_config)
3697 }
3698
3699 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3700 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3701 Some(server.clone())
3702 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3703 Some(Arc::clone(server))
3704 } else {
3705 None
3706 }
3707 }
3708}
3709
3710fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3711 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3712 cx.emit(LspStoreEvent::LanguageServerUpdate {
3713 language_server_id: server.server_id(),
3714 name: Some(server.name()),
3715 message: proto::update_language_server::Variant::MetadataUpdated(
3716 proto::ServerMetadataUpdated {
3717 capabilities: Some(capabilities),
3718 binary: Some(proto::LanguageServerBinaryInfo {
3719 path: server.binary().path.to_string_lossy().into_owned(),
3720 arguments: server
3721 .binary()
3722 .arguments
3723 .iter()
3724 .map(|arg| arg.to_string_lossy().into_owned())
3725 .collect(),
3726 }),
3727 configuration: serde_json::to_string(server.configuration()).ok(),
3728 workspace_folders: server
3729 .workspace_folders()
3730 .iter()
3731 .map(|uri| uri.to_string())
3732 .collect(),
3733 },
3734 ),
3735 });
3736 }
3737}
3738
3739#[derive(Debug)]
3740pub struct FormattableBuffer {
3741 handle: Entity<Buffer>,
3742 abs_path: Option<PathBuf>,
3743 env: Option<HashMap<String, String>>,
3744 ranges: Option<Vec<Range<Anchor>>>,
3745}
3746
3747pub struct RemoteLspStore {
3748 upstream_client: Option<AnyProtoClient>,
3749 upstream_project_id: u64,
3750}
3751
3752pub(crate) enum LspStoreMode {
3753 Local(LocalLspStore), // ssh host and collab host
3754 Remote(RemoteLspStore), // collab guest
3755}
3756
3757impl LspStoreMode {
3758 fn is_local(&self) -> bool {
3759 matches!(self, LspStoreMode::Local(_))
3760 }
3761}
3762
3763pub struct LspStore {
3764 mode: LspStoreMode,
3765 last_formatting_failure: Option<String>,
3766 downstream_client: Option<(AnyProtoClient, u64)>,
3767 nonce: u128,
3768 buffer_store: Entity<BufferStore>,
3769 worktree_store: Entity<WorktreeStore>,
3770 pub languages: Arc<LanguageRegistry>,
3771 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3772 active_entry: Option<ProjectEntryId>,
3773 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3774 _maintain_buffer_languages: Task<()>,
3775 diagnostic_summaries:
3776 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3777 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3778 lsp_data: HashMap<BufferId, BufferLspData>,
3779 next_hint_id: Arc<AtomicUsize>,
3780}
3781
3782#[derive(Debug)]
3783pub struct BufferLspData {
3784 buffer_version: Global,
3785 document_colors: Option<DocumentColorData>,
3786 code_lens: Option<CodeLensData>,
3787 inlay_hints: BufferInlayHints,
3788 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3789 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3790}
3791
3792#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3793struct LspKey {
3794 request_type: TypeId,
3795 server_queried: Option<LanguageServerId>,
3796}
3797
3798impl BufferLspData {
3799 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3800 Self {
3801 buffer_version: buffer.read(cx).version(),
3802 document_colors: None,
3803 code_lens: None,
3804 inlay_hints: BufferInlayHints::new(buffer, cx),
3805 lsp_requests: HashMap::default(),
3806 chunk_lsp_requests: HashMap::default(),
3807 }
3808 }
3809
3810 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3811 if let Some(document_colors) = &mut self.document_colors {
3812 document_colors.colors.remove(&for_server);
3813 document_colors.cache_version += 1;
3814 }
3815
3816 if let Some(code_lens) = &mut self.code_lens {
3817 code_lens.lens.remove(&for_server);
3818 }
3819
3820 self.inlay_hints.remove_server_data(for_server);
3821 }
3822
3823 #[cfg(any(test, feature = "test-support"))]
3824 pub fn inlay_hints(&self) -> &BufferInlayHints {
3825 &self.inlay_hints
3826 }
3827}
3828
3829#[derive(Debug, Default, Clone)]
3830pub struct DocumentColors {
3831 pub colors: HashSet<DocumentColor>,
3832 pub cache_version: Option<usize>,
3833}
3834
3835type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3836type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3837
3838#[derive(Debug, Default)]
3839struct DocumentColorData {
3840 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3841 cache_version: usize,
3842 colors_update: Option<(Global, DocumentColorTask)>,
3843}
3844
3845#[derive(Debug, Default)]
3846struct CodeLensData {
3847 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3848 update: Option<(Global, CodeLensTask)>,
3849}
3850
3851#[derive(Debug)]
3852pub enum LspStoreEvent {
3853 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3854 LanguageServerRemoved(LanguageServerId),
3855 LanguageServerUpdate {
3856 language_server_id: LanguageServerId,
3857 name: Option<LanguageServerName>,
3858 message: proto::update_language_server::Variant,
3859 },
3860 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3861 LanguageServerPrompt(LanguageServerPromptRequest),
3862 LanguageDetected {
3863 buffer: Entity<Buffer>,
3864 new_language: Option<Arc<Language>>,
3865 },
3866 Notification(String),
3867 RefreshInlayHints {
3868 server_id: LanguageServerId,
3869 request_id: Option<usize>,
3870 },
3871 RefreshCodeLens,
3872 DiagnosticsUpdated {
3873 server_id: LanguageServerId,
3874 paths: Vec<ProjectPath>,
3875 },
3876 DiskBasedDiagnosticsStarted {
3877 language_server_id: LanguageServerId,
3878 },
3879 DiskBasedDiagnosticsFinished {
3880 language_server_id: LanguageServerId,
3881 },
3882 SnippetEdit {
3883 buffer_id: BufferId,
3884 edits: Vec<(lsp::Range, Snippet)>,
3885 most_recent_edit: clock::Lamport,
3886 },
3887 WorkspaceEditApplied(ProjectTransaction),
3888}
3889
3890#[derive(Clone, Debug, Serialize)]
3891pub struct LanguageServerStatus {
3892 pub name: LanguageServerName,
3893 pub server_version: Option<SharedString>,
3894 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3895 pub has_pending_diagnostic_updates: bool,
3896 pub progress_tokens: HashSet<ProgressToken>,
3897 pub worktree: Option<WorktreeId>,
3898 pub binary: Option<LanguageServerBinary>,
3899 pub configuration: Option<Value>,
3900 pub workspace_folders: BTreeSet<Uri>,
3901}
3902
3903#[derive(Clone, Debug)]
3904struct CoreSymbol {
3905 pub language_server_name: LanguageServerName,
3906 pub source_worktree_id: WorktreeId,
3907 pub source_language_server_id: LanguageServerId,
3908 pub path: SymbolLocation,
3909 pub name: String,
3910 pub kind: lsp::SymbolKind,
3911 pub range: Range<Unclipped<PointUtf16>>,
3912}
3913
3914#[derive(Clone, Debug, PartialEq, Eq)]
3915pub enum SymbolLocation {
3916 InProject(ProjectPath),
3917 OutsideProject {
3918 abs_path: Arc<Path>,
3919 signature: [u8; 32],
3920 },
3921}
3922
3923impl SymbolLocation {
3924 fn file_name(&self) -> Option<&str> {
3925 match self {
3926 Self::InProject(path) => path.path.file_name(),
3927 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3928 }
3929 }
3930}
3931
3932impl LspStore {
3933 pub fn init(client: &AnyProtoClient) {
3934 client.add_entity_request_handler(Self::handle_lsp_query);
3935 client.add_entity_message_handler(Self::handle_lsp_query_response);
3936 client.add_entity_request_handler(Self::handle_restart_language_servers);
3937 client.add_entity_request_handler(Self::handle_stop_language_servers);
3938 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3939 client.add_entity_message_handler(Self::handle_start_language_server);
3940 client.add_entity_message_handler(Self::handle_update_language_server);
3941 client.add_entity_message_handler(Self::handle_language_server_log);
3942 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3943 client.add_entity_request_handler(Self::handle_format_buffers);
3944 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3945 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3946 client.add_entity_request_handler(Self::handle_apply_code_action);
3947 client.add_entity_request_handler(Self::handle_get_project_symbols);
3948 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3949 client.add_entity_request_handler(Self::handle_get_color_presentation);
3950 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3951 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3952 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3953 client.add_entity_request_handler(Self::handle_on_type_formatting);
3954 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3955 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3956 client.add_entity_request_handler(Self::handle_rename_project_entry);
3957 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3958 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3959 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3960 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3961 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3962 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3963 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3964
3965 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3966 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3967 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3968 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3969 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3970 client.add_entity_request_handler(
3971 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3972 );
3973 client.add_entity_request_handler(
3974 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3975 );
3976 client.add_entity_request_handler(
3977 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3978 );
3979 }
3980
3981 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3982 match &self.mode {
3983 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3984 _ => None,
3985 }
3986 }
3987
3988 pub fn as_local(&self) -> Option<&LocalLspStore> {
3989 match &self.mode {
3990 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3991 _ => None,
3992 }
3993 }
3994
3995 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3996 match &mut self.mode {
3997 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3998 _ => None,
3999 }
4000 }
4001
4002 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4003 match &self.mode {
4004 LspStoreMode::Remote(RemoteLspStore {
4005 upstream_client: Some(upstream_client),
4006 upstream_project_id,
4007 ..
4008 }) => Some((upstream_client.clone(), *upstream_project_id)),
4009
4010 LspStoreMode::Remote(RemoteLspStore {
4011 upstream_client: None,
4012 ..
4013 }) => None,
4014 LspStoreMode::Local(_) => None,
4015 }
4016 }
4017
4018 pub fn new_local(
4019 buffer_store: Entity<BufferStore>,
4020 worktree_store: Entity<WorktreeStore>,
4021 prettier_store: Entity<PrettierStore>,
4022 toolchain_store: Entity<LocalToolchainStore>,
4023 environment: Entity<ProjectEnvironment>,
4024 manifest_tree: Entity<ManifestTree>,
4025 languages: Arc<LanguageRegistry>,
4026 http_client: Arc<dyn HttpClient>,
4027 fs: Arc<dyn Fs>,
4028 cx: &mut Context<Self>,
4029 ) -> Self {
4030 let yarn = YarnPathStore::new(fs.clone(), cx);
4031 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4032 .detach();
4033 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4034 .detach();
4035 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4036 .detach();
4037 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4038 .detach();
4039 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4040 .detach();
4041 subscribe_to_binary_statuses(&languages, cx).detach();
4042
4043 let _maintain_workspace_config = {
4044 let (sender, receiver) = watch::channel();
4045 (Self::maintain_workspace_config(receiver, cx), sender)
4046 };
4047
4048 Self {
4049 mode: LspStoreMode::Local(LocalLspStore {
4050 weak: cx.weak_entity(),
4051 worktree_store: worktree_store.clone(),
4052
4053 supplementary_language_servers: Default::default(),
4054 languages: languages.clone(),
4055 language_server_ids: Default::default(),
4056 language_servers: Default::default(),
4057 last_workspace_edits_by_language_server: Default::default(),
4058 language_server_watched_paths: Default::default(),
4059 language_server_paths_watched_for_rename: Default::default(),
4060 language_server_dynamic_registrations: Default::default(),
4061 buffers_being_formatted: Default::default(),
4062 buffer_snapshots: Default::default(),
4063 prettier_store,
4064 environment,
4065 http_client,
4066 fs,
4067 yarn,
4068 next_diagnostic_group_id: Default::default(),
4069 diagnostics: Default::default(),
4070 _subscription: cx.on_app_quit(|this, cx| {
4071 this.as_local_mut()
4072 .unwrap()
4073 .shutdown_language_servers_on_quit(cx)
4074 }),
4075 lsp_tree: LanguageServerTree::new(
4076 manifest_tree,
4077 languages.clone(),
4078 toolchain_store.clone(),
4079 ),
4080 toolchain_store,
4081 registered_buffers: HashMap::default(),
4082 buffers_opened_in_servers: HashMap::default(),
4083 buffer_pull_diagnostics_result_ids: HashMap::default(),
4084 workspace_pull_diagnostics_result_ids: HashMap::default(),
4085 restricted_worktrees_tasks: HashMap::default(),
4086 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4087 .manifest_file_names(),
4088 }),
4089 last_formatting_failure: None,
4090 downstream_client: None,
4091 buffer_store,
4092 worktree_store,
4093 languages: languages.clone(),
4094 language_server_statuses: Default::default(),
4095 nonce: StdRng::from_os_rng().random(),
4096 diagnostic_summaries: HashMap::default(),
4097 lsp_server_capabilities: HashMap::default(),
4098 lsp_data: HashMap::default(),
4099 next_hint_id: Arc::default(),
4100 active_entry: None,
4101 _maintain_workspace_config,
4102 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4103 }
4104 }
4105
4106 fn send_lsp_proto_request<R: LspCommand>(
4107 &self,
4108 buffer: Entity<Buffer>,
4109 client: AnyProtoClient,
4110 upstream_project_id: u64,
4111 request: R,
4112 cx: &mut Context<LspStore>,
4113 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4114 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4115 return Task::ready(Ok(R::Response::default()));
4116 }
4117 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4118 cx.spawn(async move |this, cx| {
4119 let response = client.request(message).await?;
4120 let this = this.upgrade().context("project dropped")?;
4121 request
4122 .response_from_proto(response, this, buffer, cx.clone())
4123 .await
4124 })
4125 }
4126
4127 pub(super) fn new_remote(
4128 buffer_store: Entity<BufferStore>,
4129 worktree_store: Entity<WorktreeStore>,
4130 languages: Arc<LanguageRegistry>,
4131 upstream_client: AnyProtoClient,
4132 project_id: u64,
4133 cx: &mut Context<Self>,
4134 ) -> Self {
4135 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4136 .detach();
4137 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4138 .detach();
4139 subscribe_to_binary_statuses(&languages, cx).detach();
4140 let _maintain_workspace_config = {
4141 let (sender, receiver) = watch::channel();
4142 (Self::maintain_workspace_config(receiver, cx), sender)
4143 };
4144 Self {
4145 mode: LspStoreMode::Remote(RemoteLspStore {
4146 upstream_client: Some(upstream_client),
4147 upstream_project_id: project_id,
4148 }),
4149 downstream_client: None,
4150 last_formatting_failure: None,
4151 buffer_store,
4152 worktree_store,
4153 languages: languages.clone(),
4154 language_server_statuses: Default::default(),
4155 nonce: StdRng::from_os_rng().random(),
4156 diagnostic_summaries: HashMap::default(),
4157 lsp_server_capabilities: HashMap::default(),
4158 next_hint_id: Arc::default(),
4159 lsp_data: HashMap::default(),
4160 active_entry: None,
4161
4162 _maintain_workspace_config,
4163 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4164 }
4165 }
4166
4167 fn on_buffer_store_event(
4168 &mut self,
4169 _: Entity<BufferStore>,
4170 event: &BufferStoreEvent,
4171 cx: &mut Context<Self>,
4172 ) {
4173 match event {
4174 BufferStoreEvent::BufferAdded(buffer) => {
4175 self.on_buffer_added(buffer, cx).log_err();
4176 }
4177 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4178 let buffer_id = buffer.read(cx).remote_id();
4179 if let Some(local) = self.as_local_mut()
4180 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4181 {
4182 local.reset_buffer(buffer, old_file, cx);
4183
4184 if local.registered_buffers.contains_key(&buffer_id) {
4185 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4186 }
4187 }
4188
4189 self.detect_language_for_buffer(buffer, cx);
4190 if let Some(local) = self.as_local_mut() {
4191 local.initialize_buffer(buffer, cx);
4192 if local.registered_buffers.contains_key(&buffer_id) {
4193 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4194 }
4195 }
4196 }
4197 _ => {}
4198 }
4199 }
4200
4201 fn on_worktree_store_event(
4202 &mut self,
4203 _: Entity<WorktreeStore>,
4204 event: &WorktreeStoreEvent,
4205 cx: &mut Context<Self>,
4206 ) {
4207 match event {
4208 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4209 if !worktree.read(cx).is_local() {
4210 return;
4211 }
4212 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4213 worktree::Event::UpdatedEntries(changes) => {
4214 this.update_local_worktree_language_servers(&worktree, changes, cx);
4215 }
4216 worktree::Event::UpdatedGitRepositories(_)
4217 | worktree::Event::DeletedEntry(_) => {}
4218 })
4219 .detach()
4220 }
4221 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4222 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4223 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4224 }
4225 WorktreeStoreEvent::WorktreeReleased(..)
4226 | WorktreeStoreEvent::WorktreeOrderChanged
4227 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4228 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4229 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4230 }
4231 }
4232
4233 fn on_prettier_store_event(
4234 &mut self,
4235 _: Entity<PrettierStore>,
4236 event: &PrettierStoreEvent,
4237 cx: &mut Context<Self>,
4238 ) {
4239 match event {
4240 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4241 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4242 }
4243 PrettierStoreEvent::LanguageServerAdded {
4244 new_server_id,
4245 name,
4246 prettier_server,
4247 } => {
4248 self.register_supplementary_language_server(
4249 *new_server_id,
4250 name.clone(),
4251 prettier_server.clone(),
4252 cx,
4253 );
4254 }
4255 }
4256 }
4257
4258 fn on_toolchain_store_event(
4259 &mut self,
4260 _: Entity<LocalToolchainStore>,
4261 event: &ToolchainStoreEvent,
4262 _: &mut Context<Self>,
4263 ) {
4264 if let ToolchainStoreEvent::ToolchainActivated = event {
4265 self.request_workspace_config_refresh()
4266 }
4267 }
4268
4269 fn request_workspace_config_refresh(&mut self) {
4270 *self._maintain_workspace_config.1.borrow_mut() = ();
4271 }
4272
4273 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4274 self.as_local().map(|local| local.prettier_store.clone())
4275 }
4276
4277 fn on_buffer_event(
4278 &mut self,
4279 buffer: Entity<Buffer>,
4280 event: &language::BufferEvent,
4281 cx: &mut Context<Self>,
4282 ) {
4283 match event {
4284 language::BufferEvent::Edited => {
4285 self.on_buffer_edited(buffer, cx);
4286 }
4287
4288 language::BufferEvent::Saved => {
4289 self.on_buffer_saved(buffer, cx);
4290 }
4291
4292 _ => {}
4293 }
4294 }
4295
4296 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4297 buffer
4298 .read(cx)
4299 .set_language_registry(self.languages.clone());
4300
4301 cx.subscribe(buffer, |this, buffer, event, cx| {
4302 this.on_buffer_event(buffer, event, cx);
4303 })
4304 .detach();
4305
4306 self.detect_language_for_buffer(buffer, cx);
4307 if let Some(local) = self.as_local_mut() {
4308 local.initialize_buffer(buffer, cx);
4309 }
4310
4311 Ok(())
4312 }
4313
4314 pub(crate) fn register_buffer_with_language_servers(
4315 &mut self,
4316 buffer: &Entity<Buffer>,
4317 only_register_servers: HashSet<LanguageServerSelector>,
4318 ignore_refcounts: bool,
4319 cx: &mut Context<Self>,
4320 ) -> OpenLspBufferHandle {
4321 let buffer_id = buffer.read(cx).remote_id();
4322 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4323 if let Some(local) = self.as_local_mut() {
4324 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4325 if !ignore_refcounts {
4326 *refcount += 1;
4327 }
4328
4329 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4330 // 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
4331 // 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
4332 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4333 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4334 return handle;
4335 };
4336 if !file.is_local() {
4337 return handle;
4338 }
4339
4340 if ignore_refcounts || *refcount == 1 {
4341 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4342 }
4343 if !ignore_refcounts {
4344 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4345 let refcount = {
4346 let local = lsp_store.as_local_mut().unwrap();
4347 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4348 debug_panic!("bad refcounting");
4349 return;
4350 };
4351
4352 *refcount -= 1;
4353 *refcount
4354 };
4355 if refcount == 0 {
4356 lsp_store.lsp_data.remove(&buffer_id);
4357 let local = lsp_store.as_local_mut().unwrap();
4358 local.registered_buffers.remove(&buffer_id);
4359
4360 local.buffers_opened_in_servers.remove(&buffer_id);
4361 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4362 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4363
4364 let buffer_abs_path = file.abs_path(cx);
4365 for (_, buffer_pull_diagnostics_result_ids) in
4366 &mut local.buffer_pull_diagnostics_result_ids
4367 {
4368 buffer_pull_diagnostics_result_ids.retain(
4369 |_, buffer_result_ids| {
4370 buffer_result_ids.remove(&buffer_abs_path);
4371 !buffer_result_ids.is_empty()
4372 },
4373 );
4374 }
4375
4376 let diagnostic_updates = local
4377 .language_servers
4378 .keys()
4379 .cloned()
4380 .map(|server_id| DocumentDiagnosticsUpdate {
4381 diagnostics: DocumentDiagnostics {
4382 document_abs_path: buffer_abs_path.clone(),
4383 version: None,
4384 diagnostics: Vec::new(),
4385 },
4386 result_id: None,
4387 registration_id: None,
4388 server_id: server_id,
4389 disk_based_sources: Cow::Borrowed(&[]),
4390 })
4391 .collect::<Vec<_>>();
4392
4393 lsp_store
4394 .merge_diagnostic_entries(
4395 diagnostic_updates,
4396 |_, diagnostic, _| {
4397 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4398 },
4399 cx,
4400 )
4401 .context("Clearing diagnostics for the closed buffer")
4402 .log_err();
4403 }
4404 }
4405 })
4406 .detach();
4407 }
4408 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4409 let buffer_id = buffer.read(cx).remote_id().to_proto();
4410 cx.background_spawn(async move {
4411 upstream_client
4412 .request(proto::RegisterBufferWithLanguageServers {
4413 project_id: upstream_project_id,
4414 buffer_id,
4415 only_servers: only_register_servers
4416 .into_iter()
4417 .map(|selector| {
4418 let selector = match selector {
4419 LanguageServerSelector::Id(language_server_id) => {
4420 proto::language_server_selector::Selector::ServerId(
4421 language_server_id.to_proto(),
4422 )
4423 }
4424 LanguageServerSelector::Name(language_server_name) => {
4425 proto::language_server_selector::Selector::Name(
4426 language_server_name.to_string(),
4427 )
4428 }
4429 };
4430 proto::LanguageServerSelector {
4431 selector: Some(selector),
4432 }
4433 })
4434 .collect(),
4435 })
4436 .await
4437 })
4438 .detach();
4439 } else {
4440 // Our remote connection got closed
4441 }
4442 handle
4443 }
4444
4445 fn maintain_buffer_languages(
4446 languages: Arc<LanguageRegistry>,
4447 cx: &mut Context<Self>,
4448 ) -> Task<()> {
4449 let mut subscription = languages.subscribe();
4450 let mut prev_reload_count = languages.reload_count();
4451 cx.spawn(async move |this, cx| {
4452 while let Some(()) = subscription.next().await {
4453 if let Some(this) = this.upgrade() {
4454 // If the language registry has been reloaded, then remove and
4455 // re-assign the languages on all open buffers.
4456 let reload_count = languages.reload_count();
4457 if reload_count > prev_reload_count {
4458 prev_reload_count = reload_count;
4459 this.update(cx, |this, cx| {
4460 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4461 for buffer in buffer_store.buffers() {
4462 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4463 {
4464 buffer.update(cx, |buffer, cx| {
4465 buffer.set_language_async(None, cx)
4466 });
4467 if let Some(local) = this.as_local_mut() {
4468 local.reset_buffer(&buffer, &f, cx);
4469
4470 if local
4471 .registered_buffers
4472 .contains_key(&buffer.read(cx).remote_id())
4473 && let Some(file_url) =
4474 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4475 {
4476 local.unregister_buffer_from_language_servers(
4477 &buffer, &file_url, cx,
4478 );
4479 }
4480 }
4481 }
4482 }
4483 });
4484 })
4485 .ok();
4486 }
4487
4488 this.update(cx, |this, cx| {
4489 let mut plain_text_buffers = Vec::new();
4490 let mut buffers_with_unknown_injections = Vec::new();
4491 for handle in this.buffer_store.read(cx).buffers() {
4492 let buffer = handle.read(cx);
4493 if buffer.language().is_none()
4494 || buffer.language() == Some(&*language::PLAIN_TEXT)
4495 {
4496 plain_text_buffers.push(handle);
4497 } else if buffer.contains_unknown_injections() {
4498 buffers_with_unknown_injections.push(handle);
4499 }
4500 }
4501
4502 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4503 // and reused later in the invisible worktrees.
4504 plain_text_buffers.sort_by_key(|buffer| {
4505 Reverse(
4506 File::from_dyn(buffer.read(cx).file())
4507 .map(|file| file.worktree.read(cx).is_visible()),
4508 )
4509 });
4510
4511 for buffer in plain_text_buffers {
4512 this.detect_language_for_buffer(&buffer, cx);
4513 if let Some(local) = this.as_local_mut() {
4514 local.initialize_buffer(&buffer, cx);
4515 if local
4516 .registered_buffers
4517 .contains_key(&buffer.read(cx).remote_id())
4518 {
4519 local.register_buffer_with_language_servers(
4520 &buffer,
4521 HashSet::default(),
4522 cx,
4523 );
4524 }
4525 }
4526 }
4527
4528 for buffer in buffers_with_unknown_injections {
4529 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4530 }
4531 })
4532 .ok();
4533 }
4534 }
4535 })
4536 }
4537
4538 fn detect_language_for_buffer(
4539 &mut self,
4540 buffer_handle: &Entity<Buffer>,
4541 cx: &mut Context<Self>,
4542 ) -> Option<language::AvailableLanguage> {
4543 // If the buffer has a language, set it and start the language server if we haven't already.
4544 let buffer = buffer_handle.read(cx);
4545 let file = buffer.file()?;
4546
4547 let content = buffer.as_rope();
4548 let available_language = self.languages.language_for_file(file, Some(content), cx);
4549 if let Some(available_language) = &available_language {
4550 if let Some(Ok(Ok(new_language))) = self
4551 .languages
4552 .load_language(available_language)
4553 .now_or_never()
4554 {
4555 self.set_language_for_buffer(buffer_handle, new_language, cx);
4556 }
4557 } else {
4558 cx.emit(LspStoreEvent::LanguageDetected {
4559 buffer: buffer_handle.clone(),
4560 new_language: None,
4561 });
4562 }
4563
4564 available_language
4565 }
4566
4567 pub(crate) fn set_language_for_buffer(
4568 &mut self,
4569 buffer_entity: &Entity<Buffer>,
4570 new_language: Arc<Language>,
4571 cx: &mut Context<Self>,
4572 ) {
4573 let buffer = buffer_entity.read(cx);
4574 let buffer_file = buffer.file().cloned();
4575 let buffer_id = buffer.remote_id();
4576 if let Some(local_store) = self.as_local_mut()
4577 && local_store.registered_buffers.contains_key(&buffer_id)
4578 && let Some(abs_path) =
4579 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4580 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4581 {
4582 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4583 }
4584 buffer_entity.update(cx, |buffer, cx| {
4585 if buffer
4586 .language()
4587 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4588 {
4589 buffer.set_language_async(Some(new_language.clone()), cx);
4590 }
4591 });
4592
4593 let settings =
4594 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4595 let buffer_file = File::from_dyn(buffer_file.as_ref());
4596
4597 let worktree_id = if let Some(file) = buffer_file {
4598 let worktree = file.worktree.clone();
4599
4600 if let Some(local) = self.as_local_mut()
4601 && local.registered_buffers.contains_key(&buffer_id)
4602 {
4603 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4604 }
4605 Some(worktree.read(cx).id())
4606 } else {
4607 None
4608 };
4609
4610 if settings.prettier.allowed
4611 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4612 {
4613 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4614 if let Some(prettier_store) = prettier_store {
4615 prettier_store.update(cx, |prettier_store, cx| {
4616 prettier_store.install_default_prettier(
4617 worktree_id,
4618 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4619 cx,
4620 )
4621 })
4622 }
4623 }
4624
4625 cx.emit(LspStoreEvent::LanguageDetected {
4626 buffer: buffer_entity.clone(),
4627 new_language: Some(new_language),
4628 })
4629 }
4630
4631 pub fn buffer_store(&self) -> Entity<BufferStore> {
4632 self.buffer_store.clone()
4633 }
4634
4635 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4636 self.active_entry = active_entry;
4637 }
4638
4639 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4640 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4641 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4642 {
4643 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4644 summaries
4645 .iter()
4646 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4647 });
4648 if let Some(summary) = summaries.next() {
4649 client
4650 .send(proto::UpdateDiagnosticSummary {
4651 project_id: downstream_project_id,
4652 worktree_id: worktree.id().to_proto(),
4653 summary: Some(summary),
4654 more_summaries: summaries.collect(),
4655 })
4656 .log_err();
4657 }
4658 }
4659 }
4660
4661 fn is_capable_for_proto_request<R>(
4662 &self,
4663 buffer: &Entity<Buffer>,
4664 request: &R,
4665 cx: &App,
4666 ) -> bool
4667 where
4668 R: LspCommand,
4669 {
4670 self.check_if_capable_for_proto_request(
4671 buffer,
4672 |capabilities| {
4673 request.check_capabilities(AdapterServerCapabilities {
4674 server_capabilities: capabilities.clone(),
4675 code_action_kinds: None,
4676 })
4677 },
4678 cx,
4679 )
4680 }
4681
4682 fn check_if_capable_for_proto_request<F>(
4683 &self,
4684 buffer: &Entity<Buffer>,
4685 check: F,
4686 cx: &App,
4687 ) -> bool
4688 where
4689 F: FnMut(&lsp::ServerCapabilities) -> bool,
4690 {
4691 let Some(language) = buffer.read(cx).language().cloned() else {
4692 return false;
4693 };
4694 let registered_language_servers = self
4695 .languages
4696 .lsp_adapters(&language.name())
4697 .into_iter()
4698 .map(|lsp_adapter| lsp_adapter.name())
4699 .collect::<HashSet<_>>();
4700 self.language_server_statuses
4701 .iter()
4702 .filter_map(|(server_id, server_status)| {
4703 // Include servers that are either registered for this language OR
4704 // available to be loaded (for SSH remote mode where adapters like
4705 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4706 // but only loaded on the server side)
4707 let is_relevant = registered_language_servers.contains(&server_status.name)
4708 || self.languages.is_lsp_adapter_available(&server_status.name);
4709 is_relevant.then_some(server_id)
4710 })
4711 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4712 .any(check)
4713 }
4714
4715 fn all_capable_for_proto_request<F>(
4716 &self,
4717 buffer: &Entity<Buffer>,
4718 mut check: F,
4719 cx: &App,
4720 ) -> Vec<lsp::LanguageServerId>
4721 where
4722 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4723 {
4724 let Some(language) = buffer.read(cx).language().cloned() else {
4725 return Vec::default();
4726 };
4727 let registered_language_servers = self
4728 .languages
4729 .lsp_adapters(&language.name())
4730 .into_iter()
4731 .map(|lsp_adapter| lsp_adapter.name())
4732 .collect::<HashSet<_>>();
4733 self.language_server_statuses
4734 .iter()
4735 .filter_map(|(server_id, server_status)| {
4736 // Include servers that are either registered for this language OR
4737 // available to be loaded (for SSH remote mode where adapters like
4738 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4739 // but only loaded on the server side)
4740 let is_relevant = registered_language_servers.contains(&server_status.name)
4741 || self.languages.is_lsp_adapter_available(&server_status.name);
4742 is_relevant.then_some((server_id, &server_status.name))
4743 })
4744 .filter_map(|(server_id, server_name)| {
4745 self.lsp_server_capabilities
4746 .get(server_id)
4747 .map(|c| (server_id, server_name, c))
4748 })
4749 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4750 .map(|(server_id, _, _)| *server_id)
4751 .collect()
4752 }
4753
4754 pub fn request_lsp<R>(
4755 &mut self,
4756 buffer: Entity<Buffer>,
4757 server: LanguageServerToQuery,
4758 request: R,
4759 cx: &mut Context<Self>,
4760 ) -> Task<Result<R::Response>>
4761 where
4762 R: LspCommand,
4763 <R::LspRequest as lsp::request::Request>::Result: Send,
4764 <R::LspRequest as lsp::request::Request>::Params: Send,
4765 {
4766 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4767 return self.send_lsp_proto_request(
4768 buffer,
4769 upstream_client,
4770 upstream_project_id,
4771 request,
4772 cx,
4773 );
4774 }
4775
4776 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4777 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4778 local
4779 .language_servers_for_buffer(buffer, cx)
4780 .find(|(_, server)| {
4781 request.check_capabilities(server.adapter_server_capabilities())
4782 })
4783 .map(|(_, server)| server.clone())
4784 }),
4785 LanguageServerToQuery::Other(id) => self
4786 .language_server_for_local_buffer(buffer, id, cx)
4787 .and_then(|(_, server)| {
4788 request
4789 .check_capabilities(server.adapter_server_capabilities())
4790 .then(|| Arc::clone(server))
4791 }),
4792 }) else {
4793 return Task::ready(Ok(Default::default()));
4794 };
4795
4796 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4797
4798 let Some(file) = file else {
4799 return Task::ready(Ok(Default::default()));
4800 };
4801
4802 let lsp_params = match request.to_lsp_params_or_response(
4803 &file.abs_path(cx),
4804 buffer.read(cx),
4805 &language_server,
4806 cx,
4807 ) {
4808 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4809 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4810 Err(err) => {
4811 let message = format!(
4812 "{} via {} failed: {}",
4813 request.display_name(),
4814 language_server.name(),
4815 err
4816 );
4817 // rust-analyzer likes to error with this when its still loading up
4818 if !message.ends_with("content modified") {
4819 log::warn!("{message}");
4820 }
4821 return Task::ready(Err(anyhow!(message)));
4822 }
4823 };
4824
4825 let status = request.status();
4826 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4827 return Task::ready(Ok(Default::default()));
4828 }
4829 cx.spawn(async move |this, cx| {
4830 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4831
4832 let id = lsp_request.id();
4833 let _cleanup = if status.is_some() {
4834 cx.update(|cx| {
4835 this.update(cx, |this, cx| {
4836 this.on_lsp_work_start(
4837 language_server.server_id(),
4838 ProgressToken::Number(id),
4839 LanguageServerProgress {
4840 is_disk_based_diagnostics_progress: false,
4841 is_cancellable: false,
4842 title: None,
4843 message: status.clone(),
4844 percentage: None,
4845 last_update_at: cx.background_executor().now(),
4846 },
4847 cx,
4848 );
4849 })
4850 })
4851 .log_err();
4852
4853 Some(defer(|| {
4854 cx.update(|cx| {
4855 this.update(cx, |this, cx| {
4856 this.on_lsp_work_end(
4857 language_server.server_id(),
4858 ProgressToken::Number(id),
4859 cx,
4860 );
4861 })
4862 })
4863 .log_err();
4864 }))
4865 } else {
4866 None
4867 };
4868
4869 let result = lsp_request.await.into_response();
4870
4871 let response = result.map_err(|err| {
4872 let message = format!(
4873 "{} via {} failed: {}",
4874 request.display_name(),
4875 language_server.name(),
4876 err
4877 );
4878 // rust-analyzer likes to error with this when its still loading up
4879 if !message.ends_with("content modified") {
4880 log::warn!("{message}");
4881 }
4882 anyhow::anyhow!(message)
4883 })?;
4884
4885 request
4886 .response_from_lsp(
4887 response,
4888 this.upgrade().context("no app context")?,
4889 buffer,
4890 language_server.server_id(),
4891 cx.clone(),
4892 )
4893 .await
4894 })
4895 }
4896
4897 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4898 let mut language_formatters_to_check = Vec::new();
4899 for buffer in self.buffer_store.read(cx).buffers() {
4900 let buffer = buffer.read(cx);
4901 let buffer_file = File::from_dyn(buffer.file());
4902 let buffer_language = buffer.language();
4903 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4904 if buffer_language.is_some() {
4905 language_formatters_to_check.push((
4906 buffer_file.map(|f| f.worktree_id(cx)),
4907 settings.into_owned(),
4908 ));
4909 }
4910 }
4911
4912 self.request_workspace_config_refresh();
4913
4914 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4915 prettier_store.update(cx, |prettier_store, cx| {
4916 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4917 })
4918 }
4919
4920 cx.notify();
4921 }
4922
4923 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4924 let buffer_store = self.buffer_store.clone();
4925 let Some(local) = self.as_local_mut() else {
4926 return;
4927 };
4928 let mut adapters = BTreeMap::default();
4929 let get_adapter = {
4930 let languages = local.languages.clone();
4931 let environment = local.environment.clone();
4932 let weak = local.weak.clone();
4933 let worktree_store = local.worktree_store.clone();
4934 let http_client = local.http_client.clone();
4935 let fs = local.fs.clone();
4936 move |worktree_id, cx: &mut App| {
4937 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4938 Some(LocalLspAdapterDelegate::new(
4939 languages.clone(),
4940 &environment,
4941 weak.clone(),
4942 &worktree,
4943 http_client.clone(),
4944 fs.clone(),
4945 cx,
4946 ))
4947 }
4948 };
4949
4950 let mut messages_to_report = Vec::new();
4951 let (new_tree, to_stop) = {
4952 let mut rebase = local.lsp_tree.rebase();
4953 let buffers = buffer_store
4954 .read(cx)
4955 .buffers()
4956 .filter_map(|buffer| {
4957 let raw_buffer = buffer.read(cx);
4958 if !local
4959 .registered_buffers
4960 .contains_key(&raw_buffer.remote_id())
4961 {
4962 return None;
4963 }
4964 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4965 let language = raw_buffer.language().cloned()?;
4966 Some((file, language, raw_buffer.remote_id()))
4967 })
4968 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4969 for (file, language, buffer_id) in buffers {
4970 let worktree_id = file.worktree_id(cx);
4971 let Some(worktree) = local
4972 .worktree_store
4973 .read(cx)
4974 .worktree_for_id(worktree_id, cx)
4975 else {
4976 continue;
4977 };
4978
4979 if let Some((_, apply)) = local.reuse_existing_language_server(
4980 rebase.server_tree(),
4981 &worktree,
4982 &language.name(),
4983 cx,
4984 ) {
4985 (apply)(rebase.server_tree());
4986 } else if let Some(lsp_delegate) = adapters
4987 .entry(worktree_id)
4988 .or_insert_with(|| get_adapter(worktree_id, cx))
4989 .clone()
4990 {
4991 let delegate =
4992 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4993 let path = file
4994 .path()
4995 .parent()
4996 .map(Arc::from)
4997 .unwrap_or_else(|| file.path().clone());
4998 let worktree_path = ProjectPath { worktree_id, path };
4999 let abs_path = file.abs_path(cx);
5000 let nodes = rebase
5001 .walk(
5002 worktree_path,
5003 language.name(),
5004 language.manifest(),
5005 delegate.clone(),
5006 cx,
5007 )
5008 .collect::<Vec<_>>();
5009 for node in nodes {
5010 let server_id = node.server_id_or_init(|disposition| {
5011 let path = &disposition.path;
5012 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5013 let key = LanguageServerSeed {
5014 worktree_id,
5015 name: disposition.server_name.clone(),
5016 settings: disposition.settings.clone(),
5017 toolchain: local.toolchain_store.read(cx).active_toolchain(
5018 path.worktree_id,
5019 &path.path,
5020 language.name(),
5021 ),
5022 };
5023 local.language_server_ids.remove(&key);
5024
5025 let server_id = local.get_or_insert_language_server(
5026 &worktree,
5027 lsp_delegate.clone(),
5028 disposition,
5029 &language.name(),
5030 cx,
5031 );
5032 if let Some(state) = local.language_servers.get(&server_id)
5033 && let Ok(uri) = uri
5034 {
5035 state.add_workspace_folder(uri);
5036 };
5037 server_id
5038 });
5039
5040 if let Some(language_server_id) = server_id {
5041 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5042 language_server_id,
5043 name: node.name(),
5044 message:
5045 proto::update_language_server::Variant::RegisteredForBuffer(
5046 proto::RegisteredForBuffer {
5047 buffer_abs_path: abs_path
5048 .to_string_lossy()
5049 .into_owned(),
5050 buffer_id: buffer_id.to_proto(),
5051 },
5052 ),
5053 });
5054 }
5055 }
5056 } else {
5057 continue;
5058 }
5059 }
5060 rebase.finish()
5061 };
5062 for message in messages_to_report {
5063 cx.emit(message);
5064 }
5065 local.lsp_tree = new_tree;
5066 for (id, _) in to_stop {
5067 self.stop_local_language_server(id, cx).detach();
5068 }
5069 }
5070
5071 pub fn apply_code_action(
5072 &self,
5073 buffer_handle: Entity<Buffer>,
5074 mut action: CodeAction,
5075 push_to_history: bool,
5076 cx: &mut Context<Self>,
5077 ) -> Task<Result<ProjectTransaction>> {
5078 if let Some((upstream_client, project_id)) = self.upstream_client() {
5079 let request = proto::ApplyCodeAction {
5080 project_id,
5081 buffer_id: buffer_handle.read(cx).remote_id().into(),
5082 action: Some(Self::serialize_code_action(&action)),
5083 };
5084 let buffer_store = self.buffer_store();
5085 cx.spawn(async move |_, cx| {
5086 let response = upstream_client
5087 .request(request)
5088 .await?
5089 .transaction
5090 .context("missing transaction")?;
5091
5092 buffer_store
5093 .update(cx, |buffer_store, cx| {
5094 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5095 })?
5096 .await
5097 })
5098 } else if self.mode.is_local() {
5099 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5100 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5101 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5102 }) else {
5103 return Task::ready(Ok(ProjectTransaction::default()));
5104 };
5105 cx.spawn(async move |this, cx| {
5106 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5107 .await
5108 .context("resolving a code action")?;
5109 if let Some(edit) = action.lsp_action.edit()
5110 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5111 return LocalLspStore::deserialize_workspace_edit(
5112 this.upgrade().context("no app present")?,
5113 edit.clone(),
5114 push_to_history,
5115
5116 lang_server.clone(),
5117 cx,
5118 )
5119 .await;
5120 }
5121
5122 if let Some(command) = action.lsp_action.command() {
5123 let server_capabilities = lang_server.capabilities();
5124 let available_commands = server_capabilities
5125 .execute_command_provider
5126 .as_ref()
5127 .map(|options| options.commands.as_slice())
5128 .unwrap_or_default();
5129 if available_commands.contains(&command.command) {
5130 this.update(cx, |this, _| {
5131 this.as_local_mut()
5132 .unwrap()
5133 .last_workspace_edits_by_language_server
5134 .remove(&lang_server.server_id());
5135 })?;
5136
5137 let _result = lang_server
5138 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5139 command: command.command.clone(),
5140 arguments: command.arguments.clone().unwrap_or_default(),
5141 ..lsp::ExecuteCommandParams::default()
5142 })
5143 .await.into_response()
5144 .context("execute command")?;
5145
5146 return this.update(cx, |this, _| {
5147 this.as_local_mut()
5148 .unwrap()
5149 .last_workspace_edits_by_language_server
5150 .remove(&lang_server.server_id())
5151 .unwrap_or_default()
5152 });
5153 } else {
5154 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5155 }
5156 }
5157
5158 Ok(ProjectTransaction::default())
5159 })
5160 } else {
5161 Task::ready(Err(anyhow!("no upstream client and not local")))
5162 }
5163 }
5164
5165 pub fn apply_code_action_kind(
5166 &mut self,
5167 buffers: HashSet<Entity<Buffer>>,
5168 kind: CodeActionKind,
5169 push_to_history: bool,
5170 cx: &mut Context<Self>,
5171 ) -> Task<anyhow::Result<ProjectTransaction>> {
5172 if self.as_local().is_some() {
5173 cx.spawn(async move |lsp_store, cx| {
5174 let buffers = buffers.into_iter().collect::<Vec<_>>();
5175 let result = LocalLspStore::execute_code_action_kind_locally(
5176 lsp_store.clone(),
5177 buffers,
5178 kind,
5179 push_to_history,
5180 cx,
5181 )
5182 .await;
5183 lsp_store.update(cx, |lsp_store, _| {
5184 lsp_store.update_last_formatting_failure(&result);
5185 })?;
5186 result
5187 })
5188 } else if let Some((client, project_id)) = self.upstream_client() {
5189 let buffer_store = self.buffer_store();
5190 cx.spawn(async move |lsp_store, cx| {
5191 let result = client
5192 .request(proto::ApplyCodeActionKind {
5193 project_id,
5194 kind: kind.as_str().to_owned(),
5195 buffer_ids: buffers
5196 .iter()
5197 .map(|buffer| {
5198 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5199 })
5200 .collect::<Result<_>>()?,
5201 })
5202 .await
5203 .and_then(|result| result.transaction.context("missing transaction"));
5204 lsp_store.update(cx, |lsp_store, _| {
5205 lsp_store.update_last_formatting_failure(&result);
5206 })?;
5207
5208 let transaction_response = result?;
5209 buffer_store
5210 .update(cx, |buffer_store, cx| {
5211 buffer_store.deserialize_project_transaction(
5212 transaction_response,
5213 push_to_history,
5214 cx,
5215 )
5216 })?
5217 .await
5218 })
5219 } else {
5220 Task::ready(Ok(ProjectTransaction::default()))
5221 }
5222 }
5223
5224 pub fn resolved_hint(
5225 &mut self,
5226 buffer_id: BufferId,
5227 id: InlayId,
5228 cx: &mut Context<Self>,
5229 ) -> Option<ResolvedHint> {
5230 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5231
5232 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5233 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5234 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5235 let (server_id, resolve_data) = match &hint.resolve_state {
5236 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5237 ResolveState::Resolving => {
5238 return Some(ResolvedHint::Resolving(
5239 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5240 ));
5241 }
5242 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5243 };
5244
5245 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5246 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5247 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5248 id,
5249 cx.spawn(async move |lsp_store, cx| {
5250 let resolved_hint = resolve_task.await;
5251 lsp_store
5252 .update(cx, |lsp_store, _| {
5253 if let Some(old_inlay_hint) = lsp_store
5254 .lsp_data
5255 .get_mut(&buffer_id)
5256 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5257 {
5258 match resolved_hint {
5259 Ok(resolved_hint) => {
5260 *old_inlay_hint = resolved_hint;
5261 }
5262 Err(e) => {
5263 old_inlay_hint.resolve_state =
5264 ResolveState::CanResolve(server_id, resolve_data);
5265 log::error!("Inlay hint resolve failed: {e:#}");
5266 }
5267 }
5268 }
5269 })
5270 .ok();
5271 })
5272 .shared(),
5273 );
5274 debug_assert!(
5275 previous_task.is_none(),
5276 "Did not change hint's resolve state after spawning its resolve"
5277 );
5278 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5279 None
5280 }
5281
5282 fn resolve_inlay_hint(
5283 &self,
5284 mut hint: InlayHint,
5285 buffer: Entity<Buffer>,
5286 server_id: LanguageServerId,
5287 cx: &mut Context<Self>,
5288 ) -> Task<anyhow::Result<InlayHint>> {
5289 if let Some((upstream_client, project_id)) = self.upstream_client() {
5290 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5291 {
5292 hint.resolve_state = ResolveState::Resolved;
5293 return Task::ready(Ok(hint));
5294 }
5295 let request = proto::ResolveInlayHint {
5296 project_id,
5297 buffer_id: buffer.read(cx).remote_id().into(),
5298 language_server_id: server_id.0 as u64,
5299 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5300 };
5301 cx.background_spawn(async move {
5302 let response = upstream_client
5303 .request(request)
5304 .await
5305 .context("inlay hints proto request")?;
5306 match response.hint {
5307 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5308 .context("inlay hints proto resolve response conversion"),
5309 None => Ok(hint),
5310 }
5311 })
5312 } else {
5313 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5314 self.language_server_for_local_buffer(buffer, server_id, cx)
5315 .map(|(_, server)| server.clone())
5316 }) else {
5317 return Task::ready(Ok(hint));
5318 };
5319 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5320 return Task::ready(Ok(hint));
5321 }
5322 let buffer_snapshot = buffer.read(cx).snapshot();
5323 cx.spawn(async move |_, cx| {
5324 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5325 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5326 );
5327 let resolved_hint = resolve_task
5328 .await
5329 .into_response()
5330 .context("inlay hint resolve LSP request")?;
5331 let resolved_hint = InlayHints::lsp_to_project_hint(
5332 resolved_hint,
5333 &buffer,
5334 server_id,
5335 ResolveState::Resolved,
5336 false,
5337 cx,
5338 )
5339 .await?;
5340 Ok(resolved_hint)
5341 })
5342 }
5343 }
5344
5345 pub fn resolve_color_presentation(
5346 &mut self,
5347 mut color: DocumentColor,
5348 buffer: Entity<Buffer>,
5349 server_id: LanguageServerId,
5350 cx: &mut Context<Self>,
5351 ) -> Task<Result<DocumentColor>> {
5352 if color.resolved {
5353 return Task::ready(Ok(color));
5354 }
5355
5356 if let Some((upstream_client, project_id)) = self.upstream_client() {
5357 let start = color.lsp_range.start;
5358 let end = color.lsp_range.end;
5359 let request = proto::GetColorPresentation {
5360 project_id,
5361 server_id: server_id.to_proto(),
5362 buffer_id: buffer.read(cx).remote_id().into(),
5363 color: Some(proto::ColorInformation {
5364 red: color.color.red,
5365 green: color.color.green,
5366 blue: color.color.blue,
5367 alpha: color.color.alpha,
5368 lsp_range_start: Some(proto::PointUtf16 {
5369 row: start.line,
5370 column: start.character,
5371 }),
5372 lsp_range_end: Some(proto::PointUtf16 {
5373 row: end.line,
5374 column: end.character,
5375 }),
5376 }),
5377 };
5378 cx.background_spawn(async move {
5379 let response = upstream_client
5380 .request(request)
5381 .await
5382 .context("color presentation proto request")?;
5383 color.resolved = true;
5384 color.color_presentations = response
5385 .presentations
5386 .into_iter()
5387 .map(|presentation| ColorPresentation {
5388 label: SharedString::from(presentation.label),
5389 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5390 additional_text_edits: presentation
5391 .additional_text_edits
5392 .into_iter()
5393 .filter_map(deserialize_lsp_edit)
5394 .collect(),
5395 })
5396 .collect();
5397 Ok(color)
5398 })
5399 } else {
5400 let path = match buffer
5401 .update(cx, |buffer, cx| {
5402 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5403 })
5404 .context("buffer with the missing path")
5405 {
5406 Ok(path) => path,
5407 Err(e) => return Task::ready(Err(e)),
5408 };
5409 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5410 self.language_server_for_local_buffer(buffer, server_id, cx)
5411 .map(|(_, server)| server.clone())
5412 }) else {
5413 return Task::ready(Ok(color));
5414 };
5415 cx.background_spawn(async move {
5416 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5417 lsp::ColorPresentationParams {
5418 text_document: make_text_document_identifier(&path)?,
5419 color: color.color,
5420 range: color.lsp_range,
5421 work_done_progress_params: Default::default(),
5422 partial_result_params: Default::default(),
5423 },
5424 );
5425 color.color_presentations = resolve_task
5426 .await
5427 .into_response()
5428 .context("color presentation resolve LSP request")?
5429 .into_iter()
5430 .map(|presentation| ColorPresentation {
5431 label: SharedString::from(presentation.label),
5432 text_edit: presentation.text_edit,
5433 additional_text_edits: presentation
5434 .additional_text_edits
5435 .unwrap_or_default(),
5436 })
5437 .collect();
5438 color.resolved = true;
5439 Ok(color)
5440 })
5441 }
5442 }
5443
5444 pub(crate) fn linked_edits(
5445 &mut self,
5446 buffer: &Entity<Buffer>,
5447 position: Anchor,
5448 cx: &mut Context<Self>,
5449 ) -> Task<Result<Vec<Range<Anchor>>>> {
5450 let snapshot = buffer.read(cx).snapshot();
5451 let scope = snapshot.language_scope_at(position);
5452 let Some(server_id) = self
5453 .as_local()
5454 .and_then(|local| {
5455 buffer.update(cx, |buffer, cx| {
5456 local
5457 .language_servers_for_buffer(buffer, cx)
5458 .filter(|(_, server)| {
5459 LinkedEditingRange::check_server_capabilities(server.capabilities())
5460 })
5461 .filter(|(adapter, _)| {
5462 scope
5463 .as_ref()
5464 .map(|scope| scope.language_allowed(&adapter.name))
5465 .unwrap_or(true)
5466 })
5467 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5468 .next()
5469 })
5470 })
5471 .or_else(|| {
5472 self.upstream_client()
5473 .is_some()
5474 .then_some(LanguageServerToQuery::FirstCapable)
5475 })
5476 .filter(|_| {
5477 maybe!({
5478 let language = buffer.read(cx).language_at(position)?;
5479 Some(
5480 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5481 .linked_edits,
5482 )
5483 }) == Some(true)
5484 })
5485 else {
5486 return Task::ready(Ok(Vec::new()));
5487 };
5488
5489 self.request_lsp(
5490 buffer.clone(),
5491 server_id,
5492 LinkedEditingRange { position },
5493 cx,
5494 )
5495 }
5496
5497 fn apply_on_type_formatting(
5498 &mut self,
5499 buffer: Entity<Buffer>,
5500 position: Anchor,
5501 trigger: String,
5502 cx: &mut Context<Self>,
5503 ) -> Task<Result<Option<Transaction>>> {
5504 if let Some((client, project_id)) = self.upstream_client() {
5505 if !self.check_if_capable_for_proto_request(
5506 &buffer,
5507 |capabilities| {
5508 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5509 },
5510 cx,
5511 ) {
5512 return Task::ready(Ok(None));
5513 }
5514 let request = proto::OnTypeFormatting {
5515 project_id,
5516 buffer_id: buffer.read(cx).remote_id().into(),
5517 position: Some(serialize_anchor(&position)),
5518 trigger,
5519 version: serialize_version(&buffer.read(cx).version()),
5520 };
5521 cx.background_spawn(async move {
5522 client
5523 .request(request)
5524 .await?
5525 .transaction
5526 .map(language::proto::deserialize_transaction)
5527 .transpose()
5528 })
5529 } else if let Some(local) = self.as_local_mut() {
5530 let buffer_id = buffer.read(cx).remote_id();
5531 local.buffers_being_formatted.insert(buffer_id);
5532 cx.spawn(async move |this, cx| {
5533 let _cleanup = defer({
5534 let this = this.clone();
5535 let mut cx = cx.clone();
5536 move || {
5537 this.update(&mut cx, |this, _| {
5538 if let Some(local) = this.as_local_mut() {
5539 local.buffers_being_formatted.remove(&buffer_id);
5540 }
5541 })
5542 .ok();
5543 }
5544 });
5545
5546 buffer
5547 .update(cx, |buffer, _| {
5548 buffer.wait_for_edits(Some(position.timestamp))
5549 })?
5550 .await?;
5551 this.update(cx, |this, cx| {
5552 let position = position.to_point_utf16(buffer.read(cx));
5553 this.on_type_format(buffer, position, trigger, false, cx)
5554 })?
5555 .await
5556 })
5557 } else {
5558 Task::ready(Err(anyhow!("No upstream client or local language server")))
5559 }
5560 }
5561
5562 pub fn on_type_format<T: ToPointUtf16>(
5563 &mut self,
5564 buffer: Entity<Buffer>,
5565 position: T,
5566 trigger: String,
5567 push_to_history: bool,
5568 cx: &mut Context<Self>,
5569 ) -> Task<Result<Option<Transaction>>> {
5570 let position = position.to_point_utf16(buffer.read(cx));
5571 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5572 }
5573
5574 fn on_type_format_impl(
5575 &mut self,
5576 buffer: Entity<Buffer>,
5577 position: PointUtf16,
5578 trigger: String,
5579 push_to_history: bool,
5580 cx: &mut Context<Self>,
5581 ) -> Task<Result<Option<Transaction>>> {
5582 let options = buffer.update(cx, |buffer, cx| {
5583 lsp_command::lsp_formatting_options(
5584 language_settings(
5585 buffer.language_at(position).map(|l| l.name()),
5586 buffer.file(),
5587 cx,
5588 )
5589 .as_ref(),
5590 )
5591 });
5592
5593 cx.spawn(async move |this, cx| {
5594 if let Some(waiter) =
5595 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())?
5596 {
5597 waiter.await?;
5598 }
5599 cx.update(|cx| {
5600 this.update(cx, |this, cx| {
5601 this.request_lsp(
5602 buffer.clone(),
5603 LanguageServerToQuery::FirstCapable,
5604 OnTypeFormatting {
5605 position,
5606 trigger,
5607 options,
5608 push_to_history,
5609 },
5610 cx,
5611 )
5612 })
5613 })??
5614 .await
5615 })
5616 }
5617
5618 pub fn definitions(
5619 &mut self,
5620 buffer: &Entity<Buffer>,
5621 position: PointUtf16,
5622 cx: &mut Context<Self>,
5623 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5624 if let Some((upstream_client, project_id)) = self.upstream_client() {
5625 let request = GetDefinitions { position };
5626 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5627 return Task::ready(Ok(None));
5628 }
5629 let request_task = upstream_client.request_lsp(
5630 project_id,
5631 None,
5632 LSP_REQUEST_TIMEOUT,
5633 cx.background_executor().clone(),
5634 request.to_proto(project_id, buffer.read(cx)),
5635 );
5636 let buffer = buffer.clone();
5637 cx.spawn(async move |weak_lsp_store, cx| {
5638 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5639 return Ok(None);
5640 };
5641 let Some(responses) = request_task.await? else {
5642 return Ok(None);
5643 };
5644 let actions = join_all(responses.payload.into_iter().map(|response| {
5645 GetDefinitions { position }.response_from_proto(
5646 response.response,
5647 lsp_store.clone(),
5648 buffer.clone(),
5649 cx.clone(),
5650 )
5651 }))
5652 .await;
5653
5654 Ok(Some(
5655 actions
5656 .into_iter()
5657 .collect::<Result<Vec<Vec<_>>>>()?
5658 .into_iter()
5659 .flatten()
5660 .dedup()
5661 .collect(),
5662 ))
5663 })
5664 } else {
5665 let definitions_task = self.request_multiple_lsp_locally(
5666 buffer,
5667 Some(position),
5668 GetDefinitions { position },
5669 cx,
5670 );
5671 cx.background_spawn(async move {
5672 Ok(Some(
5673 definitions_task
5674 .await
5675 .into_iter()
5676 .flat_map(|(_, definitions)| definitions)
5677 .dedup()
5678 .collect(),
5679 ))
5680 })
5681 }
5682 }
5683
5684 pub fn declarations(
5685 &mut self,
5686 buffer: &Entity<Buffer>,
5687 position: PointUtf16,
5688 cx: &mut Context<Self>,
5689 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5690 if let Some((upstream_client, project_id)) = self.upstream_client() {
5691 let request = GetDeclarations { position };
5692 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5693 return Task::ready(Ok(None));
5694 }
5695 let request_task = upstream_client.request_lsp(
5696 project_id,
5697 None,
5698 LSP_REQUEST_TIMEOUT,
5699 cx.background_executor().clone(),
5700 request.to_proto(project_id, buffer.read(cx)),
5701 );
5702 let buffer = buffer.clone();
5703 cx.spawn(async move |weak_lsp_store, cx| {
5704 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5705 return Ok(None);
5706 };
5707 let Some(responses) = request_task.await? else {
5708 return Ok(None);
5709 };
5710 let actions = join_all(responses.payload.into_iter().map(|response| {
5711 GetDeclarations { position }.response_from_proto(
5712 response.response,
5713 lsp_store.clone(),
5714 buffer.clone(),
5715 cx.clone(),
5716 )
5717 }))
5718 .await;
5719
5720 Ok(Some(
5721 actions
5722 .into_iter()
5723 .collect::<Result<Vec<Vec<_>>>>()?
5724 .into_iter()
5725 .flatten()
5726 .dedup()
5727 .collect(),
5728 ))
5729 })
5730 } else {
5731 let declarations_task = self.request_multiple_lsp_locally(
5732 buffer,
5733 Some(position),
5734 GetDeclarations { position },
5735 cx,
5736 );
5737 cx.background_spawn(async move {
5738 Ok(Some(
5739 declarations_task
5740 .await
5741 .into_iter()
5742 .flat_map(|(_, declarations)| declarations)
5743 .dedup()
5744 .collect(),
5745 ))
5746 })
5747 }
5748 }
5749
5750 pub fn type_definitions(
5751 &mut self,
5752 buffer: &Entity<Buffer>,
5753 position: PointUtf16,
5754 cx: &mut Context<Self>,
5755 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5756 if let Some((upstream_client, project_id)) = self.upstream_client() {
5757 let request = GetTypeDefinitions { position };
5758 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5759 return Task::ready(Ok(None));
5760 }
5761 let request_task = upstream_client.request_lsp(
5762 project_id,
5763 None,
5764 LSP_REQUEST_TIMEOUT,
5765 cx.background_executor().clone(),
5766 request.to_proto(project_id, buffer.read(cx)),
5767 );
5768 let buffer = buffer.clone();
5769 cx.spawn(async move |weak_lsp_store, cx| {
5770 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5771 return Ok(None);
5772 };
5773 let Some(responses) = request_task.await? else {
5774 return Ok(None);
5775 };
5776 let actions = join_all(responses.payload.into_iter().map(|response| {
5777 GetTypeDefinitions { position }.response_from_proto(
5778 response.response,
5779 lsp_store.clone(),
5780 buffer.clone(),
5781 cx.clone(),
5782 )
5783 }))
5784 .await;
5785
5786 Ok(Some(
5787 actions
5788 .into_iter()
5789 .collect::<Result<Vec<Vec<_>>>>()?
5790 .into_iter()
5791 .flatten()
5792 .dedup()
5793 .collect(),
5794 ))
5795 })
5796 } else {
5797 let type_definitions_task = self.request_multiple_lsp_locally(
5798 buffer,
5799 Some(position),
5800 GetTypeDefinitions { position },
5801 cx,
5802 );
5803 cx.background_spawn(async move {
5804 Ok(Some(
5805 type_definitions_task
5806 .await
5807 .into_iter()
5808 .flat_map(|(_, type_definitions)| type_definitions)
5809 .dedup()
5810 .collect(),
5811 ))
5812 })
5813 }
5814 }
5815
5816 pub fn implementations(
5817 &mut self,
5818 buffer: &Entity<Buffer>,
5819 position: PointUtf16,
5820 cx: &mut Context<Self>,
5821 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5822 if let Some((upstream_client, project_id)) = self.upstream_client() {
5823 let request = GetImplementations { position };
5824 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5825 return Task::ready(Ok(None));
5826 }
5827 let request_task = upstream_client.request_lsp(
5828 project_id,
5829 None,
5830 LSP_REQUEST_TIMEOUT,
5831 cx.background_executor().clone(),
5832 request.to_proto(project_id, buffer.read(cx)),
5833 );
5834 let buffer = buffer.clone();
5835 cx.spawn(async move |weak_lsp_store, cx| {
5836 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5837 return Ok(None);
5838 };
5839 let Some(responses) = request_task.await? else {
5840 return Ok(None);
5841 };
5842 let actions = join_all(responses.payload.into_iter().map(|response| {
5843 GetImplementations { position }.response_from_proto(
5844 response.response,
5845 lsp_store.clone(),
5846 buffer.clone(),
5847 cx.clone(),
5848 )
5849 }))
5850 .await;
5851
5852 Ok(Some(
5853 actions
5854 .into_iter()
5855 .collect::<Result<Vec<Vec<_>>>>()?
5856 .into_iter()
5857 .flatten()
5858 .dedup()
5859 .collect(),
5860 ))
5861 })
5862 } else {
5863 let implementations_task = self.request_multiple_lsp_locally(
5864 buffer,
5865 Some(position),
5866 GetImplementations { position },
5867 cx,
5868 );
5869 cx.background_spawn(async move {
5870 Ok(Some(
5871 implementations_task
5872 .await
5873 .into_iter()
5874 .flat_map(|(_, implementations)| implementations)
5875 .dedup()
5876 .collect(),
5877 ))
5878 })
5879 }
5880 }
5881
5882 pub fn references(
5883 &mut self,
5884 buffer: &Entity<Buffer>,
5885 position: PointUtf16,
5886 cx: &mut Context<Self>,
5887 ) -> Task<Result<Option<Vec<Location>>>> {
5888 if let Some((upstream_client, project_id)) = self.upstream_client() {
5889 let request = GetReferences { position };
5890 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5891 return Task::ready(Ok(None));
5892 }
5893
5894 let request_task = upstream_client.request_lsp(
5895 project_id,
5896 None,
5897 LSP_REQUEST_TIMEOUT,
5898 cx.background_executor().clone(),
5899 request.to_proto(project_id, buffer.read(cx)),
5900 );
5901 let buffer = buffer.clone();
5902 cx.spawn(async move |weak_lsp_store, cx| {
5903 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5904 return Ok(None);
5905 };
5906 let Some(responses) = request_task.await? else {
5907 return Ok(None);
5908 };
5909
5910 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5911 GetReferences { position }.response_from_proto(
5912 lsp_response.response,
5913 lsp_store.clone(),
5914 buffer.clone(),
5915 cx.clone(),
5916 )
5917 }))
5918 .await
5919 .into_iter()
5920 .collect::<Result<Vec<Vec<_>>>>()?
5921 .into_iter()
5922 .flatten()
5923 .dedup()
5924 .collect();
5925 Ok(Some(locations))
5926 })
5927 } else {
5928 let references_task = self.request_multiple_lsp_locally(
5929 buffer,
5930 Some(position),
5931 GetReferences { position },
5932 cx,
5933 );
5934 cx.background_spawn(async move {
5935 Ok(Some(
5936 references_task
5937 .await
5938 .into_iter()
5939 .flat_map(|(_, references)| references)
5940 .dedup()
5941 .collect(),
5942 ))
5943 })
5944 }
5945 }
5946
5947 pub fn code_actions(
5948 &mut self,
5949 buffer: &Entity<Buffer>,
5950 range: Range<Anchor>,
5951 kinds: Option<Vec<CodeActionKind>>,
5952 cx: &mut Context<Self>,
5953 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5954 if let Some((upstream_client, project_id)) = self.upstream_client() {
5955 let request = GetCodeActions {
5956 range: range.clone(),
5957 kinds: kinds.clone(),
5958 };
5959 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5960 return Task::ready(Ok(None));
5961 }
5962 let request_task = upstream_client.request_lsp(
5963 project_id,
5964 None,
5965 LSP_REQUEST_TIMEOUT,
5966 cx.background_executor().clone(),
5967 request.to_proto(project_id, buffer.read(cx)),
5968 );
5969 let buffer = buffer.clone();
5970 cx.spawn(async move |weak_lsp_store, cx| {
5971 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5972 return Ok(None);
5973 };
5974 let Some(responses) = request_task.await? else {
5975 return Ok(None);
5976 };
5977 let actions = join_all(responses.payload.into_iter().map(|response| {
5978 GetCodeActions {
5979 range: range.clone(),
5980 kinds: kinds.clone(),
5981 }
5982 .response_from_proto(
5983 response.response,
5984 lsp_store.clone(),
5985 buffer.clone(),
5986 cx.clone(),
5987 )
5988 }))
5989 .await;
5990
5991 Ok(Some(
5992 actions
5993 .into_iter()
5994 .collect::<Result<Vec<Vec<_>>>>()?
5995 .into_iter()
5996 .flatten()
5997 .collect(),
5998 ))
5999 })
6000 } else {
6001 let all_actions_task = self.request_multiple_lsp_locally(
6002 buffer,
6003 Some(range.start),
6004 GetCodeActions { range, kinds },
6005 cx,
6006 );
6007 cx.background_spawn(async move {
6008 Ok(Some(
6009 all_actions_task
6010 .await
6011 .into_iter()
6012 .flat_map(|(_, actions)| actions)
6013 .collect(),
6014 ))
6015 })
6016 }
6017 }
6018
6019 pub fn code_lens_actions(
6020 &mut self,
6021 buffer: &Entity<Buffer>,
6022 cx: &mut Context<Self>,
6023 ) -> CodeLensTask {
6024 let version_queried_for = buffer.read(cx).version();
6025 let buffer_id = buffer.read(cx).remote_id();
6026 let existing_servers = self.as_local().map(|local| {
6027 local
6028 .buffers_opened_in_servers
6029 .get(&buffer_id)
6030 .cloned()
6031 .unwrap_or_default()
6032 });
6033
6034 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6035 if let Some(cached_lens) = &lsp_data.code_lens {
6036 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6037 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6038 existing_servers != cached_lens.lens.keys().copied().collect()
6039 });
6040 if !has_different_servers {
6041 return Task::ready(Ok(Some(
6042 cached_lens.lens.values().flatten().cloned().collect(),
6043 )))
6044 .shared();
6045 }
6046 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6047 if !version_queried_for.changed_since(updating_for) {
6048 return running_update.clone();
6049 }
6050 }
6051 }
6052 }
6053
6054 let lens_lsp_data = self
6055 .latest_lsp_data(buffer, cx)
6056 .code_lens
6057 .get_or_insert_default();
6058 let buffer = buffer.clone();
6059 let query_version_queried_for = version_queried_for.clone();
6060 let new_task = cx
6061 .spawn(async move |lsp_store, cx| {
6062 cx.background_executor()
6063 .timer(Duration::from_millis(30))
6064 .await;
6065 let fetched_lens = lsp_store
6066 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6067 .map_err(Arc::new)?
6068 .await
6069 .context("fetching code lens")
6070 .map_err(Arc::new);
6071 let fetched_lens = match fetched_lens {
6072 Ok(fetched_lens) => fetched_lens,
6073 Err(e) => {
6074 lsp_store
6075 .update(cx, |lsp_store, _| {
6076 if let Some(lens_lsp_data) = lsp_store
6077 .lsp_data
6078 .get_mut(&buffer_id)
6079 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6080 {
6081 lens_lsp_data.update = None;
6082 }
6083 })
6084 .ok();
6085 return Err(e);
6086 }
6087 };
6088
6089 lsp_store
6090 .update(cx, |lsp_store, _| {
6091 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6092 let code_lens = lsp_data.code_lens.as_mut()?;
6093 if let Some(fetched_lens) = fetched_lens {
6094 if lsp_data.buffer_version == query_version_queried_for {
6095 code_lens.lens.extend(fetched_lens);
6096 } else if !lsp_data
6097 .buffer_version
6098 .changed_since(&query_version_queried_for)
6099 {
6100 lsp_data.buffer_version = query_version_queried_for;
6101 code_lens.lens = fetched_lens;
6102 }
6103 }
6104 code_lens.update = None;
6105 Some(code_lens.lens.values().flatten().cloned().collect())
6106 })
6107 .map_err(Arc::new)
6108 })
6109 .shared();
6110 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6111 new_task
6112 }
6113
6114 fn fetch_code_lens(
6115 &mut self,
6116 buffer: &Entity<Buffer>,
6117 cx: &mut Context<Self>,
6118 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6119 if let Some((upstream_client, project_id)) = self.upstream_client() {
6120 let request = GetCodeLens;
6121 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6122 return Task::ready(Ok(None));
6123 }
6124 let request_task = upstream_client.request_lsp(
6125 project_id,
6126 None,
6127 LSP_REQUEST_TIMEOUT,
6128 cx.background_executor().clone(),
6129 request.to_proto(project_id, buffer.read(cx)),
6130 );
6131 let buffer = buffer.clone();
6132 cx.spawn(async move |weak_lsp_store, cx| {
6133 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6134 return Ok(None);
6135 };
6136 let Some(responses) = request_task.await? else {
6137 return Ok(None);
6138 };
6139
6140 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6141 let lsp_store = lsp_store.clone();
6142 let buffer = buffer.clone();
6143 let cx = cx.clone();
6144 async move {
6145 (
6146 LanguageServerId::from_proto(response.server_id),
6147 GetCodeLens
6148 .response_from_proto(response.response, lsp_store, buffer, cx)
6149 .await,
6150 )
6151 }
6152 }))
6153 .await;
6154
6155 let mut has_errors = false;
6156 let code_lens_actions = code_lens_actions
6157 .into_iter()
6158 .filter_map(|(server_id, code_lens)| match code_lens {
6159 Ok(code_lens) => Some((server_id, code_lens)),
6160 Err(e) => {
6161 has_errors = true;
6162 log::error!("{e:#}");
6163 None
6164 }
6165 })
6166 .collect::<HashMap<_, _>>();
6167 anyhow::ensure!(
6168 !has_errors || !code_lens_actions.is_empty(),
6169 "Failed to fetch code lens"
6170 );
6171 Ok(Some(code_lens_actions))
6172 })
6173 } else {
6174 let code_lens_actions_task =
6175 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6176 cx.background_spawn(async move {
6177 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6178 })
6179 }
6180 }
6181
6182 #[inline(never)]
6183 pub fn completions(
6184 &self,
6185 buffer: &Entity<Buffer>,
6186 position: PointUtf16,
6187 context: CompletionContext,
6188 cx: &mut Context<Self>,
6189 ) -> Task<Result<Vec<CompletionResponse>>> {
6190 let language_registry = self.languages.clone();
6191
6192 if let Some((upstream_client, project_id)) = self.upstream_client() {
6193 let snapshot = buffer.read(cx).snapshot();
6194 let offset = position.to_offset(&snapshot);
6195 let scope = snapshot.language_scope_at(offset);
6196 let capable_lsps = self.all_capable_for_proto_request(
6197 buffer,
6198 |server_name, capabilities| {
6199 capabilities.completion_provider.is_some()
6200 && scope
6201 .as_ref()
6202 .map(|scope| scope.language_allowed(server_name))
6203 .unwrap_or(true)
6204 },
6205 cx,
6206 );
6207 if capable_lsps.is_empty() {
6208 return Task::ready(Ok(Vec::new()));
6209 }
6210
6211 let language = buffer.read(cx).language().cloned();
6212
6213 // In the future, we should provide project guests with the names of LSP adapters,
6214 // so that they can use the correct LSP adapter when computing labels. For now,
6215 // guests just use the first LSP adapter associated with the buffer's language.
6216 let lsp_adapter = language.as_ref().and_then(|language| {
6217 language_registry
6218 .lsp_adapters(&language.name())
6219 .first()
6220 .cloned()
6221 });
6222
6223 let buffer = buffer.clone();
6224
6225 cx.spawn(async move |this, cx| {
6226 let requests = join_all(
6227 capable_lsps
6228 .into_iter()
6229 .map(|id| {
6230 let request = GetCompletions {
6231 position,
6232 context: context.clone(),
6233 server_id: Some(id),
6234 };
6235 let buffer = buffer.clone();
6236 let language = language.clone();
6237 let lsp_adapter = lsp_adapter.clone();
6238 let upstream_client = upstream_client.clone();
6239 let response = this
6240 .update(cx, |this, cx| {
6241 this.send_lsp_proto_request(
6242 buffer,
6243 upstream_client,
6244 project_id,
6245 request,
6246 cx,
6247 )
6248 })
6249 .log_err();
6250 async move {
6251 let response = response?.await.log_err()?;
6252
6253 let completions = populate_labels_for_completions(
6254 response.completions,
6255 language,
6256 lsp_adapter,
6257 )
6258 .await;
6259
6260 Some(CompletionResponse {
6261 completions,
6262 display_options: CompletionDisplayOptions::default(),
6263 is_incomplete: response.is_incomplete,
6264 })
6265 }
6266 })
6267 .collect::<Vec<_>>(),
6268 );
6269 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6270 })
6271 } else if let Some(local) = self.as_local() {
6272 let snapshot = buffer.read(cx).snapshot();
6273 let offset = position.to_offset(&snapshot);
6274 let scope = snapshot.language_scope_at(offset);
6275 let language = snapshot.language().cloned();
6276 let completion_settings = language_settings(
6277 language.as_ref().map(|language| language.name()),
6278 buffer.read(cx).file(),
6279 cx,
6280 )
6281 .completions
6282 .clone();
6283 if !completion_settings.lsp {
6284 return Task::ready(Ok(Vec::new()));
6285 }
6286
6287 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6288 local
6289 .language_servers_for_buffer(buffer, cx)
6290 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6291 .filter(|(adapter, _)| {
6292 scope
6293 .as_ref()
6294 .map(|scope| scope.language_allowed(&adapter.name))
6295 .unwrap_or(true)
6296 })
6297 .map(|(_, server)| server.server_id())
6298 .collect()
6299 });
6300
6301 let buffer = buffer.clone();
6302 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6303 let lsp_timeout = if lsp_timeout > 0 {
6304 Some(Duration::from_millis(lsp_timeout))
6305 } else {
6306 None
6307 };
6308 cx.spawn(async move |this, cx| {
6309 let mut tasks = Vec::with_capacity(server_ids.len());
6310 this.update(cx, |lsp_store, cx| {
6311 for server_id in server_ids {
6312 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6313 let lsp_timeout = lsp_timeout
6314 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6315 let mut timeout = cx.background_spawn(async move {
6316 match lsp_timeout {
6317 Some(lsp_timeout) => {
6318 lsp_timeout.await;
6319 true
6320 },
6321 None => false,
6322 }
6323 }).fuse();
6324 let mut lsp_request = lsp_store.request_lsp(
6325 buffer.clone(),
6326 LanguageServerToQuery::Other(server_id),
6327 GetCompletions {
6328 position,
6329 context: context.clone(),
6330 server_id: Some(server_id),
6331 },
6332 cx,
6333 ).fuse();
6334 let new_task = cx.background_spawn(async move {
6335 select_biased! {
6336 response = lsp_request => anyhow::Ok(Some(response?)),
6337 timeout_happened = timeout => {
6338 if timeout_happened {
6339 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6340 Ok(None)
6341 } else {
6342 let completions = lsp_request.await?;
6343 Ok(Some(completions))
6344 }
6345 },
6346 }
6347 });
6348 tasks.push((lsp_adapter, new_task));
6349 }
6350 })?;
6351
6352 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6353 let completion_response = task.await.ok()??;
6354 let completions = populate_labels_for_completions(
6355 completion_response.completions,
6356 language.clone(),
6357 lsp_adapter,
6358 )
6359 .await;
6360 Some(CompletionResponse {
6361 completions,
6362 display_options: CompletionDisplayOptions::default(),
6363 is_incomplete: completion_response.is_incomplete,
6364 })
6365 });
6366
6367 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6368
6369 Ok(responses.into_iter().flatten().collect())
6370 })
6371 } else {
6372 Task::ready(Err(anyhow!("No upstream client or local language server")))
6373 }
6374 }
6375
6376 pub fn resolve_completions(
6377 &self,
6378 buffer: Entity<Buffer>,
6379 completion_indices: Vec<usize>,
6380 completions: Rc<RefCell<Box<[Completion]>>>,
6381 cx: &mut Context<Self>,
6382 ) -> Task<Result<bool>> {
6383 let client = self.upstream_client();
6384 let buffer_id = buffer.read(cx).remote_id();
6385 let buffer_snapshot = buffer.read(cx).snapshot();
6386
6387 if !self.check_if_capable_for_proto_request(
6388 &buffer,
6389 GetCompletions::can_resolve_completions,
6390 cx,
6391 ) {
6392 return Task::ready(Ok(false));
6393 }
6394 cx.spawn(async move |lsp_store, cx| {
6395 let mut did_resolve = false;
6396 if let Some((client, project_id)) = client {
6397 for completion_index in completion_indices {
6398 let server_id = {
6399 let completion = &completions.borrow()[completion_index];
6400 completion.source.server_id()
6401 };
6402 if let Some(server_id) = server_id {
6403 if Self::resolve_completion_remote(
6404 project_id,
6405 server_id,
6406 buffer_id,
6407 completions.clone(),
6408 completion_index,
6409 client.clone(),
6410 )
6411 .await
6412 .log_err()
6413 .is_some()
6414 {
6415 did_resolve = true;
6416 }
6417 } else {
6418 resolve_word_completion(
6419 &buffer_snapshot,
6420 &mut completions.borrow_mut()[completion_index],
6421 );
6422 }
6423 }
6424 } else {
6425 for completion_index in completion_indices {
6426 let server_id = {
6427 let completion = &completions.borrow()[completion_index];
6428 completion.source.server_id()
6429 };
6430 if let Some(server_id) = server_id {
6431 let server_and_adapter = lsp_store
6432 .read_with(cx, |lsp_store, _| {
6433 let server = lsp_store.language_server_for_id(server_id)?;
6434 let adapter =
6435 lsp_store.language_server_adapter_for_id(server.server_id())?;
6436 Some((server, adapter))
6437 })
6438 .ok()
6439 .flatten();
6440 let Some((server, adapter)) = server_and_adapter else {
6441 continue;
6442 };
6443
6444 let resolved = Self::resolve_completion_local(
6445 server,
6446 completions.clone(),
6447 completion_index,
6448 )
6449 .await
6450 .log_err()
6451 .is_some();
6452 if resolved {
6453 Self::regenerate_completion_labels(
6454 adapter,
6455 &buffer_snapshot,
6456 completions.clone(),
6457 completion_index,
6458 )
6459 .await
6460 .log_err();
6461 did_resolve = true;
6462 }
6463 } else {
6464 resolve_word_completion(
6465 &buffer_snapshot,
6466 &mut completions.borrow_mut()[completion_index],
6467 );
6468 }
6469 }
6470 }
6471
6472 Ok(did_resolve)
6473 })
6474 }
6475
6476 async fn resolve_completion_local(
6477 server: Arc<lsp::LanguageServer>,
6478 completions: Rc<RefCell<Box<[Completion]>>>,
6479 completion_index: usize,
6480 ) -> Result<()> {
6481 let server_id = server.server_id();
6482 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6483 return Ok(());
6484 }
6485
6486 let request = {
6487 let completion = &completions.borrow()[completion_index];
6488 match &completion.source {
6489 CompletionSource::Lsp {
6490 lsp_completion,
6491 resolved,
6492 server_id: completion_server_id,
6493 ..
6494 } => {
6495 if *resolved {
6496 return Ok(());
6497 }
6498 anyhow::ensure!(
6499 server_id == *completion_server_id,
6500 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6501 );
6502 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6503 }
6504 CompletionSource::BufferWord { .. }
6505 | CompletionSource::Dap { .. }
6506 | CompletionSource::Custom => {
6507 return Ok(());
6508 }
6509 }
6510 };
6511 let resolved_completion = request
6512 .await
6513 .into_response()
6514 .context("resolve completion")?;
6515
6516 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6517 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6518
6519 let mut completions = completions.borrow_mut();
6520 let completion = &mut completions[completion_index];
6521 if let CompletionSource::Lsp {
6522 lsp_completion,
6523 resolved,
6524 server_id: completion_server_id,
6525 ..
6526 } = &mut completion.source
6527 {
6528 if *resolved {
6529 return Ok(());
6530 }
6531 anyhow::ensure!(
6532 server_id == *completion_server_id,
6533 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6534 );
6535 **lsp_completion = resolved_completion;
6536 *resolved = true;
6537 }
6538 Ok(())
6539 }
6540
6541 async fn regenerate_completion_labels(
6542 adapter: Arc<CachedLspAdapter>,
6543 snapshot: &BufferSnapshot,
6544 completions: Rc<RefCell<Box<[Completion]>>>,
6545 completion_index: usize,
6546 ) -> Result<()> {
6547 let completion_item = completions.borrow()[completion_index]
6548 .source
6549 .lsp_completion(true)
6550 .map(Cow::into_owned);
6551 if let Some(lsp_documentation) = completion_item
6552 .as_ref()
6553 .and_then(|completion_item| completion_item.documentation.clone())
6554 {
6555 let mut completions = completions.borrow_mut();
6556 let completion = &mut completions[completion_index];
6557 completion.documentation = Some(lsp_documentation.into());
6558 } else {
6559 let mut completions = completions.borrow_mut();
6560 let completion = &mut completions[completion_index];
6561 completion.documentation = Some(CompletionDocumentation::Undocumented);
6562 }
6563
6564 let mut new_label = match completion_item {
6565 Some(completion_item) => {
6566 // Some language servers always return `detail` lazily via resolve, regardless of
6567 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6568 // See: https://github.com/yioneko/vtsls/issues/213
6569 let language = snapshot.language();
6570 match language {
6571 Some(language) => {
6572 adapter
6573 .labels_for_completions(
6574 std::slice::from_ref(&completion_item),
6575 language,
6576 )
6577 .await?
6578 }
6579 None => Vec::new(),
6580 }
6581 .pop()
6582 .flatten()
6583 .unwrap_or_else(|| {
6584 CodeLabel::fallback_for_completion(
6585 &completion_item,
6586 language.map(|language| language.as_ref()),
6587 )
6588 })
6589 }
6590 None => CodeLabel::plain(
6591 completions.borrow()[completion_index].new_text.clone(),
6592 None,
6593 ),
6594 };
6595 ensure_uniform_list_compatible_label(&mut new_label);
6596
6597 let mut completions = completions.borrow_mut();
6598 let completion = &mut completions[completion_index];
6599 if completion.label.filter_text() == new_label.filter_text() {
6600 completion.label = new_label;
6601 } else {
6602 log::error!(
6603 "Resolved completion changed display label from {} to {}. \
6604 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6605 completion.label.text(),
6606 new_label.text(),
6607 completion.label.filter_text(),
6608 new_label.filter_text()
6609 );
6610 }
6611
6612 Ok(())
6613 }
6614
6615 async fn resolve_completion_remote(
6616 project_id: u64,
6617 server_id: LanguageServerId,
6618 buffer_id: BufferId,
6619 completions: Rc<RefCell<Box<[Completion]>>>,
6620 completion_index: usize,
6621 client: AnyProtoClient,
6622 ) -> Result<()> {
6623 let lsp_completion = {
6624 let completion = &completions.borrow()[completion_index];
6625 match &completion.source {
6626 CompletionSource::Lsp {
6627 lsp_completion,
6628 resolved,
6629 server_id: completion_server_id,
6630 ..
6631 } => {
6632 anyhow::ensure!(
6633 server_id == *completion_server_id,
6634 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6635 );
6636 if *resolved {
6637 return Ok(());
6638 }
6639 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6640 }
6641 CompletionSource::Custom
6642 | CompletionSource::Dap { .. }
6643 | CompletionSource::BufferWord { .. } => {
6644 return Ok(());
6645 }
6646 }
6647 };
6648 let request = proto::ResolveCompletionDocumentation {
6649 project_id,
6650 language_server_id: server_id.0 as u64,
6651 lsp_completion,
6652 buffer_id: buffer_id.into(),
6653 };
6654
6655 let response = client
6656 .request(request)
6657 .await
6658 .context("completion documentation resolve proto request")?;
6659 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6660
6661 let documentation = if response.documentation.is_empty() {
6662 CompletionDocumentation::Undocumented
6663 } else if response.documentation_is_markdown {
6664 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6665 } else if response.documentation.lines().count() <= 1 {
6666 CompletionDocumentation::SingleLine(response.documentation.into())
6667 } else {
6668 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6669 };
6670
6671 let mut completions = completions.borrow_mut();
6672 let completion = &mut completions[completion_index];
6673 completion.documentation = Some(documentation);
6674 if let CompletionSource::Lsp {
6675 insert_range,
6676 lsp_completion,
6677 resolved,
6678 server_id: completion_server_id,
6679 lsp_defaults: _,
6680 } = &mut completion.source
6681 {
6682 let completion_insert_range = response
6683 .old_insert_start
6684 .and_then(deserialize_anchor)
6685 .zip(response.old_insert_end.and_then(deserialize_anchor));
6686 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6687
6688 if *resolved {
6689 return Ok(());
6690 }
6691 anyhow::ensure!(
6692 server_id == *completion_server_id,
6693 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6694 );
6695 **lsp_completion = resolved_lsp_completion;
6696 *resolved = true;
6697 }
6698
6699 let replace_range = response
6700 .old_replace_start
6701 .and_then(deserialize_anchor)
6702 .zip(response.old_replace_end.and_then(deserialize_anchor));
6703 if let Some((old_replace_start, old_replace_end)) = replace_range
6704 && !response.new_text.is_empty()
6705 {
6706 completion.new_text = response.new_text;
6707 completion.replace_range = old_replace_start..old_replace_end;
6708 }
6709
6710 Ok(())
6711 }
6712
6713 pub fn apply_additional_edits_for_completion(
6714 &self,
6715 buffer_handle: Entity<Buffer>,
6716 completions: Rc<RefCell<Box<[Completion]>>>,
6717 completion_index: usize,
6718 push_to_history: bool,
6719 cx: &mut Context<Self>,
6720 ) -> Task<Result<Option<Transaction>>> {
6721 if let Some((client, project_id)) = self.upstream_client() {
6722 let buffer = buffer_handle.read(cx);
6723 let buffer_id = buffer.remote_id();
6724 cx.spawn(async move |_, cx| {
6725 let request = {
6726 let completion = completions.borrow()[completion_index].clone();
6727 proto::ApplyCompletionAdditionalEdits {
6728 project_id,
6729 buffer_id: buffer_id.into(),
6730 completion: Some(Self::serialize_completion(&CoreCompletion {
6731 replace_range: completion.replace_range,
6732 new_text: completion.new_text,
6733 source: completion.source,
6734 })),
6735 }
6736 };
6737
6738 if let Some(transaction) = client.request(request).await?.transaction {
6739 let transaction = language::proto::deserialize_transaction(transaction)?;
6740 buffer_handle
6741 .update(cx, |buffer, _| {
6742 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6743 })?
6744 .await?;
6745 if push_to_history {
6746 buffer_handle.update(cx, |buffer, _| {
6747 buffer.push_transaction(transaction.clone(), Instant::now());
6748 buffer.finalize_last_transaction();
6749 })?;
6750 }
6751 Ok(Some(transaction))
6752 } else {
6753 Ok(None)
6754 }
6755 })
6756 } else {
6757 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6758 let completion = &completions.borrow()[completion_index];
6759 let server_id = completion.source.server_id()?;
6760 Some(
6761 self.language_server_for_local_buffer(buffer, server_id, cx)?
6762 .1
6763 .clone(),
6764 )
6765 }) else {
6766 return Task::ready(Ok(None));
6767 };
6768
6769 cx.spawn(async move |this, cx| {
6770 Self::resolve_completion_local(
6771 server.clone(),
6772 completions.clone(),
6773 completion_index,
6774 )
6775 .await
6776 .context("resolving completion")?;
6777 let completion = completions.borrow()[completion_index].clone();
6778 let additional_text_edits = completion
6779 .source
6780 .lsp_completion(true)
6781 .as_ref()
6782 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6783 if let Some(edits) = additional_text_edits {
6784 let edits = this
6785 .update(cx, |this, cx| {
6786 this.as_local_mut().unwrap().edits_from_lsp(
6787 &buffer_handle,
6788 edits,
6789 server.server_id(),
6790 None,
6791 cx,
6792 )
6793 })?
6794 .await?;
6795
6796 buffer_handle.update(cx, |buffer, cx| {
6797 buffer.finalize_last_transaction();
6798 buffer.start_transaction();
6799
6800 for (range, text) in edits {
6801 let primary = &completion.replace_range;
6802
6803 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6804 // and the primary completion is just an insertion (empty range), then this is likely
6805 // an auto-import scenario and should not be considered overlapping
6806 // https://github.com/zed-industries/zed/issues/26136
6807 let is_file_start_auto_import = {
6808 let snapshot = buffer.snapshot();
6809 let primary_start_point = primary.start.to_point(&snapshot);
6810 let range_start_point = range.start.to_point(&snapshot);
6811
6812 let result = primary_start_point.row == 0
6813 && primary_start_point.column == 0
6814 && range_start_point.row == 0
6815 && range_start_point.column == 0;
6816
6817 result
6818 };
6819
6820 let has_overlap = if is_file_start_auto_import {
6821 false
6822 } else {
6823 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6824 && primary.end.cmp(&range.start, buffer).is_ge();
6825 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6826 && range.end.cmp(&primary.end, buffer).is_ge();
6827 let result = start_within || end_within;
6828 result
6829 };
6830
6831 //Skip additional edits which overlap with the primary completion edit
6832 //https://github.com/zed-industries/zed/pull/1871
6833 if !has_overlap {
6834 buffer.edit([(range, text)], None, cx);
6835 }
6836 }
6837
6838 let transaction = if buffer.end_transaction(cx).is_some() {
6839 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6840 if !push_to_history {
6841 buffer.forget_transaction(transaction.id);
6842 }
6843 Some(transaction)
6844 } else {
6845 None
6846 };
6847 Ok(transaction)
6848 })?
6849 } else {
6850 Ok(None)
6851 }
6852 })
6853 }
6854 }
6855
6856 pub fn pull_diagnostics(
6857 &mut self,
6858 buffer: Entity<Buffer>,
6859 cx: &mut Context<Self>,
6860 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6861 let buffer_id = buffer.read(cx).remote_id();
6862
6863 if let Some((client, upstream_project_id)) = self.upstream_client() {
6864 let mut suitable_capabilities = None;
6865 // Are we capable for proto request?
6866 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6867 &buffer,
6868 |capabilities| {
6869 if let Some(caps) = &capabilities.diagnostic_provider {
6870 suitable_capabilities = Some(caps.clone());
6871 true
6872 } else {
6873 false
6874 }
6875 },
6876 cx,
6877 );
6878 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6879 let Some(dynamic_caps) = suitable_capabilities else {
6880 return Task::ready(Ok(None));
6881 };
6882 assert!(any_server_has_diagnostics_provider);
6883
6884 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6885 let request = GetDocumentDiagnostics {
6886 previous_result_id: None,
6887 identifier,
6888 registration_id: None,
6889 };
6890 let request_task = client.request_lsp(
6891 upstream_project_id,
6892 None,
6893 LSP_REQUEST_TIMEOUT,
6894 cx.background_executor().clone(),
6895 request.to_proto(upstream_project_id, buffer.read(cx)),
6896 );
6897 cx.background_spawn(async move {
6898 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6899 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6900 // Do not attempt to further process the dummy responses here.
6901 let _response = request_task.await?;
6902 Ok(None)
6903 })
6904 } else {
6905 let servers = buffer.update(cx, |buffer, cx| {
6906 self.running_language_servers_for_local_buffer(buffer, cx)
6907 .map(|(_, server)| server.clone())
6908 .collect::<Vec<_>>()
6909 });
6910
6911 let pull_diagnostics = servers
6912 .into_iter()
6913 .flat_map(|server| {
6914 let result = maybe!({
6915 let local = self.as_local()?;
6916 let server_id = server.server_id();
6917 let providers_with_identifiers = local
6918 .language_server_dynamic_registrations
6919 .get(&server_id)
6920 .into_iter()
6921 .flat_map(|registrations| registrations.diagnostics.clone())
6922 .collect::<Vec<_>>();
6923 Some(
6924 providers_with_identifiers
6925 .into_iter()
6926 .map(|(registration_id, dynamic_caps)| {
6927 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6928 let registration_id = registration_id.map(SharedString::from);
6929 let result_id = self.result_id_for_buffer_pull(
6930 server_id,
6931 buffer_id,
6932 ®istration_id,
6933 cx,
6934 );
6935 self.request_lsp(
6936 buffer.clone(),
6937 LanguageServerToQuery::Other(server_id),
6938 GetDocumentDiagnostics {
6939 previous_result_id: result_id,
6940 registration_id,
6941 identifier,
6942 },
6943 cx,
6944 )
6945 })
6946 .collect::<Vec<_>>(),
6947 )
6948 });
6949
6950 result.unwrap_or_default()
6951 })
6952 .collect::<Vec<_>>();
6953
6954 cx.background_spawn(async move {
6955 let mut responses = Vec::new();
6956 for diagnostics in join_all(pull_diagnostics).await {
6957 responses.extend(diagnostics?);
6958 }
6959 Ok(Some(responses))
6960 })
6961 }
6962 }
6963
6964 pub fn applicable_inlay_chunks(
6965 &mut self,
6966 buffer: &Entity<Buffer>,
6967 ranges: &[Range<text::Anchor>],
6968 cx: &mut Context<Self>,
6969 ) -> Vec<Range<BufferRow>> {
6970 let buffer_snapshot = buffer.read(cx).snapshot();
6971 let ranges = ranges
6972 .iter()
6973 .map(|range| range.to_point(&buffer_snapshot))
6974 .collect::<Vec<_>>();
6975
6976 self.latest_lsp_data(buffer, cx)
6977 .inlay_hints
6978 .applicable_chunks(ranges.as_slice())
6979 .map(|chunk| chunk.row_range())
6980 .collect()
6981 }
6982
6983 pub fn invalidate_inlay_hints<'a>(
6984 &'a mut self,
6985 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6986 ) {
6987 for buffer_id in for_buffers {
6988 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6989 lsp_data.inlay_hints.clear();
6990 }
6991 }
6992 }
6993
6994 pub fn inlay_hints(
6995 &mut self,
6996 invalidate: InvalidationStrategy,
6997 buffer: Entity<Buffer>,
6998 ranges: Vec<Range<text::Anchor>>,
6999 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7000 cx: &mut Context<Self>,
7001 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7002 let next_hint_id = self.next_hint_id.clone();
7003 let lsp_data = self.latest_lsp_data(&buffer, cx);
7004 let query_version = lsp_data.buffer_version.clone();
7005 let mut lsp_refresh_requested = false;
7006 let for_server = if let InvalidationStrategy::RefreshRequested {
7007 server_id,
7008 request_id,
7009 } = invalidate
7010 {
7011 let invalidated = lsp_data
7012 .inlay_hints
7013 .invalidate_for_server_refresh(server_id, request_id);
7014 lsp_refresh_requested = invalidated;
7015 Some(server_id)
7016 } else {
7017 None
7018 };
7019 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7020 let known_chunks = known_chunks
7021 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7022 .map(|(_, known_chunks)| known_chunks)
7023 .unwrap_or_default();
7024
7025 let buffer_snapshot = buffer.read(cx).snapshot();
7026 let ranges = ranges
7027 .iter()
7028 .map(|range| range.to_point(&buffer_snapshot))
7029 .collect::<Vec<_>>();
7030
7031 let mut hint_fetch_tasks = Vec::new();
7032 let mut cached_inlay_hints = None;
7033 let mut ranges_to_query = None;
7034 let applicable_chunks = existing_inlay_hints
7035 .applicable_chunks(ranges.as_slice())
7036 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7037 .collect::<Vec<_>>();
7038 if applicable_chunks.is_empty() {
7039 return HashMap::default();
7040 }
7041
7042 for row_chunk in applicable_chunks {
7043 match (
7044 existing_inlay_hints
7045 .cached_hints(&row_chunk)
7046 .filter(|_| !lsp_refresh_requested)
7047 .cloned(),
7048 existing_inlay_hints
7049 .fetched_hints(&row_chunk)
7050 .as_ref()
7051 .filter(|_| !lsp_refresh_requested)
7052 .cloned(),
7053 ) {
7054 (None, None) => {
7055 let chunk_range = row_chunk.anchor_range();
7056 ranges_to_query
7057 .get_or_insert_with(Vec::new)
7058 .push((row_chunk, chunk_range));
7059 }
7060 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7061 (Some(cached_hints), None) => {
7062 for (server_id, cached_hints) in cached_hints {
7063 if for_server.is_none_or(|for_server| for_server == server_id) {
7064 cached_inlay_hints
7065 .get_or_insert_with(HashMap::default)
7066 .entry(row_chunk.row_range())
7067 .or_insert_with(HashMap::default)
7068 .entry(server_id)
7069 .or_insert_with(Vec::new)
7070 .extend(cached_hints);
7071 }
7072 }
7073 }
7074 (Some(cached_hints), Some(fetched_hints)) => {
7075 hint_fetch_tasks.push((row_chunk, fetched_hints));
7076 for (server_id, cached_hints) in cached_hints {
7077 if for_server.is_none_or(|for_server| for_server == server_id) {
7078 cached_inlay_hints
7079 .get_or_insert_with(HashMap::default)
7080 .entry(row_chunk.row_range())
7081 .or_insert_with(HashMap::default)
7082 .entry(server_id)
7083 .or_insert_with(Vec::new)
7084 .extend(cached_hints);
7085 }
7086 }
7087 }
7088 }
7089 }
7090
7091 if hint_fetch_tasks.is_empty()
7092 && ranges_to_query
7093 .as_ref()
7094 .is_none_or(|ranges| ranges.is_empty())
7095 && let Some(cached_inlay_hints) = cached_inlay_hints
7096 {
7097 cached_inlay_hints
7098 .into_iter()
7099 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7100 .collect()
7101 } else {
7102 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7103 let next_hint_id = next_hint_id.clone();
7104 let buffer = buffer.clone();
7105 let query_version = query_version.clone();
7106 let new_inlay_hints = cx
7107 .spawn(async move |lsp_store, cx| {
7108 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7109 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7110 })?;
7111 new_fetch_task
7112 .await
7113 .and_then(|new_hints_by_server| {
7114 lsp_store.update(cx, |lsp_store, cx| {
7115 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7116 let update_cache = lsp_data.buffer_version == query_version;
7117 if new_hints_by_server.is_empty() {
7118 if update_cache {
7119 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7120 }
7121 HashMap::default()
7122 } else {
7123 new_hints_by_server
7124 .into_iter()
7125 .map(|(server_id, new_hints)| {
7126 let new_hints = new_hints
7127 .into_iter()
7128 .map(|new_hint| {
7129 (
7130 InlayId::Hint(next_hint_id.fetch_add(
7131 1,
7132 atomic::Ordering::AcqRel,
7133 )),
7134 new_hint,
7135 )
7136 })
7137 .collect::<Vec<_>>();
7138 if update_cache {
7139 lsp_data.inlay_hints.insert_new_hints(
7140 chunk,
7141 server_id,
7142 new_hints.clone(),
7143 );
7144 }
7145 (server_id, new_hints)
7146 })
7147 .collect()
7148 }
7149 })
7150 })
7151 .map_err(Arc::new)
7152 })
7153 .shared();
7154
7155 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7156 *fetch_task = Some(new_inlay_hints.clone());
7157 hint_fetch_tasks.push((chunk, new_inlay_hints));
7158 }
7159
7160 cached_inlay_hints
7161 .unwrap_or_default()
7162 .into_iter()
7163 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7164 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7165 (
7166 chunk.row_range(),
7167 cx.spawn(async move |_, _| {
7168 hints_fetch.await.map_err(|e| {
7169 if e.error_code() != ErrorCode::Internal {
7170 anyhow!(e.error_code())
7171 } else {
7172 anyhow!("{e:#}")
7173 }
7174 })
7175 }),
7176 )
7177 }))
7178 .collect()
7179 }
7180 }
7181
7182 fn fetch_inlay_hints(
7183 &mut self,
7184 for_server: Option<LanguageServerId>,
7185 buffer: &Entity<Buffer>,
7186 range: Range<Anchor>,
7187 cx: &mut Context<Self>,
7188 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7189 let request = InlayHints {
7190 range: range.clone(),
7191 };
7192 if let Some((upstream_client, project_id)) = self.upstream_client() {
7193 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7194 return Task::ready(Ok(HashMap::default()));
7195 }
7196 let request_task = upstream_client.request_lsp(
7197 project_id,
7198 for_server.map(|id| id.to_proto()),
7199 LSP_REQUEST_TIMEOUT,
7200 cx.background_executor().clone(),
7201 request.to_proto(project_id, buffer.read(cx)),
7202 );
7203 let buffer = buffer.clone();
7204 cx.spawn(async move |weak_lsp_store, cx| {
7205 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7206 return Ok(HashMap::default());
7207 };
7208 let Some(responses) = request_task.await? else {
7209 return Ok(HashMap::default());
7210 };
7211
7212 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7213 let lsp_store = lsp_store.clone();
7214 let buffer = buffer.clone();
7215 let cx = cx.clone();
7216 let request = request.clone();
7217 async move {
7218 (
7219 LanguageServerId::from_proto(response.server_id),
7220 request
7221 .response_from_proto(response.response, lsp_store, buffer, cx)
7222 .await,
7223 )
7224 }
7225 }))
7226 .await;
7227
7228 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot())?;
7229 let mut has_errors = false;
7230 let inlay_hints = inlay_hints
7231 .into_iter()
7232 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7233 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7234 Err(e) => {
7235 has_errors = true;
7236 log::error!("{e:#}");
7237 None
7238 }
7239 })
7240 .map(|(server_id, mut new_hints)| {
7241 new_hints.retain(|hint| {
7242 hint.position.is_valid(&buffer_snapshot)
7243 && range.start.is_valid(&buffer_snapshot)
7244 && range.end.is_valid(&buffer_snapshot)
7245 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7246 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7247 });
7248 (server_id, new_hints)
7249 })
7250 .collect::<HashMap<_, _>>();
7251 anyhow::ensure!(
7252 !has_errors || !inlay_hints.is_empty(),
7253 "Failed to fetch inlay hints"
7254 );
7255 Ok(inlay_hints)
7256 })
7257 } else {
7258 let inlay_hints_task = match for_server {
7259 Some(server_id) => {
7260 let server_task = self.request_lsp(
7261 buffer.clone(),
7262 LanguageServerToQuery::Other(server_id),
7263 request,
7264 cx,
7265 );
7266 cx.background_spawn(async move {
7267 let mut responses = Vec::new();
7268 match server_task.await {
7269 Ok(response) => responses.push((server_id, response)),
7270 // rust-analyzer likes to error with this when its still loading up
7271 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7272 Err(e) => log::error!(
7273 "Error handling response for inlay hints request: {e:#}"
7274 ),
7275 }
7276 responses
7277 })
7278 }
7279 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7280 };
7281 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7282 cx.background_spawn(async move {
7283 Ok(inlay_hints_task
7284 .await
7285 .into_iter()
7286 .map(|(server_id, mut new_hints)| {
7287 new_hints.retain(|hint| {
7288 hint.position.is_valid(&buffer_snapshot)
7289 && range.start.is_valid(&buffer_snapshot)
7290 && range.end.is_valid(&buffer_snapshot)
7291 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7292 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7293 });
7294 (server_id, new_hints)
7295 })
7296 .collect())
7297 })
7298 }
7299 }
7300
7301 fn diagnostic_registration_exists(
7302 &self,
7303 server_id: LanguageServerId,
7304 registration_id: &Option<SharedString>,
7305 ) -> bool {
7306 let Some(local) = self.as_local() else {
7307 return false;
7308 };
7309 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7310 else {
7311 return false;
7312 };
7313 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7314 registrations.diagnostics.contains_key(®istration_key)
7315 }
7316
7317 pub fn pull_diagnostics_for_buffer(
7318 &mut self,
7319 buffer: Entity<Buffer>,
7320 cx: &mut Context<Self>,
7321 ) -> Task<anyhow::Result<()>> {
7322 let diagnostics = self.pull_diagnostics(buffer, cx);
7323 cx.spawn(async move |lsp_store, cx| {
7324 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7325 return Ok(());
7326 };
7327 lsp_store.update(cx, |lsp_store, cx| {
7328 if lsp_store.as_local().is_none() {
7329 return;
7330 }
7331
7332 let mut unchanged_buffers = HashMap::default();
7333 let server_diagnostics_updates = diagnostics
7334 .into_iter()
7335 .filter_map(|diagnostics_set| match diagnostics_set {
7336 LspPullDiagnostics::Response {
7337 server_id,
7338 uri,
7339 diagnostics,
7340 registration_id,
7341 } => Some((server_id, uri, diagnostics, registration_id)),
7342 LspPullDiagnostics::Default => None,
7343 })
7344 .filter(|(server_id, _, _, registration_id)| {
7345 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7346 })
7347 .fold(
7348 HashMap::default(),
7349 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7350 let (result_id, diagnostics) = match diagnostics {
7351 PulledDiagnostics::Unchanged { result_id } => {
7352 unchanged_buffers
7353 .entry(new_registration_id.clone())
7354 .or_insert_with(HashSet::default)
7355 .insert(uri.clone());
7356 (Some(result_id), Vec::new())
7357 }
7358 PulledDiagnostics::Changed {
7359 result_id,
7360 diagnostics,
7361 } => (result_id, diagnostics),
7362 };
7363 let disk_based_sources = Cow::Owned(
7364 lsp_store
7365 .language_server_adapter_for_id(server_id)
7366 .as_ref()
7367 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7368 .unwrap_or(&[])
7369 .to_vec(),
7370 );
7371 acc.entry(server_id)
7372 .or_insert_with(HashMap::default)
7373 .entry(new_registration_id.clone())
7374 .or_insert_with(Vec::new)
7375 .push(DocumentDiagnosticsUpdate {
7376 server_id,
7377 diagnostics: lsp::PublishDiagnosticsParams {
7378 uri,
7379 diagnostics,
7380 version: None,
7381 },
7382 result_id,
7383 disk_based_sources,
7384 registration_id: new_registration_id,
7385 });
7386 acc
7387 },
7388 );
7389
7390 for diagnostic_updates in server_diagnostics_updates.into_values() {
7391 for (registration_id, diagnostic_updates) in diagnostic_updates {
7392 lsp_store
7393 .merge_lsp_diagnostics(
7394 DiagnosticSourceKind::Pulled,
7395 diagnostic_updates,
7396 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7397 DiagnosticSourceKind::Pulled => {
7398 old_diagnostic.registration_id != registration_id
7399 || unchanged_buffers
7400 .get(&old_diagnostic.registration_id)
7401 .is_some_and(|unchanged_buffers| {
7402 unchanged_buffers.contains(&document_uri)
7403 })
7404 }
7405 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7406 true
7407 }
7408 },
7409 cx,
7410 )
7411 .log_err();
7412 }
7413 }
7414 })
7415 })
7416 }
7417
7418 pub fn document_colors(
7419 &mut self,
7420 known_cache_version: Option<usize>,
7421 buffer: Entity<Buffer>,
7422 cx: &mut Context<Self>,
7423 ) -> Option<DocumentColorTask> {
7424 let version_queried_for = buffer.read(cx).version();
7425 let buffer_id = buffer.read(cx).remote_id();
7426
7427 let current_language_servers = self.as_local().map(|local| {
7428 local
7429 .buffers_opened_in_servers
7430 .get(&buffer_id)
7431 .cloned()
7432 .unwrap_or_default()
7433 });
7434
7435 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7436 if let Some(cached_colors) = &lsp_data.document_colors {
7437 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7438 let has_different_servers =
7439 current_language_servers.is_some_and(|current_language_servers| {
7440 current_language_servers
7441 != cached_colors.colors.keys().copied().collect()
7442 });
7443 if !has_different_servers {
7444 let cache_version = cached_colors.cache_version;
7445 if Some(cache_version) == known_cache_version {
7446 return None;
7447 } else {
7448 return Some(
7449 Task::ready(Ok(DocumentColors {
7450 colors: cached_colors
7451 .colors
7452 .values()
7453 .flatten()
7454 .cloned()
7455 .collect(),
7456 cache_version: Some(cache_version),
7457 }))
7458 .shared(),
7459 );
7460 }
7461 }
7462 }
7463 }
7464 }
7465
7466 let color_lsp_data = self
7467 .latest_lsp_data(&buffer, cx)
7468 .document_colors
7469 .get_or_insert_default();
7470 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7471 && !version_queried_for.changed_since(updating_for)
7472 {
7473 return Some(running_update.clone());
7474 }
7475 let buffer_version_queried_for = version_queried_for.clone();
7476 let new_task = cx
7477 .spawn(async move |lsp_store, cx| {
7478 cx.background_executor()
7479 .timer(Duration::from_millis(30))
7480 .await;
7481 let fetched_colors = lsp_store
7482 .update(cx, |lsp_store, cx| {
7483 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7484 })?
7485 .await
7486 .context("fetching document colors")
7487 .map_err(Arc::new);
7488 let fetched_colors = match fetched_colors {
7489 Ok(fetched_colors) => {
7490 if Some(true)
7491 == buffer
7492 .update(cx, |buffer, _| {
7493 buffer.version() != buffer_version_queried_for
7494 })
7495 .ok()
7496 {
7497 return Ok(DocumentColors::default());
7498 }
7499 fetched_colors
7500 }
7501 Err(e) => {
7502 lsp_store
7503 .update(cx, |lsp_store, _| {
7504 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7505 if let Some(document_colors) = &mut lsp_data.document_colors {
7506 document_colors.colors_update = None;
7507 }
7508 }
7509 })
7510 .ok();
7511 return Err(e);
7512 }
7513 };
7514
7515 lsp_store
7516 .update(cx, |lsp_store, cx| {
7517 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7518 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7519
7520 if let Some(fetched_colors) = fetched_colors {
7521 if lsp_data.buffer_version == buffer_version_queried_for {
7522 lsp_colors.colors.extend(fetched_colors);
7523 lsp_colors.cache_version += 1;
7524 } else if !lsp_data
7525 .buffer_version
7526 .changed_since(&buffer_version_queried_for)
7527 {
7528 lsp_data.buffer_version = buffer_version_queried_for;
7529 lsp_colors.colors = fetched_colors;
7530 lsp_colors.cache_version += 1;
7531 }
7532 }
7533 lsp_colors.colors_update = None;
7534 let colors = lsp_colors
7535 .colors
7536 .values()
7537 .flatten()
7538 .cloned()
7539 .collect::<HashSet<_>>();
7540 DocumentColors {
7541 colors,
7542 cache_version: Some(lsp_colors.cache_version),
7543 }
7544 })
7545 .map_err(Arc::new)
7546 })
7547 .shared();
7548 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7549 Some(new_task)
7550 }
7551
7552 fn fetch_document_colors_for_buffer(
7553 &mut self,
7554 buffer: &Entity<Buffer>,
7555 cx: &mut Context<Self>,
7556 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7557 if let Some((client, project_id)) = self.upstream_client() {
7558 let request = GetDocumentColor {};
7559 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7560 return Task::ready(Ok(None));
7561 }
7562
7563 let request_task = client.request_lsp(
7564 project_id,
7565 None,
7566 LSP_REQUEST_TIMEOUT,
7567 cx.background_executor().clone(),
7568 request.to_proto(project_id, buffer.read(cx)),
7569 );
7570 let buffer = buffer.clone();
7571 cx.spawn(async move |lsp_store, cx| {
7572 let Some(lsp_store) = lsp_store.upgrade() else {
7573 return Ok(None);
7574 };
7575 let colors = join_all(
7576 request_task
7577 .await
7578 .log_err()
7579 .flatten()
7580 .map(|response| response.payload)
7581 .unwrap_or_default()
7582 .into_iter()
7583 .map(|color_response| {
7584 let response = request.response_from_proto(
7585 color_response.response,
7586 lsp_store.clone(),
7587 buffer.clone(),
7588 cx.clone(),
7589 );
7590 async move {
7591 (
7592 LanguageServerId::from_proto(color_response.server_id),
7593 response.await.log_err().unwrap_or_default(),
7594 )
7595 }
7596 }),
7597 )
7598 .await
7599 .into_iter()
7600 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7601 acc.entry(server_id)
7602 .or_insert_with(HashSet::default)
7603 .extend(colors);
7604 acc
7605 });
7606 Ok(Some(colors))
7607 })
7608 } else {
7609 let document_colors_task =
7610 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7611 cx.background_spawn(async move {
7612 Ok(Some(
7613 document_colors_task
7614 .await
7615 .into_iter()
7616 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7617 acc.entry(server_id)
7618 .or_insert_with(HashSet::default)
7619 .extend(colors);
7620 acc
7621 })
7622 .into_iter()
7623 .collect(),
7624 ))
7625 })
7626 }
7627 }
7628
7629 pub fn signature_help<T: ToPointUtf16>(
7630 &mut self,
7631 buffer: &Entity<Buffer>,
7632 position: T,
7633 cx: &mut Context<Self>,
7634 ) -> Task<Option<Vec<SignatureHelp>>> {
7635 let position = position.to_point_utf16(buffer.read(cx));
7636
7637 if let Some((client, upstream_project_id)) = self.upstream_client() {
7638 let request = GetSignatureHelp { position };
7639 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7640 return Task::ready(None);
7641 }
7642 let request_task = client.request_lsp(
7643 upstream_project_id,
7644 None,
7645 LSP_REQUEST_TIMEOUT,
7646 cx.background_executor().clone(),
7647 request.to_proto(upstream_project_id, buffer.read(cx)),
7648 );
7649 let buffer = buffer.clone();
7650 cx.spawn(async move |weak_lsp_store, cx| {
7651 let lsp_store = weak_lsp_store.upgrade()?;
7652 let signatures = join_all(
7653 request_task
7654 .await
7655 .log_err()
7656 .flatten()
7657 .map(|response| response.payload)
7658 .unwrap_or_default()
7659 .into_iter()
7660 .map(|response| {
7661 let response = GetSignatureHelp { position }.response_from_proto(
7662 response.response,
7663 lsp_store.clone(),
7664 buffer.clone(),
7665 cx.clone(),
7666 );
7667 async move { response.await.log_err().flatten() }
7668 }),
7669 )
7670 .await
7671 .into_iter()
7672 .flatten()
7673 .collect();
7674 Some(signatures)
7675 })
7676 } else {
7677 let all_actions_task = self.request_multiple_lsp_locally(
7678 buffer,
7679 Some(position),
7680 GetSignatureHelp { position },
7681 cx,
7682 );
7683 cx.background_spawn(async move {
7684 Some(
7685 all_actions_task
7686 .await
7687 .into_iter()
7688 .flat_map(|(_, actions)| actions)
7689 .collect::<Vec<_>>(),
7690 )
7691 })
7692 }
7693 }
7694
7695 pub fn hover(
7696 &mut self,
7697 buffer: &Entity<Buffer>,
7698 position: PointUtf16,
7699 cx: &mut Context<Self>,
7700 ) -> Task<Option<Vec<Hover>>> {
7701 if let Some((client, upstream_project_id)) = self.upstream_client() {
7702 let request = GetHover { position };
7703 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7704 return Task::ready(None);
7705 }
7706 let request_task = client.request_lsp(
7707 upstream_project_id,
7708 None,
7709 LSP_REQUEST_TIMEOUT,
7710 cx.background_executor().clone(),
7711 request.to_proto(upstream_project_id, buffer.read(cx)),
7712 );
7713 let buffer = buffer.clone();
7714 cx.spawn(async move |weak_lsp_store, cx| {
7715 let lsp_store = weak_lsp_store.upgrade()?;
7716 let hovers = join_all(
7717 request_task
7718 .await
7719 .log_err()
7720 .flatten()
7721 .map(|response| response.payload)
7722 .unwrap_or_default()
7723 .into_iter()
7724 .map(|response| {
7725 let response = GetHover { position }.response_from_proto(
7726 response.response,
7727 lsp_store.clone(),
7728 buffer.clone(),
7729 cx.clone(),
7730 );
7731 async move {
7732 response
7733 .await
7734 .log_err()
7735 .flatten()
7736 .and_then(remove_empty_hover_blocks)
7737 }
7738 }),
7739 )
7740 .await
7741 .into_iter()
7742 .flatten()
7743 .collect();
7744 Some(hovers)
7745 })
7746 } else {
7747 let all_actions_task = self.request_multiple_lsp_locally(
7748 buffer,
7749 Some(position),
7750 GetHover { position },
7751 cx,
7752 );
7753 cx.background_spawn(async move {
7754 Some(
7755 all_actions_task
7756 .await
7757 .into_iter()
7758 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7759 .collect::<Vec<Hover>>(),
7760 )
7761 })
7762 }
7763 }
7764
7765 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7766 let language_registry = self.languages.clone();
7767
7768 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7769 let request = upstream_client.request(proto::GetProjectSymbols {
7770 project_id: *project_id,
7771 query: query.to_string(),
7772 });
7773 cx.foreground_executor().spawn(async move {
7774 let response = request.await?;
7775 let mut symbols = Vec::new();
7776 let core_symbols = response
7777 .symbols
7778 .into_iter()
7779 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7780 .collect::<Vec<_>>();
7781 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7782 .await;
7783 Ok(symbols)
7784 })
7785 } else if let Some(local) = self.as_local() {
7786 struct WorkspaceSymbolsResult {
7787 server_id: LanguageServerId,
7788 lsp_adapter: Arc<CachedLspAdapter>,
7789 worktree: WeakEntity<Worktree>,
7790 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7791 }
7792
7793 let mut requests = Vec::new();
7794 let mut requested_servers = BTreeSet::new();
7795 for (seed, state) in local.language_server_ids.iter() {
7796 let Some(worktree_handle) = self
7797 .worktree_store
7798 .read(cx)
7799 .worktree_for_id(seed.worktree_id, cx)
7800 else {
7801 continue;
7802 };
7803 let worktree = worktree_handle.read(cx);
7804 if !worktree.is_visible() {
7805 continue;
7806 }
7807
7808 if !requested_servers.insert(state.id) {
7809 continue;
7810 }
7811
7812 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7813 Some(LanguageServerState::Running {
7814 adapter, server, ..
7815 }) => (adapter.clone(), server),
7816
7817 _ => continue,
7818 };
7819 let supports_workspace_symbol_request =
7820 match server.capabilities().workspace_symbol_provider {
7821 Some(OneOf::Left(supported)) => supported,
7822 Some(OneOf::Right(_)) => true,
7823 None => false,
7824 };
7825 if !supports_workspace_symbol_request {
7826 continue;
7827 }
7828 let worktree_handle = worktree_handle.clone();
7829 let server_id = server.server_id();
7830 requests.push(
7831 server
7832 .request::<lsp::request::WorkspaceSymbolRequest>(
7833 lsp::WorkspaceSymbolParams {
7834 query: query.to_string(),
7835 ..Default::default()
7836 },
7837 )
7838 .map(move |response| {
7839 let lsp_symbols = response.into_response()
7840 .context("workspace symbols request")
7841 .log_err()
7842 .flatten()
7843 .map(|symbol_response| match symbol_response {
7844 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7845 flat_responses.into_iter().map(|lsp_symbol| {
7846 (lsp_symbol.name, lsp_symbol.kind, lsp_symbol.location)
7847 }).collect::<Vec<_>>()
7848 }
7849 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7850 nested_responses.into_iter().filter_map(|lsp_symbol| {
7851 let location = match lsp_symbol.location {
7852 OneOf::Left(location) => location,
7853 OneOf::Right(_) => {
7854 log::error!("Unexpected: client capabilities forbid symbol resolutions in workspace.symbol.resolveSupport");
7855 return None
7856 }
7857 };
7858 Some((lsp_symbol.name, lsp_symbol.kind, location))
7859 }).collect::<Vec<_>>()
7860 }
7861 }).unwrap_or_default();
7862
7863 WorkspaceSymbolsResult {
7864 server_id,
7865 lsp_adapter,
7866 worktree: worktree_handle.downgrade(),
7867 lsp_symbols,
7868 }
7869 }),
7870 );
7871 }
7872
7873 cx.spawn(async move |this, cx| {
7874 let responses = futures::future::join_all(requests).await;
7875 let this = match this.upgrade() {
7876 Some(this) => this,
7877 None => return Ok(Vec::new()),
7878 };
7879
7880 let mut symbols = Vec::new();
7881 for result in responses {
7882 let core_symbols = this.update(cx, |this, cx| {
7883 result
7884 .lsp_symbols
7885 .into_iter()
7886 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7887 let abs_path = symbol_location.uri.to_file_path().ok()?;
7888 let source_worktree = result.worktree.upgrade()?;
7889 let source_worktree_id = source_worktree.read(cx).id();
7890
7891 let path = if let Some((tree, rel_path)) =
7892 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7893 {
7894 let worktree_id = tree.read(cx).id();
7895 SymbolLocation::InProject(ProjectPath {
7896 worktree_id,
7897 path: rel_path,
7898 })
7899 } else {
7900 SymbolLocation::OutsideProject {
7901 signature: this.symbol_signature(&abs_path),
7902 abs_path: abs_path.into(),
7903 }
7904 };
7905
7906 Some(CoreSymbol {
7907 source_language_server_id: result.server_id,
7908 language_server_name: result.lsp_adapter.name.clone(),
7909 source_worktree_id,
7910 path,
7911 kind: symbol_kind,
7912 name: symbol_name,
7913 range: range_from_lsp(symbol_location.range),
7914 })
7915 })
7916 .collect()
7917 })?;
7918
7919 populate_labels_for_symbols(
7920 core_symbols,
7921 &language_registry,
7922 Some(result.lsp_adapter),
7923 &mut symbols,
7924 )
7925 .await;
7926 }
7927
7928 Ok(symbols)
7929 })
7930 } else {
7931 Task::ready(Err(anyhow!("No upstream client or local language server")))
7932 }
7933 }
7934
7935 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7936 let mut summary = DiagnosticSummary::default();
7937 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7938 summary.error_count += path_summary.error_count;
7939 summary.warning_count += path_summary.warning_count;
7940 }
7941 summary
7942 }
7943
7944 /// Returns the diagnostic summary for a specific project path.
7945 pub fn diagnostic_summary_for_path(
7946 &self,
7947 project_path: &ProjectPath,
7948 _: &App,
7949 ) -> DiagnosticSummary {
7950 if let Some(summaries) = self
7951 .diagnostic_summaries
7952 .get(&project_path.worktree_id)
7953 .and_then(|map| map.get(&project_path.path))
7954 {
7955 let (error_count, warning_count) = summaries.iter().fold(
7956 (0, 0),
7957 |(error_count, warning_count), (_language_server_id, summary)| {
7958 (
7959 error_count + summary.error_count,
7960 warning_count + summary.warning_count,
7961 )
7962 },
7963 );
7964
7965 DiagnosticSummary {
7966 error_count,
7967 warning_count,
7968 }
7969 } else {
7970 DiagnosticSummary::default()
7971 }
7972 }
7973
7974 pub fn diagnostic_summaries<'a>(
7975 &'a self,
7976 include_ignored: bool,
7977 cx: &'a App,
7978 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7979 self.worktree_store
7980 .read(cx)
7981 .visible_worktrees(cx)
7982 .filter_map(|worktree| {
7983 let worktree = worktree.read(cx);
7984 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7985 })
7986 .flat_map(move |(worktree, summaries)| {
7987 let worktree_id = worktree.id();
7988 summaries
7989 .iter()
7990 .filter(move |(path, _)| {
7991 include_ignored
7992 || worktree
7993 .entry_for_path(path.as_ref())
7994 .is_some_and(|entry| !entry.is_ignored)
7995 })
7996 .flat_map(move |(path, summaries)| {
7997 summaries.iter().map(move |(server_id, summary)| {
7998 (
7999 ProjectPath {
8000 worktree_id,
8001 path: path.clone(),
8002 },
8003 *server_id,
8004 *summary,
8005 )
8006 })
8007 })
8008 })
8009 }
8010
8011 pub fn on_buffer_edited(
8012 &mut self,
8013 buffer: Entity<Buffer>,
8014 cx: &mut Context<Self>,
8015 ) -> Option<()> {
8016 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8017 Some(
8018 self.as_local()?
8019 .language_servers_for_buffer(buffer, cx)
8020 .map(|i| i.1.clone())
8021 .collect(),
8022 )
8023 })?;
8024
8025 let buffer = buffer.read(cx);
8026 let file = File::from_dyn(buffer.file())?;
8027 let abs_path = file.as_local()?.abs_path(cx);
8028 let uri = lsp::Uri::from_file_path(&abs_path)
8029 .ok()
8030 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8031 .log_err()?;
8032 let next_snapshot = buffer.text_snapshot();
8033 for language_server in language_servers {
8034 let language_server = language_server.clone();
8035
8036 let buffer_snapshots = self
8037 .as_local_mut()?
8038 .buffer_snapshots
8039 .get_mut(&buffer.remote_id())
8040 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8041 let previous_snapshot = buffer_snapshots.last()?;
8042
8043 let build_incremental_change = || {
8044 buffer
8045 .edits_since::<Dimensions<PointUtf16, usize>>(
8046 previous_snapshot.snapshot.version(),
8047 )
8048 .map(|edit| {
8049 let edit_start = edit.new.start.0;
8050 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8051 let new_text = next_snapshot
8052 .text_for_range(edit.new.start.1..edit.new.end.1)
8053 .collect();
8054 lsp::TextDocumentContentChangeEvent {
8055 range: Some(lsp::Range::new(
8056 point_to_lsp(edit_start),
8057 point_to_lsp(edit_end),
8058 )),
8059 range_length: None,
8060 text: new_text,
8061 }
8062 })
8063 .collect()
8064 };
8065
8066 let document_sync_kind = language_server
8067 .capabilities()
8068 .text_document_sync
8069 .as_ref()
8070 .and_then(|sync| match sync {
8071 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8072 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8073 });
8074
8075 let content_changes: Vec<_> = match document_sync_kind {
8076 Some(lsp::TextDocumentSyncKind::FULL) => {
8077 vec![lsp::TextDocumentContentChangeEvent {
8078 range: None,
8079 range_length: None,
8080 text: next_snapshot.text(),
8081 }]
8082 }
8083 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8084 _ => {
8085 #[cfg(any(test, feature = "test-support"))]
8086 {
8087 build_incremental_change()
8088 }
8089
8090 #[cfg(not(any(test, feature = "test-support")))]
8091 {
8092 continue;
8093 }
8094 }
8095 };
8096
8097 let next_version = previous_snapshot.version + 1;
8098 buffer_snapshots.push(LspBufferSnapshot {
8099 version: next_version,
8100 snapshot: next_snapshot.clone(),
8101 });
8102
8103 language_server
8104 .notify::<lsp::notification::DidChangeTextDocument>(
8105 lsp::DidChangeTextDocumentParams {
8106 text_document: lsp::VersionedTextDocumentIdentifier::new(
8107 uri.clone(),
8108 next_version,
8109 ),
8110 content_changes,
8111 },
8112 )
8113 .ok();
8114 self.pull_workspace_diagnostics(language_server.server_id());
8115 }
8116
8117 None
8118 }
8119
8120 pub fn on_buffer_saved(
8121 &mut self,
8122 buffer: Entity<Buffer>,
8123 cx: &mut Context<Self>,
8124 ) -> Option<()> {
8125 let file = File::from_dyn(buffer.read(cx).file())?;
8126 let worktree_id = file.worktree_id(cx);
8127 let abs_path = file.as_local()?.abs_path(cx);
8128 let text_document = lsp::TextDocumentIdentifier {
8129 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8130 };
8131 let local = self.as_local()?;
8132
8133 for server in local.language_servers_for_worktree(worktree_id) {
8134 if let Some(include_text) = include_text(server.as_ref()) {
8135 let text = if include_text {
8136 Some(buffer.read(cx).text())
8137 } else {
8138 None
8139 };
8140 server
8141 .notify::<lsp::notification::DidSaveTextDocument>(
8142 lsp::DidSaveTextDocumentParams {
8143 text_document: text_document.clone(),
8144 text,
8145 },
8146 )
8147 .ok();
8148 }
8149 }
8150
8151 let language_servers = buffer.update(cx, |buffer, cx| {
8152 local.language_server_ids_for_buffer(buffer, cx)
8153 });
8154 for language_server_id in language_servers {
8155 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8156 }
8157
8158 None
8159 }
8160
8161 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8162 maybe!(async move {
8163 let mut refreshed_servers = HashSet::default();
8164 let servers = lsp_store
8165 .update(cx, |lsp_store, cx| {
8166 let local = lsp_store.as_local()?;
8167
8168 let servers = local
8169 .language_server_ids
8170 .iter()
8171 .filter_map(|(seed, state)| {
8172 let worktree = lsp_store
8173 .worktree_store
8174 .read(cx)
8175 .worktree_for_id(seed.worktree_id, cx);
8176 let delegate: Arc<dyn LspAdapterDelegate> =
8177 worktree.map(|worktree| {
8178 LocalLspAdapterDelegate::new(
8179 local.languages.clone(),
8180 &local.environment,
8181 cx.weak_entity(),
8182 &worktree,
8183 local.http_client.clone(),
8184 local.fs.clone(),
8185 cx,
8186 )
8187 })?;
8188 let server_id = state.id;
8189
8190 let states = local.language_servers.get(&server_id)?;
8191
8192 match states {
8193 LanguageServerState::Starting { .. } => None,
8194 LanguageServerState::Running {
8195 adapter, server, ..
8196 } => {
8197 let adapter = adapter.clone();
8198 let server = server.clone();
8199 refreshed_servers.insert(server.name());
8200 let toolchain = seed.toolchain.clone();
8201 Some(cx.spawn(async move |_, cx| {
8202 let settings =
8203 LocalLspStore::workspace_configuration_for_adapter(
8204 adapter.adapter.clone(),
8205 &delegate,
8206 toolchain,
8207 None,
8208 cx,
8209 )
8210 .await
8211 .ok()?;
8212 server
8213 .notify::<lsp::notification::DidChangeConfiguration>(
8214 lsp::DidChangeConfigurationParams { settings },
8215 )
8216 .ok()?;
8217 Some(())
8218 }))
8219 }
8220 }
8221 })
8222 .collect::<Vec<_>>();
8223
8224 Some(servers)
8225 })
8226 .ok()
8227 .flatten()?;
8228
8229 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8230 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8231 // to stop and unregister its language server wrapper.
8232 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8233 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8234 let _: Vec<Option<()>> = join_all(servers).await;
8235
8236 Some(())
8237 })
8238 .await;
8239 }
8240
8241 fn maintain_workspace_config(
8242 external_refresh_requests: watch::Receiver<()>,
8243 cx: &mut Context<Self>,
8244 ) -> Task<Result<()>> {
8245 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8246 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8247
8248 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8249 *settings_changed_tx.borrow_mut() = ();
8250 });
8251
8252 let mut joint_future =
8253 futures::stream::select(settings_changed_rx, external_refresh_requests);
8254 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8255 // - 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).
8256 // - 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.
8257 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8258 // - 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,
8259 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8260 cx.spawn(async move |this, cx| {
8261 while let Some(()) = joint_future.next().await {
8262 this.update(cx, |this, cx| {
8263 this.refresh_server_tree(cx);
8264 })
8265 .ok();
8266
8267 Self::refresh_workspace_configurations(&this, cx).await;
8268 }
8269
8270 drop(settings_observation);
8271 anyhow::Ok(())
8272 })
8273 }
8274
8275 pub fn running_language_servers_for_local_buffer<'a>(
8276 &'a self,
8277 buffer: &Buffer,
8278 cx: &mut App,
8279 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8280 let local = self.as_local();
8281 let language_server_ids = local
8282 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8283 .unwrap_or_default();
8284
8285 language_server_ids
8286 .into_iter()
8287 .filter_map(
8288 move |server_id| match local?.language_servers.get(&server_id)? {
8289 LanguageServerState::Running {
8290 adapter, server, ..
8291 } => Some((adapter, server)),
8292 _ => None,
8293 },
8294 )
8295 }
8296
8297 pub fn language_servers_for_local_buffer(
8298 &self,
8299 buffer: &Buffer,
8300 cx: &mut App,
8301 ) -> Vec<LanguageServerId> {
8302 let local = self.as_local();
8303 local
8304 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8305 .unwrap_or_default()
8306 }
8307
8308 pub fn language_server_for_local_buffer<'a>(
8309 &'a self,
8310 buffer: &'a Buffer,
8311 server_id: LanguageServerId,
8312 cx: &'a mut App,
8313 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8314 self.as_local()?
8315 .language_servers_for_buffer(buffer, cx)
8316 .find(|(_, s)| s.server_id() == server_id)
8317 }
8318
8319 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8320 self.diagnostic_summaries.remove(&id_to_remove);
8321 if let Some(local) = self.as_local_mut() {
8322 let to_remove = local.remove_worktree(id_to_remove, cx);
8323 for server in to_remove {
8324 self.language_server_statuses.remove(&server);
8325 }
8326 }
8327 }
8328
8329 pub fn shared(
8330 &mut self,
8331 project_id: u64,
8332 downstream_client: AnyProtoClient,
8333 _: &mut Context<Self>,
8334 ) {
8335 self.downstream_client = Some((downstream_client.clone(), project_id));
8336
8337 for (server_id, status) in &self.language_server_statuses {
8338 if let Some(server) = self.language_server_for_id(*server_id) {
8339 downstream_client
8340 .send(proto::StartLanguageServer {
8341 project_id,
8342 server: Some(proto::LanguageServer {
8343 id: server_id.to_proto(),
8344 name: status.name.to_string(),
8345 worktree_id: status.worktree.map(|id| id.to_proto()),
8346 }),
8347 capabilities: serde_json::to_string(&server.capabilities())
8348 .expect("serializing server LSP capabilities"),
8349 })
8350 .log_err();
8351 }
8352 }
8353 }
8354
8355 pub fn disconnected_from_host(&mut self) {
8356 self.downstream_client.take();
8357 }
8358
8359 pub fn disconnected_from_ssh_remote(&mut self) {
8360 if let LspStoreMode::Remote(RemoteLspStore {
8361 upstream_client, ..
8362 }) = &mut self.mode
8363 {
8364 upstream_client.take();
8365 }
8366 }
8367
8368 pub(crate) fn set_language_server_statuses_from_proto(
8369 &mut self,
8370 project: WeakEntity<Project>,
8371 language_servers: Vec<proto::LanguageServer>,
8372 server_capabilities: Vec<String>,
8373 cx: &mut Context<Self>,
8374 ) {
8375 let lsp_logs = cx
8376 .try_global::<GlobalLogStore>()
8377 .map(|lsp_store| lsp_store.0.clone());
8378
8379 self.language_server_statuses = language_servers
8380 .into_iter()
8381 .zip(server_capabilities)
8382 .map(|(server, server_capabilities)| {
8383 let server_id = LanguageServerId(server.id as usize);
8384 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8385 self.lsp_server_capabilities
8386 .insert(server_id, server_capabilities);
8387 }
8388
8389 let name = LanguageServerName::from_proto(server.name);
8390 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8391
8392 if let Some(lsp_logs) = &lsp_logs {
8393 lsp_logs.update(cx, |lsp_logs, cx| {
8394 lsp_logs.add_language_server(
8395 // Only remote clients get their language servers set from proto
8396 LanguageServerKind::Remote {
8397 project: project.clone(),
8398 },
8399 server_id,
8400 Some(name.clone()),
8401 worktree,
8402 None,
8403 cx,
8404 );
8405 });
8406 }
8407
8408 (
8409 server_id,
8410 LanguageServerStatus {
8411 name,
8412 server_version: None,
8413 pending_work: Default::default(),
8414 has_pending_diagnostic_updates: false,
8415 progress_tokens: Default::default(),
8416 worktree,
8417 binary: None,
8418 configuration: None,
8419 workspace_folders: BTreeSet::new(),
8420 },
8421 )
8422 })
8423 .collect();
8424 }
8425
8426 #[cfg(test)]
8427 pub fn update_diagnostic_entries(
8428 &mut self,
8429 server_id: LanguageServerId,
8430 abs_path: PathBuf,
8431 result_id: Option<SharedString>,
8432 version: Option<i32>,
8433 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8434 cx: &mut Context<Self>,
8435 ) -> anyhow::Result<()> {
8436 self.merge_diagnostic_entries(
8437 vec![DocumentDiagnosticsUpdate {
8438 diagnostics: DocumentDiagnostics {
8439 diagnostics,
8440 document_abs_path: abs_path,
8441 version,
8442 },
8443 result_id,
8444 server_id,
8445 disk_based_sources: Cow::Borrowed(&[]),
8446 registration_id: None,
8447 }],
8448 |_, _, _| false,
8449 cx,
8450 )?;
8451 Ok(())
8452 }
8453
8454 pub fn merge_diagnostic_entries<'a>(
8455 &mut self,
8456 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8457 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8458 cx: &mut Context<Self>,
8459 ) -> anyhow::Result<()> {
8460 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8461 let mut updated_diagnostics_paths = HashMap::default();
8462 for mut update in diagnostic_updates {
8463 let abs_path = &update.diagnostics.document_abs_path;
8464 let server_id = update.server_id;
8465 let Some((worktree, relative_path)) =
8466 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8467 else {
8468 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8469 return Ok(());
8470 };
8471
8472 let worktree_id = worktree.read(cx).id();
8473 let project_path = ProjectPath {
8474 worktree_id,
8475 path: relative_path,
8476 };
8477
8478 let document_uri = lsp::Uri::from_file_path(abs_path)
8479 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8480 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8481 let snapshot = buffer_handle.read(cx).snapshot();
8482 let buffer = buffer_handle.read(cx);
8483 let reused_diagnostics = buffer
8484 .buffer_diagnostics(Some(server_id))
8485 .iter()
8486 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8487 .map(|v| {
8488 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8489 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8490 DiagnosticEntry {
8491 range: start..end,
8492 diagnostic: v.diagnostic.clone(),
8493 }
8494 })
8495 .collect::<Vec<_>>();
8496
8497 self.as_local_mut()
8498 .context("cannot merge diagnostics on a remote LspStore")?
8499 .update_buffer_diagnostics(
8500 &buffer_handle,
8501 server_id,
8502 Some(update.registration_id),
8503 update.result_id,
8504 update.diagnostics.version,
8505 update.diagnostics.diagnostics.clone(),
8506 reused_diagnostics.clone(),
8507 cx,
8508 )?;
8509
8510 update.diagnostics.diagnostics.extend(reused_diagnostics);
8511 } else if let Some(local) = self.as_local() {
8512 let reused_diagnostics = local
8513 .diagnostics
8514 .get(&worktree_id)
8515 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8516 .and_then(|diagnostics_by_server_id| {
8517 diagnostics_by_server_id
8518 .binary_search_by_key(&server_id, |e| e.0)
8519 .ok()
8520 .map(|ix| &diagnostics_by_server_id[ix].1)
8521 })
8522 .into_iter()
8523 .flatten()
8524 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8525
8526 update
8527 .diagnostics
8528 .diagnostics
8529 .extend(reused_diagnostics.cloned());
8530 }
8531
8532 let updated = worktree.update(cx, |worktree, cx| {
8533 self.update_worktree_diagnostics(
8534 worktree.id(),
8535 server_id,
8536 project_path.path.clone(),
8537 update.diagnostics.diagnostics,
8538 cx,
8539 )
8540 })?;
8541 match updated {
8542 ControlFlow::Continue(new_summary) => {
8543 if let Some((project_id, new_summary)) = new_summary {
8544 match &mut diagnostics_summary {
8545 Some(diagnostics_summary) => {
8546 diagnostics_summary
8547 .more_summaries
8548 .push(proto::DiagnosticSummary {
8549 path: project_path.path.as_ref().to_proto(),
8550 language_server_id: server_id.0 as u64,
8551 error_count: new_summary.error_count,
8552 warning_count: new_summary.warning_count,
8553 })
8554 }
8555 None => {
8556 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8557 project_id,
8558 worktree_id: worktree_id.to_proto(),
8559 summary: Some(proto::DiagnosticSummary {
8560 path: project_path.path.as_ref().to_proto(),
8561 language_server_id: server_id.0 as u64,
8562 error_count: new_summary.error_count,
8563 warning_count: new_summary.warning_count,
8564 }),
8565 more_summaries: Vec::new(),
8566 })
8567 }
8568 }
8569 }
8570 updated_diagnostics_paths
8571 .entry(server_id)
8572 .or_insert_with(Vec::new)
8573 .push(project_path);
8574 }
8575 ControlFlow::Break(()) => {}
8576 }
8577 }
8578
8579 if let Some((diagnostics_summary, (downstream_client, _))) =
8580 diagnostics_summary.zip(self.downstream_client.as_ref())
8581 {
8582 downstream_client.send(diagnostics_summary).log_err();
8583 }
8584 for (server_id, paths) in updated_diagnostics_paths {
8585 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8586 }
8587 Ok(())
8588 }
8589
8590 fn update_worktree_diagnostics(
8591 &mut self,
8592 worktree_id: WorktreeId,
8593 server_id: LanguageServerId,
8594 path_in_worktree: Arc<RelPath>,
8595 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8596 _: &mut Context<Worktree>,
8597 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8598 let local = match &mut self.mode {
8599 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8600 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8601 };
8602
8603 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8604 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8605 let summaries_by_server_id = summaries_for_tree
8606 .entry(path_in_worktree.clone())
8607 .or_default();
8608
8609 let old_summary = summaries_by_server_id
8610 .remove(&server_id)
8611 .unwrap_or_default();
8612
8613 let new_summary = DiagnosticSummary::new(&diagnostics);
8614 if diagnostics.is_empty() {
8615 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8616 {
8617 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8618 diagnostics_by_server_id.remove(ix);
8619 }
8620 if diagnostics_by_server_id.is_empty() {
8621 diagnostics_for_tree.remove(&path_in_worktree);
8622 }
8623 }
8624 } else {
8625 summaries_by_server_id.insert(server_id, new_summary);
8626 let diagnostics_by_server_id = diagnostics_for_tree
8627 .entry(path_in_worktree.clone())
8628 .or_default();
8629 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8630 Ok(ix) => {
8631 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8632 }
8633 Err(ix) => {
8634 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8635 }
8636 }
8637 }
8638
8639 if !old_summary.is_empty() || !new_summary.is_empty() {
8640 if let Some((_, project_id)) = &self.downstream_client {
8641 Ok(ControlFlow::Continue(Some((
8642 *project_id,
8643 proto::DiagnosticSummary {
8644 path: path_in_worktree.to_proto(),
8645 language_server_id: server_id.0 as u64,
8646 error_count: new_summary.error_count as u32,
8647 warning_count: new_summary.warning_count as u32,
8648 },
8649 ))))
8650 } else {
8651 Ok(ControlFlow::Continue(None))
8652 }
8653 } else {
8654 Ok(ControlFlow::Break(()))
8655 }
8656 }
8657
8658 pub fn open_buffer_for_symbol(
8659 &mut self,
8660 symbol: &Symbol,
8661 cx: &mut Context<Self>,
8662 ) -> Task<Result<Entity<Buffer>>> {
8663 if let Some((client, project_id)) = self.upstream_client() {
8664 let request = client.request(proto::OpenBufferForSymbol {
8665 project_id,
8666 symbol: Some(Self::serialize_symbol(symbol)),
8667 });
8668 cx.spawn(async move |this, cx| {
8669 let response = request.await?;
8670 let buffer_id = BufferId::new(response.buffer_id)?;
8671 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8672 .await
8673 })
8674 } else if let Some(local) = self.as_local() {
8675 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8676 seed.worktree_id == symbol.source_worktree_id
8677 && state.id == symbol.source_language_server_id
8678 && symbol.language_server_name == seed.name
8679 });
8680 if !is_valid {
8681 return Task::ready(Err(anyhow!(
8682 "language server for worktree and language not found"
8683 )));
8684 };
8685
8686 let symbol_abs_path = match &symbol.path {
8687 SymbolLocation::InProject(project_path) => self
8688 .worktree_store
8689 .read(cx)
8690 .absolutize(&project_path, cx)
8691 .context("no such worktree"),
8692 SymbolLocation::OutsideProject {
8693 abs_path,
8694 signature: _,
8695 } => Ok(abs_path.to_path_buf()),
8696 };
8697 let symbol_abs_path = match symbol_abs_path {
8698 Ok(abs_path) => abs_path,
8699 Err(err) => return Task::ready(Err(err)),
8700 };
8701 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8702 uri
8703 } else {
8704 return Task::ready(Err(anyhow!("invalid symbol path")));
8705 };
8706
8707 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8708 } else {
8709 Task::ready(Err(anyhow!("no upstream client or local store")))
8710 }
8711 }
8712
8713 pub(crate) fn open_local_buffer_via_lsp(
8714 &mut self,
8715 abs_path: lsp::Uri,
8716 language_server_id: LanguageServerId,
8717 cx: &mut Context<Self>,
8718 ) -> Task<Result<Entity<Buffer>>> {
8719 cx.spawn(async move |lsp_store, cx| {
8720 // Escape percent-encoded string.
8721 let current_scheme = abs_path.scheme().to_owned();
8722 // Uri is immutable, so we can't modify the scheme
8723
8724 let abs_path = abs_path
8725 .to_file_path()
8726 .map_err(|()| anyhow!("can't convert URI to path"))?;
8727 let p = abs_path.clone();
8728 let yarn_worktree = lsp_store
8729 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8730 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8731 cx.spawn(async move |this, cx| {
8732 let t = this
8733 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8734 .ok()?;
8735 t.await
8736 })
8737 }),
8738 None => Task::ready(None),
8739 })?
8740 .await;
8741 let (worktree_root_target, known_relative_path) =
8742 if let Some((zip_root, relative_path)) = yarn_worktree {
8743 (zip_root, Some(relative_path))
8744 } else {
8745 (Arc::<Path>::from(abs_path.as_path()), None)
8746 };
8747 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8748 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8749 worktree_store.find_worktree(&worktree_root_target, cx)
8750 })
8751 })?;
8752 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8753 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8754 (result.0, relative_path, None)
8755 } else {
8756 let worktree = lsp_store
8757 .update(cx, |lsp_store, cx| {
8758 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8759 worktree_store.create_worktree(&worktree_root_target, false, cx)
8760 })
8761 })?
8762 .await?;
8763 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path())?;
8764 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local())? {
8765 lsp_store
8766 .update(cx, |lsp_store, cx| {
8767 if let Some(local) = lsp_store.as_local_mut() {
8768 local.register_language_server_for_invisible_worktree(
8769 &worktree,
8770 language_server_id,
8771 cx,
8772 )
8773 }
8774 match lsp_store.language_server_statuses.get(&language_server_id) {
8775 Some(status) => status.worktree,
8776 None => None,
8777 }
8778 })
8779 .ok()
8780 .flatten()
8781 .zip(Some(worktree_root.clone()))
8782 } else {
8783 None
8784 };
8785 let relative_path = if let Some(known_path) = known_relative_path {
8786 known_path
8787 } else {
8788 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8789 .into_arc()
8790 };
8791 (worktree, relative_path, source_ws)
8792 };
8793 let project_path = ProjectPath {
8794 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id())?,
8795 path: relative_path,
8796 };
8797 let buffer = lsp_store
8798 .update(cx, |lsp_store, cx| {
8799 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8800 buffer_store.open_buffer(project_path, cx)
8801 })
8802 })?
8803 .await?;
8804 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8805 if let Some((source_ws, worktree_root)) = source_ws {
8806 buffer.update(cx, |buffer, cx| {
8807 let settings = WorktreeSettings::get(
8808 Some(
8809 (&ProjectPath {
8810 worktree_id: source_ws,
8811 path: Arc::from(RelPath::empty()),
8812 })
8813 .into(),
8814 ),
8815 cx,
8816 );
8817 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8818 if is_read_only {
8819 buffer.set_capability(Capability::ReadOnly, cx);
8820 }
8821 })?;
8822 }
8823 Ok(buffer)
8824 })
8825 }
8826
8827 fn request_multiple_lsp_locally<P, R>(
8828 &mut self,
8829 buffer: &Entity<Buffer>,
8830 position: Option<P>,
8831 request: R,
8832 cx: &mut Context<Self>,
8833 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8834 where
8835 P: ToOffset,
8836 R: LspCommand + Clone,
8837 <R::LspRequest as lsp::request::Request>::Result: Send,
8838 <R::LspRequest as lsp::request::Request>::Params: Send,
8839 {
8840 let Some(local) = self.as_local() else {
8841 return Task::ready(Vec::new());
8842 };
8843
8844 let snapshot = buffer.read(cx).snapshot();
8845 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8846
8847 let server_ids = buffer.update(cx, |buffer, cx| {
8848 local
8849 .language_servers_for_buffer(buffer, cx)
8850 .filter(|(adapter, _)| {
8851 scope
8852 .as_ref()
8853 .map(|scope| scope.language_allowed(&adapter.name))
8854 .unwrap_or(true)
8855 })
8856 .map(|(_, server)| server.server_id())
8857 .filter(|server_id| {
8858 self.as_local().is_none_or(|local| {
8859 local
8860 .buffers_opened_in_servers
8861 .get(&snapshot.remote_id())
8862 .is_some_and(|servers| servers.contains(server_id))
8863 })
8864 })
8865 .collect::<Vec<_>>()
8866 });
8867
8868 let mut response_results = server_ids
8869 .into_iter()
8870 .map(|server_id| {
8871 let task = self.request_lsp(
8872 buffer.clone(),
8873 LanguageServerToQuery::Other(server_id),
8874 request.clone(),
8875 cx,
8876 );
8877 async move { (server_id, task.await) }
8878 })
8879 .collect::<FuturesUnordered<_>>();
8880
8881 cx.background_spawn(async move {
8882 let mut responses = Vec::with_capacity(response_results.len());
8883 while let Some((server_id, response_result)) = response_results.next().await {
8884 match response_result {
8885 Ok(response) => responses.push((server_id, response)),
8886 // rust-analyzer likes to error with this when its still loading up
8887 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8888 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8889 }
8890 }
8891 responses
8892 })
8893 }
8894
8895 async fn handle_lsp_get_completions(
8896 this: Entity<Self>,
8897 envelope: TypedEnvelope<proto::GetCompletions>,
8898 mut cx: AsyncApp,
8899 ) -> Result<proto::GetCompletionsResponse> {
8900 let sender_id = envelope.original_sender_id().unwrap_or_default();
8901
8902 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8903 let buffer_handle = this.update(&mut cx, |this, cx| {
8904 this.buffer_store.read(cx).get_existing(buffer_id)
8905 })??;
8906 let request = GetCompletions::from_proto(
8907 envelope.payload,
8908 this.clone(),
8909 buffer_handle.clone(),
8910 cx.clone(),
8911 )
8912 .await?;
8913
8914 let server_to_query = match request.server_id {
8915 Some(server_id) => LanguageServerToQuery::Other(server_id),
8916 None => LanguageServerToQuery::FirstCapable,
8917 };
8918
8919 let response = this
8920 .update(&mut cx, |this, cx| {
8921 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8922 })?
8923 .await?;
8924 this.update(&mut cx, |this, cx| {
8925 Ok(GetCompletions::response_to_proto(
8926 response,
8927 this,
8928 sender_id,
8929 &buffer_handle.read(cx).version(),
8930 cx,
8931 ))
8932 })?
8933 }
8934
8935 async fn handle_lsp_command<T: LspCommand>(
8936 this: Entity<Self>,
8937 envelope: TypedEnvelope<T::ProtoRequest>,
8938 mut cx: AsyncApp,
8939 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8940 where
8941 <T::LspRequest as lsp::request::Request>::Params: Send,
8942 <T::LspRequest as lsp::request::Request>::Result: Send,
8943 {
8944 let sender_id = envelope.original_sender_id().unwrap_or_default();
8945 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8946 let buffer_handle = this.update(&mut cx, |this, cx| {
8947 this.buffer_store.read(cx).get_existing(buffer_id)
8948 })??;
8949 let request = T::from_proto(
8950 envelope.payload,
8951 this.clone(),
8952 buffer_handle.clone(),
8953 cx.clone(),
8954 )
8955 .await?;
8956 let response = this
8957 .update(&mut cx, |this, cx| {
8958 this.request_lsp(
8959 buffer_handle.clone(),
8960 LanguageServerToQuery::FirstCapable,
8961 request,
8962 cx,
8963 )
8964 })?
8965 .await?;
8966 this.update(&mut cx, |this, cx| {
8967 Ok(T::response_to_proto(
8968 response,
8969 this,
8970 sender_id,
8971 &buffer_handle.read(cx).version(),
8972 cx,
8973 ))
8974 })?
8975 }
8976
8977 async fn handle_lsp_query(
8978 lsp_store: Entity<Self>,
8979 envelope: TypedEnvelope<proto::LspQuery>,
8980 mut cx: AsyncApp,
8981 ) -> Result<proto::Ack> {
8982 use proto::lsp_query::Request;
8983 let sender_id = envelope.original_sender_id().unwrap_or_default();
8984 let lsp_query = envelope.payload;
8985 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8986 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8987 match lsp_query.request.context("invalid LSP query request")? {
8988 Request::GetReferences(get_references) => {
8989 let position = get_references.position.clone().and_then(deserialize_anchor);
8990 Self::query_lsp_locally::<GetReferences>(
8991 lsp_store,
8992 server_id,
8993 sender_id,
8994 lsp_request_id,
8995 get_references,
8996 position,
8997 &mut cx,
8998 )
8999 .await?;
9000 }
9001 Request::GetDocumentColor(get_document_color) => {
9002 Self::query_lsp_locally::<GetDocumentColor>(
9003 lsp_store,
9004 server_id,
9005 sender_id,
9006 lsp_request_id,
9007 get_document_color,
9008 None,
9009 &mut cx,
9010 )
9011 .await?;
9012 }
9013 Request::GetHover(get_hover) => {
9014 let position = get_hover.position.clone().and_then(deserialize_anchor);
9015 Self::query_lsp_locally::<GetHover>(
9016 lsp_store,
9017 server_id,
9018 sender_id,
9019 lsp_request_id,
9020 get_hover,
9021 position,
9022 &mut cx,
9023 )
9024 .await?;
9025 }
9026 Request::GetCodeActions(get_code_actions) => {
9027 Self::query_lsp_locally::<GetCodeActions>(
9028 lsp_store,
9029 server_id,
9030 sender_id,
9031 lsp_request_id,
9032 get_code_actions,
9033 None,
9034 &mut cx,
9035 )
9036 .await?;
9037 }
9038 Request::GetSignatureHelp(get_signature_help) => {
9039 let position = get_signature_help
9040 .position
9041 .clone()
9042 .and_then(deserialize_anchor);
9043 Self::query_lsp_locally::<GetSignatureHelp>(
9044 lsp_store,
9045 server_id,
9046 sender_id,
9047 lsp_request_id,
9048 get_signature_help,
9049 position,
9050 &mut cx,
9051 )
9052 .await?;
9053 }
9054 Request::GetCodeLens(get_code_lens) => {
9055 Self::query_lsp_locally::<GetCodeLens>(
9056 lsp_store,
9057 server_id,
9058 sender_id,
9059 lsp_request_id,
9060 get_code_lens,
9061 None,
9062 &mut cx,
9063 )
9064 .await?;
9065 }
9066 Request::GetDefinition(get_definition) => {
9067 let position = get_definition.position.clone().and_then(deserialize_anchor);
9068 Self::query_lsp_locally::<GetDefinitions>(
9069 lsp_store,
9070 server_id,
9071 sender_id,
9072 lsp_request_id,
9073 get_definition,
9074 position,
9075 &mut cx,
9076 )
9077 .await?;
9078 }
9079 Request::GetDeclaration(get_declaration) => {
9080 let position = get_declaration
9081 .position
9082 .clone()
9083 .and_then(deserialize_anchor);
9084 Self::query_lsp_locally::<GetDeclarations>(
9085 lsp_store,
9086 server_id,
9087 sender_id,
9088 lsp_request_id,
9089 get_declaration,
9090 position,
9091 &mut cx,
9092 )
9093 .await?;
9094 }
9095 Request::GetTypeDefinition(get_type_definition) => {
9096 let position = get_type_definition
9097 .position
9098 .clone()
9099 .and_then(deserialize_anchor);
9100 Self::query_lsp_locally::<GetTypeDefinitions>(
9101 lsp_store,
9102 server_id,
9103 sender_id,
9104 lsp_request_id,
9105 get_type_definition,
9106 position,
9107 &mut cx,
9108 )
9109 .await?;
9110 }
9111 Request::GetImplementation(get_implementation) => {
9112 let position = get_implementation
9113 .position
9114 .clone()
9115 .and_then(deserialize_anchor);
9116 Self::query_lsp_locally::<GetImplementations>(
9117 lsp_store,
9118 server_id,
9119 sender_id,
9120 lsp_request_id,
9121 get_implementation,
9122 position,
9123 &mut cx,
9124 )
9125 .await?;
9126 }
9127 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9128 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9129 let version = deserialize_version(get_document_diagnostics.buffer_version());
9130 let buffer = lsp_store.update(&mut cx, |this, cx| {
9131 this.buffer_store.read(cx).get_existing(buffer_id)
9132 })??;
9133 buffer
9134 .update(&mut cx, |buffer, _| {
9135 buffer.wait_for_version(version.clone())
9136 })?
9137 .await?;
9138 lsp_store.update(&mut cx, |lsp_store, cx| {
9139 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9140 let key = LspKey {
9141 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9142 server_queried: server_id,
9143 };
9144 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9145 ) {
9146 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9147 lsp_requests.clear();
9148 };
9149 }
9150
9151 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9152 existing_queries.insert(
9153 lsp_request_id,
9154 cx.spawn(async move |lsp_store, cx| {
9155 let diagnostics_pull = lsp_store
9156 .update(cx, |lsp_store, cx| {
9157 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9158 })
9159 .ok();
9160 if let Some(diagnostics_pull) = diagnostics_pull {
9161 match diagnostics_pull.await {
9162 Ok(()) => {}
9163 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9164 };
9165 }
9166 }),
9167 );
9168 })?;
9169 }
9170 Request::InlayHints(inlay_hints) => {
9171 let query_start = inlay_hints
9172 .start
9173 .clone()
9174 .and_then(deserialize_anchor)
9175 .context("invalid inlay hints range start")?;
9176 let query_end = inlay_hints
9177 .end
9178 .clone()
9179 .and_then(deserialize_anchor)
9180 .context("invalid inlay hints range end")?;
9181 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9182 &lsp_store,
9183 server_id,
9184 lsp_request_id,
9185 &inlay_hints,
9186 query_start..query_end,
9187 &mut cx,
9188 )
9189 .await
9190 .context("preparing inlay hints request")?;
9191 Self::query_lsp_locally::<InlayHints>(
9192 lsp_store,
9193 server_id,
9194 sender_id,
9195 lsp_request_id,
9196 inlay_hints,
9197 None,
9198 &mut cx,
9199 )
9200 .await
9201 .context("querying for inlay hints")?
9202 }
9203 }
9204 Ok(proto::Ack {})
9205 }
9206
9207 async fn handle_lsp_query_response(
9208 lsp_store: Entity<Self>,
9209 envelope: TypedEnvelope<proto::LspQueryResponse>,
9210 cx: AsyncApp,
9211 ) -> Result<()> {
9212 lsp_store.read_with(&cx, |lsp_store, _| {
9213 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9214 upstream_client.handle_lsp_response(envelope.clone());
9215 }
9216 })?;
9217 Ok(())
9218 }
9219
9220 async fn handle_apply_code_action(
9221 this: Entity<Self>,
9222 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9223 mut cx: AsyncApp,
9224 ) -> Result<proto::ApplyCodeActionResponse> {
9225 let sender_id = envelope.original_sender_id().unwrap_or_default();
9226 let action =
9227 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9228 let apply_code_action = this.update(&mut cx, |this, cx| {
9229 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9230 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9231 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9232 })??;
9233
9234 let project_transaction = apply_code_action.await?;
9235 let project_transaction = this.update(&mut cx, |this, cx| {
9236 this.buffer_store.update(cx, |buffer_store, cx| {
9237 buffer_store.serialize_project_transaction_for_peer(
9238 project_transaction,
9239 sender_id,
9240 cx,
9241 )
9242 })
9243 })?;
9244 Ok(proto::ApplyCodeActionResponse {
9245 transaction: Some(project_transaction),
9246 })
9247 }
9248
9249 async fn handle_register_buffer_with_language_servers(
9250 this: Entity<Self>,
9251 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9252 mut cx: AsyncApp,
9253 ) -> Result<proto::Ack> {
9254 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9255 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9256 this.update(&mut cx, |this, cx| {
9257 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9258 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9259 project_id: upstream_project_id,
9260 buffer_id: buffer_id.to_proto(),
9261 only_servers: envelope.payload.only_servers,
9262 });
9263 }
9264
9265 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9266 anyhow::bail!("buffer is not open");
9267 };
9268
9269 let handle = this.register_buffer_with_language_servers(
9270 &buffer,
9271 envelope
9272 .payload
9273 .only_servers
9274 .into_iter()
9275 .filter_map(|selector| {
9276 Some(match selector.selector? {
9277 proto::language_server_selector::Selector::ServerId(server_id) => {
9278 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9279 }
9280 proto::language_server_selector::Selector::Name(name) => {
9281 LanguageServerSelector::Name(LanguageServerName(
9282 SharedString::from(name),
9283 ))
9284 }
9285 })
9286 })
9287 .collect(),
9288 false,
9289 cx,
9290 );
9291 this.buffer_store().update(cx, |buffer_store, _| {
9292 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9293 });
9294
9295 Ok(())
9296 })??;
9297 Ok(proto::Ack {})
9298 }
9299
9300 async fn handle_rename_project_entry(
9301 this: Entity<Self>,
9302 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9303 mut cx: AsyncApp,
9304 ) -> Result<proto::ProjectEntryResponse> {
9305 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9306 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9307 let new_path =
9308 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9309
9310 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9311 .update(&mut cx, |this, cx| {
9312 let (worktree, entry) = this
9313 .worktree_store
9314 .read(cx)
9315 .worktree_and_entry_for_id(entry_id, cx)?;
9316 let new_worktree = this
9317 .worktree_store
9318 .read(cx)
9319 .worktree_for_id(new_worktree_id, cx)?;
9320 Some((
9321 this.worktree_store.clone(),
9322 worktree,
9323 new_worktree,
9324 entry.clone(),
9325 ))
9326 })?
9327 .context("worktree not found")?;
9328 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9329 (worktree.absolutize(&old_entry.path), worktree.id())
9330 })?;
9331 let new_abs_path =
9332 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path))?;
9333
9334 let _transaction = Self::will_rename_entry(
9335 this.downgrade(),
9336 old_worktree_id,
9337 &old_abs_path,
9338 &new_abs_path,
9339 old_entry.is_dir(),
9340 cx.clone(),
9341 )
9342 .await;
9343 let response = WorktreeStore::handle_rename_project_entry(
9344 worktree_store,
9345 envelope.payload,
9346 cx.clone(),
9347 )
9348 .await;
9349 this.read_with(&cx, |this, _| {
9350 this.did_rename_entry(
9351 old_worktree_id,
9352 &old_abs_path,
9353 &new_abs_path,
9354 old_entry.is_dir(),
9355 );
9356 })
9357 .ok();
9358 response
9359 }
9360
9361 async fn handle_update_diagnostic_summary(
9362 this: Entity<Self>,
9363 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9364 mut cx: AsyncApp,
9365 ) -> Result<()> {
9366 this.update(&mut cx, |lsp_store, cx| {
9367 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9368 let mut updated_diagnostics_paths = HashMap::default();
9369 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9370 for message_summary in envelope
9371 .payload
9372 .summary
9373 .into_iter()
9374 .chain(envelope.payload.more_summaries)
9375 {
9376 let project_path = ProjectPath {
9377 worktree_id,
9378 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9379 };
9380 let path = project_path.path.clone();
9381 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9382 let summary = DiagnosticSummary {
9383 error_count: message_summary.error_count as usize,
9384 warning_count: message_summary.warning_count as usize,
9385 };
9386
9387 if summary.is_empty() {
9388 if let Some(worktree_summaries) =
9389 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9390 && let Some(summaries) = worktree_summaries.get_mut(&path)
9391 {
9392 summaries.remove(&server_id);
9393 if summaries.is_empty() {
9394 worktree_summaries.remove(&path);
9395 }
9396 }
9397 } else {
9398 lsp_store
9399 .diagnostic_summaries
9400 .entry(worktree_id)
9401 .or_default()
9402 .entry(path)
9403 .or_default()
9404 .insert(server_id, summary);
9405 }
9406
9407 if let Some((_, project_id)) = &lsp_store.downstream_client {
9408 match &mut diagnostics_summary {
9409 Some(diagnostics_summary) => {
9410 diagnostics_summary
9411 .more_summaries
9412 .push(proto::DiagnosticSummary {
9413 path: project_path.path.as_ref().to_proto(),
9414 language_server_id: server_id.0 as u64,
9415 error_count: summary.error_count as u32,
9416 warning_count: summary.warning_count as u32,
9417 })
9418 }
9419 None => {
9420 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9421 project_id: *project_id,
9422 worktree_id: worktree_id.to_proto(),
9423 summary: Some(proto::DiagnosticSummary {
9424 path: project_path.path.as_ref().to_proto(),
9425 language_server_id: server_id.0 as u64,
9426 error_count: summary.error_count as u32,
9427 warning_count: summary.warning_count as u32,
9428 }),
9429 more_summaries: Vec::new(),
9430 })
9431 }
9432 }
9433 }
9434 updated_diagnostics_paths
9435 .entry(server_id)
9436 .or_insert_with(Vec::new)
9437 .push(project_path);
9438 }
9439
9440 if let Some((diagnostics_summary, (downstream_client, _))) =
9441 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9442 {
9443 downstream_client.send(diagnostics_summary).log_err();
9444 }
9445 for (server_id, paths) in updated_diagnostics_paths {
9446 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9447 }
9448 Ok(())
9449 })?
9450 }
9451
9452 async fn handle_start_language_server(
9453 lsp_store: Entity<Self>,
9454 envelope: TypedEnvelope<proto::StartLanguageServer>,
9455 mut cx: AsyncApp,
9456 ) -> Result<()> {
9457 let server = envelope.payload.server.context("invalid server")?;
9458 let server_capabilities =
9459 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9460 .with_context(|| {
9461 format!(
9462 "incorrect server capabilities {}",
9463 envelope.payload.capabilities
9464 )
9465 })?;
9466 lsp_store.update(&mut cx, |lsp_store, cx| {
9467 let server_id = LanguageServerId(server.id as usize);
9468 let server_name = LanguageServerName::from_proto(server.name.clone());
9469 lsp_store
9470 .lsp_server_capabilities
9471 .insert(server_id, server_capabilities);
9472 lsp_store.language_server_statuses.insert(
9473 server_id,
9474 LanguageServerStatus {
9475 name: server_name.clone(),
9476 server_version: None,
9477 pending_work: Default::default(),
9478 has_pending_diagnostic_updates: false,
9479 progress_tokens: Default::default(),
9480 worktree: server.worktree_id.map(WorktreeId::from_proto),
9481 binary: None,
9482 configuration: None,
9483 workspace_folders: BTreeSet::new(),
9484 },
9485 );
9486 cx.emit(LspStoreEvent::LanguageServerAdded(
9487 server_id,
9488 server_name,
9489 server.worktree_id.map(WorktreeId::from_proto),
9490 ));
9491 cx.notify();
9492 })?;
9493 Ok(())
9494 }
9495
9496 async fn handle_update_language_server(
9497 lsp_store: Entity<Self>,
9498 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9499 mut cx: AsyncApp,
9500 ) -> Result<()> {
9501 lsp_store.update(&mut cx, |lsp_store, cx| {
9502 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9503
9504 match envelope.payload.variant.context("invalid variant")? {
9505 proto::update_language_server::Variant::WorkStart(payload) => {
9506 lsp_store.on_lsp_work_start(
9507 language_server_id,
9508 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9509 .context("invalid progress token value")?,
9510 LanguageServerProgress {
9511 title: payload.title,
9512 is_disk_based_diagnostics_progress: false,
9513 is_cancellable: payload.is_cancellable.unwrap_or(false),
9514 message: payload.message,
9515 percentage: payload.percentage.map(|p| p as usize),
9516 last_update_at: cx.background_executor().now(),
9517 },
9518 cx,
9519 );
9520 }
9521 proto::update_language_server::Variant::WorkProgress(payload) => {
9522 lsp_store.on_lsp_work_progress(
9523 language_server_id,
9524 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9525 .context("invalid progress token value")?,
9526 LanguageServerProgress {
9527 title: None,
9528 is_disk_based_diagnostics_progress: false,
9529 is_cancellable: payload.is_cancellable.unwrap_or(false),
9530 message: payload.message,
9531 percentage: payload.percentage.map(|p| p as usize),
9532 last_update_at: cx.background_executor().now(),
9533 },
9534 cx,
9535 );
9536 }
9537
9538 proto::update_language_server::Variant::WorkEnd(payload) => {
9539 lsp_store.on_lsp_work_end(
9540 language_server_id,
9541 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9542 .context("invalid progress token value")?,
9543 cx,
9544 );
9545 }
9546
9547 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9548 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9549 }
9550
9551 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9552 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9553 }
9554
9555 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9556 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9557 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9558 cx.emit(LspStoreEvent::LanguageServerUpdate {
9559 language_server_id,
9560 name: envelope
9561 .payload
9562 .server_name
9563 .map(SharedString::new)
9564 .map(LanguageServerName),
9565 message: non_lsp,
9566 });
9567 }
9568 }
9569
9570 Ok(())
9571 })?
9572 }
9573
9574 async fn handle_language_server_log(
9575 this: Entity<Self>,
9576 envelope: TypedEnvelope<proto::LanguageServerLog>,
9577 mut cx: AsyncApp,
9578 ) -> Result<()> {
9579 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9580 let log_type = envelope
9581 .payload
9582 .log_type
9583 .map(LanguageServerLogType::from_proto)
9584 .context("invalid language server log type")?;
9585
9586 let message = envelope.payload.message;
9587
9588 this.update(&mut cx, |_, cx| {
9589 cx.emit(LspStoreEvent::LanguageServerLog(
9590 language_server_id,
9591 log_type,
9592 message,
9593 ));
9594 })
9595 }
9596
9597 async fn handle_lsp_ext_cancel_flycheck(
9598 lsp_store: Entity<Self>,
9599 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9600 cx: AsyncApp,
9601 ) -> Result<proto::Ack> {
9602 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9603 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9604 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9605 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9606 } else {
9607 None
9608 }
9609 })?;
9610 if let Some(task) = task {
9611 task.context("handling lsp ext cancel flycheck")?;
9612 }
9613
9614 Ok(proto::Ack {})
9615 }
9616
9617 async fn handle_lsp_ext_run_flycheck(
9618 lsp_store: Entity<Self>,
9619 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9620 mut cx: AsyncApp,
9621 ) -> Result<proto::Ack> {
9622 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9623 lsp_store.update(&mut cx, |lsp_store, cx| {
9624 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9625 let text_document = if envelope.payload.current_file_only {
9626 let buffer_id = envelope
9627 .payload
9628 .buffer_id
9629 .map(|id| BufferId::new(id))
9630 .transpose()?;
9631 buffer_id
9632 .and_then(|buffer_id| {
9633 lsp_store
9634 .buffer_store()
9635 .read(cx)
9636 .get(buffer_id)
9637 .and_then(|buffer| {
9638 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9639 })
9640 .map(|path| make_text_document_identifier(&path))
9641 })
9642 .transpose()?
9643 } else {
9644 None
9645 };
9646 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9647 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9648 )?;
9649 }
9650 anyhow::Ok(())
9651 })??;
9652
9653 Ok(proto::Ack {})
9654 }
9655
9656 async fn handle_lsp_ext_clear_flycheck(
9657 lsp_store: Entity<Self>,
9658 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9659 cx: AsyncApp,
9660 ) -> Result<proto::Ack> {
9661 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9662 lsp_store
9663 .read_with(&cx, |lsp_store, _| {
9664 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9665 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9666 } else {
9667 None
9668 }
9669 })
9670 .context("handling lsp ext clear flycheck")?;
9671
9672 Ok(proto::Ack {})
9673 }
9674
9675 pub fn disk_based_diagnostics_started(
9676 &mut self,
9677 language_server_id: LanguageServerId,
9678 cx: &mut Context<Self>,
9679 ) {
9680 if let Some(language_server_status) =
9681 self.language_server_statuses.get_mut(&language_server_id)
9682 {
9683 language_server_status.has_pending_diagnostic_updates = true;
9684 }
9685
9686 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9687 cx.emit(LspStoreEvent::LanguageServerUpdate {
9688 language_server_id,
9689 name: self
9690 .language_server_adapter_for_id(language_server_id)
9691 .map(|adapter| adapter.name()),
9692 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9693 Default::default(),
9694 ),
9695 })
9696 }
9697
9698 pub fn disk_based_diagnostics_finished(
9699 &mut self,
9700 language_server_id: LanguageServerId,
9701 cx: &mut Context<Self>,
9702 ) {
9703 if let Some(language_server_status) =
9704 self.language_server_statuses.get_mut(&language_server_id)
9705 {
9706 language_server_status.has_pending_diagnostic_updates = false;
9707 }
9708
9709 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9710 cx.emit(LspStoreEvent::LanguageServerUpdate {
9711 language_server_id,
9712 name: self
9713 .language_server_adapter_for_id(language_server_id)
9714 .map(|adapter| adapter.name()),
9715 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9716 Default::default(),
9717 ),
9718 })
9719 }
9720
9721 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9722 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9723 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9724 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9725 // the language server might take some time to publish diagnostics.
9726 fn simulate_disk_based_diagnostics_events_if_needed(
9727 &mut self,
9728 language_server_id: LanguageServerId,
9729 cx: &mut Context<Self>,
9730 ) {
9731 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9732
9733 let Some(LanguageServerState::Running {
9734 simulate_disk_based_diagnostics_completion,
9735 adapter,
9736 ..
9737 }) = self
9738 .as_local_mut()
9739 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9740 else {
9741 return;
9742 };
9743
9744 if adapter.disk_based_diagnostics_progress_token.is_some() {
9745 return;
9746 }
9747
9748 let prev_task =
9749 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9750 cx.background_executor()
9751 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9752 .await;
9753
9754 this.update(cx, |this, cx| {
9755 this.disk_based_diagnostics_finished(language_server_id, cx);
9756
9757 if let Some(LanguageServerState::Running {
9758 simulate_disk_based_diagnostics_completion,
9759 ..
9760 }) = this.as_local_mut().and_then(|local_store| {
9761 local_store.language_servers.get_mut(&language_server_id)
9762 }) {
9763 *simulate_disk_based_diagnostics_completion = None;
9764 }
9765 })
9766 .ok();
9767 }));
9768
9769 if prev_task.is_none() {
9770 self.disk_based_diagnostics_started(language_server_id, cx);
9771 }
9772 }
9773
9774 pub fn language_server_statuses(
9775 &self,
9776 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9777 self.language_server_statuses
9778 .iter()
9779 .map(|(key, value)| (*key, value))
9780 }
9781
9782 pub(super) fn did_rename_entry(
9783 &self,
9784 worktree_id: WorktreeId,
9785 old_path: &Path,
9786 new_path: &Path,
9787 is_dir: bool,
9788 ) {
9789 maybe!({
9790 let local_store = self.as_local()?;
9791
9792 let old_uri = lsp::Uri::from_file_path(old_path)
9793 .ok()
9794 .map(|uri| uri.to_string())?;
9795 let new_uri = lsp::Uri::from_file_path(new_path)
9796 .ok()
9797 .map(|uri| uri.to_string())?;
9798
9799 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9800 let Some(filter) = local_store
9801 .language_server_paths_watched_for_rename
9802 .get(&language_server.server_id())
9803 else {
9804 continue;
9805 };
9806
9807 if filter.should_send_did_rename(&old_uri, is_dir) {
9808 language_server
9809 .notify::<DidRenameFiles>(RenameFilesParams {
9810 files: vec![FileRename {
9811 old_uri: old_uri.clone(),
9812 new_uri: new_uri.clone(),
9813 }],
9814 })
9815 .ok();
9816 }
9817 }
9818 Some(())
9819 });
9820 }
9821
9822 pub(super) fn will_rename_entry(
9823 this: WeakEntity<Self>,
9824 worktree_id: WorktreeId,
9825 old_path: &Path,
9826 new_path: &Path,
9827 is_dir: bool,
9828 cx: AsyncApp,
9829 ) -> Task<ProjectTransaction> {
9830 let old_uri = lsp::Uri::from_file_path(old_path)
9831 .ok()
9832 .map(|uri| uri.to_string());
9833 let new_uri = lsp::Uri::from_file_path(new_path)
9834 .ok()
9835 .map(|uri| uri.to_string());
9836 cx.spawn(async move |cx| {
9837 let mut tasks = vec![];
9838 this.update(cx, |this, cx| {
9839 let local_store = this.as_local()?;
9840 let old_uri = old_uri?;
9841 let new_uri = new_uri?;
9842 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9843 let Some(filter) = local_store
9844 .language_server_paths_watched_for_rename
9845 .get(&language_server.server_id())
9846 else {
9847 continue;
9848 };
9849
9850 if filter.should_send_will_rename(&old_uri, is_dir) {
9851 let apply_edit = cx.spawn({
9852 let old_uri = old_uri.clone();
9853 let new_uri = new_uri.clone();
9854 let language_server = language_server.clone();
9855 async move |this, cx| {
9856 let edit = language_server
9857 .request::<WillRenameFiles>(RenameFilesParams {
9858 files: vec![FileRename { old_uri, new_uri }],
9859 })
9860 .await
9861 .into_response()
9862 .context("will rename files")
9863 .log_err()
9864 .flatten()?;
9865
9866 let transaction = LocalLspStore::deserialize_workspace_edit(
9867 this.upgrade()?,
9868 edit,
9869 false,
9870 language_server.clone(),
9871 cx,
9872 )
9873 .await
9874 .ok()?;
9875 Some(transaction)
9876 }
9877 });
9878 tasks.push(apply_edit);
9879 }
9880 }
9881 Some(())
9882 })
9883 .ok()
9884 .flatten();
9885 let mut merged_transaction = ProjectTransaction::default();
9886 for task in tasks {
9887 // Await on tasks sequentially so that the order of application of edits is deterministic
9888 // (at least with regards to the order of registration of language servers)
9889 if let Some(transaction) = task.await {
9890 for (buffer, buffer_transaction) in transaction.0 {
9891 merged_transaction.0.insert(buffer, buffer_transaction);
9892 }
9893 }
9894 }
9895 merged_transaction
9896 })
9897 }
9898
9899 fn lsp_notify_abs_paths_changed(
9900 &mut self,
9901 server_id: LanguageServerId,
9902 changes: Vec<PathEvent>,
9903 ) {
9904 maybe!({
9905 let server = self.language_server_for_id(server_id)?;
9906 let changes = changes
9907 .into_iter()
9908 .filter_map(|event| {
9909 let typ = match event.kind? {
9910 PathEventKind::Created => lsp::FileChangeType::CREATED,
9911 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9912 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9913 };
9914 Some(lsp::FileEvent {
9915 uri: file_path_to_lsp_url(&event.path).log_err()?,
9916 typ,
9917 })
9918 })
9919 .collect::<Vec<_>>();
9920 if !changes.is_empty() {
9921 server
9922 .notify::<lsp::notification::DidChangeWatchedFiles>(
9923 lsp::DidChangeWatchedFilesParams { changes },
9924 )
9925 .ok();
9926 }
9927 Some(())
9928 });
9929 }
9930
9931 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9932 self.as_local()?.language_server_for_id(id)
9933 }
9934
9935 fn on_lsp_progress(
9936 &mut self,
9937 progress_params: lsp::ProgressParams,
9938 language_server_id: LanguageServerId,
9939 disk_based_diagnostics_progress_token: Option<String>,
9940 cx: &mut Context<Self>,
9941 ) {
9942 match progress_params.value {
9943 lsp::ProgressParamsValue::WorkDone(progress) => {
9944 self.handle_work_done_progress(
9945 progress,
9946 language_server_id,
9947 disk_based_diagnostics_progress_token,
9948 ProgressToken::from_lsp(progress_params.token),
9949 cx,
9950 );
9951 }
9952 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9953 let registration_id = match progress_params.token {
9954 lsp::NumberOrString::Number(_) => None,
9955 lsp::NumberOrString::String(token) => token
9956 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9957 .map(|(_, id)| id.to_owned()),
9958 };
9959 if let Some(LanguageServerState::Running {
9960 workspace_diagnostics_refresh_tasks,
9961 ..
9962 }) = self
9963 .as_local_mut()
9964 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9965 && let Some(workspace_diagnostics) =
9966 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9967 {
9968 workspace_diagnostics.progress_tx.try_send(()).ok();
9969 self.apply_workspace_diagnostic_report(
9970 language_server_id,
9971 report,
9972 registration_id.map(SharedString::from),
9973 cx,
9974 )
9975 }
9976 }
9977 }
9978 }
9979
9980 fn handle_work_done_progress(
9981 &mut self,
9982 progress: lsp::WorkDoneProgress,
9983 language_server_id: LanguageServerId,
9984 disk_based_diagnostics_progress_token: Option<String>,
9985 token: ProgressToken,
9986 cx: &mut Context<Self>,
9987 ) {
9988 let language_server_status =
9989 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9990 status
9991 } else {
9992 return;
9993 };
9994
9995 if !language_server_status.progress_tokens.contains(&token) {
9996 return;
9997 }
9998
9999 let is_disk_based_diagnostics_progress =
10000 if let (Some(disk_based_token), ProgressToken::String(token)) =
10001 (&disk_based_diagnostics_progress_token, &token)
10002 {
10003 token.starts_with(disk_based_token)
10004 } else {
10005 false
10006 };
10007
10008 match progress {
10009 lsp::WorkDoneProgress::Begin(report) => {
10010 if is_disk_based_diagnostics_progress {
10011 self.disk_based_diagnostics_started(language_server_id, cx);
10012 }
10013 self.on_lsp_work_start(
10014 language_server_id,
10015 token.clone(),
10016 LanguageServerProgress {
10017 title: Some(report.title),
10018 is_disk_based_diagnostics_progress,
10019 is_cancellable: report.cancellable.unwrap_or(false),
10020 message: report.message.clone(),
10021 percentage: report.percentage.map(|p| p as usize),
10022 last_update_at: cx.background_executor().now(),
10023 },
10024 cx,
10025 );
10026 }
10027 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10028 language_server_id,
10029 token,
10030 LanguageServerProgress {
10031 title: None,
10032 is_disk_based_diagnostics_progress,
10033 is_cancellable: report.cancellable.unwrap_or(false),
10034 message: report.message,
10035 percentage: report.percentage.map(|p| p as usize),
10036 last_update_at: cx.background_executor().now(),
10037 },
10038 cx,
10039 ),
10040 lsp::WorkDoneProgress::End(_) => {
10041 language_server_status.progress_tokens.remove(&token);
10042 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10043 if is_disk_based_diagnostics_progress {
10044 self.disk_based_diagnostics_finished(language_server_id, cx);
10045 }
10046 }
10047 }
10048 }
10049
10050 fn on_lsp_work_start(
10051 &mut self,
10052 language_server_id: LanguageServerId,
10053 token: ProgressToken,
10054 progress: LanguageServerProgress,
10055 cx: &mut Context<Self>,
10056 ) {
10057 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10058 status.pending_work.insert(token.clone(), progress.clone());
10059 cx.notify();
10060 }
10061 cx.emit(LspStoreEvent::LanguageServerUpdate {
10062 language_server_id,
10063 name: self
10064 .language_server_adapter_for_id(language_server_id)
10065 .map(|adapter| adapter.name()),
10066 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10067 token: Some(token.to_proto()),
10068 title: progress.title,
10069 message: progress.message,
10070 percentage: progress.percentage.map(|p| p as u32),
10071 is_cancellable: Some(progress.is_cancellable),
10072 }),
10073 })
10074 }
10075
10076 fn on_lsp_work_progress(
10077 &mut self,
10078 language_server_id: LanguageServerId,
10079 token: ProgressToken,
10080 progress: LanguageServerProgress,
10081 cx: &mut Context<Self>,
10082 ) {
10083 let mut did_update = false;
10084 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10085 match status.pending_work.entry(token.clone()) {
10086 btree_map::Entry::Vacant(entry) => {
10087 entry.insert(progress.clone());
10088 did_update = true;
10089 }
10090 btree_map::Entry::Occupied(mut entry) => {
10091 let entry = entry.get_mut();
10092 if (progress.last_update_at - entry.last_update_at)
10093 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10094 {
10095 entry.last_update_at = progress.last_update_at;
10096 if progress.message.is_some() {
10097 entry.message = progress.message.clone();
10098 }
10099 if progress.percentage.is_some() {
10100 entry.percentage = progress.percentage;
10101 }
10102 if progress.is_cancellable != entry.is_cancellable {
10103 entry.is_cancellable = progress.is_cancellable;
10104 }
10105 did_update = true;
10106 }
10107 }
10108 }
10109 }
10110
10111 if did_update {
10112 cx.emit(LspStoreEvent::LanguageServerUpdate {
10113 language_server_id,
10114 name: self
10115 .language_server_adapter_for_id(language_server_id)
10116 .map(|adapter| adapter.name()),
10117 message: proto::update_language_server::Variant::WorkProgress(
10118 proto::LspWorkProgress {
10119 token: Some(token.to_proto()),
10120 message: progress.message,
10121 percentage: progress.percentage.map(|p| p as u32),
10122 is_cancellable: Some(progress.is_cancellable),
10123 },
10124 ),
10125 })
10126 }
10127 }
10128
10129 fn on_lsp_work_end(
10130 &mut self,
10131 language_server_id: LanguageServerId,
10132 token: ProgressToken,
10133 cx: &mut Context<Self>,
10134 ) {
10135 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10136 if let Some(work) = status.pending_work.remove(&token)
10137 && !work.is_disk_based_diagnostics_progress
10138 {
10139 cx.emit(LspStoreEvent::RefreshInlayHints {
10140 server_id: language_server_id,
10141 request_id: None,
10142 });
10143 }
10144 cx.notify();
10145 }
10146
10147 cx.emit(LspStoreEvent::LanguageServerUpdate {
10148 language_server_id,
10149 name: self
10150 .language_server_adapter_for_id(language_server_id)
10151 .map(|adapter| adapter.name()),
10152 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10153 token: Some(token.to_proto()),
10154 }),
10155 })
10156 }
10157
10158 pub async fn handle_resolve_completion_documentation(
10159 this: Entity<Self>,
10160 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10161 mut cx: AsyncApp,
10162 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10163 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10164
10165 let completion = this
10166 .read_with(&cx, |this, cx| {
10167 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10168 let server = this
10169 .language_server_for_id(id)
10170 .with_context(|| format!("No language server {id}"))?;
10171
10172 anyhow::Ok(cx.background_spawn(async move {
10173 let can_resolve = server
10174 .capabilities()
10175 .completion_provider
10176 .as_ref()
10177 .and_then(|options| options.resolve_provider)
10178 .unwrap_or(false);
10179 if can_resolve {
10180 server
10181 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10182 .await
10183 .into_response()
10184 .context("resolve completion item")
10185 } else {
10186 anyhow::Ok(lsp_completion)
10187 }
10188 }))
10189 })??
10190 .await?;
10191
10192 let mut documentation_is_markdown = false;
10193 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10194 let documentation = match completion.documentation {
10195 Some(lsp::Documentation::String(text)) => text,
10196
10197 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10198 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10199 value
10200 }
10201
10202 _ => String::new(),
10203 };
10204
10205 // If we have a new buffer_id, that means we're talking to a new client
10206 // and want to check for new text_edits in the completion too.
10207 let mut old_replace_start = None;
10208 let mut old_replace_end = None;
10209 let mut old_insert_start = None;
10210 let mut old_insert_end = None;
10211 let mut new_text = String::default();
10212 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10213 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10214 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10215 anyhow::Ok(buffer.read(cx).snapshot())
10216 })??;
10217
10218 if let Some(text_edit) = completion.text_edit.as_ref() {
10219 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10220
10221 if let Some(mut edit) = edit {
10222 LineEnding::normalize(&mut edit.new_text);
10223
10224 new_text = edit.new_text;
10225 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10226 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10227 if let Some(insert_range) = edit.insert_range {
10228 old_insert_start = Some(serialize_anchor(&insert_range.start));
10229 old_insert_end = Some(serialize_anchor(&insert_range.end));
10230 }
10231 }
10232 }
10233 }
10234
10235 Ok(proto::ResolveCompletionDocumentationResponse {
10236 documentation,
10237 documentation_is_markdown,
10238 old_replace_start,
10239 old_replace_end,
10240 new_text,
10241 lsp_completion,
10242 old_insert_start,
10243 old_insert_end,
10244 })
10245 }
10246
10247 async fn handle_on_type_formatting(
10248 this: Entity<Self>,
10249 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10250 mut cx: AsyncApp,
10251 ) -> Result<proto::OnTypeFormattingResponse> {
10252 let on_type_formatting = this.update(&mut cx, |this, cx| {
10253 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10254 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10255 let position = envelope
10256 .payload
10257 .position
10258 .and_then(deserialize_anchor)
10259 .context("invalid position")?;
10260 anyhow::Ok(this.apply_on_type_formatting(
10261 buffer,
10262 position,
10263 envelope.payload.trigger.clone(),
10264 cx,
10265 ))
10266 })??;
10267
10268 let transaction = on_type_formatting
10269 .await?
10270 .as_ref()
10271 .map(language::proto::serialize_transaction);
10272 Ok(proto::OnTypeFormattingResponse { transaction })
10273 }
10274
10275 async fn handle_refresh_inlay_hints(
10276 lsp_store: Entity<Self>,
10277 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10278 mut cx: AsyncApp,
10279 ) -> Result<proto::Ack> {
10280 lsp_store.update(&mut cx, |_, cx| {
10281 cx.emit(LspStoreEvent::RefreshInlayHints {
10282 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10283 request_id: envelope.payload.request_id.map(|id| id as usize),
10284 });
10285 })?;
10286 Ok(proto::Ack {})
10287 }
10288
10289 async fn handle_pull_workspace_diagnostics(
10290 lsp_store: Entity<Self>,
10291 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10292 mut cx: AsyncApp,
10293 ) -> Result<proto::Ack> {
10294 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10295 lsp_store.update(&mut cx, |lsp_store, _| {
10296 lsp_store.pull_workspace_diagnostics(server_id);
10297 })?;
10298 Ok(proto::Ack {})
10299 }
10300
10301 async fn handle_get_color_presentation(
10302 lsp_store: Entity<Self>,
10303 envelope: TypedEnvelope<proto::GetColorPresentation>,
10304 mut cx: AsyncApp,
10305 ) -> Result<proto::GetColorPresentationResponse> {
10306 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10307 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10308 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10309 })??;
10310
10311 let color = envelope
10312 .payload
10313 .color
10314 .context("invalid color resolve request")?;
10315 let start = color
10316 .lsp_range_start
10317 .context("invalid color resolve request")?;
10318 let end = color
10319 .lsp_range_end
10320 .context("invalid color resolve request")?;
10321
10322 let color = DocumentColor {
10323 lsp_range: lsp::Range {
10324 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10325 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10326 },
10327 color: lsp::Color {
10328 red: color.red,
10329 green: color.green,
10330 blue: color.blue,
10331 alpha: color.alpha,
10332 },
10333 resolved: false,
10334 color_presentations: Vec::new(),
10335 };
10336 let resolved_color = lsp_store
10337 .update(&mut cx, |lsp_store, cx| {
10338 lsp_store.resolve_color_presentation(
10339 color,
10340 buffer.clone(),
10341 LanguageServerId(envelope.payload.server_id as usize),
10342 cx,
10343 )
10344 })?
10345 .await
10346 .context("resolving color presentation")?;
10347
10348 Ok(proto::GetColorPresentationResponse {
10349 presentations: resolved_color
10350 .color_presentations
10351 .into_iter()
10352 .map(|presentation| proto::ColorPresentation {
10353 label: presentation.label.to_string(),
10354 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10355 additional_text_edits: presentation
10356 .additional_text_edits
10357 .into_iter()
10358 .map(serialize_lsp_edit)
10359 .collect(),
10360 })
10361 .collect(),
10362 })
10363 }
10364
10365 async fn handle_resolve_inlay_hint(
10366 lsp_store: Entity<Self>,
10367 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10368 mut cx: AsyncApp,
10369 ) -> Result<proto::ResolveInlayHintResponse> {
10370 let proto_hint = envelope
10371 .payload
10372 .hint
10373 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10374 let hint = InlayHints::proto_to_project_hint(proto_hint)
10375 .context("resolved proto inlay hint conversion")?;
10376 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10377 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10378 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10379 })??;
10380 let response_hint = lsp_store
10381 .update(&mut cx, |lsp_store, cx| {
10382 lsp_store.resolve_inlay_hint(
10383 hint,
10384 buffer,
10385 LanguageServerId(envelope.payload.language_server_id as usize),
10386 cx,
10387 )
10388 })?
10389 .await
10390 .context("inlay hints fetch")?;
10391 Ok(proto::ResolveInlayHintResponse {
10392 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10393 })
10394 }
10395
10396 async fn handle_refresh_code_lens(
10397 this: Entity<Self>,
10398 _: TypedEnvelope<proto::RefreshCodeLens>,
10399 mut cx: AsyncApp,
10400 ) -> Result<proto::Ack> {
10401 this.update(&mut cx, |_, cx| {
10402 cx.emit(LspStoreEvent::RefreshCodeLens);
10403 })?;
10404 Ok(proto::Ack {})
10405 }
10406
10407 async fn handle_open_buffer_for_symbol(
10408 this: Entity<Self>,
10409 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10410 mut cx: AsyncApp,
10411 ) -> Result<proto::OpenBufferForSymbolResponse> {
10412 let peer_id = envelope.original_sender_id().unwrap_or_default();
10413 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10414 let symbol = Self::deserialize_symbol(symbol)?;
10415 this.read_with(&cx, |this, _| {
10416 if let SymbolLocation::OutsideProject {
10417 abs_path,
10418 signature,
10419 } = &symbol.path
10420 {
10421 let new_signature = this.symbol_signature(&abs_path);
10422 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10423 }
10424 Ok(())
10425 })??;
10426 let buffer = this
10427 .update(&mut cx, |this, cx| {
10428 this.open_buffer_for_symbol(
10429 &Symbol {
10430 language_server_name: symbol.language_server_name,
10431 source_worktree_id: symbol.source_worktree_id,
10432 source_language_server_id: symbol.source_language_server_id,
10433 path: symbol.path,
10434 name: symbol.name,
10435 kind: symbol.kind,
10436 range: symbol.range,
10437 label: CodeLabel::default(),
10438 },
10439 cx,
10440 )
10441 })?
10442 .await?;
10443
10444 this.update(&mut cx, |this, cx| {
10445 let is_private = buffer
10446 .read(cx)
10447 .file()
10448 .map(|f| f.is_private())
10449 .unwrap_or_default();
10450 if is_private {
10451 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10452 } else {
10453 this.buffer_store
10454 .update(cx, |buffer_store, cx| {
10455 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10456 })
10457 .detach_and_log_err(cx);
10458 let buffer_id = buffer.read(cx).remote_id().to_proto();
10459 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10460 }
10461 })?
10462 }
10463
10464 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10465 let mut hasher = Sha256::new();
10466 hasher.update(abs_path.to_string_lossy().as_bytes());
10467 hasher.update(self.nonce.to_be_bytes());
10468 hasher.finalize().as_slice().try_into().unwrap()
10469 }
10470
10471 pub async fn handle_get_project_symbols(
10472 this: Entity<Self>,
10473 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10474 mut cx: AsyncApp,
10475 ) -> Result<proto::GetProjectSymbolsResponse> {
10476 let symbols = this
10477 .update(&mut cx, |this, cx| {
10478 this.symbols(&envelope.payload.query, cx)
10479 })?
10480 .await?;
10481
10482 Ok(proto::GetProjectSymbolsResponse {
10483 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10484 })
10485 }
10486
10487 pub async fn handle_restart_language_servers(
10488 this: Entity<Self>,
10489 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10490 mut cx: AsyncApp,
10491 ) -> Result<proto::Ack> {
10492 this.update(&mut cx, |lsp_store, cx| {
10493 let buffers =
10494 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10495 lsp_store.restart_language_servers_for_buffers(
10496 buffers,
10497 envelope
10498 .payload
10499 .only_servers
10500 .into_iter()
10501 .filter_map(|selector| {
10502 Some(match selector.selector? {
10503 proto::language_server_selector::Selector::ServerId(server_id) => {
10504 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10505 }
10506 proto::language_server_selector::Selector::Name(name) => {
10507 LanguageServerSelector::Name(LanguageServerName(
10508 SharedString::from(name),
10509 ))
10510 }
10511 })
10512 })
10513 .collect(),
10514 cx,
10515 );
10516 })?;
10517
10518 Ok(proto::Ack {})
10519 }
10520
10521 pub async fn handle_stop_language_servers(
10522 lsp_store: Entity<Self>,
10523 envelope: TypedEnvelope<proto::StopLanguageServers>,
10524 mut cx: AsyncApp,
10525 ) -> Result<proto::Ack> {
10526 lsp_store.update(&mut cx, |lsp_store, cx| {
10527 if envelope.payload.all
10528 && envelope.payload.also_servers.is_empty()
10529 && envelope.payload.buffer_ids.is_empty()
10530 {
10531 lsp_store.stop_all_language_servers(cx);
10532 } else {
10533 let buffers =
10534 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10535 lsp_store
10536 .stop_language_servers_for_buffers(
10537 buffers,
10538 envelope
10539 .payload
10540 .also_servers
10541 .into_iter()
10542 .filter_map(|selector| {
10543 Some(match selector.selector? {
10544 proto::language_server_selector::Selector::ServerId(
10545 server_id,
10546 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10547 server_id,
10548 )),
10549 proto::language_server_selector::Selector::Name(name) => {
10550 LanguageServerSelector::Name(LanguageServerName(
10551 SharedString::from(name),
10552 ))
10553 }
10554 })
10555 })
10556 .collect(),
10557 cx,
10558 )
10559 .detach_and_log_err(cx);
10560 }
10561 })?;
10562
10563 Ok(proto::Ack {})
10564 }
10565
10566 pub async fn handle_cancel_language_server_work(
10567 lsp_store: Entity<Self>,
10568 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10569 mut cx: AsyncApp,
10570 ) -> Result<proto::Ack> {
10571 lsp_store.update(&mut cx, |lsp_store, cx| {
10572 if let Some(work) = envelope.payload.work {
10573 match work {
10574 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10575 let buffers =
10576 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10577 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10578 }
10579 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10580 let server_id = LanguageServerId::from_proto(work.language_server_id);
10581 let token = work
10582 .token
10583 .map(|token| {
10584 ProgressToken::from_proto(token)
10585 .context("invalid work progress token")
10586 })
10587 .transpose()?;
10588 lsp_store.cancel_language_server_work(server_id, token, cx);
10589 }
10590 }
10591 }
10592 anyhow::Ok(())
10593 })??;
10594
10595 Ok(proto::Ack {})
10596 }
10597
10598 fn buffer_ids_to_buffers(
10599 &mut self,
10600 buffer_ids: impl Iterator<Item = u64>,
10601 cx: &mut Context<Self>,
10602 ) -> Vec<Entity<Buffer>> {
10603 buffer_ids
10604 .into_iter()
10605 .flat_map(|buffer_id| {
10606 self.buffer_store
10607 .read(cx)
10608 .get(BufferId::new(buffer_id).log_err()?)
10609 })
10610 .collect::<Vec<_>>()
10611 }
10612
10613 async fn handle_apply_additional_edits_for_completion(
10614 this: Entity<Self>,
10615 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10616 mut cx: AsyncApp,
10617 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10618 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10619 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10620 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10621 let completion = Self::deserialize_completion(
10622 envelope.payload.completion.context("invalid completion")?,
10623 )?;
10624 anyhow::Ok((buffer, completion))
10625 })??;
10626
10627 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10628 this.apply_additional_edits_for_completion(
10629 buffer,
10630 Rc::new(RefCell::new(Box::new([Completion {
10631 replace_range: completion.replace_range,
10632 new_text: completion.new_text,
10633 source: completion.source,
10634 documentation: None,
10635 label: CodeLabel::default(),
10636 match_start: None,
10637 snippet_deduplication_key: None,
10638 insert_text_mode: None,
10639 icon_path: None,
10640 confirm: None,
10641 }]))),
10642 0,
10643 false,
10644 cx,
10645 )
10646 })?;
10647
10648 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10649 transaction: apply_additional_edits
10650 .await?
10651 .as_ref()
10652 .map(language::proto::serialize_transaction),
10653 })
10654 }
10655
10656 pub fn last_formatting_failure(&self) -> Option<&str> {
10657 self.last_formatting_failure.as_deref()
10658 }
10659
10660 pub fn reset_last_formatting_failure(&mut self) {
10661 self.last_formatting_failure = None;
10662 }
10663
10664 pub fn environment_for_buffer(
10665 &self,
10666 buffer: &Entity<Buffer>,
10667 cx: &mut Context<Self>,
10668 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10669 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10670 environment.update(cx, |env, cx| {
10671 env.buffer_environment(buffer, &self.worktree_store, cx)
10672 })
10673 } else {
10674 Task::ready(None).shared()
10675 }
10676 }
10677
10678 pub fn format(
10679 &mut self,
10680 buffers: HashSet<Entity<Buffer>>,
10681 target: LspFormatTarget,
10682 push_to_history: bool,
10683 trigger: FormatTrigger,
10684 cx: &mut Context<Self>,
10685 ) -> Task<anyhow::Result<ProjectTransaction>> {
10686 let logger = zlog::scoped!("format");
10687 if self.as_local().is_some() {
10688 zlog::trace!(logger => "Formatting locally");
10689 let logger = zlog::scoped!(logger => "local");
10690 let buffers = buffers
10691 .into_iter()
10692 .map(|buffer_handle| {
10693 let buffer = buffer_handle.read(cx);
10694 let buffer_abs_path = File::from_dyn(buffer.file())
10695 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10696
10697 (buffer_handle, buffer_abs_path, buffer.remote_id())
10698 })
10699 .collect::<Vec<_>>();
10700
10701 cx.spawn(async move |lsp_store, cx| {
10702 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10703
10704 for (handle, abs_path, id) in buffers {
10705 let env = lsp_store
10706 .update(cx, |lsp_store, cx| {
10707 lsp_store.environment_for_buffer(&handle, cx)
10708 })?
10709 .await;
10710
10711 let ranges = match &target {
10712 LspFormatTarget::Buffers => None,
10713 LspFormatTarget::Ranges(ranges) => {
10714 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10715 }
10716 };
10717
10718 formattable_buffers.push(FormattableBuffer {
10719 handle,
10720 abs_path,
10721 env,
10722 ranges,
10723 });
10724 }
10725 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10726
10727 let format_timer = zlog::time!(logger => "Formatting buffers");
10728 let result = LocalLspStore::format_locally(
10729 lsp_store.clone(),
10730 formattable_buffers,
10731 push_to_history,
10732 trigger,
10733 logger,
10734 cx,
10735 )
10736 .await;
10737 format_timer.end();
10738
10739 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10740
10741 lsp_store.update(cx, |lsp_store, _| {
10742 lsp_store.update_last_formatting_failure(&result);
10743 })?;
10744
10745 result
10746 })
10747 } else if let Some((client, project_id)) = self.upstream_client() {
10748 zlog::trace!(logger => "Formatting remotely");
10749 let logger = zlog::scoped!(logger => "remote");
10750 // Don't support formatting ranges via remote
10751 match target {
10752 LspFormatTarget::Buffers => {}
10753 LspFormatTarget::Ranges(_) => {
10754 zlog::trace!(logger => "Ignoring unsupported remote range formatting request");
10755 return Task::ready(Ok(ProjectTransaction::default()));
10756 }
10757 }
10758
10759 let buffer_store = self.buffer_store();
10760 cx.spawn(async move |lsp_store, cx| {
10761 zlog::trace!(logger => "Sending remote format request");
10762 let request_timer = zlog::time!(logger => "remote format request");
10763 let result = client
10764 .request(proto::FormatBuffers {
10765 project_id,
10766 trigger: trigger as i32,
10767 buffer_ids: buffers
10768 .iter()
10769 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().into()))
10770 .collect::<Result<_>>()?,
10771 })
10772 .await
10773 .and_then(|result| result.transaction.context("missing transaction"));
10774 request_timer.end();
10775
10776 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10777
10778 lsp_store.update(cx, |lsp_store, _| {
10779 lsp_store.update_last_formatting_failure(&result);
10780 })?;
10781
10782 let transaction_response = result?;
10783 let _timer = zlog::time!(logger => "deserializing project transaction");
10784 buffer_store
10785 .update(cx, |buffer_store, cx| {
10786 buffer_store.deserialize_project_transaction(
10787 transaction_response,
10788 push_to_history,
10789 cx,
10790 )
10791 })?
10792 .await
10793 })
10794 } else {
10795 zlog::trace!(logger => "Not formatting");
10796 Task::ready(Ok(ProjectTransaction::default()))
10797 }
10798 }
10799
10800 async fn handle_format_buffers(
10801 this: Entity<Self>,
10802 envelope: TypedEnvelope<proto::FormatBuffers>,
10803 mut cx: AsyncApp,
10804 ) -> Result<proto::FormatBuffersResponse> {
10805 let sender_id = envelope.original_sender_id().unwrap_or_default();
10806 let format = this.update(&mut cx, |this, cx| {
10807 let mut buffers = HashSet::default();
10808 for buffer_id in &envelope.payload.buffer_ids {
10809 let buffer_id = BufferId::new(*buffer_id)?;
10810 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10811 }
10812 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10813 anyhow::Ok(this.format(buffers, LspFormatTarget::Buffers, false, trigger, cx))
10814 })??;
10815
10816 let project_transaction = format.await?;
10817 let project_transaction = this.update(&mut cx, |this, cx| {
10818 this.buffer_store.update(cx, |buffer_store, cx| {
10819 buffer_store.serialize_project_transaction_for_peer(
10820 project_transaction,
10821 sender_id,
10822 cx,
10823 )
10824 })
10825 })?;
10826 Ok(proto::FormatBuffersResponse {
10827 transaction: Some(project_transaction),
10828 })
10829 }
10830
10831 async fn handle_apply_code_action_kind(
10832 this: Entity<Self>,
10833 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10834 mut cx: AsyncApp,
10835 ) -> Result<proto::ApplyCodeActionKindResponse> {
10836 let sender_id = envelope.original_sender_id().unwrap_or_default();
10837 let format = this.update(&mut cx, |this, cx| {
10838 let mut buffers = HashSet::default();
10839 for buffer_id in &envelope.payload.buffer_ids {
10840 let buffer_id = BufferId::new(*buffer_id)?;
10841 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10842 }
10843 let kind = match envelope.payload.kind.as_str() {
10844 "" => CodeActionKind::EMPTY,
10845 "quickfix" => CodeActionKind::QUICKFIX,
10846 "refactor" => CodeActionKind::REFACTOR,
10847 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10848 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10849 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10850 "source" => CodeActionKind::SOURCE,
10851 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10852 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10853 _ => anyhow::bail!(
10854 "Invalid code action kind {}",
10855 envelope.payload.kind.as_str()
10856 ),
10857 };
10858 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10859 })??;
10860
10861 let project_transaction = format.await?;
10862 let project_transaction = this.update(&mut cx, |this, cx| {
10863 this.buffer_store.update(cx, |buffer_store, cx| {
10864 buffer_store.serialize_project_transaction_for_peer(
10865 project_transaction,
10866 sender_id,
10867 cx,
10868 )
10869 })
10870 })?;
10871 Ok(proto::ApplyCodeActionKindResponse {
10872 transaction: Some(project_transaction),
10873 })
10874 }
10875
10876 async fn shutdown_language_server(
10877 server_state: Option<LanguageServerState>,
10878 name: LanguageServerName,
10879 cx: &mut AsyncApp,
10880 ) {
10881 let server = match server_state {
10882 Some(LanguageServerState::Starting { startup, .. }) => {
10883 let mut timer = cx
10884 .background_executor()
10885 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10886 .fuse();
10887
10888 select! {
10889 server = startup.fuse() => server,
10890 () = timer => {
10891 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10892 None
10893 },
10894 }
10895 }
10896
10897 Some(LanguageServerState::Running { server, .. }) => Some(server),
10898
10899 None => None,
10900 };
10901
10902 if let Some(server) = server
10903 && let Some(shutdown) = server.shutdown()
10904 {
10905 shutdown.await;
10906 }
10907 }
10908
10909 // Returns a list of all of the worktrees which no longer have a language server and the root path
10910 // for the stopped server
10911 fn stop_local_language_server(
10912 &mut self,
10913 server_id: LanguageServerId,
10914 cx: &mut Context<Self>,
10915 ) -> Task<()> {
10916 let local = match &mut self.mode {
10917 LspStoreMode::Local(local) => local,
10918 _ => {
10919 return Task::ready(());
10920 }
10921 };
10922
10923 // Remove this server ID from all entries in the given worktree.
10924 local
10925 .language_server_ids
10926 .retain(|_, state| state.id != server_id);
10927 self.buffer_store.update(cx, |buffer_store, cx| {
10928 for buffer in buffer_store.buffers() {
10929 buffer.update(cx, |buffer, cx| {
10930 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10931 buffer.set_completion_triggers(server_id, Default::default(), cx);
10932 });
10933 }
10934 });
10935
10936 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10937 summaries.retain(|path, summaries_by_server_id| {
10938 if summaries_by_server_id.remove(&server_id).is_some() {
10939 if let Some((client, project_id)) = self.downstream_client.clone() {
10940 client
10941 .send(proto::UpdateDiagnosticSummary {
10942 project_id,
10943 worktree_id: worktree_id.to_proto(),
10944 summary: Some(proto::DiagnosticSummary {
10945 path: path.as_ref().to_proto(),
10946 language_server_id: server_id.0 as u64,
10947 error_count: 0,
10948 warning_count: 0,
10949 }),
10950 more_summaries: Vec::new(),
10951 })
10952 .log_err();
10953 }
10954 !summaries_by_server_id.is_empty()
10955 } else {
10956 true
10957 }
10958 });
10959 }
10960
10961 let local = self.as_local_mut().unwrap();
10962 for diagnostics in local.diagnostics.values_mut() {
10963 diagnostics.retain(|_, diagnostics_by_server_id| {
10964 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10965 diagnostics_by_server_id.remove(ix);
10966 !diagnostics_by_server_id.is_empty()
10967 } else {
10968 true
10969 }
10970 });
10971 }
10972 local.language_server_watched_paths.remove(&server_id);
10973
10974 let server_state = local.language_servers.remove(&server_id);
10975 self.cleanup_lsp_data(server_id);
10976 let name = self
10977 .language_server_statuses
10978 .remove(&server_id)
10979 .map(|status| status.name)
10980 .or_else(|| {
10981 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10982 Some(adapter.name())
10983 } else {
10984 None
10985 }
10986 });
10987
10988 if let Some(name) = name {
10989 log::info!("stopping language server {name}");
10990 self.languages
10991 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10992 cx.notify();
10993
10994 return cx.spawn(async move |lsp_store, cx| {
10995 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10996 lsp_store
10997 .update(cx, |lsp_store, cx| {
10998 lsp_store
10999 .languages
11000 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11001 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11002 cx.notify();
11003 })
11004 .ok();
11005 });
11006 }
11007
11008 if server_state.is_some() {
11009 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11010 }
11011 Task::ready(())
11012 }
11013
11014 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11015 if let Some((client, project_id)) = self.upstream_client() {
11016 let request = client.request(proto::StopLanguageServers {
11017 project_id,
11018 buffer_ids: Vec::new(),
11019 also_servers: Vec::new(),
11020 all: true,
11021 });
11022 cx.background_spawn(request).detach_and_log_err(cx);
11023 } else {
11024 let Some(local) = self.as_local_mut() else {
11025 return;
11026 };
11027 let language_servers_to_stop = local
11028 .language_server_ids
11029 .values()
11030 .map(|state| state.id)
11031 .collect();
11032 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11033 let tasks = language_servers_to_stop
11034 .into_iter()
11035 .map(|server| self.stop_local_language_server(server, cx))
11036 .collect::<Vec<_>>();
11037 cx.background_spawn(async move {
11038 futures::future::join_all(tasks).await;
11039 })
11040 .detach();
11041 }
11042 }
11043
11044 pub fn restart_language_servers_for_buffers(
11045 &mut self,
11046 buffers: Vec<Entity<Buffer>>,
11047 only_restart_servers: HashSet<LanguageServerSelector>,
11048 cx: &mut Context<Self>,
11049 ) {
11050 if let Some((client, project_id)) = self.upstream_client() {
11051 let request = client.request(proto::RestartLanguageServers {
11052 project_id,
11053 buffer_ids: buffers
11054 .into_iter()
11055 .map(|b| b.read(cx).remote_id().to_proto())
11056 .collect(),
11057 only_servers: only_restart_servers
11058 .into_iter()
11059 .map(|selector| {
11060 let selector = match selector {
11061 LanguageServerSelector::Id(language_server_id) => {
11062 proto::language_server_selector::Selector::ServerId(
11063 language_server_id.to_proto(),
11064 )
11065 }
11066 LanguageServerSelector::Name(language_server_name) => {
11067 proto::language_server_selector::Selector::Name(
11068 language_server_name.to_string(),
11069 )
11070 }
11071 };
11072 proto::LanguageServerSelector {
11073 selector: Some(selector),
11074 }
11075 })
11076 .collect(),
11077 all: false,
11078 });
11079 cx.background_spawn(request).detach_and_log_err(cx);
11080 } else {
11081 let stop_task = if only_restart_servers.is_empty() {
11082 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11083 } else {
11084 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11085 };
11086 cx.spawn(async move |lsp_store, cx| {
11087 stop_task.await;
11088 lsp_store
11089 .update(cx, |lsp_store, cx| {
11090 for buffer in buffers {
11091 lsp_store.register_buffer_with_language_servers(
11092 &buffer,
11093 only_restart_servers.clone(),
11094 true,
11095 cx,
11096 );
11097 }
11098 })
11099 .ok()
11100 })
11101 .detach();
11102 }
11103 }
11104
11105 pub fn stop_language_servers_for_buffers(
11106 &mut self,
11107 buffers: Vec<Entity<Buffer>>,
11108 also_stop_servers: HashSet<LanguageServerSelector>,
11109 cx: &mut Context<Self>,
11110 ) -> Task<Result<()>> {
11111 if let Some((client, project_id)) = self.upstream_client() {
11112 let request = client.request(proto::StopLanguageServers {
11113 project_id,
11114 buffer_ids: buffers
11115 .into_iter()
11116 .map(|b| b.read(cx).remote_id().to_proto())
11117 .collect(),
11118 also_servers: also_stop_servers
11119 .into_iter()
11120 .map(|selector| {
11121 let selector = match selector {
11122 LanguageServerSelector::Id(language_server_id) => {
11123 proto::language_server_selector::Selector::ServerId(
11124 language_server_id.to_proto(),
11125 )
11126 }
11127 LanguageServerSelector::Name(language_server_name) => {
11128 proto::language_server_selector::Selector::Name(
11129 language_server_name.to_string(),
11130 )
11131 }
11132 };
11133 proto::LanguageServerSelector {
11134 selector: Some(selector),
11135 }
11136 })
11137 .collect(),
11138 all: false,
11139 });
11140 cx.background_spawn(async move {
11141 let _ = request.await?;
11142 Ok(())
11143 })
11144 } else {
11145 let task =
11146 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11147 cx.background_spawn(async move {
11148 task.await;
11149 Ok(())
11150 })
11151 }
11152 }
11153
11154 fn stop_local_language_servers_for_buffers(
11155 &mut self,
11156 buffers: &[Entity<Buffer>],
11157 also_stop_servers: HashSet<LanguageServerSelector>,
11158 cx: &mut Context<Self>,
11159 ) -> Task<()> {
11160 let Some(local) = self.as_local_mut() else {
11161 return Task::ready(());
11162 };
11163 let mut language_server_names_to_stop = BTreeSet::default();
11164 let mut language_servers_to_stop = also_stop_servers
11165 .into_iter()
11166 .flat_map(|selector| match selector {
11167 LanguageServerSelector::Id(id) => Some(id),
11168 LanguageServerSelector::Name(name) => {
11169 language_server_names_to_stop.insert(name);
11170 None
11171 }
11172 })
11173 .collect::<BTreeSet<_>>();
11174
11175 let mut covered_worktrees = HashSet::default();
11176 for buffer in buffers {
11177 buffer.update(cx, |buffer, cx| {
11178 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11179 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11180 && covered_worktrees.insert(worktree_id)
11181 {
11182 language_server_names_to_stop.retain(|name| {
11183 let old_ids_count = language_servers_to_stop.len();
11184 let all_language_servers_with_this_name = local
11185 .language_server_ids
11186 .iter()
11187 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11188 language_servers_to_stop.extend(all_language_servers_with_this_name);
11189 old_ids_count == language_servers_to_stop.len()
11190 });
11191 }
11192 });
11193 }
11194 for name in language_server_names_to_stop {
11195 language_servers_to_stop.extend(
11196 local
11197 .language_server_ids
11198 .iter()
11199 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11200 );
11201 }
11202
11203 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11204 let tasks = language_servers_to_stop
11205 .into_iter()
11206 .map(|server| self.stop_local_language_server(server, cx))
11207 .collect::<Vec<_>>();
11208
11209 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11210 }
11211
11212 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11213 let (worktree, relative_path) =
11214 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11215
11216 let project_path = ProjectPath {
11217 worktree_id: worktree.read(cx).id(),
11218 path: relative_path,
11219 };
11220
11221 Some(
11222 self.buffer_store()
11223 .read(cx)
11224 .get_by_path(&project_path)?
11225 .read(cx),
11226 )
11227 }
11228
11229 #[cfg(any(test, feature = "test-support"))]
11230 pub fn update_diagnostics(
11231 &mut self,
11232 server_id: LanguageServerId,
11233 diagnostics: lsp::PublishDiagnosticsParams,
11234 result_id: Option<SharedString>,
11235 source_kind: DiagnosticSourceKind,
11236 disk_based_sources: &[String],
11237 cx: &mut Context<Self>,
11238 ) -> Result<()> {
11239 self.merge_lsp_diagnostics(
11240 source_kind,
11241 vec![DocumentDiagnosticsUpdate {
11242 diagnostics,
11243 result_id,
11244 server_id,
11245 disk_based_sources: Cow::Borrowed(disk_based_sources),
11246 registration_id: None,
11247 }],
11248 |_, _, _| false,
11249 cx,
11250 )
11251 }
11252
11253 pub fn merge_lsp_diagnostics(
11254 &mut self,
11255 source_kind: DiagnosticSourceKind,
11256 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11257 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11258 cx: &mut Context<Self>,
11259 ) -> Result<()> {
11260 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11261 let updates = lsp_diagnostics
11262 .into_iter()
11263 .filter_map(|update| {
11264 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11265 Some(DocumentDiagnosticsUpdate {
11266 diagnostics: self.lsp_to_document_diagnostics(
11267 abs_path,
11268 source_kind,
11269 update.server_id,
11270 update.diagnostics,
11271 &update.disk_based_sources,
11272 update.registration_id.clone(),
11273 ),
11274 result_id: update.result_id,
11275 server_id: update.server_id,
11276 disk_based_sources: update.disk_based_sources,
11277 registration_id: update.registration_id,
11278 })
11279 })
11280 .collect();
11281 self.merge_diagnostic_entries(updates, merge, cx)?;
11282 Ok(())
11283 }
11284
11285 fn lsp_to_document_diagnostics(
11286 &mut self,
11287 document_abs_path: PathBuf,
11288 source_kind: DiagnosticSourceKind,
11289 server_id: LanguageServerId,
11290 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11291 disk_based_sources: &[String],
11292 registration_id: Option<SharedString>,
11293 ) -> DocumentDiagnostics {
11294 let mut diagnostics = Vec::default();
11295 let mut primary_diagnostic_group_ids = HashMap::default();
11296 let mut sources_by_group_id = HashMap::default();
11297 let mut supporting_diagnostics = HashMap::default();
11298
11299 let adapter = self.language_server_adapter_for_id(server_id);
11300
11301 // Ensure that primary diagnostics are always the most severe
11302 lsp_diagnostics
11303 .diagnostics
11304 .sort_by_key(|item| item.severity);
11305
11306 for diagnostic in &lsp_diagnostics.diagnostics {
11307 let source = diagnostic.source.as_ref();
11308 let range = range_from_lsp(diagnostic.range);
11309 let is_supporting = diagnostic
11310 .related_information
11311 .as_ref()
11312 .is_some_and(|infos| {
11313 infos.iter().any(|info| {
11314 primary_diagnostic_group_ids.contains_key(&(
11315 source,
11316 diagnostic.code.clone(),
11317 range_from_lsp(info.location.range),
11318 ))
11319 })
11320 });
11321
11322 let is_unnecessary = diagnostic
11323 .tags
11324 .as_ref()
11325 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11326
11327 let underline = self
11328 .language_server_adapter_for_id(server_id)
11329 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11330
11331 if is_supporting {
11332 supporting_diagnostics.insert(
11333 (source, diagnostic.code.clone(), range),
11334 (diagnostic.severity, is_unnecessary),
11335 );
11336 } else {
11337 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11338 let is_disk_based =
11339 source.is_some_and(|source| disk_based_sources.contains(source));
11340
11341 sources_by_group_id.insert(group_id, source);
11342 primary_diagnostic_group_ids
11343 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11344
11345 diagnostics.push(DiagnosticEntry {
11346 range,
11347 diagnostic: Diagnostic {
11348 source: diagnostic.source.clone(),
11349 source_kind,
11350 code: diagnostic.code.clone(),
11351 code_description: diagnostic
11352 .code_description
11353 .as_ref()
11354 .and_then(|d| d.href.clone()),
11355 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11356 markdown: adapter.as_ref().and_then(|adapter| {
11357 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11358 }),
11359 message: diagnostic.message.trim().to_string(),
11360 group_id,
11361 is_primary: true,
11362 is_disk_based,
11363 is_unnecessary,
11364 underline,
11365 data: diagnostic.data.clone(),
11366 registration_id: registration_id.clone(),
11367 },
11368 });
11369 if let Some(infos) = &diagnostic.related_information {
11370 for info in infos {
11371 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11372 let range = range_from_lsp(info.location.range);
11373 diagnostics.push(DiagnosticEntry {
11374 range,
11375 diagnostic: Diagnostic {
11376 source: diagnostic.source.clone(),
11377 source_kind,
11378 code: diagnostic.code.clone(),
11379 code_description: diagnostic
11380 .code_description
11381 .as_ref()
11382 .and_then(|d| d.href.clone()),
11383 severity: DiagnosticSeverity::INFORMATION,
11384 markdown: adapter.as_ref().and_then(|adapter| {
11385 adapter.diagnostic_message_to_markdown(&info.message)
11386 }),
11387 message: info.message.trim().to_string(),
11388 group_id,
11389 is_primary: false,
11390 is_disk_based,
11391 is_unnecessary: false,
11392 underline,
11393 data: diagnostic.data.clone(),
11394 registration_id: registration_id.clone(),
11395 },
11396 });
11397 }
11398 }
11399 }
11400 }
11401 }
11402
11403 for entry in &mut diagnostics {
11404 let diagnostic = &mut entry.diagnostic;
11405 if !diagnostic.is_primary {
11406 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11407 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11408 source,
11409 diagnostic.code.clone(),
11410 entry.range.clone(),
11411 )) {
11412 if let Some(severity) = severity {
11413 diagnostic.severity = severity;
11414 }
11415 diagnostic.is_unnecessary = is_unnecessary;
11416 }
11417 }
11418 }
11419
11420 DocumentDiagnostics {
11421 diagnostics,
11422 document_abs_path,
11423 version: lsp_diagnostics.version,
11424 }
11425 }
11426
11427 fn insert_newly_running_language_server(
11428 &mut self,
11429 adapter: Arc<CachedLspAdapter>,
11430 language_server: Arc<LanguageServer>,
11431 server_id: LanguageServerId,
11432 key: LanguageServerSeed,
11433 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11434 cx: &mut Context<Self>,
11435 ) {
11436 let Some(local) = self.as_local_mut() else {
11437 return;
11438 };
11439 // If the language server for this key doesn't match the server id, don't store the
11440 // server. Which will cause it to be dropped, killing the process
11441 if local
11442 .language_server_ids
11443 .get(&key)
11444 .map(|state| state.id != server_id)
11445 .unwrap_or(false)
11446 {
11447 return;
11448 }
11449
11450 // Update language_servers collection with Running variant of LanguageServerState
11451 // indicating that the server is up and running and ready
11452 let workspace_folders = workspace_folders.lock().clone();
11453 language_server.set_workspace_folders(workspace_folders);
11454
11455 let workspace_diagnostics_refresh_tasks = language_server
11456 .capabilities()
11457 .diagnostic_provider
11458 .and_then(|provider| {
11459 local
11460 .language_server_dynamic_registrations
11461 .entry(server_id)
11462 .or_default()
11463 .diagnostics
11464 .entry(None)
11465 .or_insert(provider.clone());
11466 let workspace_refresher =
11467 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11468
11469 Some((None, workspace_refresher))
11470 })
11471 .into_iter()
11472 .collect();
11473 local.language_servers.insert(
11474 server_id,
11475 LanguageServerState::Running {
11476 workspace_diagnostics_refresh_tasks,
11477 adapter: adapter.clone(),
11478 server: language_server.clone(),
11479 simulate_disk_based_diagnostics_completion: None,
11480 },
11481 );
11482 local
11483 .languages
11484 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11485 if let Some(file_ops_caps) = language_server
11486 .capabilities()
11487 .workspace
11488 .as_ref()
11489 .and_then(|ws| ws.file_operations.as_ref())
11490 {
11491 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11492 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11493 if did_rename_caps.or(will_rename_caps).is_some() {
11494 let watcher = RenamePathsWatchedForServer::default()
11495 .with_did_rename_patterns(did_rename_caps)
11496 .with_will_rename_patterns(will_rename_caps);
11497 local
11498 .language_server_paths_watched_for_rename
11499 .insert(server_id, watcher);
11500 }
11501 }
11502
11503 self.language_server_statuses.insert(
11504 server_id,
11505 LanguageServerStatus {
11506 name: language_server.name(),
11507 server_version: language_server.version(),
11508 pending_work: Default::default(),
11509 has_pending_diagnostic_updates: false,
11510 progress_tokens: Default::default(),
11511 worktree: Some(key.worktree_id),
11512 binary: Some(language_server.binary().clone()),
11513 configuration: Some(language_server.configuration().clone()),
11514 workspace_folders: language_server.workspace_folders(),
11515 },
11516 );
11517
11518 cx.emit(LspStoreEvent::LanguageServerAdded(
11519 server_id,
11520 language_server.name(),
11521 Some(key.worktree_id),
11522 ));
11523
11524 let server_capabilities = language_server.capabilities();
11525 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11526 downstream_client
11527 .send(proto::StartLanguageServer {
11528 project_id: *project_id,
11529 server: Some(proto::LanguageServer {
11530 id: server_id.to_proto(),
11531 name: language_server.name().to_string(),
11532 worktree_id: Some(key.worktree_id.to_proto()),
11533 }),
11534 capabilities: serde_json::to_string(&server_capabilities)
11535 .expect("serializing server LSP capabilities"),
11536 })
11537 .log_err();
11538 }
11539 self.lsp_server_capabilities
11540 .insert(server_id, server_capabilities);
11541
11542 // Tell the language server about every open buffer in the worktree that matches the language.
11543 // Also check for buffers in worktrees that reused this server
11544 let mut worktrees_using_server = vec![key.worktree_id];
11545 if let Some(local) = self.as_local() {
11546 // Find all worktrees that have this server in their language server tree
11547 for (worktree_id, servers) in &local.lsp_tree.instances {
11548 if *worktree_id != key.worktree_id {
11549 for server_map in servers.roots.values() {
11550 if server_map
11551 .values()
11552 .any(|(node, _)| node.id() == Some(server_id))
11553 {
11554 worktrees_using_server.push(*worktree_id);
11555 }
11556 }
11557 }
11558 }
11559 }
11560
11561 let mut buffer_paths_registered = Vec::new();
11562 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11563 let mut lsp_adapters = HashMap::default();
11564 for buffer_handle in buffer_store.buffers() {
11565 let buffer = buffer_handle.read(cx);
11566 let file = match File::from_dyn(buffer.file()) {
11567 Some(file) => file,
11568 None => continue,
11569 };
11570 let language = match buffer.language() {
11571 Some(language) => language,
11572 None => continue,
11573 };
11574
11575 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11576 || !lsp_adapters
11577 .entry(language.name())
11578 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11579 .iter()
11580 .any(|a| a.name == key.name)
11581 {
11582 continue;
11583 }
11584 // didOpen
11585 let file = match file.as_local() {
11586 Some(file) => file,
11587 None => continue,
11588 };
11589
11590 let local = self.as_local_mut().unwrap();
11591
11592 let buffer_id = buffer.remote_id();
11593 if local.registered_buffers.contains_key(&buffer_id) {
11594 let versions = local
11595 .buffer_snapshots
11596 .entry(buffer_id)
11597 .or_default()
11598 .entry(server_id)
11599 .and_modify(|_| {
11600 assert!(
11601 false,
11602 "There should not be an existing snapshot for a newly inserted buffer"
11603 )
11604 })
11605 .or_insert_with(|| {
11606 vec![LspBufferSnapshot {
11607 version: 0,
11608 snapshot: buffer.text_snapshot(),
11609 }]
11610 });
11611
11612 let snapshot = versions.last().unwrap();
11613 let version = snapshot.version;
11614 let initial_snapshot = &snapshot.snapshot;
11615 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11616 language_server.register_buffer(
11617 uri,
11618 adapter.language_id(&language.name()),
11619 version,
11620 initial_snapshot.text(),
11621 );
11622 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11623 local
11624 .buffers_opened_in_servers
11625 .entry(buffer_id)
11626 .or_default()
11627 .insert(server_id);
11628 }
11629 buffer_handle.update(cx, |buffer, cx| {
11630 buffer.set_completion_triggers(
11631 server_id,
11632 language_server
11633 .capabilities()
11634 .completion_provider
11635 .as_ref()
11636 .and_then(|provider| {
11637 provider
11638 .trigger_characters
11639 .as_ref()
11640 .map(|characters| characters.iter().cloned().collect())
11641 })
11642 .unwrap_or_default(),
11643 cx,
11644 )
11645 });
11646 }
11647 });
11648
11649 for (buffer_id, abs_path) in buffer_paths_registered {
11650 cx.emit(LspStoreEvent::LanguageServerUpdate {
11651 language_server_id: server_id,
11652 name: Some(adapter.name()),
11653 message: proto::update_language_server::Variant::RegisteredForBuffer(
11654 proto::RegisteredForBuffer {
11655 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11656 buffer_id: buffer_id.to_proto(),
11657 },
11658 ),
11659 });
11660 }
11661
11662 cx.notify();
11663 }
11664
11665 pub fn language_servers_running_disk_based_diagnostics(
11666 &self,
11667 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11668 self.language_server_statuses
11669 .iter()
11670 .filter_map(|(id, status)| {
11671 if status.has_pending_diagnostic_updates {
11672 Some(*id)
11673 } else {
11674 None
11675 }
11676 })
11677 }
11678
11679 pub(crate) fn cancel_language_server_work_for_buffers(
11680 &mut self,
11681 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11682 cx: &mut Context<Self>,
11683 ) {
11684 if let Some((client, project_id)) = self.upstream_client() {
11685 let request = client.request(proto::CancelLanguageServerWork {
11686 project_id,
11687 work: Some(proto::cancel_language_server_work::Work::Buffers(
11688 proto::cancel_language_server_work::Buffers {
11689 buffer_ids: buffers
11690 .into_iter()
11691 .map(|b| b.read(cx).remote_id().to_proto())
11692 .collect(),
11693 },
11694 )),
11695 });
11696 cx.background_spawn(request).detach_and_log_err(cx);
11697 } else if let Some(local) = self.as_local() {
11698 let servers = buffers
11699 .into_iter()
11700 .flat_map(|buffer| {
11701 buffer.update(cx, |buffer, cx| {
11702 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11703 })
11704 })
11705 .collect::<HashSet<_>>();
11706 for server_id in servers {
11707 self.cancel_language_server_work(server_id, None, cx);
11708 }
11709 }
11710 }
11711
11712 pub(crate) fn cancel_language_server_work(
11713 &mut self,
11714 server_id: LanguageServerId,
11715 token_to_cancel: Option<ProgressToken>,
11716 cx: &mut Context<Self>,
11717 ) {
11718 if let Some(local) = self.as_local() {
11719 let status = self.language_server_statuses.get(&server_id);
11720 let server = local.language_servers.get(&server_id);
11721 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11722 {
11723 for (token, progress) in &status.pending_work {
11724 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11725 && token != token_to_cancel
11726 {
11727 continue;
11728 }
11729 if progress.is_cancellable {
11730 server
11731 .notify::<lsp::notification::WorkDoneProgressCancel>(
11732 WorkDoneProgressCancelParams {
11733 token: token.to_lsp(),
11734 },
11735 )
11736 .ok();
11737 }
11738 }
11739 }
11740 } else if let Some((client, project_id)) = self.upstream_client() {
11741 let request = client.request(proto::CancelLanguageServerWork {
11742 project_id,
11743 work: Some(
11744 proto::cancel_language_server_work::Work::LanguageServerWork(
11745 proto::cancel_language_server_work::LanguageServerWork {
11746 language_server_id: server_id.to_proto(),
11747 token: token_to_cancel.map(|token| token.to_proto()),
11748 },
11749 ),
11750 ),
11751 });
11752 cx.background_spawn(request).detach_and_log_err(cx);
11753 }
11754 }
11755
11756 fn register_supplementary_language_server(
11757 &mut self,
11758 id: LanguageServerId,
11759 name: LanguageServerName,
11760 server: Arc<LanguageServer>,
11761 cx: &mut Context<Self>,
11762 ) {
11763 if let Some(local) = self.as_local_mut() {
11764 local
11765 .supplementary_language_servers
11766 .insert(id, (name.clone(), server));
11767 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11768 }
11769 }
11770
11771 fn unregister_supplementary_language_server(
11772 &mut self,
11773 id: LanguageServerId,
11774 cx: &mut Context<Self>,
11775 ) {
11776 if let Some(local) = self.as_local_mut() {
11777 local.supplementary_language_servers.remove(&id);
11778 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11779 }
11780 }
11781
11782 pub(crate) fn supplementary_language_servers(
11783 &self,
11784 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11785 self.as_local().into_iter().flat_map(|local| {
11786 local
11787 .supplementary_language_servers
11788 .iter()
11789 .map(|(id, (name, _))| (*id, name.clone()))
11790 })
11791 }
11792
11793 pub fn language_server_adapter_for_id(
11794 &self,
11795 id: LanguageServerId,
11796 ) -> Option<Arc<CachedLspAdapter>> {
11797 self.as_local()
11798 .and_then(|local| local.language_servers.get(&id))
11799 .and_then(|language_server_state| match language_server_state {
11800 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11801 _ => None,
11802 })
11803 }
11804
11805 pub(super) fn update_local_worktree_language_servers(
11806 &mut self,
11807 worktree_handle: &Entity<Worktree>,
11808 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11809 cx: &mut Context<Self>,
11810 ) {
11811 if changes.is_empty() {
11812 return;
11813 }
11814
11815 let Some(local) = self.as_local() else { return };
11816
11817 local.prettier_store.update(cx, |prettier_store, cx| {
11818 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11819 });
11820
11821 let worktree_id = worktree_handle.read(cx).id();
11822 let mut language_server_ids = local
11823 .language_server_ids
11824 .iter()
11825 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11826 .collect::<Vec<_>>();
11827 language_server_ids.sort();
11828 language_server_ids.dedup();
11829
11830 // let abs_path = worktree_handle.read(cx).abs_path();
11831 for server_id in &language_server_ids {
11832 if let Some(LanguageServerState::Running { server, .. }) =
11833 local.language_servers.get(server_id)
11834 && let Some(watched_paths) = local
11835 .language_server_watched_paths
11836 .get(server_id)
11837 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11838 {
11839 let params = lsp::DidChangeWatchedFilesParams {
11840 changes: changes
11841 .iter()
11842 .filter_map(|(path, _, change)| {
11843 if !watched_paths.is_match(path.as_std_path()) {
11844 return None;
11845 }
11846 let typ = match change {
11847 PathChange::Loaded => return None,
11848 PathChange::Added => lsp::FileChangeType::CREATED,
11849 PathChange::Removed => lsp::FileChangeType::DELETED,
11850 PathChange::Updated => lsp::FileChangeType::CHANGED,
11851 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11852 };
11853 let uri = lsp::Uri::from_file_path(
11854 worktree_handle.read(cx).absolutize(&path),
11855 )
11856 .ok()?;
11857 Some(lsp::FileEvent { uri, typ })
11858 })
11859 .collect(),
11860 };
11861 if !params.changes.is_empty() {
11862 server
11863 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11864 .ok();
11865 }
11866 }
11867 }
11868 for (path, _, _) in changes {
11869 if let Some(file_name) = path.file_name()
11870 && local.watched_manifest_filenames.contains(file_name)
11871 {
11872 self.request_workspace_config_refresh();
11873 break;
11874 }
11875 }
11876 }
11877
11878 pub fn wait_for_remote_buffer(
11879 &mut self,
11880 id: BufferId,
11881 cx: &mut Context<Self>,
11882 ) -> Task<Result<Entity<Buffer>>> {
11883 self.buffer_store.update(cx, |buffer_store, cx| {
11884 buffer_store.wait_for_remote_buffer(id, cx)
11885 })
11886 }
11887
11888 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11889 let mut result = proto::Symbol {
11890 language_server_name: symbol.language_server_name.0.to_string(),
11891 source_worktree_id: symbol.source_worktree_id.to_proto(),
11892 language_server_id: symbol.source_language_server_id.to_proto(),
11893 name: symbol.name.clone(),
11894 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11895 start: Some(proto::PointUtf16 {
11896 row: symbol.range.start.0.row,
11897 column: symbol.range.start.0.column,
11898 }),
11899 end: Some(proto::PointUtf16 {
11900 row: symbol.range.end.0.row,
11901 column: symbol.range.end.0.column,
11902 }),
11903 worktree_id: Default::default(),
11904 path: Default::default(),
11905 signature: Default::default(),
11906 };
11907 match &symbol.path {
11908 SymbolLocation::InProject(path) => {
11909 result.worktree_id = path.worktree_id.to_proto();
11910 result.path = path.path.to_proto();
11911 }
11912 SymbolLocation::OutsideProject {
11913 abs_path,
11914 signature,
11915 } => {
11916 result.path = abs_path.to_string_lossy().into_owned();
11917 result.signature = signature.to_vec();
11918 }
11919 }
11920 result
11921 }
11922
11923 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11924 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11925 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11926 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11927
11928 let path = if serialized_symbol.signature.is_empty() {
11929 SymbolLocation::InProject(ProjectPath {
11930 worktree_id,
11931 path: RelPath::from_proto(&serialized_symbol.path)
11932 .context("invalid symbol path")?,
11933 })
11934 } else {
11935 SymbolLocation::OutsideProject {
11936 abs_path: Path::new(&serialized_symbol.path).into(),
11937 signature: serialized_symbol
11938 .signature
11939 .try_into()
11940 .map_err(|_| anyhow!("invalid signature"))?,
11941 }
11942 };
11943
11944 let start = serialized_symbol.start.context("invalid start")?;
11945 let end = serialized_symbol.end.context("invalid end")?;
11946 Ok(CoreSymbol {
11947 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11948 source_worktree_id,
11949 source_language_server_id: LanguageServerId::from_proto(
11950 serialized_symbol.language_server_id,
11951 ),
11952 path,
11953 name: serialized_symbol.name,
11954 range: Unclipped(PointUtf16::new(start.row, start.column))
11955 ..Unclipped(PointUtf16::new(end.row, end.column)),
11956 kind,
11957 })
11958 }
11959
11960 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11961 let mut serialized_completion = proto::Completion {
11962 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11963 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11964 new_text: completion.new_text.clone(),
11965 ..proto::Completion::default()
11966 };
11967 match &completion.source {
11968 CompletionSource::Lsp {
11969 insert_range,
11970 server_id,
11971 lsp_completion,
11972 lsp_defaults,
11973 resolved,
11974 } => {
11975 let (old_insert_start, old_insert_end) = insert_range
11976 .as_ref()
11977 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11978 .unzip();
11979
11980 serialized_completion.old_insert_start = old_insert_start;
11981 serialized_completion.old_insert_end = old_insert_end;
11982 serialized_completion.source = proto::completion::Source::Lsp as i32;
11983 serialized_completion.server_id = server_id.0 as u64;
11984 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11985 serialized_completion.lsp_defaults = lsp_defaults
11986 .as_deref()
11987 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11988 serialized_completion.resolved = *resolved;
11989 }
11990 CompletionSource::BufferWord {
11991 word_range,
11992 resolved,
11993 } => {
11994 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11995 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11996 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11997 serialized_completion.resolved = *resolved;
11998 }
11999 CompletionSource::Custom => {
12000 serialized_completion.source = proto::completion::Source::Custom as i32;
12001 serialized_completion.resolved = true;
12002 }
12003 CompletionSource::Dap { sort_text } => {
12004 serialized_completion.source = proto::completion::Source::Dap as i32;
12005 serialized_completion.sort_text = Some(sort_text.clone());
12006 }
12007 }
12008
12009 serialized_completion
12010 }
12011
12012 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12013 let old_replace_start = completion
12014 .old_replace_start
12015 .and_then(deserialize_anchor)
12016 .context("invalid old start")?;
12017 let old_replace_end = completion
12018 .old_replace_end
12019 .and_then(deserialize_anchor)
12020 .context("invalid old end")?;
12021 let insert_range = {
12022 match completion.old_insert_start.zip(completion.old_insert_end) {
12023 Some((start, end)) => {
12024 let start = deserialize_anchor(start).context("invalid insert old start")?;
12025 let end = deserialize_anchor(end).context("invalid insert old end")?;
12026 Some(start..end)
12027 }
12028 None => None,
12029 }
12030 };
12031 Ok(CoreCompletion {
12032 replace_range: old_replace_start..old_replace_end,
12033 new_text: completion.new_text,
12034 source: match proto::completion::Source::from_i32(completion.source) {
12035 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12036 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12037 insert_range,
12038 server_id: LanguageServerId::from_proto(completion.server_id),
12039 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12040 lsp_defaults: completion
12041 .lsp_defaults
12042 .as_deref()
12043 .map(serde_json::from_slice)
12044 .transpose()?,
12045 resolved: completion.resolved,
12046 },
12047 Some(proto::completion::Source::BufferWord) => {
12048 let word_range = completion
12049 .buffer_word_start
12050 .and_then(deserialize_anchor)
12051 .context("invalid buffer word start")?
12052 ..completion
12053 .buffer_word_end
12054 .and_then(deserialize_anchor)
12055 .context("invalid buffer word end")?;
12056 CompletionSource::BufferWord {
12057 word_range,
12058 resolved: completion.resolved,
12059 }
12060 }
12061 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12062 sort_text: completion
12063 .sort_text
12064 .context("expected sort text to exist")?,
12065 },
12066 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12067 },
12068 })
12069 }
12070
12071 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12072 let (kind, lsp_action) = match &action.lsp_action {
12073 LspAction::Action(code_action) => (
12074 proto::code_action::Kind::Action as i32,
12075 serde_json::to_vec(code_action).unwrap(),
12076 ),
12077 LspAction::Command(command) => (
12078 proto::code_action::Kind::Command as i32,
12079 serde_json::to_vec(command).unwrap(),
12080 ),
12081 LspAction::CodeLens(code_lens) => (
12082 proto::code_action::Kind::CodeLens as i32,
12083 serde_json::to_vec(code_lens).unwrap(),
12084 ),
12085 };
12086
12087 proto::CodeAction {
12088 server_id: action.server_id.0 as u64,
12089 start: Some(serialize_anchor(&action.range.start)),
12090 end: Some(serialize_anchor(&action.range.end)),
12091 lsp_action,
12092 kind,
12093 resolved: action.resolved,
12094 }
12095 }
12096
12097 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12098 let start = action
12099 .start
12100 .and_then(deserialize_anchor)
12101 .context("invalid start")?;
12102 let end = action
12103 .end
12104 .and_then(deserialize_anchor)
12105 .context("invalid end")?;
12106 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12107 Some(proto::code_action::Kind::Action) => {
12108 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12109 }
12110 Some(proto::code_action::Kind::Command) => {
12111 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12112 }
12113 Some(proto::code_action::Kind::CodeLens) => {
12114 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12115 }
12116 None => anyhow::bail!("Unknown action kind {}", action.kind),
12117 };
12118 Ok(CodeAction {
12119 server_id: LanguageServerId(action.server_id as usize),
12120 range: start..end,
12121 resolved: action.resolved,
12122 lsp_action,
12123 })
12124 }
12125
12126 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12127 match &formatting_result {
12128 Ok(_) => self.last_formatting_failure = None,
12129 Err(error) => {
12130 let error_string = format!("{error:#}");
12131 log::error!("Formatting failed: {error_string}");
12132 self.last_formatting_failure
12133 .replace(error_string.lines().join(" "));
12134 }
12135 }
12136 }
12137
12138 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12139 self.lsp_server_capabilities.remove(&for_server);
12140 for lsp_data in self.lsp_data.values_mut() {
12141 lsp_data.remove_server_data(for_server);
12142 }
12143 if let Some(local) = self.as_local_mut() {
12144 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12145 local
12146 .workspace_pull_diagnostics_result_ids
12147 .remove(&for_server);
12148 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12149 buffer_servers.remove(&for_server);
12150 }
12151 }
12152 }
12153
12154 pub fn result_id_for_buffer_pull(
12155 &self,
12156 server_id: LanguageServerId,
12157 buffer_id: BufferId,
12158 registration_id: &Option<SharedString>,
12159 cx: &App,
12160 ) -> Option<SharedString> {
12161 let abs_path = self
12162 .buffer_store
12163 .read(cx)
12164 .get(buffer_id)
12165 .and_then(|b| File::from_dyn(b.read(cx).file()))
12166 .map(|f| f.abs_path(cx))?;
12167 self.as_local()?
12168 .buffer_pull_diagnostics_result_ids
12169 .get(&server_id)?
12170 .get(registration_id)?
12171 .get(&abs_path)?
12172 .clone()
12173 }
12174
12175 /// Gets all result_ids for a workspace diagnostics pull request.
12176 /// 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.
12177 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12178 pub fn result_ids_for_workspace_refresh(
12179 &self,
12180 server_id: LanguageServerId,
12181 registration_id: &Option<SharedString>,
12182 ) -> HashMap<PathBuf, SharedString> {
12183 let Some(local) = self.as_local() else {
12184 return HashMap::default();
12185 };
12186 local
12187 .workspace_pull_diagnostics_result_ids
12188 .get(&server_id)
12189 .into_iter()
12190 .filter_map(|diagnostics| diagnostics.get(registration_id))
12191 .flatten()
12192 .filter_map(|(abs_path, result_id)| {
12193 let result_id = local
12194 .buffer_pull_diagnostics_result_ids
12195 .get(&server_id)
12196 .and_then(|buffer_ids_result_ids| {
12197 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12198 })
12199 .cloned()
12200 .flatten()
12201 .or_else(|| result_id.clone())?;
12202 Some((abs_path.clone(), result_id))
12203 })
12204 .collect()
12205 }
12206
12207 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12208 if let Some(LanguageServerState::Running {
12209 workspace_diagnostics_refresh_tasks,
12210 ..
12211 }) = self
12212 .as_local_mut()
12213 .and_then(|local| local.language_servers.get_mut(&server_id))
12214 {
12215 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12216 diagnostics.refresh_tx.try_send(()).ok();
12217 }
12218 }
12219 }
12220
12221 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12222 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12223 /// which requires refreshing both workspace and document diagnostics.
12224 pub fn pull_document_diagnostics_for_server(
12225 &mut self,
12226 server_id: LanguageServerId,
12227 cx: &mut Context<Self>,
12228 ) {
12229 let buffers_to_pull: Vec<_> = self
12230 .as_local()
12231 .into_iter()
12232 .flat_map(|local| {
12233 self.buffer_store.read(cx).buffers().filter(|buffer| {
12234 let buffer_id = buffer.read(cx).remote_id();
12235 local
12236 .buffers_opened_in_servers
12237 .get(&buffer_id)
12238 .is_some_and(|servers| servers.contains(&server_id))
12239 })
12240 })
12241 .collect();
12242
12243 for buffer in buffers_to_pull {
12244 self.pull_diagnostics_for_buffer(buffer, cx)
12245 .detach_and_log_err(cx);
12246 }
12247 }
12248
12249 fn apply_workspace_diagnostic_report(
12250 &mut self,
12251 server_id: LanguageServerId,
12252 report: lsp::WorkspaceDiagnosticReportResult,
12253 registration_id: Option<SharedString>,
12254 cx: &mut Context<Self>,
12255 ) {
12256 let mut workspace_diagnostics =
12257 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12258 report,
12259 server_id,
12260 registration_id,
12261 );
12262 workspace_diagnostics.retain(|d| match &d.diagnostics {
12263 LspPullDiagnostics::Response {
12264 server_id,
12265 registration_id,
12266 ..
12267 } => self.diagnostic_registration_exists(*server_id, registration_id),
12268 LspPullDiagnostics::Default => false,
12269 });
12270 let mut unchanged_buffers = HashMap::default();
12271 let workspace_diagnostics_updates = workspace_diagnostics
12272 .into_iter()
12273 .filter_map(
12274 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12275 LspPullDiagnostics::Response {
12276 server_id,
12277 uri,
12278 diagnostics,
12279 registration_id,
12280 } => Some((
12281 server_id,
12282 uri,
12283 diagnostics,
12284 workspace_diagnostics.version,
12285 registration_id,
12286 )),
12287 LspPullDiagnostics::Default => None,
12288 },
12289 )
12290 .fold(
12291 HashMap::default(),
12292 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12293 let (result_id, diagnostics) = match diagnostics {
12294 PulledDiagnostics::Unchanged { result_id } => {
12295 unchanged_buffers
12296 .entry(new_registration_id.clone())
12297 .or_insert_with(HashSet::default)
12298 .insert(uri.clone());
12299 (Some(result_id), Vec::new())
12300 }
12301 PulledDiagnostics::Changed {
12302 result_id,
12303 diagnostics,
12304 } => (result_id, diagnostics),
12305 };
12306 let disk_based_sources = Cow::Owned(
12307 self.language_server_adapter_for_id(server_id)
12308 .as_ref()
12309 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12310 .unwrap_or(&[])
12311 .to_vec(),
12312 );
12313
12314 let Some(abs_path) = uri.to_file_path().ok() else {
12315 return acc;
12316 };
12317 let Some((worktree, relative_path)) =
12318 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12319 else {
12320 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12321 return acc;
12322 };
12323 let worktree_id = worktree.read(cx).id();
12324 let project_path = ProjectPath {
12325 worktree_id,
12326 path: relative_path,
12327 };
12328 if let Some(local_lsp_store) = self.as_local_mut() {
12329 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12330 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12331 }
12332 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12333 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12334 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12335 acc.entry(server_id)
12336 .or_insert_with(HashMap::default)
12337 .entry(new_registration_id.clone())
12338 .or_insert_with(Vec::new)
12339 .push(DocumentDiagnosticsUpdate {
12340 server_id,
12341 diagnostics: lsp::PublishDiagnosticsParams {
12342 uri,
12343 diagnostics,
12344 version,
12345 },
12346 result_id,
12347 disk_based_sources,
12348 registration_id: new_registration_id,
12349 });
12350 }
12351 acc
12352 },
12353 );
12354
12355 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12356 for (registration_id, diagnostic_updates) in diagnostic_updates {
12357 self.merge_lsp_diagnostics(
12358 DiagnosticSourceKind::Pulled,
12359 diagnostic_updates,
12360 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12361 DiagnosticSourceKind::Pulled => {
12362 old_diagnostic.registration_id != registration_id
12363 || unchanged_buffers
12364 .get(&old_diagnostic.registration_id)
12365 .is_some_and(|unchanged_buffers| {
12366 unchanged_buffers.contains(&document_uri)
12367 })
12368 }
12369 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12370 },
12371 cx,
12372 )
12373 .log_err();
12374 }
12375 }
12376 }
12377
12378 fn register_server_capabilities(
12379 &mut self,
12380 server_id: LanguageServerId,
12381 params: lsp::RegistrationParams,
12382 cx: &mut Context<Self>,
12383 ) -> anyhow::Result<()> {
12384 let server = self
12385 .language_server_for_id(server_id)
12386 .with_context(|| format!("no server {server_id} found"))?;
12387 for reg in params.registrations {
12388 match reg.method.as_str() {
12389 "workspace/didChangeWatchedFiles" => {
12390 if let Some(options) = reg.register_options {
12391 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12392 let caps = serde_json::from_value(options)?;
12393 local_lsp_store
12394 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12395 true
12396 } else {
12397 false
12398 };
12399 if notify {
12400 notify_server_capabilities_updated(&server, cx);
12401 }
12402 }
12403 }
12404 "workspace/didChangeConfiguration" => {
12405 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12406 }
12407 "workspace/didChangeWorkspaceFolders" => {
12408 // In this case register options is an empty object, we can ignore it
12409 let caps = lsp::WorkspaceFoldersServerCapabilities {
12410 supported: Some(true),
12411 change_notifications: Some(OneOf::Right(reg.id)),
12412 };
12413 server.update_capabilities(|capabilities| {
12414 capabilities
12415 .workspace
12416 .get_or_insert_default()
12417 .workspace_folders = Some(caps);
12418 });
12419 notify_server_capabilities_updated(&server, cx);
12420 }
12421 "workspace/symbol" => {
12422 let options = parse_register_capabilities(reg)?;
12423 server.update_capabilities(|capabilities| {
12424 capabilities.workspace_symbol_provider = Some(options);
12425 });
12426 notify_server_capabilities_updated(&server, cx);
12427 }
12428 "workspace/fileOperations" => {
12429 if let Some(options) = reg.register_options {
12430 let caps = serde_json::from_value(options)?;
12431 server.update_capabilities(|capabilities| {
12432 capabilities
12433 .workspace
12434 .get_or_insert_default()
12435 .file_operations = Some(caps);
12436 });
12437 notify_server_capabilities_updated(&server, cx);
12438 }
12439 }
12440 "workspace/executeCommand" => {
12441 if let Some(options) = reg.register_options {
12442 let options = serde_json::from_value(options)?;
12443 server.update_capabilities(|capabilities| {
12444 capabilities.execute_command_provider = Some(options);
12445 });
12446 notify_server_capabilities_updated(&server, cx);
12447 }
12448 }
12449 "textDocument/rangeFormatting" => {
12450 let options = parse_register_capabilities(reg)?;
12451 server.update_capabilities(|capabilities| {
12452 capabilities.document_range_formatting_provider = Some(options);
12453 });
12454 notify_server_capabilities_updated(&server, cx);
12455 }
12456 "textDocument/onTypeFormatting" => {
12457 if let Some(options) = reg
12458 .register_options
12459 .map(serde_json::from_value)
12460 .transpose()?
12461 {
12462 server.update_capabilities(|capabilities| {
12463 capabilities.document_on_type_formatting_provider = Some(options);
12464 });
12465 notify_server_capabilities_updated(&server, cx);
12466 }
12467 }
12468 "textDocument/formatting" => {
12469 let options = parse_register_capabilities(reg)?;
12470 server.update_capabilities(|capabilities| {
12471 capabilities.document_formatting_provider = Some(options);
12472 });
12473 notify_server_capabilities_updated(&server, cx);
12474 }
12475 "textDocument/rename" => {
12476 let options = parse_register_capabilities(reg)?;
12477 server.update_capabilities(|capabilities| {
12478 capabilities.rename_provider = Some(options);
12479 });
12480 notify_server_capabilities_updated(&server, cx);
12481 }
12482 "textDocument/inlayHint" => {
12483 let options = parse_register_capabilities(reg)?;
12484 server.update_capabilities(|capabilities| {
12485 capabilities.inlay_hint_provider = Some(options);
12486 });
12487 notify_server_capabilities_updated(&server, cx);
12488 }
12489 "textDocument/documentSymbol" => {
12490 let options = parse_register_capabilities(reg)?;
12491 server.update_capabilities(|capabilities| {
12492 capabilities.document_symbol_provider = Some(options);
12493 });
12494 notify_server_capabilities_updated(&server, cx);
12495 }
12496 "textDocument/codeAction" => {
12497 let options = parse_register_capabilities(reg)?;
12498 let provider = match options {
12499 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12500 OneOf::Right(caps) => caps,
12501 };
12502 server.update_capabilities(|capabilities| {
12503 capabilities.code_action_provider = Some(provider);
12504 });
12505 notify_server_capabilities_updated(&server, cx);
12506 }
12507 "textDocument/definition" => {
12508 let options = parse_register_capabilities(reg)?;
12509 server.update_capabilities(|capabilities| {
12510 capabilities.definition_provider = Some(options);
12511 });
12512 notify_server_capabilities_updated(&server, cx);
12513 }
12514 "textDocument/completion" => {
12515 if let Some(caps) = reg
12516 .register_options
12517 .map(serde_json::from_value::<CompletionOptions>)
12518 .transpose()?
12519 {
12520 server.update_capabilities(|capabilities| {
12521 capabilities.completion_provider = Some(caps.clone());
12522 });
12523
12524 if let Some(local) = self.as_local() {
12525 let mut buffers_with_language_server = Vec::new();
12526 for handle in self.buffer_store.read(cx).buffers() {
12527 let buffer_id = handle.read(cx).remote_id();
12528 if local
12529 .buffers_opened_in_servers
12530 .get(&buffer_id)
12531 .filter(|s| s.contains(&server_id))
12532 .is_some()
12533 {
12534 buffers_with_language_server.push(handle);
12535 }
12536 }
12537 let triggers = caps
12538 .trigger_characters
12539 .unwrap_or_default()
12540 .into_iter()
12541 .collect::<BTreeSet<_>>();
12542 for handle in buffers_with_language_server {
12543 let triggers = triggers.clone();
12544 let _ = handle.update(cx, move |buffer, cx| {
12545 buffer.set_completion_triggers(server_id, triggers, cx);
12546 });
12547 }
12548 }
12549 notify_server_capabilities_updated(&server, cx);
12550 }
12551 }
12552 "textDocument/hover" => {
12553 let options = parse_register_capabilities(reg)?;
12554 let provider = match options {
12555 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12556 OneOf::Right(caps) => caps,
12557 };
12558 server.update_capabilities(|capabilities| {
12559 capabilities.hover_provider = Some(provider);
12560 });
12561 notify_server_capabilities_updated(&server, cx);
12562 }
12563 "textDocument/signatureHelp" => {
12564 if let Some(caps) = reg
12565 .register_options
12566 .map(serde_json::from_value)
12567 .transpose()?
12568 {
12569 server.update_capabilities(|capabilities| {
12570 capabilities.signature_help_provider = Some(caps);
12571 });
12572 notify_server_capabilities_updated(&server, cx);
12573 }
12574 }
12575 "textDocument/didChange" => {
12576 if let Some(sync_kind) = reg
12577 .register_options
12578 .and_then(|opts| opts.get("syncKind").cloned())
12579 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12580 .transpose()?
12581 {
12582 server.update_capabilities(|capabilities| {
12583 let mut sync_options =
12584 Self::take_text_document_sync_options(capabilities);
12585 sync_options.change = Some(sync_kind);
12586 capabilities.text_document_sync =
12587 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12588 });
12589 notify_server_capabilities_updated(&server, cx);
12590 }
12591 }
12592 "textDocument/didSave" => {
12593 if let Some(include_text) = reg
12594 .register_options
12595 .map(|opts| {
12596 let transpose = opts
12597 .get("includeText")
12598 .cloned()
12599 .map(serde_json::from_value::<Option<bool>>)
12600 .transpose();
12601 match transpose {
12602 Ok(value) => Ok(value.flatten()),
12603 Err(e) => Err(e),
12604 }
12605 })
12606 .transpose()?
12607 {
12608 server.update_capabilities(|capabilities| {
12609 let mut sync_options =
12610 Self::take_text_document_sync_options(capabilities);
12611 sync_options.save =
12612 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12613 include_text,
12614 }));
12615 capabilities.text_document_sync =
12616 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12617 });
12618 notify_server_capabilities_updated(&server, cx);
12619 }
12620 }
12621 "textDocument/codeLens" => {
12622 if let Some(caps) = reg
12623 .register_options
12624 .map(serde_json::from_value)
12625 .transpose()?
12626 {
12627 server.update_capabilities(|capabilities| {
12628 capabilities.code_lens_provider = Some(caps);
12629 });
12630 notify_server_capabilities_updated(&server, cx);
12631 }
12632 }
12633 "textDocument/diagnostic" => {
12634 if let Some(caps) = reg
12635 .register_options
12636 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12637 .transpose()?
12638 {
12639 let local = self
12640 .as_local_mut()
12641 .context("Expected LSP Store to be local")?;
12642 let state = local
12643 .language_servers
12644 .get_mut(&server_id)
12645 .context("Could not obtain Language Servers state")?;
12646 local
12647 .language_server_dynamic_registrations
12648 .entry(server_id)
12649 .or_default()
12650 .diagnostics
12651 .insert(Some(reg.id.clone()), caps.clone());
12652
12653 let supports_workspace_diagnostics =
12654 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12655 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12656 diagnostic_options.workspace_diagnostics
12657 }
12658 DiagnosticServerCapabilities::RegistrationOptions(
12659 diagnostic_registration_options,
12660 ) => {
12661 diagnostic_registration_options
12662 .diagnostic_options
12663 .workspace_diagnostics
12664 }
12665 };
12666
12667 if supports_workspace_diagnostics(&caps) {
12668 if let LanguageServerState::Running {
12669 workspace_diagnostics_refresh_tasks,
12670 ..
12671 } = state
12672 && let Some(task) = lsp_workspace_diagnostics_refresh(
12673 Some(reg.id.clone()),
12674 caps.clone(),
12675 server.clone(),
12676 cx,
12677 )
12678 {
12679 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12680 }
12681 }
12682
12683 server.update_capabilities(|capabilities| {
12684 capabilities.diagnostic_provider = Some(caps);
12685 });
12686
12687 notify_server_capabilities_updated(&server, cx);
12688
12689 self.pull_document_diagnostics_for_server(server_id, cx);
12690 }
12691 }
12692 "textDocument/documentColor" => {
12693 let options = parse_register_capabilities(reg)?;
12694 let provider = match options {
12695 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12696 OneOf::Right(caps) => caps,
12697 };
12698 server.update_capabilities(|capabilities| {
12699 capabilities.color_provider = Some(provider);
12700 });
12701 notify_server_capabilities_updated(&server, cx);
12702 }
12703 _ => log::warn!("unhandled capability registration: {reg:?}"),
12704 }
12705 }
12706
12707 Ok(())
12708 }
12709
12710 fn unregister_server_capabilities(
12711 &mut self,
12712 server_id: LanguageServerId,
12713 params: lsp::UnregistrationParams,
12714 cx: &mut Context<Self>,
12715 ) -> anyhow::Result<()> {
12716 let server = self
12717 .language_server_for_id(server_id)
12718 .with_context(|| format!("no server {server_id} found"))?;
12719 for unreg in params.unregisterations.iter() {
12720 match unreg.method.as_str() {
12721 "workspace/didChangeWatchedFiles" => {
12722 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12723 local_lsp_store
12724 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12725 true
12726 } else {
12727 false
12728 };
12729 if notify {
12730 notify_server_capabilities_updated(&server, cx);
12731 }
12732 }
12733 "workspace/didChangeConfiguration" => {
12734 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12735 }
12736 "workspace/didChangeWorkspaceFolders" => {
12737 server.update_capabilities(|capabilities| {
12738 capabilities
12739 .workspace
12740 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12741 workspace_folders: None,
12742 file_operations: None,
12743 })
12744 .workspace_folders = None;
12745 });
12746 notify_server_capabilities_updated(&server, cx);
12747 }
12748 "workspace/symbol" => {
12749 server.update_capabilities(|capabilities| {
12750 capabilities.workspace_symbol_provider = None
12751 });
12752 notify_server_capabilities_updated(&server, cx);
12753 }
12754 "workspace/fileOperations" => {
12755 server.update_capabilities(|capabilities| {
12756 capabilities
12757 .workspace
12758 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12759 workspace_folders: None,
12760 file_operations: None,
12761 })
12762 .file_operations = None;
12763 });
12764 notify_server_capabilities_updated(&server, cx);
12765 }
12766 "workspace/executeCommand" => {
12767 server.update_capabilities(|capabilities| {
12768 capabilities.execute_command_provider = None;
12769 });
12770 notify_server_capabilities_updated(&server, cx);
12771 }
12772 "textDocument/rangeFormatting" => {
12773 server.update_capabilities(|capabilities| {
12774 capabilities.document_range_formatting_provider = None
12775 });
12776 notify_server_capabilities_updated(&server, cx);
12777 }
12778 "textDocument/onTypeFormatting" => {
12779 server.update_capabilities(|capabilities| {
12780 capabilities.document_on_type_formatting_provider = None;
12781 });
12782 notify_server_capabilities_updated(&server, cx);
12783 }
12784 "textDocument/formatting" => {
12785 server.update_capabilities(|capabilities| {
12786 capabilities.document_formatting_provider = None;
12787 });
12788 notify_server_capabilities_updated(&server, cx);
12789 }
12790 "textDocument/rename" => {
12791 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12792 notify_server_capabilities_updated(&server, cx);
12793 }
12794 "textDocument/codeAction" => {
12795 server.update_capabilities(|capabilities| {
12796 capabilities.code_action_provider = None;
12797 });
12798 notify_server_capabilities_updated(&server, cx);
12799 }
12800 "textDocument/definition" => {
12801 server.update_capabilities(|capabilities| {
12802 capabilities.definition_provider = None;
12803 });
12804 notify_server_capabilities_updated(&server, cx);
12805 }
12806 "textDocument/completion" => {
12807 server.update_capabilities(|capabilities| {
12808 capabilities.completion_provider = None;
12809 });
12810 notify_server_capabilities_updated(&server, cx);
12811 }
12812 "textDocument/hover" => {
12813 server.update_capabilities(|capabilities| {
12814 capabilities.hover_provider = None;
12815 });
12816 notify_server_capabilities_updated(&server, cx);
12817 }
12818 "textDocument/signatureHelp" => {
12819 server.update_capabilities(|capabilities| {
12820 capabilities.signature_help_provider = None;
12821 });
12822 notify_server_capabilities_updated(&server, cx);
12823 }
12824 "textDocument/didChange" => {
12825 server.update_capabilities(|capabilities| {
12826 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12827 sync_options.change = None;
12828 capabilities.text_document_sync =
12829 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12830 });
12831 notify_server_capabilities_updated(&server, cx);
12832 }
12833 "textDocument/didSave" => {
12834 server.update_capabilities(|capabilities| {
12835 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12836 sync_options.save = None;
12837 capabilities.text_document_sync =
12838 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12839 });
12840 notify_server_capabilities_updated(&server, cx);
12841 }
12842 "textDocument/codeLens" => {
12843 server.update_capabilities(|capabilities| {
12844 capabilities.code_lens_provider = None;
12845 });
12846 notify_server_capabilities_updated(&server, cx);
12847 }
12848 "textDocument/diagnostic" => {
12849 let local = self
12850 .as_local_mut()
12851 .context("Expected LSP Store to be local")?;
12852
12853 let state = local
12854 .language_servers
12855 .get_mut(&server_id)
12856 .context("Could not obtain Language Servers state")?;
12857 let registrations = local
12858 .language_server_dynamic_registrations
12859 .get_mut(&server_id)
12860 .with_context(|| {
12861 format!("Expected dynamic registration to exist for server {server_id}")
12862 })?;
12863 registrations.diagnostics
12864 .remove(&Some(unreg.id.clone()))
12865 .with_context(|| format!(
12866 "Attempted to unregister non-existent diagnostic registration with ID {}",
12867 unreg.id)
12868 )?;
12869 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12870
12871 if let LanguageServerState::Running {
12872 workspace_diagnostics_refresh_tasks,
12873 ..
12874 } = state
12875 {
12876 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12877 }
12878
12879 self.clear_unregistered_diagnostics(
12880 server_id,
12881 SharedString::from(unreg.id.clone()),
12882 cx,
12883 )?;
12884
12885 if removed_last_diagnostic_provider {
12886 server.update_capabilities(|capabilities| {
12887 debug_assert!(capabilities.diagnostic_provider.is_some());
12888 capabilities.diagnostic_provider = None;
12889 });
12890 }
12891
12892 notify_server_capabilities_updated(&server, cx);
12893 }
12894 "textDocument/documentColor" => {
12895 server.update_capabilities(|capabilities| {
12896 capabilities.color_provider = None;
12897 });
12898 notify_server_capabilities_updated(&server, cx);
12899 }
12900 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12901 }
12902 }
12903
12904 Ok(())
12905 }
12906
12907 fn clear_unregistered_diagnostics(
12908 &mut self,
12909 server_id: LanguageServerId,
12910 cleared_registration_id: SharedString,
12911 cx: &mut Context<Self>,
12912 ) -> anyhow::Result<()> {
12913 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12914
12915 self.buffer_store.update(cx, |buffer_store, cx| {
12916 for buffer_handle in buffer_store.buffers() {
12917 let buffer = buffer_handle.read(cx);
12918 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12919 let Some(abs_path) = abs_path else {
12920 continue;
12921 };
12922 affected_abs_paths.insert(abs_path);
12923 }
12924 });
12925
12926 let local = self.as_local().context("Expected LSP Store to be local")?;
12927 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12928 let Some(worktree) = self
12929 .worktree_store
12930 .read(cx)
12931 .worktree_for_id(*worktree_id, cx)
12932 else {
12933 continue;
12934 };
12935
12936 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12937 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12938 let has_matching_registration =
12939 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12940 entry.diagnostic.registration_id.as_ref()
12941 == Some(&cleared_registration_id)
12942 });
12943 if has_matching_registration {
12944 let abs_path = worktree.read(cx).absolutize(rel_path);
12945 affected_abs_paths.insert(abs_path);
12946 }
12947 }
12948 }
12949 }
12950
12951 if affected_abs_paths.is_empty() {
12952 return Ok(());
12953 }
12954
12955 // Send a fake diagnostic update which clears the state for the registration ID
12956 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12957 affected_abs_paths
12958 .into_iter()
12959 .map(|abs_path| DocumentDiagnosticsUpdate {
12960 diagnostics: DocumentDiagnostics {
12961 diagnostics: Vec::new(),
12962 document_abs_path: abs_path,
12963 version: None,
12964 },
12965 result_id: None,
12966 registration_id: Some(cleared_registration_id.clone()),
12967 server_id,
12968 disk_based_sources: Cow::Borrowed(&[]),
12969 })
12970 .collect();
12971
12972 let merge_registration_id = cleared_registration_id.clone();
12973 self.merge_diagnostic_entries(
12974 clears,
12975 move |_, diagnostic, _| {
12976 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12977 diagnostic.registration_id != Some(merge_registration_id.clone())
12978 } else {
12979 true
12980 }
12981 },
12982 cx,
12983 )?;
12984
12985 Ok(())
12986 }
12987
12988 async fn deduplicate_range_based_lsp_requests<T>(
12989 lsp_store: &Entity<Self>,
12990 server_id: Option<LanguageServerId>,
12991 lsp_request_id: LspRequestId,
12992 proto_request: &T::ProtoRequest,
12993 range: Range<Anchor>,
12994 cx: &mut AsyncApp,
12995 ) -> Result<()>
12996 where
12997 T: LspCommand,
12998 T::ProtoRequest: proto::LspRequestMessage,
12999 {
13000 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13001 let version = deserialize_version(proto_request.buffer_version());
13002 let buffer = lsp_store.update(cx, |this, cx| {
13003 this.buffer_store.read(cx).get_existing(buffer_id)
13004 })??;
13005 buffer
13006 .update(cx, |buffer, _| buffer.wait_for_version(version))?
13007 .await?;
13008 lsp_store.update(cx, |lsp_store, cx| {
13009 let buffer_snapshot = buffer.read(cx).snapshot();
13010 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13011 let chunks_queried_for = lsp_data
13012 .inlay_hints
13013 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13014 .collect::<Vec<_>>();
13015 match chunks_queried_for.as_slice() {
13016 &[chunk] => {
13017 let key = LspKey {
13018 request_type: TypeId::of::<T>(),
13019 server_queried: server_id,
13020 };
13021 let previous_request = lsp_data
13022 .chunk_lsp_requests
13023 .entry(key)
13024 .or_default()
13025 .insert(chunk, lsp_request_id);
13026 if let Some((previous_request, running_requests)) =
13027 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13028 {
13029 running_requests.remove(&previous_request);
13030 }
13031 }
13032 _ambiguous_chunks => {
13033 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13034 // there, a buffer version-based check will be performed and outdated requests discarded.
13035 }
13036 }
13037 anyhow::Ok(())
13038 })??;
13039
13040 Ok(())
13041 }
13042
13043 async fn query_lsp_locally<T>(
13044 lsp_store: Entity<Self>,
13045 for_server_id: Option<LanguageServerId>,
13046 sender_id: proto::PeerId,
13047 lsp_request_id: LspRequestId,
13048 proto_request: T::ProtoRequest,
13049 position: Option<Anchor>,
13050 cx: &mut AsyncApp,
13051 ) -> Result<()>
13052 where
13053 T: LspCommand + Clone,
13054 T::ProtoRequest: proto::LspRequestMessage,
13055 <T::ProtoRequest as proto::RequestMessage>::Response:
13056 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13057 {
13058 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13059 let version = deserialize_version(proto_request.buffer_version());
13060 let buffer = lsp_store.update(cx, |this, cx| {
13061 this.buffer_store.read(cx).get_existing(buffer_id)
13062 })??;
13063 buffer
13064 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))?
13065 .await?;
13066 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version())?;
13067 let request =
13068 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13069 let key = LspKey {
13070 request_type: TypeId::of::<T>(),
13071 server_queried: for_server_id,
13072 };
13073 lsp_store.update(cx, |lsp_store, cx| {
13074 let request_task = match for_server_id {
13075 Some(server_id) => {
13076 let server_task = lsp_store.request_lsp(
13077 buffer.clone(),
13078 LanguageServerToQuery::Other(server_id),
13079 request.clone(),
13080 cx,
13081 );
13082 cx.background_spawn(async move {
13083 let mut responses = Vec::new();
13084 match server_task.await {
13085 Ok(response) => responses.push((server_id, response)),
13086 // rust-analyzer likes to error with this when its still loading up
13087 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13088 Err(e) => log::error!(
13089 "Error handling response for request {request:?}: {e:#}"
13090 ),
13091 }
13092 responses
13093 })
13094 }
13095 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13096 };
13097 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13098 if T::ProtoRequest::stop_previous_requests() {
13099 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13100 lsp_requests.clear();
13101 }
13102 }
13103 lsp_data.lsp_requests.entry(key).or_default().insert(
13104 lsp_request_id,
13105 cx.spawn(async move |lsp_store, cx| {
13106 let response = request_task.await;
13107 lsp_store
13108 .update(cx, |lsp_store, cx| {
13109 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13110 {
13111 let response = response
13112 .into_iter()
13113 .map(|(server_id, response)| {
13114 (
13115 server_id.to_proto(),
13116 T::response_to_proto(
13117 response,
13118 lsp_store,
13119 sender_id,
13120 &buffer_version,
13121 cx,
13122 )
13123 .into(),
13124 )
13125 })
13126 .collect::<HashMap<_, _>>();
13127 match client.send_lsp_response::<T::ProtoRequest>(
13128 project_id,
13129 lsp_request_id,
13130 response,
13131 ) {
13132 Ok(()) => {}
13133 Err(e) => {
13134 log::error!("Failed to send LSP response: {e:#}",)
13135 }
13136 }
13137 }
13138 })
13139 .ok();
13140 }),
13141 );
13142 })?;
13143 Ok(())
13144 }
13145
13146 fn take_text_document_sync_options(
13147 capabilities: &mut lsp::ServerCapabilities,
13148 ) -> lsp::TextDocumentSyncOptions {
13149 match capabilities.text_document_sync.take() {
13150 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13151 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13152 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13153 sync_options.change = Some(sync_kind);
13154 sync_options
13155 }
13156 None => lsp::TextDocumentSyncOptions::default(),
13157 }
13158 }
13159
13160 #[cfg(any(test, feature = "test-support"))]
13161 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13162 Some(
13163 self.lsp_data
13164 .get_mut(&buffer_id)?
13165 .code_lens
13166 .take()?
13167 .update
13168 .take()?
13169 .1,
13170 )
13171 }
13172
13173 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13174 self.downstream_client.clone()
13175 }
13176
13177 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13178 self.worktree_store.clone()
13179 }
13180
13181 /// Gets what's stored in the LSP data for the given buffer.
13182 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13183 self.lsp_data.get_mut(&buffer_id)
13184 }
13185
13186 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13187 /// new [`BufferLspData`] will be created to replace the previous state.
13188 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13189 let (buffer_id, buffer_version) =
13190 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13191 let lsp_data = self
13192 .lsp_data
13193 .entry(buffer_id)
13194 .or_insert_with(|| BufferLspData::new(buffer, cx));
13195 if buffer_version.changed_since(&lsp_data.buffer_version) {
13196 *lsp_data = BufferLspData::new(buffer, cx);
13197 }
13198 lsp_data
13199 }
13200}
13201
13202// Registration with registerOptions as null, should fallback to true.
13203// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13204fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13205 reg: lsp::Registration,
13206) -> Result<OneOf<bool, T>> {
13207 Ok(match reg.register_options {
13208 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13209 None => OneOf::Left(true),
13210 })
13211}
13212
13213fn subscribe_to_binary_statuses(
13214 languages: &Arc<LanguageRegistry>,
13215 cx: &mut Context<'_, LspStore>,
13216) -> Task<()> {
13217 let mut server_statuses = languages.language_server_binary_statuses();
13218 cx.spawn(async move |lsp_store, cx| {
13219 while let Some((server_name, binary_status)) = server_statuses.next().await {
13220 if lsp_store
13221 .update(cx, |_, cx| {
13222 let mut message = None;
13223 let binary_status = match binary_status {
13224 BinaryStatus::None => proto::ServerBinaryStatus::None,
13225 BinaryStatus::CheckingForUpdate => {
13226 proto::ServerBinaryStatus::CheckingForUpdate
13227 }
13228 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13229 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13230 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13231 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13232 BinaryStatus::Failed { error } => {
13233 message = Some(error);
13234 proto::ServerBinaryStatus::Failed
13235 }
13236 };
13237 cx.emit(LspStoreEvent::LanguageServerUpdate {
13238 // Binary updates are about the binary that might not have any language server id at that point.
13239 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13240 language_server_id: LanguageServerId(0),
13241 name: Some(server_name),
13242 message: proto::update_language_server::Variant::StatusUpdate(
13243 proto::StatusUpdate {
13244 message,
13245 status: Some(proto::status_update::Status::Binary(
13246 binary_status as i32,
13247 )),
13248 },
13249 ),
13250 });
13251 })
13252 .is_err()
13253 {
13254 break;
13255 }
13256 }
13257 })
13258}
13259
13260fn lsp_workspace_diagnostics_refresh(
13261 registration_id: Option<String>,
13262 options: DiagnosticServerCapabilities,
13263 server: Arc<LanguageServer>,
13264 cx: &mut Context<'_, LspStore>,
13265) -> Option<WorkspaceRefreshTask> {
13266 let identifier = workspace_diagnostic_identifier(&options)?;
13267 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13268
13269 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13270 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13271 refresh_tx.try_send(()).ok();
13272
13273 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13274 let mut attempts = 0;
13275 let max_attempts = 50;
13276 let mut requests = 0;
13277
13278 loop {
13279 let Some(()) = refresh_rx.recv().await else {
13280 return;
13281 };
13282
13283 'request: loop {
13284 requests += 1;
13285 if attempts > max_attempts {
13286 log::error!(
13287 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13288 );
13289 return;
13290 }
13291 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13292 cx.background_executor()
13293 .timer(Duration::from_millis(backoff_millis))
13294 .await;
13295 attempts += 1;
13296
13297 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13298 lsp_store
13299 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13300 .into_iter()
13301 .filter_map(|(abs_path, result_id)| {
13302 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13303 Some(lsp::PreviousResultId {
13304 uri,
13305 value: result_id.to_string(),
13306 })
13307 })
13308 .collect()
13309 }) else {
13310 return;
13311 };
13312
13313 let token = if let Some(registration_id) = ®istration_id {
13314 format!(
13315 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13316 server.server_id(),
13317 )
13318 } else {
13319 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13320 };
13321
13322 progress_rx.try_recv().ok();
13323 let timer =
13324 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13325 let progress = pin!(progress_rx.recv().fuse());
13326 let response_result = server
13327 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13328 lsp::WorkspaceDiagnosticParams {
13329 previous_result_ids,
13330 identifier: identifier.clone(),
13331 work_done_progress_params: Default::default(),
13332 partial_result_params: lsp::PartialResultParams {
13333 partial_result_token: Some(lsp::ProgressToken::String(token)),
13334 },
13335 },
13336 select(timer, progress).then(|either| match either {
13337 Either::Left((message, ..)) => ready(message).left_future(),
13338 Either::Right(..) => pending::<String>().right_future(),
13339 }),
13340 )
13341 .await;
13342
13343 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13344 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13345 match response_result {
13346 ConnectionResult::Timeout => {
13347 log::error!("Timeout during workspace diagnostics pull");
13348 continue 'request;
13349 }
13350 ConnectionResult::ConnectionReset => {
13351 log::error!("Server closed a workspace diagnostics pull request");
13352 continue 'request;
13353 }
13354 ConnectionResult::Result(Err(e)) => {
13355 log::error!("Error during workspace diagnostics pull: {e:#}");
13356 break 'request;
13357 }
13358 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13359 attempts = 0;
13360 if lsp_store
13361 .update(cx, |lsp_store, cx| {
13362 lsp_store.apply_workspace_diagnostic_report(
13363 server.server_id(),
13364 pulled_diagnostics,
13365 registration_id_shared.clone(),
13366 cx,
13367 )
13368 })
13369 .is_err()
13370 {
13371 return;
13372 }
13373 break 'request;
13374 }
13375 }
13376 }
13377 }
13378 });
13379
13380 Some(WorkspaceRefreshTask {
13381 refresh_tx,
13382 progress_tx,
13383 task: workspace_query_language_server,
13384 })
13385}
13386
13387fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13388 match &options {
13389 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13390 diagnostic_options.identifier.clone()
13391 }
13392 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13393 let diagnostic_options = ®istration_options.diagnostic_options;
13394 diagnostic_options.identifier.clone()
13395 }
13396 }
13397}
13398
13399fn workspace_diagnostic_identifier(
13400 options: &DiagnosticServerCapabilities,
13401) -> Option<Option<String>> {
13402 match &options {
13403 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13404 if !diagnostic_options.workspace_diagnostics {
13405 return None;
13406 }
13407 Some(diagnostic_options.identifier.clone())
13408 }
13409 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13410 let diagnostic_options = ®istration_options.diagnostic_options;
13411 if !diagnostic_options.workspace_diagnostics {
13412 return None;
13413 }
13414 Some(diagnostic_options.identifier.clone())
13415 }
13416 }
13417}
13418
13419fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13420 let CompletionSource::BufferWord {
13421 word_range,
13422 resolved,
13423 } = &mut completion.source
13424 else {
13425 return;
13426 };
13427 if *resolved {
13428 return;
13429 }
13430
13431 if completion.new_text
13432 != snapshot
13433 .text_for_range(word_range.clone())
13434 .collect::<String>()
13435 {
13436 return;
13437 }
13438
13439 let mut offset = 0;
13440 for chunk in snapshot.chunks(word_range.clone(), true) {
13441 let end_offset = offset + chunk.text.len();
13442 if let Some(highlight_id) = chunk.syntax_highlight_id {
13443 completion
13444 .label
13445 .runs
13446 .push((offset..end_offset, highlight_id));
13447 }
13448 offset = end_offset;
13449 }
13450 *resolved = true;
13451}
13452
13453impl EventEmitter<LspStoreEvent> for LspStore {}
13454
13455fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13456 hover
13457 .contents
13458 .retain(|hover_block| !hover_block.text.trim().is_empty());
13459 if hover.contents.is_empty() {
13460 None
13461 } else {
13462 Some(hover)
13463 }
13464}
13465
13466async fn populate_labels_for_completions(
13467 new_completions: Vec<CoreCompletion>,
13468 language: Option<Arc<Language>>,
13469 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13470) -> Vec<Completion> {
13471 let lsp_completions = new_completions
13472 .iter()
13473 .filter_map(|new_completion| {
13474 new_completion
13475 .source
13476 .lsp_completion(true)
13477 .map(|lsp_completion| lsp_completion.into_owned())
13478 })
13479 .collect::<Vec<_>>();
13480
13481 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13482 lsp_adapter
13483 .labels_for_completions(&lsp_completions, language)
13484 .await
13485 .log_err()
13486 .unwrap_or_default()
13487 } else {
13488 Vec::new()
13489 }
13490 .into_iter()
13491 .fuse();
13492
13493 let mut completions = Vec::new();
13494 for completion in new_completions {
13495 match completion.source.lsp_completion(true) {
13496 Some(lsp_completion) => {
13497 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13498
13499 let mut label = labels.next().flatten().unwrap_or_else(|| {
13500 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13501 });
13502 ensure_uniform_list_compatible_label(&mut label);
13503 completions.push(Completion {
13504 label,
13505 documentation,
13506 replace_range: completion.replace_range,
13507 new_text: completion.new_text,
13508 insert_text_mode: lsp_completion.insert_text_mode,
13509 source: completion.source,
13510 icon_path: None,
13511 confirm: None,
13512 match_start: None,
13513 snippet_deduplication_key: None,
13514 });
13515 }
13516 None => {
13517 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13518 ensure_uniform_list_compatible_label(&mut label);
13519 completions.push(Completion {
13520 label,
13521 documentation: None,
13522 replace_range: completion.replace_range,
13523 new_text: completion.new_text,
13524 source: completion.source,
13525 insert_text_mode: None,
13526 icon_path: None,
13527 confirm: None,
13528 match_start: None,
13529 snippet_deduplication_key: None,
13530 });
13531 }
13532 }
13533 }
13534 completions
13535}
13536
13537#[derive(Debug)]
13538pub enum LanguageServerToQuery {
13539 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13540 FirstCapable,
13541 /// Query a specific language server.
13542 Other(LanguageServerId),
13543}
13544
13545#[derive(Default)]
13546struct RenamePathsWatchedForServer {
13547 did_rename: Vec<RenameActionPredicate>,
13548 will_rename: Vec<RenameActionPredicate>,
13549}
13550
13551impl RenamePathsWatchedForServer {
13552 fn with_did_rename_patterns(
13553 mut self,
13554 did_rename: Option<&FileOperationRegistrationOptions>,
13555 ) -> Self {
13556 if let Some(did_rename) = did_rename {
13557 self.did_rename = did_rename
13558 .filters
13559 .iter()
13560 .filter_map(|filter| filter.try_into().log_err())
13561 .collect();
13562 }
13563 self
13564 }
13565 fn with_will_rename_patterns(
13566 mut self,
13567 will_rename: Option<&FileOperationRegistrationOptions>,
13568 ) -> Self {
13569 if let Some(will_rename) = will_rename {
13570 self.will_rename = will_rename
13571 .filters
13572 .iter()
13573 .filter_map(|filter| filter.try_into().log_err())
13574 .collect();
13575 }
13576 self
13577 }
13578
13579 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13580 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13581 }
13582 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13583 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13584 }
13585}
13586
13587impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13588 type Error = globset::Error;
13589 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13590 Ok(Self {
13591 kind: ops.pattern.matches.clone(),
13592 glob: GlobBuilder::new(&ops.pattern.glob)
13593 .case_insensitive(
13594 ops.pattern
13595 .options
13596 .as_ref()
13597 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13598 )
13599 .build()?
13600 .compile_matcher(),
13601 })
13602 }
13603}
13604struct RenameActionPredicate {
13605 glob: GlobMatcher,
13606 kind: Option<FileOperationPatternKind>,
13607}
13608
13609impl RenameActionPredicate {
13610 // Returns true if language server should be notified
13611 fn eval(&self, path: &str, is_dir: bool) -> bool {
13612 self.kind.as_ref().is_none_or(|kind| {
13613 let expected_kind = if is_dir {
13614 FileOperationPatternKind::Folder
13615 } else {
13616 FileOperationPatternKind::File
13617 };
13618 kind == &expected_kind
13619 }) && self.glob.is_match(path)
13620 }
13621}
13622
13623#[derive(Default)]
13624struct LanguageServerWatchedPaths {
13625 worktree_paths: HashMap<WorktreeId, GlobSet>,
13626 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13627}
13628
13629#[derive(Default)]
13630struct LanguageServerWatchedPathsBuilder {
13631 worktree_paths: HashMap<WorktreeId, GlobSet>,
13632 abs_paths: HashMap<Arc<Path>, GlobSet>,
13633}
13634
13635impl LanguageServerWatchedPathsBuilder {
13636 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13637 self.worktree_paths.insert(worktree_id, glob_set);
13638 }
13639 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13640 self.abs_paths.insert(path, glob_set);
13641 }
13642 fn build(
13643 self,
13644 fs: Arc<dyn Fs>,
13645 language_server_id: LanguageServerId,
13646 cx: &mut Context<LspStore>,
13647 ) -> LanguageServerWatchedPaths {
13648 let lsp_store = cx.weak_entity();
13649
13650 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13651 let abs_paths = self
13652 .abs_paths
13653 .into_iter()
13654 .map(|(abs_path, globset)| {
13655 let task = cx.spawn({
13656 let abs_path = abs_path.clone();
13657 let fs = fs.clone();
13658
13659 let lsp_store = lsp_store.clone();
13660 async move |_, cx| {
13661 maybe!(async move {
13662 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13663 while let Some(update) = push_updates.0.next().await {
13664 let action = lsp_store
13665 .update(cx, |this, _| {
13666 let Some(local) = this.as_local() else {
13667 return ControlFlow::Break(());
13668 };
13669 let Some(watcher) = local
13670 .language_server_watched_paths
13671 .get(&language_server_id)
13672 else {
13673 return ControlFlow::Break(());
13674 };
13675 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13676 "Watched abs path is not registered with a watcher",
13677 );
13678 let matching_entries = update
13679 .into_iter()
13680 .filter(|event| globs.is_match(&event.path))
13681 .collect::<Vec<_>>();
13682 this.lsp_notify_abs_paths_changed(
13683 language_server_id,
13684 matching_entries,
13685 );
13686 ControlFlow::Continue(())
13687 })
13688 .ok()?;
13689
13690 if action.is_break() {
13691 break;
13692 }
13693 }
13694 Some(())
13695 })
13696 .await;
13697 }
13698 });
13699 (abs_path, (globset, task))
13700 })
13701 .collect();
13702 LanguageServerWatchedPaths {
13703 worktree_paths: self.worktree_paths,
13704 abs_paths,
13705 }
13706 }
13707}
13708
13709struct LspBufferSnapshot {
13710 version: i32,
13711 snapshot: TextBufferSnapshot,
13712}
13713
13714/// A prompt requested by LSP server.
13715#[derive(Clone, Debug)]
13716pub struct LanguageServerPromptRequest {
13717 pub level: PromptLevel,
13718 pub message: String,
13719 pub actions: Vec<MessageActionItem>,
13720 pub lsp_name: String,
13721 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13722}
13723
13724impl LanguageServerPromptRequest {
13725 pub async fn respond(self, index: usize) -> Option<()> {
13726 if let Some(response) = self.actions.into_iter().nth(index) {
13727 self.response_channel.send(response).await.ok()
13728 } else {
13729 None
13730 }
13731 }
13732}
13733impl PartialEq for LanguageServerPromptRequest {
13734 fn eq(&self, other: &Self) -> bool {
13735 self.message == other.message && self.actions == other.actions
13736 }
13737}
13738
13739#[derive(Clone, Debug, PartialEq)]
13740pub enum LanguageServerLogType {
13741 Log(MessageType),
13742 Trace { verbose_info: Option<String> },
13743 Rpc { received: bool },
13744}
13745
13746impl LanguageServerLogType {
13747 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13748 match self {
13749 Self::Log(log_type) => {
13750 use proto::log_message::LogLevel;
13751 let level = match *log_type {
13752 MessageType::ERROR => LogLevel::Error,
13753 MessageType::WARNING => LogLevel::Warning,
13754 MessageType::INFO => LogLevel::Info,
13755 MessageType::LOG => LogLevel::Log,
13756 other => {
13757 log::warn!("Unknown lsp log message type: {other:?}");
13758 LogLevel::Log
13759 }
13760 };
13761 proto::language_server_log::LogType::Log(proto::LogMessage {
13762 level: level as i32,
13763 })
13764 }
13765 Self::Trace { verbose_info } => {
13766 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13767 verbose_info: verbose_info.to_owned(),
13768 })
13769 }
13770 Self::Rpc { received } => {
13771 let kind = if *received {
13772 proto::rpc_message::Kind::Received
13773 } else {
13774 proto::rpc_message::Kind::Sent
13775 };
13776 let kind = kind as i32;
13777 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13778 }
13779 }
13780 }
13781
13782 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13783 use proto::log_message::LogLevel;
13784 use proto::rpc_message;
13785 match log_type {
13786 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13787 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13788 LogLevel::Error => MessageType::ERROR,
13789 LogLevel::Warning => MessageType::WARNING,
13790 LogLevel::Info => MessageType::INFO,
13791 LogLevel::Log => MessageType::LOG,
13792 },
13793 ),
13794 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13795 verbose_info: trace_message.verbose_info,
13796 },
13797 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13798 received: match rpc_message::Kind::from_i32(message.kind)
13799 .unwrap_or(rpc_message::Kind::Received)
13800 {
13801 rpc_message::Kind::Received => true,
13802 rpc_message::Kind::Sent => false,
13803 },
13804 },
13805 }
13806 }
13807}
13808
13809pub struct WorkspaceRefreshTask {
13810 refresh_tx: mpsc::Sender<()>,
13811 progress_tx: mpsc::Sender<()>,
13812 #[allow(dead_code)]
13813 task: Task<()>,
13814}
13815
13816pub enum LanguageServerState {
13817 Starting {
13818 startup: Task<Option<Arc<LanguageServer>>>,
13819 /// List of language servers that will be added to the workspace once it's initialization completes.
13820 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13821 },
13822
13823 Running {
13824 adapter: Arc<CachedLspAdapter>,
13825 server: Arc<LanguageServer>,
13826 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13827 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13828 },
13829}
13830
13831impl LanguageServerState {
13832 fn add_workspace_folder(&self, uri: Uri) {
13833 match self {
13834 LanguageServerState::Starting {
13835 pending_workspace_folders,
13836 ..
13837 } => {
13838 pending_workspace_folders.lock().insert(uri);
13839 }
13840 LanguageServerState::Running { server, .. } => {
13841 server.add_workspace_folder(uri);
13842 }
13843 }
13844 }
13845 fn _remove_workspace_folder(&self, uri: Uri) {
13846 match self {
13847 LanguageServerState::Starting {
13848 pending_workspace_folders,
13849 ..
13850 } => {
13851 pending_workspace_folders.lock().remove(&uri);
13852 }
13853 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13854 }
13855 }
13856}
13857
13858impl std::fmt::Debug for LanguageServerState {
13859 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13860 match self {
13861 LanguageServerState::Starting { .. } => {
13862 f.debug_struct("LanguageServerState::Starting").finish()
13863 }
13864 LanguageServerState::Running { .. } => {
13865 f.debug_struct("LanguageServerState::Running").finish()
13866 }
13867 }
13868 }
13869}
13870
13871#[derive(Clone, Debug, Serialize)]
13872pub struct LanguageServerProgress {
13873 pub is_disk_based_diagnostics_progress: bool,
13874 pub is_cancellable: bool,
13875 pub title: Option<String>,
13876 pub message: Option<String>,
13877 pub percentage: Option<usize>,
13878 #[serde(skip_serializing)]
13879 pub last_update_at: Instant,
13880}
13881
13882#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13883pub struct DiagnosticSummary {
13884 pub error_count: usize,
13885 pub warning_count: usize,
13886}
13887
13888impl DiagnosticSummary {
13889 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13890 let mut this = Self {
13891 error_count: 0,
13892 warning_count: 0,
13893 };
13894
13895 for entry in diagnostics {
13896 if entry.diagnostic.is_primary {
13897 match entry.diagnostic.severity {
13898 DiagnosticSeverity::ERROR => this.error_count += 1,
13899 DiagnosticSeverity::WARNING => this.warning_count += 1,
13900 _ => {}
13901 }
13902 }
13903 }
13904
13905 this
13906 }
13907
13908 pub fn is_empty(&self) -> bool {
13909 self.error_count == 0 && self.warning_count == 0
13910 }
13911
13912 pub fn to_proto(
13913 self,
13914 language_server_id: LanguageServerId,
13915 path: &RelPath,
13916 ) -> proto::DiagnosticSummary {
13917 proto::DiagnosticSummary {
13918 path: path.to_proto(),
13919 language_server_id: language_server_id.0 as u64,
13920 error_count: self.error_count as u32,
13921 warning_count: self.warning_count as u32,
13922 }
13923 }
13924}
13925
13926#[derive(Clone, Debug)]
13927pub enum CompletionDocumentation {
13928 /// There is no documentation for this completion.
13929 Undocumented,
13930 /// A single line of documentation.
13931 SingleLine(SharedString),
13932 /// Multiple lines of plain text documentation.
13933 MultiLinePlainText(SharedString),
13934 /// Markdown documentation.
13935 MultiLineMarkdown(SharedString),
13936 /// Both single line and multiple lines of plain text documentation.
13937 SingleLineAndMultiLinePlainText {
13938 single_line: SharedString,
13939 plain_text: Option<SharedString>,
13940 },
13941}
13942
13943impl CompletionDocumentation {
13944 #[cfg(any(test, feature = "test-support"))]
13945 pub fn text(&self) -> SharedString {
13946 match self {
13947 CompletionDocumentation::Undocumented => "".into(),
13948 CompletionDocumentation::SingleLine(s) => s.clone(),
13949 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13950 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13951 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13952 single_line.clone()
13953 }
13954 }
13955 }
13956}
13957
13958impl From<lsp::Documentation> for CompletionDocumentation {
13959 fn from(docs: lsp::Documentation) -> Self {
13960 match docs {
13961 lsp::Documentation::String(text) => {
13962 if text.lines().count() <= 1 {
13963 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13964 } else {
13965 CompletionDocumentation::MultiLinePlainText(text.into())
13966 }
13967 }
13968
13969 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13970 lsp::MarkupKind::PlainText => {
13971 if value.lines().count() <= 1 {
13972 CompletionDocumentation::SingleLine(value.into())
13973 } else {
13974 CompletionDocumentation::MultiLinePlainText(value.into())
13975 }
13976 }
13977
13978 lsp::MarkupKind::Markdown => {
13979 CompletionDocumentation::MultiLineMarkdown(value.into())
13980 }
13981 },
13982 }
13983 }
13984}
13985
13986pub enum ResolvedHint {
13987 Resolved(InlayHint),
13988 Resolving(Shared<Task<()>>),
13989}
13990
13991fn glob_literal_prefix(glob: &Path) -> PathBuf {
13992 glob.components()
13993 .take_while(|component| match component {
13994 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13995 _ => true,
13996 })
13997 .collect()
13998}
13999
14000pub struct SshLspAdapter {
14001 name: LanguageServerName,
14002 binary: LanguageServerBinary,
14003 initialization_options: Option<String>,
14004 code_action_kinds: Option<Vec<CodeActionKind>>,
14005}
14006
14007impl SshLspAdapter {
14008 pub fn new(
14009 name: LanguageServerName,
14010 binary: LanguageServerBinary,
14011 initialization_options: Option<String>,
14012 code_action_kinds: Option<String>,
14013 ) -> Self {
14014 Self {
14015 name,
14016 binary,
14017 initialization_options,
14018 code_action_kinds: code_action_kinds
14019 .as_ref()
14020 .and_then(|c| serde_json::from_str(c).ok()),
14021 }
14022 }
14023}
14024
14025impl LspInstaller for SshLspAdapter {
14026 type BinaryVersion = ();
14027 async fn check_if_user_installed(
14028 &self,
14029 _: &dyn LspAdapterDelegate,
14030 _: Option<Toolchain>,
14031 _: &AsyncApp,
14032 ) -> Option<LanguageServerBinary> {
14033 Some(self.binary.clone())
14034 }
14035
14036 async fn cached_server_binary(
14037 &self,
14038 _: PathBuf,
14039 _: &dyn LspAdapterDelegate,
14040 ) -> Option<LanguageServerBinary> {
14041 None
14042 }
14043
14044 async fn fetch_latest_server_version(
14045 &self,
14046 _: &dyn LspAdapterDelegate,
14047 _: bool,
14048 _: &mut AsyncApp,
14049 ) -> Result<()> {
14050 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14051 }
14052
14053 async fn fetch_server_binary(
14054 &self,
14055 _: (),
14056 _: PathBuf,
14057 _: &dyn LspAdapterDelegate,
14058 ) -> Result<LanguageServerBinary> {
14059 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14060 }
14061}
14062
14063#[async_trait(?Send)]
14064impl LspAdapter for SshLspAdapter {
14065 fn name(&self) -> LanguageServerName {
14066 self.name.clone()
14067 }
14068
14069 async fn initialization_options(
14070 self: Arc<Self>,
14071 _: &Arc<dyn LspAdapterDelegate>,
14072 ) -> Result<Option<serde_json::Value>> {
14073 let Some(options) = &self.initialization_options else {
14074 return Ok(None);
14075 };
14076 let result = serde_json::from_str(options)?;
14077 Ok(result)
14078 }
14079
14080 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14081 self.code_action_kinds.clone()
14082 }
14083}
14084
14085pub fn language_server_settings<'a>(
14086 delegate: &'a dyn LspAdapterDelegate,
14087 language: &LanguageServerName,
14088 cx: &'a App,
14089) -> Option<&'a LspSettings> {
14090 language_server_settings_for(
14091 SettingsLocation {
14092 worktree_id: delegate.worktree_id(),
14093 path: RelPath::empty(),
14094 },
14095 language,
14096 cx,
14097 )
14098}
14099
14100pub fn language_server_settings_for<'a>(
14101 location: SettingsLocation<'a>,
14102 language: &LanguageServerName,
14103 cx: &'a App,
14104) -> Option<&'a LspSettings> {
14105 ProjectSettings::get(Some(location), cx).lsp.get(language)
14106}
14107
14108pub struct LocalLspAdapterDelegate {
14109 lsp_store: WeakEntity<LspStore>,
14110 worktree: worktree::Snapshot,
14111 fs: Arc<dyn Fs>,
14112 http_client: Arc<dyn HttpClient>,
14113 language_registry: Arc<LanguageRegistry>,
14114 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14115}
14116
14117impl LocalLspAdapterDelegate {
14118 pub fn new(
14119 language_registry: Arc<LanguageRegistry>,
14120 environment: &Entity<ProjectEnvironment>,
14121 lsp_store: WeakEntity<LspStore>,
14122 worktree: &Entity<Worktree>,
14123 http_client: Arc<dyn HttpClient>,
14124 fs: Arc<dyn Fs>,
14125 cx: &mut App,
14126 ) -> Arc<Self> {
14127 let load_shell_env_task =
14128 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14129
14130 Arc::new(Self {
14131 lsp_store,
14132 worktree: worktree.read(cx).snapshot(),
14133 fs,
14134 http_client,
14135 language_registry,
14136 load_shell_env_task,
14137 })
14138 }
14139
14140 pub fn from_local_lsp(
14141 local: &LocalLspStore,
14142 worktree: &Entity<Worktree>,
14143 cx: &mut App,
14144 ) -> Arc<Self> {
14145 Self::new(
14146 local.languages.clone(),
14147 &local.environment,
14148 local.weak.clone(),
14149 worktree,
14150 local.http_client.clone(),
14151 local.fs.clone(),
14152 cx,
14153 )
14154 }
14155}
14156
14157#[async_trait]
14158impl LspAdapterDelegate for LocalLspAdapterDelegate {
14159 fn show_notification(&self, message: &str, cx: &mut App) {
14160 self.lsp_store
14161 .update(cx, |_, cx| {
14162 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14163 })
14164 .ok();
14165 }
14166
14167 fn http_client(&self) -> Arc<dyn HttpClient> {
14168 self.http_client.clone()
14169 }
14170
14171 fn worktree_id(&self) -> WorktreeId {
14172 self.worktree.id()
14173 }
14174
14175 fn worktree_root_path(&self) -> &Path {
14176 self.worktree.abs_path().as_ref()
14177 }
14178
14179 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14180 self.worktree.resolve_executable_path(path)
14181 }
14182
14183 async fn shell_env(&self) -> HashMap<String, String> {
14184 let task = self.load_shell_env_task.clone();
14185 task.await.unwrap_or_default()
14186 }
14187
14188 async fn npm_package_installed_version(
14189 &self,
14190 package_name: &str,
14191 ) -> Result<Option<(PathBuf, Version)>> {
14192 let local_package_directory = self.worktree_root_path();
14193 let node_modules_directory = local_package_directory.join("node_modules");
14194
14195 if let Some(version) =
14196 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14197 {
14198 return Ok(Some((node_modules_directory, version)));
14199 }
14200 let Some(npm) = self.which("npm".as_ref()).await else {
14201 log::warn!(
14202 "Failed to find npm executable for {:?}",
14203 local_package_directory
14204 );
14205 return Ok(None);
14206 };
14207
14208 let env = self.shell_env().await;
14209 let output = util::command::new_smol_command(&npm)
14210 .args(["root", "-g"])
14211 .envs(env)
14212 .current_dir(local_package_directory)
14213 .output()
14214 .await?;
14215 let global_node_modules =
14216 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14217
14218 if let Some(version) =
14219 read_package_installed_version(global_node_modules.clone(), package_name).await?
14220 {
14221 return Ok(Some((global_node_modules, version)));
14222 }
14223 return Ok(None);
14224 }
14225
14226 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14227 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14228 if self.fs.is_file(&worktree_abs_path).await {
14229 worktree_abs_path.pop();
14230 }
14231
14232 let env = self.shell_env().await;
14233
14234 let shell_path = env.get("PATH").cloned();
14235
14236 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14237 }
14238
14239 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14240 let mut working_dir = self.worktree_root_path().to_path_buf();
14241 if self.fs.is_file(&working_dir).await {
14242 working_dir.pop();
14243 }
14244 let output = util::command::new_smol_command(&command.path)
14245 .args(command.arguments)
14246 .envs(command.env.clone().unwrap_or_default())
14247 .current_dir(working_dir)
14248 .output()
14249 .await?;
14250
14251 anyhow::ensure!(
14252 output.status.success(),
14253 "{}, stdout: {:?}, stderr: {:?}",
14254 output.status,
14255 String::from_utf8_lossy(&output.stdout),
14256 String::from_utf8_lossy(&output.stderr)
14257 );
14258 Ok(())
14259 }
14260
14261 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14262 self.language_registry
14263 .update_lsp_binary_status(server_name, status);
14264 }
14265
14266 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14267 self.language_registry
14268 .all_lsp_adapters()
14269 .into_iter()
14270 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14271 .collect()
14272 }
14273
14274 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14275 let dir = self.language_registry.language_server_download_dir(name)?;
14276
14277 if !dir.exists() {
14278 smol::fs::create_dir_all(&dir)
14279 .await
14280 .context("failed to create container directory")
14281 .log_err()?;
14282 }
14283
14284 Some(dir)
14285 }
14286
14287 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14288 let entry = self
14289 .worktree
14290 .entry_for_path(path)
14291 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14292 let abs_path = self.worktree.absolutize(&entry.path);
14293 self.fs.load(&abs_path).await
14294 }
14295}
14296
14297async fn populate_labels_for_symbols(
14298 symbols: Vec<CoreSymbol>,
14299 language_registry: &Arc<LanguageRegistry>,
14300 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14301 output: &mut Vec<Symbol>,
14302) {
14303 #[allow(clippy::mutable_key_type)]
14304 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14305
14306 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14307 for symbol in symbols {
14308 let Some(file_name) = symbol.path.file_name() else {
14309 continue;
14310 };
14311 let language = language_registry
14312 .load_language_for_file_path(Path::new(file_name))
14313 .await
14314 .ok()
14315 .or_else(|| {
14316 unknown_paths.insert(file_name.into());
14317 None
14318 });
14319 symbols_by_language
14320 .entry(language)
14321 .or_default()
14322 .push(symbol);
14323 }
14324
14325 for unknown_path in unknown_paths {
14326 log::info!("no language found for symbol in file {unknown_path:?}");
14327 }
14328
14329 let mut label_params = Vec::new();
14330 for (language, mut symbols) in symbols_by_language {
14331 label_params.clear();
14332 label_params.extend(
14333 symbols
14334 .iter_mut()
14335 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14336 );
14337
14338 let mut labels = Vec::new();
14339 if let Some(language) = language {
14340 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14341 language_registry
14342 .lsp_adapters(&language.name())
14343 .first()
14344 .cloned()
14345 });
14346 if let Some(lsp_adapter) = lsp_adapter {
14347 labels = lsp_adapter
14348 .labels_for_symbols(&label_params, &language)
14349 .await
14350 .log_err()
14351 .unwrap_or_default();
14352 }
14353 }
14354
14355 for ((symbol, (name, _)), label) in symbols
14356 .into_iter()
14357 .zip(label_params.drain(..))
14358 .zip(labels.into_iter().chain(iter::repeat(None)))
14359 {
14360 output.push(Symbol {
14361 language_server_name: symbol.language_server_name,
14362 source_worktree_id: symbol.source_worktree_id,
14363 source_language_server_id: symbol.source_language_server_id,
14364 path: symbol.path,
14365 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14366 name,
14367 kind: symbol.kind,
14368 range: symbol.range,
14369 });
14370 }
14371 }
14372}
14373
14374fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14375 match server.capabilities().text_document_sync.as_ref()? {
14376 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14377 // Server wants didSave but didn't specify includeText.
14378 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14379 // Server doesn't want didSave at all.
14380 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14381 // Server provided SaveOptions.
14382 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14383 Some(save_options.include_text.unwrap_or(false))
14384 }
14385 },
14386 // We do not have any save info. Kind affects didChange only.
14387 lsp::TextDocumentSyncCapability::Kind(_) => None,
14388 }
14389}
14390
14391/// Completion items are displayed in a `UniformList`.
14392/// Usually, those items are single-line strings, but in LSP responses,
14393/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14394/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14395/// 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,
14396/// breaking the completions menu presentation.
14397///
14398/// 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.
14399fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14400 let mut new_text = String::with_capacity(label.text.len());
14401 let mut offset_map = vec![0; label.text.len() + 1];
14402 let mut last_char_was_space = false;
14403 let mut new_idx = 0;
14404 let chars = label.text.char_indices().fuse();
14405 let mut newlines_removed = false;
14406
14407 for (idx, c) in chars {
14408 offset_map[idx] = new_idx;
14409
14410 match c {
14411 '\n' if last_char_was_space => {
14412 newlines_removed = true;
14413 }
14414 '\t' | ' ' if last_char_was_space => {}
14415 '\n' if !last_char_was_space => {
14416 new_text.push(' ');
14417 new_idx += 1;
14418 last_char_was_space = true;
14419 newlines_removed = true;
14420 }
14421 ' ' | '\t' => {
14422 new_text.push(' ');
14423 new_idx += 1;
14424 last_char_was_space = true;
14425 }
14426 _ => {
14427 new_text.push(c);
14428 new_idx += c.len_utf8();
14429 last_char_was_space = false;
14430 }
14431 }
14432 }
14433 offset_map[label.text.len()] = new_idx;
14434
14435 // Only modify the label if newlines were removed.
14436 if !newlines_removed {
14437 return;
14438 }
14439
14440 let last_index = new_idx;
14441 let mut run_ranges_errors = Vec::new();
14442 label.runs.retain_mut(|(range, _)| {
14443 match offset_map.get(range.start) {
14444 Some(&start) => range.start = start,
14445 None => {
14446 run_ranges_errors.push(range.clone());
14447 return false;
14448 }
14449 }
14450
14451 match offset_map.get(range.end) {
14452 Some(&end) => range.end = end,
14453 None => {
14454 run_ranges_errors.push(range.clone());
14455 range.end = last_index;
14456 }
14457 }
14458 true
14459 });
14460 if !run_ranges_errors.is_empty() {
14461 log::error!(
14462 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14463 label.text
14464 );
14465 }
14466
14467 let mut wrong_filter_range = None;
14468 if label.filter_range == (0..label.text.len()) {
14469 label.filter_range = 0..new_text.len();
14470 } else {
14471 let mut original_filter_range = Some(label.filter_range.clone());
14472 match offset_map.get(label.filter_range.start) {
14473 Some(&start) => label.filter_range.start = start,
14474 None => {
14475 wrong_filter_range = original_filter_range.take();
14476 label.filter_range.start = last_index;
14477 }
14478 }
14479
14480 match offset_map.get(label.filter_range.end) {
14481 Some(&end) => label.filter_range.end = end,
14482 None => {
14483 wrong_filter_range = original_filter_range.take();
14484 label.filter_range.end = last_index;
14485 }
14486 }
14487 }
14488 if let Some(wrong_filter_range) = wrong_filter_range {
14489 log::error!(
14490 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14491 label.text
14492 );
14493 }
14494
14495 label.text = new_text;
14496}
14497
14498#[cfg(test)]
14499mod tests {
14500 use language::HighlightId;
14501
14502 use super::*;
14503
14504 #[test]
14505 fn test_glob_literal_prefix() {
14506 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14507 assert_eq!(
14508 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14509 Path::new("node_modules")
14510 );
14511 assert_eq!(
14512 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14513 Path::new("foo")
14514 );
14515 assert_eq!(
14516 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14517 Path::new("foo/bar/baz.js")
14518 );
14519
14520 #[cfg(target_os = "windows")]
14521 {
14522 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14523 assert_eq!(
14524 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14525 Path::new("node_modules")
14526 );
14527 assert_eq!(
14528 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14529 Path::new("foo")
14530 );
14531 assert_eq!(
14532 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14533 Path::new("foo/bar/baz.js")
14534 );
14535 }
14536 }
14537
14538 #[test]
14539 fn test_multi_len_chars_normalization() {
14540 let mut label = CodeLabel::new(
14541 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14542 0..6,
14543 vec![(0..6, HighlightId(1))],
14544 );
14545 ensure_uniform_list_compatible_label(&mut label);
14546 assert_eq!(
14547 label,
14548 CodeLabel::new(
14549 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14550 0..6,
14551 vec![(0..6, HighlightId(1))],
14552 )
14553 );
14554 }
14555
14556 #[test]
14557 fn test_trailing_newline_in_completion_documentation() {
14558 let doc = lsp::Documentation::String(
14559 "Inappropriate argument value (of correct type).\n".to_string(),
14560 );
14561 let completion_doc: CompletionDocumentation = doc.into();
14562 assert!(
14563 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
14564 );
14565
14566 let doc = lsp::Documentation::String(" some value \n".to_string());
14567 let completion_doc: CompletionDocumentation = doc.into();
14568 assert!(matches!(
14569 completion_doc,
14570 CompletionDocumentation::SingleLine(s) if s == "some value"
14571 ));
14572 }
14573}