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_anchor_range, deserialize_lsp_edit, deserialize_version,
73 serialize_anchor, serialize_anchor_range, 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.update(cx, |lsp_store, cx| {
546 lsp_store.cleanup_lsp_data(server_id);
547 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
548 });
549 }
550 })?;
551
552 language_server.notify::<lsp::notification::DidChangeConfiguration>(
553 did_change_configuration_params,
554 )?;
555
556 anyhow::Ok(language_server)
557 }
558 .await;
559
560 match result {
561 Ok(server) => {
562 lsp_store
563 .update(cx, |lsp_store, cx| {
564 lsp_store.insert_newly_running_language_server(
565 adapter,
566 server.clone(),
567 server_id,
568 key,
569 pending_workspace_folders,
570 cx,
571 );
572 })
573 .ok();
574 stderr_capture.lock().take();
575 Some(server)
576 }
577
578 Err(err) => {
579 let log = stderr_capture.lock().take().unwrap_or_default();
580 delegate.update_status(
581 adapter.name(),
582 BinaryStatus::Failed {
583 error: if log.is_empty() {
584 format!("{err:#}")
585 } else {
586 format!("{err:#}\n-- stderr --\n{log}")
587 },
588 },
589 );
590 log::error!(
591 "Failed to start language server {server_name:?}: {}",
592 redact_command(&format!("{err:?}"))
593 );
594 if !log.is_empty() {
595 log::error!("server stderr: {}", redact_command(&log));
596 }
597 None
598 }
599 }
600 })
601 };
602 let state = LanguageServerState::Starting {
603 startup,
604 pending_workspace_folders,
605 };
606
607 if update_binary_status {
608 self.languages
609 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
610 }
611
612 self.language_servers.insert(server_id, state);
613 self.language_server_ids
614 .entry(key)
615 .or_insert(UnifiedLanguageServer {
616 id: server_id,
617 project_roots: Default::default(),
618 });
619 server_id
620 }
621
622 fn get_language_server_binary(
623 &self,
624 worktree_abs_path: Arc<Path>,
625 adapter: Arc<CachedLspAdapter>,
626 settings: Arc<LspSettings>,
627 toolchain: Option<Toolchain>,
628 delegate: Arc<dyn LspAdapterDelegate>,
629 allow_binary_download: bool,
630 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
631 cx: &mut App,
632 ) -> Task<Result<LanguageServerBinary>> {
633 if let Some(settings) = &settings.binary
634 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
635 {
636 let settings = settings.clone();
637 let languages = self.languages.clone();
638 return cx.background_spawn(async move {
639 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
640 let already_trusted = *wait_until_worktree_trust.borrow();
641 if !already_trusted {
642 log::info!(
643 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
644 adapter.name(),
645 );
646 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
647 if worktree_trusted {
648 break;
649 }
650 }
651 log::info!(
652 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
653 adapter.name(),
654 );
655 }
656 languages
657 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
658 }
659 let mut env = delegate.shell_env().await;
660 env.extend(settings.env.unwrap_or_default());
661
662 Ok(LanguageServerBinary {
663 path: delegate.resolve_executable_path(path),
664 env: Some(env),
665 arguments: settings
666 .arguments
667 .unwrap_or_default()
668 .iter()
669 .map(Into::into)
670 .collect(),
671 })
672 });
673 }
674 let lsp_binary_options = LanguageServerBinaryOptions {
675 allow_path_lookup: !settings
676 .binary
677 .as_ref()
678 .and_then(|b| b.ignore_system_version)
679 .unwrap_or_default(),
680 allow_binary_download,
681 pre_release: settings
682 .fetch
683 .as_ref()
684 .and_then(|f| f.pre_release)
685 .unwrap_or(false),
686 };
687
688 cx.spawn(async move |cx| {
689 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
690 let already_trusted = *wait_until_worktree_trust.borrow();
691 if !already_trusted {
692 log::info!(
693 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
694 adapter.name(),
695 );
696 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
697 if worktree_trusted {
698 break;
699 }
700 }
701 log::info!(
702 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
703 adapter.name(),
704 );
705 }
706 }
707
708 let (existing_binary, maybe_download_binary) = adapter
709 .clone()
710 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
711 .await
712 .await;
713
714 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
715
716 let mut binary = match (existing_binary, maybe_download_binary) {
717 (binary, None) => binary?,
718 (Err(_), Some(downloader)) => downloader.await?,
719 (Ok(existing_binary), Some(downloader)) => {
720 let mut download_timeout = cx
721 .background_executor()
722 .timer(SERVER_DOWNLOAD_TIMEOUT)
723 .fuse();
724 let mut downloader = downloader.fuse();
725 futures::select! {
726 _ = download_timeout => {
727 // Return existing binary and kick the existing work to the background.
728 cx.spawn(async move |_| downloader.await).detach();
729 Ok(existing_binary)
730 },
731 downloaded_or_existing_binary = downloader => {
732 // If download fails, this results in the existing binary.
733 downloaded_or_existing_binary
734 }
735 }?
736 }
737 };
738 let mut shell_env = delegate.shell_env().await;
739
740 shell_env.extend(binary.env.unwrap_or_default());
741
742 if let Some(settings) = settings.binary.as_ref() {
743 if let Some(arguments) = &settings.arguments {
744 binary.arguments = arguments.iter().map(Into::into).collect();
745 }
746 if let Some(env) = &settings.env {
747 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
748 }
749 }
750
751 binary.env = Some(shell_env);
752 Ok(binary)
753 })
754 }
755
756 fn setup_lsp_messages(
757 lsp_store: WeakEntity<LspStore>,
758 language_server: &LanguageServer,
759 delegate: Arc<dyn LspAdapterDelegate>,
760 adapter: Arc<CachedLspAdapter>,
761 ) {
762 let name = language_server.name();
763 let server_id = language_server.server_id();
764 language_server
765 .on_notification::<lsp::notification::PublishDiagnostics, _>({
766 let adapter = adapter.clone();
767 let this = lsp_store.clone();
768 move |mut params, cx| {
769 let adapter = adapter.clone();
770 if let Some(this) = this.upgrade() {
771 this.update(cx, |this, cx| {
772 {
773 let buffer = params
774 .uri
775 .to_file_path()
776 .map(|file_path| this.get_buffer(&file_path, cx))
777 .ok()
778 .flatten();
779 adapter.process_diagnostics(&mut params, server_id, buffer);
780 }
781
782 this.merge_lsp_diagnostics(
783 DiagnosticSourceKind::Pushed,
784 vec![DocumentDiagnosticsUpdate {
785 server_id,
786 diagnostics: params,
787 result_id: None,
788 disk_based_sources: Cow::Borrowed(
789 &adapter.disk_based_diagnostic_sources,
790 ),
791 registration_id: None,
792 }],
793 |_, diagnostic, cx| match diagnostic.source_kind {
794 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
795 adapter.retain_old_diagnostic(diagnostic, cx)
796 }
797 DiagnosticSourceKind::Pulled => true,
798 },
799 cx,
800 )
801 .log_err();
802 });
803 }
804 }
805 })
806 .detach();
807 language_server
808 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
809 let adapter = adapter.adapter.clone();
810 let delegate = delegate.clone();
811 let this = lsp_store.clone();
812 move |params, cx| {
813 let adapter = adapter.clone();
814 let delegate = delegate.clone();
815 let this = this.clone();
816 let mut cx = cx.clone();
817 async move {
818 let toolchain_for_id = this
819 .update(&mut cx, |this, _| {
820 this.as_local()?.language_server_ids.iter().find_map(
821 |(seed, value)| {
822 (value.id == server_id).then(|| seed.toolchain.clone())
823 },
824 )
825 })?
826 .context("Expected the LSP store to be in a local mode")?;
827
828 let mut scope_uri_to_workspace_config = BTreeMap::new();
829 for item in ¶ms.items {
830 let scope_uri = item.scope_uri.clone();
831 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
832 scope_uri_to_workspace_config.entry(scope_uri.clone())
833 else {
834 // We've already queried workspace configuration of this URI.
835 continue;
836 };
837 let workspace_config = Self::workspace_configuration_for_adapter(
838 adapter.clone(),
839 &delegate,
840 toolchain_for_id.clone(),
841 scope_uri,
842 &mut cx,
843 )
844 .await?;
845 new_scope_uri.insert(workspace_config);
846 }
847
848 Ok(params
849 .items
850 .into_iter()
851 .filter_map(|item| {
852 let workspace_config =
853 scope_uri_to_workspace_config.get(&item.scope_uri)?;
854 if let Some(section) = &item.section {
855 Some(
856 workspace_config
857 .get(section)
858 .cloned()
859 .unwrap_or(serde_json::Value::Null),
860 )
861 } else {
862 Some(workspace_config.clone())
863 }
864 })
865 .collect())
866 }
867 }
868 })
869 .detach();
870
871 language_server
872 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
873 let this = lsp_store.clone();
874 move |_, cx| {
875 let this = this.clone();
876 let cx = cx.clone();
877 async move {
878 let Some(server) =
879 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
880 else {
881 return Ok(None);
882 };
883 let root = server.workspace_folders();
884 Ok(Some(
885 root.into_iter()
886 .map(|uri| WorkspaceFolder {
887 uri,
888 name: Default::default(),
889 })
890 .collect(),
891 ))
892 }
893 }
894 })
895 .detach();
896 // Even though we don't have handling for these requests, respond to them to
897 // avoid stalling any language server like `gopls` which waits for a response
898 // to these requests when initializing.
899 language_server
900 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
901 let this = lsp_store.clone();
902 move |params, cx| {
903 let this = this.clone();
904 let mut cx = cx.clone();
905 async move {
906 this.update(&mut cx, |this, _| {
907 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
908 {
909 status
910 .progress_tokens
911 .insert(ProgressToken::from_lsp(params.token));
912 }
913 })?;
914
915 Ok(())
916 }
917 }
918 })
919 .detach();
920
921 language_server
922 .on_request::<lsp::request::RegisterCapability, _, _>({
923 let lsp_store = lsp_store.clone();
924 move |params, cx| {
925 let lsp_store = lsp_store.clone();
926 let mut cx = cx.clone();
927 async move {
928 lsp_store
929 .update(&mut cx, |lsp_store, cx| {
930 if lsp_store.as_local().is_some() {
931 match lsp_store
932 .register_server_capabilities(server_id, params, cx)
933 {
934 Ok(()) => {}
935 Err(e) => {
936 log::error!(
937 "Failed to register server capabilities: {e:#}"
938 );
939 }
940 };
941 }
942 })
943 .ok();
944 Ok(())
945 }
946 }
947 })
948 .detach();
949
950 language_server
951 .on_request::<lsp::request::UnregisterCapability, _, _>({
952 let lsp_store = lsp_store.clone();
953 move |params, cx| {
954 let lsp_store = lsp_store.clone();
955 let mut cx = cx.clone();
956 async move {
957 lsp_store
958 .update(&mut cx, |lsp_store, cx| {
959 if lsp_store.as_local().is_some() {
960 match lsp_store
961 .unregister_server_capabilities(server_id, params, cx)
962 {
963 Ok(()) => {}
964 Err(e) => {
965 log::error!(
966 "Failed to unregister server capabilities: {e:#}"
967 );
968 }
969 }
970 }
971 })
972 .ok();
973 Ok(())
974 }
975 }
976 })
977 .detach();
978
979 language_server
980 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
981 let this = lsp_store.clone();
982 move |params, cx| {
983 let mut cx = cx.clone();
984 let this = this.clone();
985 async move {
986 LocalLspStore::on_lsp_workspace_edit(
987 this.clone(),
988 params,
989 server_id,
990 &mut cx,
991 )
992 .await
993 }
994 }
995 })
996 .detach();
997
998 language_server
999 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1000 let lsp_store = lsp_store.clone();
1001 let request_id = Arc::new(AtomicUsize::new(0));
1002 move |(), cx| {
1003 let lsp_store = lsp_store.clone();
1004 let request_id = request_id.clone();
1005 let mut cx = cx.clone();
1006 async move {
1007 lsp_store
1008 .update(&mut cx, |lsp_store, cx| {
1009 let request_id =
1010 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1011 cx.emit(LspStoreEvent::RefreshInlayHints {
1012 server_id,
1013 request_id,
1014 });
1015 lsp_store
1016 .downstream_client
1017 .as_ref()
1018 .map(|(client, project_id)| {
1019 client.send(proto::RefreshInlayHints {
1020 project_id: *project_id,
1021 server_id: server_id.to_proto(),
1022 request_id: request_id.map(|id| id as u64),
1023 })
1024 })
1025 })?
1026 .transpose()?;
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1035 let this = lsp_store.clone();
1036 move |(), cx| {
1037 let this = this.clone();
1038 let mut cx = cx.clone();
1039 async move {
1040 this.update(&mut cx, |this, cx| {
1041 cx.emit(LspStoreEvent::RefreshCodeLens);
1042 this.downstream_client.as_ref().map(|(client, project_id)| {
1043 client.send(proto::RefreshCodeLens {
1044 project_id: *project_id,
1045 })
1046 })
1047 })?
1048 .transpose()?;
1049 Ok(())
1050 }
1051 }
1052 })
1053 .detach();
1054
1055 language_server
1056 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1057 let this = lsp_store.clone();
1058 move |(), cx| {
1059 let this = this.clone();
1060 let mut cx = cx.clone();
1061 async move {
1062 this.update(&mut cx, |lsp_store, cx| {
1063 lsp_store.pull_workspace_diagnostics(server_id);
1064 lsp_store
1065 .downstream_client
1066 .as_ref()
1067 .map(|(client, project_id)| {
1068 client.send(proto::PullWorkspaceDiagnostics {
1069 project_id: *project_id,
1070 server_id: server_id.to_proto(),
1071 })
1072 })
1073 .transpose()?;
1074 anyhow::Ok(
1075 lsp_store.pull_document_diagnostics_for_server(server_id, cx),
1076 )
1077 })??
1078 .await;
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 }
1180 }
1181 })
1182 .detach();
1183
1184 language_server
1185 .on_notification::<lsp::notification::LogMessage, _>({
1186 let this = lsp_store.clone();
1187 move |params, cx| {
1188 if let Some(this) = this.upgrade() {
1189 this.update(cx, |_, cx| {
1190 cx.emit(LspStoreEvent::LanguageServerLog(
1191 server_id,
1192 LanguageServerLogType::Log(params.typ),
1193 params.message,
1194 ));
1195 });
1196 }
1197 }
1198 })
1199 .detach();
1200
1201 language_server
1202 .on_notification::<lsp::notification::LogTrace, _>({
1203 let this = lsp_store.clone();
1204 move |params, cx| {
1205 let mut cx = cx.clone();
1206 if let Some(this) = this.upgrade() {
1207 this.update(&mut cx, |_, cx| {
1208 cx.emit(LspStoreEvent::LanguageServerLog(
1209 server_id,
1210 LanguageServerLogType::Trace {
1211 verbose_info: params.verbose,
1212 },
1213 params.message,
1214 ));
1215 });
1216 }
1217 }
1218 })
1219 .detach();
1220
1221 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1222 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1223 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1224 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1225 }
1226
1227 fn shutdown_language_servers_on_quit(
1228 &mut self,
1229 _: &mut Context<LspStore>,
1230 ) -> impl Future<Output = ()> + use<> {
1231 let shutdown_futures = self
1232 .language_servers
1233 .drain()
1234 .map(|(_, server_state)| Self::shutdown_server(server_state))
1235 .collect::<Vec<_>>();
1236
1237 async move {
1238 join_all(shutdown_futures).await;
1239 }
1240 }
1241
1242 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1243 match server_state {
1244 LanguageServerState::Running { server, .. } => {
1245 if let Some(shutdown) = server.shutdown() {
1246 shutdown.await;
1247 }
1248 }
1249 LanguageServerState::Starting { startup, .. } => {
1250 if let Some(server) = startup.await
1251 && let Some(shutdown) = server.shutdown()
1252 {
1253 shutdown.await;
1254 }
1255 }
1256 }
1257 Ok(())
1258 }
1259
1260 fn language_servers_for_worktree(
1261 &self,
1262 worktree_id: WorktreeId,
1263 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1264 self.language_server_ids
1265 .iter()
1266 .filter_map(move |(seed, state)| {
1267 if seed.worktree_id != worktree_id {
1268 return None;
1269 }
1270
1271 if let Some(LanguageServerState::Running { server, .. }) =
1272 self.language_servers.get(&state.id)
1273 {
1274 Some(server)
1275 } else {
1276 None
1277 }
1278 })
1279 }
1280
1281 fn language_server_ids_for_project_path(
1282 &self,
1283 project_path: ProjectPath,
1284 language: &Language,
1285 cx: &mut App,
1286 ) -> Vec<LanguageServerId> {
1287 let Some(worktree) = self
1288 .worktree_store
1289 .read(cx)
1290 .worktree_for_id(project_path.worktree_id, cx)
1291 else {
1292 return Vec::new();
1293 };
1294 let delegate: Arc<dyn ManifestDelegate> =
1295 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1296
1297 self.lsp_tree
1298 .get(
1299 project_path,
1300 language.name(),
1301 language.manifest(),
1302 &delegate,
1303 cx,
1304 )
1305 .collect::<Vec<_>>()
1306 }
1307
1308 fn language_server_ids_for_buffer(
1309 &self,
1310 buffer: &Buffer,
1311 cx: &mut App,
1312 ) -> Vec<LanguageServerId> {
1313 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1314 let worktree_id = file.worktree_id(cx);
1315
1316 let path: Arc<RelPath> = file
1317 .path()
1318 .parent()
1319 .map(Arc::from)
1320 .unwrap_or_else(|| file.path().clone());
1321 let worktree_path = ProjectPath { worktree_id, path };
1322 self.language_server_ids_for_project_path(worktree_path, language, cx)
1323 } else {
1324 Vec::new()
1325 }
1326 }
1327
1328 fn language_servers_for_buffer<'a>(
1329 &'a self,
1330 buffer: &'a Buffer,
1331 cx: &'a mut App,
1332 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1333 self.language_server_ids_for_buffer(buffer, cx)
1334 .into_iter()
1335 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1336 LanguageServerState::Running {
1337 adapter, server, ..
1338 } => Some((adapter, server)),
1339 _ => None,
1340 })
1341 }
1342
1343 async fn execute_code_action_kind_locally(
1344 lsp_store: WeakEntity<LspStore>,
1345 mut buffers: Vec<Entity<Buffer>>,
1346 kind: CodeActionKind,
1347 push_to_history: bool,
1348 cx: &mut AsyncApp,
1349 ) -> anyhow::Result<ProjectTransaction> {
1350 // Do not allow multiple concurrent code actions requests for the
1351 // same buffer.
1352 lsp_store.update(cx, |this, cx| {
1353 let this = this.as_local_mut().unwrap();
1354 buffers.retain(|buffer| {
1355 this.buffers_being_formatted
1356 .insert(buffer.read(cx).remote_id())
1357 });
1358 })?;
1359 let _cleanup = defer({
1360 let this = lsp_store.clone();
1361 let mut cx = cx.clone();
1362 let buffers = &buffers;
1363 move || {
1364 this.update(&mut cx, |this, cx| {
1365 let this = this.as_local_mut().unwrap();
1366 for buffer in buffers {
1367 this.buffers_being_formatted
1368 .remove(&buffer.read(cx).remote_id());
1369 }
1370 })
1371 .ok();
1372 }
1373 });
1374 let mut project_transaction = ProjectTransaction::default();
1375
1376 for buffer in &buffers {
1377 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1378 buffer.update(cx, |buffer, cx| {
1379 lsp_store
1380 .as_local()
1381 .unwrap()
1382 .language_servers_for_buffer(buffer, cx)
1383 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1384 .collect::<Vec<_>>()
1385 })
1386 })?;
1387 for (_, language_server) in adapters_and_servers.iter() {
1388 let actions = Self::get_server_code_actions_from_action_kinds(
1389 &lsp_store,
1390 language_server.server_id(),
1391 vec![kind.clone()],
1392 buffer,
1393 cx,
1394 )
1395 .await?;
1396 Self::execute_code_actions_on_server(
1397 &lsp_store,
1398 language_server,
1399 actions,
1400 push_to_history,
1401 &mut project_transaction,
1402 cx,
1403 )
1404 .await?;
1405 }
1406 }
1407 Ok(project_transaction)
1408 }
1409
1410 async fn format_locally(
1411 lsp_store: WeakEntity<LspStore>,
1412 mut buffers: Vec<FormattableBuffer>,
1413 push_to_history: bool,
1414 trigger: FormatTrigger,
1415 logger: zlog::Logger,
1416 cx: &mut AsyncApp,
1417 ) -> anyhow::Result<ProjectTransaction> {
1418 // Do not allow multiple concurrent formatting requests for the
1419 // same buffer.
1420 lsp_store.update(cx, |this, cx| {
1421 let this = this.as_local_mut().unwrap();
1422 buffers.retain(|buffer| {
1423 this.buffers_being_formatted
1424 .insert(buffer.handle.read(cx).remote_id())
1425 });
1426 })?;
1427
1428 let _cleanup = defer({
1429 let this = lsp_store.clone();
1430 let mut cx = cx.clone();
1431 let buffers = &buffers;
1432 move || {
1433 this.update(&mut cx, |this, cx| {
1434 let this = this.as_local_mut().unwrap();
1435 for buffer in buffers {
1436 this.buffers_being_formatted
1437 .remove(&buffer.handle.read(cx).remote_id());
1438 }
1439 })
1440 .ok();
1441 }
1442 });
1443
1444 let mut project_transaction = ProjectTransaction::default();
1445
1446 for buffer in &buffers {
1447 zlog::debug!(
1448 logger =>
1449 "formatting buffer '{:?}'",
1450 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1451 );
1452 // Create an empty transaction to hold all of the formatting edits.
1453 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1454 // ensure no transactions created while formatting are
1455 // grouped with the previous transaction in the history
1456 // based on the transaction group interval
1457 buffer.finalize_last_transaction();
1458 buffer
1459 .start_transaction()
1460 .context("transaction already open")?;
1461 buffer.end_transaction(cx);
1462 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1463 buffer.finalize_last_transaction();
1464 anyhow::Ok(transaction_id)
1465 })?;
1466
1467 let result = Self::format_buffer_locally(
1468 lsp_store.clone(),
1469 buffer,
1470 formatting_transaction_id,
1471 trigger,
1472 logger,
1473 cx,
1474 )
1475 .await;
1476
1477 buffer.handle.update(cx, |buffer, cx| {
1478 let Some(formatting_transaction) =
1479 buffer.get_transaction(formatting_transaction_id).cloned()
1480 else {
1481 zlog::warn!(logger => "no formatting transaction");
1482 return;
1483 };
1484 if formatting_transaction.edit_ids.is_empty() {
1485 zlog::debug!(logger => "no changes made while formatting");
1486 buffer.forget_transaction(formatting_transaction_id);
1487 return;
1488 }
1489 if !push_to_history {
1490 zlog::trace!(logger => "forgetting format transaction");
1491 buffer.forget_transaction(formatting_transaction.id);
1492 }
1493 project_transaction
1494 .0
1495 .insert(cx.entity(), formatting_transaction);
1496 });
1497
1498 result?;
1499 }
1500
1501 Ok(project_transaction)
1502 }
1503
1504 async fn format_buffer_locally(
1505 lsp_store: WeakEntity<LspStore>,
1506 buffer: &FormattableBuffer,
1507 formatting_transaction_id: clock::Lamport,
1508 trigger: FormatTrigger,
1509 logger: zlog::Logger,
1510 cx: &mut AsyncApp,
1511 ) -> Result<()> {
1512 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1513 buffer.handle.update(cx, |buffer, cx| {
1514 let adapters_and_servers = lsp_store
1515 .as_local()
1516 .unwrap()
1517 .language_servers_for_buffer(buffer, cx)
1518 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1519 .collect::<Vec<_>>();
1520 let settings =
1521 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1522 .into_owned();
1523 (adapters_and_servers, settings)
1524 })
1525 })?;
1526
1527 /// Apply edits to the buffer that will become part of the formatting transaction.
1528 /// Fails if the buffer has been edited since the start of that transaction.
1529 fn extend_formatting_transaction(
1530 buffer: &FormattableBuffer,
1531 formatting_transaction_id: text::TransactionId,
1532 cx: &mut AsyncApp,
1533 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1534 ) -> anyhow::Result<()> {
1535 buffer.handle.update(cx, |buffer, cx| {
1536 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1537 if last_transaction_id != Some(formatting_transaction_id) {
1538 anyhow::bail!("Buffer edited while formatting. Aborting")
1539 }
1540 buffer.start_transaction();
1541 operation(buffer, cx);
1542 if let Some(transaction_id) = buffer.end_transaction(cx) {
1543 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1544 }
1545 Ok(())
1546 })
1547 }
1548
1549 // handle whitespace formatting
1550 if settings.remove_trailing_whitespace_on_save {
1551 zlog::trace!(logger => "removing trailing whitespace");
1552 let diff = buffer
1553 .handle
1554 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1555 .await;
1556 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1557 buffer.apply_diff(diff, cx);
1558 })?;
1559 }
1560
1561 if settings.ensure_final_newline_on_save {
1562 zlog::trace!(logger => "ensuring final newline");
1563 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1564 buffer.ensure_final_newline(cx);
1565 })?;
1566 }
1567
1568 // Formatter for `code_actions_on_format` that runs before
1569 // the rest of the formatters
1570 let mut code_actions_on_format_formatters = None;
1571 let should_run_code_actions_on_format = !matches!(
1572 (trigger, &settings.format_on_save),
1573 (FormatTrigger::Save, &FormatOnSave::Off)
1574 );
1575 if should_run_code_actions_on_format {
1576 let have_code_actions_to_run_on_format = settings
1577 .code_actions_on_format
1578 .values()
1579 .any(|enabled| *enabled);
1580 if have_code_actions_to_run_on_format {
1581 zlog::trace!(logger => "going to run code actions on format");
1582 code_actions_on_format_formatters = Some(
1583 settings
1584 .code_actions_on_format
1585 .iter()
1586 .filter_map(|(action, enabled)| enabled.then_some(action))
1587 .cloned()
1588 .map(Formatter::CodeAction)
1589 .collect::<Vec<_>>(),
1590 );
1591 }
1592 }
1593
1594 let formatters = match (trigger, &settings.format_on_save) {
1595 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1596 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1597 settings.formatter.as_ref()
1598 }
1599 };
1600
1601 let formatters = code_actions_on_format_formatters
1602 .iter()
1603 .flatten()
1604 .chain(formatters);
1605
1606 for formatter in formatters {
1607 let formatter = if formatter == &Formatter::Auto {
1608 if settings.prettier.allowed {
1609 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1610 &Formatter::Prettier
1611 } else {
1612 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1613 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1614 }
1615 } else {
1616 formatter
1617 };
1618 match formatter {
1619 Formatter::Auto => unreachable!("Auto resolved above"),
1620 Formatter::Prettier => {
1621 let logger = zlog::scoped!(logger => "prettier");
1622 zlog::trace!(logger => "formatting");
1623 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1624
1625 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1626 lsp_store.prettier_store().unwrap().downgrade()
1627 })?;
1628 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1629 .await
1630 .transpose()?;
1631 let Some(diff) = diff else {
1632 zlog::trace!(logger => "No changes");
1633 continue;
1634 };
1635
1636 extend_formatting_transaction(
1637 buffer,
1638 formatting_transaction_id,
1639 cx,
1640 |buffer, cx| {
1641 buffer.apply_diff(diff, cx);
1642 },
1643 )?;
1644 }
1645 Formatter::External { command, arguments } => {
1646 let logger = zlog::scoped!(logger => "command");
1647 zlog::trace!(logger => "formatting");
1648 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1649
1650 let diff = Self::format_via_external_command(
1651 buffer,
1652 &command,
1653 arguments.as_deref(),
1654 cx,
1655 )
1656 .await
1657 .with_context(|| {
1658 format!("Failed to format buffer via external command: {}", command)
1659 })?;
1660 let Some(diff) = diff else {
1661 zlog::trace!(logger => "No changes");
1662 continue;
1663 };
1664
1665 extend_formatting_transaction(
1666 buffer,
1667 formatting_transaction_id,
1668 cx,
1669 |buffer, cx| {
1670 buffer.apply_diff(diff, cx);
1671 },
1672 )?;
1673 }
1674 Formatter::LanguageServer(specifier) => {
1675 let logger = zlog::scoped!(logger => "language-server");
1676 zlog::trace!(logger => "formatting");
1677 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1678
1679 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1680 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1681 continue;
1682 };
1683
1684 let language_server = match specifier {
1685 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1686 adapters_and_servers.iter().find_map(|(adapter, server)| {
1687 if adapter.name.0.as_ref() == name {
1688 Some(server.clone())
1689 } else {
1690 None
1691 }
1692 })
1693 }
1694 settings::LanguageServerFormatterSpecifier::Current => {
1695 adapters_and_servers.first().map(|e| e.1.clone())
1696 }
1697 };
1698
1699 let Some(language_server) = language_server else {
1700 log::debug!(
1701 "No language server found to format buffer '{:?}'. Skipping",
1702 buffer_path_abs.as_path().to_string_lossy()
1703 );
1704 continue;
1705 };
1706
1707 zlog::trace!(
1708 logger =>
1709 "Formatting buffer '{:?}' using language server '{:?}'",
1710 buffer_path_abs.as_path().to_string_lossy(),
1711 language_server.name()
1712 );
1713
1714 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1715 zlog::trace!(logger => "formatting ranges");
1716 Self::format_ranges_via_lsp(
1717 &lsp_store,
1718 &buffer.handle,
1719 ranges,
1720 buffer_path_abs,
1721 &language_server,
1722 &settings,
1723 cx,
1724 )
1725 .await
1726 .context("Failed to format ranges via language server")?
1727 } else {
1728 zlog::trace!(logger => "formatting full");
1729 Self::format_via_lsp(
1730 &lsp_store,
1731 &buffer.handle,
1732 buffer_path_abs,
1733 &language_server,
1734 &settings,
1735 cx,
1736 )
1737 .await
1738 .context("failed to format via language server")?
1739 };
1740
1741 if edits.is_empty() {
1742 zlog::trace!(logger => "No changes");
1743 continue;
1744 }
1745 extend_formatting_transaction(
1746 buffer,
1747 formatting_transaction_id,
1748 cx,
1749 |buffer, cx| {
1750 buffer.edit(edits, None, cx);
1751 },
1752 )?;
1753 }
1754 Formatter::CodeAction(code_action_name) => {
1755 let logger = zlog::scoped!(logger => "code-actions");
1756 zlog::trace!(logger => "formatting");
1757 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1758
1759 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1760 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1761 continue;
1762 };
1763
1764 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1765 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1766
1767 let mut actions_and_servers = Vec::new();
1768
1769 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1770 let actions_result = Self::get_server_code_actions_from_action_kinds(
1771 &lsp_store,
1772 language_server.server_id(),
1773 vec![code_action_kind.clone()],
1774 &buffer.handle,
1775 cx,
1776 )
1777 .await
1778 .with_context(|| {
1779 format!(
1780 "Failed to resolve code action {:?} with language server {}",
1781 code_action_kind,
1782 language_server.name()
1783 )
1784 });
1785 let Ok(actions) = actions_result else {
1786 // note: it may be better to set result to the error and break formatters here
1787 // but for now we try to execute the actions that we can resolve and skip the rest
1788 zlog::error!(
1789 logger =>
1790 "Failed to resolve code action {:?} with language server {}",
1791 code_action_kind,
1792 language_server.name()
1793 );
1794 continue;
1795 };
1796 for action in actions {
1797 actions_and_servers.push((action, index));
1798 }
1799 }
1800
1801 if actions_and_servers.is_empty() {
1802 zlog::warn!(logger => "No code actions were resolved, continuing");
1803 continue;
1804 }
1805
1806 'actions: for (mut action, server_index) in actions_and_servers {
1807 let server = &adapters_and_servers[server_index].1;
1808
1809 let describe_code_action = |action: &CodeAction| {
1810 format!(
1811 "code action '{}' with title \"{}\" on server {}",
1812 action
1813 .lsp_action
1814 .action_kind()
1815 .unwrap_or("unknown".into())
1816 .as_str(),
1817 action.lsp_action.title(),
1818 server.name(),
1819 )
1820 };
1821
1822 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1823
1824 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1825 zlog::error!(
1826 logger =>
1827 "Failed to resolve {}. Error: {}",
1828 describe_code_action(&action),
1829 err
1830 );
1831 continue;
1832 }
1833
1834 if let Some(edit) = action.lsp_action.edit().cloned() {
1835 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1836 // but filters out and logs warnings for code actions that require unreasonably
1837 // difficult handling on our part, such as:
1838 // - applying edits that call commands
1839 // which can result in arbitrary workspace edits being sent from the server that
1840 // have no way of being tied back to the command that initiated them (i.e. we
1841 // can't know which edits are part of the format request, or if the server is done sending
1842 // actions in response to the command)
1843 // - actions that create/delete/modify/rename files other than the one we are formatting
1844 // as we then would need to handle such changes correctly in the local history as well
1845 // as the remote history through the ProjectTransaction
1846 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1847 // Supporting these actions is not impossible, but not supported as of yet.
1848 if edit.changes.is_none() && edit.document_changes.is_none() {
1849 zlog::trace!(
1850 logger =>
1851 "No changes for code action. Skipping {}",
1852 describe_code_action(&action),
1853 );
1854 continue;
1855 }
1856
1857 let mut operations = Vec::new();
1858 if let Some(document_changes) = edit.document_changes {
1859 match document_changes {
1860 lsp::DocumentChanges::Edits(edits) => operations.extend(
1861 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1862 ),
1863 lsp::DocumentChanges::Operations(ops) => operations = ops,
1864 }
1865 } else if let Some(changes) = edit.changes {
1866 operations.extend(changes.into_iter().map(|(uri, edits)| {
1867 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1868 text_document:
1869 lsp::OptionalVersionedTextDocumentIdentifier {
1870 uri,
1871 version: None,
1872 },
1873 edits: edits.into_iter().map(Edit::Plain).collect(),
1874 })
1875 }));
1876 }
1877
1878 let mut edits = Vec::with_capacity(operations.len());
1879
1880 if operations.is_empty() {
1881 zlog::trace!(
1882 logger =>
1883 "No changes for code action. Skipping {}",
1884 describe_code_action(&action),
1885 );
1886 continue;
1887 }
1888 for operation in operations {
1889 let op = match operation {
1890 lsp::DocumentChangeOperation::Edit(op) => op,
1891 lsp::DocumentChangeOperation::Op(_) => {
1892 zlog::warn!(
1893 logger =>
1894 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1895 describe_code_action(&action),
1896 );
1897 continue 'actions;
1898 }
1899 };
1900 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1901 zlog::warn!(
1902 logger =>
1903 "Failed to convert URI '{:?}' to file path. Skipping {}",
1904 &op.text_document.uri,
1905 describe_code_action(&action),
1906 );
1907 continue 'actions;
1908 };
1909 if &file_path != buffer_path_abs {
1910 zlog::warn!(
1911 logger =>
1912 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1913 file_path,
1914 buffer_path_abs,
1915 describe_code_action(&action),
1916 );
1917 continue 'actions;
1918 }
1919
1920 let mut lsp_edits = Vec::new();
1921 for edit in op.edits {
1922 match edit {
1923 Edit::Plain(edit) => {
1924 if !lsp_edits.contains(&edit) {
1925 lsp_edits.push(edit);
1926 }
1927 }
1928 Edit::Annotated(edit) => {
1929 if !lsp_edits.contains(&edit.text_edit) {
1930 lsp_edits.push(edit.text_edit);
1931 }
1932 }
1933 Edit::Snippet(_) => {
1934 zlog::warn!(
1935 logger =>
1936 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1937 describe_code_action(&action),
1938 );
1939 continue 'actions;
1940 }
1941 }
1942 }
1943 let edits_result = lsp_store
1944 .update(cx, |lsp_store, cx| {
1945 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1946 &buffer.handle,
1947 lsp_edits,
1948 server.server_id(),
1949 op.text_document.version,
1950 cx,
1951 )
1952 })?
1953 .await;
1954 let Ok(resolved_edits) = edits_result else {
1955 zlog::warn!(
1956 logger =>
1957 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1958 buffer_path_abs.as_path(),
1959 describe_code_action(&action),
1960 );
1961 continue 'actions;
1962 };
1963 edits.extend(resolved_edits);
1964 }
1965
1966 if edits.is_empty() {
1967 zlog::warn!(logger => "No edits resolved from LSP");
1968 continue;
1969 }
1970
1971 extend_formatting_transaction(
1972 buffer,
1973 formatting_transaction_id,
1974 cx,
1975 |buffer, cx| {
1976 zlog::info!(
1977 "Applying edits {edits:?}. Content: {:?}",
1978 buffer.text()
1979 );
1980 buffer.edit(edits, None, cx);
1981 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1982 },
1983 )?;
1984 }
1985
1986 if let Some(command) = action.lsp_action.command() {
1987 zlog::warn!(
1988 logger =>
1989 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1990 &command.command,
1991 );
1992
1993 // bail early if command is invalid
1994 let server_capabilities = server.capabilities();
1995 let available_commands = server_capabilities
1996 .execute_command_provider
1997 .as_ref()
1998 .map(|options| options.commands.as_slice())
1999 .unwrap_or_default();
2000 if !available_commands.contains(&command.command) {
2001 zlog::warn!(
2002 logger =>
2003 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2004 command.command,
2005 server.name(),
2006 );
2007 continue;
2008 }
2009
2010 // noop so we just ensure buffer hasn't been edited since resolving code actions
2011 extend_formatting_transaction(
2012 buffer,
2013 formatting_transaction_id,
2014 cx,
2015 |_, _| {},
2016 )?;
2017 zlog::info!(logger => "Executing command {}", &command.command);
2018
2019 lsp_store.update(cx, |this, _| {
2020 this.as_local_mut()
2021 .unwrap()
2022 .last_workspace_edits_by_language_server
2023 .remove(&server.server_id());
2024 })?;
2025
2026 let execute_command_result = server
2027 .request::<lsp::request::ExecuteCommand>(
2028 lsp::ExecuteCommandParams {
2029 command: command.command.clone(),
2030 arguments: command.arguments.clone().unwrap_or_default(),
2031 ..Default::default()
2032 },
2033 )
2034 .await
2035 .into_response();
2036
2037 if execute_command_result.is_err() {
2038 zlog::error!(
2039 logger =>
2040 "Failed to execute command '{}' as part of {}",
2041 &command.command,
2042 describe_code_action(&action),
2043 );
2044 continue 'actions;
2045 }
2046
2047 let mut project_transaction_command =
2048 lsp_store.update(cx, |this, _| {
2049 this.as_local_mut()
2050 .unwrap()
2051 .last_workspace_edits_by_language_server
2052 .remove(&server.server_id())
2053 .unwrap_or_default()
2054 })?;
2055
2056 if let Some(transaction) =
2057 project_transaction_command.0.remove(&buffer.handle)
2058 {
2059 zlog::trace!(
2060 logger =>
2061 "Successfully captured {} edits that resulted from command {}",
2062 transaction.edit_ids.len(),
2063 &command.command,
2064 );
2065 let transaction_id_project_transaction = transaction.id;
2066 buffer.handle.update(cx, |buffer, _| {
2067 // it may have been removed from history if push_to_history was
2068 // false in deserialize_workspace_edit. If so push it so we
2069 // can merge it with the format transaction
2070 // and pop the combined transaction off the history stack
2071 // later if push_to_history is false
2072 if buffer.get_transaction(transaction.id).is_none() {
2073 buffer.push_transaction(transaction, Instant::now());
2074 }
2075 buffer.merge_transactions(
2076 transaction_id_project_transaction,
2077 formatting_transaction_id,
2078 );
2079 });
2080 }
2081
2082 if !project_transaction_command.0.is_empty() {
2083 let mut extra_buffers = String::new();
2084 for buffer in project_transaction_command.0.keys() {
2085 buffer.read_with(cx, |b, cx| {
2086 if let Some(path) = b.project_path(cx) {
2087 if !extra_buffers.is_empty() {
2088 extra_buffers.push_str(", ");
2089 }
2090 extra_buffers.push_str(path.path.as_unix_str());
2091 }
2092 });
2093 }
2094 zlog::warn!(
2095 logger =>
2096 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2097 &command.command,
2098 extra_buffers,
2099 );
2100 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2101 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2102 // add it so it's included, and merge it into the format transaction when its created later
2103 }
2104 }
2105 }
2106 }
2107 }
2108 }
2109
2110 Ok(())
2111 }
2112
2113 pub async fn format_ranges_via_lsp(
2114 this: &WeakEntity<LspStore>,
2115 buffer_handle: &Entity<Buffer>,
2116 ranges: &[Range<Anchor>],
2117 abs_path: &Path,
2118 language_server: &Arc<LanguageServer>,
2119 settings: &LanguageSettings,
2120 cx: &mut AsyncApp,
2121 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2122 let capabilities = &language_server.capabilities();
2123 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2124 if range_formatting_provider == Some(&OneOf::Left(false)) {
2125 anyhow::bail!(
2126 "{} language server does not support range formatting",
2127 language_server.name()
2128 );
2129 }
2130
2131 let uri = file_path_to_lsp_url(abs_path)?;
2132 let text_document = lsp::TextDocumentIdentifier::new(uri);
2133
2134 let lsp_edits = {
2135 let mut lsp_ranges = Vec::new();
2136 this.update(cx, |_this, cx| {
2137 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2138 // not have been sent to the language server. This seems like a fairly systemic
2139 // issue, though, the resolution probably is not specific to formatting.
2140 //
2141 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2142 // LSP.
2143 let snapshot = buffer_handle.read(cx).snapshot();
2144 for range in ranges {
2145 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2146 }
2147 anyhow::Ok(())
2148 })??;
2149
2150 let mut edits = None;
2151 for range in lsp_ranges {
2152 if let Some(mut edit) = language_server
2153 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2154 text_document: text_document.clone(),
2155 range,
2156 options: lsp_command::lsp_formatting_options(settings),
2157 work_done_progress_params: Default::default(),
2158 })
2159 .await
2160 .into_response()?
2161 {
2162 edits.get_or_insert_with(Vec::new).append(&mut edit);
2163 }
2164 }
2165 edits
2166 };
2167
2168 if let Some(lsp_edits) = lsp_edits {
2169 this.update(cx, |this, cx| {
2170 this.as_local_mut().unwrap().edits_from_lsp(
2171 buffer_handle,
2172 lsp_edits,
2173 language_server.server_id(),
2174 None,
2175 cx,
2176 )
2177 })?
2178 .await
2179 } else {
2180 Ok(Vec::with_capacity(0))
2181 }
2182 }
2183
2184 async fn format_via_lsp(
2185 this: &WeakEntity<LspStore>,
2186 buffer: &Entity<Buffer>,
2187 abs_path: &Path,
2188 language_server: &Arc<LanguageServer>,
2189 settings: &LanguageSettings,
2190 cx: &mut AsyncApp,
2191 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2192 let logger = zlog::scoped!("lsp_format");
2193 zlog::debug!(logger => "Formatting via LSP");
2194
2195 let uri = file_path_to_lsp_url(abs_path)?;
2196 let text_document = lsp::TextDocumentIdentifier::new(uri);
2197 let capabilities = &language_server.capabilities();
2198
2199 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2200 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2201
2202 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2203 let _timer = zlog::time!(logger => "format-full");
2204 language_server
2205 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2206 text_document,
2207 options: lsp_command::lsp_formatting_options(settings),
2208 work_done_progress_params: Default::default(),
2209 })
2210 .await
2211 .into_response()?
2212 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2213 let _timer = zlog::time!(logger => "format-range");
2214 let buffer_start = lsp::Position::new(0, 0);
2215 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2216 language_server
2217 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2218 text_document: text_document.clone(),
2219 range: lsp::Range::new(buffer_start, buffer_end),
2220 options: lsp_command::lsp_formatting_options(settings),
2221 work_done_progress_params: Default::default(),
2222 })
2223 .await
2224 .into_response()?
2225 } else {
2226 None
2227 };
2228
2229 if let Some(lsp_edits) = lsp_edits {
2230 this.update(cx, |this, cx| {
2231 this.as_local_mut().unwrap().edits_from_lsp(
2232 buffer,
2233 lsp_edits,
2234 language_server.server_id(),
2235 None,
2236 cx,
2237 )
2238 })?
2239 .await
2240 } else {
2241 Ok(Vec::with_capacity(0))
2242 }
2243 }
2244
2245 async fn format_via_external_command(
2246 buffer: &FormattableBuffer,
2247 command: &str,
2248 arguments: Option<&[String]>,
2249 cx: &mut AsyncApp,
2250 ) -> Result<Option<Diff>> {
2251 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2252 let file = File::from_dyn(buffer.file())?;
2253 let worktree = file.worktree.read(cx);
2254 let mut worktree_path = worktree.abs_path().to_path_buf();
2255 if worktree.root_entry()?.is_file() {
2256 worktree_path.pop();
2257 }
2258 Some(worktree_path)
2259 });
2260
2261 let mut child = util::command::new_smol_command(command);
2262
2263 if let Some(buffer_env) = buffer.env.as_ref() {
2264 child.envs(buffer_env);
2265 }
2266
2267 if let Some(working_dir_path) = working_dir_path {
2268 child.current_dir(working_dir_path);
2269 }
2270
2271 if let Some(arguments) = arguments {
2272 child.args(arguments.iter().map(|arg| {
2273 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2274 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2275 } else {
2276 arg.replace("{buffer_path}", "Untitled")
2277 }
2278 }));
2279 }
2280
2281 let mut child = child
2282 .stdin(smol::process::Stdio::piped())
2283 .stdout(smol::process::Stdio::piped())
2284 .stderr(smol::process::Stdio::piped())
2285 .spawn()?;
2286
2287 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2288 let text = buffer
2289 .handle
2290 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2291 for chunk in text.chunks() {
2292 stdin.write_all(chunk.as_bytes()).await?;
2293 }
2294 stdin.flush().await?;
2295
2296 let output = child.output().await?;
2297 anyhow::ensure!(
2298 output.status.success(),
2299 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2300 output.status.code(),
2301 String::from_utf8_lossy(&output.stdout),
2302 String::from_utf8_lossy(&output.stderr),
2303 );
2304
2305 let stdout = String::from_utf8(output.stdout)?;
2306 Ok(Some(
2307 buffer
2308 .handle
2309 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2310 .await,
2311 ))
2312 }
2313
2314 async fn try_resolve_code_action(
2315 lang_server: &LanguageServer,
2316 action: &mut CodeAction,
2317 ) -> anyhow::Result<()> {
2318 match &mut action.lsp_action {
2319 LspAction::Action(lsp_action) => {
2320 if !action.resolved
2321 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2322 && lsp_action.data.is_some()
2323 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2324 {
2325 **lsp_action = lang_server
2326 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2327 .await
2328 .into_response()?;
2329 }
2330 }
2331 LspAction::CodeLens(lens) => {
2332 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2333 *lens = lang_server
2334 .request::<lsp::request::CodeLensResolve>(lens.clone())
2335 .await
2336 .into_response()?;
2337 }
2338 }
2339 LspAction::Command(_) => {}
2340 }
2341
2342 action.resolved = true;
2343 anyhow::Ok(())
2344 }
2345
2346 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2347 let buffer = buffer_handle.read(cx);
2348
2349 let file = buffer.file().cloned();
2350
2351 let Some(file) = File::from_dyn(file.as_ref()) else {
2352 return;
2353 };
2354 if !file.is_local() {
2355 return;
2356 }
2357 let path = ProjectPath::from_file(file, cx);
2358 let worktree_id = file.worktree_id(cx);
2359 let language = buffer.language().cloned();
2360
2361 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2362 for (server_id, diagnostics) in
2363 diagnostics.get(file.path()).cloned().unwrap_or_default()
2364 {
2365 self.update_buffer_diagnostics(
2366 buffer_handle,
2367 server_id,
2368 None,
2369 None,
2370 None,
2371 Vec::new(),
2372 diagnostics,
2373 cx,
2374 )
2375 .log_err();
2376 }
2377 }
2378 let Some(language) = language else {
2379 return;
2380 };
2381 let Some(snapshot) = self
2382 .worktree_store
2383 .read(cx)
2384 .worktree_for_id(worktree_id, cx)
2385 .map(|worktree| worktree.read(cx).snapshot())
2386 else {
2387 return;
2388 };
2389 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2390
2391 for server_id in
2392 self.lsp_tree
2393 .get(path, language.name(), language.manifest(), &delegate, cx)
2394 {
2395 let server = self
2396 .language_servers
2397 .get(&server_id)
2398 .and_then(|server_state| {
2399 if let LanguageServerState::Running { server, .. } = server_state {
2400 Some(server.clone())
2401 } else {
2402 None
2403 }
2404 });
2405 let server = match server {
2406 Some(server) => server,
2407 None => continue,
2408 };
2409
2410 buffer_handle.update(cx, |buffer, cx| {
2411 buffer.set_completion_triggers(
2412 server.server_id(),
2413 server
2414 .capabilities()
2415 .completion_provider
2416 .as_ref()
2417 .and_then(|provider| {
2418 provider
2419 .trigger_characters
2420 .as_ref()
2421 .map(|characters| characters.iter().cloned().collect())
2422 })
2423 .unwrap_or_default(),
2424 cx,
2425 );
2426 });
2427 }
2428 }
2429
2430 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2431 buffer.update(cx, |buffer, cx| {
2432 let Some(language) = buffer.language() else {
2433 return;
2434 };
2435 let path = ProjectPath {
2436 worktree_id: old_file.worktree_id(cx),
2437 path: old_file.path.clone(),
2438 };
2439 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2440 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2441 buffer.set_completion_triggers(server_id, Default::default(), cx);
2442 }
2443 });
2444 }
2445
2446 fn update_buffer_diagnostics(
2447 &mut self,
2448 buffer: &Entity<Buffer>,
2449 server_id: LanguageServerId,
2450 registration_id: Option<Option<SharedString>>,
2451 result_id: Option<SharedString>,
2452 version: Option<i32>,
2453 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2454 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2455 cx: &mut Context<LspStore>,
2456 ) -> Result<()> {
2457 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2458 Ordering::Equal
2459 .then_with(|| b.is_primary.cmp(&a.is_primary))
2460 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2461 .then_with(|| a.severity.cmp(&b.severity))
2462 .then_with(|| a.message.cmp(&b.message))
2463 }
2464
2465 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2466 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2467 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2468
2469 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2470 Ordering::Equal
2471 .then_with(|| a.range.start.cmp(&b.range.start))
2472 .then_with(|| b.range.end.cmp(&a.range.end))
2473 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2474 });
2475
2476 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2477
2478 let edits_since_save = std::cell::LazyCell::new(|| {
2479 let saved_version = buffer.read(cx).saved_version();
2480 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2481 });
2482
2483 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2484
2485 for (new_diagnostic, entry) in diagnostics {
2486 let start;
2487 let end;
2488 if new_diagnostic && entry.diagnostic.is_disk_based {
2489 // Some diagnostics are based on files on disk instead of buffers'
2490 // current contents. Adjust these diagnostics' ranges to reflect
2491 // any unsaved edits.
2492 // Do not alter the reused ones though, as their coordinates were stored as anchors
2493 // and were properly adjusted on reuse.
2494 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2495 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2496 } else {
2497 start = entry.range.start;
2498 end = entry.range.end;
2499 }
2500
2501 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2502 ..snapshot.clip_point_utf16(end, Bias::Right);
2503
2504 // Expand empty ranges by one codepoint
2505 if range.start == range.end {
2506 // This will be go to the next boundary when being clipped
2507 range.end.column += 1;
2508 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2509 if range.start == range.end && range.end.column > 0 {
2510 range.start.column -= 1;
2511 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2512 }
2513 }
2514
2515 sanitized_diagnostics.push(DiagnosticEntry {
2516 range,
2517 diagnostic: entry.diagnostic,
2518 });
2519 }
2520 drop(edits_since_save);
2521
2522 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2523 buffer.update(cx, |buffer, cx| {
2524 if let Some(registration_id) = registration_id {
2525 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2526 self.buffer_pull_diagnostics_result_ids
2527 .entry(server_id)
2528 .or_default()
2529 .entry(registration_id)
2530 .or_default()
2531 .insert(abs_path, result_id);
2532 }
2533 }
2534
2535 buffer.update_diagnostics(server_id, set, cx)
2536 });
2537
2538 Ok(())
2539 }
2540
2541 fn register_language_server_for_invisible_worktree(
2542 &mut self,
2543 worktree: &Entity<Worktree>,
2544 language_server_id: LanguageServerId,
2545 cx: &mut App,
2546 ) {
2547 let worktree = worktree.read(cx);
2548 let worktree_id = worktree.id();
2549 debug_assert!(!worktree.is_visible());
2550 let Some(mut origin_seed) = self
2551 .language_server_ids
2552 .iter()
2553 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2554 else {
2555 return;
2556 };
2557 origin_seed.worktree_id = worktree_id;
2558 self.language_server_ids
2559 .entry(origin_seed)
2560 .or_insert_with(|| UnifiedLanguageServer {
2561 id: language_server_id,
2562 project_roots: Default::default(),
2563 });
2564 }
2565
2566 fn register_buffer_with_language_servers(
2567 &mut self,
2568 buffer_handle: &Entity<Buffer>,
2569 only_register_servers: HashSet<LanguageServerSelector>,
2570 cx: &mut Context<LspStore>,
2571 ) {
2572 let buffer = buffer_handle.read(cx);
2573 let buffer_id = buffer.remote_id();
2574
2575 let Some(file) = File::from_dyn(buffer.file()) else {
2576 return;
2577 };
2578 if !file.is_local() {
2579 return;
2580 }
2581
2582 let abs_path = file.abs_path(cx);
2583 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2584 return;
2585 };
2586 let initial_snapshot = buffer.text_snapshot();
2587 let worktree_id = file.worktree_id(cx);
2588
2589 let Some(language) = buffer.language().cloned() else {
2590 return;
2591 };
2592 let path: Arc<RelPath> = file
2593 .path()
2594 .parent()
2595 .map(Arc::from)
2596 .unwrap_or_else(|| file.path().clone());
2597 let Some(worktree) = self
2598 .worktree_store
2599 .read(cx)
2600 .worktree_for_id(worktree_id, cx)
2601 else {
2602 return;
2603 };
2604 let language_name = language.name();
2605 let (reused, delegate, servers) = self
2606 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2607 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2608 .unwrap_or_else(|| {
2609 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2610 let delegate: Arc<dyn ManifestDelegate> =
2611 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2612
2613 let servers = self
2614 .lsp_tree
2615 .walk(
2616 ProjectPath { worktree_id, path },
2617 language.name(),
2618 language.manifest(),
2619 &delegate,
2620 cx,
2621 )
2622 .collect::<Vec<_>>();
2623 (false, lsp_delegate, servers)
2624 });
2625 let servers_and_adapters = servers
2626 .into_iter()
2627 .filter_map(|server_node| {
2628 if reused && server_node.server_id().is_none() {
2629 return None;
2630 }
2631 if !only_register_servers.is_empty() {
2632 if let Some(server_id) = server_node.server_id()
2633 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2634 {
2635 return None;
2636 }
2637 if let Some(name) = server_node.name()
2638 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2639 {
2640 return None;
2641 }
2642 }
2643
2644 let server_id = server_node.server_id_or_init(|disposition| {
2645 let path = &disposition.path;
2646
2647 {
2648 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2649
2650 let server_id = self.get_or_insert_language_server(
2651 &worktree,
2652 delegate.clone(),
2653 disposition,
2654 &language_name,
2655 cx,
2656 );
2657
2658 if let Some(state) = self.language_servers.get(&server_id)
2659 && let Ok(uri) = uri
2660 {
2661 state.add_workspace_folder(uri);
2662 };
2663 server_id
2664 }
2665 })?;
2666 let server_state = self.language_servers.get(&server_id)?;
2667 if let LanguageServerState::Running {
2668 server, adapter, ..
2669 } = server_state
2670 {
2671 Some((server.clone(), adapter.clone()))
2672 } else {
2673 None
2674 }
2675 })
2676 .collect::<Vec<_>>();
2677 for (server, adapter) in servers_and_adapters {
2678 buffer_handle.update(cx, |buffer, cx| {
2679 buffer.set_completion_triggers(
2680 server.server_id(),
2681 server
2682 .capabilities()
2683 .completion_provider
2684 .as_ref()
2685 .and_then(|provider| {
2686 provider
2687 .trigger_characters
2688 .as_ref()
2689 .map(|characters| characters.iter().cloned().collect())
2690 })
2691 .unwrap_or_default(),
2692 cx,
2693 );
2694 });
2695
2696 let snapshot = LspBufferSnapshot {
2697 version: 0,
2698 snapshot: initial_snapshot.clone(),
2699 };
2700
2701 let mut registered = false;
2702 self.buffer_snapshots
2703 .entry(buffer_id)
2704 .or_default()
2705 .entry(server.server_id())
2706 .or_insert_with(|| {
2707 registered = true;
2708 server.register_buffer(
2709 uri.clone(),
2710 adapter.language_id(&language.name()),
2711 0,
2712 initial_snapshot.text(),
2713 );
2714
2715 vec![snapshot]
2716 });
2717
2718 self.buffers_opened_in_servers
2719 .entry(buffer_id)
2720 .or_default()
2721 .insert(server.server_id());
2722 if registered {
2723 cx.emit(LspStoreEvent::LanguageServerUpdate {
2724 language_server_id: server.server_id(),
2725 name: None,
2726 message: proto::update_language_server::Variant::RegisteredForBuffer(
2727 proto::RegisteredForBuffer {
2728 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2729 buffer_id: buffer_id.to_proto(),
2730 },
2731 ),
2732 });
2733 }
2734 }
2735 }
2736
2737 fn reuse_existing_language_server<'lang_name>(
2738 &self,
2739 server_tree: &LanguageServerTree,
2740 worktree: &Entity<Worktree>,
2741 language_name: &'lang_name LanguageName,
2742 cx: &mut App,
2743 ) -> Option<(
2744 Arc<LocalLspAdapterDelegate>,
2745 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2746 )> {
2747 if worktree.read(cx).is_visible() {
2748 return None;
2749 }
2750
2751 let worktree_store = self.worktree_store.read(cx);
2752 let servers = server_tree
2753 .instances
2754 .iter()
2755 .filter(|(worktree_id, _)| {
2756 worktree_store
2757 .worktree_for_id(**worktree_id, cx)
2758 .is_some_and(|worktree| worktree.read(cx).is_visible())
2759 })
2760 .flat_map(|(worktree_id, servers)| {
2761 servers
2762 .roots
2763 .iter()
2764 .flat_map(|(_, language_servers)| language_servers)
2765 .map(move |(_, (server_node, server_languages))| {
2766 (worktree_id, server_node, server_languages)
2767 })
2768 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2769 .map(|(worktree_id, server_node, _)| {
2770 (
2771 *worktree_id,
2772 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2773 )
2774 })
2775 })
2776 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2777 acc.entry(worktree_id)
2778 .or_insert_with(Vec::new)
2779 .push(server_node);
2780 acc
2781 })
2782 .into_values()
2783 .max_by_key(|servers| servers.len())?;
2784
2785 let worktree_id = worktree.read(cx).id();
2786 let apply = move |tree: &mut LanguageServerTree| {
2787 for server_node in &servers {
2788 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2789 }
2790 servers
2791 };
2792
2793 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2794 Some((delegate, apply))
2795 }
2796
2797 pub(crate) fn unregister_old_buffer_from_language_servers(
2798 &mut self,
2799 buffer: &Entity<Buffer>,
2800 old_file: &File,
2801 cx: &mut App,
2802 ) {
2803 let old_path = match old_file.as_local() {
2804 Some(local) => local.abs_path(cx),
2805 None => return,
2806 };
2807
2808 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2809 debug_panic!("{old_path:?} is not parseable as an URI");
2810 return;
2811 };
2812 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2813 }
2814
2815 pub(crate) fn unregister_buffer_from_language_servers(
2816 &mut self,
2817 buffer: &Entity<Buffer>,
2818 file_url: &lsp::Uri,
2819 cx: &mut App,
2820 ) {
2821 buffer.update(cx, |buffer, cx| {
2822 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2823
2824 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2825 if snapshots
2826 .as_mut()
2827 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2828 {
2829 language_server.unregister_buffer(file_url.clone());
2830 }
2831 }
2832 });
2833 }
2834
2835 fn buffer_snapshot_for_lsp_version(
2836 &mut self,
2837 buffer: &Entity<Buffer>,
2838 server_id: LanguageServerId,
2839 version: Option<i32>,
2840 cx: &App,
2841 ) -> Result<TextBufferSnapshot> {
2842 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2843
2844 if let Some(version) = version {
2845 let buffer_id = buffer.read(cx).remote_id();
2846 let snapshots = if let Some(snapshots) = self
2847 .buffer_snapshots
2848 .get_mut(&buffer_id)
2849 .and_then(|m| m.get_mut(&server_id))
2850 {
2851 snapshots
2852 } else if version == 0 {
2853 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2854 // We detect this case and treat it as if the version was `None`.
2855 return Ok(buffer.read(cx).text_snapshot());
2856 } else {
2857 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2858 };
2859
2860 let found_snapshot = snapshots
2861 .binary_search_by_key(&version, |e| e.version)
2862 .map(|ix| snapshots[ix].snapshot.clone())
2863 .map_err(|_| {
2864 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2865 })?;
2866
2867 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2868 Ok(found_snapshot)
2869 } else {
2870 Ok((buffer.read(cx)).text_snapshot())
2871 }
2872 }
2873
2874 async fn get_server_code_actions_from_action_kinds(
2875 lsp_store: &WeakEntity<LspStore>,
2876 language_server_id: LanguageServerId,
2877 code_action_kinds: Vec<lsp::CodeActionKind>,
2878 buffer: &Entity<Buffer>,
2879 cx: &mut AsyncApp,
2880 ) -> Result<Vec<CodeAction>> {
2881 let actions = lsp_store
2882 .update(cx, move |this, cx| {
2883 let request = GetCodeActions {
2884 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2885 kinds: Some(code_action_kinds),
2886 };
2887 let server = LanguageServerToQuery::Other(language_server_id);
2888 this.request_lsp(buffer.clone(), server, request, cx)
2889 })?
2890 .await?;
2891 Ok(actions)
2892 }
2893
2894 pub async fn execute_code_actions_on_server(
2895 lsp_store: &WeakEntity<LspStore>,
2896 language_server: &Arc<LanguageServer>,
2897
2898 actions: Vec<CodeAction>,
2899 push_to_history: bool,
2900 project_transaction: &mut ProjectTransaction,
2901 cx: &mut AsyncApp,
2902 ) -> anyhow::Result<()> {
2903 for mut action in actions {
2904 Self::try_resolve_code_action(language_server, &mut action)
2905 .await
2906 .context("resolving a formatting code action")?;
2907
2908 if let Some(edit) = action.lsp_action.edit() {
2909 if edit.changes.is_none() && edit.document_changes.is_none() {
2910 continue;
2911 }
2912
2913 let new = Self::deserialize_workspace_edit(
2914 lsp_store.upgrade().context("project dropped")?,
2915 edit.clone(),
2916 push_to_history,
2917 language_server.clone(),
2918 cx,
2919 )
2920 .await?;
2921 project_transaction.0.extend(new.0);
2922 }
2923
2924 if let Some(command) = action.lsp_action.command() {
2925 let server_capabilities = language_server.capabilities();
2926 let available_commands = server_capabilities
2927 .execute_command_provider
2928 .as_ref()
2929 .map(|options| options.commands.as_slice())
2930 .unwrap_or_default();
2931 if available_commands.contains(&command.command) {
2932 lsp_store.update(cx, |lsp_store, _| {
2933 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2934 mode.last_workspace_edits_by_language_server
2935 .remove(&language_server.server_id());
2936 }
2937 })?;
2938
2939 language_server
2940 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2941 command: command.command.clone(),
2942 arguments: command.arguments.clone().unwrap_or_default(),
2943 ..Default::default()
2944 })
2945 .await
2946 .into_response()
2947 .context("execute command")?;
2948
2949 lsp_store.update(cx, |this, _| {
2950 if let LspStoreMode::Local(mode) = &mut this.mode {
2951 project_transaction.0.extend(
2952 mode.last_workspace_edits_by_language_server
2953 .remove(&language_server.server_id())
2954 .unwrap_or_default()
2955 .0,
2956 )
2957 }
2958 })?;
2959 } else {
2960 log::warn!(
2961 "Cannot execute a command {} not listed in the language server capabilities",
2962 command.command
2963 )
2964 }
2965 }
2966 }
2967 Ok(())
2968 }
2969
2970 pub async fn deserialize_text_edits(
2971 this: Entity<LspStore>,
2972 buffer_to_edit: Entity<Buffer>,
2973 edits: Vec<lsp::TextEdit>,
2974 push_to_history: bool,
2975 _: Arc<CachedLspAdapter>,
2976 language_server: Arc<LanguageServer>,
2977 cx: &mut AsyncApp,
2978 ) -> Result<Option<Transaction>> {
2979 let edits = this
2980 .update(cx, |this, cx| {
2981 this.as_local_mut().unwrap().edits_from_lsp(
2982 &buffer_to_edit,
2983 edits,
2984 language_server.server_id(),
2985 None,
2986 cx,
2987 )
2988 })
2989 .await?;
2990
2991 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2992 buffer.finalize_last_transaction();
2993 buffer.start_transaction();
2994 for (range, text) in edits {
2995 buffer.edit([(range, text)], None, cx);
2996 }
2997
2998 if buffer.end_transaction(cx).is_some() {
2999 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3000 if !push_to_history {
3001 buffer.forget_transaction(transaction.id);
3002 }
3003 Some(transaction)
3004 } else {
3005 None
3006 }
3007 });
3008
3009 Ok(transaction)
3010 }
3011
3012 #[allow(clippy::type_complexity)]
3013 pub(crate) fn edits_from_lsp(
3014 &mut self,
3015 buffer: &Entity<Buffer>,
3016 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3017 server_id: LanguageServerId,
3018 version: Option<i32>,
3019 cx: &mut Context<LspStore>,
3020 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3021 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3022 cx.background_spawn(async move {
3023 let snapshot = snapshot?;
3024 let mut lsp_edits = lsp_edits
3025 .into_iter()
3026 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3027 .collect::<Vec<_>>();
3028
3029 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3030
3031 let mut lsp_edits = lsp_edits.into_iter().peekable();
3032 let mut edits = Vec::new();
3033 while let Some((range, mut new_text)) = lsp_edits.next() {
3034 // Clip invalid ranges provided by the language server.
3035 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3036 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3037
3038 // Combine any LSP edits that are adjacent.
3039 //
3040 // Also, combine LSP edits that are separated from each other by only
3041 // a newline. This is important because for some code actions,
3042 // Rust-analyzer rewrites the entire buffer via a series of edits that
3043 // are separated by unchanged newline characters.
3044 //
3045 // In order for the diffing logic below to work properly, any edits that
3046 // cancel each other out must be combined into one.
3047 while let Some((next_range, next_text)) = lsp_edits.peek() {
3048 if next_range.start.0 > range.end {
3049 if next_range.start.0.row > range.end.row + 1
3050 || next_range.start.0.column > 0
3051 || snapshot.clip_point_utf16(
3052 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3053 Bias::Left,
3054 ) > range.end
3055 {
3056 break;
3057 }
3058 new_text.push('\n');
3059 }
3060 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3061 new_text.push_str(next_text);
3062 lsp_edits.next();
3063 }
3064
3065 // For multiline edits, perform a diff of the old and new text so that
3066 // we can identify the changes more precisely, preserving the locations
3067 // of any anchors positioned in the unchanged regions.
3068 if range.end.row > range.start.row {
3069 let offset = range.start.to_offset(&snapshot);
3070 let old_text = snapshot.text_for_range(range).collect::<String>();
3071 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3072 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3073 (
3074 snapshot.anchor_after(offset + range.start)
3075 ..snapshot.anchor_before(offset + range.end),
3076 replacement,
3077 )
3078 }));
3079 } else if range.end == range.start {
3080 let anchor = snapshot.anchor_after(range.start);
3081 edits.push((anchor..anchor, new_text.into()));
3082 } else {
3083 let edit_start = snapshot.anchor_after(range.start);
3084 let edit_end = snapshot.anchor_before(range.end);
3085 edits.push((edit_start..edit_end, new_text.into()));
3086 }
3087 }
3088
3089 Ok(edits)
3090 })
3091 }
3092
3093 pub(crate) async fn deserialize_workspace_edit(
3094 this: Entity<LspStore>,
3095 edit: lsp::WorkspaceEdit,
3096 push_to_history: bool,
3097 language_server: Arc<LanguageServer>,
3098 cx: &mut AsyncApp,
3099 ) -> Result<ProjectTransaction> {
3100 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3101
3102 let mut operations = Vec::new();
3103 if let Some(document_changes) = edit.document_changes {
3104 match document_changes {
3105 lsp::DocumentChanges::Edits(edits) => {
3106 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3107 }
3108 lsp::DocumentChanges::Operations(ops) => operations = ops,
3109 }
3110 } else if let Some(changes) = edit.changes {
3111 operations.extend(changes.into_iter().map(|(uri, edits)| {
3112 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3113 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3114 uri,
3115 version: None,
3116 },
3117 edits: edits.into_iter().map(Edit::Plain).collect(),
3118 })
3119 }));
3120 }
3121
3122 let mut project_transaction = ProjectTransaction::default();
3123 for operation in operations {
3124 match operation {
3125 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3126 let abs_path = op
3127 .uri
3128 .to_file_path()
3129 .map_err(|()| anyhow!("can't convert URI to path"))?;
3130
3131 if let Some(parent_path) = abs_path.parent() {
3132 fs.create_dir(parent_path).await?;
3133 }
3134 if abs_path.ends_with("/") {
3135 fs.create_dir(&abs_path).await?;
3136 } else {
3137 fs.create_file(
3138 &abs_path,
3139 op.options
3140 .map(|options| fs::CreateOptions {
3141 overwrite: options.overwrite.unwrap_or(false),
3142 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3143 })
3144 .unwrap_or_default(),
3145 )
3146 .await?;
3147 }
3148 }
3149
3150 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3151 let source_abs_path = op
3152 .old_uri
3153 .to_file_path()
3154 .map_err(|()| anyhow!("can't convert URI to path"))?;
3155 let target_abs_path = op
3156 .new_uri
3157 .to_file_path()
3158 .map_err(|()| anyhow!("can't convert URI to path"))?;
3159
3160 let options = fs::RenameOptions {
3161 overwrite: op
3162 .options
3163 .as_ref()
3164 .and_then(|options| options.overwrite)
3165 .unwrap_or(false),
3166 ignore_if_exists: op
3167 .options
3168 .as_ref()
3169 .and_then(|options| options.ignore_if_exists)
3170 .unwrap_or(false),
3171 create_parents: true,
3172 };
3173
3174 fs.rename(&source_abs_path, &target_abs_path, options)
3175 .await?;
3176 }
3177
3178 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3179 let abs_path = op
3180 .uri
3181 .to_file_path()
3182 .map_err(|()| anyhow!("can't convert URI to path"))?;
3183 let options = op
3184 .options
3185 .map(|options| fs::RemoveOptions {
3186 recursive: options.recursive.unwrap_or(false),
3187 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3188 })
3189 .unwrap_or_default();
3190 if abs_path.ends_with("/") {
3191 fs.remove_dir(&abs_path, options).await?;
3192 } else {
3193 fs.remove_file(&abs_path, options).await?;
3194 }
3195 }
3196
3197 lsp::DocumentChangeOperation::Edit(op) => {
3198 let buffer_to_edit = this
3199 .update(cx, |this, cx| {
3200 this.open_local_buffer_via_lsp(
3201 op.text_document.uri.clone(),
3202 language_server.server_id(),
3203 cx,
3204 )
3205 })
3206 .await?;
3207
3208 let edits = this
3209 .update(cx, |this, cx| {
3210 let path = buffer_to_edit.read(cx).project_path(cx);
3211 let active_entry = this.active_entry;
3212 let is_active_entry = path.is_some_and(|project_path| {
3213 this.worktree_store
3214 .read(cx)
3215 .entry_for_path(&project_path, cx)
3216 .is_some_and(|entry| Some(entry.id) == active_entry)
3217 });
3218 let local = this.as_local_mut().unwrap();
3219
3220 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3221 for edit in op.edits {
3222 match edit {
3223 Edit::Plain(edit) => {
3224 if !edits.contains(&edit) {
3225 edits.push(edit)
3226 }
3227 }
3228 Edit::Annotated(edit) => {
3229 if !edits.contains(&edit.text_edit) {
3230 edits.push(edit.text_edit)
3231 }
3232 }
3233 Edit::Snippet(edit) => {
3234 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3235 else {
3236 continue;
3237 };
3238
3239 if is_active_entry {
3240 snippet_edits.push((edit.range, snippet));
3241 } else {
3242 // Since this buffer is not focused, apply a normal edit.
3243 let new_edit = TextEdit {
3244 range: edit.range,
3245 new_text: snippet.text,
3246 };
3247 if !edits.contains(&new_edit) {
3248 edits.push(new_edit);
3249 }
3250 }
3251 }
3252 }
3253 }
3254 if !snippet_edits.is_empty() {
3255 let buffer_id = buffer_to_edit.read(cx).remote_id();
3256 let version = if let Some(buffer_version) = op.text_document.version
3257 {
3258 local
3259 .buffer_snapshot_for_lsp_version(
3260 &buffer_to_edit,
3261 language_server.server_id(),
3262 Some(buffer_version),
3263 cx,
3264 )
3265 .ok()
3266 .map(|snapshot| snapshot.version)
3267 } else {
3268 Some(buffer_to_edit.read(cx).saved_version().clone())
3269 };
3270
3271 let most_recent_edit =
3272 version.and_then(|version| version.most_recent());
3273 // Check if the edit that triggered that edit has been made by this participant.
3274
3275 if let Some(most_recent_edit) = most_recent_edit {
3276 cx.emit(LspStoreEvent::SnippetEdit {
3277 buffer_id,
3278 edits: snippet_edits,
3279 most_recent_edit,
3280 });
3281 }
3282 }
3283
3284 local.edits_from_lsp(
3285 &buffer_to_edit,
3286 edits,
3287 language_server.server_id(),
3288 op.text_document.version,
3289 cx,
3290 )
3291 })
3292 .await?;
3293
3294 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3295 buffer.finalize_last_transaction();
3296 buffer.start_transaction();
3297 for (range, text) in edits {
3298 buffer.edit([(range, text)], None, cx);
3299 }
3300
3301 buffer.end_transaction(cx).and_then(|transaction_id| {
3302 if push_to_history {
3303 buffer.finalize_last_transaction();
3304 buffer.get_transaction(transaction_id).cloned()
3305 } else {
3306 buffer.forget_transaction(transaction_id)
3307 }
3308 })
3309 });
3310 if let Some(transaction) = transaction {
3311 project_transaction.0.insert(buffer_to_edit, transaction);
3312 }
3313 }
3314 }
3315 }
3316
3317 Ok(project_transaction)
3318 }
3319
3320 async fn on_lsp_workspace_edit(
3321 this: WeakEntity<LspStore>,
3322 params: lsp::ApplyWorkspaceEditParams,
3323 server_id: LanguageServerId,
3324 cx: &mut AsyncApp,
3325 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3326 let this = this.upgrade().context("project project closed")?;
3327 let language_server = this
3328 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3329 .context("language server not found")?;
3330 let transaction = Self::deserialize_workspace_edit(
3331 this.clone(),
3332 params.edit,
3333 true,
3334 language_server.clone(),
3335 cx,
3336 )
3337 .await
3338 .log_err();
3339 this.update(cx, |this, cx| {
3340 if let Some(transaction) = transaction {
3341 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3342
3343 this.as_local_mut()
3344 .unwrap()
3345 .last_workspace_edits_by_language_server
3346 .insert(server_id, transaction);
3347 }
3348 });
3349 Ok(lsp::ApplyWorkspaceEditResponse {
3350 applied: true,
3351 failed_change: None,
3352 failure_reason: None,
3353 })
3354 }
3355
3356 fn remove_worktree(
3357 &mut self,
3358 id_to_remove: WorktreeId,
3359 cx: &mut Context<LspStore>,
3360 ) -> Vec<LanguageServerId> {
3361 self.restricted_worktrees_tasks.remove(&id_to_remove);
3362 self.diagnostics.remove(&id_to_remove);
3363 self.prettier_store.update(cx, |prettier_store, cx| {
3364 prettier_store.remove_worktree(id_to_remove, cx);
3365 });
3366
3367 let mut servers_to_remove = BTreeSet::default();
3368 let mut servers_to_preserve = HashSet::default();
3369 for (seed, state) in &self.language_server_ids {
3370 if seed.worktree_id == id_to_remove {
3371 servers_to_remove.insert(state.id);
3372 } else {
3373 servers_to_preserve.insert(state.id);
3374 }
3375 }
3376 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3377 self.language_server_ids
3378 .retain(|_, state| !servers_to_remove.contains(&state.id));
3379 for server_id_to_remove in &servers_to_remove {
3380 self.language_server_watched_paths
3381 .remove(server_id_to_remove);
3382 self.language_server_paths_watched_for_rename
3383 .remove(server_id_to_remove);
3384 self.last_workspace_edits_by_language_server
3385 .remove(server_id_to_remove);
3386 self.language_servers.remove(server_id_to_remove);
3387 self.buffer_pull_diagnostics_result_ids
3388 .remove(server_id_to_remove);
3389 self.workspace_pull_diagnostics_result_ids
3390 .remove(server_id_to_remove);
3391 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3392 buffer_servers.remove(server_id_to_remove);
3393 }
3394 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3395 }
3396 servers_to_remove.into_iter().collect()
3397 }
3398
3399 fn rebuild_watched_paths_inner<'a>(
3400 &'a self,
3401 language_server_id: LanguageServerId,
3402 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3403 cx: &mut Context<LspStore>,
3404 ) -> LanguageServerWatchedPathsBuilder {
3405 let worktrees = self
3406 .worktree_store
3407 .read(cx)
3408 .worktrees()
3409 .filter_map(|worktree| {
3410 self.language_servers_for_worktree(worktree.read(cx).id())
3411 .find(|server| server.server_id() == language_server_id)
3412 .map(|_| worktree)
3413 })
3414 .collect::<Vec<_>>();
3415
3416 let mut worktree_globs = HashMap::default();
3417 let mut abs_globs = HashMap::default();
3418 log::trace!(
3419 "Processing new watcher paths for language server with id {}",
3420 language_server_id
3421 );
3422
3423 for watcher in watchers {
3424 if let Some((worktree, literal_prefix, pattern)) =
3425 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3426 {
3427 worktree.update(cx, |worktree, _| {
3428 if let Some((tree, glob)) =
3429 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3430 {
3431 tree.add_path_prefix_to_scan(literal_prefix);
3432 worktree_globs
3433 .entry(tree.id())
3434 .or_insert_with(GlobSetBuilder::new)
3435 .add(glob);
3436 }
3437 });
3438 } else {
3439 let (path, pattern) = match &watcher.glob_pattern {
3440 lsp::GlobPattern::String(s) => {
3441 let watcher_path = SanitizedPath::new(s);
3442 let path = glob_literal_prefix(watcher_path.as_path());
3443 let pattern = watcher_path
3444 .as_path()
3445 .strip_prefix(&path)
3446 .map(|p| p.to_string_lossy().into_owned())
3447 .unwrap_or_else(|e| {
3448 debug_panic!(
3449 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3450 s,
3451 path.display(),
3452 e
3453 );
3454 watcher_path.as_path().to_string_lossy().into_owned()
3455 });
3456 (path, pattern)
3457 }
3458 lsp::GlobPattern::Relative(rp) => {
3459 let Ok(mut base_uri) = match &rp.base_uri {
3460 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3461 lsp::OneOf::Right(base_uri) => base_uri,
3462 }
3463 .to_file_path() else {
3464 continue;
3465 };
3466
3467 let path = glob_literal_prefix(Path::new(&rp.pattern));
3468 let pattern = Path::new(&rp.pattern)
3469 .strip_prefix(&path)
3470 .map(|p| p.to_string_lossy().into_owned())
3471 .unwrap_or_else(|e| {
3472 debug_panic!(
3473 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3474 rp.pattern,
3475 path.display(),
3476 e
3477 );
3478 rp.pattern.clone()
3479 });
3480 base_uri.push(path);
3481 (base_uri, pattern)
3482 }
3483 };
3484
3485 if let Some(glob) = Glob::new(&pattern).log_err() {
3486 if !path
3487 .components()
3488 .any(|c| matches!(c, path::Component::Normal(_)))
3489 {
3490 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3491 // rather than adding a new watcher for `/`.
3492 for worktree in &worktrees {
3493 worktree_globs
3494 .entry(worktree.read(cx).id())
3495 .or_insert_with(GlobSetBuilder::new)
3496 .add(glob.clone());
3497 }
3498 } else {
3499 abs_globs
3500 .entry(path.into())
3501 .or_insert_with(GlobSetBuilder::new)
3502 .add(glob);
3503 }
3504 }
3505 }
3506 }
3507
3508 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3509 for (worktree_id, builder) in worktree_globs {
3510 if let Ok(globset) = builder.build() {
3511 watch_builder.watch_worktree(worktree_id, globset);
3512 }
3513 }
3514 for (abs_path, builder) in abs_globs {
3515 if let Ok(globset) = builder.build() {
3516 watch_builder.watch_abs_path(abs_path, globset);
3517 }
3518 }
3519 watch_builder
3520 }
3521
3522 fn worktree_and_path_for_file_watcher(
3523 worktrees: &[Entity<Worktree>],
3524 watcher: &FileSystemWatcher,
3525 cx: &App,
3526 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3527 worktrees.iter().find_map(|worktree| {
3528 let tree = worktree.read(cx);
3529 let worktree_root_path = tree.abs_path();
3530 let path_style = tree.path_style();
3531 match &watcher.glob_pattern {
3532 lsp::GlobPattern::String(s) => {
3533 let watcher_path = SanitizedPath::new(s);
3534 let relative = watcher_path
3535 .as_path()
3536 .strip_prefix(&worktree_root_path)
3537 .ok()?;
3538 let literal_prefix = glob_literal_prefix(relative);
3539 Some((
3540 worktree.clone(),
3541 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3542 relative.to_string_lossy().into_owned(),
3543 ))
3544 }
3545 lsp::GlobPattern::Relative(rp) => {
3546 let base_uri = match &rp.base_uri {
3547 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3548 lsp::OneOf::Right(base_uri) => base_uri,
3549 }
3550 .to_file_path()
3551 .ok()?;
3552 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3553 let mut literal_prefix = relative.to_owned();
3554 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3555 Some((
3556 worktree.clone(),
3557 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3558 rp.pattern.clone(),
3559 ))
3560 }
3561 }
3562 })
3563 }
3564
3565 fn rebuild_watched_paths(
3566 &mut self,
3567 language_server_id: LanguageServerId,
3568 cx: &mut Context<LspStore>,
3569 ) {
3570 let Some(registrations) = self
3571 .language_server_dynamic_registrations
3572 .get(&language_server_id)
3573 else {
3574 return;
3575 };
3576
3577 let watch_builder = self.rebuild_watched_paths_inner(
3578 language_server_id,
3579 registrations.did_change_watched_files.values().flatten(),
3580 cx,
3581 );
3582 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3583 self.language_server_watched_paths
3584 .insert(language_server_id, watcher);
3585
3586 cx.notify();
3587 }
3588
3589 fn on_lsp_did_change_watched_files(
3590 &mut self,
3591 language_server_id: LanguageServerId,
3592 registration_id: &str,
3593 params: DidChangeWatchedFilesRegistrationOptions,
3594 cx: &mut Context<LspStore>,
3595 ) {
3596 let registrations = self
3597 .language_server_dynamic_registrations
3598 .entry(language_server_id)
3599 .or_default();
3600
3601 registrations
3602 .did_change_watched_files
3603 .insert(registration_id.to_string(), params.watchers);
3604
3605 self.rebuild_watched_paths(language_server_id, cx);
3606 }
3607
3608 fn on_lsp_unregister_did_change_watched_files(
3609 &mut self,
3610 language_server_id: LanguageServerId,
3611 registration_id: &str,
3612 cx: &mut Context<LspStore>,
3613 ) {
3614 let registrations = self
3615 .language_server_dynamic_registrations
3616 .entry(language_server_id)
3617 .or_default();
3618
3619 if registrations
3620 .did_change_watched_files
3621 .remove(registration_id)
3622 .is_some()
3623 {
3624 log::info!(
3625 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3626 language_server_id,
3627 registration_id
3628 );
3629 } else {
3630 log::warn!(
3631 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3632 language_server_id,
3633 registration_id
3634 );
3635 }
3636
3637 self.rebuild_watched_paths(language_server_id, cx);
3638 }
3639
3640 async fn initialization_options_for_adapter(
3641 adapter: Arc<dyn LspAdapter>,
3642 delegate: &Arc<dyn LspAdapterDelegate>,
3643 ) -> Result<Option<serde_json::Value>> {
3644 let Some(mut initialization_config) =
3645 adapter.clone().initialization_options(delegate).await?
3646 else {
3647 return Ok(None);
3648 };
3649
3650 for other_adapter in delegate.registered_lsp_adapters() {
3651 if other_adapter.name() == adapter.name() {
3652 continue;
3653 }
3654 if let Ok(Some(target_config)) = other_adapter
3655 .clone()
3656 .additional_initialization_options(adapter.name(), delegate)
3657 .await
3658 {
3659 merge_json_value_into(target_config.clone(), &mut initialization_config);
3660 }
3661 }
3662
3663 Ok(Some(initialization_config))
3664 }
3665
3666 async fn workspace_configuration_for_adapter(
3667 adapter: Arc<dyn LspAdapter>,
3668 delegate: &Arc<dyn LspAdapterDelegate>,
3669 toolchain: Option<Toolchain>,
3670 requested_uri: Option<Uri>,
3671 cx: &mut AsyncApp,
3672 ) -> Result<serde_json::Value> {
3673 let mut workspace_config = adapter
3674 .clone()
3675 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3676 .await?;
3677
3678 for other_adapter in delegate.registered_lsp_adapters() {
3679 if other_adapter.name() == adapter.name() {
3680 continue;
3681 }
3682 if let Ok(Some(target_config)) = other_adapter
3683 .clone()
3684 .additional_workspace_configuration(adapter.name(), delegate, cx)
3685 .await
3686 {
3687 merge_json_value_into(target_config.clone(), &mut workspace_config);
3688 }
3689 }
3690
3691 Ok(workspace_config)
3692 }
3693
3694 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3695 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3696 Some(server.clone())
3697 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3698 Some(Arc::clone(server))
3699 } else {
3700 None
3701 }
3702 }
3703}
3704
3705fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3706 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3707 cx.emit(LspStoreEvent::LanguageServerUpdate {
3708 language_server_id: server.server_id(),
3709 name: Some(server.name()),
3710 message: proto::update_language_server::Variant::MetadataUpdated(
3711 proto::ServerMetadataUpdated {
3712 capabilities: Some(capabilities),
3713 binary: Some(proto::LanguageServerBinaryInfo {
3714 path: server.binary().path.to_string_lossy().into_owned(),
3715 arguments: server
3716 .binary()
3717 .arguments
3718 .iter()
3719 .map(|arg| arg.to_string_lossy().into_owned())
3720 .collect(),
3721 }),
3722 configuration: serde_json::to_string(server.configuration()).ok(),
3723 workspace_folders: server
3724 .workspace_folders()
3725 .iter()
3726 .map(|uri| uri.to_string())
3727 .collect(),
3728 },
3729 ),
3730 });
3731 }
3732}
3733
3734#[derive(Debug)]
3735pub struct FormattableBuffer {
3736 handle: Entity<Buffer>,
3737 abs_path: Option<PathBuf>,
3738 env: Option<HashMap<String, String>>,
3739 ranges: Option<Vec<Range<Anchor>>>,
3740}
3741
3742pub struct RemoteLspStore {
3743 upstream_client: Option<AnyProtoClient>,
3744 upstream_project_id: u64,
3745}
3746
3747pub(crate) enum LspStoreMode {
3748 Local(LocalLspStore), // ssh host and collab host
3749 Remote(RemoteLspStore), // collab guest
3750}
3751
3752impl LspStoreMode {
3753 fn is_local(&self) -> bool {
3754 matches!(self, LspStoreMode::Local(_))
3755 }
3756}
3757
3758pub struct LspStore {
3759 mode: LspStoreMode,
3760 last_formatting_failure: Option<String>,
3761 downstream_client: Option<(AnyProtoClient, u64)>,
3762 nonce: u128,
3763 buffer_store: Entity<BufferStore>,
3764 worktree_store: Entity<WorktreeStore>,
3765 pub languages: Arc<LanguageRegistry>,
3766 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3767 active_entry: Option<ProjectEntryId>,
3768 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3769 _maintain_buffer_languages: Task<()>,
3770 diagnostic_summaries:
3771 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3772 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3773 lsp_data: HashMap<BufferId, BufferLspData>,
3774 next_hint_id: Arc<AtomicUsize>,
3775}
3776
3777#[derive(Debug)]
3778pub struct BufferLspData {
3779 buffer_version: Global,
3780 document_colors: Option<DocumentColorData>,
3781 code_lens: Option<CodeLensData>,
3782 inlay_hints: BufferInlayHints,
3783 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3784 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3785}
3786
3787#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3788struct LspKey {
3789 request_type: TypeId,
3790 server_queried: Option<LanguageServerId>,
3791}
3792
3793impl BufferLspData {
3794 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3795 Self {
3796 buffer_version: buffer.read(cx).version(),
3797 document_colors: None,
3798 code_lens: None,
3799 inlay_hints: BufferInlayHints::new(buffer, cx),
3800 lsp_requests: HashMap::default(),
3801 chunk_lsp_requests: HashMap::default(),
3802 }
3803 }
3804
3805 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3806 if let Some(document_colors) = &mut self.document_colors {
3807 document_colors.colors.remove(&for_server);
3808 document_colors.cache_version += 1;
3809 }
3810
3811 if let Some(code_lens) = &mut self.code_lens {
3812 code_lens.lens.remove(&for_server);
3813 }
3814
3815 self.inlay_hints.remove_server_data(for_server);
3816 }
3817
3818 #[cfg(any(test, feature = "test-support"))]
3819 pub fn inlay_hints(&self) -> &BufferInlayHints {
3820 &self.inlay_hints
3821 }
3822}
3823
3824#[derive(Debug, Default, Clone)]
3825pub struct DocumentColors {
3826 pub colors: HashSet<DocumentColor>,
3827 pub cache_version: Option<usize>,
3828}
3829
3830type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3831type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3832
3833#[derive(Debug, Default)]
3834struct DocumentColorData {
3835 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3836 cache_version: usize,
3837 colors_update: Option<(Global, DocumentColorTask)>,
3838}
3839
3840#[derive(Debug, Default)]
3841struct CodeLensData {
3842 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3843 update: Option<(Global, CodeLensTask)>,
3844}
3845
3846#[derive(Debug)]
3847pub enum LspStoreEvent {
3848 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3849 LanguageServerRemoved(LanguageServerId),
3850 LanguageServerUpdate {
3851 language_server_id: LanguageServerId,
3852 name: Option<LanguageServerName>,
3853 message: proto::update_language_server::Variant,
3854 },
3855 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3856 LanguageServerPrompt(LanguageServerPromptRequest),
3857 LanguageDetected {
3858 buffer: Entity<Buffer>,
3859 new_language: Option<Arc<Language>>,
3860 },
3861 Notification(String),
3862 RefreshInlayHints {
3863 server_id: LanguageServerId,
3864 request_id: Option<usize>,
3865 },
3866 RefreshCodeLens,
3867 DiagnosticsUpdated {
3868 server_id: LanguageServerId,
3869 paths: Vec<ProjectPath>,
3870 },
3871 DiskBasedDiagnosticsStarted {
3872 language_server_id: LanguageServerId,
3873 },
3874 DiskBasedDiagnosticsFinished {
3875 language_server_id: LanguageServerId,
3876 },
3877 SnippetEdit {
3878 buffer_id: BufferId,
3879 edits: Vec<(lsp::Range, Snippet)>,
3880 most_recent_edit: clock::Lamport,
3881 },
3882 WorkspaceEditApplied(ProjectTransaction),
3883}
3884
3885#[derive(Clone, Debug, Serialize)]
3886pub struct LanguageServerStatus {
3887 pub name: LanguageServerName,
3888 pub server_version: Option<SharedString>,
3889 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3890 pub has_pending_diagnostic_updates: bool,
3891 pub progress_tokens: HashSet<ProgressToken>,
3892 pub worktree: Option<WorktreeId>,
3893 pub binary: Option<LanguageServerBinary>,
3894 pub configuration: Option<Value>,
3895 pub workspace_folders: BTreeSet<Uri>,
3896}
3897
3898#[derive(Clone, Debug)]
3899struct CoreSymbol {
3900 pub language_server_name: LanguageServerName,
3901 pub source_worktree_id: WorktreeId,
3902 pub source_language_server_id: LanguageServerId,
3903 pub path: SymbolLocation,
3904 pub name: String,
3905 pub kind: lsp::SymbolKind,
3906 pub range: Range<Unclipped<PointUtf16>>,
3907}
3908
3909#[derive(Clone, Debug, PartialEq, Eq)]
3910pub enum SymbolLocation {
3911 InProject(ProjectPath),
3912 OutsideProject {
3913 abs_path: Arc<Path>,
3914 signature: [u8; 32],
3915 },
3916}
3917
3918impl SymbolLocation {
3919 fn file_name(&self) -> Option<&str> {
3920 match self {
3921 Self::InProject(path) => path.path.file_name(),
3922 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3923 }
3924 }
3925}
3926
3927impl LspStore {
3928 pub fn init(client: &AnyProtoClient) {
3929 client.add_entity_request_handler(Self::handle_lsp_query);
3930 client.add_entity_message_handler(Self::handle_lsp_query_response);
3931 client.add_entity_request_handler(Self::handle_restart_language_servers);
3932 client.add_entity_request_handler(Self::handle_stop_language_servers);
3933 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3934 client.add_entity_message_handler(Self::handle_start_language_server);
3935 client.add_entity_message_handler(Self::handle_update_language_server);
3936 client.add_entity_message_handler(Self::handle_language_server_log);
3937 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3938 client.add_entity_request_handler(Self::handle_format_buffers);
3939 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3940 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3941 client.add_entity_request_handler(Self::handle_apply_code_action);
3942 client.add_entity_request_handler(Self::handle_get_project_symbols);
3943 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3944 client.add_entity_request_handler(Self::handle_get_color_presentation);
3945 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3946 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3947 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3948 client.add_entity_request_handler(Self::handle_on_type_formatting);
3949 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3950 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3951 client.add_entity_request_handler(Self::handle_rename_project_entry);
3952 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3953 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3954 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3955 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3956 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3957 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3958 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3959
3960 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3961 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3962 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3963 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3964 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3965 client.add_entity_request_handler(
3966 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3967 );
3968 client.add_entity_request_handler(
3969 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3970 );
3971 client.add_entity_request_handler(
3972 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3973 );
3974 }
3975
3976 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3977 match &self.mode {
3978 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3979 _ => None,
3980 }
3981 }
3982
3983 pub fn as_local(&self) -> Option<&LocalLspStore> {
3984 match &self.mode {
3985 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3986 _ => None,
3987 }
3988 }
3989
3990 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3991 match &mut self.mode {
3992 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3993 _ => None,
3994 }
3995 }
3996
3997 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3998 match &self.mode {
3999 LspStoreMode::Remote(RemoteLspStore {
4000 upstream_client: Some(upstream_client),
4001 upstream_project_id,
4002 ..
4003 }) => Some((upstream_client.clone(), *upstream_project_id)),
4004
4005 LspStoreMode::Remote(RemoteLspStore {
4006 upstream_client: None,
4007 ..
4008 }) => None,
4009 LspStoreMode::Local(_) => None,
4010 }
4011 }
4012
4013 pub fn new_local(
4014 buffer_store: Entity<BufferStore>,
4015 worktree_store: Entity<WorktreeStore>,
4016 prettier_store: Entity<PrettierStore>,
4017 toolchain_store: Entity<LocalToolchainStore>,
4018 environment: Entity<ProjectEnvironment>,
4019 manifest_tree: Entity<ManifestTree>,
4020 languages: Arc<LanguageRegistry>,
4021 http_client: Arc<dyn HttpClient>,
4022 fs: Arc<dyn Fs>,
4023 cx: &mut Context<Self>,
4024 ) -> Self {
4025 let yarn = YarnPathStore::new(fs.clone(), cx);
4026 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4027 .detach();
4028 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4029 .detach();
4030 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4031 .detach();
4032 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4033 .detach();
4034 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4035 .detach();
4036 subscribe_to_binary_statuses(&languages, cx).detach();
4037
4038 let _maintain_workspace_config = {
4039 let (sender, receiver) = watch::channel();
4040 (Self::maintain_workspace_config(receiver, cx), sender)
4041 };
4042
4043 Self {
4044 mode: LspStoreMode::Local(LocalLspStore {
4045 weak: cx.weak_entity(),
4046 worktree_store: worktree_store.clone(),
4047
4048 supplementary_language_servers: Default::default(),
4049 languages: languages.clone(),
4050 language_server_ids: Default::default(),
4051 language_servers: Default::default(),
4052 last_workspace_edits_by_language_server: Default::default(),
4053 language_server_watched_paths: Default::default(),
4054 language_server_paths_watched_for_rename: Default::default(),
4055 language_server_dynamic_registrations: Default::default(),
4056 buffers_being_formatted: Default::default(),
4057 buffer_snapshots: Default::default(),
4058 prettier_store,
4059 environment,
4060 http_client,
4061 fs,
4062 yarn,
4063 next_diagnostic_group_id: Default::default(),
4064 diagnostics: Default::default(),
4065 _subscription: cx.on_app_quit(|this, cx| {
4066 this.as_local_mut()
4067 .unwrap()
4068 .shutdown_language_servers_on_quit(cx)
4069 }),
4070 lsp_tree: LanguageServerTree::new(
4071 manifest_tree,
4072 languages.clone(),
4073 toolchain_store.clone(),
4074 ),
4075 toolchain_store,
4076 registered_buffers: HashMap::default(),
4077 buffers_opened_in_servers: HashMap::default(),
4078 buffer_pull_diagnostics_result_ids: HashMap::default(),
4079 workspace_pull_diagnostics_result_ids: HashMap::default(),
4080 restricted_worktrees_tasks: HashMap::default(),
4081 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4082 .manifest_file_names(),
4083 }),
4084 last_formatting_failure: None,
4085 downstream_client: None,
4086 buffer_store,
4087 worktree_store,
4088 languages: languages.clone(),
4089 language_server_statuses: Default::default(),
4090 nonce: StdRng::from_os_rng().random(),
4091 diagnostic_summaries: HashMap::default(),
4092 lsp_server_capabilities: HashMap::default(),
4093 lsp_data: HashMap::default(),
4094 next_hint_id: Arc::default(),
4095 active_entry: None,
4096 _maintain_workspace_config,
4097 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4098 }
4099 }
4100
4101 fn send_lsp_proto_request<R: LspCommand>(
4102 &self,
4103 buffer: Entity<Buffer>,
4104 client: AnyProtoClient,
4105 upstream_project_id: u64,
4106 request: R,
4107 cx: &mut Context<LspStore>,
4108 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4109 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4110 return Task::ready(Ok(R::Response::default()));
4111 }
4112 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4113 cx.spawn(async move |this, cx| {
4114 let response = client.request(message).await?;
4115 let this = this.upgrade().context("project dropped")?;
4116 request
4117 .response_from_proto(response, this, buffer, cx.clone())
4118 .await
4119 })
4120 }
4121
4122 pub(super) fn new_remote(
4123 buffer_store: Entity<BufferStore>,
4124 worktree_store: Entity<WorktreeStore>,
4125 languages: Arc<LanguageRegistry>,
4126 upstream_client: AnyProtoClient,
4127 project_id: u64,
4128 cx: &mut Context<Self>,
4129 ) -> Self {
4130 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4131 .detach();
4132 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4133 .detach();
4134 subscribe_to_binary_statuses(&languages, cx).detach();
4135 let _maintain_workspace_config = {
4136 let (sender, receiver) = watch::channel();
4137 (Self::maintain_workspace_config(receiver, cx), sender)
4138 };
4139 Self {
4140 mode: LspStoreMode::Remote(RemoteLspStore {
4141 upstream_client: Some(upstream_client),
4142 upstream_project_id: project_id,
4143 }),
4144 downstream_client: None,
4145 last_formatting_failure: None,
4146 buffer_store,
4147 worktree_store,
4148 languages: languages.clone(),
4149 language_server_statuses: Default::default(),
4150 nonce: StdRng::from_os_rng().random(),
4151 diagnostic_summaries: HashMap::default(),
4152 lsp_server_capabilities: HashMap::default(),
4153 next_hint_id: Arc::default(),
4154 lsp_data: HashMap::default(),
4155 active_entry: None,
4156
4157 _maintain_workspace_config,
4158 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4159 }
4160 }
4161
4162 fn on_buffer_store_event(
4163 &mut self,
4164 _: Entity<BufferStore>,
4165 event: &BufferStoreEvent,
4166 cx: &mut Context<Self>,
4167 ) {
4168 match event {
4169 BufferStoreEvent::BufferAdded(buffer) => {
4170 self.on_buffer_added(buffer, cx).log_err();
4171 }
4172 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4173 let buffer_id = buffer.read(cx).remote_id();
4174 if let Some(local) = self.as_local_mut()
4175 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4176 {
4177 local.reset_buffer(buffer, old_file, cx);
4178
4179 if local.registered_buffers.contains_key(&buffer_id) {
4180 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4181 }
4182 }
4183
4184 self.detect_language_for_buffer(buffer, cx);
4185 if let Some(local) = self.as_local_mut() {
4186 local.initialize_buffer(buffer, cx);
4187 if local.registered_buffers.contains_key(&buffer_id) {
4188 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4189 }
4190 }
4191 }
4192 _ => {}
4193 }
4194 }
4195
4196 fn on_worktree_store_event(
4197 &mut self,
4198 _: Entity<WorktreeStore>,
4199 event: &WorktreeStoreEvent,
4200 cx: &mut Context<Self>,
4201 ) {
4202 match event {
4203 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4204 if !worktree.read(cx).is_local() {
4205 return;
4206 }
4207 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4208 worktree::Event::UpdatedEntries(changes) => {
4209 this.update_local_worktree_language_servers(&worktree, changes, cx);
4210 }
4211 worktree::Event::UpdatedGitRepositories(_)
4212 | worktree::Event::DeletedEntry(_) => {}
4213 })
4214 .detach()
4215 }
4216 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4217 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4218 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4219 }
4220 WorktreeStoreEvent::WorktreeReleased(..)
4221 | WorktreeStoreEvent::WorktreeOrderChanged
4222 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4223 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4224 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4225 }
4226 }
4227
4228 fn on_prettier_store_event(
4229 &mut self,
4230 _: Entity<PrettierStore>,
4231 event: &PrettierStoreEvent,
4232 cx: &mut Context<Self>,
4233 ) {
4234 match event {
4235 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4236 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4237 }
4238 PrettierStoreEvent::LanguageServerAdded {
4239 new_server_id,
4240 name,
4241 prettier_server,
4242 } => {
4243 self.register_supplementary_language_server(
4244 *new_server_id,
4245 name.clone(),
4246 prettier_server.clone(),
4247 cx,
4248 );
4249 }
4250 }
4251 }
4252
4253 fn on_toolchain_store_event(
4254 &mut self,
4255 _: Entity<LocalToolchainStore>,
4256 event: &ToolchainStoreEvent,
4257 _: &mut Context<Self>,
4258 ) {
4259 if let ToolchainStoreEvent::ToolchainActivated = event {
4260 self.request_workspace_config_refresh()
4261 }
4262 }
4263
4264 fn request_workspace_config_refresh(&mut self) {
4265 *self._maintain_workspace_config.1.borrow_mut() = ();
4266 }
4267
4268 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4269 self.as_local().map(|local| local.prettier_store.clone())
4270 }
4271
4272 fn on_buffer_event(
4273 &mut self,
4274 buffer: Entity<Buffer>,
4275 event: &language::BufferEvent,
4276 cx: &mut Context<Self>,
4277 ) {
4278 match event {
4279 language::BufferEvent::Edited => {
4280 self.on_buffer_edited(buffer, cx);
4281 }
4282
4283 language::BufferEvent::Saved => {
4284 self.on_buffer_saved(buffer, cx);
4285 }
4286
4287 _ => {}
4288 }
4289 }
4290
4291 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4292 buffer
4293 .read(cx)
4294 .set_language_registry(self.languages.clone());
4295
4296 cx.subscribe(buffer, |this, buffer, event, cx| {
4297 this.on_buffer_event(buffer, event, cx);
4298 })
4299 .detach();
4300
4301 self.detect_language_for_buffer(buffer, cx);
4302 if let Some(local) = self.as_local_mut() {
4303 local.initialize_buffer(buffer, cx);
4304 }
4305
4306 Ok(())
4307 }
4308
4309 pub(crate) fn register_buffer_with_language_servers(
4310 &mut self,
4311 buffer: &Entity<Buffer>,
4312 only_register_servers: HashSet<LanguageServerSelector>,
4313 ignore_refcounts: bool,
4314 cx: &mut Context<Self>,
4315 ) -> OpenLspBufferHandle {
4316 let buffer_id = buffer.read(cx).remote_id();
4317 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4318 if let Some(local) = self.as_local_mut() {
4319 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4320 if !ignore_refcounts {
4321 *refcount += 1;
4322 }
4323
4324 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4325 // 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
4326 // 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
4327 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4328 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4329 return handle;
4330 };
4331 if !file.is_local() {
4332 return handle;
4333 }
4334
4335 if ignore_refcounts || *refcount == 1 {
4336 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4337 }
4338 if !ignore_refcounts {
4339 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4340 let refcount = {
4341 let local = lsp_store.as_local_mut().unwrap();
4342 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4343 debug_panic!("bad refcounting");
4344 return;
4345 };
4346
4347 *refcount -= 1;
4348 *refcount
4349 };
4350 if refcount == 0 {
4351 lsp_store.lsp_data.remove(&buffer_id);
4352 let local = lsp_store.as_local_mut().unwrap();
4353 local.registered_buffers.remove(&buffer_id);
4354
4355 local.buffers_opened_in_servers.remove(&buffer_id);
4356 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4357 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4358
4359 let buffer_abs_path = file.abs_path(cx);
4360 for (_, buffer_pull_diagnostics_result_ids) in
4361 &mut local.buffer_pull_diagnostics_result_ids
4362 {
4363 buffer_pull_diagnostics_result_ids.retain(
4364 |_, buffer_result_ids| {
4365 buffer_result_ids.remove(&buffer_abs_path);
4366 !buffer_result_ids.is_empty()
4367 },
4368 );
4369 }
4370
4371 let diagnostic_updates = local
4372 .language_servers
4373 .keys()
4374 .cloned()
4375 .map(|server_id| DocumentDiagnosticsUpdate {
4376 diagnostics: DocumentDiagnostics {
4377 document_abs_path: buffer_abs_path.clone(),
4378 version: None,
4379 diagnostics: Vec::new(),
4380 },
4381 result_id: None,
4382 registration_id: None,
4383 server_id: server_id,
4384 disk_based_sources: Cow::Borrowed(&[]),
4385 })
4386 .collect::<Vec<_>>();
4387
4388 lsp_store
4389 .merge_diagnostic_entries(
4390 diagnostic_updates,
4391 |_, diagnostic, _| {
4392 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4393 },
4394 cx,
4395 )
4396 .context("Clearing diagnostics for the closed buffer")
4397 .log_err();
4398 }
4399 }
4400 })
4401 .detach();
4402 }
4403 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4404 let buffer_id = buffer.read(cx).remote_id().to_proto();
4405 cx.background_spawn(async move {
4406 upstream_client
4407 .request(proto::RegisterBufferWithLanguageServers {
4408 project_id: upstream_project_id,
4409 buffer_id,
4410 only_servers: only_register_servers
4411 .into_iter()
4412 .map(|selector| {
4413 let selector = match selector {
4414 LanguageServerSelector::Id(language_server_id) => {
4415 proto::language_server_selector::Selector::ServerId(
4416 language_server_id.to_proto(),
4417 )
4418 }
4419 LanguageServerSelector::Name(language_server_name) => {
4420 proto::language_server_selector::Selector::Name(
4421 language_server_name.to_string(),
4422 )
4423 }
4424 };
4425 proto::LanguageServerSelector {
4426 selector: Some(selector),
4427 }
4428 })
4429 .collect(),
4430 })
4431 .await
4432 })
4433 .detach();
4434 } else {
4435 // Our remote connection got closed
4436 }
4437 handle
4438 }
4439
4440 fn maintain_buffer_languages(
4441 languages: Arc<LanguageRegistry>,
4442 cx: &mut Context<Self>,
4443 ) -> Task<()> {
4444 let mut subscription = languages.subscribe();
4445 let mut prev_reload_count = languages.reload_count();
4446 cx.spawn(async move |this, cx| {
4447 while let Some(()) = subscription.next().await {
4448 if let Some(this) = this.upgrade() {
4449 // If the language registry has been reloaded, then remove and
4450 // re-assign the languages on all open buffers.
4451 let reload_count = languages.reload_count();
4452 if reload_count > prev_reload_count {
4453 prev_reload_count = reload_count;
4454 this.update(cx, |this, cx| {
4455 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4456 for buffer in buffer_store.buffers() {
4457 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4458 {
4459 buffer.update(cx, |buffer, cx| {
4460 buffer.set_language_async(None, cx)
4461 });
4462 if let Some(local) = this.as_local_mut() {
4463 local.reset_buffer(&buffer, &f, cx);
4464
4465 if local
4466 .registered_buffers
4467 .contains_key(&buffer.read(cx).remote_id())
4468 && let Some(file_url) =
4469 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4470 {
4471 local.unregister_buffer_from_language_servers(
4472 &buffer, &file_url, cx,
4473 );
4474 }
4475 }
4476 }
4477 }
4478 });
4479 });
4480 }
4481
4482 this.update(cx, |this, cx| {
4483 let mut plain_text_buffers = Vec::new();
4484 let mut buffers_with_unknown_injections = Vec::new();
4485 for handle in this.buffer_store.read(cx).buffers() {
4486 let buffer = handle.read(cx);
4487 if buffer.language().is_none()
4488 || buffer.language() == Some(&*language::PLAIN_TEXT)
4489 {
4490 plain_text_buffers.push(handle);
4491 } else if buffer.contains_unknown_injections() {
4492 buffers_with_unknown_injections.push(handle);
4493 }
4494 }
4495
4496 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4497 // and reused later in the invisible worktrees.
4498 plain_text_buffers.sort_by_key(|buffer| {
4499 Reverse(
4500 File::from_dyn(buffer.read(cx).file())
4501 .map(|file| file.worktree.read(cx).is_visible()),
4502 )
4503 });
4504
4505 for buffer in plain_text_buffers {
4506 this.detect_language_for_buffer(&buffer, cx);
4507 if let Some(local) = this.as_local_mut() {
4508 local.initialize_buffer(&buffer, cx);
4509 if local
4510 .registered_buffers
4511 .contains_key(&buffer.read(cx).remote_id())
4512 {
4513 local.register_buffer_with_language_servers(
4514 &buffer,
4515 HashSet::default(),
4516 cx,
4517 );
4518 }
4519 }
4520 }
4521
4522 for buffer in buffers_with_unknown_injections {
4523 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4524 }
4525 });
4526 }
4527 }
4528 })
4529 }
4530
4531 fn detect_language_for_buffer(
4532 &mut self,
4533 buffer_handle: &Entity<Buffer>,
4534 cx: &mut Context<Self>,
4535 ) -> Option<language::AvailableLanguage> {
4536 // If the buffer has a language, set it and start the language server if we haven't already.
4537 let buffer = buffer_handle.read(cx);
4538 let file = buffer.file()?;
4539
4540 let content = buffer.as_rope();
4541 let available_language = self.languages.language_for_file(file, Some(content), cx);
4542 if let Some(available_language) = &available_language {
4543 if let Some(Ok(Ok(new_language))) = self
4544 .languages
4545 .load_language(available_language)
4546 .now_or_never()
4547 {
4548 self.set_language_for_buffer(buffer_handle, new_language, cx);
4549 }
4550 } else {
4551 cx.emit(LspStoreEvent::LanguageDetected {
4552 buffer: buffer_handle.clone(),
4553 new_language: None,
4554 });
4555 }
4556
4557 available_language
4558 }
4559
4560 pub(crate) fn set_language_for_buffer(
4561 &mut self,
4562 buffer_entity: &Entity<Buffer>,
4563 new_language: Arc<Language>,
4564 cx: &mut Context<Self>,
4565 ) {
4566 let buffer = buffer_entity.read(cx);
4567 let buffer_file = buffer.file().cloned();
4568 let buffer_id = buffer.remote_id();
4569 if let Some(local_store) = self.as_local_mut()
4570 && local_store.registered_buffers.contains_key(&buffer_id)
4571 && let Some(abs_path) =
4572 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4573 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4574 {
4575 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4576 }
4577 buffer_entity.update(cx, |buffer, cx| {
4578 if buffer
4579 .language()
4580 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4581 {
4582 buffer.set_language_async(Some(new_language.clone()), cx);
4583 }
4584 });
4585
4586 let settings =
4587 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4588 let buffer_file = File::from_dyn(buffer_file.as_ref());
4589
4590 let worktree_id = if let Some(file) = buffer_file {
4591 let worktree = file.worktree.clone();
4592
4593 if let Some(local) = self.as_local_mut()
4594 && local.registered_buffers.contains_key(&buffer_id)
4595 {
4596 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4597 }
4598 Some(worktree.read(cx).id())
4599 } else {
4600 None
4601 };
4602
4603 if settings.prettier.allowed
4604 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4605 {
4606 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4607 if let Some(prettier_store) = prettier_store {
4608 prettier_store.update(cx, |prettier_store, cx| {
4609 prettier_store.install_default_prettier(
4610 worktree_id,
4611 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4612 cx,
4613 )
4614 })
4615 }
4616 }
4617
4618 cx.emit(LspStoreEvent::LanguageDetected {
4619 buffer: buffer_entity.clone(),
4620 new_language: Some(new_language),
4621 })
4622 }
4623
4624 pub fn buffer_store(&self) -> Entity<BufferStore> {
4625 self.buffer_store.clone()
4626 }
4627
4628 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4629 self.active_entry = active_entry;
4630 }
4631
4632 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4633 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4634 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4635 {
4636 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4637 summaries
4638 .iter()
4639 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4640 });
4641 if let Some(summary) = summaries.next() {
4642 client
4643 .send(proto::UpdateDiagnosticSummary {
4644 project_id: downstream_project_id,
4645 worktree_id: worktree.id().to_proto(),
4646 summary: Some(summary),
4647 more_summaries: summaries.collect(),
4648 })
4649 .log_err();
4650 }
4651 }
4652 }
4653
4654 fn is_capable_for_proto_request<R>(
4655 &self,
4656 buffer: &Entity<Buffer>,
4657 request: &R,
4658 cx: &App,
4659 ) -> bool
4660 where
4661 R: LspCommand,
4662 {
4663 self.check_if_capable_for_proto_request(
4664 buffer,
4665 |capabilities| {
4666 request.check_capabilities(AdapterServerCapabilities {
4667 server_capabilities: capabilities.clone(),
4668 code_action_kinds: None,
4669 })
4670 },
4671 cx,
4672 )
4673 }
4674
4675 fn check_if_capable_for_proto_request<F>(
4676 &self,
4677 buffer: &Entity<Buffer>,
4678 check: F,
4679 cx: &App,
4680 ) -> bool
4681 where
4682 F: FnMut(&lsp::ServerCapabilities) -> bool,
4683 {
4684 let Some(language) = buffer.read(cx).language().cloned() else {
4685 return false;
4686 };
4687 let registered_language_servers = self
4688 .languages
4689 .lsp_adapters(&language.name())
4690 .into_iter()
4691 .map(|lsp_adapter| lsp_adapter.name())
4692 .collect::<HashSet<_>>();
4693 self.language_server_statuses
4694 .iter()
4695 .filter_map(|(server_id, server_status)| {
4696 // Include servers that are either registered for this language OR
4697 // available to be loaded (for SSH remote mode where adapters like
4698 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4699 // but only loaded on the server side)
4700 let is_relevant = registered_language_servers.contains(&server_status.name)
4701 || self.languages.is_lsp_adapter_available(&server_status.name);
4702 is_relevant.then_some(server_id)
4703 })
4704 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4705 .any(check)
4706 }
4707
4708 fn all_capable_for_proto_request<F>(
4709 &self,
4710 buffer: &Entity<Buffer>,
4711 mut check: F,
4712 cx: &App,
4713 ) -> Vec<lsp::LanguageServerId>
4714 where
4715 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4716 {
4717 let Some(language) = buffer.read(cx).language().cloned() else {
4718 return Vec::default();
4719 };
4720 let registered_language_servers = self
4721 .languages
4722 .lsp_adapters(&language.name())
4723 .into_iter()
4724 .map(|lsp_adapter| lsp_adapter.name())
4725 .collect::<HashSet<_>>();
4726 self.language_server_statuses
4727 .iter()
4728 .filter_map(|(server_id, server_status)| {
4729 // Include servers that are either registered for this language OR
4730 // available to be loaded (for SSH remote mode where adapters like
4731 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4732 // but only loaded on the server side)
4733 let is_relevant = registered_language_servers.contains(&server_status.name)
4734 || self.languages.is_lsp_adapter_available(&server_status.name);
4735 is_relevant.then_some((server_id, &server_status.name))
4736 })
4737 .filter_map(|(server_id, server_name)| {
4738 self.lsp_server_capabilities
4739 .get(server_id)
4740 .map(|c| (server_id, server_name, c))
4741 })
4742 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4743 .map(|(server_id, _, _)| *server_id)
4744 .collect()
4745 }
4746
4747 pub fn request_lsp<R>(
4748 &mut self,
4749 buffer: Entity<Buffer>,
4750 server: LanguageServerToQuery,
4751 request: R,
4752 cx: &mut Context<Self>,
4753 ) -> Task<Result<R::Response>>
4754 where
4755 R: LspCommand,
4756 <R::LspRequest as lsp::request::Request>::Result: Send,
4757 <R::LspRequest as lsp::request::Request>::Params: Send,
4758 {
4759 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4760 return self.send_lsp_proto_request(
4761 buffer,
4762 upstream_client,
4763 upstream_project_id,
4764 request,
4765 cx,
4766 );
4767 }
4768
4769 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4770 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4771 local
4772 .language_servers_for_buffer(buffer, cx)
4773 .find(|(_, server)| {
4774 request.check_capabilities(server.adapter_server_capabilities())
4775 })
4776 .map(|(_, server)| server.clone())
4777 }),
4778 LanguageServerToQuery::Other(id) => self
4779 .language_server_for_local_buffer(buffer, id, cx)
4780 .and_then(|(_, server)| {
4781 request
4782 .check_capabilities(server.adapter_server_capabilities())
4783 .then(|| Arc::clone(server))
4784 }),
4785 }) else {
4786 return Task::ready(Ok(Default::default()));
4787 };
4788
4789 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4790
4791 let Some(file) = file else {
4792 return Task::ready(Ok(Default::default()));
4793 };
4794
4795 let lsp_params = match request.to_lsp_params_or_response(
4796 &file.abs_path(cx),
4797 buffer.read(cx),
4798 &language_server,
4799 cx,
4800 ) {
4801 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4802 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4803 Err(err) => {
4804 let message = format!(
4805 "{} via {} failed: {}",
4806 request.display_name(),
4807 language_server.name(),
4808 err
4809 );
4810 // rust-analyzer likes to error with this when its still loading up
4811 if !message.ends_with("content modified") {
4812 log::warn!("{message}");
4813 }
4814 return Task::ready(Err(anyhow!(message)));
4815 }
4816 };
4817
4818 let status = request.status();
4819 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4820 return Task::ready(Ok(Default::default()));
4821 }
4822 cx.spawn(async move |this, cx| {
4823 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4824
4825 let id = lsp_request.id();
4826 let _cleanup = if status.is_some() {
4827 cx.update(|cx| {
4828 this.update(cx, |this, cx| {
4829 this.on_lsp_work_start(
4830 language_server.server_id(),
4831 ProgressToken::Number(id),
4832 LanguageServerProgress {
4833 is_disk_based_diagnostics_progress: false,
4834 is_cancellable: false,
4835 title: None,
4836 message: status.clone(),
4837 percentage: None,
4838 last_update_at: cx.background_executor().now(),
4839 },
4840 cx,
4841 );
4842 })
4843 })
4844 .log_err();
4845
4846 Some(defer(|| {
4847 cx.update(|cx| {
4848 this.update(cx, |this, cx| {
4849 this.on_lsp_work_end(
4850 language_server.server_id(),
4851 ProgressToken::Number(id),
4852 cx,
4853 );
4854 })
4855 })
4856 .log_err();
4857 }))
4858 } else {
4859 None
4860 };
4861
4862 let result = lsp_request.await.into_response();
4863
4864 let response = result.map_err(|err| {
4865 let message = format!(
4866 "{} via {} failed: {}",
4867 request.display_name(),
4868 language_server.name(),
4869 err
4870 );
4871 // rust-analyzer likes to error with this when its still loading up
4872 if !message.ends_with("content modified") {
4873 log::warn!("{message}");
4874 }
4875 anyhow::anyhow!(message)
4876 })?;
4877
4878 request
4879 .response_from_lsp(
4880 response,
4881 this.upgrade().context("no app context")?,
4882 buffer,
4883 language_server.server_id(),
4884 cx.clone(),
4885 )
4886 .await
4887 })
4888 }
4889
4890 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4891 let mut language_formatters_to_check = Vec::new();
4892 for buffer in self.buffer_store.read(cx).buffers() {
4893 let buffer = buffer.read(cx);
4894 let buffer_file = File::from_dyn(buffer.file());
4895 let buffer_language = buffer.language();
4896 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4897 if buffer_language.is_some() {
4898 language_formatters_to_check.push((
4899 buffer_file.map(|f| f.worktree_id(cx)),
4900 settings.into_owned(),
4901 ));
4902 }
4903 }
4904
4905 self.request_workspace_config_refresh();
4906
4907 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4908 prettier_store.update(cx, |prettier_store, cx| {
4909 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4910 })
4911 }
4912
4913 cx.notify();
4914 }
4915
4916 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4917 let buffer_store = self.buffer_store.clone();
4918 let Some(local) = self.as_local_mut() else {
4919 return;
4920 };
4921 let mut adapters = BTreeMap::default();
4922 let get_adapter = {
4923 let languages = local.languages.clone();
4924 let environment = local.environment.clone();
4925 let weak = local.weak.clone();
4926 let worktree_store = local.worktree_store.clone();
4927 let http_client = local.http_client.clone();
4928 let fs = local.fs.clone();
4929 move |worktree_id, cx: &mut App| {
4930 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4931 Some(LocalLspAdapterDelegate::new(
4932 languages.clone(),
4933 &environment,
4934 weak.clone(),
4935 &worktree,
4936 http_client.clone(),
4937 fs.clone(),
4938 cx,
4939 ))
4940 }
4941 };
4942
4943 let mut messages_to_report = Vec::new();
4944 let (new_tree, to_stop) = {
4945 let mut rebase = local.lsp_tree.rebase();
4946 let buffers = buffer_store
4947 .read(cx)
4948 .buffers()
4949 .filter_map(|buffer| {
4950 let raw_buffer = buffer.read(cx);
4951 if !local
4952 .registered_buffers
4953 .contains_key(&raw_buffer.remote_id())
4954 {
4955 return None;
4956 }
4957 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4958 let language = raw_buffer.language().cloned()?;
4959 Some((file, language, raw_buffer.remote_id()))
4960 })
4961 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4962 for (file, language, buffer_id) in buffers {
4963 let worktree_id = file.worktree_id(cx);
4964 let Some(worktree) = local
4965 .worktree_store
4966 .read(cx)
4967 .worktree_for_id(worktree_id, cx)
4968 else {
4969 continue;
4970 };
4971
4972 if let Some((_, apply)) = local.reuse_existing_language_server(
4973 rebase.server_tree(),
4974 &worktree,
4975 &language.name(),
4976 cx,
4977 ) {
4978 (apply)(rebase.server_tree());
4979 } else if let Some(lsp_delegate) = adapters
4980 .entry(worktree_id)
4981 .or_insert_with(|| get_adapter(worktree_id, cx))
4982 .clone()
4983 {
4984 let delegate =
4985 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4986 let path = file
4987 .path()
4988 .parent()
4989 .map(Arc::from)
4990 .unwrap_or_else(|| file.path().clone());
4991 let worktree_path = ProjectPath { worktree_id, path };
4992 let abs_path = file.abs_path(cx);
4993 let nodes = rebase
4994 .walk(
4995 worktree_path,
4996 language.name(),
4997 language.manifest(),
4998 delegate.clone(),
4999 cx,
5000 )
5001 .collect::<Vec<_>>();
5002 for node in nodes {
5003 let server_id = node.server_id_or_init(|disposition| {
5004 let path = &disposition.path;
5005 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5006 let key = LanguageServerSeed {
5007 worktree_id,
5008 name: disposition.server_name.clone(),
5009 settings: disposition.settings.clone(),
5010 toolchain: local.toolchain_store.read(cx).active_toolchain(
5011 path.worktree_id,
5012 &path.path,
5013 language.name(),
5014 ),
5015 };
5016 local.language_server_ids.remove(&key);
5017
5018 let server_id = local.get_or_insert_language_server(
5019 &worktree,
5020 lsp_delegate.clone(),
5021 disposition,
5022 &language.name(),
5023 cx,
5024 );
5025 if let Some(state) = local.language_servers.get(&server_id)
5026 && let Ok(uri) = uri
5027 {
5028 state.add_workspace_folder(uri);
5029 };
5030 server_id
5031 });
5032
5033 if let Some(language_server_id) = server_id {
5034 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5035 language_server_id,
5036 name: node.name(),
5037 message:
5038 proto::update_language_server::Variant::RegisteredForBuffer(
5039 proto::RegisteredForBuffer {
5040 buffer_abs_path: abs_path
5041 .to_string_lossy()
5042 .into_owned(),
5043 buffer_id: buffer_id.to_proto(),
5044 },
5045 ),
5046 });
5047 }
5048 }
5049 } else {
5050 continue;
5051 }
5052 }
5053 rebase.finish()
5054 };
5055 for message in messages_to_report {
5056 cx.emit(message);
5057 }
5058 local.lsp_tree = new_tree;
5059 for (id, _) in to_stop {
5060 self.stop_local_language_server(id, cx).detach();
5061 }
5062 }
5063
5064 pub fn apply_code_action(
5065 &self,
5066 buffer_handle: Entity<Buffer>,
5067 mut action: CodeAction,
5068 push_to_history: bool,
5069 cx: &mut Context<Self>,
5070 ) -> Task<Result<ProjectTransaction>> {
5071 if let Some((upstream_client, project_id)) = self.upstream_client() {
5072 let request = proto::ApplyCodeAction {
5073 project_id,
5074 buffer_id: buffer_handle.read(cx).remote_id().into(),
5075 action: Some(Self::serialize_code_action(&action)),
5076 };
5077 let buffer_store = self.buffer_store();
5078 cx.spawn(async move |_, cx| {
5079 let response = upstream_client
5080 .request(request)
5081 .await?
5082 .transaction
5083 .context("missing transaction")?;
5084
5085 buffer_store
5086 .update(cx, |buffer_store, cx| {
5087 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5088 })
5089 .await
5090 })
5091 } else if self.mode.is_local() {
5092 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5093 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5094 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5095 }) else {
5096 return Task::ready(Ok(ProjectTransaction::default()));
5097 };
5098 cx.spawn(async move |this, cx| {
5099 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5100 .await
5101 .context("resolving a code action")?;
5102 if let Some(edit) = action.lsp_action.edit()
5103 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5104 return LocalLspStore::deserialize_workspace_edit(
5105 this.upgrade().context("no app present")?,
5106 edit.clone(),
5107 push_to_history,
5108
5109 lang_server.clone(),
5110 cx,
5111 )
5112 .await;
5113 }
5114
5115 if let Some(command) = action.lsp_action.command() {
5116 let server_capabilities = lang_server.capabilities();
5117 let available_commands = server_capabilities
5118 .execute_command_provider
5119 .as_ref()
5120 .map(|options| options.commands.as_slice())
5121 .unwrap_or_default();
5122 if available_commands.contains(&command.command) {
5123 this.update(cx, |this, _| {
5124 this.as_local_mut()
5125 .unwrap()
5126 .last_workspace_edits_by_language_server
5127 .remove(&lang_server.server_id());
5128 })?;
5129
5130 let _result = lang_server
5131 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5132 command: command.command.clone(),
5133 arguments: command.arguments.clone().unwrap_or_default(),
5134 ..lsp::ExecuteCommandParams::default()
5135 })
5136 .await.into_response()
5137 .context("execute command")?;
5138
5139 return this.update(cx, |this, _| {
5140 this.as_local_mut()
5141 .unwrap()
5142 .last_workspace_edits_by_language_server
5143 .remove(&lang_server.server_id())
5144 .unwrap_or_default()
5145 });
5146 } else {
5147 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5148 }
5149 }
5150
5151 Ok(ProjectTransaction::default())
5152 })
5153 } else {
5154 Task::ready(Err(anyhow!("no upstream client and not local")))
5155 }
5156 }
5157
5158 pub fn apply_code_action_kind(
5159 &mut self,
5160 buffers: HashSet<Entity<Buffer>>,
5161 kind: CodeActionKind,
5162 push_to_history: bool,
5163 cx: &mut Context<Self>,
5164 ) -> Task<anyhow::Result<ProjectTransaction>> {
5165 if self.as_local().is_some() {
5166 cx.spawn(async move |lsp_store, cx| {
5167 let buffers = buffers.into_iter().collect::<Vec<_>>();
5168 let result = LocalLspStore::execute_code_action_kind_locally(
5169 lsp_store.clone(),
5170 buffers,
5171 kind,
5172 push_to_history,
5173 cx,
5174 )
5175 .await;
5176 lsp_store.update(cx, |lsp_store, _| {
5177 lsp_store.update_last_formatting_failure(&result);
5178 })?;
5179 result
5180 })
5181 } else if let Some((client, project_id)) = self.upstream_client() {
5182 let buffer_store = self.buffer_store();
5183 cx.spawn(async move |lsp_store, cx| {
5184 let result = client
5185 .request(proto::ApplyCodeActionKind {
5186 project_id,
5187 kind: kind.as_str().to_owned(),
5188 buffer_ids: buffers
5189 .iter()
5190 .map(|buffer| {
5191 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5192 })
5193 .collect(),
5194 })
5195 .await
5196 .and_then(|result| result.transaction.context("missing transaction"));
5197 lsp_store.update(cx, |lsp_store, _| {
5198 lsp_store.update_last_formatting_failure(&result);
5199 })?;
5200
5201 let transaction_response = result?;
5202 buffer_store
5203 .update(cx, |buffer_store, cx| {
5204 buffer_store.deserialize_project_transaction(
5205 transaction_response,
5206 push_to_history,
5207 cx,
5208 )
5209 })
5210 .await
5211 })
5212 } else {
5213 Task::ready(Ok(ProjectTransaction::default()))
5214 }
5215 }
5216
5217 pub fn resolved_hint(
5218 &mut self,
5219 buffer_id: BufferId,
5220 id: InlayId,
5221 cx: &mut Context<Self>,
5222 ) -> Option<ResolvedHint> {
5223 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5224
5225 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5226 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5227 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5228 let (server_id, resolve_data) = match &hint.resolve_state {
5229 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5230 ResolveState::Resolving => {
5231 return Some(ResolvedHint::Resolving(
5232 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5233 ));
5234 }
5235 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5236 };
5237
5238 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5239 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5240 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5241 id,
5242 cx.spawn(async move |lsp_store, cx| {
5243 let resolved_hint = resolve_task.await;
5244 lsp_store
5245 .update(cx, |lsp_store, _| {
5246 if let Some(old_inlay_hint) = lsp_store
5247 .lsp_data
5248 .get_mut(&buffer_id)
5249 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5250 {
5251 match resolved_hint {
5252 Ok(resolved_hint) => {
5253 *old_inlay_hint = resolved_hint;
5254 }
5255 Err(e) => {
5256 old_inlay_hint.resolve_state =
5257 ResolveState::CanResolve(server_id, resolve_data);
5258 log::error!("Inlay hint resolve failed: {e:#}");
5259 }
5260 }
5261 }
5262 })
5263 .ok();
5264 })
5265 .shared(),
5266 );
5267 debug_assert!(
5268 previous_task.is_none(),
5269 "Did not change hint's resolve state after spawning its resolve"
5270 );
5271 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5272 None
5273 }
5274
5275 fn resolve_inlay_hint(
5276 &self,
5277 mut hint: InlayHint,
5278 buffer: Entity<Buffer>,
5279 server_id: LanguageServerId,
5280 cx: &mut Context<Self>,
5281 ) -> Task<anyhow::Result<InlayHint>> {
5282 if let Some((upstream_client, project_id)) = self.upstream_client() {
5283 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5284 {
5285 hint.resolve_state = ResolveState::Resolved;
5286 return Task::ready(Ok(hint));
5287 }
5288 let request = proto::ResolveInlayHint {
5289 project_id,
5290 buffer_id: buffer.read(cx).remote_id().into(),
5291 language_server_id: server_id.0 as u64,
5292 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5293 };
5294 cx.background_spawn(async move {
5295 let response = upstream_client
5296 .request(request)
5297 .await
5298 .context("inlay hints proto request")?;
5299 match response.hint {
5300 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5301 .context("inlay hints proto resolve response conversion"),
5302 None => Ok(hint),
5303 }
5304 })
5305 } else {
5306 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5307 self.language_server_for_local_buffer(buffer, server_id, cx)
5308 .map(|(_, server)| server.clone())
5309 }) else {
5310 return Task::ready(Ok(hint));
5311 };
5312 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5313 return Task::ready(Ok(hint));
5314 }
5315 let buffer_snapshot = buffer.read(cx).snapshot();
5316 cx.spawn(async move |_, cx| {
5317 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5318 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5319 );
5320 let resolved_hint = resolve_task
5321 .await
5322 .into_response()
5323 .context("inlay hint resolve LSP request")?;
5324 let resolved_hint = InlayHints::lsp_to_project_hint(
5325 resolved_hint,
5326 &buffer,
5327 server_id,
5328 ResolveState::Resolved,
5329 false,
5330 cx,
5331 )
5332 .await?;
5333 Ok(resolved_hint)
5334 })
5335 }
5336 }
5337
5338 pub fn resolve_color_presentation(
5339 &mut self,
5340 mut color: DocumentColor,
5341 buffer: Entity<Buffer>,
5342 server_id: LanguageServerId,
5343 cx: &mut Context<Self>,
5344 ) -> Task<Result<DocumentColor>> {
5345 if color.resolved {
5346 return Task::ready(Ok(color));
5347 }
5348
5349 if let Some((upstream_client, project_id)) = self.upstream_client() {
5350 let start = color.lsp_range.start;
5351 let end = color.lsp_range.end;
5352 let request = proto::GetColorPresentation {
5353 project_id,
5354 server_id: server_id.to_proto(),
5355 buffer_id: buffer.read(cx).remote_id().into(),
5356 color: Some(proto::ColorInformation {
5357 red: color.color.red,
5358 green: color.color.green,
5359 blue: color.color.blue,
5360 alpha: color.color.alpha,
5361 lsp_range_start: Some(proto::PointUtf16 {
5362 row: start.line,
5363 column: start.character,
5364 }),
5365 lsp_range_end: Some(proto::PointUtf16 {
5366 row: end.line,
5367 column: end.character,
5368 }),
5369 }),
5370 };
5371 cx.background_spawn(async move {
5372 let response = upstream_client
5373 .request(request)
5374 .await
5375 .context("color presentation proto request")?;
5376 color.resolved = true;
5377 color.color_presentations = response
5378 .presentations
5379 .into_iter()
5380 .map(|presentation| ColorPresentation {
5381 label: SharedString::from(presentation.label),
5382 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5383 additional_text_edits: presentation
5384 .additional_text_edits
5385 .into_iter()
5386 .filter_map(deserialize_lsp_edit)
5387 .collect(),
5388 })
5389 .collect();
5390 Ok(color)
5391 })
5392 } else {
5393 let path = match buffer
5394 .update(cx, |buffer, cx| {
5395 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5396 })
5397 .context("buffer with the missing path")
5398 {
5399 Ok(path) => path,
5400 Err(e) => return Task::ready(Err(e)),
5401 };
5402 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5403 self.language_server_for_local_buffer(buffer, server_id, cx)
5404 .map(|(_, server)| server.clone())
5405 }) else {
5406 return Task::ready(Ok(color));
5407 };
5408 cx.background_spawn(async move {
5409 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5410 lsp::ColorPresentationParams {
5411 text_document: make_text_document_identifier(&path)?,
5412 color: color.color,
5413 range: color.lsp_range,
5414 work_done_progress_params: Default::default(),
5415 partial_result_params: Default::default(),
5416 },
5417 );
5418 color.color_presentations = resolve_task
5419 .await
5420 .into_response()
5421 .context("color presentation resolve LSP request")?
5422 .into_iter()
5423 .map(|presentation| ColorPresentation {
5424 label: SharedString::from(presentation.label),
5425 text_edit: presentation.text_edit,
5426 additional_text_edits: presentation
5427 .additional_text_edits
5428 .unwrap_or_default(),
5429 })
5430 .collect();
5431 color.resolved = true;
5432 Ok(color)
5433 })
5434 }
5435 }
5436
5437 pub(crate) fn linked_edits(
5438 &mut self,
5439 buffer: &Entity<Buffer>,
5440 position: Anchor,
5441 cx: &mut Context<Self>,
5442 ) -> Task<Result<Vec<Range<Anchor>>>> {
5443 let snapshot = buffer.read(cx).snapshot();
5444 let scope = snapshot.language_scope_at(position);
5445 let Some(server_id) = self
5446 .as_local()
5447 .and_then(|local| {
5448 buffer.update(cx, |buffer, cx| {
5449 local
5450 .language_servers_for_buffer(buffer, cx)
5451 .filter(|(_, server)| {
5452 LinkedEditingRange::check_server_capabilities(server.capabilities())
5453 })
5454 .filter(|(adapter, _)| {
5455 scope
5456 .as_ref()
5457 .map(|scope| scope.language_allowed(&adapter.name))
5458 .unwrap_or(true)
5459 })
5460 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5461 .next()
5462 })
5463 })
5464 .or_else(|| {
5465 self.upstream_client()
5466 .is_some()
5467 .then_some(LanguageServerToQuery::FirstCapable)
5468 })
5469 .filter(|_| {
5470 maybe!({
5471 let language = buffer.read(cx).language_at(position)?;
5472 Some(
5473 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5474 .linked_edits,
5475 )
5476 }) == Some(true)
5477 })
5478 else {
5479 return Task::ready(Ok(Vec::new()));
5480 };
5481
5482 self.request_lsp(
5483 buffer.clone(),
5484 server_id,
5485 LinkedEditingRange { position },
5486 cx,
5487 )
5488 }
5489
5490 fn apply_on_type_formatting(
5491 &mut self,
5492 buffer: Entity<Buffer>,
5493 position: Anchor,
5494 trigger: String,
5495 cx: &mut Context<Self>,
5496 ) -> Task<Result<Option<Transaction>>> {
5497 if let Some((client, project_id)) = self.upstream_client() {
5498 if !self.check_if_capable_for_proto_request(
5499 &buffer,
5500 |capabilities| {
5501 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5502 },
5503 cx,
5504 ) {
5505 return Task::ready(Ok(None));
5506 }
5507 let request = proto::OnTypeFormatting {
5508 project_id,
5509 buffer_id: buffer.read(cx).remote_id().into(),
5510 position: Some(serialize_anchor(&position)),
5511 trigger,
5512 version: serialize_version(&buffer.read(cx).version()),
5513 };
5514 cx.background_spawn(async move {
5515 client
5516 .request(request)
5517 .await?
5518 .transaction
5519 .map(language::proto::deserialize_transaction)
5520 .transpose()
5521 })
5522 } else if let Some(local) = self.as_local_mut() {
5523 let buffer_id = buffer.read(cx).remote_id();
5524 local.buffers_being_formatted.insert(buffer_id);
5525 cx.spawn(async move |this, cx| {
5526 let _cleanup = defer({
5527 let this = this.clone();
5528 let mut cx = cx.clone();
5529 move || {
5530 this.update(&mut cx, |this, _| {
5531 if let Some(local) = this.as_local_mut() {
5532 local.buffers_being_formatted.remove(&buffer_id);
5533 }
5534 })
5535 .ok();
5536 }
5537 });
5538
5539 buffer
5540 .update(cx, |buffer, _| {
5541 buffer.wait_for_edits(Some(position.timestamp))
5542 })
5543 .await?;
5544 this.update(cx, |this, cx| {
5545 let position = position.to_point_utf16(buffer.read(cx));
5546 this.on_type_format(buffer, position, trigger, false, cx)
5547 })?
5548 .await
5549 })
5550 } else {
5551 Task::ready(Err(anyhow!("No upstream client or local language server")))
5552 }
5553 }
5554
5555 pub fn on_type_format<T: ToPointUtf16>(
5556 &mut self,
5557 buffer: Entity<Buffer>,
5558 position: T,
5559 trigger: String,
5560 push_to_history: bool,
5561 cx: &mut Context<Self>,
5562 ) -> Task<Result<Option<Transaction>>> {
5563 let position = position.to_point_utf16(buffer.read(cx));
5564 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5565 }
5566
5567 fn on_type_format_impl(
5568 &mut self,
5569 buffer: Entity<Buffer>,
5570 position: PointUtf16,
5571 trigger: String,
5572 push_to_history: bool,
5573 cx: &mut Context<Self>,
5574 ) -> Task<Result<Option<Transaction>>> {
5575 let options = buffer.update(cx, |buffer, cx| {
5576 lsp_command::lsp_formatting_options(
5577 language_settings(
5578 buffer.language_at(position).map(|l| l.name()),
5579 buffer.file(),
5580 cx,
5581 )
5582 .as_ref(),
5583 )
5584 });
5585
5586 cx.spawn(async move |this, cx| {
5587 if let Some(waiter) =
5588 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5589 {
5590 waiter.await?;
5591 }
5592 cx.update(|cx| {
5593 this.update(cx, |this, cx| {
5594 this.request_lsp(
5595 buffer.clone(),
5596 LanguageServerToQuery::FirstCapable,
5597 OnTypeFormatting {
5598 position,
5599 trigger,
5600 options,
5601 push_to_history,
5602 },
5603 cx,
5604 )
5605 })
5606 })?
5607 .await
5608 })
5609 }
5610
5611 pub fn definitions(
5612 &mut self,
5613 buffer: &Entity<Buffer>,
5614 position: PointUtf16,
5615 cx: &mut Context<Self>,
5616 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5617 if let Some((upstream_client, project_id)) = self.upstream_client() {
5618 let request = GetDefinitions { position };
5619 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5620 return Task::ready(Ok(None));
5621 }
5622 let request_task = upstream_client.request_lsp(
5623 project_id,
5624 None,
5625 LSP_REQUEST_TIMEOUT,
5626 cx.background_executor().clone(),
5627 request.to_proto(project_id, buffer.read(cx)),
5628 );
5629 let buffer = buffer.clone();
5630 cx.spawn(async move |weak_lsp_store, cx| {
5631 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5632 return Ok(None);
5633 };
5634 let Some(responses) = request_task.await? else {
5635 return Ok(None);
5636 };
5637 let actions = join_all(responses.payload.into_iter().map(|response| {
5638 GetDefinitions { position }.response_from_proto(
5639 response.response,
5640 lsp_store.clone(),
5641 buffer.clone(),
5642 cx.clone(),
5643 )
5644 }))
5645 .await;
5646
5647 Ok(Some(
5648 actions
5649 .into_iter()
5650 .collect::<Result<Vec<Vec<_>>>>()?
5651 .into_iter()
5652 .flatten()
5653 .dedup()
5654 .collect(),
5655 ))
5656 })
5657 } else {
5658 let definitions_task = self.request_multiple_lsp_locally(
5659 buffer,
5660 Some(position),
5661 GetDefinitions { position },
5662 cx,
5663 );
5664 cx.background_spawn(async move {
5665 Ok(Some(
5666 definitions_task
5667 .await
5668 .into_iter()
5669 .flat_map(|(_, definitions)| definitions)
5670 .dedup()
5671 .collect(),
5672 ))
5673 })
5674 }
5675 }
5676
5677 pub fn declarations(
5678 &mut self,
5679 buffer: &Entity<Buffer>,
5680 position: PointUtf16,
5681 cx: &mut Context<Self>,
5682 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5683 if let Some((upstream_client, project_id)) = self.upstream_client() {
5684 let request = GetDeclarations { position };
5685 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5686 return Task::ready(Ok(None));
5687 }
5688 let request_task = upstream_client.request_lsp(
5689 project_id,
5690 None,
5691 LSP_REQUEST_TIMEOUT,
5692 cx.background_executor().clone(),
5693 request.to_proto(project_id, buffer.read(cx)),
5694 );
5695 let buffer = buffer.clone();
5696 cx.spawn(async move |weak_lsp_store, cx| {
5697 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5698 return Ok(None);
5699 };
5700 let Some(responses) = request_task.await? else {
5701 return Ok(None);
5702 };
5703 let actions = join_all(responses.payload.into_iter().map(|response| {
5704 GetDeclarations { position }.response_from_proto(
5705 response.response,
5706 lsp_store.clone(),
5707 buffer.clone(),
5708 cx.clone(),
5709 )
5710 }))
5711 .await;
5712
5713 Ok(Some(
5714 actions
5715 .into_iter()
5716 .collect::<Result<Vec<Vec<_>>>>()?
5717 .into_iter()
5718 .flatten()
5719 .dedup()
5720 .collect(),
5721 ))
5722 })
5723 } else {
5724 let declarations_task = self.request_multiple_lsp_locally(
5725 buffer,
5726 Some(position),
5727 GetDeclarations { position },
5728 cx,
5729 );
5730 cx.background_spawn(async move {
5731 Ok(Some(
5732 declarations_task
5733 .await
5734 .into_iter()
5735 .flat_map(|(_, declarations)| declarations)
5736 .dedup()
5737 .collect(),
5738 ))
5739 })
5740 }
5741 }
5742
5743 pub fn type_definitions(
5744 &mut self,
5745 buffer: &Entity<Buffer>,
5746 position: PointUtf16,
5747 cx: &mut Context<Self>,
5748 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5749 if let Some((upstream_client, project_id)) = self.upstream_client() {
5750 let request = GetTypeDefinitions { position };
5751 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5752 return Task::ready(Ok(None));
5753 }
5754 let request_task = upstream_client.request_lsp(
5755 project_id,
5756 None,
5757 LSP_REQUEST_TIMEOUT,
5758 cx.background_executor().clone(),
5759 request.to_proto(project_id, buffer.read(cx)),
5760 );
5761 let buffer = buffer.clone();
5762 cx.spawn(async move |weak_lsp_store, cx| {
5763 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5764 return Ok(None);
5765 };
5766 let Some(responses) = request_task.await? else {
5767 return Ok(None);
5768 };
5769 let actions = join_all(responses.payload.into_iter().map(|response| {
5770 GetTypeDefinitions { position }.response_from_proto(
5771 response.response,
5772 lsp_store.clone(),
5773 buffer.clone(),
5774 cx.clone(),
5775 )
5776 }))
5777 .await;
5778
5779 Ok(Some(
5780 actions
5781 .into_iter()
5782 .collect::<Result<Vec<Vec<_>>>>()?
5783 .into_iter()
5784 .flatten()
5785 .dedup()
5786 .collect(),
5787 ))
5788 })
5789 } else {
5790 let type_definitions_task = self.request_multiple_lsp_locally(
5791 buffer,
5792 Some(position),
5793 GetTypeDefinitions { position },
5794 cx,
5795 );
5796 cx.background_spawn(async move {
5797 Ok(Some(
5798 type_definitions_task
5799 .await
5800 .into_iter()
5801 .flat_map(|(_, type_definitions)| type_definitions)
5802 .dedup()
5803 .collect(),
5804 ))
5805 })
5806 }
5807 }
5808
5809 pub fn implementations(
5810 &mut self,
5811 buffer: &Entity<Buffer>,
5812 position: PointUtf16,
5813 cx: &mut Context<Self>,
5814 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5815 if let Some((upstream_client, project_id)) = self.upstream_client() {
5816 let request = GetImplementations { position };
5817 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5818 return Task::ready(Ok(None));
5819 }
5820 let request_task = upstream_client.request_lsp(
5821 project_id,
5822 None,
5823 LSP_REQUEST_TIMEOUT,
5824 cx.background_executor().clone(),
5825 request.to_proto(project_id, buffer.read(cx)),
5826 );
5827 let buffer = buffer.clone();
5828 cx.spawn(async move |weak_lsp_store, cx| {
5829 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5830 return Ok(None);
5831 };
5832 let Some(responses) = request_task.await? else {
5833 return Ok(None);
5834 };
5835 let actions = join_all(responses.payload.into_iter().map(|response| {
5836 GetImplementations { position }.response_from_proto(
5837 response.response,
5838 lsp_store.clone(),
5839 buffer.clone(),
5840 cx.clone(),
5841 )
5842 }))
5843 .await;
5844
5845 Ok(Some(
5846 actions
5847 .into_iter()
5848 .collect::<Result<Vec<Vec<_>>>>()?
5849 .into_iter()
5850 .flatten()
5851 .dedup()
5852 .collect(),
5853 ))
5854 })
5855 } else {
5856 let implementations_task = self.request_multiple_lsp_locally(
5857 buffer,
5858 Some(position),
5859 GetImplementations { position },
5860 cx,
5861 );
5862 cx.background_spawn(async move {
5863 Ok(Some(
5864 implementations_task
5865 .await
5866 .into_iter()
5867 .flat_map(|(_, implementations)| implementations)
5868 .dedup()
5869 .collect(),
5870 ))
5871 })
5872 }
5873 }
5874
5875 pub fn references(
5876 &mut self,
5877 buffer: &Entity<Buffer>,
5878 position: PointUtf16,
5879 cx: &mut Context<Self>,
5880 ) -> Task<Result<Option<Vec<Location>>>> {
5881 if let Some((upstream_client, project_id)) = self.upstream_client() {
5882 let request = GetReferences { position };
5883 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5884 return Task::ready(Ok(None));
5885 }
5886
5887 let request_task = upstream_client.request_lsp(
5888 project_id,
5889 None,
5890 LSP_REQUEST_TIMEOUT,
5891 cx.background_executor().clone(),
5892 request.to_proto(project_id, buffer.read(cx)),
5893 );
5894 let buffer = buffer.clone();
5895 cx.spawn(async move |weak_lsp_store, cx| {
5896 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5897 return Ok(None);
5898 };
5899 let Some(responses) = request_task.await? else {
5900 return Ok(None);
5901 };
5902
5903 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5904 GetReferences { position }.response_from_proto(
5905 lsp_response.response,
5906 lsp_store.clone(),
5907 buffer.clone(),
5908 cx.clone(),
5909 )
5910 }))
5911 .await
5912 .into_iter()
5913 .collect::<Result<Vec<Vec<_>>>>()?
5914 .into_iter()
5915 .flatten()
5916 .dedup()
5917 .collect();
5918 Ok(Some(locations))
5919 })
5920 } else {
5921 let references_task = self.request_multiple_lsp_locally(
5922 buffer,
5923 Some(position),
5924 GetReferences { position },
5925 cx,
5926 );
5927 cx.background_spawn(async move {
5928 Ok(Some(
5929 references_task
5930 .await
5931 .into_iter()
5932 .flat_map(|(_, references)| references)
5933 .dedup()
5934 .collect(),
5935 ))
5936 })
5937 }
5938 }
5939
5940 pub fn code_actions(
5941 &mut self,
5942 buffer: &Entity<Buffer>,
5943 range: Range<Anchor>,
5944 kinds: Option<Vec<CodeActionKind>>,
5945 cx: &mut Context<Self>,
5946 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5947 if let Some((upstream_client, project_id)) = self.upstream_client() {
5948 let request = GetCodeActions {
5949 range: range.clone(),
5950 kinds: kinds.clone(),
5951 };
5952 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5953 return Task::ready(Ok(None));
5954 }
5955 let request_task = upstream_client.request_lsp(
5956 project_id,
5957 None,
5958 LSP_REQUEST_TIMEOUT,
5959 cx.background_executor().clone(),
5960 request.to_proto(project_id, buffer.read(cx)),
5961 );
5962 let buffer = buffer.clone();
5963 cx.spawn(async move |weak_lsp_store, cx| {
5964 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5965 return Ok(None);
5966 };
5967 let Some(responses) = request_task.await? else {
5968 return Ok(None);
5969 };
5970 let actions = join_all(responses.payload.into_iter().map(|response| {
5971 GetCodeActions {
5972 range: range.clone(),
5973 kinds: kinds.clone(),
5974 }
5975 .response_from_proto(
5976 response.response,
5977 lsp_store.clone(),
5978 buffer.clone(),
5979 cx.clone(),
5980 )
5981 }))
5982 .await;
5983
5984 Ok(Some(
5985 actions
5986 .into_iter()
5987 .collect::<Result<Vec<Vec<_>>>>()?
5988 .into_iter()
5989 .flatten()
5990 .collect(),
5991 ))
5992 })
5993 } else {
5994 let all_actions_task = self.request_multiple_lsp_locally(
5995 buffer,
5996 Some(range.start),
5997 GetCodeActions { range, kinds },
5998 cx,
5999 );
6000 cx.background_spawn(async move {
6001 Ok(Some(
6002 all_actions_task
6003 .await
6004 .into_iter()
6005 .flat_map(|(_, actions)| actions)
6006 .collect(),
6007 ))
6008 })
6009 }
6010 }
6011
6012 pub fn code_lens_actions(
6013 &mut self,
6014 buffer: &Entity<Buffer>,
6015 cx: &mut Context<Self>,
6016 ) -> CodeLensTask {
6017 let version_queried_for = buffer.read(cx).version();
6018 let buffer_id = buffer.read(cx).remote_id();
6019 let existing_servers = self.as_local().map(|local| {
6020 local
6021 .buffers_opened_in_servers
6022 .get(&buffer_id)
6023 .cloned()
6024 .unwrap_or_default()
6025 });
6026
6027 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6028 if let Some(cached_lens) = &lsp_data.code_lens {
6029 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6030 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6031 existing_servers != cached_lens.lens.keys().copied().collect()
6032 });
6033 if !has_different_servers {
6034 return Task::ready(Ok(Some(
6035 cached_lens.lens.values().flatten().cloned().collect(),
6036 )))
6037 .shared();
6038 }
6039 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6040 if !version_queried_for.changed_since(updating_for) {
6041 return running_update.clone();
6042 }
6043 }
6044 }
6045 }
6046
6047 let lens_lsp_data = self
6048 .latest_lsp_data(buffer, cx)
6049 .code_lens
6050 .get_or_insert_default();
6051 let buffer = buffer.clone();
6052 let query_version_queried_for = version_queried_for.clone();
6053 let new_task = cx
6054 .spawn(async move |lsp_store, cx| {
6055 cx.background_executor()
6056 .timer(Duration::from_millis(30))
6057 .await;
6058 let fetched_lens = lsp_store
6059 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6060 .map_err(Arc::new)?
6061 .await
6062 .context("fetching code lens")
6063 .map_err(Arc::new);
6064 let fetched_lens = match fetched_lens {
6065 Ok(fetched_lens) => fetched_lens,
6066 Err(e) => {
6067 lsp_store
6068 .update(cx, |lsp_store, _| {
6069 if let Some(lens_lsp_data) = lsp_store
6070 .lsp_data
6071 .get_mut(&buffer_id)
6072 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6073 {
6074 lens_lsp_data.update = None;
6075 }
6076 })
6077 .ok();
6078 return Err(e);
6079 }
6080 };
6081
6082 lsp_store
6083 .update(cx, |lsp_store, _| {
6084 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6085 let code_lens = lsp_data.code_lens.as_mut()?;
6086 if let Some(fetched_lens) = fetched_lens {
6087 if lsp_data.buffer_version == query_version_queried_for {
6088 code_lens.lens.extend(fetched_lens);
6089 } else if !lsp_data
6090 .buffer_version
6091 .changed_since(&query_version_queried_for)
6092 {
6093 lsp_data.buffer_version = query_version_queried_for;
6094 code_lens.lens = fetched_lens;
6095 }
6096 }
6097 code_lens.update = None;
6098 Some(code_lens.lens.values().flatten().cloned().collect())
6099 })
6100 .map_err(Arc::new)
6101 })
6102 .shared();
6103 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6104 new_task
6105 }
6106
6107 fn fetch_code_lens(
6108 &mut self,
6109 buffer: &Entity<Buffer>,
6110 cx: &mut Context<Self>,
6111 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6112 if let Some((upstream_client, project_id)) = self.upstream_client() {
6113 let request = GetCodeLens;
6114 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6115 return Task::ready(Ok(None));
6116 }
6117 let request_task = upstream_client.request_lsp(
6118 project_id,
6119 None,
6120 LSP_REQUEST_TIMEOUT,
6121 cx.background_executor().clone(),
6122 request.to_proto(project_id, buffer.read(cx)),
6123 );
6124 let buffer = buffer.clone();
6125 cx.spawn(async move |weak_lsp_store, cx| {
6126 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6127 return Ok(None);
6128 };
6129 let Some(responses) = request_task.await? else {
6130 return Ok(None);
6131 };
6132
6133 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6134 let lsp_store = lsp_store.clone();
6135 let buffer = buffer.clone();
6136 let cx = cx.clone();
6137 async move {
6138 (
6139 LanguageServerId::from_proto(response.server_id),
6140 GetCodeLens
6141 .response_from_proto(response.response, lsp_store, buffer, cx)
6142 .await,
6143 )
6144 }
6145 }))
6146 .await;
6147
6148 let mut has_errors = false;
6149 let code_lens_actions = code_lens_actions
6150 .into_iter()
6151 .filter_map(|(server_id, code_lens)| match code_lens {
6152 Ok(code_lens) => Some((server_id, code_lens)),
6153 Err(e) => {
6154 has_errors = true;
6155 log::error!("{e:#}");
6156 None
6157 }
6158 })
6159 .collect::<HashMap<_, _>>();
6160 anyhow::ensure!(
6161 !has_errors || !code_lens_actions.is_empty(),
6162 "Failed to fetch code lens"
6163 );
6164 Ok(Some(code_lens_actions))
6165 })
6166 } else {
6167 let code_lens_actions_task =
6168 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6169 cx.background_spawn(async move {
6170 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6171 })
6172 }
6173 }
6174
6175 #[inline(never)]
6176 pub fn completions(
6177 &self,
6178 buffer: &Entity<Buffer>,
6179 position: PointUtf16,
6180 context: CompletionContext,
6181 cx: &mut Context<Self>,
6182 ) -> Task<Result<Vec<CompletionResponse>>> {
6183 let language_registry = self.languages.clone();
6184
6185 if let Some((upstream_client, project_id)) = self.upstream_client() {
6186 let snapshot = buffer.read(cx).snapshot();
6187 let offset = position.to_offset(&snapshot);
6188 let scope = snapshot.language_scope_at(offset);
6189 let capable_lsps = self.all_capable_for_proto_request(
6190 buffer,
6191 |server_name, capabilities| {
6192 capabilities.completion_provider.is_some()
6193 && scope
6194 .as_ref()
6195 .map(|scope| scope.language_allowed(server_name))
6196 .unwrap_or(true)
6197 },
6198 cx,
6199 );
6200 if capable_lsps.is_empty() {
6201 return Task::ready(Ok(Vec::new()));
6202 }
6203
6204 let language = buffer.read(cx).language().cloned();
6205
6206 // In the future, we should provide project guests with the names of LSP adapters,
6207 // so that they can use the correct LSP adapter when computing labels. For now,
6208 // guests just use the first LSP adapter associated with the buffer's language.
6209 let lsp_adapter = language.as_ref().and_then(|language| {
6210 language_registry
6211 .lsp_adapters(&language.name())
6212 .first()
6213 .cloned()
6214 });
6215
6216 let buffer = buffer.clone();
6217
6218 cx.spawn(async move |this, cx| {
6219 let requests = join_all(
6220 capable_lsps
6221 .into_iter()
6222 .map(|id| {
6223 let request = GetCompletions {
6224 position,
6225 context: context.clone(),
6226 server_id: Some(id),
6227 };
6228 let buffer = buffer.clone();
6229 let language = language.clone();
6230 let lsp_adapter = lsp_adapter.clone();
6231 let upstream_client = upstream_client.clone();
6232 let response = this
6233 .update(cx, |this, cx| {
6234 this.send_lsp_proto_request(
6235 buffer,
6236 upstream_client,
6237 project_id,
6238 request,
6239 cx,
6240 )
6241 })
6242 .log_err();
6243 async move {
6244 let response = response?.await.log_err()?;
6245
6246 let completions = populate_labels_for_completions(
6247 response.completions,
6248 language,
6249 lsp_adapter,
6250 )
6251 .await;
6252
6253 Some(CompletionResponse {
6254 completions,
6255 display_options: CompletionDisplayOptions::default(),
6256 is_incomplete: response.is_incomplete,
6257 })
6258 }
6259 })
6260 .collect::<Vec<_>>(),
6261 );
6262 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6263 })
6264 } else if let Some(local) = self.as_local() {
6265 let snapshot = buffer.read(cx).snapshot();
6266 let offset = position.to_offset(&snapshot);
6267 let scope = snapshot.language_scope_at(offset);
6268 let language = snapshot.language().cloned();
6269 let completion_settings = language_settings(
6270 language.as_ref().map(|language| language.name()),
6271 buffer.read(cx).file(),
6272 cx,
6273 )
6274 .completions
6275 .clone();
6276 if !completion_settings.lsp {
6277 return Task::ready(Ok(Vec::new()));
6278 }
6279
6280 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6281 local
6282 .language_servers_for_buffer(buffer, cx)
6283 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6284 .filter(|(adapter, _)| {
6285 scope
6286 .as_ref()
6287 .map(|scope| scope.language_allowed(&adapter.name))
6288 .unwrap_or(true)
6289 })
6290 .map(|(_, server)| server.server_id())
6291 .collect()
6292 });
6293
6294 let buffer = buffer.clone();
6295 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6296 let lsp_timeout = if lsp_timeout > 0 {
6297 Some(Duration::from_millis(lsp_timeout))
6298 } else {
6299 None
6300 };
6301 cx.spawn(async move |this, cx| {
6302 let mut tasks = Vec::with_capacity(server_ids.len());
6303 this.update(cx, |lsp_store, cx| {
6304 for server_id in server_ids {
6305 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6306 let lsp_timeout = lsp_timeout
6307 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6308 let mut timeout = cx.background_spawn(async move {
6309 match lsp_timeout {
6310 Some(lsp_timeout) => {
6311 lsp_timeout.await;
6312 true
6313 },
6314 None => false,
6315 }
6316 }).fuse();
6317 let mut lsp_request = lsp_store.request_lsp(
6318 buffer.clone(),
6319 LanguageServerToQuery::Other(server_id),
6320 GetCompletions {
6321 position,
6322 context: context.clone(),
6323 server_id: Some(server_id),
6324 },
6325 cx,
6326 ).fuse();
6327 let new_task = cx.background_spawn(async move {
6328 select_biased! {
6329 response = lsp_request => anyhow::Ok(Some(response?)),
6330 timeout_happened = timeout => {
6331 if timeout_happened {
6332 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6333 Ok(None)
6334 } else {
6335 let completions = lsp_request.await?;
6336 Ok(Some(completions))
6337 }
6338 },
6339 }
6340 });
6341 tasks.push((lsp_adapter, new_task));
6342 }
6343 })?;
6344
6345 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6346 let completion_response = task.await.ok()??;
6347 let completions = populate_labels_for_completions(
6348 completion_response.completions,
6349 language.clone(),
6350 lsp_adapter,
6351 )
6352 .await;
6353 Some(CompletionResponse {
6354 completions,
6355 display_options: CompletionDisplayOptions::default(),
6356 is_incomplete: completion_response.is_incomplete,
6357 })
6358 });
6359
6360 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6361
6362 Ok(responses.into_iter().flatten().collect())
6363 })
6364 } else {
6365 Task::ready(Err(anyhow!("No upstream client or local language server")))
6366 }
6367 }
6368
6369 pub fn resolve_completions(
6370 &self,
6371 buffer: Entity<Buffer>,
6372 completion_indices: Vec<usize>,
6373 completions: Rc<RefCell<Box<[Completion]>>>,
6374 cx: &mut Context<Self>,
6375 ) -> Task<Result<bool>> {
6376 let client = self.upstream_client();
6377 let buffer_id = buffer.read(cx).remote_id();
6378 let buffer_snapshot = buffer.read(cx).snapshot();
6379
6380 if !self.check_if_capable_for_proto_request(
6381 &buffer,
6382 GetCompletions::can_resolve_completions,
6383 cx,
6384 ) {
6385 return Task::ready(Ok(false));
6386 }
6387 cx.spawn(async move |lsp_store, cx| {
6388 let mut did_resolve = false;
6389 if let Some((client, project_id)) = client {
6390 for completion_index in completion_indices {
6391 let server_id = {
6392 let completion = &completions.borrow()[completion_index];
6393 completion.source.server_id()
6394 };
6395 if let Some(server_id) = server_id {
6396 if Self::resolve_completion_remote(
6397 project_id,
6398 server_id,
6399 buffer_id,
6400 completions.clone(),
6401 completion_index,
6402 client.clone(),
6403 )
6404 .await
6405 .log_err()
6406 .is_some()
6407 {
6408 did_resolve = true;
6409 }
6410 } else {
6411 resolve_word_completion(
6412 &buffer_snapshot,
6413 &mut completions.borrow_mut()[completion_index],
6414 );
6415 }
6416 }
6417 } else {
6418 for completion_index in completion_indices {
6419 let server_id = {
6420 let completion = &completions.borrow()[completion_index];
6421 completion.source.server_id()
6422 };
6423 if let Some(server_id) = server_id {
6424 let server_and_adapter = lsp_store
6425 .read_with(cx, |lsp_store, _| {
6426 let server = lsp_store.language_server_for_id(server_id)?;
6427 let adapter =
6428 lsp_store.language_server_adapter_for_id(server.server_id())?;
6429 Some((server, adapter))
6430 })
6431 .ok()
6432 .flatten();
6433 let Some((server, adapter)) = server_and_adapter else {
6434 continue;
6435 };
6436
6437 let resolved = Self::resolve_completion_local(
6438 server,
6439 completions.clone(),
6440 completion_index,
6441 )
6442 .await
6443 .log_err()
6444 .is_some();
6445 if resolved {
6446 Self::regenerate_completion_labels(
6447 adapter,
6448 &buffer_snapshot,
6449 completions.clone(),
6450 completion_index,
6451 )
6452 .await
6453 .log_err();
6454 did_resolve = true;
6455 }
6456 } else {
6457 resolve_word_completion(
6458 &buffer_snapshot,
6459 &mut completions.borrow_mut()[completion_index],
6460 );
6461 }
6462 }
6463 }
6464
6465 Ok(did_resolve)
6466 })
6467 }
6468
6469 async fn resolve_completion_local(
6470 server: Arc<lsp::LanguageServer>,
6471 completions: Rc<RefCell<Box<[Completion]>>>,
6472 completion_index: usize,
6473 ) -> Result<()> {
6474 let server_id = server.server_id();
6475 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6476 return Ok(());
6477 }
6478
6479 let request = {
6480 let completion = &completions.borrow()[completion_index];
6481 match &completion.source {
6482 CompletionSource::Lsp {
6483 lsp_completion,
6484 resolved,
6485 server_id: completion_server_id,
6486 ..
6487 } => {
6488 if *resolved {
6489 return Ok(());
6490 }
6491 anyhow::ensure!(
6492 server_id == *completion_server_id,
6493 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6494 );
6495 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6496 }
6497 CompletionSource::BufferWord { .. }
6498 | CompletionSource::Dap { .. }
6499 | CompletionSource::Custom => {
6500 return Ok(());
6501 }
6502 }
6503 };
6504 let resolved_completion = request
6505 .await
6506 .into_response()
6507 .context("resolve completion")?;
6508
6509 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6510 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6511
6512 let mut completions = completions.borrow_mut();
6513 let completion = &mut completions[completion_index];
6514 if let CompletionSource::Lsp {
6515 lsp_completion,
6516 resolved,
6517 server_id: completion_server_id,
6518 ..
6519 } = &mut completion.source
6520 {
6521 if *resolved {
6522 return Ok(());
6523 }
6524 anyhow::ensure!(
6525 server_id == *completion_server_id,
6526 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6527 );
6528 **lsp_completion = resolved_completion;
6529 *resolved = true;
6530 }
6531 Ok(())
6532 }
6533
6534 async fn regenerate_completion_labels(
6535 adapter: Arc<CachedLspAdapter>,
6536 snapshot: &BufferSnapshot,
6537 completions: Rc<RefCell<Box<[Completion]>>>,
6538 completion_index: usize,
6539 ) -> Result<()> {
6540 let completion_item = completions.borrow()[completion_index]
6541 .source
6542 .lsp_completion(true)
6543 .map(Cow::into_owned);
6544 if let Some(lsp_documentation) = completion_item
6545 .as_ref()
6546 .and_then(|completion_item| completion_item.documentation.clone())
6547 {
6548 let mut completions = completions.borrow_mut();
6549 let completion = &mut completions[completion_index];
6550 completion.documentation = Some(lsp_documentation.into());
6551 } else {
6552 let mut completions = completions.borrow_mut();
6553 let completion = &mut completions[completion_index];
6554 completion.documentation = Some(CompletionDocumentation::Undocumented);
6555 }
6556
6557 let mut new_label = match completion_item {
6558 Some(completion_item) => {
6559 // Some language servers always return `detail` lazily via resolve, regardless of
6560 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6561 // See: https://github.com/yioneko/vtsls/issues/213
6562 let language = snapshot.language();
6563 match language {
6564 Some(language) => {
6565 adapter
6566 .labels_for_completions(
6567 std::slice::from_ref(&completion_item),
6568 language,
6569 )
6570 .await?
6571 }
6572 None => Vec::new(),
6573 }
6574 .pop()
6575 .flatten()
6576 .unwrap_or_else(|| {
6577 CodeLabel::fallback_for_completion(
6578 &completion_item,
6579 language.map(|language| language.as_ref()),
6580 )
6581 })
6582 }
6583 None => CodeLabel::plain(
6584 completions.borrow()[completion_index].new_text.clone(),
6585 None,
6586 ),
6587 };
6588 ensure_uniform_list_compatible_label(&mut new_label);
6589
6590 let mut completions = completions.borrow_mut();
6591 let completion = &mut completions[completion_index];
6592 if completion.label.filter_text() == new_label.filter_text() {
6593 completion.label = new_label;
6594 } else {
6595 log::error!(
6596 "Resolved completion changed display label from {} to {}. \
6597 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6598 completion.label.text(),
6599 new_label.text(),
6600 completion.label.filter_text(),
6601 new_label.filter_text()
6602 );
6603 }
6604
6605 Ok(())
6606 }
6607
6608 async fn resolve_completion_remote(
6609 project_id: u64,
6610 server_id: LanguageServerId,
6611 buffer_id: BufferId,
6612 completions: Rc<RefCell<Box<[Completion]>>>,
6613 completion_index: usize,
6614 client: AnyProtoClient,
6615 ) -> Result<()> {
6616 let lsp_completion = {
6617 let completion = &completions.borrow()[completion_index];
6618 match &completion.source {
6619 CompletionSource::Lsp {
6620 lsp_completion,
6621 resolved,
6622 server_id: completion_server_id,
6623 ..
6624 } => {
6625 anyhow::ensure!(
6626 server_id == *completion_server_id,
6627 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6628 );
6629 if *resolved {
6630 return Ok(());
6631 }
6632 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6633 }
6634 CompletionSource::Custom
6635 | CompletionSource::Dap { .. }
6636 | CompletionSource::BufferWord { .. } => {
6637 return Ok(());
6638 }
6639 }
6640 };
6641 let request = proto::ResolveCompletionDocumentation {
6642 project_id,
6643 language_server_id: server_id.0 as u64,
6644 lsp_completion,
6645 buffer_id: buffer_id.into(),
6646 };
6647
6648 let response = client
6649 .request(request)
6650 .await
6651 .context("completion documentation resolve proto request")?;
6652 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6653
6654 let documentation = if response.documentation.is_empty() {
6655 CompletionDocumentation::Undocumented
6656 } else if response.documentation_is_markdown {
6657 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6658 } else if response.documentation.lines().count() <= 1 {
6659 CompletionDocumentation::SingleLine(response.documentation.into())
6660 } else {
6661 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6662 };
6663
6664 let mut completions = completions.borrow_mut();
6665 let completion = &mut completions[completion_index];
6666 completion.documentation = Some(documentation);
6667 if let CompletionSource::Lsp {
6668 insert_range,
6669 lsp_completion,
6670 resolved,
6671 server_id: completion_server_id,
6672 lsp_defaults: _,
6673 } = &mut completion.source
6674 {
6675 let completion_insert_range = response
6676 .old_insert_start
6677 .and_then(deserialize_anchor)
6678 .zip(response.old_insert_end.and_then(deserialize_anchor));
6679 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6680
6681 if *resolved {
6682 return Ok(());
6683 }
6684 anyhow::ensure!(
6685 server_id == *completion_server_id,
6686 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6687 );
6688 **lsp_completion = resolved_lsp_completion;
6689 *resolved = true;
6690 }
6691
6692 let replace_range = response
6693 .old_replace_start
6694 .and_then(deserialize_anchor)
6695 .zip(response.old_replace_end.and_then(deserialize_anchor));
6696 if let Some((old_replace_start, old_replace_end)) = replace_range
6697 && !response.new_text.is_empty()
6698 {
6699 completion.new_text = response.new_text;
6700 completion.replace_range = old_replace_start..old_replace_end;
6701 }
6702
6703 Ok(())
6704 }
6705
6706 pub fn apply_additional_edits_for_completion(
6707 &self,
6708 buffer_handle: Entity<Buffer>,
6709 completions: Rc<RefCell<Box<[Completion]>>>,
6710 completion_index: usize,
6711 push_to_history: bool,
6712 cx: &mut Context<Self>,
6713 ) -> Task<Result<Option<Transaction>>> {
6714 if let Some((client, project_id)) = self.upstream_client() {
6715 let buffer = buffer_handle.read(cx);
6716 let buffer_id = buffer.remote_id();
6717 cx.spawn(async move |_, cx| {
6718 let request = {
6719 let completion = completions.borrow()[completion_index].clone();
6720 proto::ApplyCompletionAdditionalEdits {
6721 project_id,
6722 buffer_id: buffer_id.into(),
6723 completion: Some(Self::serialize_completion(&CoreCompletion {
6724 replace_range: completion.replace_range,
6725 new_text: completion.new_text,
6726 source: completion.source,
6727 })),
6728 }
6729 };
6730
6731 if let Some(transaction) = client.request(request).await?.transaction {
6732 let transaction = language::proto::deserialize_transaction(transaction)?;
6733 buffer_handle
6734 .update(cx, |buffer, _| {
6735 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6736 })
6737 .await?;
6738 if push_to_history {
6739 buffer_handle.update(cx, |buffer, _| {
6740 buffer.push_transaction(transaction.clone(), Instant::now());
6741 buffer.finalize_last_transaction();
6742 });
6743 }
6744 Ok(Some(transaction))
6745 } else {
6746 Ok(None)
6747 }
6748 })
6749 } else {
6750 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6751 let completion = &completions.borrow()[completion_index];
6752 let server_id = completion.source.server_id()?;
6753 Some(
6754 self.language_server_for_local_buffer(buffer, server_id, cx)?
6755 .1
6756 .clone(),
6757 )
6758 }) else {
6759 return Task::ready(Ok(None));
6760 };
6761
6762 cx.spawn(async move |this, cx| {
6763 Self::resolve_completion_local(
6764 server.clone(),
6765 completions.clone(),
6766 completion_index,
6767 )
6768 .await
6769 .context("resolving completion")?;
6770 let completion = completions.borrow()[completion_index].clone();
6771 let additional_text_edits = completion
6772 .source
6773 .lsp_completion(true)
6774 .as_ref()
6775 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6776 if let Some(edits) = additional_text_edits {
6777 let edits = this
6778 .update(cx, |this, cx| {
6779 this.as_local_mut().unwrap().edits_from_lsp(
6780 &buffer_handle,
6781 edits,
6782 server.server_id(),
6783 None,
6784 cx,
6785 )
6786 })?
6787 .await?;
6788
6789 buffer_handle.update(cx, |buffer, cx| {
6790 buffer.finalize_last_transaction();
6791 buffer.start_transaction();
6792
6793 for (range, text) in edits {
6794 let primary = &completion.replace_range;
6795
6796 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6797 // and the primary completion is just an insertion (empty range), then this is likely
6798 // an auto-import scenario and should not be considered overlapping
6799 // https://github.com/zed-industries/zed/issues/26136
6800 let is_file_start_auto_import = {
6801 let snapshot = buffer.snapshot();
6802 let primary_start_point = primary.start.to_point(&snapshot);
6803 let range_start_point = range.start.to_point(&snapshot);
6804
6805 let result = primary_start_point.row == 0
6806 && primary_start_point.column == 0
6807 && range_start_point.row == 0
6808 && range_start_point.column == 0;
6809
6810 result
6811 };
6812
6813 let has_overlap = if is_file_start_auto_import {
6814 false
6815 } else {
6816 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6817 && primary.end.cmp(&range.start, buffer).is_ge();
6818 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6819 && range.end.cmp(&primary.end, buffer).is_ge();
6820 let result = start_within || end_within;
6821 result
6822 };
6823
6824 //Skip additional edits which overlap with the primary completion edit
6825 //https://github.com/zed-industries/zed/pull/1871
6826 if !has_overlap {
6827 buffer.edit([(range, text)], None, cx);
6828 }
6829 }
6830
6831 let transaction = if buffer.end_transaction(cx).is_some() {
6832 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6833 if !push_to_history {
6834 buffer.forget_transaction(transaction.id);
6835 }
6836 Some(transaction)
6837 } else {
6838 None
6839 };
6840 Ok(transaction)
6841 })
6842 } else {
6843 Ok(None)
6844 }
6845 })
6846 }
6847 }
6848
6849 pub fn pull_diagnostics(
6850 &mut self,
6851 buffer: Entity<Buffer>,
6852 cx: &mut Context<Self>,
6853 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6854 let buffer_id = buffer.read(cx).remote_id();
6855
6856 if let Some((client, upstream_project_id)) = self.upstream_client() {
6857 let mut suitable_capabilities = None;
6858 // Are we capable for proto request?
6859 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6860 &buffer,
6861 |capabilities| {
6862 if let Some(caps) = &capabilities.diagnostic_provider {
6863 suitable_capabilities = Some(caps.clone());
6864 true
6865 } else {
6866 false
6867 }
6868 },
6869 cx,
6870 );
6871 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6872 let Some(dynamic_caps) = suitable_capabilities else {
6873 return Task::ready(Ok(None));
6874 };
6875 assert!(any_server_has_diagnostics_provider);
6876
6877 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6878 let request = GetDocumentDiagnostics {
6879 previous_result_id: None,
6880 identifier,
6881 registration_id: None,
6882 };
6883 let request_task = client.request_lsp(
6884 upstream_project_id,
6885 None,
6886 LSP_REQUEST_TIMEOUT,
6887 cx.background_executor().clone(),
6888 request.to_proto(upstream_project_id, buffer.read(cx)),
6889 );
6890 cx.background_spawn(async move {
6891 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6892 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6893 // Do not attempt to further process the dummy responses here.
6894 let _response = request_task.await?;
6895 Ok(None)
6896 })
6897 } else {
6898 let servers = buffer.update(cx, |buffer, cx| {
6899 self.running_language_servers_for_local_buffer(buffer, cx)
6900 .map(|(_, server)| server.clone())
6901 .collect::<Vec<_>>()
6902 });
6903
6904 let pull_diagnostics = servers
6905 .into_iter()
6906 .flat_map(|server| {
6907 let result = maybe!({
6908 let local = self.as_local()?;
6909 let server_id = server.server_id();
6910 let providers_with_identifiers = local
6911 .language_server_dynamic_registrations
6912 .get(&server_id)
6913 .into_iter()
6914 .flat_map(|registrations| registrations.diagnostics.clone())
6915 .collect::<Vec<_>>();
6916 Some(
6917 providers_with_identifiers
6918 .into_iter()
6919 .map(|(registration_id, dynamic_caps)| {
6920 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6921 let registration_id = registration_id.map(SharedString::from);
6922 let result_id = self.result_id_for_buffer_pull(
6923 server_id,
6924 buffer_id,
6925 ®istration_id,
6926 cx,
6927 );
6928 self.request_lsp(
6929 buffer.clone(),
6930 LanguageServerToQuery::Other(server_id),
6931 GetDocumentDiagnostics {
6932 previous_result_id: result_id,
6933 registration_id,
6934 identifier,
6935 },
6936 cx,
6937 )
6938 })
6939 .collect::<Vec<_>>(),
6940 )
6941 });
6942
6943 result.unwrap_or_default()
6944 })
6945 .collect::<Vec<_>>();
6946
6947 cx.background_spawn(async move {
6948 let mut responses = Vec::new();
6949 for diagnostics in join_all(pull_diagnostics).await {
6950 responses.extend(diagnostics?);
6951 }
6952 Ok(Some(responses))
6953 })
6954 }
6955 }
6956
6957 pub fn applicable_inlay_chunks(
6958 &mut self,
6959 buffer: &Entity<Buffer>,
6960 ranges: &[Range<text::Anchor>],
6961 cx: &mut Context<Self>,
6962 ) -> Vec<Range<BufferRow>> {
6963 let buffer_snapshot = buffer.read(cx).snapshot();
6964 let ranges = ranges
6965 .iter()
6966 .map(|range| range.to_point(&buffer_snapshot))
6967 .collect::<Vec<_>>();
6968
6969 self.latest_lsp_data(buffer, cx)
6970 .inlay_hints
6971 .applicable_chunks(ranges.as_slice())
6972 .map(|chunk| chunk.row_range())
6973 .collect()
6974 }
6975
6976 pub fn invalidate_inlay_hints<'a>(
6977 &'a mut self,
6978 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6979 ) {
6980 for buffer_id in for_buffers {
6981 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6982 lsp_data.inlay_hints.clear();
6983 }
6984 }
6985 }
6986
6987 pub fn inlay_hints(
6988 &mut self,
6989 invalidate: InvalidationStrategy,
6990 buffer: Entity<Buffer>,
6991 ranges: Vec<Range<text::Anchor>>,
6992 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6993 cx: &mut Context<Self>,
6994 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6995 let next_hint_id = self.next_hint_id.clone();
6996 let lsp_data = self.latest_lsp_data(&buffer, cx);
6997 let query_version = lsp_data.buffer_version.clone();
6998 let mut lsp_refresh_requested = false;
6999 let for_server = if let InvalidationStrategy::RefreshRequested {
7000 server_id,
7001 request_id,
7002 } = invalidate
7003 {
7004 let invalidated = lsp_data
7005 .inlay_hints
7006 .invalidate_for_server_refresh(server_id, request_id);
7007 lsp_refresh_requested = invalidated;
7008 Some(server_id)
7009 } else {
7010 None
7011 };
7012 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7013 let known_chunks = known_chunks
7014 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7015 .map(|(_, known_chunks)| known_chunks)
7016 .unwrap_or_default();
7017
7018 let buffer_snapshot = buffer.read(cx).snapshot();
7019 let ranges = ranges
7020 .iter()
7021 .map(|range| range.to_point(&buffer_snapshot))
7022 .collect::<Vec<_>>();
7023
7024 let mut hint_fetch_tasks = Vec::new();
7025 let mut cached_inlay_hints = None;
7026 let mut ranges_to_query = None;
7027 let applicable_chunks = existing_inlay_hints
7028 .applicable_chunks(ranges.as_slice())
7029 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7030 .collect::<Vec<_>>();
7031 if applicable_chunks.is_empty() {
7032 return HashMap::default();
7033 }
7034
7035 for row_chunk in applicable_chunks {
7036 match (
7037 existing_inlay_hints
7038 .cached_hints(&row_chunk)
7039 .filter(|_| !lsp_refresh_requested)
7040 .cloned(),
7041 existing_inlay_hints
7042 .fetched_hints(&row_chunk)
7043 .as_ref()
7044 .filter(|_| !lsp_refresh_requested)
7045 .cloned(),
7046 ) {
7047 (None, None) => {
7048 let chunk_range = row_chunk.anchor_range();
7049 ranges_to_query
7050 .get_or_insert_with(Vec::new)
7051 .push((row_chunk, chunk_range));
7052 }
7053 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7054 (Some(cached_hints), None) => {
7055 for (server_id, cached_hints) in cached_hints {
7056 if for_server.is_none_or(|for_server| for_server == server_id) {
7057 cached_inlay_hints
7058 .get_or_insert_with(HashMap::default)
7059 .entry(row_chunk.row_range())
7060 .or_insert_with(HashMap::default)
7061 .entry(server_id)
7062 .or_insert_with(Vec::new)
7063 .extend(cached_hints);
7064 }
7065 }
7066 }
7067 (Some(cached_hints), Some(fetched_hints)) => {
7068 hint_fetch_tasks.push((row_chunk, fetched_hints));
7069 for (server_id, cached_hints) in cached_hints {
7070 if for_server.is_none_or(|for_server| for_server == server_id) {
7071 cached_inlay_hints
7072 .get_or_insert_with(HashMap::default)
7073 .entry(row_chunk.row_range())
7074 .or_insert_with(HashMap::default)
7075 .entry(server_id)
7076 .or_insert_with(Vec::new)
7077 .extend(cached_hints);
7078 }
7079 }
7080 }
7081 }
7082 }
7083
7084 if hint_fetch_tasks.is_empty()
7085 && ranges_to_query
7086 .as_ref()
7087 .is_none_or(|ranges| ranges.is_empty())
7088 && let Some(cached_inlay_hints) = cached_inlay_hints
7089 {
7090 cached_inlay_hints
7091 .into_iter()
7092 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7093 .collect()
7094 } else {
7095 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7096 let next_hint_id = next_hint_id.clone();
7097 let buffer = buffer.clone();
7098 let query_version = query_version.clone();
7099 let new_inlay_hints = cx
7100 .spawn(async move |lsp_store, cx| {
7101 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7102 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7103 })?;
7104 new_fetch_task
7105 .await
7106 .and_then(|new_hints_by_server| {
7107 lsp_store.update(cx, |lsp_store, cx| {
7108 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7109 let update_cache = lsp_data.buffer_version == query_version;
7110 if new_hints_by_server.is_empty() {
7111 if update_cache {
7112 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7113 }
7114 HashMap::default()
7115 } else {
7116 new_hints_by_server
7117 .into_iter()
7118 .map(|(server_id, new_hints)| {
7119 let new_hints = new_hints
7120 .into_iter()
7121 .map(|new_hint| {
7122 (
7123 InlayId::Hint(next_hint_id.fetch_add(
7124 1,
7125 atomic::Ordering::AcqRel,
7126 )),
7127 new_hint,
7128 )
7129 })
7130 .collect::<Vec<_>>();
7131 if update_cache {
7132 lsp_data.inlay_hints.insert_new_hints(
7133 chunk,
7134 server_id,
7135 new_hints.clone(),
7136 );
7137 }
7138 (server_id, new_hints)
7139 })
7140 .collect()
7141 }
7142 })
7143 })
7144 .map_err(Arc::new)
7145 })
7146 .shared();
7147
7148 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7149 *fetch_task = Some(new_inlay_hints.clone());
7150 hint_fetch_tasks.push((chunk, new_inlay_hints));
7151 }
7152
7153 cached_inlay_hints
7154 .unwrap_or_default()
7155 .into_iter()
7156 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7157 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7158 (
7159 chunk.row_range(),
7160 cx.spawn(async move |_, _| {
7161 hints_fetch.await.map_err(|e| {
7162 if e.error_code() != ErrorCode::Internal {
7163 anyhow!(e.error_code())
7164 } else {
7165 anyhow!("{e:#}")
7166 }
7167 })
7168 }),
7169 )
7170 }))
7171 .collect()
7172 }
7173 }
7174
7175 fn fetch_inlay_hints(
7176 &mut self,
7177 for_server: Option<LanguageServerId>,
7178 buffer: &Entity<Buffer>,
7179 range: Range<Anchor>,
7180 cx: &mut Context<Self>,
7181 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7182 let request = InlayHints {
7183 range: range.clone(),
7184 };
7185 if let Some((upstream_client, project_id)) = self.upstream_client() {
7186 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7187 return Task::ready(Ok(HashMap::default()));
7188 }
7189 let request_task = upstream_client.request_lsp(
7190 project_id,
7191 for_server.map(|id| id.to_proto()),
7192 LSP_REQUEST_TIMEOUT,
7193 cx.background_executor().clone(),
7194 request.to_proto(project_id, buffer.read(cx)),
7195 );
7196 let buffer = buffer.clone();
7197 cx.spawn(async move |weak_lsp_store, cx| {
7198 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7199 return Ok(HashMap::default());
7200 };
7201 let Some(responses) = request_task.await? else {
7202 return Ok(HashMap::default());
7203 };
7204
7205 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7206 let lsp_store = lsp_store.clone();
7207 let buffer = buffer.clone();
7208 let cx = cx.clone();
7209 let request = request.clone();
7210 async move {
7211 (
7212 LanguageServerId::from_proto(response.server_id),
7213 request
7214 .response_from_proto(response.response, lsp_store, buffer, cx)
7215 .await,
7216 )
7217 }
7218 }))
7219 .await;
7220
7221 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7222 let mut has_errors = false;
7223 let inlay_hints = inlay_hints
7224 .into_iter()
7225 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7226 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7227 Err(e) => {
7228 has_errors = true;
7229 log::error!("{e:#}");
7230 None
7231 }
7232 })
7233 .map(|(server_id, mut new_hints)| {
7234 new_hints.retain(|hint| {
7235 hint.position.is_valid(&buffer_snapshot)
7236 && range.start.is_valid(&buffer_snapshot)
7237 && range.end.is_valid(&buffer_snapshot)
7238 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7239 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7240 });
7241 (server_id, new_hints)
7242 })
7243 .collect::<HashMap<_, _>>();
7244 anyhow::ensure!(
7245 !has_errors || !inlay_hints.is_empty(),
7246 "Failed to fetch inlay hints"
7247 );
7248 Ok(inlay_hints)
7249 })
7250 } else {
7251 let inlay_hints_task = match for_server {
7252 Some(server_id) => {
7253 let server_task = self.request_lsp(
7254 buffer.clone(),
7255 LanguageServerToQuery::Other(server_id),
7256 request,
7257 cx,
7258 );
7259 cx.background_spawn(async move {
7260 let mut responses = Vec::new();
7261 match server_task.await {
7262 Ok(response) => responses.push((server_id, response)),
7263 // rust-analyzer likes to error with this when its still loading up
7264 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7265 Err(e) => log::error!(
7266 "Error handling response for inlay hints request: {e:#}"
7267 ),
7268 }
7269 responses
7270 })
7271 }
7272 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7273 };
7274 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7275 cx.background_spawn(async move {
7276 Ok(inlay_hints_task
7277 .await
7278 .into_iter()
7279 .map(|(server_id, mut new_hints)| {
7280 new_hints.retain(|hint| {
7281 hint.position.is_valid(&buffer_snapshot)
7282 && range.start.is_valid(&buffer_snapshot)
7283 && range.end.is_valid(&buffer_snapshot)
7284 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7285 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7286 });
7287 (server_id, new_hints)
7288 })
7289 .collect())
7290 })
7291 }
7292 }
7293
7294 fn diagnostic_registration_exists(
7295 &self,
7296 server_id: LanguageServerId,
7297 registration_id: &Option<SharedString>,
7298 ) -> bool {
7299 let Some(local) = self.as_local() else {
7300 return false;
7301 };
7302 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7303 else {
7304 return false;
7305 };
7306 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7307 registrations.diagnostics.contains_key(®istration_key)
7308 }
7309
7310 pub fn pull_diagnostics_for_buffer(
7311 &mut self,
7312 buffer: Entity<Buffer>,
7313 cx: &mut Context<Self>,
7314 ) -> Task<anyhow::Result<()>> {
7315 let diagnostics = self.pull_diagnostics(buffer, cx);
7316 cx.spawn(async move |lsp_store, cx| {
7317 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7318 return Ok(());
7319 };
7320 lsp_store.update(cx, |lsp_store, cx| {
7321 if lsp_store.as_local().is_none() {
7322 return;
7323 }
7324
7325 let mut unchanged_buffers = HashMap::default();
7326 let server_diagnostics_updates = diagnostics
7327 .into_iter()
7328 .filter_map(|diagnostics_set| match diagnostics_set {
7329 LspPullDiagnostics::Response {
7330 server_id,
7331 uri,
7332 diagnostics,
7333 registration_id,
7334 } => Some((server_id, uri, diagnostics, registration_id)),
7335 LspPullDiagnostics::Default => None,
7336 })
7337 .filter(|(server_id, _, _, registration_id)| {
7338 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7339 })
7340 .fold(
7341 HashMap::default(),
7342 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7343 let (result_id, diagnostics) = match diagnostics {
7344 PulledDiagnostics::Unchanged { result_id } => {
7345 unchanged_buffers
7346 .entry(new_registration_id.clone())
7347 .or_insert_with(HashSet::default)
7348 .insert(uri.clone());
7349 (Some(result_id), Vec::new())
7350 }
7351 PulledDiagnostics::Changed {
7352 result_id,
7353 diagnostics,
7354 } => (result_id, diagnostics),
7355 };
7356 let disk_based_sources = Cow::Owned(
7357 lsp_store
7358 .language_server_adapter_for_id(server_id)
7359 .as_ref()
7360 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7361 .unwrap_or(&[])
7362 .to_vec(),
7363 );
7364 acc.entry(server_id)
7365 .or_insert_with(HashMap::default)
7366 .entry(new_registration_id.clone())
7367 .or_insert_with(Vec::new)
7368 .push(DocumentDiagnosticsUpdate {
7369 server_id,
7370 diagnostics: lsp::PublishDiagnosticsParams {
7371 uri,
7372 diagnostics,
7373 version: None,
7374 },
7375 result_id,
7376 disk_based_sources,
7377 registration_id: new_registration_id,
7378 });
7379 acc
7380 },
7381 );
7382
7383 for diagnostic_updates in server_diagnostics_updates.into_values() {
7384 for (registration_id, diagnostic_updates) in diagnostic_updates {
7385 lsp_store
7386 .merge_lsp_diagnostics(
7387 DiagnosticSourceKind::Pulled,
7388 diagnostic_updates,
7389 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7390 DiagnosticSourceKind::Pulled => {
7391 old_diagnostic.registration_id != registration_id
7392 || unchanged_buffers
7393 .get(&old_diagnostic.registration_id)
7394 .is_some_and(|unchanged_buffers| {
7395 unchanged_buffers.contains(&document_uri)
7396 })
7397 }
7398 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7399 true
7400 }
7401 },
7402 cx,
7403 )
7404 .log_err();
7405 }
7406 }
7407 })
7408 })
7409 }
7410
7411 pub fn document_colors(
7412 &mut self,
7413 known_cache_version: Option<usize>,
7414 buffer: Entity<Buffer>,
7415 cx: &mut Context<Self>,
7416 ) -> Option<DocumentColorTask> {
7417 let version_queried_for = buffer.read(cx).version();
7418 let buffer_id = buffer.read(cx).remote_id();
7419
7420 let current_language_servers = self.as_local().map(|local| {
7421 local
7422 .buffers_opened_in_servers
7423 .get(&buffer_id)
7424 .cloned()
7425 .unwrap_or_default()
7426 });
7427
7428 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7429 if let Some(cached_colors) = &lsp_data.document_colors {
7430 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7431 let has_different_servers =
7432 current_language_servers.is_some_and(|current_language_servers| {
7433 current_language_servers
7434 != cached_colors.colors.keys().copied().collect()
7435 });
7436 if !has_different_servers {
7437 let cache_version = cached_colors.cache_version;
7438 if Some(cache_version) == known_cache_version {
7439 return None;
7440 } else {
7441 return Some(
7442 Task::ready(Ok(DocumentColors {
7443 colors: cached_colors
7444 .colors
7445 .values()
7446 .flatten()
7447 .cloned()
7448 .collect(),
7449 cache_version: Some(cache_version),
7450 }))
7451 .shared(),
7452 );
7453 }
7454 }
7455 }
7456 }
7457 }
7458
7459 let color_lsp_data = self
7460 .latest_lsp_data(&buffer, cx)
7461 .document_colors
7462 .get_or_insert_default();
7463 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7464 && !version_queried_for.changed_since(updating_for)
7465 {
7466 return Some(running_update.clone());
7467 }
7468 let buffer_version_queried_for = version_queried_for.clone();
7469 let new_task = cx
7470 .spawn(async move |lsp_store, cx| {
7471 cx.background_executor()
7472 .timer(Duration::from_millis(30))
7473 .await;
7474 let fetched_colors = lsp_store
7475 .update(cx, |lsp_store, cx| {
7476 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7477 })?
7478 .await
7479 .context("fetching document colors")
7480 .map_err(Arc::new);
7481 let fetched_colors = match fetched_colors {
7482 Ok(fetched_colors) => {
7483 if buffer.update(cx, |buffer, _| {
7484 buffer.version() != buffer_version_queried_for
7485 }) {
7486 return Ok(DocumentColors::default());
7487 }
7488 fetched_colors
7489 }
7490 Err(e) => {
7491 lsp_store
7492 .update(cx, |lsp_store, _| {
7493 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7494 if let Some(document_colors) = &mut lsp_data.document_colors {
7495 document_colors.colors_update = None;
7496 }
7497 }
7498 })
7499 .ok();
7500 return Err(e);
7501 }
7502 };
7503
7504 lsp_store
7505 .update(cx, |lsp_store, cx| {
7506 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7507 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7508
7509 if let Some(fetched_colors) = fetched_colors {
7510 if lsp_data.buffer_version == buffer_version_queried_for {
7511 lsp_colors.colors.extend(fetched_colors);
7512 lsp_colors.cache_version += 1;
7513 } else if !lsp_data
7514 .buffer_version
7515 .changed_since(&buffer_version_queried_for)
7516 {
7517 lsp_data.buffer_version = buffer_version_queried_for;
7518 lsp_colors.colors = fetched_colors;
7519 lsp_colors.cache_version += 1;
7520 }
7521 }
7522 lsp_colors.colors_update = None;
7523 let colors = lsp_colors
7524 .colors
7525 .values()
7526 .flatten()
7527 .cloned()
7528 .collect::<HashSet<_>>();
7529 DocumentColors {
7530 colors,
7531 cache_version: Some(lsp_colors.cache_version),
7532 }
7533 })
7534 .map_err(Arc::new)
7535 })
7536 .shared();
7537 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7538 Some(new_task)
7539 }
7540
7541 fn fetch_document_colors_for_buffer(
7542 &mut self,
7543 buffer: &Entity<Buffer>,
7544 cx: &mut Context<Self>,
7545 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7546 if let Some((client, project_id)) = self.upstream_client() {
7547 let request = GetDocumentColor {};
7548 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7549 return Task::ready(Ok(None));
7550 }
7551
7552 let request_task = client.request_lsp(
7553 project_id,
7554 None,
7555 LSP_REQUEST_TIMEOUT,
7556 cx.background_executor().clone(),
7557 request.to_proto(project_id, buffer.read(cx)),
7558 );
7559 let buffer = buffer.clone();
7560 cx.spawn(async move |lsp_store, cx| {
7561 let Some(lsp_store) = lsp_store.upgrade() else {
7562 return Ok(None);
7563 };
7564 let colors = join_all(
7565 request_task
7566 .await
7567 .log_err()
7568 .flatten()
7569 .map(|response| response.payload)
7570 .unwrap_or_default()
7571 .into_iter()
7572 .map(|color_response| {
7573 let response = request.response_from_proto(
7574 color_response.response,
7575 lsp_store.clone(),
7576 buffer.clone(),
7577 cx.clone(),
7578 );
7579 async move {
7580 (
7581 LanguageServerId::from_proto(color_response.server_id),
7582 response.await.log_err().unwrap_or_default(),
7583 )
7584 }
7585 }),
7586 )
7587 .await
7588 .into_iter()
7589 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7590 acc.entry(server_id)
7591 .or_insert_with(HashSet::default)
7592 .extend(colors);
7593 acc
7594 });
7595 Ok(Some(colors))
7596 })
7597 } else {
7598 let document_colors_task =
7599 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7600 cx.background_spawn(async move {
7601 Ok(Some(
7602 document_colors_task
7603 .await
7604 .into_iter()
7605 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7606 acc.entry(server_id)
7607 .or_insert_with(HashSet::default)
7608 .extend(colors);
7609 acc
7610 })
7611 .into_iter()
7612 .collect(),
7613 ))
7614 })
7615 }
7616 }
7617
7618 pub fn signature_help<T: ToPointUtf16>(
7619 &mut self,
7620 buffer: &Entity<Buffer>,
7621 position: T,
7622 cx: &mut Context<Self>,
7623 ) -> Task<Option<Vec<SignatureHelp>>> {
7624 let position = position.to_point_utf16(buffer.read(cx));
7625
7626 if let Some((client, upstream_project_id)) = self.upstream_client() {
7627 let request = GetSignatureHelp { position };
7628 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7629 return Task::ready(None);
7630 }
7631 let request_task = client.request_lsp(
7632 upstream_project_id,
7633 None,
7634 LSP_REQUEST_TIMEOUT,
7635 cx.background_executor().clone(),
7636 request.to_proto(upstream_project_id, buffer.read(cx)),
7637 );
7638 let buffer = buffer.clone();
7639 cx.spawn(async move |weak_lsp_store, cx| {
7640 let lsp_store = weak_lsp_store.upgrade()?;
7641 let signatures = join_all(
7642 request_task
7643 .await
7644 .log_err()
7645 .flatten()
7646 .map(|response| response.payload)
7647 .unwrap_or_default()
7648 .into_iter()
7649 .map(|response| {
7650 let response = GetSignatureHelp { position }.response_from_proto(
7651 response.response,
7652 lsp_store.clone(),
7653 buffer.clone(),
7654 cx.clone(),
7655 );
7656 async move { response.await.log_err().flatten() }
7657 }),
7658 )
7659 .await
7660 .into_iter()
7661 .flatten()
7662 .collect();
7663 Some(signatures)
7664 })
7665 } else {
7666 let all_actions_task = self.request_multiple_lsp_locally(
7667 buffer,
7668 Some(position),
7669 GetSignatureHelp { position },
7670 cx,
7671 );
7672 cx.background_spawn(async move {
7673 Some(
7674 all_actions_task
7675 .await
7676 .into_iter()
7677 .flat_map(|(_, actions)| actions)
7678 .collect::<Vec<_>>(),
7679 )
7680 })
7681 }
7682 }
7683
7684 pub fn hover(
7685 &mut self,
7686 buffer: &Entity<Buffer>,
7687 position: PointUtf16,
7688 cx: &mut Context<Self>,
7689 ) -> Task<Option<Vec<Hover>>> {
7690 if let Some((client, upstream_project_id)) = self.upstream_client() {
7691 let request = GetHover { position };
7692 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7693 return Task::ready(None);
7694 }
7695 let request_task = client.request_lsp(
7696 upstream_project_id,
7697 None,
7698 LSP_REQUEST_TIMEOUT,
7699 cx.background_executor().clone(),
7700 request.to_proto(upstream_project_id, buffer.read(cx)),
7701 );
7702 let buffer = buffer.clone();
7703 cx.spawn(async move |weak_lsp_store, cx| {
7704 let lsp_store = weak_lsp_store.upgrade()?;
7705 let hovers = join_all(
7706 request_task
7707 .await
7708 .log_err()
7709 .flatten()
7710 .map(|response| response.payload)
7711 .unwrap_or_default()
7712 .into_iter()
7713 .map(|response| {
7714 let response = GetHover { position }.response_from_proto(
7715 response.response,
7716 lsp_store.clone(),
7717 buffer.clone(),
7718 cx.clone(),
7719 );
7720 async move {
7721 response
7722 .await
7723 .log_err()
7724 .flatten()
7725 .and_then(remove_empty_hover_blocks)
7726 }
7727 }),
7728 )
7729 .await
7730 .into_iter()
7731 .flatten()
7732 .collect();
7733 Some(hovers)
7734 })
7735 } else {
7736 let all_actions_task = self.request_multiple_lsp_locally(
7737 buffer,
7738 Some(position),
7739 GetHover { position },
7740 cx,
7741 );
7742 cx.background_spawn(async move {
7743 Some(
7744 all_actions_task
7745 .await
7746 .into_iter()
7747 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7748 .collect::<Vec<Hover>>(),
7749 )
7750 })
7751 }
7752 }
7753
7754 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7755 let language_registry = self.languages.clone();
7756
7757 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7758 let request = upstream_client.request(proto::GetProjectSymbols {
7759 project_id: *project_id,
7760 query: query.to_string(),
7761 });
7762 cx.foreground_executor().spawn(async move {
7763 let response = request.await?;
7764 let mut symbols = Vec::new();
7765 let core_symbols = response
7766 .symbols
7767 .into_iter()
7768 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7769 .collect::<Vec<_>>();
7770 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7771 .await;
7772 Ok(symbols)
7773 })
7774 } else if let Some(local) = self.as_local() {
7775 struct WorkspaceSymbolsResult {
7776 server_id: LanguageServerId,
7777 lsp_adapter: Arc<CachedLspAdapter>,
7778 worktree: WeakEntity<Worktree>,
7779 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7780 }
7781
7782 let mut requests = Vec::new();
7783 let mut requested_servers = BTreeSet::new();
7784 for (seed, state) in local.language_server_ids.iter() {
7785 let Some(worktree_handle) = self
7786 .worktree_store
7787 .read(cx)
7788 .worktree_for_id(seed.worktree_id, cx)
7789 else {
7790 continue;
7791 };
7792 let worktree = worktree_handle.read(cx);
7793 if !worktree.is_visible() {
7794 continue;
7795 }
7796
7797 if !requested_servers.insert(state.id) {
7798 continue;
7799 }
7800
7801 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7802 Some(LanguageServerState::Running {
7803 adapter, server, ..
7804 }) => (adapter.clone(), server),
7805
7806 _ => continue,
7807 };
7808 let supports_workspace_symbol_request =
7809 match server.capabilities().workspace_symbol_provider {
7810 Some(OneOf::Left(supported)) => supported,
7811 Some(OneOf::Right(_)) => true,
7812 None => false,
7813 };
7814 if !supports_workspace_symbol_request {
7815 continue;
7816 }
7817 let worktree_handle = worktree_handle.clone();
7818 let server_id = server.server_id();
7819 requests.push(
7820 server
7821 .request::<lsp::request::WorkspaceSymbolRequest>(
7822 lsp::WorkspaceSymbolParams {
7823 query: query.to_string(),
7824 ..Default::default()
7825 },
7826 )
7827 .map(move |response| {
7828 let lsp_symbols = response
7829 .into_response()
7830 .context("workspace symbols request")
7831 .log_err()
7832 .flatten()
7833 .map(|symbol_response| match symbol_response {
7834 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7835 flat_responses
7836 .into_iter()
7837 .map(|lsp_symbol| {
7838 (
7839 lsp_symbol.name,
7840 lsp_symbol.kind,
7841 lsp_symbol.location,
7842 )
7843 })
7844 .collect::<Vec<_>>()
7845 }
7846 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7847 nested_responses
7848 .into_iter()
7849 .filter_map(|lsp_symbol| {
7850 let location = match lsp_symbol.location {
7851 OneOf::Left(location) => location,
7852 OneOf::Right(_) => {
7853 log::error!(
7854 "Unexpected: client capabilities \
7855 forbid symbol resolutions in \
7856 workspace.symbol.resolveSupport"
7857 );
7858 return None;
7859 }
7860 };
7861 Some((lsp_symbol.name, lsp_symbol.kind, location))
7862 })
7863 .collect::<Vec<_>>()
7864 }
7865 })
7866 .unwrap_or_default();
7867
7868 WorkspaceSymbolsResult {
7869 server_id,
7870 lsp_adapter,
7871 worktree: worktree_handle.downgrade(),
7872 lsp_symbols,
7873 }
7874 }),
7875 );
7876 }
7877
7878 cx.spawn(async move |this, cx| {
7879 let responses = futures::future::join_all(requests).await;
7880 let this = match this.upgrade() {
7881 Some(this) => this,
7882 None => return Ok(Vec::new()),
7883 };
7884
7885 let mut symbols = Vec::new();
7886 for result in responses {
7887 let core_symbols = this.update(cx, |this, cx| {
7888 result
7889 .lsp_symbols
7890 .into_iter()
7891 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7892 let abs_path = symbol_location.uri.to_file_path().ok()?;
7893 let source_worktree = result.worktree.upgrade()?;
7894 let source_worktree_id = source_worktree.read(cx).id();
7895
7896 let path = if let Some((tree, rel_path)) =
7897 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7898 {
7899 let worktree_id = tree.read(cx).id();
7900 SymbolLocation::InProject(ProjectPath {
7901 worktree_id,
7902 path: rel_path,
7903 })
7904 } else {
7905 SymbolLocation::OutsideProject {
7906 signature: this.symbol_signature(&abs_path),
7907 abs_path: abs_path.into(),
7908 }
7909 };
7910
7911 Some(CoreSymbol {
7912 source_language_server_id: result.server_id,
7913 language_server_name: result.lsp_adapter.name.clone(),
7914 source_worktree_id,
7915 path,
7916 kind: symbol_kind,
7917 name: symbol_name,
7918 range: range_from_lsp(symbol_location.range),
7919 })
7920 })
7921 .collect::<Vec<_>>()
7922 });
7923
7924 populate_labels_for_symbols(
7925 core_symbols,
7926 &language_registry,
7927 Some(result.lsp_adapter),
7928 &mut symbols,
7929 )
7930 .await;
7931 }
7932
7933 Ok(symbols)
7934 })
7935 } else {
7936 Task::ready(Err(anyhow!("No upstream client or local language server")))
7937 }
7938 }
7939
7940 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7941 let mut summary = DiagnosticSummary::default();
7942 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7943 summary.error_count += path_summary.error_count;
7944 summary.warning_count += path_summary.warning_count;
7945 }
7946 summary
7947 }
7948
7949 /// Returns the diagnostic summary for a specific project path.
7950 pub fn diagnostic_summary_for_path(
7951 &self,
7952 project_path: &ProjectPath,
7953 _: &App,
7954 ) -> DiagnosticSummary {
7955 if let Some(summaries) = self
7956 .diagnostic_summaries
7957 .get(&project_path.worktree_id)
7958 .and_then(|map| map.get(&project_path.path))
7959 {
7960 let (error_count, warning_count) = summaries.iter().fold(
7961 (0, 0),
7962 |(error_count, warning_count), (_language_server_id, summary)| {
7963 (
7964 error_count + summary.error_count,
7965 warning_count + summary.warning_count,
7966 )
7967 },
7968 );
7969
7970 DiagnosticSummary {
7971 error_count,
7972 warning_count,
7973 }
7974 } else {
7975 DiagnosticSummary::default()
7976 }
7977 }
7978
7979 pub fn diagnostic_summaries<'a>(
7980 &'a self,
7981 include_ignored: bool,
7982 cx: &'a App,
7983 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7984 self.worktree_store
7985 .read(cx)
7986 .visible_worktrees(cx)
7987 .filter_map(|worktree| {
7988 let worktree = worktree.read(cx);
7989 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7990 })
7991 .flat_map(move |(worktree, summaries)| {
7992 let worktree_id = worktree.id();
7993 summaries
7994 .iter()
7995 .filter(move |(path, _)| {
7996 include_ignored
7997 || worktree
7998 .entry_for_path(path.as_ref())
7999 .is_some_and(|entry| !entry.is_ignored)
8000 })
8001 .flat_map(move |(path, summaries)| {
8002 summaries.iter().map(move |(server_id, summary)| {
8003 (
8004 ProjectPath {
8005 worktree_id,
8006 path: path.clone(),
8007 },
8008 *server_id,
8009 *summary,
8010 )
8011 })
8012 })
8013 })
8014 }
8015
8016 pub fn on_buffer_edited(
8017 &mut self,
8018 buffer: Entity<Buffer>,
8019 cx: &mut Context<Self>,
8020 ) -> Option<()> {
8021 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8022 Some(
8023 self.as_local()?
8024 .language_servers_for_buffer(buffer, cx)
8025 .map(|i| i.1.clone())
8026 .collect(),
8027 )
8028 })?;
8029
8030 let buffer = buffer.read(cx);
8031 let file = File::from_dyn(buffer.file())?;
8032 let abs_path = file.as_local()?.abs_path(cx);
8033 let uri = lsp::Uri::from_file_path(&abs_path)
8034 .ok()
8035 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8036 .log_err()?;
8037 let next_snapshot = buffer.text_snapshot();
8038 for language_server in language_servers {
8039 let language_server = language_server.clone();
8040
8041 let buffer_snapshots = self
8042 .as_local_mut()?
8043 .buffer_snapshots
8044 .get_mut(&buffer.remote_id())
8045 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8046 let previous_snapshot = buffer_snapshots.last()?;
8047
8048 let build_incremental_change = || {
8049 buffer
8050 .edits_since::<Dimensions<PointUtf16, usize>>(
8051 previous_snapshot.snapshot.version(),
8052 )
8053 .map(|edit| {
8054 let edit_start = edit.new.start.0;
8055 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8056 let new_text = next_snapshot
8057 .text_for_range(edit.new.start.1..edit.new.end.1)
8058 .collect();
8059 lsp::TextDocumentContentChangeEvent {
8060 range: Some(lsp::Range::new(
8061 point_to_lsp(edit_start),
8062 point_to_lsp(edit_end),
8063 )),
8064 range_length: None,
8065 text: new_text,
8066 }
8067 })
8068 .collect()
8069 };
8070
8071 let document_sync_kind = language_server
8072 .capabilities()
8073 .text_document_sync
8074 .as_ref()
8075 .and_then(|sync| match sync {
8076 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8077 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8078 });
8079
8080 let content_changes: Vec<_> = match document_sync_kind {
8081 Some(lsp::TextDocumentSyncKind::FULL) => {
8082 vec![lsp::TextDocumentContentChangeEvent {
8083 range: None,
8084 range_length: None,
8085 text: next_snapshot.text(),
8086 }]
8087 }
8088 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8089 _ => {
8090 #[cfg(any(test, feature = "test-support"))]
8091 {
8092 build_incremental_change()
8093 }
8094
8095 #[cfg(not(any(test, feature = "test-support")))]
8096 {
8097 continue;
8098 }
8099 }
8100 };
8101
8102 let next_version = previous_snapshot.version + 1;
8103 buffer_snapshots.push(LspBufferSnapshot {
8104 version: next_version,
8105 snapshot: next_snapshot.clone(),
8106 });
8107
8108 language_server
8109 .notify::<lsp::notification::DidChangeTextDocument>(
8110 lsp::DidChangeTextDocumentParams {
8111 text_document: lsp::VersionedTextDocumentIdentifier::new(
8112 uri.clone(),
8113 next_version,
8114 ),
8115 content_changes,
8116 },
8117 )
8118 .ok();
8119 self.pull_workspace_diagnostics(language_server.server_id());
8120 }
8121
8122 None
8123 }
8124
8125 pub fn on_buffer_saved(
8126 &mut self,
8127 buffer: Entity<Buffer>,
8128 cx: &mut Context<Self>,
8129 ) -> Option<()> {
8130 let file = File::from_dyn(buffer.read(cx).file())?;
8131 let worktree_id = file.worktree_id(cx);
8132 let abs_path = file.as_local()?.abs_path(cx);
8133 let text_document = lsp::TextDocumentIdentifier {
8134 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8135 };
8136 let local = self.as_local()?;
8137
8138 for server in local.language_servers_for_worktree(worktree_id) {
8139 if let Some(include_text) = include_text(server.as_ref()) {
8140 let text = if include_text {
8141 Some(buffer.read(cx).text())
8142 } else {
8143 None
8144 };
8145 server
8146 .notify::<lsp::notification::DidSaveTextDocument>(
8147 lsp::DidSaveTextDocumentParams {
8148 text_document: text_document.clone(),
8149 text,
8150 },
8151 )
8152 .ok();
8153 }
8154 }
8155
8156 let language_servers = buffer.update(cx, |buffer, cx| {
8157 local.language_server_ids_for_buffer(buffer, cx)
8158 });
8159 for language_server_id in language_servers {
8160 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8161 }
8162
8163 None
8164 }
8165
8166 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8167 maybe!(async move {
8168 let mut refreshed_servers = HashSet::default();
8169 let servers = lsp_store
8170 .update(cx, |lsp_store, cx| {
8171 let local = lsp_store.as_local()?;
8172
8173 let servers = local
8174 .language_server_ids
8175 .iter()
8176 .filter_map(|(seed, state)| {
8177 let worktree = lsp_store
8178 .worktree_store
8179 .read(cx)
8180 .worktree_for_id(seed.worktree_id, cx);
8181 let delegate: Arc<dyn LspAdapterDelegate> =
8182 worktree.map(|worktree| {
8183 LocalLspAdapterDelegate::new(
8184 local.languages.clone(),
8185 &local.environment,
8186 cx.weak_entity(),
8187 &worktree,
8188 local.http_client.clone(),
8189 local.fs.clone(),
8190 cx,
8191 )
8192 })?;
8193 let server_id = state.id;
8194
8195 let states = local.language_servers.get(&server_id)?;
8196
8197 match states {
8198 LanguageServerState::Starting { .. } => None,
8199 LanguageServerState::Running {
8200 adapter, server, ..
8201 } => {
8202 let adapter = adapter.clone();
8203 let server = server.clone();
8204 refreshed_servers.insert(server.name());
8205 let toolchain = seed.toolchain.clone();
8206 Some(cx.spawn(async move |_, cx| {
8207 let settings =
8208 LocalLspStore::workspace_configuration_for_adapter(
8209 adapter.adapter.clone(),
8210 &delegate,
8211 toolchain,
8212 None,
8213 cx,
8214 )
8215 .await
8216 .ok()?;
8217 server
8218 .notify::<lsp::notification::DidChangeConfiguration>(
8219 lsp::DidChangeConfigurationParams { settings },
8220 )
8221 .ok()?;
8222 Some(())
8223 }))
8224 }
8225 }
8226 })
8227 .collect::<Vec<_>>();
8228
8229 Some(servers)
8230 })
8231 .ok()
8232 .flatten()?;
8233
8234 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8235 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8236 // to stop and unregister its language server wrapper.
8237 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8238 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8239 let _: Vec<Option<()>> = join_all(servers).await;
8240
8241 Some(())
8242 })
8243 .await;
8244 }
8245
8246 fn maintain_workspace_config(
8247 external_refresh_requests: watch::Receiver<()>,
8248 cx: &mut Context<Self>,
8249 ) -> Task<Result<()>> {
8250 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8251 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8252
8253 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8254 *settings_changed_tx.borrow_mut() = ();
8255 });
8256
8257 let mut joint_future =
8258 futures::stream::select(settings_changed_rx, external_refresh_requests);
8259 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8260 // - 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).
8261 // - 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.
8262 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8263 // - 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,
8264 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8265 cx.spawn(async move |this, cx| {
8266 while let Some(()) = joint_future.next().await {
8267 this.update(cx, |this, cx| {
8268 this.refresh_server_tree(cx);
8269 })
8270 .ok();
8271
8272 Self::refresh_workspace_configurations(&this, cx).await;
8273 }
8274
8275 drop(settings_observation);
8276 anyhow::Ok(())
8277 })
8278 }
8279
8280 pub fn running_language_servers_for_local_buffer<'a>(
8281 &'a self,
8282 buffer: &Buffer,
8283 cx: &mut App,
8284 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8285 let local = self.as_local();
8286 let language_server_ids = local
8287 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8288 .unwrap_or_default();
8289
8290 language_server_ids
8291 .into_iter()
8292 .filter_map(
8293 move |server_id| match local?.language_servers.get(&server_id)? {
8294 LanguageServerState::Running {
8295 adapter, server, ..
8296 } => Some((adapter, server)),
8297 _ => None,
8298 },
8299 )
8300 }
8301
8302 pub fn language_servers_for_local_buffer(
8303 &self,
8304 buffer: &Buffer,
8305 cx: &mut App,
8306 ) -> Vec<LanguageServerId> {
8307 let local = self.as_local();
8308 local
8309 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8310 .unwrap_or_default()
8311 }
8312
8313 pub fn language_server_for_local_buffer<'a>(
8314 &'a self,
8315 buffer: &'a Buffer,
8316 server_id: LanguageServerId,
8317 cx: &'a mut App,
8318 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8319 self.as_local()?
8320 .language_servers_for_buffer(buffer, cx)
8321 .find(|(_, s)| s.server_id() == server_id)
8322 }
8323
8324 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8325 self.diagnostic_summaries.remove(&id_to_remove);
8326 if let Some(local) = self.as_local_mut() {
8327 let to_remove = local.remove_worktree(id_to_remove, cx);
8328 for server in to_remove {
8329 self.language_server_statuses.remove(&server);
8330 }
8331 }
8332 }
8333
8334 pub fn shared(
8335 &mut self,
8336 project_id: u64,
8337 downstream_client: AnyProtoClient,
8338 _: &mut Context<Self>,
8339 ) {
8340 self.downstream_client = Some((downstream_client.clone(), project_id));
8341
8342 for (server_id, status) in &self.language_server_statuses {
8343 if let Some(server) = self.language_server_for_id(*server_id) {
8344 downstream_client
8345 .send(proto::StartLanguageServer {
8346 project_id,
8347 server: Some(proto::LanguageServer {
8348 id: server_id.to_proto(),
8349 name: status.name.to_string(),
8350 worktree_id: status.worktree.map(|id| id.to_proto()),
8351 }),
8352 capabilities: serde_json::to_string(&server.capabilities())
8353 .expect("serializing server LSP capabilities"),
8354 })
8355 .log_err();
8356 }
8357 }
8358 }
8359
8360 pub fn disconnected_from_host(&mut self) {
8361 self.downstream_client.take();
8362 }
8363
8364 pub fn disconnected_from_ssh_remote(&mut self) {
8365 if let LspStoreMode::Remote(RemoteLspStore {
8366 upstream_client, ..
8367 }) = &mut self.mode
8368 {
8369 upstream_client.take();
8370 }
8371 }
8372
8373 pub(crate) fn set_language_server_statuses_from_proto(
8374 &mut self,
8375 project: WeakEntity<Project>,
8376 language_servers: Vec<proto::LanguageServer>,
8377 server_capabilities: Vec<String>,
8378 cx: &mut Context<Self>,
8379 ) {
8380 let lsp_logs = cx
8381 .try_global::<GlobalLogStore>()
8382 .map(|lsp_store| lsp_store.0.clone());
8383
8384 self.language_server_statuses = language_servers
8385 .into_iter()
8386 .zip(server_capabilities)
8387 .map(|(server, server_capabilities)| {
8388 let server_id = LanguageServerId(server.id as usize);
8389 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8390 self.lsp_server_capabilities
8391 .insert(server_id, server_capabilities);
8392 }
8393
8394 let name = LanguageServerName::from_proto(server.name);
8395 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8396
8397 if let Some(lsp_logs) = &lsp_logs {
8398 lsp_logs.update(cx, |lsp_logs, cx| {
8399 lsp_logs.add_language_server(
8400 // Only remote clients get their language servers set from proto
8401 LanguageServerKind::Remote {
8402 project: project.clone(),
8403 },
8404 server_id,
8405 Some(name.clone()),
8406 worktree,
8407 None,
8408 cx,
8409 );
8410 });
8411 }
8412
8413 (
8414 server_id,
8415 LanguageServerStatus {
8416 name,
8417 server_version: None,
8418 pending_work: Default::default(),
8419 has_pending_diagnostic_updates: false,
8420 progress_tokens: Default::default(),
8421 worktree,
8422 binary: None,
8423 configuration: None,
8424 workspace_folders: BTreeSet::new(),
8425 },
8426 )
8427 })
8428 .collect();
8429 }
8430
8431 #[cfg(test)]
8432 pub fn update_diagnostic_entries(
8433 &mut self,
8434 server_id: LanguageServerId,
8435 abs_path: PathBuf,
8436 result_id: Option<SharedString>,
8437 version: Option<i32>,
8438 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8439 cx: &mut Context<Self>,
8440 ) -> anyhow::Result<()> {
8441 self.merge_diagnostic_entries(
8442 vec![DocumentDiagnosticsUpdate {
8443 diagnostics: DocumentDiagnostics {
8444 diagnostics,
8445 document_abs_path: abs_path,
8446 version,
8447 },
8448 result_id,
8449 server_id,
8450 disk_based_sources: Cow::Borrowed(&[]),
8451 registration_id: None,
8452 }],
8453 |_, _, _| false,
8454 cx,
8455 )?;
8456 Ok(())
8457 }
8458
8459 pub fn merge_diagnostic_entries<'a>(
8460 &mut self,
8461 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8462 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8463 cx: &mut Context<Self>,
8464 ) -> anyhow::Result<()> {
8465 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8466 let mut updated_diagnostics_paths = HashMap::default();
8467 for mut update in diagnostic_updates {
8468 let abs_path = &update.diagnostics.document_abs_path;
8469 let server_id = update.server_id;
8470 let Some((worktree, relative_path)) =
8471 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8472 else {
8473 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8474 return Ok(());
8475 };
8476
8477 let worktree_id = worktree.read(cx).id();
8478 let project_path = ProjectPath {
8479 worktree_id,
8480 path: relative_path,
8481 };
8482
8483 let document_uri = lsp::Uri::from_file_path(abs_path)
8484 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8485 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8486 let snapshot = buffer_handle.read(cx).snapshot();
8487 let buffer = buffer_handle.read(cx);
8488 let reused_diagnostics = buffer
8489 .buffer_diagnostics(Some(server_id))
8490 .iter()
8491 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8492 .map(|v| {
8493 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8494 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8495 DiagnosticEntry {
8496 range: start..end,
8497 diagnostic: v.diagnostic.clone(),
8498 }
8499 })
8500 .collect::<Vec<_>>();
8501
8502 self.as_local_mut()
8503 .context("cannot merge diagnostics on a remote LspStore")?
8504 .update_buffer_diagnostics(
8505 &buffer_handle,
8506 server_id,
8507 Some(update.registration_id),
8508 update.result_id,
8509 update.diagnostics.version,
8510 update.diagnostics.diagnostics.clone(),
8511 reused_diagnostics.clone(),
8512 cx,
8513 )?;
8514
8515 update.diagnostics.diagnostics.extend(reused_diagnostics);
8516 } else if let Some(local) = self.as_local() {
8517 let reused_diagnostics = local
8518 .diagnostics
8519 .get(&worktree_id)
8520 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8521 .and_then(|diagnostics_by_server_id| {
8522 diagnostics_by_server_id
8523 .binary_search_by_key(&server_id, |e| e.0)
8524 .ok()
8525 .map(|ix| &diagnostics_by_server_id[ix].1)
8526 })
8527 .into_iter()
8528 .flatten()
8529 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8530
8531 update
8532 .diagnostics
8533 .diagnostics
8534 .extend(reused_diagnostics.cloned());
8535 }
8536
8537 let updated = worktree.update(cx, |worktree, cx| {
8538 self.update_worktree_diagnostics(
8539 worktree.id(),
8540 server_id,
8541 project_path.path.clone(),
8542 update.diagnostics.diagnostics,
8543 cx,
8544 )
8545 })?;
8546 match updated {
8547 ControlFlow::Continue(new_summary) => {
8548 if let Some((project_id, new_summary)) = new_summary {
8549 match &mut diagnostics_summary {
8550 Some(diagnostics_summary) => {
8551 diagnostics_summary
8552 .more_summaries
8553 .push(proto::DiagnosticSummary {
8554 path: project_path.path.as_ref().to_proto(),
8555 language_server_id: server_id.0 as u64,
8556 error_count: new_summary.error_count,
8557 warning_count: new_summary.warning_count,
8558 })
8559 }
8560 None => {
8561 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8562 project_id,
8563 worktree_id: worktree_id.to_proto(),
8564 summary: Some(proto::DiagnosticSummary {
8565 path: project_path.path.as_ref().to_proto(),
8566 language_server_id: server_id.0 as u64,
8567 error_count: new_summary.error_count,
8568 warning_count: new_summary.warning_count,
8569 }),
8570 more_summaries: Vec::new(),
8571 })
8572 }
8573 }
8574 }
8575 updated_diagnostics_paths
8576 .entry(server_id)
8577 .or_insert_with(Vec::new)
8578 .push(project_path);
8579 }
8580 ControlFlow::Break(()) => {}
8581 }
8582 }
8583
8584 if let Some((diagnostics_summary, (downstream_client, _))) =
8585 diagnostics_summary.zip(self.downstream_client.as_ref())
8586 {
8587 downstream_client.send(diagnostics_summary).log_err();
8588 }
8589 for (server_id, paths) in updated_diagnostics_paths {
8590 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8591 }
8592 Ok(())
8593 }
8594
8595 fn update_worktree_diagnostics(
8596 &mut self,
8597 worktree_id: WorktreeId,
8598 server_id: LanguageServerId,
8599 path_in_worktree: Arc<RelPath>,
8600 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8601 _: &mut Context<Worktree>,
8602 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8603 let local = match &mut self.mode {
8604 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8605 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8606 };
8607
8608 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8609 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8610 let summaries_by_server_id = summaries_for_tree
8611 .entry(path_in_worktree.clone())
8612 .or_default();
8613
8614 let old_summary = summaries_by_server_id
8615 .remove(&server_id)
8616 .unwrap_or_default();
8617
8618 let new_summary = DiagnosticSummary::new(&diagnostics);
8619 if diagnostics.is_empty() {
8620 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8621 {
8622 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8623 diagnostics_by_server_id.remove(ix);
8624 }
8625 if diagnostics_by_server_id.is_empty() {
8626 diagnostics_for_tree.remove(&path_in_worktree);
8627 }
8628 }
8629 } else {
8630 summaries_by_server_id.insert(server_id, new_summary);
8631 let diagnostics_by_server_id = diagnostics_for_tree
8632 .entry(path_in_worktree.clone())
8633 .or_default();
8634 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8635 Ok(ix) => {
8636 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8637 }
8638 Err(ix) => {
8639 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8640 }
8641 }
8642 }
8643
8644 if !old_summary.is_empty() || !new_summary.is_empty() {
8645 if let Some((_, project_id)) = &self.downstream_client {
8646 Ok(ControlFlow::Continue(Some((
8647 *project_id,
8648 proto::DiagnosticSummary {
8649 path: path_in_worktree.to_proto(),
8650 language_server_id: server_id.0 as u64,
8651 error_count: new_summary.error_count as u32,
8652 warning_count: new_summary.warning_count as u32,
8653 },
8654 ))))
8655 } else {
8656 Ok(ControlFlow::Continue(None))
8657 }
8658 } else {
8659 Ok(ControlFlow::Break(()))
8660 }
8661 }
8662
8663 pub fn open_buffer_for_symbol(
8664 &mut self,
8665 symbol: &Symbol,
8666 cx: &mut Context<Self>,
8667 ) -> Task<Result<Entity<Buffer>>> {
8668 if let Some((client, project_id)) = self.upstream_client() {
8669 let request = client.request(proto::OpenBufferForSymbol {
8670 project_id,
8671 symbol: Some(Self::serialize_symbol(symbol)),
8672 });
8673 cx.spawn(async move |this, cx| {
8674 let response = request.await?;
8675 let buffer_id = BufferId::new(response.buffer_id)?;
8676 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8677 .await
8678 })
8679 } else if let Some(local) = self.as_local() {
8680 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8681 seed.worktree_id == symbol.source_worktree_id
8682 && state.id == symbol.source_language_server_id
8683 && symbol.language_server_name == seed.name
8684 });
8685 if !is_valid {
8686 return Task::ready(Err(anyhow!(
8687 "language server for worktree and language not found"
8688 )));
8689 };
8690
8691 let symbol_abs_path = match &symbol.path {
8692 SymbolLocation::InProject(project_path) => self
8693 .worktree_store
8694 .read(cx)
8695 .absolutize(&project_path, cx)
8696 .context("no such worktree"),
8697 SymbolLocation::OutsideProject {
8698 abs_path,
8699 signature: _,
8700 } => Ok(abs_path.to_path_buf()),
8701 };
8702 let symbol_abs_path = match symbol_abs_path {
8703 Ok(abs_path) => abs_path,
8704 Err(err) => return Task::ready(Err(err)),
8705 };
8706 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8707 uri
8708 } else {
8709 return Task::ready(Err(anyhow!("invalid symbol path")));
8710 };
8711
8712 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8713 } else {
8714 Task::ready(Err(anyhow!("no upstream client or local store")))
8715 }
8716 }
8717
8718 pub(crate) fn open_local_buffer_via_lsp(
8719 &mut self,
8720 abs_path: lsp::Uri,
8721 language_server_id: LanguageServerId,
8722 cx: &mut Context<Self>,
8723 ) -> Task<Result<Entity<Buffer>>> {
8724 cx.spawn(async move |lsp_store, cx| {
8725 // Escape percent-encoded string.
8726 let current_scheme = abs_path.scheme().to_owned();
8727 // Uri is immutable, so we can't modify the scheme
8728
8729 let abs_path = abs_path
8730 .to_file_path()
8731 .map_err(|()| anyhow!("can't convert URI to path"))?;
8732 let p = abs_path.clone();
8733 let yarn_worktree = lsp_store
8734 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8735 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8736 cx.spawn(async move |this, cx| {
8737 let t = this
8738 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8739 .ok()?;
8740 t.await
8741 })
8742 }),
8743 None => Task::ready(None),
8744 })?
8745 .await;
8746 let (worktree_root_target, known_relative_path) =
8747 if let Some((zip_root, relative_path)) = yarn_worktree {
8748 (zip_root, Some(relative_path))
8749 } else {
8750 (Arc::<Path>::from(abs_path.as_path()), None)
8751 };
8752 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8753 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8754 worktree_store.find_worktree(&worktree_root_target, cx)
8755 })
8756 })?;
8757 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8758 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8759 (result.0, relative_path, None)
8760 } else {
8761 let worktree = lsp_store
8762 .update(cx, |lsp_store, cx| {
8763 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8764 worktree_store.create_worktree(&worktree_root_target, false, cx)
8765 })
8766 })?
8767 .await?;
8768 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8769 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8770 lsp_store
8771 .update(cx, |lsp_store, cx| {
8772 if let Some(local) = lsp_store.as_local_mut() {
8773 local.register_language_server_for_invisible_worktree(
8774 &worktree,
8775 language_server_id,
8776 cx,
8777 )
8778 }
8779 match lsp_store.language_server_statuses.get(&language_server_id) {
8780 Some(status) => status.worktree,
8781 None => None,
8782 }
8783 })
8784 .ok()
8785 .flatten()
8786 .zip(Some(worktree_root.clone()))
8787 } else {
8788 None
8789 };
8790 let relative_path = if let Some(known_path) = known_relative_path {
8791 known_path
8792 } else {
8793 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8794 .into_arc()
8795 };
8796 (worktree, relative_path, source_ws)
8797 };
8798 let project_path = ProjectPath {
8799 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8800 path: relative_path,
8801 };
8802 let buffer = lsp_store
8803 .update(cx, |lsp_store, cx| {
8804 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8805 buffer_store.open_buffer(project_path, cx)
8806 })
8807 })?
8808 .await?;
8809 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8810 if let Some((source_ws, worktree_root)) = source_ws {
8811 buffer.update(cx, |buffer, cx| {
8812 let settings = WorktreeSettings::get(
8813 Some(
8814 (&ProjectPath {
8815 worktree_id: source_ws,
8816 path: Arc::from(RelPath::empty()),
8817 })
8818 .into(),
8819 ),
8820 cx,
8821 );
8822 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8823 if is_read_only {
8824 buffer.set_capability(Capability::ReadOnly, cx);
8825 }
8826 });
8827 }
8828 Ok(buffer)
8829 })
8830 }
8831
8832 fn request_multiple_lsp_locally<P, R>(
8833 &mut self,
8834 buffer: &Entity<Buffer>,
8835 position: Option<P>,
8836 request: R,
8837 cx: &mut Context<Self>,
8838 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8839 where
8840 P: ToOffset,
8841 R: LspCommand + Clone,
8842 <R::LspRequest as lsp::request::Request>::Result: Send,
8843 <R::LspRequest as lsp::request::Request>::Params: Send,
8844 {
8845 let Some(local) = self.as_local() else {
8846 return Task::ready(Vec::new());
8847 };
8848
8849 let snapshot = buffer.read(cx).snapshot();
8850 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8851
8852 let server_ids = buffer.update(cx, |buffer, cx| {
8853 local
8854 .language_servers_for_buffer(buffer, cx)
8855 .filter(|(adapter, _)| {
8856 scope
8857 .as_ref()
8858 .map(|scope| scope.language_allowed(&adapter.name))
8859 .unwrap_or(true)
8860 })
8861 .map(|(_, server)| server.server_id())
8862 .filter(|server_id| {
8863 self.as_local().is_none_or(|local| {
8864 local
8865 .buffers_opened_in_servers
8866 .get(&snapshot.remote_id())
8867 .is_some_and(|servers| servers.contains(server_id))
8868 })
8869 })
8870 .collect::<Vec<_>>()
8871 });
8872
8873 let mut response_results = server_ids
8874 .into_iter()
8875 .map(|server_id| {
8876 let task = self.request_lsp(
8877 buffer.clone(),
8878 LanguageServerToQuery::Other(server_id),
8879 request.clone(),
8880 cx,
8881 );
8882 async move { (server_id, task.await) }
8883 })
8884 .collect::<FuturesUnordered<_>>();
8885
8886 cx.background_spawn(async move {
8887 let mut responses = Vec::with_capacity(response_results.len());
8888 while let Some((server_id, response_result)) = response_results.next().await {
8889 match response_result {
8890 Ok(response) => responses.push((server_id, response)),
8891 // rust-analyzer likes to error with this when its still loading up
8892 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8893 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8894 }
8895 }
8896 responses
8897 })
8898 }
8899
8900 async fn handle_lsp_get_completions(
8901 this: Entity<Self>,
8902 envelope: TypedEnvelope<proto::GetCompletions>,
8903 mut cx: AsyncApp,
8904 ) -> Result<proto::GetCompletionsResponse> {
8905 let sender_id = envelope.original_sender_id().unwrap_or_default();
8906
8907 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8908 let buffer_handle = this.update(&mut cx, |this, cx| {
8909 this.buffer_store.read(cx).get_existing(buffer_id)
8910 })?;
8911 let request = GetCompletions::from_proto(
8912 envelope.payload,
8913 this.clone(),
8914 buffer_handle.clone(),
8915 cx.clone(),
8916 )
8917 .await?;
8918
8919 let server_to_query = match request.server_id {
8920 Some(server_id) => LanguageServerToQuery::Other(server_id),
8921 None => LanguageServerToQuery::FirstCapable,
8922 };
8923
8924 let response = this
8925 .update(&mut cx, |this, cx| {
8926 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8927 })
8928 .await?;
8929 this.update(&mut cx, |this, cx| {
8930 Ok(GetCompletions::response_to_proto(
8931 response,
8932 this,
8933 sender_id,
8934 &buffer_handle.read(cx).version(),
8935 cx,
8936 ))
8937 })
8938 }
8939
8940 async fn handle_lsp_command<T: LspCommand>(
8941 this: Entity<Self>,
8942 envelope: TypedEnvelope<T::ProtoRequest>,
8943 mut cx: AsyncApp,
8944 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8945 where
8946 <T::LspRequest as lsp::request::Request>::Params: Send,
8947 <T::LspRequest as lsp::request::Request>::Result: Send,
8948 {
8949 let sender_id = envelope.original_sender_id().unwrap_or_default();
8950 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8951 let buffer_handle = this.update(&mut cx, |this, cx| {
8952 this.buffer_store.read(cx).get_existing(buffer_id)
8953 })?;
8954 let request = T::from_proto(
8955 envelope.payload,
8956 this.clone(),
8957 buffer_handle.clone(),
8958 cx.clone(),
8959 )
8960 .await?;
8961 let response = this
8962 .update(&mut cx, |this, cx| {
8963 this.request_lsp(
8964 buffer_handle.clone(),
8965 LanguageServerToQuery::FirstCapable,
8966 request,
8967 cx,
8968 )
8969 })
8970 .await?;
8971 this.update(&mut cx, |this, cx| {
8972 Ok(T::response_to_proto(
8973 response,
8974 this,
8975 sender_id,
8976 &buffer_handle.read(cx).version(),
8977 cx,
8978 ))
8979 })
8980 }
8981
8982 async fn handle_lsp_query(
8983 lsp_store: Entity<Self>,
8984 envelope: TypedEnvelope<proto::LspQuery>,
8985 mut cx: AsyncApp,
8986 ) -> Result<proto::Ack> {
8987 use proto::lsp_query::Request;
8988 let sender_id = envelope.original_sender_id().unwrap_or_default();
8989 let lsp_query = envelope.payload;
8990 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8991 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8992 match lsp_query.request.context("invalid LSP query request")? {
8993 Request::GetReferences(get_references) => {
8994 let position = get_references.position.clone().and_then(deserialize_anchor);
8995 Self::query_lsp_locally::<GetReferences>(
8996 lsp_store,
8997 server_id,
8998 sender_id,
8999 lsp_request_id,
9000 get_references,
9001 position,
9002 &mut cx,
9003 )
9004 .await?;
9005 }
9006 Request::GetDocumentColor(get_document_color) => {
9007 Self::query_lsp_locally::<GetDocumentColor>(
9008 lsp_store,
9009 server_id,
9010 sender_id,
9011 lsp_request_id,
9012 get_document_color,
9013 None,
9014 &mut cx,
9015 )
9016 .await?;
9017 }
9018 Request::GetHover(get_hover) => {
9019 let position = get_hover.position.clone().and_then(deserialize_anchor);
9020 Self::query_lsp_locally::<GetHover>(
9021 lsp_store,
9022 server_id,
9023 sender_id,
9024 lsp_request_id,
9025 get_hover,
9026 position,
9027 &mut cx,
9028 )
9029 .await?;
9030 }
9031 Request::GetCodeActions(get_code_actions) => {
9032 Self::query_lsp_locally::<GetCodeActions>(
9033 lsp_store,
9034 server_id,
9035 sender_id,
9036 lsp_request_id,
9037 get_code_actions,
9038 None,
9039 &mut cx,
9040 )
9041 .await?;
9042 }
9043 Request::GetSignatureHelp(get_signature_help) => {
9044 let position = get_signature_help
9045 .position
9046 .clone()
9047 .and_then(deserialize_anchor);
9048 Self::query_lsp_locally::<GetSignatureHelp>(
9049 lsp_store,
9050 server_id,
9051 sender_id,
9052 lsp_request_id,
9053 get_signature_help,
9054 position,
9055 &mut cx,
9056 )
9057 .await?;
9058 }
9059 Request::GetCodeLens(get_code_lens) => {
9060 Self::query_lsp_locally::<GetCodeLens>(
9061 lsp_store,
9062 server_id,
9063 sender_id,
9064 lsp_request_id,
9065 get_code_lens,
9066 None,
9067 &mut cx,
9068 )
9069 .await?;
9070 }
9071 Request::GetDefinition(get_definition) => {
9072 let position = get_definition.position.clone().and_then(deserialize_anchor);
9073 Self::query_lsp_locally::<GetDefinitions>(
9074 lsp_store,
9075 server_id,
9076 sender_id,
9077 lsp_request_id,
9078 get_definition,
9079 position,
9080 &mut cx,
9081 )
9082 .await?;
9083 }
9084 Request::GetDeclaration(get_declaration) => {
9085 let position = get_declaration
9086 .position
9087 .clone()
9088 .and_then(deserialize_anchor);
9089 Self::query_lsp_locally::<GetDeclarations>(
9090 lsp_store,
9091 server_id,
9092 sender_id,
9093 lsp_request_id,
9094 get_declaration,
9095 position,
9096 &mut cx,
9097 )
9098 .await?;
9099 }
9100 Request::GetTypeDefinition(get_type_definition) => {
9101 let position = get_type_definition
9102 .position
9103 .clone()
9104 .and_then(deserialize_anchor);
9105 Self::query_lsp_locally::<GetTypeDefinitions>(
9106 lsp_store,
9107 server_id,
9108 sender_id,
9109 lsp_request_id,
9110 get_type_definition,
9111 position,
9112 &mut cx,
9113 )
9114 .await?;
9115 }
9116 Request::GetImplementation(get_implementation) => {
9117 let position = get_implementation
9118 .position
9119 .clone()
9120 .and_then(deserialize_anchor);
9121 Self::query_lsp_locally::<GetImplementations>(
9122 lsp_store,
9123 server_id,
9124 sender_id,
9125 lsp_request_id,
9126 get_implementation,
9127 position,
9128 &mut cx,
9129 )
9130 .await?;
9131 }
9132 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9133 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9134 let version = deserialize_version(get_document_diagnostics.buffer_version());
9135 let buffer = lsp_store.update(&mut cx, |this, cx| {
9136 this.buffer_store.read(cx).get_existing(buffer_id)
9137 })?;
9138 buffer
9139 .update(&mut cx, |buffer, _| {
9140 buffer.wait_for_version(version.clone())
9141 })
9142 .await?;
9143 lsp_store.update(&mut cx, |lsp_store, cx| {
9144 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9145 let key = LspKey {
9146 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9147 server_queried: server_id,
9148 };
9149 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9150 ) {
9151 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9152 lsp_requests.clear();
9153 };
9154 }
9155
9156 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9157 existing_queries.insert(
9158 lsp_request_id,
9159 cx.spawn(async move |lsp_store, cx| {
9160 let diagnostics_pull = lsp_store.update(cx, |lsp_store, cx| {
9161 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9162 });
9163 if let Ok(diagnostics_pull) = diagnostics_pull {
9164 match diagnostics_pull.await {
9165 Ok(()) => {}
9166 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9167 };
9168 }
9169 }),
9170 );
9171 });
9172 }
9173 Request::InlayHints(inlay_hints) => {
9174 let query_start = inlay_hints
9175 .start
9176 .clone()
9177 .and_then(deserialize_anchor)
9178 .context("invalid inlay hints range start")?;
9179 let query_end = inlay_hints
9180 .end
9181 .clone()
9182 .and_then(deserialize_anchor)
9183 .context("invalid inlay hints range end")?;
9184 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9185 &lsp_store,
9186 server_id,
9187 lsp_request_id,
9188 &inlay_hints,
9189 query_start..query_end,
9190 &mut cx,
9191 )
9192 .await
9193 .context("preparing inlay hints request")?;
9194 Self::query_lsp_locally::<InlayHints>(
9195 lsp_store,
9196 server_id,
9197 sender_id,
9198 lsp_request_id,
9199 inlay_hints,
9200 None,
9201 &mut cx,
9202 )
9203 .await
9204 .context("querying for inlay hints")?
9205 }
9206 }
9207 Ok(proto::Ack {})
9208 }
9209
9210 async fn handle_lsp_query_response(
9211 lsp_store: Entity<Self>,
9212 envelope: TypedEnvelope<proto::LspQueryResponse>,
9213 cx: AsyncApp,
9214 ) -> Result<()> {
9215 lsp_store.read_with(&cx, |lsp_store, _| {
9216 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9217 upstream_client.handle_lsp_response(envelope.clone());
9218 }
9219 });
9220 Ok(())
9221 }
9222
9223 async fn handle_apply_code_action(
9224 this: Entity<Self>,
9225 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9226 mut cx: AsyncApp,
9227 ) -> Result<proto::ApplyCodeActionResponse> {
9228 let sender_id = envelope.original_sender_id().unwrap_or_default();
9229 let action =
9230 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9231 let apply_code_action = this.update(&mut cx, |this, cx| {
9232 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9233 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9234 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9235 })?;
9236
9237 let project_transaction = apply_code_action.await?;
9238 let project_transaction = this.update(&mut cx, |this, cx| {
9239 this.buffer_store.update(cx, |buffer_store, cx| {
9240 buffer_store.serialize_project_transaction_for_peer(
9241 project_transaction,
9242 sender_id,
9243 cx,
9244 )
9245 })
9246 });
9247 Ok(proto::ApplyCodeActionResponse {
9248 transaction: Some(project_transaction),
9249 })
9250 }
9251
9252 async fn handle_register_buffer_with_language_servers(
9253 this: Entity<Self>,
9254 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9255 mut cx: AsyncApp,
9256 ) -> Result<proto::Ack> {
9257 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9258 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9259 this.update(&mut cx, |this, cx| {
9260 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9261 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9262 project_id: upstream_project_id,
9263 buffer_id: buffer_id.to_proto(),
9264 only_servers: envelope.payload.only_servers,
9265 });
9266 }
9267
9268 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9269 anyhow::bail!("buffer is not open");
9270 };
9271
9272 let handle = this.register_buffer_with_language_servers(
9273 &buffer,
9274 envelope
9275 .payload
9276 .only_servers
9277 .into_iter()
9278 .filter_map(|selector| {
9279 Some(match selector.selector? {
9280 proto::language_server_selector::Selector::ServerId(server_id) => {
9281 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9282 }
9283 proto::language_server_selector::Selector::Name(name) => {
9284 LanguageServerSelector::Name(LanguageServerName(
9285 SharedString::from(name),
9286 ))
9287 }
9288 })
9289 })
9290 .collect(),
9291 false,
9292 cx,
9293 );
9294 this.buffer_store().update(cx, |buffer_store, _| {
9295 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9296 });
9297
9298 Ok(())
9299 })?;
9300 Ok(proto::Ack {})
9301 }
9302
9303 async fn handle_rename_project_entry(
9304 this: Entity<Self>,
9305 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9306 mut cx: AsyncApp,
9307 ) -> Result<proto::ProjectEntryResponse> {
9308 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9309 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9310 let new_path =
9311 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9312
9313 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9314 .update(&mut cx, |this, cx| {
9315 let (worktree, entry) = this
9316 .worktree_store
9317 .read(cx)
9318 .worktree_and_entry_for_id(entry_id, cx)?;
9319 let new_worktree = this
9320 .worktree_store
9321 .read(cx)
9322 .worktree_for_id(new_worktree_id, cx)?;
9323 Some((
9324 this.worktree_store.clone(),
9325 worktree,
9326 new_worktree,
9327 entry.clone(),
9328 ))
9329 })
9330 .context("worktree not found")?;
9331 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9332 (worktree.absolutize(&old_entry.path), worktree.id())
9333 });
9334 let new_abs_path =
9335 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9336
9337 let _transaction = Self::will_rename_entry(
9338 this.downgrade(),
9339 old_worktree_id,
9340 &old_abs_path,
9341 &new_abs_path,
9342 old_entry.is_dir(),
9343 cx.clone(),
9344 )
9345 .await;
9346 let response = WorktreeStore::handle_rename_project_entry(
9347 worktree_store,
9348 envelope.payload,
9349 cx.clone(),
9350 )
9351 .await;
9352 this.read_with(&cx, |this, _| {
9353 this.did_rename_entry(
9354 old_worktree_id,
9355 &old_abs_path,
9356 &new_abs_path,
9357 old_entry.is_dir(),
9358 );
9359 });
9360 response
9361 }
9362
9363 async fn handle_update_diagnostic_summary(
9364 this: Entity<Self>,
9365 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9366 mut cx: AsyncApp,
9367 ) -> Result<()> {
9368 this.update(&mut cx, |lsp_store, cx| {
9369 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9370 let mut updated_diagnostics_paths = HashMap::default();
9371 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9372 for message_summary in envelope
9373 .payload
9374 .summary
9375 .into_iter()
9376 .chain(envelope.payload.more_summaries)
9377 {
9378 let project_path = ProjectPath {
9379 worktree_id,
9380 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9381 };
9382 let path = project_path.path.clone();
9383 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9384 let summary = DiagnosticSummary {
9385 error_count: message_summary.error_count as usize,
9386 warning_count: message_summary.warning_count as usize,
9387 };
9388
9389 if summary.is_empty() {
9390 if let Some(worktree_summaries) =
9391 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9392 && let Some(summaries) = worktree_summaries.get_mut(&path)
9393 {
9394 summaries.remove(&server_id);
9395 if summaries.is_empty() {
9396 worktree_summaries.remove(&path);
9397 }
9398 }
9399 } else {
9400 lsp_store
9401 .diagnostic_summaries
9402 .entry(worktree_id)
9403 .or_default()
9404 .entry(path)
9405 .or_default()
9406 .insert(server_id, summary);
9407 }
9408
9409 if let Some((_, project_id)) = &lsp_store.downstream_client {
9410 match &mut diagnostics_summary {
9411 Some(diagnostics_summary) => {
9412 diagnostics_summary
9413 .more_summaries
9414 .push(proto::DiagnosticSummary {
9415 path: project_path.path.as_ref().to_proto(),
9416 language_server_id: server_id.0 as u64,
9417 error_count: summary.error_count as u32,
9418 warning_count: summary.warning_count as u32,
9419 })
9420 }
9421 None => {
9422 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9423 project_id: *project_id,
9424 worktree_id: worktree_id.to_proto(),
9425 summary: Some(proto::DiagnosticSummary {
9426 path: project_path.path.as_ref().to_proto(),
9427 language_server_id: server_id.0 as u64,
9428 error_count: summary.error_count as u32,
9429 warning_count: summary.warning_count as u32,
9430 }),
9431 more_summaries: Vec::new(),
9432 })
9433 }
9434 }
9435 }
9436 updated_diagnostics_paths
9437 .entry(server_id)
9438 .or_insert_with(Vec::new)
9439 .push(project_path);
9440 }
9441
9442 if let Some((diagnostics_summary, (downstream_client, _))) =
9443 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9444 {
9445 downstream_client.send(diagnostics_summary).log_err();
9446 }
9447 for (server_id, paths) in updated_diagnostics_paths {
9448 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9449 }
9450 Ok(())
9451 })
9452 }
9453
9454 async fn handle_start_language_server(
9455 lsp_store: Entity<Self>,
9456 envelope: TypedEnvelope<proto::StartLanguageServer>,
9457 mut cx: AsyncApp,
9458 ) -> Result<()> {
9459 let server = envelope.payload.server.context("invalid server")?;
9460 let server_capabilities =
9461 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9462 .with_context(|| {
9463 format!(
9464 "incorrect server capabilities {}",
9465 envelope.payload.capabilities
9466 )
9467 })?;
9468 lsp_store.update(&mut cx, |lsp_store, cx| {
9469 let server_id = LanguageServerId(server.id as usize);
9470 let server_name = LanguageServerName::from_proto(server.name.clone());
9471 lsp_store
9472 .lsp_server_capabilities
9473 .insert(server_id, server_capabilities);
9474 lsp_store.language_server_statuses.insert(
9475 server_id,
9476 LanguageServerStatus {
9477 name: server_name.clone(),
9478 server_version: None,
9479 pending_work: Default::default(),
9480 has_pending_diagnostic_updates: false,
9481 progress_tokens: Default::default(),
9482 worktree: server.worktree_id.map(WorktreeId::from_proto),
9483 binary: None,
9484 configuration: None,
9485 workspace_folders: BTreeSet::new(),
9486 },
9487 );
9488 cx.emit(LspStoreEvent::LanguageServerAdded(
9489 server_id,
9490 server_name,
9491 server.worktree_id.map(WorktreeId::from_proto),
9492 ));
9493 cx.notify();
9494 });
9495 Ok(())
9496 }
9497
9498 async fn handle_update_language_server(
9499 lsp_store: Entity<Self>,
9500 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9501 mut cx: AsyncApp,
9502 ) -> Result<()> {
9503 lsp_store.update(&mut cx, |lsp_store, cx| {
9504 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9505
9506 match envelope.payload.variant.context("invalid variant")? {
9507 proto::update_language_server::Variant::WorkStart(payload) => {
9508 lsp_store.on_lsp_work_start(
9509 language_server_id,
9510 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9511 .context("invalid progress token value")?,
9512 LanguageServerProgress {
9513 title: payload.title,
9514 is_disk_based_diagnostics_progress: false,
9515 is_cancellable: payload.is_cancellable.unwrap_or(false),
9516 message: payload.message,
9517 percentage: payload.percentage.map(|p| p as usize),
9518 last_update_at: cx.background_executor().now(),
9519 },
9520 cx,
9521 );
9522 }
9523 proto::update_language_server::Variant::WorkProgress(payload) => {
9524 lsp_store.on_lsp_work_progress(
9525 language_server_id,
9526 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9527 .context("invalid progress token value")?,
9528 LanguageServerProgress {
9529 title: None,
9530 is_disk_based_diagnostics_progress: false,
9531 is_cancellable: payload.is_cancellable.unwrap_or(false),
9532 message: payload.message,
9533 percentage: payload.percentage.map(|p| p as usize),
9534 last_update_at: cx.background_executor().now(),
9535 },
9536 cx,
9537 );
9538 }
9539
9540 proto::update_language_server::Variant::WorkEnd(payload) => {
9541 lsp_store.on_lsp_work_end(
9542 language_server_id,
9543 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9544 .context("invalid progress token value")?,
9545 cx,
9546 );
9547 }
9548
9549 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9550 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9551 }
9552
9553 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9554 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9555 }
9556
9557 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9558 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9559 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9560 cx.emit(LspStoreEvent::LanguageServerUpdate {
9561 language_server_id,
9562 name: envelope
9563 .payload
9564 .server_name
9565 .map(SharedString::new)
9566 .map(LanguageServerName),
9567 message: non_lsp,
9568 });
9569 }
9570 }
9571
9572 Ok(())
9573 })
9574 }
9575
9576 async fn handle_language_server_log(
9577 this: Entity<Self>,
9578 envelope: TypedEnvelope<proto::LanguageServerLog>,
9579 mut cx: AsyncApp,
9580 ) -> Result<()> {
9581 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9582 let log_type = envelope
9583 .payload
9584 .log_type
9585 .map(LanguageServerLogType::from_proto)
9586 .context("invalid language server log type")?;
9587
9588 let message = envelope.payload.message;
9589
9590 this.update(&mut cx, |_, cx| {
9591 cx.emit(LspStoreEvent::LanguageServerLog(
9592 language_server_id,
9593 log_type,
9594 message,
9595 ));
9596 });
9597 Ok(())
9598 }
9599
9600 async fn handle_lsp_ext_cancel_flycheck(
9601 lsp_store: Entity<Self>,
9602 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9603 cx: AsyncApp,
9604 ) -> Result<proto::Ack> {
9605 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9606 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9607 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9608 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9609 } else {
9610 None
9611 }
9612 });
9613 if let Some(task) = task {
9614 task.context("handling lsp ext cancel flycheck")?;
9615 }
9616
9617 Ok(proto::Ack {})
9618 }
9619
9620 async fn handle_lsp_ext_run_flycheck(
9621 lsp_store: Entity<Self>,
9622 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9623 mut cx: AsyncApp,
9624 ) -> Result<proto::Ack> {
9625 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9626 lsp_store.update(&mut cx, |lsp_store, cx| {
9627 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9628 let text_document = if envelope.payload.current_file_only {
9629 let buffer_id = envelope
9630 .payload
9631 .buffer_id
9632 .map(|id| BufferId::new(id))
9633 .transpose()?;
9634 buffer_id
9635 .and_then(|buffer_id| {
9636 lsp_store
9637 .buffer_store()
9638 .read(cx)
9639 .get(buffer_id)
9640 .and_then(|buffer| {
9641 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9642 })
9643 .map(|path| make_text_document_identifier(&path))
9644 })
9645 .transpose()?
9646 } else {
9647 None
9648 };
9649 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9650 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9651 )?;
9652 }
9653 anyhow::Ok(())
9654 })?;
9655
9656 Ok(proto::Ack {})
9657 }
9658
9659 async fn handle_lsp_ext_clear_flycheck(
9660 lsp_store: Entity<Self>,
9661 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9662 cx: AsyncApp,
9663 ) -> Result<proto::Ack> {
9664 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9665 lsp_store.read_with(&cx, |lsp_store, _| {
9666 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9667 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9668 } else {
9669 None
9670 }
9671 });
9672
9673 Ok(proto::Ack {})
9674 }
9675
9676 pub fn disk_based_diagnostics_started(
9677 &mut self,
9678 language_server_id: LanguageServerId,
9679 cx: &mut Context<Self>,
9680 ) {
9681 if let Some(language_server_status) =
9682 self.language_server_statuses.get_mut(&language_server_id)
9683 {
9684 language_server_status.has_pending_diagnostic_updates = true;
9685 }
9686
9687 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9688 cx.emit(LspStoreEvent::LanguageServerUpdate {
9689 language_server_id,
9690 name: self
9691 .language_server_adapter_for_id(language_server_id)
9692 .map(|adapter| adapter.name()),
9693 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9694 Default::default(),
9695 ),
9696 })
9697 }
9698
9699 pub fn disk_based_diagnostics_finished(
9700 &mut self,
9701 language_server_id: LanguageServerId,
9702 cx: &mut Context<Self>,
9703 ) {
9704 if let Some(language_server_status) =
9705 self.language_server_statuses.get_mut(&language_server_id)
9706 {
9707 language_server_status.has_pending_diagnostic_updates = false;
9708 }
9709
9710 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9711 cx.emit(LspStoreEvent::LanguageServerUpdate {
9712 language_server_id,
9713 name: self
9714 .language_server_adapter_for_id(language_server_id)
9715 .map(|adapter| adapter.name()),
9716 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9717 Default::default(),
9718 ),
9719 })
9720 }
9721
9722 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9723 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9724 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9725 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9726 // the language server might take some time to publish diagnostics.
9727 fn simulate_disk_based_diagnostics_events_if_needed(
9728 &mut self,
9729 language_server_id: LanguageServerId,
9730 cx: &mut Context<Self>,
9731 ) {
9732 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9733
9734 let Some(LanguageServerState::Running {
9735 simulate_disk_based_diagnostics_completion,
9736 adapter,
9737 ..
9738 }) = self
9739 .as_local_mut()
9740 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9741 else {
9742 return;
9743 };
9744
9745 if adapter.disk_based_diagnostics_progress_token.is_some() {
9746 return;
9747 }
9748
9749 let prev_task =
9750 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9751 cx.background_executor()
9752 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9753 .await;
9754
9755 this.update(cx, |this, cx| {
9756 this.disk_based_diagnostics_finished(language_server_id, cx);
9757
9758 if let Some(LanguageServerState::Running {
9759 simulate_disk_based_diagnostics_completion,
9760 ..
9761 }) = this.as_local_mut().and_then(|local_store| {
9762 local_store.language_servers.get_mut(&language_server_id)
9763 }) {
9764 *simulate_disk_based_diagnostics_completion = None;
9765 }
9766 })
9767 .ok();
9768 }));
9769
9770 if prev_task.is_none() {
9771 self.disk_based_diagnostics_started(language_server_id, cx);
9772 }
9773 }
9774
9775 pub fn language_server_statuses(
9776 &self,
9777 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9778 self.language_server_statuses
9779 .iter()
9780 .map(|(key, value)| (*key, value))
9781 }
9782
9783 pub(super) fn did_rename_entry(
9784 &self,
9785 worktree_id: WorktreeId,
9786 old_path: &Path,
9787 new_path: &Path,
9788 is_dir: bool,
9789 ) {
9790 maybe!({
9791 let local_store = self.as_local()?;
9792
9793 let old_uri = lsp::Uri::from_file_path(old_path)
9794 .ok()
9795 .map(|uri| uri.to_string())?;
9796 let new_uri = lsp::Uri::from_file_path(new_path)
9797 .ok()
9798 .map(|uri| uri.to_string())?;
9799
9800 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9801 let Some(filter) = local_store
9802 .language_server_paths_watched_for_rename
9803 .get(&language_server.server_id())
9804 else {
9805 continue;
9806 };
9807
9808 if filter.should_send_did_rename(&old_uri, is_dir) {
9809 language_server
9810 .notify::<DidRenameFiles>(RenameFilesParams {
9811 files: vec![FileRename {
9812 old_uri: old_uri.clone(),
9813 new_uri: new_uri.clone(),
9814 }],
9815 })
9816 .ok();
9817 }
9818 }
9819 Some(())
9820 });
9821 }
9822
9823 pub(super) fn will_rename_entry(
9824 this: WeakEntity<Self>,
9825 worktree_id: WorktreeId,
9826 old_path: &Path,
9827 new_path: &Path,
9828 is_dir: bool,
9829 cx: AsyncApp,
9830 ) -> Task<ProjectTransaction> {
9831 let old_uri = lsp::Uri::from_file_path(old_path)
9832 .ok()
9833 .map(|uri| uri.to_string());
9834 let new_uri = lsp::Uri::from_file_path(new_path)
9835 .ok()
9836 .map(|uri| uri.to_string());
9837 cx.spawn(async move |cx| {
9838 let mut tasks = vec![];
9839 this.update(cx, |this, cx| {
9840 let local_store = this.as_local()?;
9841 let old_uri = old_uri?;
9842 let new_uri = new_uri?;
9843 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9844 let Some(filter) = local_store
9845 .language_server_paths_watched_for_rename
9846 .get(&language_server.server_id())
9847 else {
9848 continue;
9849 };
9850
9851 if filter.should_send_will_rename(&old_uri, is_dir) {
9852 let apply_edit = cx.spawn({
9853 let old_uri = old_uri.clone();
9854 let new_uri = new_uri.clone();
9855 let language_server = language_server.clone();
9856 async move |this, cx| {
9857 let edit = language_server
9858 .request::<WillRenameFiles>(RenameFilesParams {
9859 files: vec![FileRename { old_uri, new_uri }],
9860 })
9861 .await
9862 .into_response()
9863 .context("will rename files")
9864 .log_err()
9865 .flatten()?;
9866
9867 let transaction = LocalLspStore::deserialize_workspace_edit(
9868 this.upgrade()?,
9869 edit,
9870 false,
9871 language_server.clone(),
9872 cx,
9873 )
9874 .await
9875 .ok()?;
9876 Some(transaction)
9877 }
9878 });
9879 tasks.push(apply_edit);
9880 }
9881 }
9882 Some(())
9883 })
9884 .ok()
9885 .flatten();
9886 let mut merged_transaction = ProjectTransaction::default();
9887 for task in tasks {
9888 // Await on tasks sequentially so that the order of application of edits is deterministic
9889 // (at least with regards to the order of registration of language servers)
9890 if let Some(transaction) = task.await {
9891 for (buffer, buffer_transaction) in transaction.0 {
9892 merged_transaction.0.insert(buffer, buffer_transaction);
9893 }
9894 }
9895 }
9896 merged_transaction
9897 })
9898 }
9899
9900 fn lsp_notify_abs_paths_changed(
9901 &mut self,
9902 server_id: LanguageServerId,
9903 changes: Vec<PathEvent>,
9904 ) {
9905 maybe!({
9906 let server = self.language_server_for_id(server_id)?;
9907 let changes = changes
9908 .into_iter()
9909 .filter_map(|event| {
9910 let typ = match event.kind? {
9911 PathEventKind::Created => lsp::FileChangeType::CREATED,
9912 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9913 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9914 };
9915 Some(lsp::FileEvent {
9916 uri: file_path_to_lsp_url(&event.path).log_err()?,
9917 typ,
9918 })
9919 })
9920 .collect::<Vec<_>>();
9921 if !changes.is_empty() {
9922 server
9923 .notify::<lsp::notification::DidChangeWatchedFiles>(
9924 lsp::DidChangeWatchedFilesParams { changes },
9925 )
9926 .ok();
9927 }
9928 Some(())
9929 });
9930 }
9931
9932 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9933 self.as_local()?.language_server_for_id(id)
9934 }
9935
9936 fn on_lsp_progress(
9937 &mut self,
9938 progress_params: lsp::ProgressParams,
9939 language_server_id: LanguageServerId,
9940 disk_based_diagnostics_progress_token: Option<String>,
9941 cx: &mut Context<Self>,
9942 ) {
9943 match progress_params.value {
9944 lsp::ProgressParamsValue::WorkDone(progress) => {
9945 self.handle_work_done_progress(
9946 progress,
9947 language_server_id,
9948 disk_based_diagnostics_progress_token,
9949 ProgressToken::from_lsp(progress_params.token),
9950 cx,
9951 );
9952 }
9953 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9954 let registration_id = match progress_params.token {
9955 lsp::NumberOrString::Number(_) => None,
9956 lsp::NumberOrString::String(token) => token
9957 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9958 .map(|(_, id)| id.to_owned()),
9959 };
9960 if let Some(LanguageServerState::Running {
9961 workspace_diagnostics_refresh_tasks,
9962 ..
9963 }) = self
9964 .as_local_mut()
9965 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9966 && let Some(workspace_diagnostics) =
9967 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9968 {
9969 workspace_diagnostics.progress_tx.try_send(()).ok();
9970 self.apply_workspace_diagnostic_report(
9971 language_server_id,
9972 report,
9973 registration_id.map(SharedString::from),
9974 cx,
9975 )
9976 }
9977 }
9978 }
9979 }
9980
9981 fn handle_work_done_progress(
9982 &mut self,
9983 progress: lsp::WorkDoneProgress,
9984 language_server_id: LanguageServerId,
9985 disk_based_diagnostics_progress_token: Option<String>,
9986 token: ProgressToken,
9987 cx: &mut Context<Self>,
9988 ) {
9989 let language_server_status =
9990 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9991 status
9992 } else {
9993 return;
9994 };
9995
9996 if !language_server_status.progress_tokens.contains(&token) {
9997 return;
9998 }
9999
10000 let is_disk_based_diagnostics_progress =
10001 if let (Some(disk_based_token), ProgressToken::String(token)) =
10002 (&disk_based_diagnostics_progress_token, &token)
10003 {
10004 token.starts_with(disk_based_token)
10005 } else {
10006 false
10007 };
10008
10009 match progress {
10010 lsp::WorkDoneProgress::Begin(report) => {
10011 if is_disk_based_diagnostics_progress {
10012 self.disk_based_diagnostics_started(language_server_id, cx);
10013 }
10014 self.on_lsp_work_start(
10015 language_server_id,
10016 token.clone(),
10017 LanguageServerProgress {
10018 title: Some(report.title),
10019 is_disk_based_diagnostics_progress,
10020 is_cancellable: report.cancellable.unwrap_or(false),
10021 message: report.message.clone(),
10022 percentage: report.percentage.map(|p| p as usize),
10023 last_update_at: cx.background_executor().now(),
10024 },
10025 cx,
10026 );
10027 }
10028 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10029 language_server_id,
10030 token,
10031 LanguageServerProgress {
10032 title: None,
10033 is_disk_based_diagnostics_progress,
10034 is_cancellable: report.cancellable.unwrap_or(false),
10035 message: report.message,
10036 percentage: report.percentage.map(|p| p as usize),
10037 last_update_at: cx.background_executor().now(),
10038 },
10039 cx,
10040 ),
10041 lsp::WorkDoneProgress::End(_) => {
10042 language_server_status.progress_tokens.remove(&token);
10043 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10044 if is_disk_based_diagnostics_progress {
10045 self.disk_based_diagnostics_finished(language_server_id, cx);
10046 }
10047 }
10048 }
10049 }
10050
10051 fn on_lsp_work_start(
10052 &mut self,
10053 language_server_id: LanguageServerId,
10054 token: ProgressToken,
10055 progress: LanguageServerProgress,
10056 cx: &mut Context<Self>,
10057 ) {
10058 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10059 status.pending_work.insert(token.clone(), progress.clone());
10060 cx.notify();
10061 }
10062 cx.emit(LspStoreEvent::LanguageServerUpdate {
10063 language_server_id,
10064 name: self
10065 .language_server_adapter_for_id(language_server_id)
10066 .map(|adapter| adapter.name()),
10067 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10068 token: Some(token.to_proto()),
10069 title: progress.title,
10070 message: progress.message,
10071 percentage: progress.percentage.map(|p| p as u32),
10072 is_cancellable: Some(progress.is_cancellable),
10073 }),
10074 })
10075 }
10076
10077 fn on_lsp_work_progress(
10078 &mut self,
10079 language_server_id: LanguageServerId,
10080 token: ProgressToken,
10081 progress: LanguageServerProgress,
10082 cx: &mut Context<Self>,
10083 ) {
10084 let mut did_update = false;
10085 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10086 match status.pending_work.entry(token.clone()) {
10087 btree_map::Entry::Vacant(entry) => {
10088 entry.insert(progress.clone());
10089 did_update = true;
10090 }
10091 btree_map::Entry::Occupied(mut entry) => {
10092 let entry = entry.get_mut();
10093 if (progress.last_update_at - entry.last_update_at)
10094 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10095 {
10096 entry.last_update_at = progress.last_update_at;
10097 if progress.message.is_some() {
10098 entry.message = progress.message.clone();
10099 }
10100 if progress.percentage.is_some() {
10101 entry.percentage = progress.percentage;
10102 }
10103 if progress.is_cancellable != entry.is_cancellable {
10104 entry.is_cancellable = progress.is_cancellable;
10105 }
10106 did_update = true;
10107 }
10108 }
10109 }
10110 }
10111
10112 if did_update {
10113 cx.emit(LspStoreEvent::LanguageServerUpdate {
10114 language_server_id,
10115 name: self
10116 .language_server_adapter_for_id(language_server_id)
10117 .map(|adapter| adapter.name()),
10118 message: proto::update_language_server::Variant::WorkProgress(
10119 proto::LspWorkProgress {
10120 token: Some(token.to_proto()),
10121 message: progress.message,
10122 percentage: progress.percentage.map(|p| p as u32),
10123 is_cancellable: Some(progress.is_cancellable),
10124 },
10125 ),
10126 })
10127 }
10128 }
10129
10130 fn on_lsp_work_end(
10131 &mut self,
10132 language_server_id: LanguageServerId,
10133 token: ProgressToken,
10134 cx: &mut Context<Self>,
10135 ) {
10136 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10137 if let Some(work) = status.pending_work.remove(&token)
10138 && !work.is_disk_based_diagnostics_progress
10139 {
10140 cx.emit(LspStoreEvent::RefreshInlayHints {
10141 server_id: language_server_id,
10142 request_id: None,
10143 });
10144 }
10145 cx.notify();
10146 }
10147
10148 cx.emit(LspStoreEvent::LanguageServerUpdate {
10149 language_server_id,
10150 name: self
10151 .language_server_adapter_for_id(language_server_id)
10152 .map(|adapter| adapter.name()),
10153 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10154 token: Some(token.to_proto()),
10155 }),
10156 })
10157 }
10158
10159 pub async fn handle_resolve_completion_documentation(
10160 this: Entity<Self>,
10161 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10162 mut cx: AsyncApp,
10163 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10164 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10165
10166 let completion = this
10167 .read_with(&cx, |this, cx| {
10168 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10169 let server = this
10170 .language_server_for_id(id)
10171 .with_context(|| format!("No language server {id}"))?;
10172
10173 anyhow::Ok(cx.background_spawn(async move {
10174 let can_resolve = server
10175 .capabilities()
10176 .completion_provider
10177 .as_ref()
10178 .and_then(|options| options.resolve_provider)
10179 .unwrap_or(false);
10180 if can_resolve {
10181 server
10182 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10183 .await
10184 .into_response()
10185 .context("resolve completion item")
10186 } else {
10187 anyhow::Ok(lsp_completion)
10188 }
10189 }))
10190 })?
10191 .await?;
10192
10193 let mut documentation_is_markdown = false;
10194 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10195 let documentation = match completion.documentation {
10196 Some(lsp::Documentation::String(text)) => text,
10197
10198 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10199 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10200 value
10201 }
10202
10203 _ => String::new(),
10204 };
10205
10206 // If we have a new buffer_id, that means we're talking to a new client
10207 // and want to check for new text_edits in the completion too.
10208 let mut old_replace_start = None;
10209 let mut old_replace_end = None;
10210 let mut old_insert_start = None;
10211 let mut old_insert_end = None;
10212 let mut new_text = String::default();
10213 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10214 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10215 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10216 anyhow::Ok(buffer.read(cx).snapshot())
10217 })?;
10218
10219 if let Some(text_edit) = completion.text_edit.as_ref() {
10220 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10221
10222 if let Some(mut edit) = edit {
10223 LineEnding::normalize(&mut edit.new_text);
10224
10225 new_text = edit.new_text;
10226 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10227 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10228 if let Some(insert_range) = edit.insert_range {
10229 old_insert_start = Some(serialize_anchor(&insert_range.start));
10230 old_insert_end = Some(serialize_anchor(&insert_range.end));
10231 }
10232 }
10233 }
10234 }
10235
10236 Ok(proto::ResolveCompletionDocumentationResponse {
10237 documentation,
10238 documentation_is_markdown,
10239 old_replace_start,
10240 old_replace_end,
10241 new_text,
10242 lsp_completion,
10243 old_insert_start,
10244 old_insert_end,
10245 })
10246 }
10247
10248 async fn handle_on_type_formatting(
10249 this: Entity<Self>,
10250 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10251 mut cx: AsyncApp,
10252 ) -> Result<proto::OnTypeFormattingResponse> {
10253 let on_type_formatting = this.update(&mut cx, |this, cx| {
10254 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10255 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10256 let position = envelope
10257 .payload
10258 .position
10259 .and_then(deserialize_anchor)
10260 .context("invalid position")?;
10261 anyhow::Ok(this.apply_on_type_formatting(
10262 buffer,
10263 position,
10264 envelope.payload.trigger.clone(),
10265 cx,
10266 ))
10267 })?;
10268
10269 let transaction = on_type_formatting
10270 .await?
10271 .as_ref()
10272 .map(language::proto::serialize_transaction);
10273 Ok(proto::OnTypeFormattingResponse { transaction })
10274 }
10275
10276 async fn handle_refresh_inlay_hints(
10277 lsp_store: Entity<Self>,
10278 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10279 mut cx: AsyncApp,
10280 ) -> Result<proto::Ack> {
10281 lsp_store.update(&mut cx, |_, cx| {
10282 cx.emit(LspStoreEvent::RefreshInlayHints {
10283 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10284 request_id: envelope.payload.request_id.map(|id| id as usize),
10285 });
10286 });
10287 Ok(proto::Ack {})
10288 }
10289
10290 async fn handle_pull_workspace_diagnostics(
10291 lsp_store: Entity<Self>,
10292 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10293 mut cx: AsyncApp,
10294 ) -> Result<proto::Ack> {
10295 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10296 lsp_store.update(&mut cx, |lsp_store, _| {
10297 lsp_store.pull_workspace_diagnostics(server_id);
10298 });
10299 Ok(proto::Ack {})
10300 }
10301
10302 async fn handle_get_color_presentation(
10303 lsp_store: Entity<Self>,
10304 envelope: TypedEnvelope<proto::GetColorPresentation>,
10305 mut cx: AsyncApp,
10306 ) -> Result<proto::GetColorPresentationResponse> {
10307 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10308 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10309 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10310 })?;
10311
10312 let color = envelope
10313 .payload
10314 .color
10315 .context("invalid color resolve request")?;
10316 let start = color
10317 .lsp_range_start
10318 .context("invalid color resolve request")?;
10319 let end = color
10320 .lsp_range_end
10321 .context("invalid color resolve request")?;
10322
10323 let color = DocumentColor {
10324 lsp_range: lsp::Range {
10325 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10326 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10327 },
10328 color: lsp::Color {
10329 red: color.red,
10330 green: color.green,
10331 blue: color.blue,
10332 alpha: color.alpha,
10333 },
10334 resolved: false,
10335 color_presentations: Vec::new(),
10336 };
10337 let resolved_color = lsp_store
10338 .update(&mut cx, |lsp_store, cx| {
10339 lsp_store.resolve_color_presentation(
10340 color,
10341 buffer.clone(),
10342 LanguageServerId(envelope.payload.server_id as usize),
10343 cx,
10344 )
10345 })
10346 .await
10347 .context("resolving color presentation")?;
10348
10349 Ok(proto::GetColorPresentationResponse {
10350 presentations: resolved_color
10351 .color_presentations
10352 .into_iter()
10353 .map(|presentation| proto::ColorPresentation {
10354 label: presentation.label.to_string(),
10355 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10356 additional_text_edits: presentation
10357 .additional_text_edits
10358 .into_iter()
10359 .map(serialize_lsp_edit)
10360 .collect(),
10361 })
10362 .collect(),
10363 })
10364 }
10365
10366 async fn handle_resolve_inlay_hint(
10367 lsp_store: Entity<Self>,
10368 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10369 mut cx: AsyncApp,
10370 ) -> Result<proto::ResolveInlayHintResponse> {
10371 let proto_hint = envelope
10372 .payload
10373 .hint
10374 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10375 let hint = InlayHints::proto_to_project_hint(proto_hint)
10376 .context("resolved proto inlay hint conversion")?;
10377 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10378 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10379 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10380 })?;
10381 let response_hint = lsp_store
10382 .update(&mut cx, |lsp_store, cx| {
10383 lsp_store.resolve_inlay_hint(
10384 hint,
10385 buffer,
10386 LanguageServerId(envelope.payload.language_server_id as usize),
10387 cx,
10388 )
10389 })
10390 .await
10391 .context("inlay hints fetch")?;
10392 Ok(proto::ResolveInlayHintResponse {
10393 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10394 })
10395 }
10396
10397 async fn handle_refresh_code_lens(
10398 this: Entity<Self>,
10399 _: TypedEnvelope<proto::RefreshCodeLens>,
10400 mut cx: AsyncApp,
10401 ) -> Result<proto::Ack> {
10402 this.update(&mut cx, |_, cx| {
10403 cx.emit(LspStoreEvent::RefreshCodeLens);
10404 });
10405 Ok(proto::Ack {})
10406 }
10407
10408 async fn handle_open_buffer_for_symbol(
10409 this: Entity<Self>,
10410 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10411 mut cx: AsyncApp,
10412 ) -> Result<proto::OpenBufferForSymbolResponse> {
10413 let peer_id = envelope.original_sender_id().unwrap_or_default();
10414 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10415 let symbol = Self::deserialize_symbol(symbol)?;
10416 this.read_with(&cx, |this, _| {
10417 if let SymbolLocation::OutsideProject {
10418 abs_path,
10419 signature,
10420 } = &symbol.path
10421 {
10422 let new_signature = this.symbol_signature(&abs_path);
10423 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10424 }
10425 Ok(())
10426 })?;
10427 let buffer = this
10428 .update(&mut cx, |this, cx| {
10429 this.open_buffer_for_symbol(
10430 &Symbol {
10431 language_server_name: symbol.language_server_name,
10432 source_worktree_id: symbol.source_worktree_id,
10433 source_language_server_id: symbol.source_language_server_id,
10434 path: symbol.path,
10435 name: symbol.name,
10436 kind: symbol.kind,
10437 range: symbol.range,
10438 label: CodeLabel::default(),
10439 },
10440 cx,
10441 )
10442 })
10443 .await?;
10444
10445 this.update(&mut cx, |this, cx| {
10446 let is_private = buffer
10447 .read(cx)
10448 .file()
10449 .map(|f| f.is_private())
10450 .unwrap_or_default();
10451 if is_private {
10452 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10453 } else {
10454 this.buffer_store
10455 .update(cx, |buffer_store, cx| {
10456 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10457 })
10458 .detach_and_log_err(cx);
10459 let buffer_id = buffer.read(cx).remote_id().to_proto();
10460 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10461 }
10462 })
10463 }
10464
10465 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10466 let mut hasher = Sha256::new();
10467 hasher.update(abs_path.to_string_lossy().as_bytes());
10468 hasher.update(self.nonce.to_be_bytes());
10469 hasher.finalize().as_slice().try_into().unwrap()
10470 }
10471
10472 pub async fn handle_get_project_symbols(
10473 this: Entity<Self>,
10474 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10475 mut cx: AsyncApp,
10476 ) -> Result<proto::GetProjectSymbolsResponse> {
10477 let symbols = this
10478 .update(&mut cx, |this, cx| {
10479 this.symbols(&envelope.payload.query, cx)
10480 })
10481 .await?;
10482
10483 Ok(proto::GetProjectSymbolsResponse {
10484 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10485 })
10486 }
10487
10488 pub async fn handle_restart_language_servers(
10489 this: Entity<Self>,
10490 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10491 mut cx: AsyncApp,
10492 ) -> Result<proto::Ack> {
10493 this.update(&mut cx, |lsp_store, cx| {
10494 let buffers =
10495 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10496 lsp_store.restart_language_servers_for_buffers(
10497 buffers,
10498 envelope
10499 .payload
10500 .only_servers
10501 .into_iter()
10502 .filter_map(|selector| {
10503 Some(match selector.selector? {
10504 proto::language_server_selector::Selector::ServerId(server_id) => {
10505 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10506 }
10507 proto::language_server_selector::Selector::Name(name) => {
10508 LanguageServerSelector::Name(LanguageServerName(
10509 SharedString::from(name),
10510 ))
10511 }
10512 })
10513 })
10514 .collect(),
10515 cx,
10516 );
10517 });
10518
10519 Ok(proto::Ack {})
10520 }
10521
10522 pub async fn handle_stop_language_servers(
10523 lsp_store: Entity<Self>,
10524 envelope: TypedEnvelope<proto::StopLanguageServers>,
10525 mut cx: AsyncApp,
10526 ) -> Result<proto::Ack> {
10527 lsp_store.update(&mut cx, |lsp_store, cx| {
10528 if envelope.payload.all
10529 && envelope.payload.also_servers.is_empty()
10530 && envelope.payload.buffer_ids.is_empty()
10531 {
10532 lsp_store.stop_all_language_servers(cx);
10533 } else {
10534 let buffers =
10535 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10536 lsp_store
10537 .stop_language_servers_for_buffers(
10538 buffers,
10539 envelope
10540 .payload
10541 .also_servers
10542 .into_iter()
10543 .filter_map(|selector| {
10544 Some(match selector.selector? {
10545 proto::language_server_selector::Selector::ServerId(
10546 server_id,
10547 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10548 server_id,
10549 )),
10550 proto::language_server_selector::Selector::Name(name) => {
10551 LanguageServerSelector::Name(LanguageServerName(
10552 SharedString::from(name),
10553 ))
10554 }
10555 })
10556 })
10557 .collect(),
10558 cx,
10559 )
10560 .detach_and_log_err(cx);
10561 }
10562 });
10563
10564 Ok(proto::Ack {})
10565 }
10566
10567 pub async fn handle_cancel_language_server_work(
10568 lsp_store: Entity<Self>,
10569 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10570 mut cx: AsyncApp,
10571 ) -> Result<proto::Ack> {
10572 lsp_store.update(&mut cx, |lsp_store, cx| {
10573 if let Some(work) = envelope.payload.work {
10574 match work {
10575 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10576 let buffers =
10577 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10578 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10579 }
10580 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10581 let server_id = LanguageServerId::from_proto(work.language_server_id);
10582 let token = work
10583 .token
10584 .map(|token| {
10585 ProgressToken::from_proto(token)
10586 .context("invalid work progress token")
10587 })
10588 .transpose()?;
10589 lsp_store.cancel_language_server_work(server_id, token, cx);
10590 }
10591 }
10592 }
10593 anyhow::Ok(())
10594 })?;
10595
10596 Ok(proto::Ack {})
10597 }
10598
10599 fn buffer_ids_to_buffers(
10600 &mut self,
10601 buffer_ids: impl Iterator<Item = u64>,
10602 cx: &mut Context<Self>,
10603 ) -> Vec<Entity<Buffer>> {
10604 buffer_ids
10605 .into_iter()
10606 .flat_map(|buffer_id| {
10607 self.buffer_store
10608 .read(cx)
10609 .get(BufferId::new(buffer_id).log_err()?)
10610 })
10611 .collect::<Vec<_>>()
10612 }
10613
10614 async fn handle_apply_additional_edits_for_completion(
10615 this: Entity<Self>,
10616 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10617 mut cx: AsyncApp,
10618 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10619 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10620 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10621 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10622 let completion = Self::deserialize_completion(
10623 envelope.payload.completion.context("invalid completion")?,
10624 )?;
10625 anyhow::Ok((buffer, completion))
10626 })?;
10627
10628 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10629 this.apply_additional_edits_for_completion(
10630 buffer,
10631 Rc::new(RefCell::new(Box::new([Completion {
10632 replace_range: completion.replace_range,
10633 new_text: completion.new_text,
10634 source: completion.source,
10635 documentation: None,
10636 label: CodeLabel::default(),
10637 match_start: None,
10638 snippet_deduplication_key: None,
10639 insert_text_mode: None,
10640 icon_path: None,
10641 confirm: None,
10642 }]))),
10643 0,
10644 false,
10645 cx,
10646 )
10647 });
10648
10649 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10650 transaction: apply_additional_edits
10651 .await?
10652 .as_ref()
10653 .map(language::proto::serialize_transaction),
10654 })
10655 }
10656
10657 pub fn last_formatting_failure(&self) -> Option<&str> {
10658 self.last_formatting_failure.as_deref()
10659 }
10660
10661 pub fn reset_last_formatting_failure(&mut self) {
10662 self.last_formatting_failure = None;
10663 }
10664
10665 pub fn environment_for_buffer(
10666 &self,
10667 buffer: &Entity<Buffer>,
10668 cx: &mut Context<Self>,
10669 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10670 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10671 environment.update(cx, |env, cx| {
10672 env.buffer_environment(buffer, &self.worktree_store, cx)
10673 })
10674 } else {
10675 Task::ready(None).shared()
10676 }
10677 }
10678
10679 pub fn format(
10680 &mut self,
10681 buffers: HashSet<Entity<Buffer>>,
10682 target: LspFormatTarget,
10683 push_to_history: bool,
10684 trigger: FormatTrigger,
10685 cx: &mut Context<Self>,
10686 ) -> Task<anyhow::Result<ProjectTransaction>> {
10687 let logger = zlog::scoped!("format");
10688 if self.as_local().is_some() {
10689 zlog::trace!(logger => "Formatting locally");
10690 let logger = zlog::scoped!(logger => "local");
10691 let buffers = buffers
10692 .into_iter()
10693 .map(|buffer_handle| {
10694 let buffer = buffer_handle.read(cx);
10695 let buffer_abs_path = File::from_dyn(buffer.file())
10696 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10697
10698 (buffer_handle, buffer_abs_path, buffer.remote_id())
10699 })
10700 .collect::<Vec<_>>();
10701
10702 cx.spawn(async move |lsp_store, cx| {
10703 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10704
10705 for (handle, abs_path, id) in buffers {
10706 let env = lsp_store
10707 .update(cx, |lsp_store, cx| {
10708 lsp_store.environment_for_buffer(&handle, cx)
10709 })?
10710 .await;
10711
10712 let ranges = match &target {
10713 LspFormatTarget::Buffers => None,
10714 LspFormatTarget::Ranges(ranges) => {
10715 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10716 }
10717 };
10718
10719 formattable_buffers.push(FormattableBuffer {
10720 handle,
10721 abs_path,
10722 env,
10723 ranges,
10724 });
10725 }
10726 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10727
10728 let format_timer = zlog::time!(logger => "Formatting buffers");
10729 let result = LocalLspStore::format_locally(
10730 lsp_store.clone(),
10731 formattable_buffers,
10732 push_to_history,
10733 trigger,
10734 logger,
10735 cx,
10736 )
10737 .await;
10738 format_timer.end();
10739
10740 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10741
10742 lsp_store.update(cx, |lsp_store, _| {
10743 lsp_store.update_last_formatting_failure(&result);
10744 })?;
10745
10746 result
10747 })
10748 } else if let Some((client, project_id)) = self.upstream_client() {
10749 zlog::trace!(logger => "Formatting remotely");
10750 let logger = zlog::scoped!(logger => "remote");
10751
10752 let buffer_ranges = match &target {
10753 LspFormatTarget::Buffers => Vec::new(),
10754 LspFormatTarget::Ranges(ranges) => ranges
10755 .iter()
10756 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10757 buffer_id: buffer_id.to_proto(),
10758 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10759 })
10760 .collect(),
10761 };
10762
10763 let buffer_store = self.buffer_store();
10764 cx.spawn(async move |lsp_store, cx| {
10765 zlog::trace!(logger => "Sending remote format request");
10766 let request_timer = zlog::time!(logger => "remote format request");
10767 let result = client
10768 .request(proto::FormatBuffers {
10769 project_id,
10770 trigger: trigger as i32,
10771 buffer_ids: buffers
10772 .iter()
10773 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10774 .collect(),
10775 buffer_ranges,
10776 })
10777 .await
10778 .and_then(|result| result.transaction.context("missing transaction"));
10779 request_timer.end();
10780
10781 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10782
10783 lsp_store.update(cx, |lsp_store, _| {
10784 lsp_store.update_last_formatting_failure(&result);
10785 })?;
10786
10787 let transaction_response = result?;
10788 let _timer = zlog::time!(logger => "deserializing project transaction");
10789 buffer_store
10790 .update(cx, |buffer_store, cx| {
10791 buffer_store.deserialize_project_transaction(
10792 transaction_response,
10793 push_to_history,
10794 cx,
10795 )
10796 })
10797 .await
10798 })
10799 } else {
10800 zlog::trace!(logger => "Not formatting");
10801 Task::ready(Ok(ProjectTransaction::default()))
10802 }
10803 }
10804
10805 async fn handle_format_buffers(
10806 this: Entity<Self>,
10807 envelope: TypedEnvelope<proto::FormatBuffers>,
10808 mut cx: AsyncApp,
10809 ) -> Result<proto::FormatBuffersResponse> {
10810 let sender_id = envelope.original_sender_id().unwrap_or_default();
10811 let format = this.update(&mut cx, |this, cx| {
10812 let mut buffers = HashSet::default();
10813 for buffer_id in &envelope.payload.buffer_ids {
10814 let buffer_id = BufferId::new(*buffer_id)?;
10815 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10816 }
10817
10818 let target = if envelope.payload.buffer_ranges.is_empty() {
10819 LspFormatTarget::Buffers
10820 } else {
10821 let mut ranges_map = BTreeMap::new();
10822 for buffer_range in &envelope.payload.buffer_ranges {
10823 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10824 let ranges: Result<Vec<_>> = buffer_range
10825 .ranges
10826 .iter()
10827 .map(|range| {
10828 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10829 })
10830 .collect();
10831 ranges_map.insert(buffer_id, ranges?);
10832 }
10833 LspFormatTarget::Ranges(ranges_map)
10834 };
10835
10836 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10837 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10838 })?;
10839
10840 let project_transaction = format.await?;
10841 let project_transaction = this.update(&mut cx, |this, cx| {
10842 this.buffer_store.update(cx, |buffer_store, cx| {
10843 buffer_store.serialize_project_transaction_for_peer(
10844 project_transaction,
10845 sender_id,
10846 cx,
10847 )
10848 })
10849 });
10850 Ok(proto::FormatBuffersResponse {
10851 transaction: Some(project_transaction),
10852 })
10853 }
10854
10855 async fn handle_apply_code_action_kind(
10856 this: Entity<Self>,
10857 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10858 mut cx: AsyncApp,
10859 ) -> Result<proto::ApplyCodeActionKindResponse> {
10860 let sender_id = envelope.original_sender_id().unwrap_or_default();
10861 let format = this.update(&mut cx, |this, cx| {
10862 let mut buffers = HashSet::default();
10863 for buffer_id in &envelope.payload.buffer_ids {
10864 let buffer_id = BufferId::new(*buffer_id)?;
10865 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10866 }
10867 let kind = match envelope.payload.kind.as_str() {
10868 "" => CodeActionKind::EMPTY,
10869 "quickfix" => CodeActionKind::QUICKFIX,
10870 "refactor" => CodeActionKind::REFACTOR,
10871 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10872 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10873 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10874 "source" => CodeActionKind::SOURCE,
10875 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10876 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10877 _ => anyhow::bail!(
10878 "Invalid code action kind {}",
10879 envelope.payload.kind.as_str()
10880 ),
10881 };
10882 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10883 })?;
10884
10885 let project_transaction = format.await?;
10886 let project_transaction = this.update(&mut cx, |this, cx| {
10887 this.buffer_store.update(cx, |buffer_store, cx| {
10888 buffer_store.serialize_project_transaction_for_peer(
10889 project_transaction,
10890 sender_id,
10891 cx,
10892 )
10893 })
10894 });
10895 Ok(proto::ApplyCodeActionKindResponse {
10896 transaction: Some(project_transaction),
10897 })
10898 }
10899
10900 async fn shutdown_language_server(
10901 server_state: Option<LanguageServerState>,
10902 name: LanguageServerName,
10903 cx: &mut AsyncApp,
10904 ) {
10905 let server = match server_state {
10906 Some(LanguageServerState::Starting { startup, .. }) => {
10907 let mut timer = cx
10908 .background_executor()
10909 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10910 .fuse();
10911
10912 select! {
10913 server = startup.fuse() => server,
10914 () = timer => {
10915 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10916 None
10917 },
10918 }
10919 }
10920
10921 Some(LanguageServerState::Running { server, .. }) => Some(server),
10922
10923 None => None,
10924 };
10925
10926 if let Some(server) = server
10927 && let Some(shutdown) = server.shutdown()
10928 {
10929 shutdown.await;
10930 }
10931 }
10932
10933 // Returns a list of all of the worktrees which no longer have a language server and the root path
10934 // for the stopped server
10935 fn stop_local_language_server(
10936 &mut self,
10937 server_id: LanguageServerId,
10938 cx: &mut Context<Self>,
10939 ) -> Task<()> {
10940 let local = match &mut self.mode {
10941 LspStoreMode::Local(local) => local,
10942 _ => {
10943 return Task::ready(());
10944 }
10945 };
10946
10947 // Remove this server ID from all entries in the given worktree.
10948 local
10949 .language_server_ids
10950 .retain(|_, state| state.id != server_id);
10951 self.buffer_store.update(cx, |buffer_store, cx| {
10952 for buffer in buffer_store.buffers() {
10953 buffer.update(cx, |buffer, cx| {
10954 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10955 buffer.set_completion_triggers(server_id, Default::default(), cx);
10956 });
10957 }
10958 });
10959
10960 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10961 summaries.retain(|path, summaries_by_server_id| {
10962 if summaries_by_server_id.remove(&server_id).is_some() {
10963 if let Some((client, project_id)) = self.downstream_client.clone() {
10964 client
10965 .send(proto::UpdateDiagnosticSummary {
10966 project_id,
10967 worktree_id: worktree_id.to_proto(),
10968 summary: Some(proto::DiagnosticSummary {
10969 path: path.as_ref().to_proto(),
10970 language_server_id: server_id.0 as u64,
10971 error_count: 0,
10972 warning_count: 0,
10973 }),
10974 more_summaries: Vec::new(),
10975 })
10976 .log_err();
10977 }
10978 !summaries_by_server_id.is_empty()
10979 } else {
10980 true
10981 }
10982 });
10983 }
10984
10985 let local = self.as_local_mut().unwrap();
10986 for diagnostics in local.diagnostics.values_mut() {
10987 diagnostics.retain(|_, diagnostics_by_server_id| {
10988 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10989 diagnostics_by_server_id.remove(ix);
10990 !diagnostics_by_server_id.is_empty()
10991 } else {
10992 true
10993 }
10994 });
10995 }
10996 local.language_server_watched_paths.remove(&server_id);
10997
10998 let server_state = local.language_servers.remove(&server_id);
10999 self.cleanup_lsp_data(server_id);
11000 let name = self
11001 .language_server_statuses
11002 .remove(&server_id)
11003 .map(|status| status.name)
11004 .or_else(|| {
11005 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11006 Some(adapter.name())
11007 } else {
11008 None
11009 }
11010 });
11011
11012 if let Some(name) = name {
11013 log::info!("stopping language server {name}");
11014 self.languages
11015 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11016 cx.notify();
11017
11018 return cx.spawn(async move |lsp_store, cx| {
11019 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11020 lsp_store
11021 .update(cx, |lsp_store, cx| {
11022 lsp_store
11023 .languages
11024 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11025 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11026 cx.notify();
11027 })
11028 .ok();
11029 });
11030 }
11031
11032 if server_state.is_some() {
11033 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11034 }
11035 Task::ready(())
11036 }
11037
11038 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11039 self.shutdown_all_language_servers(cx).detach();
11040 }
11041
11042 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11043 if let Some((client, project_id)) = self.upstream_client() {
11044 let request = client.request(proto::StopLanguageServers {
11045 project_id,
11046 buffer_ids: Vec::new(),
11047 also_servers: Vec::new(),
11048 all: true,
11049 });
11050 cx.background_spawn(async move {
11051 request.await.ok();
11052 })
11053 } else {
11054 let Some(local) = self.as_local_mut() else {
11055 return Task::ready(());
11056 };
11057 let language_servers_to_stop = local
11058 .language_server_ids
11059 .values()
11060 .map(|state| state.id)
11061 .collect();
11062 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11063 let tasks = language_servers_to_stop
11064 .into_iter()
11065 .map(|server| self.stop_local_language_server(server, cx))
11066 .collect::<Vec<_>>();
11067 cx.background_spawn(async move {
11068 futures::future::join_all(tasks).await;
11069 })
11070 }
11071 }
11072
11073 pub fn restart_language_servers_for_buffers(
11074 &mut self,
11075 buffers: Vec<Entity<Buffer>>,
11076 only_restart_servers: HashSet<LanguageServerSelector>,
11077 cx: &mut Context<Self>,
11078 ) {
11079 if let Some((client, project_id)) = self.upstream_client() {
11080 let request = client.request(proto::RestartLanguageServers {
11081 project_id,
11082 buffer_ids: buffers
11083 .into_iter()
11084 .map(|b| b.read(cx).remote_id().to_proto())
11085 .collect(),
11086 only_servers: only_restart_servers
11087 .into_iter()
11088 .map(|selector| {
11089 let selector = match selector {
11090 LanguageServerSelector::Id(language_server_id) => {
11091 proto::language_server_selector::Selector::ServerId(
11092 language_server_id.to_proto(),
11093 )
11094 }
11095 LanguageServerSelector::Name(language_server_name) => {
11096 proto::language_server_selector::Selector::Name(
11097 language_server_name.to_string(),
11098 )
11099 }
11100 };
11101 proto::LanguageServerSelector {
11102 selector: Some(selector),
11103 }
11104 })
11105 .collect(),
11106 all: false,
11107 });
11108 cx.background_spawn(request).detach_and_log_err(cx);
11109 } else {
11110 let stop_task = if only_restart_servers.is_empty() {
11111 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11112 } else {
11113 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11114 };
11115 cx.spawn(async move |lsp_store, cx| {
11116 stop_task.await;
11117 lsp_store.update(cx, |lsp_store, cx| {
11118 for buffer in buffers {
11119 lsp_store.register_buffer_with_language_servers(
11120 &buffer,
11121 only_restart_servers.clone(),
11122 true,
11123 cx,
11124 );
11125 }
11126 })
11127 })
11128 .detach();
11129 }
11130 }
11131
11132 pub fn stop_language_servers_for_buffers(
11133 &mut self,
11134 buffers: Vec<Entity<Buffer>>,
11135 also_stop_servers: HashSet<LanguageServerSelector>,
11136 cx: &mut Context<Self>,
11137 ) -> Task<Result<()>> {
11138 if let Some((client, project_id)) = self.upstream_client() {
11139 let request = client.request(proto::StopLanguageServers {
11140 project_id,
11141 buffer_ids: buffers
11142 .into_iter()
11143 .map(|b| b.read(cx).remote_id().to_proto())
11144 .collect(),
11145 also_servers: also_stop_servers
11146 .into_iter()
11147 .map(|selector| {
11148 let selector = match selector {
11149 LanguageServerSelector::Id(language_server_id) => {
11150 proto::language_server_selector::Selector::ServerId(
11151 language_server_id.to_proto(),
11152 )
11153 }
11154 LanguageServerSelector::Name(language_server_name) => {
11155 proto::language_server_selector::Selector::Name(
11156 language_server_name.to_string(),
11157 )
11158 }
11159 };
11160 proto::LanguageServerSelector {
11161 selector: Some(selector),
11162 }
11163 })
11164 .collect(),
11165 all: false,
11166 });
11167 cx.background_spawn(async move {
11168 let _ = request.await?;
11169 Ok(())
11170 })
11171 } else {
11172 let task =
11173 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11174 cx.background_spawn(async move {
11175 task.await;
11176 Ok(())
11177 })
11178 }
11179 }
11180
11181 fn stop_local_language_servers_for_buffers(
11182 &mut self,
11183 buffers: &[Entity<Buffer>],
11184 also_stop_servers: HashSet<LanguageServerSelector>,
11185 cx: &mut Context<Self>,
11186 ) -> Task<()> {
11187 let Some(local) = self.as_local_mut() else {
11188 return Task::ready(());
11189 };
11190 let mut language_server_names_to_stop = BTreeSet::default();
11191 let mut language_servers_to_stop = also_stop_servers
11192 .into_iter()
11193 .flat_map(|selector| match selector {
11194 LanguageServerSelector::Id(id) => Some(id),
11195 LanguageServerSelector::Name(name) => {
11196 language_server_names_to_stop.insert(name);
11197 None
11198 }
11199 })
11200 .collect::<BTreeSet<_>>();
11201
11202 let mut covered_worktrees = HashSet::default();
11203 for buffer in buffers {
11204 buffer.update(cx, |buffer, cx| {
11205 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11206 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11207 && covered_worktrees.insert(worktree_id)
11208 {
11209 language_server_names_to_stop.retain(|name| {
11210 let old_ids_count = language_servers_to_stop.len();
11211 let all_language_servers_with_this_name = local
11212 .language_server_ids
11213 .iter()
11214 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11215 language_servers_to_stop.extend(all_language_servers_with_this_name);
11216 old_ids_count == language_servers_to_stop.len()
11217 });
11218 }
11219 });
11220 }
11221 for name in language_server_names_to_stop {
11222 language_servers_to_stop.extend(
11223 local
11224 .language_server_ids
11225 .iter()
11226 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11227 );
11228 }
11229
11230 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11231 let tasks = language_servers_to_stop
11232 .into_iter()
11233 .map(|server| self.stop_local_language_server(server, cx))
11234 .collect::<Vec<_>>();
11235
11236 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11237 }
11238
11239 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11240 let (worktree, relative_path) =
11241 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11242
11243 let project_path = ProjectPath {
11244 worktree_id: worktree.read(cx).id(),
11245 path: relative_path,
11246 };
11247
11248 Some(
11249 self.buffer_store()
11250 .read(cx)
11251 .get_by_path(&project_path)?
11252 .read(cx),
11253 )
11254 }
11255
11256 #[cfg(any(test, feature = "test-support"))]
11257 pub fn update_diagnostics(
11258 &mut self,
11259 server_id: LanguageServerId,
11260 diagnostics: lsp::PublishDiagnosticsParams,
11261 result_id: Option<SharedString>,
11262 source_kind: DiagnosticSourceKind,
11263 disk_based_sources: &[String],
11264 cx: &mut Context<Self>,
11265 ) -> Result<()> {
11266 self.merge_lsp_diagnostics(
11267 source_kind,
11268 vec![DocumentDiagnosticsUpdate {
11269 diagnostics,
11270 result_id,
11271 server_id,
11272 disk_based_sources: Cow::Borrowed(disk_based_sources),
11273 registration_id: None,
11274 }],
11275 |_, _, _| false,
11276 cx,
11277 )
11278 }
11279
11280 pub fn merge_lsp_diagnostics(
11281 &mut self,
11282 source_kind: DiagnosticSourceKind,
11283 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11284 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11285 cx: &mut Context<Self>,
11286 ) -> Result<()> {
11287 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11288 let updates = lsp_diagnostics
11289 .into_iter()
11290 .filter_map(|update| {
11291 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11292 Some(DocumentDiagnosticsUpdate {
11293 diagnostics: self.lsp_to_document_diagnostics(
11294 abs_path,
11295 source_kind,
11296 update.server_id,
11297 update.diagnostics,
11298 &update.disk_based_sources,
11299 update.registration_id.clone(),
11300 ),
11301 result_id: update.result_id,
11302 server_id: update.server_id,
11303 disk_based_sources: update.disk_based_sources,
11304 registration_id: update.registration_id,
11305 })
11306 })
11307 .collect();
11308 self.merge_diagnostic_entries(updates, merge, cx)?;
11309 Ok(())
11310 }
11311
11312 fn lsp_to_document_diagnostics(
11313 &mut self,
11314 document_abs_path: PathBuf,
11315 source_kind: DiagnosticSourceKind,
11316 server_id: LanguageServerId,
11317 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11318 disk_based_sources: &[String],
11319 registration_id: Option<SharedString>,
11320 ) -> DocumentDiagnostics {
11321 let mut diagnostics = Vec::default();
11322 let mut primary_diagnostic_group_ids = HashMap::default();
11323 let mut sources_by_group_id = HashMap::default();
11324 let mut supporting_diagnostics = HashMap::default();
11325
11326 let adapter = self.language_server_adapter_for_id(server_id);
11327
11328 // Ensure that primary diagnostics are always the most severe
11329 lsp_diagnostics
11330 .diagnostics
11331 .sort_by_key(|item| item.severity);
11332
11333 for diagnostic in &lsp_diagnostics.diagnostics {
11334 let source = diagnostic.source.as_ref();
11335 let range = range_from_lsp(diagnostic.range);
11336 let is_supporting = diagnostic
11337 .related_information
11338 .as_ref()
11339 .is_some_and(|infos| {
11340 infos.iter().any(|info| {
11341 primary_diagnostic_group_ids.contains_key(&(
11342 source,
11343 diagnostic.code.clone(),
11344 range_from_lsp(info.location.range),
11345 ))
11346 })
11347 });
11348
11349 let is_unnecessary = diagnostic
11350 .tags
11351 .as_ref()
11352 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11353
11354 let underline = self
11355 .language_server_adapter_for_id(server_id)
11356 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11357
11358 if is_supporting {
11359 supporting_diagnostics.insert(
11360 (source, diagnostic.code.clone(), range),
11361 (diagnostic.severity, is_unnecessary),
11362 );
11363 } else {
11364 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11365 let is_disk_based =
11366 source.is_some_and(|source| disk_based_sources.contains(source));
11367
11368 sources_by_group_id.insert(group_id, source);
11369 primary_diagnostic_group_ids
11370 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11371
11372 diagnostics.push(DiagnosticEntry {
11373 range,
11374 diagnostic: Diagnostic {
11375 source: diagnostic.source.clone(),
11376 source_kind,
11377 code: diagnostic.code.clone(),
11378 code_description: diagnostic
11379 .code_description
11380 .as_ref()
11381 .and_then(|d| d.href.clone()),
11382 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11383 markdown: adapter.as_ref().and_then(|adapter| {
11384 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11385 }),
11386 message: diagnostic.message.trim().to_string(),
11387 group_id,
11388 is_primary: true,
11389 is_disk_based,
11390 is_unnecessary,
11391 underline,
11392 data: diagnostic.data.clone(),
11393 registration_id: registration_id.clone(),
11394 },
11395 });
11396 if let Some(infos) = &diagnostic.related_information {
11397 for info in infos {
11398 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11399 let range = range_from_lsp(info.location.range);
11400 diagnostics.push(DiagnosticEntry {
11401 range,
11402 diagnostic: Diagnostic {
11403 source: diagnostic.source.clone(),
11404 source_kind,
11405 code: diagnostic.code.clone(),
11406 code_description: diagnostic
11407 .code_description
11408 .as_ref()
11409 .and_then(|d| d.href.clone()),
11410 severity: DiagnosticSeverity::INFORMATION,
11411 markdown: adapter.as_ref().and_then(|adapter| {
11412 adapter.diagnostic_message_to_markdown(&info.message)
11413 }),
11414 message: info.message.trim().to_string(),
11415 group_id,
11416 is_primary: false,
11417 is_disk_based,
11418 is_unnecessary: false,
11419 underline,
11420 data: diagnostic.data.clone(),
11421 registration_id: registration_id.clone(),
11422 },
11423 });
11424 }
11425 }
11426 }
11427 }
11428 }
11429
11430 for entry in &mut diagnostics {
11431 let diagnostic = &mut entry.diagnostic;
11432 if !diagnostic.is_primary {
11433 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11434 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11435 source,
11436 diagnostic.code.clone(),
11437 entry.range.clone(),
11438 )) {
11439 if let Some(severity) = severity {
11440 diagnostic.severity = severity;
11441 }
11442 diagnostic.is_unnecessary = is_unnecessary;
11443 }
11444 }
11445 }
11446
11447 DocumentDiagnostics {
11448 diagnostics,
11449 document_abs_path,
11450 version: lsp_diagnostics.version,
11451 }
11452 }
11453
11454 fn insert_newly_running_language_server(
11455 &mut self,
11456 adapter: Arc<CachedLspAdapter>,
11457 language_server: Arc<LanguageServer>,
11458 server_id: LanguageServerId,
11459 key: LanguageServerSeed,
11460 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11461 cx: &mut Context<Self>,
11462 ) {
11463 let Some(local) = self.as_local_mut() else {
11464 return;
11465 };
11466 // If the language server for this key doesn't match the server id, don't store the
11467 // server. Which will cause it to be dropped, killing the process
11468 if local
11469 .language_server_ids
11470 .get(&key)
11471 .map(|state| state.id != server_id)
11472 .unwrap_or(false)
11473 {
11474 return;
11475 }
11476
11477 // Update language_servers collection with Running variant of LanguageServerState
11478 // indicating that the server is up and running and ready
11479 let workspace_folders = workspace_folders.lock().clone();
11480 language_server.set_workspace_folders(workspace_folders);
11481
11482 let workspace_diagnostics_refresh_tasks = language_server
11483 .capabilities()
11484 .diagnostic_provider
11485 .and_then(|provider| {
11486 local
11487 .language_server_dynamic_registrations
11488 .entry(server_id)
11489 .or_default()
11490 .diagnostics
11491 .entry(None)
11492 .or_insert(provider.clone());
11493 let workspace_refresher =
11494 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11495
11496 Some((None, workspace_refresher))
11497 })
11498 .into_iter()
11499 .collect();
11500 local.language_servers.insert(
11501 server_id,
11502 LanguageServerState::Running {
11503 workspace_diagnostics_refresh_tasks,
11504 adapter: adapter.clone(),
11505 server: language_server.clone(),
11506 simulate_disk_based_diagnostics_completion: None,
11507 },
11508 );
11509 local
11510 .languages
11511 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11512 if let Some(file_ops_caps) = language_server
11513 .capabilities()
11514 .workspace
11515 .as_ref()
11516 .and_then(|ws| ws.file_operations.as_ref())
11517 {
11518 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11519 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11520 if did_rename_caps.or(will_rename_caps).is_some() {
11521 let watcher = RenamePathsWatchedForServer::default()
11522 .with_did_rename_patterns(did_rename_caps)
11523 .with_will_rename_patterns(will_rename_caps);
11524 local
11525 .language_server_paths_watched_for_rename
11526 .insert(server_id, watcher);
11527 }
11528 }
11529
11530 self.language_server_statuses.insert(
11531 server_id,
11532 LanguageServerStatus {
11533 name: language_server.name(),
11534 server_version: language_server.version(),
11535 pending_work: Default::default(),
11536 has_pending_diagnostic_updates: false,
11537 progress_tokens: Default::default(),
11538 worktree: Some(key.worktree_id),
11539 binary: Some(language_server.binary().clone()),
11540 configuration: Some(language_server.configuration().clone()),
11541 workspace_folders: language_server.workspace_folders(),
11542 },
11543 );
11544
11545 cx.emit(LspStoreEvent::LanguageServerAdded(
11546 server_id,
11547 language_server.name(),
11548 Some(key.worktree_id),
11549 ));
11550
11551 let server_capabilities = language_server.capabilities();
11552 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11553 downstream_client
11554 .send(proto::StartLanguageServer {
11555 project_id: *project_id,
11556 server: Some(proto::LanguageServer {
11557 id: server_id.to_proto(),
11558 name: language_server.name().to_string(),
11559 worktree_id: Some(key.worktree_id.to_proto()),
11560 }),
11561 capabilities: serde_json::to_string(&server_capabilities)
11562 .expect("serializing server LSP capabilities"),
11563 })
11564 .log_err();
11565 }
11566 self.lsp_server_capabilities
11567 .insert(server_id, server_capabilities);
11568
11569 // Tell the language server about every open buffer in the worktree that matches the language.
11570 // Also check for buffers in worktrees that reused this server
11571 let mut worktrees_using_server = vec![key.worktree_id];
11572 if let Some(local) = self.as_local() {
11573 // Find all worktrees that have this server in their language server tree
11574 for (worktree_id, servers) in &local.lsp_tree.instances {
11575 if *worktree_id != key.worktree_id {
11576 for server_map in servers.roots.values() {
11577 if server_map
11578 .values()
11579 .any(|(node, _)| node.id() == Some(server_id))
11580 {
11581 worktrees_using_server.push(*worktree_id);
11582 }
11583 }
11584 }
11585 }
11586 }
11587
11588 let mut buffer_paths_registered = Vec::new();
11589 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11590 let mut lsp_adapters = HashMap::default();
11591 for buffer_handle in buffer_store.buffers() {
11592 let buffer = buffer_handle.read(cx);
11593 let file = match File::from_dyn(buffer.file()) {
11594 Some(file) => file,
11595 None => continue,
11596 };
11597 let language = match buffer.language() {
11598 Some(language) => language,
11599 None => continue,
11600 };
11601
11602 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11603 || !lsp_adapters
11604 .entry(language.name())
11605 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11606 .iter()
11607 .any(|a| a.name == key.name)
11608 {
11609 continue;
11610 }
11611 // didOpen
11612 let file = match file.as_local() {
11613 Some(file) => file,
11614 None => continue,
11615 };
11616
11617 let local = self.as_local_mut().unwrap();
11618
11619 let buffer_id = buffer.remote_id();
11620 if local.registered_buffers.contains_key(&buffer_id) {
11621 let versions = local
11622 .buffer_snapshots
11623 .entry(buffer_id)
11624 .or_default()
11625 .entry(server_id)
11626 .and_modify(|_| {
11627 assert!(
11628 false,
11629 "There should not be an existing snapshot for a newly inserted buffer"
11630 )
11631 })
11632 .or_insert_with(|| {
11633 vec![LspBufferSnapshot {
11634 version: 0,
11635 snapshot: buffer.text_snapshot(),
11636 }]
11637 });
11638
11639 let snapshot = versions.last().unwrap();
11640 let version = snapshot.version;
11641 let initial_snapshot = &snapshot.snapshot;
11642 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11643 language_server.register_buffer(
11644 uri,
11645 adapter.language_id(&language.name()),
11646 version,
11647 initial_snapshot.text(),
11648 );
11649 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11650 local
11651 .buffers_opened_in_servers
11652 .entry(buffer_id)
11653 .or_default()
11654 .insert(server_id);
11655 }
11656 buffer_handle.update(cx, |buffer, cx| {
11657 buffer.set_completion_triggers(
11658 server_id,
11659 language_server
11660 .capabilities()
11661 .completion_provider
11662 .as_ref()
11663 .and_then(|provider| {
11664 provider
11665 .trigger_characters
11666 .as_ref()
11667 .map(|characters| characters.iter().cloned().collect())
11668 })
11669 .unwrap_or_default(),
11670 cx,
11671 )
11672 });
11673 }
11674 });
11675
11676 for (buffer_id, abs_path) in buffer_paths_registered {
11677 cx.emit(LspStoreEvent::LanguageServerUpdate {
11678 language_server_id: server_id,
11679 name: Some(adapter.name()),
11680 message: proto::update_language_server::Variant::RegisteredForBuffer(
11681 proto::RegisteredForBuffer {
11682 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11683 buffer_id: buffer_id.to_proto(),
11684 },
11685 ),
11686 });
11687 }
11688
11689 cx.notify();
11690 }
11691
11692 pub fn language_servers_running_disk_based_diagnostics(
11693 &self,
11694 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11695 self.language_server_statuses
11696 .iter()
11697 .filter_map(|(id, status)| {
11698 if status.has_pending_diagnostic_updates {
11699 Some(*id)
11700 } else {
11701 None
11702 }
11703 })
11704 }
11705
11706 pub(crate) fn cancel_language_server_work_for_buffers(
11707 &mut self,
11708 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11709 cx: &mut Context<Self>,
11710 ) {
11711 if let Some((client, project_id)) = self.upstream_client() {
11712 let request = client.request(proto::CancelLanguageServerWork {
11713 project_id,
11714 work: Some(proto::cancel_language_server_work::Work::Buffers(
11715 proto::cancel_language_server_work::Buffers {
11716 buffer_ids: buffers
11717 .into_iter()
11718 .map(|b| b.read(cx).remote_id().to_proto())
11719 .collect(),
11720 },
11721 )),
11722 });
11723 cx.background_spawn(request).detach_and_log_err(cx);
11724 } else if let Some(local) = self.as_local() {
11725 let servers = buffers
11726 .into_iter()
11727 .flat_map(|buffer| {
11728 buffer.update(cx, |buffer, cx| {
11729 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11730 })
11731 })
11732 .collect::<HashSet<_>>();
11733 for server_id in servers {
11734 self.cancel_language_server_work(server_id, None, cx);
11735 }
11736 }
11737 }
11738
11739 pub(crate) fn cancel_language_server_work(
11740 &mut self,
11741 server_id: LanguageServerId,
11742 token_to_cancel: Option<ProgressToken>,
11743 cx: &mut Context<Self>,
11744 ) {
11745 if let Some(local) = self.as_local() {
11746 let status = self.language_server_statuses.get(&server_id);
11747 let server = local.language_servers.get(&server_id);
11748 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11749 {
11750 for (token, progress) in &status.pending_work {
11751 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11752 && token != token_to_cancel
11753 {
11754 continue;
11755 }
11756 if progress.is_cancellable {
11757 server
11758 .notify::<lsp::notification::WorkDoneProgressCancel>(
11759 WorkDoneProgressCancelParams {
11760 token: token.to_lsp(),
11761 },
11762 )
11763 .ok();
11764 }
11765 }
11766 }
11767 } else if let Some((client, project_id)) = self.upstream_client() {
11768 let request = client.request(proto::CancelLanguageServerWork {
11769 project_id,
11770 work: Some(
11771 proto::cancel_language_server_work::Work::LanguageServerWork(
11772 proto::cancel_language_server_work::LanguageServerWork {
11773 language_server_id: server_id.to_proto(),
11774 token: token_to_cancel.map(|token| token.to_proto()),
11775 },
11776 ),
11777 ),
11778 });
11779 cx.background_spawn(request).detach_and_log_err(cx);
11780 }
11781 }
11782
11783 fn register_supplementary_language_server(
11784 &mut self,
11785 id: LanguageServerId,
11786 name: LanguageServerName,
11787 server: Arc<LanguageServer>,
11788 cx: &mut Context<Self>,
11789 ) {
11790 if let Some(local) = self.as_local_mut() {
11791 local
11792 .supplementary_language_servers
11793 .insert(id, (name.clone(), server));
11794 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11795 }
11796 }
11797
11798 fn unregister_supplementary_language_server(
11799 &mut self,
11800 id: LanguageServerId,
11801 cx: &mut Context<Self>,
11802 ) {
11803 if let Some(local) = self.as_local_mut() {
11804 local.supplementary_language_servers.remove(&id);
11805 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11806 }
11807 }
11808
11809 pub(crate) fn supplementary_language_servers(
11810 &self,
11811 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11812 self.as_local().into_iter().flat_map(|local| {
11813 local
11814 .supplementary_language_servers
11815 .iter()
11816 .map(|(id, (name, _))| (*id, name.clone()))
11817 })
11818 }
11819
11820 pub fn language_server_adapter_for_id(
11821 &self,
11822 id: LanguageServerId,
11823 ) -> Option<Arc<CachedLspAdapter>> {
11824 self.as_local()
11825 .and_then(|local| local.language_servers.get(&id))
11826 .and_then(|language_server_state| match language_server_state {
11827 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11828 _ => None,
11829 })
11830 }
11831
11832 pub(super) fn update_local_worktree_language_servers(
11833 &mut self,
11834 worktree_handle: &Entity<Worktree>,
11835 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11836 cx: &mut Context<Self>,
11837 ) {
11838 if changes.is_empty() {
11839 return;
11840 }
11841
11842 let Some(local) = self.as_local() else { return };
11843
11844 local.prettier_store.update(cx, |prettier_store, cx| {
11845 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11846 });
11847
11848 let worktree_id = worktree_handle.read(cx).id();
11849 let mut language_server_ids = local
11850 .language_server_ids
11851 .iter()
11852 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11853 .collect::<Vec<_>>();
11854 language_server_ids.sort();
11855 language_server_ids.dedup();
11856
11857 // let abs_path = worktree_handle.read(cx).abs_path();
11858 for server_id in &language_server_ids {
11859 if let Some(LanguageServerState::Running { server, .. }) =
11860 local.language_servers.get(server_id)
11861 && let Some(watched_paths) = local
11862 .language_server_watched_paths
11863 .get(server_id)
11864 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11865 {
11866 let params = lsp::DidChangeWatchedFilesParams {
11867 changes: changes
11868 .iter()
11869 .filter_map(|(path, _, change)| {
11870 if !watched_paths.is_match(path.as_std_path()) {
11871 return None;
11872 }
11873 let typ = match change {
11874 PathChange::Loaded => return None,
11875 PathChange::Added => lsp::FileChangeType::CREATED,
11876 PathChange::Removed => lsp::FileChangeType::DELETED,
11877 PathChange::Updated => lsp::FileChangeType::CHANGED,
11878 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11879 };
11880 let uri = lsp::Uri::from_file_path(
11881 worktree_handle.read(cx).absolutize(&path),
11882 )
11883 .ok()?;
11884 Some(lsp::FileEvent { uri, typ })
11885 })
11886 .collect(),
11887 };
11888 if !params.changes.is_empty() {
11889 server
11890 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11891 .ok();
11892 }
11893 }
11894 }
11895 for (path, _, _) in changes {
11896 if let Some(file_name) = path.file_name()
11897 && local.watched_manifest_filenames.contains(file_name)
11898 {
11899 self.request_workspace_config_refresh();
11900 break;
11901 }
11902 }
11903 }
11904
11905 pub fn wait_for_remote_buffer(
11906 &mut self,
11907 id: BufferId,
11908 cx: &mut Context<Self>,
11909 ) -> Task<Result<Entity<Buffer>>> {
11910 self.buffer_store.update(cx, |buffer_store, cx| {
11911 buffer_store.wait_for_remote_buffer(id, cx)
11912 })
11913 }
11914
11915 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11916 let mut result = proto::Symbol {
11917 language_server_name: symbol.language_server_name.0.to_string(),
11918 source_worktree_id: symbol.source_worktree_id.to_proto(),
11919 language_server_id: symbol.source_language_server_id.to_proto(),
11920 name: symbol.name.clone(),
11921 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11922 start: Some(proto::PointUtf16 {
11923 row: symbol.range.start.0.row,
11924 column: symbol.range.start.0.column,
11925 }),
11926 end: Some(proto::PointUtf16 {
11927 row: symbol.range.end.0.row,
11928 column: symbol.range.end.0.column,
11929 }),
11930 worktree_id: Default::default(),
11931 path: Default::default(),
11932 signature: Default::default(),
11933 };
11934 match &symbol.path {
11935 SymbolLocation::InProject(path) => {
11936 result.worktree_id = path.worktree_id.to_proto();
11937 result.path = path.path.to_proto();
11938 }
11939 SymbolLocation::OutsideProject {
11940 abs_path,
11941 signature,
11942 } => {
11943 result.path = abs_path.to_string_lossy().into_owned();
11944 result.signature = signature.to_vec();
11945 }
11946 }
11947 result
11948 }
11949
11950 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11951 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11952 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11953 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11954
11955 let path = if serialized_symbol.signature.is_empty() {
11956 SymbolLocation::InProject(ProjectPath {
11957 worktree_id,
11958 path: RelPath::from_proto(&serialized_symbol.path)
11959 .context("invalid symbol path")?,
11960 })
11961 } else {
11962 SymbolLocation::OutsideProject {
11963 abs_path: Path::new(&serialized_symbol.path).into(),
11964 signature: serialized_symbol
11965 .signature
11966 .try_into()
11967 .map_err(|_| anyhow!("invalid signature"))?,
11968 }
11969 };
11970
11971 let start = serialized_symbol.start.context("invalid start")?;
11972 let end = serialized_symbol.end.context("invalid end")?;
11973 Ok(CoreSymbol {
11974 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11975 source_worktree_id,
11976 source_language_server_id: LanguageServerId::from_proto(
11977 serialized_symbol.language_server_id,
11978 ),
11979 path,
11980 name: serialized_symbol.name,
11981 range: Unclipped(PointUtf16::new(start.row, start.column))
11982 ..Unclipped(PointUtf16::new(end.row, end.column)),
11983 kind,
11984 })
11985 }
11986
11987 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11988 let mut serialized_completion = proto::Completion {
11989 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11990 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11991 new_text: completion.new_text.clone(),
11992 ..proto::Completion::default()
11993 };
11994 match &completion.source {
11995 CompletionSource::Lsp {
11996 insert_range,
11997 server_id,
11998 lsp_completion,
11999 lsp_defaults,
12000 resolved,
12001 } => {
12002 let (old_insert_start, old_insert_end) = insert_range
12003 .as_ref()
12004 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12005 .unzip();
12006
12007 serialized_completion.old_insert_start = old_insert_start;
12008 serialized_completion.old_insert_end = old_insert_end;
12009 serialized_completion.source = proto::completion::Source::Lsp as i32;
12010 serialized_completion.server_id = server_id.0 as u64;
12011 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12012 serialized_completion.lsp_defaults = lsp_defaults
12013 .as_deref()
12014 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12015 serialized_completion.resolved = *resolved;
12016 }
12017 CompletionSource::BufferWord {
12018 word_range,
12019 resolved,
12020 } => {
12021 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12022 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12023 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12024 serialized_completion.resolved = *resolved;
12025 }
12026 CompletionSource::Custom => {
12027 serialized_completion.source = proto::completion::Source::Custom as i32;
12028 serialized_completion.resolved = true;
12029 }
12030 CompletionSource::Dap { sort_text } => {
12031 serialized_completion.source = proto::completion::Source::Dap as i32;
12032 serialized_completion.sort_text = Some(sort_text.clone());
12033 }
12034 }
12035
12036 serialized_completion
12037 }
12038
12039 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12040 let old_replace_start = completion
12041 .old_replace_start
12042 .and_then(deserialize_anchor)
12043 .context("invalid old start")?;
12044 let old_replace_end = completion
12045 .old_replace_end
12046 .and_then(deserialize_anchor)
12047 .context("invalid old end")?;
12048 let insert_range = {
12049 match completion.old_insert_start.zip(completion.old_insert_end) {
12050 Some((start, end)) => {
12051 let start = deserialize_anchor(start).context("invalid insert old start")?;
12052 let end = deserialize_anchor(end).context("invalid insert old end")?;
12053 Some(start..end)
12054 }
12055 None => None,
12056 }
12057 };
12058 Ok(CoreCompletion {
12059 replace_range: old_replace_start..old_replace_end,
12060 new_text: completion.new_text,
12061 source: match proto::completion::Source::from_i32(completion.source) {
12062 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12063 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12064 insert_range,
12065 server_id: LanguageServerId::from_proto(completion.server_id),
12066 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12067 lsp_defaults: completion
12068 .lsp_defaults
12069 .as_deref()
12070 .map(serde_json::from_slice)
12071 .transpose()?,
12072 resolved: completion.resolved,
12073 },
12074 Some(proto::completion::Source::BufferWord) => {
12075 let word_range = completion
12076 .buffer_word_start
12077 .and_then(deserialize_anchor)
12078 .context("invalid buffer word start")?
12079 ..completion
12080 .buffer_word_end
12081 .and_then(deserialize_anchor)
12082 .context("invalid buffer word end")?;
12083 CompletionSource::BufferWord {
12084 word_range,
12085 resolved: completion.resolved,
12086 }
12087 }
12088 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12089 sort_text: completion
12090 .sort_text
12091 .context("expected sort text to exist")?,
12092 },
12093 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12094 },
12095 })
12096 }
12097
12098 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12099 let (kind, lsp_action) = match &action.lsp_action {
12100 LspAction::Action(code_action) => (
12101 proto::code_action::Kind::Action as i32,
12102 serde_json::to_vec(code_action).unwrap(),
12103 ),
12104 LspAction::Command(command) => (
12105 proto::code_action::Kind::Command as i32,
12106 serde_json::to_vec(command).unwrap(),
12107 ),
12108 LspAction::CodeLens(code_lens) => (
12109 proto::code_action::Kind::CodeLens as i32,
12110 serde_json::to_vec(code_lens).unwrap(),
12111 ),
12112 };
12113
12114 proto::CodeAction {
12115 server_id: action.server_id.0 as u64,
12116 start: Some(serialize_anchor(&action.range.start)),
12117 end: Some(serialize_anchor(&action.range.end)),
12118 lsp_action,
12119 kind,
12120 resolved: action.resolved,
12121 }
12122 }
12123
12124 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12125 let start = action
12126 .start
12127 .and_then(deserialize_anchor)
12128 .context("invalid start")?;
12129 let end = action
12130 .end
12131 .and_then(deserialize_anchor)
12132 .context("invalid end")?;
12133 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12134 Some(proto::code_action::Kind::Action) => {
12135 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12136 }
12137 Some(proto::code_action::Kind::Command) => {
12138 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12139 }
12140 Some(proto::code_action::Kind::CodeLens) => {
12141 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12142 }
12143 None => anyhow::bail!("Unknown action kind {}", action.kind),
12144 };
12145 Ok(CodeAction {
12146 server_id: LanguageServerId(action.server_id as usize),
12147 range: start..end,
12148 resolved: action.resolved,
12149 lsp_action,
12150 })
12151 }
12152
12153 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12154 match &formatting_result {
12155 Ok(_) => self.last_formatting_failure = None,
12156 Err(error) => {
12157 let error_string = format!("{error:#}");
12158 log::error!("Formatting failed: {error_string}");
12159 self.last_formatting_failure
12160 .replace(error_string.lines().join(" "));
12161 }
12162 }
12163 }
12164
12165 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12166 self.lsp_server_capabilities.remove(&for_server);
12167 for lsp_data in self.lsp_data.values_mut() {
12168 lsp_data.remove_server_data(for_server);
12169 }
12170 if let Some(local) = self.as_local_mut() {
12171 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12172 local
12173 .workspace_pull_diagnostics_result_ids
12174 .remove(&for_server);
12175 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12176 buffer_servers.remove(&for_server);
12177 }
12178 }
12179 }
12180
12181 pub fn result_id_for_buffer_pull(
12182 &self,
12183 server_id: LanguageServerId,
12184 buffer_id: BufferId,
12185 registration_id: &Option<SharedString>,
12186 cx: &App,
12187 ) -> Option<SharedString> {
12188 let abs_path = self
12189 .buffer_store
12190 .read(cx)
12191 .get(buffer_id)
12192 .and_then(|b| File::from_dyn(b.read(cx).file()))
12193 .map(|f| f.abs_path(cx))?;
12194 self.as_local()?
12195 .buffer_pull_diagnostics_result_ids
12196 .get(&server_id)?
12197 .get(registration_id)?
12198 .get(&abs_path)?
12199 .clone()
12200 }
12201
12202 /// Gets all result_ids for a workspace diagnostics pull request.
12203 /// 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.
12204 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12205 pub fn result_ids_for_workspace_refresh(
12206 &self,
12207 server_id: LanguageServerId,
12208 registration_id: &Option<SharedString>,
12209 ) -> HashMap<PathBuf, SharedString> {
12210 let Some(local) = self.as_local() else {
12211 return HashMap::default();
12212 };
12213 local
12214 .workspace_pull_diagnostics_result_ids
12215 .get(&server_id)
12216 .into_iter()
12217 .filter_map(|diagnostics| diagnostics.get(registration_id))
12218 .flatten()
12219 .filter_map(|(abs_path, result_id)| {
12220 let result_id = local
12221 .buffer_pull_diagnostics_result_ids
12222 .get(&server_id)
12223 .and_then(|buffer_ids_result_ids| {
12224 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12225 })
12226 .cloned()
12227 .flatten()
12228 .or_else(|| result_id.clone())?;
12229 Some((abs_path.clone(), result_id))
12230 })
12231 .collect()
12232 }
12233
12234 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12235 if let Some(LanguageServerState::Running {
12236 workspace_diagnostics_refresh_tasks,
12237 ..
12238 }) = self
12239 .as_local_mut()
12240 .and_then(|local| local.language_servers.get_mut(&server_id))
12241 {
12242 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12243 diagnostics.refresh_tx.try_send(()).ok();
12244 }
12245 }
12246 }
12247
12248 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12249 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12250 /// which requires refreshing both workspace and document diagnostics.
12251 pub fn pull_document_diagnostics_for_server(
12252 &mut self,
12253 server_id: LanguageServerId,
12254 cx: &mut Context<Self>,
12255 ) -> Task<()> {
12256 let buffers_to_pull = self
12257 .as_local()
12258 .into_iter()
12259 .flat_map(|local| {
12260 self.buffer_store.read(cx).buffers().filter(|buffer| {
12261 let buffer_id = buffer.read(cx).remote_id();
12262 local
12263 .buffers_opened_in_servers
12264 .get(&buffer_id)
12265 .is_some_and(|servers| servers.contains(&server_id))
12266 })
12267 })
12268 .collect::<Vec<_>>();
12269
12270 let pulls = join_all(buffers_to_pull.into_iter().map(|buffer| {
12271 let buffer_path = buffer.read(cx).file().map(|f| f.full_path(cx));
12272 let pull_task = self.pull_diagnostics_for_buffer(buffer, cx);
12273 async move { (buffer_path, pull_task.await) }
12274 }));
12275 cx.background_spawn(async move {
12276 for (pull_task_path, pull_task_result) in pulls.await {
12277 if let Err(e) = pull_task_result {
12278 match pull_task_path {
12279 Some(path) => {
12280 log::error!("Failed to pull diagnostics for buffer {path:?}: {e:#}");
12281 }
12282 None => log::error!("Failed to pull diagnostics: {e:#}"),
12283 }
12284 }
12285 }
12286 })
12287 }
12288
12289 fn apply_workspace_diagnostic_report(
12290 &mut self,
12291 server_id: LanguageServerId,
12292 report: lsp::WorkspaceDiagnosticReportResult,
12293 registration_id: Option<SharedString>,
12294 cx: &mut Context<Self>,
12295 ) {
12296 let mut workspace_diagnostics =
12297 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12298 report,
12299 server_id,
12300 registration_id,
12301 );
12302 workspace_diagnostics.retain(|d| match &d.diagnostics {
12303 LspPullDiagnostics::Response {
12304 server_id,
12305 registration_id,
12306 ..
12307 } => self.diagnostic_registration_exists(*server_id, registration_id),
12308 LspPullDiagnostics::Default => false,
12309 });
12310 let mut unchanged_buffers = HashMap::default();
12311 let workspace_diagnostics_updates = workspace_diagnostics
12312 .into_iter()
12313 .filter_map(
12314 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12315 LspPullDiagnostics::Response {
12316 server_id,
12317 uri,
12318 diagnostics,
12319 registration_id,
12320 } => Some((
12321 server_id,
12322 uri,
12323 diagnostics,
12324 workspace_diagnostics.version,
12325 registration_id,
12326 )),
12327 LspPullDiagnostics::Default => None,
12328 },
12329 )
12330 .fold(
12331 HashMap::default(),
12332 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12333 let (result_id, diagnostics) = match diagnostics {
12334 PulledDiagnostics::Unchanged { result_id } => {
12335 unchanged_buffers
12336 .entry(new_registration_id.clone())
12337 .or_insert_with(HashSet::default)
12338 .insert(uri.clone());
12339 (Some(result_id), Vec::new())
12340 }
12341 PulledDiagnostics::Changed {
12342 result_id,
12343 diagnostics,
12344 } => (result_id, diagnostics),
12345 };
12346 let disk_based_sources = Cow::Owned(
12347 self.language_server_adapter_for_id(server_id)
12348 .as_ref()
12349 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12350 .unwrap_or(&[])
12351 .to_vec(),
12352 );
12353
12354 let Some(abs_path) = uri.to_file_path().ok() else {
12355 return acc;
12356 };
12357 let Some((worktree, relative_path)) =
12358 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12359 else {
12360 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12361 return acc;
12362 };
12363 let worktree_id = worktree.read(cx).id();
12364 let project_path = ProjectPath {
12365 worktree_id,
12366 path: relative_path,
12367 };
12368 if let Some(local_lsp_store) = self.as_local_mut() {
12369 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12370 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12371 }
12372 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12373 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12374 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12375 acc.entry(server_id)
12376 .or_insert_with(HashMap::default)
12377 .entry(new_registration_id.clone())
12378 .or_insert_with(Vec::new)
12379 .push(DocumentDiagnosticsUpdate {
12380 server_id,
12381 diagnostics: lsp::PublishDiagnosticsParams {
12382 uri,
12383 diagnostics,
12384 version,
12385 },
12386 result_id,
12387 disk_based_sources,
12388 registration_id: new_registration_id,
12389 });
12390 }
12391 acc
12392 },
12393 );
12394
12395 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12396 for (registration_id, diagnostic_updates) in diagnostic_updates {
12397 self.merge_lsp_diagnostics(
12398 DiagnosticSourceKind::Pulled,
12399 diagnostic_updates,
12400 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12401 DiagnosticSourceKind::Pulled => {
12402 old_diagnostic.registration_id != registration_id
12403 || unchanged_buffers
12404 .get(&old_diagnostic.registration_id)
12405 .is_some_and(|unchanged_buffers| {
12406 unchanged_buffers.contains(&document_uri)
12407 })
12408 }
12409 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12410 },
12411 cx,
12412 )
12413 .log_err();
12414 }
12415 }
12416 }
12417
12418 fn register_server_capabilities(
12419 &mut self,
12420 server_id: LanguageServerId,
12421 params: lsp::RegistrationParams,
12422 cx: &mut Context<Self>,
12423 ) -> anyhow::Result<()> {
12424 let server = self
12425 .language_server_for_id(server_id)
12426 .with_context(|| format!("no server {server_id} found"))?;
12427 for reg in params.registrations {
12428 match reg.method.as_str() {
12429 "workspace/didChangeWatchedFiles" => {
12430 if let Some(options) = reg.register_options {
12431 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12432 let caps = serde_json::from_value(options)?;
12433 local_lsp_store
12434 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12435 true
12436 } else {
12437 false
12438 };
12439 if notify {
12440 notify_server_capabilities_updated(&server, cx);
12441 }
12442 }
12443 }
12444 "workspace/didChangeConfiguration" => {
12445 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12446 }
12447 "workspace/didChangeWorkspaceFolders" => {
12448 // In this case register options is an empty object, we can ignore it
12449 let caps = lsp::WorkspaceFoldersServerCapabilities {
12450 supported: Some(true),
12451 change_notifications: Some(OneOf::Right(reg.id)),
12452 };
12453 server.update_capabilities(|capabilities| {
12454 capabilities
12455 .workspace
12456 .get_or_insert_default()
12457 .workspace_folders = Some(caps);
12458 });
12459 notify_server_capabilities_updated(&server, cx);
12460 }
12461 "workspace/symbol" => {
12462 let options = parse_register_capabilities(reg)?;
12463 server.update_capabilities(|capabilities| {
12464 capabilities.workspace_symbol_provider = Some(options);
12465 });
12466 notify_server_capabilities_updated(&server, cx);
12467 }
12468 "workspace/fileOperations" => {
12469 if let Some(options) = reg.register_options {
12470 let caps = serde_json::from_value(options)?;
12471 server.update_capabilities(|capabilities| {
12472 capabilities
12473 .workspace
12474 .get_or_insert_default()
12475 .file_operations = Some(caps);
12476 });
12477 notify_server_capabilities_updated(&server, cx);
12478 }
12479 }
12480 "workspace/executeCommand" => {
12481 if let Some(options) = reg.register_options {
12482 let options = serde_json::from_value(options)?;
12483 server.update_capabilities(|capabilities| {
12484 capabilities.execute_command_provider = Some(options);
12485 });
12486 notify_server_capabilities_updated(&server, cx);
12487 }
12488 }
12489 "textDocument/rangeFormatting" => {
12490 let options = parse_register_capabilities(reg)?;
12491 server.update_capabilities(|capabilities| {
12492 capabilities.document_range_formatting_provider = Some(options);
12493 });
12494 notify_server_capabilities_updated(&server, cx);
12495 }
12496 "textDocument/onTypeFormatting" => {
12497 if let Some(options) = reg
12498 .register_options
12499 .map(serde_json::from_value)
12500 .transpose()?
12501 {
12502 server.update_capabilities(|capabilities| {
12503 capabilities.document_on_type_formatting_provider = Some(options);
12504 });
12505 notify_server_capabilities_updated(&server, cx);
12506 }
12507 }
12508 "textDocument/formatting" => {
12509 let options = parse_register_capabilities(reg)?;
12510 server.update_capabilities(|capabilities| {
12511 capabilities.document_formatting_provider = Some(options);
12512 });
12513 notify_server_capabilities_updated(&server, cx);
12514 }
12515 "textDocument/rename" => {
12516 let options = parse_register_capabilities(reg)?;
12517 server.update_capabilities(|capabilities| {
12518 capabilities.rename_provider = Some(options);
12519 });
12520 notify_server_capabilities_updated(&server, cx);
12521 }
12522 "textDocument/inlayHint" => {
12523 let options = parse_register_capabilities(reg)?;
12524 server.update_capabilities(|capabilities| {
12525 capabilities.inlay_hint_provider = Some(options);
12526 });
12527 notify_server_capabilities_updated(&server, cx);
12528 }
12529 "textDocument/documentSymbol" => {
12530 let options = parse_register_capabilities(reg)?;
12531 server.update_capabilities(|capabilities| {
12532 capabilities.document_symbol_provider = Some(options);
12533 });
12534 notify_server_capabilities_updated(&server, cx);
12535 }
12536 "textDocument/codeAction" => {
12537 let options = parse_register_capabilities(reg)?;
12538 let provider = match options {
12539 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12540 OneOf::Right(caps) => caps,
12541 };
12542 server.update_capabilities(|capabilities| {
12543 capabilities.code_action_provider = Some(provider);
12544 });
12545 notify_server_capabilities_updated(&server, cx);
12546 }
12547 "textDocument/definition" => {
12548 let options = parse_register_capabilities(reg)?;
12549 server.update_capabilities(|capabilities| {
12550 capabilities.definition_provider = Some(options);
12551 });
12552 notify_server_capabilities_updated(&server, cx);
12553 }
12554 "textDocument/completion" => {
12555 if let Some(caps) = reg
12556 .register_options
12557 .map(serde_json::from_value::<CompletionOptions>)
12558 .transpose()?
12559 {
12560 server.update_capabilities(|capabilities| {
12561 capabilities.completion_provider = Some(caps.clone());
12562 });
12563
12564 if let Some(local) = self.as_local() {
12565 let mut buffers_with_language_server = Vec::new();
12566 for handle in self.buffer_store.read(cx).buffers() {
12567 let buffer_id = handle.read(cx).remote_id();
12568 if local
12569 .buffers_opened_in_servers
12570 .get(&buffer_id)
12571 .filter(|s| s.contains(&server_id))
12572 .is_some()
12573 {
12574 buffers_with_language_server.push(handle);
12575 }
12576 }
12577 let triggers = caps
12578 .trigger_characters
12579 .unwrap_or_default()
12580 .into_iter()
12581 .collect::<BTreeSet<_>>();
12582 for handle in buffers_with_language_server {
12583 let triggers = triggers.clone();
12584 let _ = handle.update(cx, move |buffer, cx| {
12585 buffer.set_completion_triggers(server_id, triggers, cx);
12586 });
12587 }
12588 }
12589 notify_server_capabilities_updated(&server, cx);
12590 }
12591 }
12592 "textDocument/hover" => {
12593 let options = parse_register_capabilities(reg)?;
12594 let provider = match options {
12595 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12596 OneOf::Right(caps) => caps,
12597 };
12598 server.update_capabilities(|capabilities| {
12599 capabilities.hover_provider = Some(provider);
12600 });
12601 notify_server_capabilities_updated(&server, cx);
12602 }
12603 "textDocument/signatureHelp" => {
12604 if let Some(caps) = reg
12605 .register_options
12606 .map(serde_json::from_value)
12607 .transpose()?
12608 {
12609 server.update_capabilities(|capabilities| {
12610 capabilities.signature_help_provider = Some(caps);
12611 });
12612 notify_server_capabilities_updated(&server, cx);
12613 }
12614 }
12615 "textDocument/didChange" => {
12616 if let Some(sync_kind) = reg
12617 .register_options
12618 .and_then(|opts| opts.get("syncKind").cloned())
12619 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12620 .transpose()?
12621 {
12622 server.update_capabilities(|capabilities| {
12623 let mut sync_options =
12624 Self::take_text_document_sync_options(capabilities);
12625 sync_options.change = Some(sync_kind);
12626 capabilities.text_document_sync =
12627 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12628 });
12629 notify_server_capabilities_updated(&server, cx);
12630 }
12631 }
12632 "textDocument/didSave" => {
12633 if let Some(include_text) = reg
12634 .register_options
12635 .map(|opts| {
12636 let transpose = opts
12637 .get("includeText")
12638 .cloned()
12639 .map(serde_json::from_value::<Option<bool>>)
12640 .transpose();
12641 match transpose {
12642 Ok(value) => Ok(value.flatten()),
12643 Err(e) => Err(e),
12644 }
12645 })
12646 .transpose()?
12647 {
12648 server.update_capabilities(|capabilities| {
12649 let mut sync_options =
12650 Self::take_text_document_sync_options(capabilities);
12651 sync_options.save =
12652 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12653 include_text,
12654 }));
12655 capabilities.text_document_sync =
12656 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12657 });
12658 notify_server_capabilities_updated(&server, cx);
12659 }
12660 }
12661 "textDocument/codeLens" => {
12662 if let Some(caps) = reg
12663 .register_options
12664 .map(serde_json::from_value)
12665 .transpose()?
12666 {
12667 server.update_capabilities(|capabilities| {
12668 capabilities.code_lens_provider = Some(caps);
12669 });
12670 notify_server_capabilities_updated(&server, cx);
12671 }
12672 }
12673 "textDocument/diagnostic" => {
12674 if let Some(caps) = reg
12675 .register_options
12676 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12677 .transpose()?
12678 {
12679 let local = self
12680 .as_local_mut()
12681 .context("Expected LSP Store to be local")?;
12682 let state = local
12683 .language_servers
12684 .get_mut(&server_id)
12685 .context("Could not obtain Language Servers state")?;
12686 local
12687 .language_server_dynamic_registrations
12688 .entry(server_id)
12689 .or_default()
12690 .diagnostics
12691 .insert(Some(reg.id.clone()), caps.clone());
12692
12693 let supports_workspace_diagnostics =
12694 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12695 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12696 diagnostic_options.workspace_diagnostics
12697 }
12698 DiagnosticServerCapabilities::RegistrationOptions(
12699 diagnostic_registration_options,
12700 ) => {
12701 diagnostic_registration_options
12702 .diagnostic_options
12703 .workspace_diagnostics
12704 }
12705 };
12706
12707 if supports_workspace_diagnostics(&caps) {
12708 if let LanguageServerState::Running {
12709 workspace_diagnostics_refresh_tasks,
12710 ..
12711 } = state
12712 && let Some(task) = lsp_workspace_diagnostics_refresh(
12713 Some(reg.id.clone()),
12714 caps.clone(),
12715 server.clone(),
12716 cx,
12717 )
12718 {
12719 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12720 }
12721 }
12722
12723 server.update_capabilities(|capabilities| {
12724 capabilities.diagnostic_provider = Some(caps);
12725 });
12726
12727 notify_server_capabilities_updated(&server, cx);
12728
12729 self.pull_document_diagnostics_for_server(server_id, cx)
12730 .detach();
12731 }
12732 }
12733 "textDocument/documentColor" => {
12734 let options = parse_register_capabilities(reg)?;
12735 let provider = match options {
12736 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12737 OneOf::Right(caps) => caps,
12738 };
12739 server.update_capabilities(|capabilities| {
12740 capabilities.color_provider = Some(provider);
12741 });
12742 notify_server_capabilities_updated(&server, cx);
12743 }
12744 _ => log::warn!("unhandled capability registration: {reg:?}"),
12745 }
12746 }
12747
12748 Ok(())
12749 }
12750
12751 fn unregister_server_capabilities(
12752 &mut self,
12753 server_id: LanguageServerId,
12754 params: lsp::UnregistrationParams,
12755 cx: &mut Context<Self>,
12756 ) -> anyhow::Result<()> {
12757 let server = self
12758 .language_server_for_id(server_id)
12759 .with_context(|| format!("no server {server_id} found"))?;
12760 for unreg in params.unregisterations.iter() {
12761 match unreg.method.as_str() {
12762 "workspace/didChangeWatchedFiles" => {
12763 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12764 local_lsp_store
12765 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12766 true
12767 } else {
12768 false
12769 };
12770 if notify {
12771 notify_server_capabilities_updated(&server, cx);
12772 }
12773 }
12774 "workspace/didChangeConfiguration" => {
12775 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12776 }
12777 "workspace/didChangeWorkspaceFolders" => {
12778 server.update_capabilities(|capabilities| {
12779 capabilities
12780 .workspace
12781 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12782 workspace_folders: None,
12783 file_operations: None,
12784 })
12785 .workspace_folders = None;
12786 });
12787 notify_server_capabilities_updated(&server, cx);
12788 }
12789 "workspace/symbol" => {
12790 server.update_capabilities(|capabilities| {
12791 capabilities.workspace_symbol_provider = None
12792 });
12793 notify_server_capabilities_updated(&server, cx);
12794 }
12795 "workspace/fileOperations" => {
12796 server.update_capabilities(|capabilities| {
12797 capabilities
12798 .workspace
12799 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12800 workspace_folders: None,
12801 file_operations: None,
12802 })
12803 .file_operations = None;
12804 });
12805 notify_server_capabilities_updated(&server, cx);
12806 }
12807 "workspace/executeCommand" => {
12808 server.update_capabilities(|capabilities| {
12809 capabilities.execute_command_provider = None;
12810 });
12811 notify_server_capabilities_updated(&server, cx);
12812 }
12813 "textDocument/rangeFormatting" => {
12814 server.update_capabilities(|capabilities| {
12815 capabilities.document_range_formatting_provider = None
12816 });
12817 notify_server_capabilities_updated(&server, cx);
12818 }
12819 "textDocument/onTypeFormatting" => {
12820 server.update_capabilities(|capabilities| {
12821 capabilities.document_on_type_formatting_provider = None;
12822 });
12823 notify_server_capabilities_updated(&server, cx);
12824 }
12825 "textDocument/formatting" => {
12826 server.update_capabilities(|capabilities| {
12827 capabilities.document_formatting_provider = None;
12828 });
12829 notify_server_capabilities_updated(&server, cx);
12830 }
12831 "textDocument/rename" => {
12832 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12833 notify_server_capabilities_updated(&server, cx);
12834 }
12835 "textDocument/codeAction" => {
12836 server.update_capabilities(|capabilities| {
12837 capabilities.code_action_provider = None;
12838 });
12839 notify_server_capabilities_updated(&server, cx);
12840 }
12841 "textDocument/definition" => {
12842 server.update_capabilities(|capabilities| {
12843 capabilities.definition_provider = None;
12844 });
12845 notify_server_capabilities_updated(&server, cx);
12846 }
12847 "textDocument/completion" => {
12848 server.update_capabilities(|capabilities| {
12849 capabilities.completion_provider = None;
12850 });
12851 notify_server_capabilities_updated(&server, cx);
12852 }
12853 "textDocument/hover" => {
12854 server.update_capabilities(|capabilities| {
12855 capabilities.hover_provider = None;
12856 });
12857 notify_server_capabilities_updated(&server, cx);
12858 }
12859 "textDocument/signatureHelp" => {
12860 server.update_capabilities(|capabilities| {
12861 capabilities.signature_help_provider = None;
12862 });
12863 notify_server_capabilities_updated(&server, cx);
12864 }
12865 "textDocument/didChange" => {
12866 server.update_capabilities(|capabilities| {
12867 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12868 sync_options.change = None;
12869 capabilities.text_document_sync =
12870 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12871 });
12872 notify_server_capabilities_updated(&server, cx);
12873 }
12874 "textDocument/didSave" => {
12875 server.update_capabilities(|capabilities| {
12876 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12877 sync_options.save = None;
12878 capabilities.text_document_sync =
12879 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12880 });
12881 notify_server_capabilities_updated(&server, cx);
12882 }
12883 "textDocument/codeLens" => {
12884 server.update_capabilities(|capabilities| {
12885 capabilities.code_lens_provider = None;
12886 });
12887 notify_server_capabilities_updated(&server, cx);
12888 }
12889 "textDocument/diagnostic" => {
12890 let local = self
12891 .as_local_mut()
12892 .context("Expected LSP Store to be local")?;
12893
12894 let state = local
12895 .language_servers
12896 .get_mut(&server_id)
12897 .context("Could not obtain Language Servers state")?;
12898 let registrations = local
12899 .language_server_dynamic_registrations
12900 .get_mut(&server_id)
12901 .with_context(|| {
12902 format!("Expected dynamic registration to exist for server {server_id}")
12903 })?;
12904 registrations.diagnostics
12905 .remove(&Some(unreg.id.clone()))
12906 .with_context(|| format!(
12907 "Attempted to unregister non-existent diagnostic registration with ID {}",
12908 unreg.id)
12909 )?;
12910 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12911
12912 if let LanguageServerState::Running {
12913 workspace_diagnostics_refresh_tasks,
12914 ..
12915 } = state
12916 {
12917 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12918 }
12919
12920 self.clear_unregistered_diagnostics(
12921 server_id,
12922 SharedString::from(unreg.id.clone()),
12923 cx,
12924 )?;
12925
12926 if removed_last_diagnostic_provider {
12927 server.update_capabilities(|capabilities| {
12928 debug_assert!(capabilities.diagnostic_provider.is_some());
12929 capabilities.diagnostic_provider = None;
12930 });
12931 }
12932
12933 notify_server_capabilities_updated(&server, cx);
12934 }
12935 "textDocument/documentColor" => {
12936 server.update_capabilities(|capabilities| {
12937 capabilities.color_provider = None;
12938 });
12939 notify_server_capabilities_updated(&server, cx);
12940 }
12941 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12942 }
12943 }
12944
12945 Ok(())
12946 }
12947
12948 fn clear_unregistered_diagnostics(
12949 &mut self,
12950 server_id: LanguageServerId,
12951 cleared_registration_id: SharedString,
12952 cx: &mut Context<Self>,
12953 ) -> anyhow::Result<()> {
12954 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12955
12956 self.buffer_store.update(cx, |buffer_store, cx| {
12957 for buffer_handle in buffer_store.buffers() {
12958 let buffer = buffer_handle.read(cx);
12959 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12960 let Some(abs_path) = abs_path else {
12961 continue;
12962 };
12963 affected_abs_paths.insert(abs_path);
12964 }
12965 });
12966
12967 let local = self.as_local().context("Expected LSP Store to be local")?;
12968 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12969 let Some(worktree) = self
12970 .worktree_store
12971 .read(cx)
12972 .worktree_for_id(*worktree_id, cx)
12973 else {
12974 continue;
12975 };
12976
12977 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12978 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12979 let has_matching_registration =
12980 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12981 entry.diagnostic.registration_id.as_ref()
12982 == Some(&cleared_registration_id)
12983 });
12984 if has_matching_registration {
12985 let abs_path = worktree.read(cx).absolutize(rel_path);
12986 affected_abs_paths.insert(abs_path);
12987 }
12988 }
12989 }
12990 }
12991
12992 if affected_abs_paths.is_empty() {
12993 return Ok(());
12994 }
12995
12996 // Send a fake diagnostic update which clears the state for the registration ID
12997 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12998 affected_abs_paths
12999 .into_iter()
13000 .map(|abs_path| DocumentDiagnosticsUpdate {
13001 diagnostics: DocumentDiagnostics {
13002 diagnostics: Vec::new(),
13003 document_abs_path: abs_path,
13004 version: None,
13005 },
13006 result_id: None,
13007 registration_id: Some(cleared_registration_id.clone()),
13008 server_id,
13009 disk_based_sources: Cow::Borrowed(&[]),
13010 })
13011 .collect();
13012
13013 let merge_registration_id = cleared_registration_id.clone();
13014 self.merge_diagnostic_entries(
13015 clears,
13016 move |_, diagnostic, _| {
13017 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13018 diagnostic.registration_id != Some(merge_registration_id.clone())
13019 } else {
13020 true
13021 }
13022 },
13023 cx,
13024 )?;
13025
13026 Ok(())
13027 }
13028
13029 async fn deduplicate_range_based_lsp_requests<T>(
13030 lsp_store: &Entity<Self>,
13031 server_id: Option<LanguageServerId>,
13032 lsp_request_id: LspRequestId,
13033 proto_request: &T::ProtoRequest,
13034 range: Range<Anchor>,
13035 cx: &mut AsyncApp,
13036 ) -> Result<()>
13037 where
13038 T: LspCommand,
13039 T::ProtoRequest: proto::LspRequestMessage,
13040 {
13041 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13042 let version = deserialize_version(proto_request.buffer_version());
13043 let buffer = lsp_store.update(cx, |this, cx| {
13044 this.buffer_store.read(cx).get_existing(buffer_id)
13045 })?;
13046 buffer
13047 .update(cx, |buffer, _| buffer.wait_for_version(version))
13048 .await?;
13049 lsp_store.update(cx, |lsp_store, cx| {
13050 let buffer_snapshot = buffer.read(cx).snapshot();
13051 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13052 let chunks_queried_for = lsp_data
13053 .inlay_hints
13054 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13055 .collect::<Vec<_>>();
13056 match chunks_queried_for.as_slice() {
13057 &[chunk] => {
13058 let key = LspKey {
13059 request_type: TypeId::of::<T>(),
13060 server_queried: server_id,
13061 };
13062 let previous_request = lsp_data
13063 .chunk_lsp_requests
13064 .entry(key)
13065 .or_default()
13066 .insert(chunk, lsp_request_id);
13067 if let Some((previous_request, running_requests)) =
13068 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13069 {
13070 running_requests.remove(&previous_request);
13071 }
13072 }
13073 _ambiguous_chunks => {
13074 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13075 // there, a buffer version-based check will be performed and outdated requests discarded.
13076 }
13077 }
13078 anyhow::Ok(())
13079 })?;
13080
13081 Ok(())
13082 }
13083
13084 async fn query_lsp_locally<T>(
13085 lsp_store: Entity<Self>,
13086 for_server_id: Option<LanguageServerId>,
13087 sender_id: proto::PeerId,
13088 lsp_request_id: LspRequestId,
13089 proto_request: T::ProtoRequest,
13090 position: Option<Anchor>,
13091 cx: &mut AsyncApp,
13092 ) -> Result<()>
13093 where
13094 T: LspCommand + Clone,
13095 T::ProtoRequest: proto::LspRequestMessage,
13096 <T::ProtoRequest as proto::RequestMessage>::Response:
13097 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13098 {
13099 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13100 let version = deserialize_version(proto_request.buffer_version());
13101 let buffer = lsp_store.update(cx, |this, cx| {
13102 this.buffer_store.read(cx).get_existing(buffer_id)
13103 })?;
13104 buffer
13105 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13106 .await?;
13107 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13108 let request =
13109 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13110 let key = LspKey {
13111 request_type: TypeId::of::<T>(),
13112 server_queried: for_server_id,
13113 };
13114 lsp_store.update(cx, |lsp_store, cx| {
13115 let request_task = match for_server_id {
13116 Some(server_id) => {
13117 let server_task = lsp_store.request_lsp(
13118 buffer.clone(),
13119 LanguageServerToQuery::Other(server_id),
13120 request.clone(),
13121 cx,
13122 );
13123 cx.background_spawn(async move {
13124 let mut responses = Vec::new();
13125 match server_task.await {
13126 Ok(response) => responses.push((server_id, response)),
13127 // rust-analyzer likes to error with this when its still loading up
13128 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13129 Err(e) => log::error!(
13130 "Error handling response for request {request:?}: {e:#}"
13131 ),
13132 }
13133 responses
13134 })
13135 }
13136 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13137 };
13138 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13139 if T::ProtoRequest::stop_previous_requests() {
13140 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13141 lsp_requests.clear();
13142 }
13143 }
13144 lsp_data.lsp_requests.entry(key).or_default().insert(
13145 lsp_request_id,
13146 cx.spawn(async move |lsp_store, cx| {
13147 let response = request_task.await;
13148 lsp_store
13149 .update(cx, |lsp_store, cx| {
13150 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13151 {
13152 let response = response
13153 .into_iter()
13154 .map(|(server_id, response)| {
13155 (
13156 server_id.to_proto(),
13157 T::response_to_proto(
13158 response,
13159 lsp_store,
13160 sender_id,
13161 &buffer_version,
13162 cx,
13163 )
13164 .into(),
13165 )
13166 })
13167 .collect::<HashMap<_, _>>();
13168 match client.send_lsp_response::<T::ProtoRequest>(
13169 project_id,
13170 lsp_request_id,
13171 response,
13172 ) {
13173 Ok(()) => {}
13174 Err(e) => {
13175 log::error!("Failed to send LSP response: {e:#}",)
13176 }
13177 }
13178 }
13179 })
13180 .ok();
13181 }),
13182 );
13183 });
13184 Ok(())
13185 }
13186
13187 fn take_text_document_sync_options(
13188 capabilities: &mut lsp::ServerCapabilities,
13189 ) -> lsp::TextDocumentSyncOptions {
13190 match capabilities.text_document_sync.take() {
13191 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13192 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13193 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13194 sync_options.change = Some(sync_kind);
13195 sync_options
13196 }
13197 None => lsp::TextDocumentSyncOptions::default(),
13198 }
13199 }
13200
13201 #[cfg(any(test, feature = "test-support"))]
13202 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13203 Some(
13204 self.lsp_data
13205 .get_mut(&buffer_id)?
13206 .code_lens
13207 .take()?
13208 .update
13209 .take()?
13210 .1,
13211 )
13212 }
13213
13214 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13215 self.downstream_client.clone()
13216 }
13217
13218 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13219 self.worktree_store.clone()
13220 }
13221
13222 /// Gets what's stored in the LSP data for the given buffer.
13223 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13224 self.lsp_data.get_mut(&buffer_id)
13225 }
13226
13227 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13228 /// new [`BufferLspData`] will be created to replace the previous state.
13229 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13230 let (buffer_id, buffer_version) =
13231 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13232 let lsp_data = self
13233 .lsp_data
13234 .entry(buffer_id)
13235 .or_insert_with(|| BufferLspData::new(buffer, cx));
13236 if buffer_version.changed_since(&lsp_data.buffer_version) {
13237 *lsp_data = BufferLspData::new(buffer, cx);
13238 }
13239 lsp_data
13240 }
13241}
13242
13243// Registration with registerOptions as null, should fallback to true.
13244// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13245fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13246 reg: lsp::Registration,
13247) -> Result<OneOf<bool, T>> {
13248 Ok(match reg.register_options {
13249 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13250 None => OneOf::Left(true),
13251 })
13252}
13253
13254fn subscribe_to_binary_statuses(
13255 languages: &Arc<LanguageRegistry>,
13256 cx: &mut Context<'_, LspStore>,
13257) -> Task<()> {
13258 let mut server_statuses = languages.language_server_binary_statuses();
13259 cx.spawn(async move |lsp_store, cx| {
13260 while let Some((server_name, binary_status)) = server_statuses.next().await {
13261 if lsp_store
13262 .update(cx, |_, cx| {
13263 let mut message = None;
13264 let binary_status = match binary_status {
13265 BinaryStatus::None => proto::ServerBinaryStatus::None,
13266 BinaryStatus::CheckingForUpdate => {
13267 proto::ServerBinaryStatus::CheckingForUpdate
13268 }
13269 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13270 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13271 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13272 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13273 BinaryStatus::Failed { error } => {
13274 message = Some(error);
13275 proto::ServerBinaryStatus::Failed
13276 }
13277 };
13278 cx.emit(LspStoreEvent::LanguageServerUpdate {
13279 // Binary updates are about the binary that might not have any language server id at that point.
13280 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13281 language_server_id: LanguageServerId(0),
13282 name: Some(server_name),
13283 message: proto::update_language_server::Variant::StatusUpdate(
13284 proto::StatusUpdate {
13285 message,
13286 status: Some(proto::status_update::Status::Binary(
13287 binary_status as i32,
13288 )),
13289 },
13290 ),
13291 });
13292 })
13293 .is_err()
13294 {
13295 break;
13296 }
13297 }
13298 })
13299}
13300
13301fn lsp_workspace_diagnostics_refresh(
13302 registration_id: Option<String>,
13303 options: DiagnosticServerCapabilities,
13304 server: Arc<LanguageServer>,
13305 cx: &mut Context<'_, LspStore>,
13306) -> Option<WorkspaceRefreshTask> {
13307 let identifier = workspace_diagnostic_identifier(&options)?;
13308 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13309
13310 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13311 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13312 refresh_tx.try_send(()).ok();
13313
13314 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13315 let mut attempts = 0;
13316 let max_attempts = 50;
13317 let mut requests = 0;
13318
13319 loop {
13320 let Some(()) = refresh_rx.recv().await else {
13321 return;
13322 };
13323
13324 'request: loop {
13325 requests += 1;
13326 if attempts > max_attempts {
13327 log::error!(
13328 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13329 );
13330 return;
13331 }
13332 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13333 cx.background_executor()
13334 .timer(Duration::from_millis(backoff_millis))
13335 .await;
13336 attempts += 1;
13337
13338 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13339 lsp_store
13340 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13341 .into_iter()
13342 .filter_map(|(abs_path, result_id)| {
13343 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13344 Some(lsp::PreviousResultId {
13345 uri,
13346 value: result_id.to_string(),
13347 })
13348 })
13349 .collect()
13350 }) else {
13351 return;
13352 };
13353
13354 let token = if let Some(registration_id) = ®istration_id {
13355 format!(
13356 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13357 server.server_id(),
13358 )
13359 } else {
13360 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13361 };
13362
13363 progress_rx.try_recv().ok();
13364 let timer =
13365 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13366 let progress = pin!(progress_rx.recv().fuse());
13367 let response_result = server
13368 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13369 lsp::WorkspaceDiagnosticParams {
13370 previous_result_ids,
13371 identifier: identifier.clone(),
13372 work_done_progress_params: Default::default(),
13373 partial_result_params: lsp::PartialResultParams {
13374 partial_result_token: Some(lsp::ProgressToken::String(token)),
13375 },
13376 },
13377 select(timer, progress).then(|either| match either {
13378 Either::Left((message, ..)) => ready(message).left_future(),
13379 Either::Right(..) => pending::<String>().right_future(),
13380 }),
13381 )
13382 .await;
13383
13384 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13385 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13386 match response_result {
13387 ConnectionResult::Timeout => {
13388 log::error!("Timeout during workspace diagnostics pull");
13389 continue 'request;
13390 }
13391 ConnectionResult::ConnectionReset => {
13392 log::error!("Server closed a workspace diagnostics pull request");
13393 continue 'request;
13394 }
13395 ConnectionResult::Result(Err(e)) => {
13396 log::error!("Error during workspace diagnostics pull: {e:#}");
13397 break 'request;
13398 }
13399 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13400 attempts = 0;
13401 if lsp_store
13402 .update(cx, |lsp_store, cx| {
13403 lsp_store.apply_workspace_diagnostic_report(
13404 server.server_id(),
13405 pulled_diagnostics,
13406 registration_id_shared.clone(),
13407 cx,
13408 )
13409 })
13410 .is_err()
13411 {
13412 return;
13413 }
13414 break 'request;
13415 }
13416 }
13417 }
13418 }
13419 });
13420
13421 Some(WorkspaceRefreshTask {
13422 refresh_tx,
13423 progress_tx,
13424 task: workspace_query_language_server,
13425 })
13426}
13427
13428fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13429 match &options {
13430 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13431 diagnostic_options.identifier.clone()
13432 }
13433 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13434 let diagnostic_options = ®istration_options.diagnostic_options;
13435 diagnostic_options.identifier.clone()
13436 }
13437 }
13438}
13439
13440fn workspace_diagnostic_identifier(
13441 options: &DiagnosticServerCapabilities,
13442) -> Option<Option<String>> {
13443 match &options {
13444 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13445 if !diagnostic_options.workspace_diagnostics {
13446 return None;
13447 }
13448 Some(diagnostic_options.identifier.clone())
13449 }
13450 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13451 let diagnostic_options = ®istration_options.diagnostic_options;
13452 if !diagnostic_options.workspace_diagnostics {
13453 return None;
13454 }
13455 Some(diagnostic_options.identifier.clone())
13456 }
13457 }
13458}
13459
13460fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13461 let CompletionSource::BufferWord {
13462 word_range,
13463 resolved,
13464 } = &mut completion.source
13465 else {
13466 return;
13467 };
13468 if *resolved {
13469 return;
13470 }
13471
13472 if completion.new_text
13473 != snapshot
13474 .text_for_range(word_range.clone())
13475 .collect::<String>()
13476 {
13477 return;
13478 }
13479
13480 let mut offset = 0;
13481 for chunk in snapshot.chunks(word_range.clone(), true) {
13482 let end_offset = offset + chunk.text.len();
13483 if let Some(highlight_id) = chunk.syntax_highlight_id {
13484 completion
13485 .label
13486 .runs
13487 .push((offset..end_offset, highlight_id));
13488 }
13489 offset = end_offset;
13490 }
13491 *resolved = true;
13492}
13493
13494impl EventEmitter<LspStoreEvent> for LspStore {}
13495
13496fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13497 hover
13498 .contents
13499 .retain(|hover_block| !hover_block.text.trim().is_empty());
13500 if hover.contents.is_empty() {
13501 None
13502 } else {
13503 Some(hover)
13504 }
13505}
13506
13507async fn populate_labels_for_completions(
13508 new_completions: Vec<CoreCompletion>,
13509 language: Option<Arc<Language>>,
13510 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13511) -> Vec<Completion> {
13512 let lsp_completions = new_completions
13513 .iter()
13514 .filter_map(|new_completion| {
13515 new_completion
13516 .source
13517 .lsp_completion(true)
13518 .map(|lsp_completion| lsp_completion.into_owned())
13519 })
13520 .collect::<Vec<_>>();
13521
13522 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13523 lsp_adapter
13524 .labels_for_completions(&lsp_completions, language)
13525 .await
13526 .log_err()
13527 .unwrap_or_default()
13528 } else {
13529 Vec::new()
13530 }
13531 .into_iter()
13532 .fuse();
13533
13534 let mut completions = Vec::new();
13535 for completion in new_completions {
13536 match completion.source.lsp_completion(true) {
13537 Some(lsp_completion) => {
13538 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13539
13540 let mut label = labels.next().flatten().unwrap_or_else(|| {
13541 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13542 });
13543 ensure_uniform_list_compatible_label(&mut label);
13544 completions.push(Completion {
13545 label,
13546 documentation,
13547 replace_range: completion.replace_range,
13548 new_text: completion.new_text,
13549 insert_text_mode: lsp_completion.insert_text_mode,
13550 source: completion.source,
13551 icon_path: None,
13552 confirm: None,
13553 match_start: None,
13554 snippet_deduplication_key: None,
13555 });
13556 }
13557 None => {
13558 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13559 ensure_uniform_list_compatible_label(&mut label);
13560 completions.push(Completion {
13561 label,
13562 documentation: None,
13563 replace_range: completion.replace_range,
13564 new_text: completion.new_text,
13565 source: completion.source,
13566 insert_text_mode: None,
13567 icon_path: None,
13568 confirm: None,
13569 match_start: None,
13570 snippet_deduplication_key: None,
13571 });
13572 }
13573 }
13574 }
13575 completions
13576}
13577
13578#[derive(Debug)]
13579pub enum LanguageServerToQuery {
13580 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13581 FirstCapable,
13582 /// Query a specific language server.
13583 Other(LanguageServerId),
13584}
13585
13586#[derive(Default)]
13587struct RenamePathsWatchedForServer {
13588 did_rename: Vec<RenameActionPredicate>,
13589 will_rename: Vec<RenameActionPredicate>,
13590}
13591
13592impl RenamePathsWatchedForServer {
13593 fn with_did_rename_patterns(
13594 mut self,
13595 did_rename: Option<&FileOperationRegistrationOptions>,
13596 ) -> Self {
13597 if let Some(did_rename) = did_rename {
13598 self.did_rename = did_rename
13599 .filters
13600 .iter()
13601 .filter_map(|filter| filter.try_into().log_err())
13602 .collect();
13603 }
13604 self
13605 }
13606 fn with_will_rename_patterns(
13607 mut self,
13608 will_rename: Option<&FileOperationRegistrationOptions>,
13609 ) -> Self {
13610 if let Some(will_rename) = will_rename {
13611 self.will_rename = will_rename
13612 .filters
13613 .iter()
13614 .filter_map(|filter| filter.try_into().log_err())
13615 .collect();
13616 }
13617 self
13618 }
13619
13620 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13621 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13622 }
13623 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13624 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13625 }
13626}
13627
13628impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13629 type Error = globset::Error;
13630 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13631 Ok(Self {
13632 kind: ops.pattern.matches.clone(),
13633 glob: GlobBuilder::new(&ops.pattern.glob)
13634 .case_insensitive(
13635 ops.pattern
13636 .options
13637 .as_ref()
13638 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13639 )
13640 .build()?
13641 .compile_matcher(),
13642 })
13643 }
13644}
13645struct RenameActionPredicate {
13646 glob: GlobMatcher,
13647 kind: Option<FileOperationPatternKind>,
13648}
13649
13650impl RenameActionPredicate {
13651 // Returns true if language server should be notified
13652 fn eval(&self, path: &str, is_dir: bool) -> bool {
13653 self.kind.as_ref().is_none_or(|kind| {
13654 let expected_kind = if is_dir {
13655 FileOperationPatternKind::Folder
13656 } else {
13657 FileOperationPatternKind::File
13658 };
13659 kind == &expected_kind
13660 }) && self.glob.is_match(path)
13661 }
13662}
13663
13664#[derive(Default)]
13665struct LanguageServerWatchedPaths {
13666 worktree_paths: HashMap<WorktreeId, GlobSet>,
13667 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13668}
13669
13670#[derive(Default)]
13671struct LanguageServerWatchedPathsBuilder {
13672 worktree_paths: HashMap<WorktreeId, GlobSet>,
13673 abs_paths: HashMap<Arc<Path>, GlobSet>,
13674}
13675
13676impl LanguageServerWatchedPathsBuilder {
13677 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13678 self.worktree_paths.insert(worktree_id, glob_set);
13679 }
13680 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13681 self.abs_paths.insert(path, glob_set);
13682 }
13683 fn build(
13684 self,
13685 fs: Arc<dyn Fs>,
13686 language_server_id: LanguageServerId,
13687 cx: &mut Context<LspStore>,
13688 ) -> LanguageServerWatchedPaths {
13689 let lsp_store = cx.weak_entity();
13690
13691 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13692 let abs_paths = self
13693 .abs_paths
13694 .into_iter()
13695 .map(|(abs_path, globset)| {
13696 let task = cx.spawn({
13697 let abs_path = abs_path.clone();
13698 let fs = fs.clone();
13699
13700 let lsp_store = lsp_store.clone();
13701 async move |_, cx| {
13702 maybe!(async move {
13703 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13704 while let Some(update) = push_updates.0.next().await {
13705 let action = lsp_store
13706 .update(cx, |this, _| {
13707 let Some(local) = this.as_local() else {
13708 return ControlFlow::Break(());
13709 };
13710 let Some(watcher) = local
13711 .language_server_watched_paths
13712 .get(&language_server_id)
13713 else {
13714 return ControlFlow::Break(());
13715 };
13716 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13717 "Watched abs path is not registered with a watcher",
13718 );
13719 let matching_entries = update
13720 .into_iter()
13721 .filter(|event| globs.is_match(&event.path))
13722 .collect::<Vec<_>>();
13723 this.lsp_notify_abs_paths_changed(
13724 language_server_id,
13725 matching_entries,
13726 );
13727 ControlFlow::Continue(())
13728 })
13729 .ok()?;
13730
13731 if action.is_break() {
13732 break;
13733 }
13734 }
13735 Some(())
13736 })
13737 .await;
13738 }
13739 });
13740 (abs_path, (globset, task))
13741 })
13742 .collect();
13743 LanguageServerWatchedPaths {
13744 worktree_paths: self.worktree_paths,
13745 abs_paths,
13746 }
13747 }
13748}
13749
13750struct LspBufferSnapshot {
13751 version: i32,
13752 snapshot: TextBufferSnapshot,
13753}
13754
13755/// A prompt requested by LSP server.
13756#[derive(Clone, Debug)]
13757pub struct LanguageServerPromptRequest {
13758 pub level: PromptLevel,
13759 pub message: String,
13760 pub actions: Vec<MessageActionItem>,
13761 pub lsp_name: String,
13762 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13763}
13764
13765impl LanguageServerPromptRequest {
13766 pub async fn respond(self, index: usize) -> Option<()> {
13767 if let Some(response) = self.actions.into_iter().nth(index) {
13768 self.response_channel.send(response).await.ok()
13769 } else {
13770 None
13771 }
13772 }
13773}
13774impl PartialEq for LanguageServerPromptRequest {
13775 fn eq(&self, other: &Self) -> bool {
13776 self.message == other.message && self.actions == other.actions
13777 }
13778}
13779
13780#[derive(Clone, Debug, PartialEq)]
13781pub enum LanguageServerLogType {
13782 Log(MessageType),
13783 Trace { verbose_info: Option<String> },
13784 Rpc { received: bool },
13785}
13786
13787impl LanguageServerLogType {
13788 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13789 match self {
13790 Self::Log(log_type) => {
13791 use proto::log_message::LogLevel;
13792 let level = match *log_type {
13793 MessageType::ERROR => LogLevel::Error,
13794 MessageType::WARNING => LogLevel::Warning,
13795 MessageType::INFO => LogLevel::Info,
13796 MessageType::LOG => LogLevel::Log,
13797 other => {
13798 log::warn!("Unknown lsp log message type: {other:?}");
13799 LogLevel::Log
13800 }
13801 };
13802 proto::language_server_log::LogType::Log(proto::LogMessage {
13803 level: level as i32,
13804 })
13805 }
13806 Self::Trace { verbose_info } => {
13807 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13808 verbose_info: verbose_info.to_owned(),
13809 })
13810 }
13811 Self::Rpc { received } => {
13812 let kind = if *received {
13813 proto::rpc_message::Kind::Received
13814 } else {
13815 proto::rpc_message::Kind::Sent
13816 };
13817 let kind = kind as i32;
13818 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13819 }
13820 }
13821 }
13822
13823 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13824 use proto::log_message::LogLevel;
13825 use proto::rpc_message;
13826 match log_type {
13827 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13828 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13829 LogLevel::Error => MessageType::ERROR,
13830 LogLevel::Warning => MessageType::WARNING,
13831 LogLevel::Info => MessageType::INFO,
13832 LogLevel::Log => MessageType::LOG,
13833 },
13834 ),
13835 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13836 verbose_info: trace_message.verbose_info,
13837 },
13838 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13839 received: match rpc_message::Kind::from_i32(message.kind)
13840 .unwrap_or(rpc_message::Kind::Received)
13841 {
13842 rpc_message::Kind::Received => true,
13843 rpc_message::Kind::Sent => false,
13844 },
13845 },
13846 }
13847 }
13848}
13849
13850pub struct WorkspaceRefreshTask {
13851 refresh_tx: mpsc::Sender<()>,
13852 progress_tx: mpsc::Sender<()>,
13853 #[allow(dead_code)]
13854 task: Task<()>,
13855}
13856
13857pub enum LanguageServerState {
13858 Starting {
13859 startup: Task<Option<Arc<LanguageServer>>>,
13860 /// List of language servers that will be added to the workspace once it's initialization completes.
13861 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13862 },
13863
13864 Running {
13865 adapter: Arc<CachedLspAdapter>,
13866 server: Arc<LanguageServer>,
13867 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13868 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13869 },
13870}
13871
13872impl LanguageServerState {
13873 fn add_workspace_folder(&self, uri: Uri) {
13874 match self {
13875 LanguageServerState::Starting {
13876 pending_workspace_folders,
13877 ..
13878 } => {
13879 pending_workspace_folders.lock().insert(uri);
13880 }
13881 LanguageServerState::Running { server, .. } => {
13882 server.add_workspace_folder(uri);
13883 }
13884 }
13885 }
13886 fn _remove_workspace_folder(&self, uri: Uri) {
13887 match self {
13888 LanguageServerState::Starting {
13889 pending_workspace_folders,
13890 ..
13891 } => {
13892 pending_workspace_folders.lock().remove(&uri);
13893 }
13894 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13895 }
13896 }
13897}
13898
13899impl std::fmt::Debug for LanguageServerState {
13900 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13901 match self {
13902 LanguageServerState::Starting { .. } => {
13903 f.debug_struct("LanguageServerState::Starting").finish()
13904 }
13905 LanguageServerState::Running { .. } => {
13906 f.debug_struct("LanguageServerState::Running").finish()
13907 }
13908 }
13909 }
13910}
13911
13912#[derive(Clone, Debug, Serialize)]
13913pub struct LanguageServerProgress {
13914 pub is_disk_based_diagnostics_progress: bool,
13915 pub is_cancellable: bool,
13916 pub title: Option<String>,
13917 pub message: Option<String>,
13918 pub percentage: Option<usize>,
13919 #[serde(skip_serializing)]
13920 pub last_update_at: Instant,
13921}
13922
13923#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13924pub struct DiagnosticSummary {
13925 pub error_count: usize,
13926 pub warning_count: usize,
13927}
13928
13929impl DiagnosticSummary {
13930 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13931 let mut this = Self {
13932 error_count: 0,
13933 warning_count: 0,
13934 };
13935
13936 for entry in diagnostics {
13937 if entry.diagnostic.is_primary {
13938 match entry.diagnostic.severity {
13939 DiagnosticSeverity::ERROR => this.error_count += 1,
13940 DiagnosticSeverity::WARNING => this.warning_count += 1,
13941 _ => {}
13942 }
13943 }
13944 }
13945
13946 this
13947 }
13948
13949 pub fn is_empty(&self) -> bool {
13950 self.error_count == 0 && self.warning_count == 0
13951 }
13952
13953 pub fn to_proto(
13954 self,
13955 language_server_id: LanguageServerId,
13956 path: &RelPath,
13957 ) -> proto::DiagnosticSummary {
13958 proto::DiagnosticSummary {
13959 path: path.to_proto(),
13960 language_server_id: language_server_id.0 as u64,
13961 error_count: self.error_count as u32,
13962 warning_count: self.warning_count as u32,
13963 }
13964 }
13965}
13966
13967#[derive(Clone, Debug)]
13968pub enum CompletionDocumentation {
13969 /// There is no documentation for this completion.
13970 Undocumented,
13971 /// A single line of documentation.
13972 SingleLine(SharedString),
13973 /// Multiple lines of plain text documentation.
13974 MultiLinePlainText(SharedString),
13975 /// Markdown documentation.
13976 MultiLineMarkdown(SharedString),
13977 /// Both single line and multiple lines of plain text documentation.
13978 SingleLineAndMultiLinePlainText {
13979 single_line: SharedString,
13980 plain_text: Option<SharedString>,
13981 },
13982}
13983
13984impl CompletionDocumentation {
13985 #[cfg(any(test, feature = "test-support"))]
13986 pub fn text(&self) -> SharedString {
13987 match self {
13988 CompletionDocumentation::Undocumented => "".into(),
13989 CompletionDocumentation::SingleLine(s) => s.clone(),
13990 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13991 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13992 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13993 single_line.clone()
13994 }
13995 }
13996 }
13997}
13998
13999impl From<lsp::Documentation> for CompletionDocumentation {
14000 fn from(docs: lsp::Documentation) -> Self {
14001 match docs {
14002 lsp::Documentation::String(text) => {
14003 if text.lines().count() <= 1 {
14004 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14005 } else {
14006 CompletionDocumentation::MultiLinePlainText(text.into())
14007 }
14008 }
14009
14010 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14011 lsp::MarkupKind::PlainText => {
14012 if value.lines().count() <= 1 {
14013 CompletionDocumentation::SingleLine(value.into())
14014 } else {
14015 CompletionDocumentation::MultiLinePlainText(value.into())
14016 }
14017 }
14018
14019 lsp::MarkupKind::Markdown => {
14020 CompletionDocumentation::MultiLineMarkdown(value.into())
14021 }
14022 },
14023 }
14024 }
14025}
14026
14027pub enum ResolvedHint {
14028 Resolved(InlayHint),
14029 Resolving(Shared<Task<()>>),
14030}
14031
14032fn glob_literal_prefix(glob: &Path) -> PathBuf {
14033 glob.components()
14034 .take_while(|component| match component {
14035 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14036 _ => true,
14037 })
14038 .collect()
14039}
14040
14041pub struct SshLspAdapter {
14042 name: LanguageServerName,
14043 binary: LanguageServerBinary,
14044 initialization_options: Option<String>,
14045 code_action_kinds: Option<Vec<CodeActionKind>>,
14046}
14047
14048impl SshLspAdapter {
14049 pub fn new(
14050 name: LanguageServerName,
14051 binary: LanguageServerBinary,
14052 initialization_options: Option<String>,
14053 code_action_kinds: Option<String>,
14054 ) -> Self {
14055 Self {
14056 name,
14057 binary,
14058 initialization_options,
14059 code_action_kinds: code_action_kinds
14060 .as_ref()
14061 .and_then(|c| serde_json::from_str(c).ok()),
14062 }
14063 }
14064}
14065
14066impl LspInstaller for SshLspAdapter {
14067 type BinaryVersion = ();
14068 async fn check_if_user_installed(
14069 &self,
14070 _: &dyn LspAdapterDelegate,
14071 _: Option<Toolchain>,
14072 _: &AsyncApp,
14073 ) -> Option<LanguageServerBinary> {
14074 Some(self.binary.clone())
14075 }
14076
14077 async fn cached_server_binary(
14078 &self,
14079 _: PathBuf,
14080 _: &dyn LspAdapterDelegate,
14081 ) -> Option<LanguageServerBinary> {
14082 None
14083 }
14084
14085 async fn fetch_latest_server_version(
14086 &self,
14087 _: &dyn LspAdapterDelegate,
14088 _: bool,
14089 _: &mut AsyncApp,
14090 ) -> Result<()> {
14091 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14092 }
14093
14094 async fn fetch_server_binary(
14095 &self,
14096 _: (),
14097 _: PathBuf,
14098 _: &dyn LspAdapterDelegate,
14099 ) -> Result<LanguageServerBinary> {
14100 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14101 }
14102}
14103
14104#[async_trait(?Send)]
14105impl LspAdapter for SshLspAdapter {
14106 fn name(&self) -> LanguageServerName {
14107 self.name.clone()
14108 }
14109
14110 async fn initialization_options(
14111 self: Arc<Self>,
14112 _: &Arc<dyn LspAdapterDelegate>,
14113 ) -> Result<Option<serde_json::Value>> {
14114 let Some(options) = &self.initialization_options else {
14115 return Ok(None);
14116 };
14117 let result = serde_json::from_str(options)?;
14118 Ok(result)
14119 }
14120
14121 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14122 self.code_action_kinds.clone()
14123 }
14124}
14125
14126pub fn language_server_settings<'a>(
14127 delegate: &'a dyn LspAdapterDelegate,
14128 language: &LanguageServerName,
14129 cx: &'a App,
14130) -> Option<&'a LspSettings> {
14131 language_server_settings_for(
14132 SettingsLocation {
14133 worktree_id: delegate.worktree_id(),
14134 path: RelPath::empty(),
14135 },
14136 language,
14137 cx,
14138 )
14139}
14140
14141pub fn language_server_settings_for<'a>(
14142 location: SettingsLocation<'a>,
14143 language: &LanguageServerName,
14144 cx: &'a App,
14145) -> Option<&'a LspSettings> {
14146 ProjectSettings::get(Some(location), cx).lsp.get(language)
14147}
14148
14149pub struct LocalLspAdapterDelegate {
14150 lsp_store: WeakEntity<LspStore>,
14151 worktree: worktree::Snapshot,
14152 fs: Arc<dyn Fs>,
14153 http_client: Arc<dyn HttpClient>,
14154 language_registry: Arc<LanguageRegistry>,
14155 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14156}
14157
14158impl LocalLspAdapterDelegate {
14159 pub fn new(
14160 language_registry: Arc<LanguageRegistry>,
14161 environment: &Entity<ProjectEnvironment>,
14162 lsp_store: WeakEntity<LspStore>,
14163 worktree: &Entity<Worktree>,
14164 http_client: Arc<dyn HttpClient>,
14165 fs: Arc<dyn Fs>,
14166 cx: &mut App,
14167 ) -> Arc<Self> {
14168 let load_shell_env_task =
14169 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14170
14171 Arc::new(Self {
14172 lsp_store,
14173 worktree: worktree.read(cx).snapshot(),
14174 fs,
14175 http_client,
14176 language_registry,
14177 load_shell_env_task,
14178 })
14179 }
14180
14181 pub fn from_local_lsp(
14182 local: &LocalLspStore,
14183 worktree: &Entity<Worktree>,
14184 cx: &mut App,
14185 ) -> Arc<Self> {
14186 Self::new(
14187 local.languages.clone(),
14188 &local.environment,
14189 local.weak.clone(),
14190 worktree,
14191 local.http_client.clone(),
14192 local.fs.clone(),
14193 cx,
14194 )
14195 }
14196}
14197
14198#[async_trait]
14199impl LspAdapterDelegate for LocalLspAdapterDelegate {
14200 fn show_notification(&self, message: &str, cx: &mut App) {
14201 self.lsp_store
14202 .update(cx, |_, cx| {
14203 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14204 })
14205 .ok();
14206 }
14207
14208 fn http_client(&self) -> Arc<dyn HttpClient> {
14209 self.http_client.clone()
14210 }
14211
14212 fn worktree_id(&self) -> WorktreeId {
14213 self.worktree.id()
14214 }
14215
14216 fn worktree_root_path(&self) -> &Path {
14217 self.worktree.abs_path().as_ref()
14218 }
14219
14220 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14221 self.worktree.resolve_executable_path(path)
14222 }
14223
14224 async fn shell_env(&self) -> HashMap<String, String> {
14225 let task = self.load_shell_env_task.clone();
14226 task.await.unwrap_or_default()
14227 }
14228
14229 async fn npm_package_installed_version(
14230 &self,
14231 package_name: &str,
14232 ) -> Result<Option<(PathBuf, Version)>> {
14233 let local_package_directory = self.worktree_root_path();
14234 let node_modules_directory = local_package_directory.join("node_modules");
14235
14236 if let Some(version) =
14237 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14238 {
14239 return Ok(Some((node_modules_directory, version)));
14240 }
14241 let Some(npm) = self.which("npm".as_ref()).await else {
14242 log::warn!(
14243 "Failed to find npm executable for {:?}",
14244 local_package_directory
14245 );
14246 return Ok(None);
14247 };
14248
14249 let env = self.shell_env().await;
14250 let output = util::command::new_smol_command(&npm)
14251 .args(["root", "-g"])
14252 .envs(env)
14253 .current_dir(local_package_directory)
14254 .output()
14255 .await?;
14256 let global_node_modules =
14257 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14258
14259 if let Some(version) =
14260 read_package_installed_version(global_node_modules.clone(), package_name).await?
14261 {
14262 return Ok(Some((global_node_modules, version)));
14263 }
14264 return Ok(None);
14265 }
14266
14267 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14268 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14269 if self.fs.is_file(&worktree_abs_path).await {
14270 worktree_abs_path.pop();
14271 }
14272
14273 let env = self.shell_env().await;
14274
14275 let shell_path = env.get("PATH").cloned();
14276
14277 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14278 }
14279
14280 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14281 let mut working_dir = self.worktree_root_path().to_path_buf();
14282 if self.fs.is_file(&working_dir).await {
14283 working_dir.pop();
14284 }
14285 let output = util::command::new_smol_command(&command.path)
14286 .args(command.arguments)
14287 .envs(command.env.clone().unwrap_or_default())
14288 .current_dir(working_dir)
14289 .output()
14290 .await?;
14291
14292 anyhow::ensure!(
14293 output.status.success(),
14294 "{}, stdout: {:?}, stderr: {:?}",
14295 output.status,
14296 String::from_utf8_lossy(&output.stdout),
14297 String::from_utf8_lossy(&output.stderr)
14298 );
14299 Ok(())
14300 }
14301
14302 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14303 self.language_registry
14304 .update_lsp_binary_status(server_name, status);
14305 }
14306
14307 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14308 self.language_registry
14309 .all_lsp_adapters()
14310 .into_iter()
14311 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14312 .collect()
14313 }
14314
14315 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14316 let dir = self.language_registry.language_server_download_dir(name)?;
14317
14318 if !dir.exists() {
14319 smol::fs::create_dir_all(&dir)
14320 .await
14321 .context("failed to create container directory")
14322 .log_err()?;
14323 }
14324
14325 Some(dir)
14326 }
14327
14328 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14329 let entry = self
14330 .worktree
14331 .entry_for_path(path)
14332 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14333 let abs_path = self.worktree.absolutize(&entry.path);
14334 self.fs.load(&abs_path).await
14335 }
14336}
14337
14338async fn populate_labels_for_symbols(
14339 symbols: Vec<CoreSymbol>,
14340 language_registry: &Arc<LanguageRegistry>,
14341 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14342 output: &mut Vec<Symbol>,
14343) {
14344 #[allow(clippy::mutable_key_type)]
14345 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14346
14347 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14348 for symbol in symbols {
14349 let Some(file_name) = symbol.path.file_name() else {
14350 continue;
14351 };
14352 let language = language_registry
14353 .load_language_for_file_path(Path::new(file_name))
14354 .await
14355 .ok()
14356 .or_else(|| {
14357 unknown_paths.insert(file_name.into());
14358 None
14359 });
14360 symbols_by_language
14361 .entry(language)
14362 .or_default()
14363 .push(symbol);
14364 }
14365
14366 for unknown_path in unknown_paths {
14367 log::info!("no language found for symbol in file {unknown_path:?}");
14368 }
14369
14370 let mut label_params = Vec::new();
14371 for (language, mut symbols) in symbols_by_language {
14372 label_params.clear();
14373 label_params.extend(
14374 symbols
14375 .iter_mut()
14376 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14377 );
14378
14379 let mut labels = Vec::new();
14380 if let Some(language) = language {
14381 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14382 language_registry
14383 .lsp_adapters(&language.name())
14384 .first()
14385 .cloned()
14386 });
14387 if let Some(lsp_adapter) = lsp_adapter {
14388 labels = lsp_adapter
14389 .labels_for_symbols(&label_params, &language)
14390 .await
14391 .log_err()
14392 .unwrap_or_default();
14393 }
14394 }
14395
14396 for ((symbol, (name, _)), label) in symbols
14397 .into_iter()
14398 .zip(label_params.drain(..))
14399 .zip(labels.into_iter().chain(iter::repeat(None)))
14400 {
14401 output.push(Symbol {
14402 language_server_name: symbol.language_server_name,
14403 source_worktree_id: symbol.source_worktree_id,
14404 source_language_server_id: symbol.source_language_server_id,
14405 path: symbol.path,
14406 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14407 name,
14408 kind: symbol.kind,
14409 range: symbol.range,
14410 });
14411 }
14412 }
14413}
14414
14415fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14416 match server.capabilities().text_document_sync.as_ref()? {
14417 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14418 // Server wants didSave but didn't specify includeText.
14419 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14420 // Server doesn't want didSave at all.
14421 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14422 // Server provided SaveOptions.
14423 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14424 Some(save_options.include_text.unwrap_or(false))
14425 }
14426 },
14427 // We do not have any save info. Kind affects didChange only.
14428 lsp::TextDocumentSyncCapability::Kind(_) => None,
14429 }
14430}
14431
14432/// Completion items are displayed in a `UniformList`.
14433/// Usually, those items are single-line strings, but in LSP responses,
14434/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14435/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14436/// 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,
14437/// breaking the completions menu presentation.
14438///
14439/// 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.
14440fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14441 let mut new_text = String::with_capacity(label.text.len());
14442 let mut offset_map = vec![0; label.text.len() + 1];
14443 let mut last_char_was_space = false;
14444 let mut new_idx = 0;
14445 let chars = label.text.char_indices().fuse();
14446 let mut newlines_removed = false;
14447
14448 for (idx, c) in chars {
14449 offset_map[idx] = new_idx;
14450
14451 match c {
14452 '\n' if last_char_was_space => {
14453 newlines_removed = true;
14454 }
14455 '\t' | ' ' if last_char_was_space => {}
14456 '\n' if !last_char_was_space => {
14457 new_text.push(' ');
14458 new_idx += 1;
14459 last_char_was_space = true;
14460 newlines_removed = true;
14461 }
14462 ' ' | '\t' => {
14463 new_text.push(' ');
14464 new_idx += 1;
14465 last_char_was_space = true;
14466 }
14467 _ => {
14468 new_text.push(c);
14469 new_idx += c.len_utf8();
14470 last_char_was_space = false;
14471 }
14472 }
14473 }
14474 offset_map[label.text.len()] = new_idx;
14475
14476 // Only modify the label if newlines were removed.
14477 if !newlines_removed {
14478 return;
14479 }
14480
14481 let last_index = new_idx;
14482 let mut run_ranges_errors = Vec::new();
14483 label.runs.retain_mut(|(range, _)| {
14484 match offset_map.get(range.start) {
14485 Some(&start) => range.start = start,
14486 None => {
14487 run_ranges_errors.push(range.clone());
14488 return false;
14489 }
14490 }
14491
14492 match offset_map.get(range.end) {
14493 Some(&end) => range.end = end,
14494 None => {
14495 run_ranges_errors.push(range.clone());
14496 range.end = last_index;
14497 }
14498 }
14499 true
14500 });
14501 if !run_ranges_errors.is_empty() {
14502 log::error!(
14503 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14504 label.text
14505 );
14506 }
14507
14508 let mut wrong_filter_range = None;
14509 if label.filter_range == (0..label.text.len()) {
14510 label.filter_range = 0..new_text.len();
14511 } else {
14512 let mut original_filter_range = Some(label.filter_range.clone());
14513 match offset_map.get(label.filter_range.start) {
14514 Some(&start) => label.filter_range.start = start,
14515 None => {
14516 wrong_filter_range = original_filter_range.take();
14517 label.filter_range.start = last_index;
14518 }
14519 }
14520
14521 match offset_map.get(label.filter_range.end) {
14522 Some(&end) => label.filter_range.end = end,
14523 None => {
14524 wrong_filter_range = original_filter_range.take();
14525 label.filter_range.end = last_index;
14526 }
14527 }
14528 }
14529 if let Some(wrong_filter_range) = wrong_filter_range {
14530 log::error!(
14531 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14532 label.text
14533 );
14534 }
14535
14536 label.text = new_text;
14537}
14538
14539#[cfg(test)]
14540mod tests {
14541 use language::HighlightId;
14542
14543 use super::*;
14544
14545 #[test]
14546 fn test_glob_literal_prefix() {
14547 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14548 assert_eq!(
14549 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14550 Path::new("node_modules")
14551 );
14552 assert_eq!(
14553 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14554 Path::new("foo")
14555 );
14556 assert_eq!(
14557 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14558 Path::new("foo/bar/baz.js")
14559 );
14560
14561 #[cfg(target_os = "windows")]
14562 {
14563 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14564 assert_eq!(
14565 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14566 Path::new("node_modules")
14567 );
14568 assert_eq!(
14569 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14570 Path::new("foo")
14571 );
14572 assert_eq!(
14573 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14574 Path::new("foo/bar/baz.js")
14575 );
14576 }
14577 }
14578
14579 #[test]
14580 fn test_multi_len_chars_normalization() {
14581 let mut label = CodeLabel::new(
14582 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14583 0..6,
14584 vec![(0..6, HighlightId(1))],
14585 );
14586 ensure_uniform_list_compatible_label(&mut label);
14587 assert_eq!(
14588 label,
14589 CodeLabel::new(
14590 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14591 0..6,
14592 vec![(0..6, HighlightId(1))],
14593 )
14594 );
14595 }
14596
14597 #[test]
14598 fn test_trailing_newline_in_completion_documentation() {
14599 let doc = lsp::Documentation::String(
14600 "Inappropriate argument value (of correct type).\n".to_string(),
14601 );
14602 let completion_doc: CompletionDocumentation = doc.into();
14603 assert!(
14604 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
14605 );
14606
14607 let doc = lsp::Documentation::String(" some value \n".to_string());
14608 let completion_doc: CompletionDocumentation = doc.into();
14609 assert!(matches!(
14610 completion_doc,
14611 CompletionDocumentation::SingleLine(s) if s == "some value"
14612 ));
14613 }
14614}