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);
148static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
149
150#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
151pub enum ProgressToken {
152 Number(i32),
153 String(SharedString),
154}
155
156impl std::fmt::Display for ProgressToken {
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 match self {
159 Self::Number(number) => write!(f, "{number}"),
160 Self::String(string) => write!(f, "{string}"),
161 }
162 }
163}
164
165impl ProgressToken {
166 fn from_lsp(value: lsp::NumberOrString) -> Self {
167 match value {
168 lsp::NumberOrString::Number(number) => Self::Number(number),
169 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
170 }
171 }
172
173 fn to_lsp(&self) -> lsp::NumberOrString {
174 match self {
175 Self::Number(number) => lsp::NumberOrString::Number(*number),
176 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
177 }
178 }
179
180 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
181 Some(match value.value? {
182 proto::progress_token::Value::Number(number) => Self::Number(number),
183 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
184 })
185 }
186
187 fn to_proto(&self) -> proto::ProgressToken {
188 proto::ProgressToken {
189 value: Some(match self {
190 Self::Number(number) => proto::progress_token::Value::Number(*number),
191 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
192 }),
193 }
194 }
195}
196
197#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198pub enum FormatTrigger {
199 Save,
200 Manual,
201}
202
203pub enum LspFormatTarget {
204 Buffers,
205 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
206}
207
208#[derive(Clone, PartialEq, Eq, Hash)]
209pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
210
211struct OpenLspBuffer(Entity<Buffer>);
212
213impl FormatTrigger {
214 fn from_proto(value: i32) -> FormatTrigger {
215 match value {
216 0 => FormatTrigger::Save,
217 1 => FormatTrigger::Manual,
218 _ => FormatTrigger::Save,
219 }
220 }
221}
222
223#[derive(Clone)]
224struct UnifiedLanguageServer {
225 id: LanguageServerId,
226 project_roots: HashSet<Arc<RelPath>>,
227}
228
229#[derive(Clone, Debug, Hash, PartialEq, Eq)]
230struct LanguageServerSeed {
231 worktree_id: WorktreeId,
232 name: LanguageServerName,
233 toolchain: Option<Toolchain>,
234 settings: Arc<LspSettings>,
235}
236
237#[derive(Debug)]
238pub struct DocumentDiagnosticsUpdate<'a, D> {
239 pub diagnostics: D,
240 pub result_id: Option<SharedString>,
241 pub registration_id: Option<SharedString>,
242 pub server_id: LanguageServerId,
243 pub disk_based_sources: Cow<'a, [String]>,
244}
245
246pub struct DocumentDiagnostics {
247 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
248 document_abs_path: PathBuf,
249 version: Option<i32>,
250}
251
252#[derive(Default, Debug)]
253struct DynamicRegistrations {
254 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
255 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
256}
257
258pub struct LocalLspStore {
259 weak: WeakEntity<LspStore>,
260 pub worktree_store: Entity<WorktreeStore>,
261 toolchain_store: Entity<LocalToolchainStore>,
262 http_client: Arc<dyn HttpClient>,
263 environment: Entity<ProjectEnvironment>,
264 fs: Arc<dyn Fs>,
265 languages: Arc<LanguageRegistry>,
266 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
267 yarn: Entity<YarnPathStore>,
268 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
269 buffers_being_formatted: HashSet<BufferId>,
270 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
271 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
272 watched_manifest_filenames: HashSet<ManifestName>,
273 language_server_paths_watched_for_rename:
274 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
275 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
276 supplementary_language_servers:
277 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
278 prettier_store: Entity<PrettierStore>,
279 next_diagnostic_group_id: usize,
280 diagnostics: HashMap<
281 WorktreeId,
282 HashMap<
283 Arc<RelPath>,
284 Vec<(
285 LanguageServerId,
286 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
287 )>,
288 >,
289 >,
290 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
291 _subscription: gpui::Subscription,
292 lsp_tree: LanguageServerTree,
293 registered_buffers: HashMap<BufferId, usize>,
294 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
295 buffer_pull_diagnostics_result_ids: HashMap<
296 LanguageServerId,
297 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
298 >,
299 workspace_pull_diagnostics_result_ids: HashMap<
300 LanguageServerId,
301 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
302 >,
303 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
304}
305
306impl LocalLspStore {
307 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
308 pub fn running_language_server_for_id(
309 &self,
310 id: LanguageServerId,
311 ) -> Option<&Arc<LanguageServer>> {
312 let language_server_state = self.language_servers.get(&id)?;
313
314 match language_server_state {
315 LanguageServerState::Running { server, .. } => Some(server),
316 LanguageServerState::Starting { .. } => None,
317 }
318 }
319
320 fn get_or_insert_language_server(
321 &mut self,
322 worktree_handle: &Entity<Worktree>,
323 delegate: Arc<LocalLspAdapterDelegate>,
324 disposition: &Arc<LaunchDisposition>,
325 language_name: &LanguageName,
326 cx: &mut App,
327 ) -> LanguageServerId {
328 let key = LanguageServerSeed {
329 worktree_id: worktree_handle.read(cx).id(),
330 name: disposition.server_name.clone(),
331 settings: disposition.settings.clone(),
332 toolchain: disposition.toolchain.clone(),
333 };
334 if let Some(state) = self.language_server_ids.get_mut(&key) {
335 state.project_roots.insert(disposition.path.path.clone());
336 state.id
337 } else {
338 let adapter = self
339 .languages
340 .lsp_adapters(language_name)
341 .into_iter()
342 .find(|adapter| adapter.name() == disposition.server_name)
343 .expect("To find LSP adapter");
344 let new_language_server_id = self.start_language_server(
345 worktree_handle,
346 delegate,
347 adapter,
348 disposition.settings.clone(),
349 key.clone(),
350 cx,
351 );
352 if let Some(state) = self.language_server_ids.get_mut(&key) {
353 state.project_roots.insert(disposition.path.path.clone());
354 } else {
355 debug_assert!(
356 false,
357 "Expected `start_language_server` to ensure that `key` exists in a map"
358 );
359 }
360 new_language_server_id
361 }
362 }
363
364 fn start_language_server(
365 &mut self,
366 worktree_handle: &Entity<Worktree>,
367 delegate: Arc<LocalLspAdapterDelegate>,
368 adapter: Arc<CachedLspAdapter>,
369 settings: Arc<LspSettings>,
370 key: LanguageServerSeed,
371 cx: &mut App,
372 ) -> LanguageServerId {
373 let worktree = worktree_handle.read(cx);
374
375 let worktree_id = worktree.id();
376 let worktree_abs_path = worktree.abs_path();
377 let toolchain = key.toolchain.clone();
378 let override_options = settings.initialization_options.clone();
379
380 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
381
382 let server_id = self.languages.next_language_server_id();
383 log::trace!(
384 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
385 adapter.name.0
386 );
387
388 let wait_until_worktree_trust =
389 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
390 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
391 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
392 });
393 if can_trust {
394 self.restricted_worktrees_tasks.remove(&worktree_id);
395 None
396 } else {
397 match self.restricted_worktrees_tasks.entry(worktree_id) {
398 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
399 hash_map::Entry::Vacant(v) => {
400 let (mut tx, rx) = watch::channel::<bool>();
401 let lsp_store = self.weak.clone();
402 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
403 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
404 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
405 tx.blocking_send(true).ok();
406 lsp_store
407 .update(cx, |lsp_store, _| {
408 if let Some(local_lsp_store) =
409 lsp_store.as_local_mut()
410 {
411 local_lsp_store
412 .restricted_worktrees_tasks
413 .remove(&worktree_id);
414 }
415 })
416 .ok();
417 }
418 }
419 });
420 v.insert((subscription, rx.clone()));
421 Some(rx)
422 }
423 }
424 }
425 });
426 let update_binary_status = wait_until_worktree_trust.is_none();
427
428 let binary = self.get_language_server_binary(
429 worktree_abs_path.clone(),
430 adapter.clone(),
431 settings,
432 toolchain.clone(),
433 delegate.clone(),
434 true,
435 wait_until_worktree_trust,
436 cx,
437 );
438 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
439
440 let pending_server = cx.spawn({
441 let adapter = adapter.clone();
442 let server_name = adapter.name.clone();
443 let stderr_capture = stderr_capture.clone();
444 #[cfg(any(test, feature = "test-support"))]
445 let lsp_store = self.weak.clone();
446 let pending_workspace_folders = pending_workspace_folders.clone();
447 async move |cx| {
448 let binary = binary.await?;
449 #[cfg(any(test, feature = "test-support"))]
450 if let Some(server) = lsp_store
451 .update(&mut cx.clone(), |this, cx| {
452 this.languages.create_fake_language_server(
453 server_id,
454 &server_name,
455 binary.clone(),
456 &mut cx.to_async(),
457 )
458 })
459 .ok()
460 .flatten()
461 {
462 return Ok(server);
463 }
464
465 let code_action_kinds = adapter.code_action_kinds();
466 lsp::LanguageServer::new(
467 stderr_capture,
468 server_id,
469 server_name,
470 binary,
471 &worktree_abs_path,
472 code_action_kinds,
473 Some(pending_workspace_folders),
474 cx,
475 )
476 }
477 });
478
479 let startup = {
480 let server_name = adapter.name.0.clone();
481 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
482 let key = key.clone();
483 let adapter = adapter.clone();
484 let lsp_store = self.weak.clone();
485 let pending_workspace_folders = pending_workspace_folders.clone();
486
487 let pull_diagnostics = ProjectSettings::get_global(cx)
488 .diagnostics
489 .lsp_pull_diagnostics
490 .enabled;
491 cx.spawn(async move |cx| {
492 let result = async {
493 let language_server = pending_server.await?;
494
495 let workspace_config = Self::workspace_configuration_for_adapter(
496 adapter.adapter.clone(),
497 &delegate,
498 toolchain,
499 None,
500 cx,
501 )
502 .await?;
503
504 let mut initialization_options = Self::initialization_options_for_adapter(
505 adapter.adapter.clone(),
506 &delegate,
507 )
508 .await?;
509
510 match (&mut initialization_options, override_options) {
511 (Some(initialization_options), Some(override_options)) => {
512 merge_json_value_into(override_options, initialization_options);
513 }
514 (None, override_options) => initialization_options = override_options,
515 _ => {}
516 }
517
518 let initialization_params = cx.update(|cx| {
519 let mut params =
520 language_server.default_initialize_params(pull_diagnostics, cx);
521 params.initialization_options = initialization_options;
522 adapter.adapter.prepare_initialize_params(params, cx)
523 })?;
524
525 Self::setup_lsp_messages(
526 lsp_store.clone(),
527 &language_server,
528 delegate.clone(),
529 adapter.clone(),
530 );
531
532 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
533 settings: workspace_config,
534 };
535 let language_server = cx
536 .update(|cx| {
537 language_server.initialize(
538 initialization_params,
539 Arc::new(did_change_configuration_params.clone()),
540 cx,
541 )
542 })
543 .await
544 .inspect_err(|_| {
545 if let Some(lsp_store) = lsp_store.upgrade() {
546 lsp_store.update(cx, |lsp_store, cx| {
547 lsp_store.cleanup_lsp_data(server_id);
548 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
549 });
550 }
551 })?;
552
553 language_server.notify::<lsp::notification::DidChangeConfiguration>(
554 did_change_configuration_params,
555 )?;
556
557 anyhow::Ok(language_server)
558 }
559 .await;
560
561 match result {
562 Ok(server) => {
563 lsp_store
564 .update(cx, |lsp_store, cx| {
565 lsp_store.insert_newly_running_language_server(
566 adapter,
567 server.clone(),
568 server_id,
569 key,
570 pending_workspace_folders,
571 cx,
572 );
573 })
574 .ok();
575 stderr_capture.lock().take();
576 Some(server)
577 }
578
579 Err(err) => {
580 let log = stderr_capture.lock().take().unwrap_or_default();
581 delegate.update_status(
582 adapter.name(),
583 BinaryStatus::Failed {
584 error: if log.is_empty() {
585 format!("{err:#}")
586 } else {
587 format!("{err:#}\n-- stderr --\n{log}")
588 },
589 },
590 );
591 log::error!(
592 "Failed to start language server {server_name:?}: {}",
593 redact_command(&format!("{err:?}"))
594 );
595 if !log.is_empty() {
596 log::error!("server stderr: {}", redact_command(&log));
597 }
598 None
599 }
600 }
601 })
602 };
603 let state = LanguageServerState::Starting {
604 startup,
605 pending_workspace_folders,
606 };
607
608 if update_binary_status {
609 self.languages
610 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
611 }
612
613 self.language_servers.insert(server_id, state);
614 self.language_server_ids
615 .entry(key)
616 .or_insert(UnifiedLanguageServer {
617 id: server_id,
618 project_roots: Default::default(),
619 });
620 server_id
621 }
622
623 fn get_language_server_binary(
624 &self,
625 worktree_abs_path: Arc<Path>,
626 adapter: Arc<CachedLspAdapter>,
627 settings: Arc<LspSettings>,
628 toolchain: Option<Toolchain>,
629 delegate: Arc<dyn LspAdapterDelegate>,
630 allow_binary_download: bool,
631 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
632 cx: &mut App,
633 ) -> Task<Result<LanguageServerBinary>> {
634 if let Some(settings) = &settings.binary
635 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
636 {
637 let settings = settings.clone();
638 let languages = self.languages.clone();
639 return cx.background_spawn(async move {
640 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
641 let already_trusted = *wait_until_worktree_trust.borrow();
642 if !already_trusted {
643 log::info!(
644 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
645 adapter.name(),
646 );
647 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
648 if worktree_trusted {
649 break;
650 }
651 }
652 log::info!(
653 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
654 adapter.name(),
655 );
656 }
657 languages
658 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
659 }
660 let mut env = delegate.shell_env().await;
661 env.extend(settings.env.unwrap_or_default());
662
663 Ok(LanguageServerBinary {
664 path: delegate.resolve_executable_path(path),
665 env: Some(env),
666 arguments: settings
667 .arguments
668 .unwrap_or_default()
669 .iter()
670 .map(Into::into)
671 .collect(),
672 })
673 });
674 }
675 let lsp_binary_options = LanguageServerBinaryOptions {
676 allow_path_lookup: !settings
677 .binary
678 .as_ref()
679 .and_then(|b| b.ignore_system_version)
680 .unwrap_or_default(),
681 allow_binary_download,
682 pre_release: settings
683 .fetch
684 .as_ref()
685 .and_then(|f| f.pre_release)
686 .unwrap_or(false),
687 };
688
689 cx.spawn(async move |cx| {
690 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
691 let already_trusted = *wait_until_worktree_trust.borrow();
692 if !already_trusted {
693 log::info!(
694 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
695 adapter.name(),
696 );
697 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
698 if worktree_trusted {
699 break;
700 }
701 }
702 log::info!(
703 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
704 adapter.name(),
705 );
706 }
707 }
708
709 let (existing_binary, maybe_download_binary) = adapter
710 .clone()
711 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
712 .await
713 .await;
714
715 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
716
717 let mut binary = match (existing_binary, maybe_download_binary) {
718 (binary, None) => binary?,
719 (Err(_), Some(downloader)) => downloader.await?,
720 (Ok(existing_binary), Some(downloader)) => {
721 let mut download_timeout = cx
722 .background_executor()
723 .timer(SERVER_DOWNLOAD_TIMEOUT)
724 .fuse();
725 let mut downloader = downloader.fuse();
726 futures::select! {
727 _ = download_timeout => {
728 // Return existing binary and kick the existing work to the background.
729 cx.spawn(async move |_| downloader.await).detach();
730 Ok(existing_binary)
731 },
732 downloaded_or_existing_binary = downloader => {
733 // If download fails, this results in the existing binary.
734 downloaded_or_existing_binary
735 }
736 }?
737 }
738 };
739 let mut shell_env = delegate.shell_env().await;
740
741 shell_env.extend(binary.env.unwrap_or_default());
742
743 if let Some(settings) = settings.binary.as_ref() {
744 if let Some(arguments) = &settings.arguments {
745 binary.arguments = arguments.iter().map(Into::into).collect();
746 }
747 if let Some(env) = &settings.env {
748 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
749 }
750 }
751
752 binary.env = Some(shell_env);
753 Ok(binary)
754 })
755 }
756
757 fn setup_lsp_messages(
758 lsp_store: WeakEntity<LspStore>,
759 language_server: &LanguageServer,
760 delegate: Arc<dyn LspAdapterDelegate>,
761 adapter: Arc<CachedLspAdapter>,
762 ) {
763 let name = language_server.name();
764 let server_id = language_server.server_id();
765 language_server
766 .on_notification::<lsp::notification::PublishDiagnostics, _>({
767 let adapter = adapter.clone();
768 let this = lsp_store.clone();
769 move |mut params, cx| {
770 let adapter = adapter.clone();
771 if let Some(this) = this.upgrade() {
772 this.update(cx, |this, cx| {
773 {
774 let buffer = params
775 .uri
776 .to_file_path()
777 .map(|file_path| this.get_buffer(&file_path, cx))
778 .ok()
779 .flatten();
780 adapter.process_diagnostics(&mut params, server_id, buffer);
781 }
782
783 this.merge_lsp_diagnostics(
784 DiagnosticSourceKind::Pushed,
785 vec![DocumentDiagnosticsUpdate {
786 server_id,
787 diagnostics: params,
788 result_id: None,
789 disk_based_sources: Cow::Borrowed(
790 &adapter.disk_based_diagnostic_sources,
791 ),
792 registration_id: None,
793 }],
794 |_, diagnostic, cx| match diagnostic.source_kind {
795 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
796 adapter.retain_old_diagnostic(diagnostic, cx)
797 }
798 DiagnosticSourceKind::Pulled => true,
799 },
800 cx,
801 )
802 .log_err();
803 });
804 }
805 }
806 })
807 .detach();
808 language_server
809 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
810 let adapter = adapter.adapter.clone();
811 let delegate = delegate.clone();
812 let this = lsp_store.clone();
813 move |params, cx| {
814 let adapter = adapter.clone();
815 let delegate = delegate.clone();
816 let this = this.clone();
817 let mut cx = cx.clone();
818 async move {
819 let toolchain_for_id = this
820 .update(&mut cx, |this, _| {
821 this.as_local()?.language_server_ids.iter().find_map(
822 |(seed, value)| {
823 (value.id == server_id).then(|| seed.toolchain.clone())
824 },
825 )
826 })?
827 .context("Expected the LSP store to be in a local mode")?;
828
829 let mut scope_uri_to_workspace_config = BTreeMap::new();
830 for item in ¶ms.items {
831 let scope_uri = item.scope_uri.clone();
832 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
833 scope_uri_to_workspace_config.entry(scope_uri.clone())
834 else {
835 // We've already queried workspace configuration of this URI.
836 continue;
837 };
838 let workspace_config = Self::workspace_configuration_for_adapter(
839 adapter.clone(),
840 &delegate,
841 toolchain_for_id.clone(),
842 scope_uri,
843 &mut cx,
844 )
845 .await?;
846 new_scope_uri.insert(workspace_config);
847 }
848
849 Ok(params
850 .items
851 .into_iter()
852 .filter_map(|item| {
853 let workspace_config =
854 scope_uri_to_workspace_config.get(&item.scope_uri)?;
855 if let Some(section) = &item.section {
856 Some(
857 workspace_config
858 .get(section)
859 .cloned()
860 .unwrap_or(serde_json::Value::Null),
861 )
862 } else {
863 Some(workspace_config.clone())
864 }
865 })
866 .collect())
867 }
868 }
869 })
870 .detach();
871
872 language_server
873 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
874 let this = lsp_store.clone();
875 move |_, cx| {
876 let this = this.clone();
877 let cx = cx.clone();
878 async move {
879 let Some(server) =
880 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
881 else {
882 return Ok(None);
883 };
884 let root = server.workspace_folders();
885 Ok(Some(
886 root.into_iter()
887 .map(|uri| WorkspaceFolder {
888 uri,
889 name: Default::default(),
890 })
891 .collect(),
892 ))
893 }
894 }
895 })
896 .detach();
897 // Even though we don't have handling for these requests, respond to them to
898 // avoid stalling any language server like `gopls` which waits for a response
899 // to these requests when initializing.
900 language_server
901 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
902 let this = lsp_store.clone();
903 move |params, cx| {
904 let this = this.clone();
905 let mut cx = cx.clone();
906 async move {
907 this.update(&mut cx, |this, _| {
908 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
909 {
910 status
911 .progress_tokens
912 .insert(ProgressToken::from_lsp(params.token));
913 }
914 })?;
915
916 Ok(())
917 }
918 }
919 })
920 .detach();
921
922 language_server
923 .on_request::<lsp::request::RegisterCapability, _, _>({
924 let lsp_store = lsp_store.clone();
925 move |params, cx| {
926 let lsp_store = lsp_store.clone();
927 let mut cx = cx.clone();
928 async move {
929 lsp_store
930 .update(&mut cx, |lsp_store, cx| {
931 if lsp_store.as_local().is_some() {
932 match lsp_store
933 .register_server_capabilities(server_id, params, cx)
934 {
935 Ok(()) => {}
936 Err(e) => {
937 log::error!(
938 "Failed to register server capabilities: {e:#}"
939 );
940 }
941 };
942 }
943 })
944 .ok();
945 Ok(())
946 }
947 }
948 })
949 .detach();
950
951 language_server
952 .on_request::<lsp::request::UnregisterCapability, _, _>({
953 let lsp_store = lsp_store.clone();
954 move |params, cx| {
955 let lsp_store = lsp_store.clone();
956 let mut cx = cx.clone();
957 async move {
958 lsp_store
959 .update(&mut cx, |lsp_store, cx| {
960 if lsp_store.as_local().is_some() {
961 match lsp_store
962 .unregister_server_capabilities(server_id, params, cx)
963 {
964 Ok(()) => {}
965 Err(e) => {
966 log::error!(
967 "Failed to unregister server capabilities: {e:#}"
968 );
969 }
970 }
971 }
972 })
973 .ok();
974 Ok(())
975 }
976 }
977 })
978 .detach();
979
980 language_server
981 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
982 let this = lsp_store.clone();
983 move |params, cx| {
984 let mut cx = cx.clone();
985 let this = this.clone();
986 async move {
987 LocalLspStore::on_lsp_workspace_edit(
988 this.clone(),
989 params,
990 server_id,
991 &mut cx,
992 )
993 .await
994 }
995 }
996 })
997 .detach();
998
999 language_server
1000 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1001 let lsp_store = lsp_store.clone();
1002 let request_id = Arc::new(AtomicUsize::new(0));
1003 move |(), cx| {
1004 let lsp_store = lsp_store.clone();
1005 let request_id = request_id.clone();
1006 let mut cx = cx.clone();
1007 async move {
1008 lsp_store
1009 .update(&mut cx, |lsp_store, cx| {
1010 let request_id =
1011 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1012 cx.emit(LspStoreEvent::RefreshInlayHints {
1013 server_id,
1014 request_id,
1015 });
1016 lsp_store
1017 .downstream_client
1018 .as_ref()
1019 .map(|(client, project_id)| {
1020 client.send(proto::RefreshInlayHints {
1021 project_id: *project_id,
1022 server_id: server_id.to_proto(),
1023 request_id: request_id.map(|id| id as u64),
1024 })
1025 })
1026 })?
1027 .transpose()?;
1028 Ok(())
1029 }
1030 }
1031 })
1032 .detach();
1033
1034 language_server
1035 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1036 let this = lsp_store.clone();
1037 move |(), cx| {
1038 let this = this.clone();
1039 let mut cx = cx.clone();
1040 async move {
1041 this.update(&mut cx, |this, cx| {
1042 cx.emit(LspStoreEvent::RefreshCodeLens);
1043 this.downstream_client.as_ref().map(|(client, project_id)| {
1044 client.send(proto::RefreshCodeLens {
1045 project_id: *project_id,
1046 })
1047 })
1048 })?
1049 .transpose()?;
1050 Ok(())
1051 }
1052 }
1053 })
1054 .detach();
1055
1056 language_server
1057 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1058 let this = lsp_store.clone();
1059 move |(), cx| {
1060 let this = this.clone();
1061 let mut cx = cx.clone();
1062 async move {
1063 this.update(&mut cx, |lsp_store, cx| {
1064 lsp_store.pull_workspace_diagnostics(server_id);
1065 lsp_store
1066 .downstream_client
1067 .as_ref()
1068 .map(|(client, project_id)| {
1069 client.send(proto::PullWorkspaceDiagnostics {
1070 project_id: *project_id,
1071 server_id: server_id.to_proto(),
1072 })
1073 })
1074 .transpose()?;
1075 anyhow::Ok(
1076 lsp_store.pull_document_diagnostics_for_server(server_id, cx),
1077 )
1078 })??
1079 .await;
1080 Ok(())
1081 }
1082 }
1083 })
1084 .detach();
1085
1086 language_server
1087 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1088 let this = lsp_store.clone();
1089 let name = name.to_string();
1090 let adapter = adapter.clone();
1091 move |params, cx| {
1092 let this = this.clone();
1093 let name = name.to_string();
1094 let adapter = adapter.clone();
1095 let mut cx = cx.clone();
1096 async move {
1097 let actions = params.actions.unwrap_or_default();
1098 let message = params.message.clone();
1099 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1100 let level = match params.typ {
1101 lsp::MessageType::ERROR => PromptLevel::Critical,
1102 lsp::MessageType::WARNING => PromptLevel::Warning,
1103 _ => PromptLevel::Info,
1104 };
1105 let request = LanguageServerPromptRequest::new(
1106 level,
1107 params.message,
1108 actions,
1109 name.clone(),
1110 tx,
1111 );
1112
1113 let did_update = this
1114 .update(&mut cx, |_, cx| {
1115 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1116 })
1117 .is_ok();
1118 if did_update {
1119 let response = rx.recv().await.ok();
1120 if let Some(ref selected_action) = response {
1121 let context = language::PromptResponseContext {
1122 message,
1123 selected_action: selected_action.clone(),
1124 };
1125 adapter.process_prompt_response(&context, &mut cx)
1126 }
1127
1128 Ok(response)
1129 } else {
1130 Ok(None)
1131 }
1132 }
1133 }
1134 })
1135 .detach();
1136 language_server
1137 .on_notification::<lsp::notification::ShowMessage, _>({
1138 let this = lsp_store.clone();
1139 let name = name.to_string();
1140 move |params, cx| {
1141 let this = this.clone();
1142 let name = name.to_string();
1143 let mut cx = cx.clone();
1144
1145 let (tx, _) = smol::channel::bounded(1);
1146 let level = match params.typ {
1147 lsp::MessageType::ERROR => PromptLevel::Critical,
1148 lsp::MessageType::WARNING => PromptLevel::Warning,
1149 _ => PromptLevel::Info,
1150 };
1151 let request =
1152 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1153
1154 let _ = this.update(&mut cx, |_, cx| {
1155 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1156 });
1157 }
1158 })
1159 .detach();
1160
1161 let disk_based_diagnostics_progress_token =
1162 adapter.disk_based_diagnostics_progress_token.clone();
1163
1164 language_server
1165 .on_notification::<lsp::notification::Progress, _>({
1166 let this = lsp_store.clone();
1167 move |params, cx| {
1168 if let Some(this) = this.upgrade() {
1169 this.update(cx, |this, cx| {
1170 this.on_lsp_progress(
1171 params,
1172 server_id,
1173 disk_based_diagnostics_progress_token.clone(),
1174 cx,
1175 );
1176 });
1177 }
1178 }
1179 })
1180 .detach();
1181
1182 language_server
1183 .on_notification::<lsp::notification::LogMessage, _>({
1184 let this = lsp_store.clone();
1185 move |params, cx| {
1186 if let Some(this) = this.upgrade() {
1187 this.update(cx, |_, cx| {
1188 cx.emit(LspStoreEvent::LanguageServerLog(
1189 server_id,
1190 LanguageServerLogType::Log(params.typ),
1191 params.message,
1192 ));
1193 });
1194 }
1195 }
1196 })
1197 .detach();
1198
1199 language_server
1200 .on_notification::<lsp::notification::LogTrace, _>({
1201 let this = lsp_store.clone();
1202 move |params, cx| {
1203 let mut cx = cx.clone();
1204 if let Some(this) = this.upgrade() {
1205 this.update(&mut cx, |_, cx| {
1206 cx.emit(LspStoreEvent::LanguageServerLog(
1207 server_id,
1208 LanguageServerLogType::Trace {
1209 verbose_info: params.verbose,
1210 },
1211 params.message,
1212 ));
1213 });
1214 }
1215 }
1216 })
1217 .detach();
1218
1219 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1220 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1221 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1222 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1223 }
1224
1225 fn shutdown_language_servers_on_quit(
1226 &mut self,
1227 _: &mut Context<LspStore>,
1228 ) -> impl Future<Output = ()> + use<> {
1229 let shutdown_futures = self
1230 .language_servers
1231 .drain()
1232 .map(|(_, server_state)| Self::shutdown_server(server_state))
1233 .collect::<Vec<_>>();
1234
1235 async move {
1236 join_all(shutdown_futures).await;
1237 }
1238 }
1239
1240 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1241 match server_state {
1242 LanguageServerState::Running { server, .. } => {
1243 if let Some(shutdown) = server.shutdown() {
1244 shutdown.await;
1245 }
1246 }
1247 LanguageServerState::Starting { startup, .. } => {
1248 if let Some(server) = startup.await
1249 && let Some(shutdown) = server.shutdown()
1250 {
1251 shutdown.await;
1252 }
1253 }
1254 }
1255 Ok(())
1256 }
1257
1258 fn language_servers_for_worktree(
1259 &self,
1260 worktree_id: WorktreeId,
1261 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1262 self.language_server_ids
1263 .iter()
1264 .filter_map(move |(seed, state)| {
1265 if seed.worktree_id != worktree_id {
1266 return None;
1267 }
1268
1269 if let Some(LanguageServerState::Running { server, .. }) =
1270 self.language_servers.get(&state.id)
1271 {
1272 Some(server)
1273 } else {
1274 None
1275 }
1276 })
1277 }
1278
1279 fn language_server_ids_for_project_path(
1280 &self,
1281 project_path: ProjectPath,
1282 language: &Language,
1283 cx: &mut App,
1284 ) -> Vec<LanguageServerId> {
1285 let Some(worktree) = self
1286 .worktree_store
1287 .read(cx)
1288 .worktree_for_id(project_path.worktree_id, cx)
1289 else {
1290 return Vec::new();
1291 };
1292 let delegate: Arc<dyn ManifestDelegate> =
1293 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1294
1295 self.lsp_tree
1296 .get(
1297 project_path,
1298 language.name(),
1299 language.manifest(),
1300 &delegate,
1301 cx,
1302 )
1303 .collect::<Vec<_>>()
1304 }
1305
1306 fn language_server_ids_for_buffer(
1307 &self,
1308 buffer: &Buffer,
1309 cx: &mut App,
1310 ) -> Vec<LanguageServerId> {
1311 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1312 let worktree_id = file.worktree_id(cx);
1313
1314 let path: Arc<RelPath> = file
1315 .path()
1316 .parent()
1317 .map(Arc::from)
1318 .unwrap_or_else(|| file.path().clone());
1319 let worktree_path = ProjectPath { worktree_id, path };
1320 self.language_server_ids_for_project_path(worktree_path, language, cx)
1321 } else {
1322 Vec::new()
1323 }
1324 }
1325
1326 fn language_servers_for_buffer<'a>(
1327 &'a self,
1328 buffer: &'a Buffer,
1329 cx: &'a mut App,
1330 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1331 self.language_server_ids_for_buffer(buffer, cx)
1332 .into_iter()
1333 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1334 LanguageServerState::Running {
1335 adapter, server, ..
1336 } => Some((adapter, server)),
1337 _ => None,
1338 })
1339 }
1340
1341 async fn execute_code_action_kind_locally(
1342 lsp_store: WeakEntity<LspStore>,
1343 mut buffers: Vec<Entity<Buffer>>,
1344 kind: CodeActionKind,
1345 push_to_history: bool,
1346 cx: &mut AsyncApp,
1347 ) -> anyhow::Result<ProjectTransaction> {
1348 // Do not allow multiple concurrent code actions requests for the
1349 // same buffer.
1350 lsp_store.update(cx, |this, cx| {
1351 let this = this.as_local_mut().unwrap();
1352 buffers.retain(|buffer| {
1353 this.buffers_being_formatted
1354 .insert(buffer.read(cx).remote_id())
1355 });
1356 })?;
1357 let _cleanup = defer({
1358 let this = lsp_store.clone();
1359 let mut cx = cx.clone();
1360 let buffers = &buffers;
1361 move || {
1362 this.update(&mut cx, |this, cx| {
1363 let this = this.as_local_mut().unwrap();
1364 for buffer in buffers {
1365 this.buffers_being_formatted
1366 .remove(&buffer.read(cx).remote_id());
1367 }
1368 })
1369 .ok();
1370 }
1371 });
1372 let mut project_transaction = ProjectTransaction::default();
1373
1374 for buffer in &buffers {
1375 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1376 buffer.update(cx, |buffer, cx| {
1377 lsp_store
1378 .as_local()
1379 .unwrap()
1380 .language_servers_for_buffer(buffer, cx)
1381 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1382 .collect::<Vec<_>>()
1383 })
1384 })?;
1385 for (_, language_server) in adapters_and_servers.iter() {
1386 let actions = Self::get_server_code_actions_from_action_kinds(
1387 &lsp_store,
1388 language_server.server_id(),
1389 vec![kind.clone()],
1390 buffer,
1391 cx,
1392 )
1393 .await?;
1394 Self::execute_code_actions_on_server(
1395 &lsp_store,
1396 language_server,
1397 actions,
1398 push_to_history,
1399 &mut project_transaction,
1400 cx,
1401 )
1402 .await?;
1403 }
1404 }
1405 Ok(project_transaction)
1406 }
1407
1408 async fn format_locally(
1409 lsp_store: WeakEntity<LspStore>,
1410 mut buffers: Vec<FormattableBuffer>,
1411 push_to_history: bool,
1412 trigger: FormatTrigger,
1413 logger: zlog::Logger,
1414 cx: &mut AsyncApp,
1415 ) -> anyhow::Result<ProjectTransaction> {
1416 // Do not allow multiple concurrent formatting requests for the
1417 // same buffer.
1418 lsp_store.update(cx, |this, cx| {
1419 let this = this.as_local_mut().unwrap();
1420 buffers.retain(|buffer| {
1421 this.buffers_being_formatted
1422 .insert(buffer.handle.read(cx).remote_id())
1423 });
1424 })?;
1425
1426 let _cleanup = defer({
1427 let this = lsp_store.clone();
1428 let mut cx = cx.clone();
1429 let buffers = &buffers;
1430 move || {
1431 this.update(&mut cx, |this, cx| {
1432 let this = this.as_local_mut().unwrap();
1433 for buffer in buffers {
1434 this.buffers_being_formatted
1435 .remove(&buffer.handle.read(cx).remote_id());
1436 }
1437 })
1438 .ok();
1439 }
1440 });
1441
1442 let mut project_transaction = ProjectTransaction::default();
1443
1444 for buffer in &buffers {
1445 zlog::debug!(
1446 logger =>
1447 "formatting buffer '{:?}'",
1448 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1449 );
1450 // Create an empty transaction to hold all of the formatting edits.
1451 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1452 // ensure no transactions created while formatting are
1453 // grouped with the previous transaction in the history
1454 // based on the transaction group interval
1455 buffer.finalize_last_transaction();
1456 buffer
1457 .start_transaction()
1458 .context("transaction already open")?;
1459 buffer.end_transaction(cx);
1460 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1461 buffer.finalize_last_transaction();
1462 anyhow::Ok(transaction_id)
1463 })?;
1464
1465 let result = Self::format_buffer_locally(
1466 lsp_store.clone(),
1467 buffer,
1468 formatting_transaction_id,
1469 trigger,
1470 logger,
1471 cx,
1472 )
1473 .await;
1474
1475 buffer.handle.update(cx, |buffer, cx| {
1476 let Some(formatting_transaction) =
1477 buffer.get_transaction(formatting_transaction_id).cloned()
1478 else {
1479 zlog::warn!(logger => "no formatting transaction");
1480 return;
1481 };
1482 if formatting_transaction.edit_ids.is_empty() {
1483 zlog::debug!(logger => "no changes made while formatting");
1484 buffer.forget_transaction(formatting_transaction_id);
1485 return;
1486 }
1487 if !push_to_history {
1488 zlog::trace!(logger => "forgetting format transaction");
1489 buffer.forget_transaction(formatting_transaction.id);
1490 }
1491 project_transaction
1492 .0
1493 .insert(cx.entity(), formatting_transaction);
1494 });
1495
1496 result?;
1497 }
1498
1499 Ok(project_transaction)
1500 }
1501
1502 async fn format_buffer_locally(
1503 lsp_store: WeakEntity<LspStore>,
1504 buffer: &FormattableBuffer,
1505 formatting_transaction_id: clock::Lamport,
1506 trigger: FormatTrigger,
1507 logger: zlog::Logger,
1508 cx: &mut AsyncApp,
1509 ) -> Result<()> {
1510 let (adapters_and_servers, settings) = lsp_store.update(cx, |lsp_store, cx| {
1511 buffer.handle.update(cx, |buffer, cx| {
1512 let adapters_and_servers = lsp_store
1513 .as_local()
1514 .unwrap()
1515 .language_servers_for_buffer(buffer, cx)
1516 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1517 .collect::<Vec<_>>();
1518 let settings =
1519 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1520 .into_owned();
1521 (adapters_and_servers, settings)
1522 })
1523 })?;
1524
1525 /// Apply edits to the buffer that will become part of the formatting transaction.
1526 /// Fails if the buffer has been edited since the start of that transaction.
1527 fn extend_formatting_transaction(
1528 buffer: &FormattableBuffer,
1529 formatting_transaction_id: text::TransactionId,
1530 cx: &mut AsyncApp,
1531 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1532 ) -> anyhow::Result<()> {
1533 buffer.handle.update(cx, |buffer, cx| {
1534 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1535 if last_transaction_id != Some(formatting_transaction_id) {
1536 anyhow::bail!("Buffer edited while formatting. Aborting")
1537 }
1538 buffer.start_transaction();
1539 operation(buffer, cx);
1540 if let Some(transaction_id) = buffer.end_transaction(cx) {
1541 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1542 }
1543 Ok(())
1544 })
1545 }
1546
1547 // handle whitespace formatting
1548 if settings.remove_trailing_whitespace_on_save {
1549 zlog::trace!(logger => "removing trailing whitespace");
1550 let diff = buffer
1551 .handle
1552 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1553 .await;
1554 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1555 buffer.apply_diff(diff, cx);
1556 })?;
1557 }
1558
1559 if settings.ensure_final_newline_on_save {
1560 zlog::trace!(logger => "ensuring final newline");
1561 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1562 buffer.ensure_final_newline(cx);
1563 })?;
1564 }
1565
1566 // Formatter for `code_actions_on_format` that runs before
1567 // the rest of the formatters
1568 let mut code_actions_on_format_formatters = None;
1569 let should_run_code_actions_on_format = !matches!(
1570 (trigger, &settings.format_on_save),
1571 (FormatTrigger::Save, &FormatOnSave::Off)
1572 );
1573 if should_run_code_actions_on_format {
1574 let have_code_actions_to_run_on_format = settings
1575 .code_actions_on_format
1576 .values()
1577 .any(|enabled| *enabled);
1578 if have_code_actions_to_run_on_format {
1579 zlog::trace!(logger => "going to run code actions on format");
1580 code_actions_on_format_formatters = Some(
1581 settings
1582 .code_actions_on_format
1583 .iter()
1584 .filter_map(|(action, enabled)| enabled.then_some(action))
1585 .cloned()
1586 .map(Formatter::CodeAction)
1587 .collect::<Vec<_>>(),
1588 );
1589 }
1590 }
1591
1592 let formatters = match (trigger, &settings.format_on_save) {
1593 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1594 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1595 settings.formatter.as_ref()
1596 }
1597 };
1598
1599 let formatters = code_actions_on_format_formatters
1600 .iter()
1601 .flatten()
1602 .chain(formatters);
1603
1604 for formatter in formatters {
1605 let formatter = if formatter == &Formatter::Auto {
1606 if settings.prettier.allowed {
1607 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1608 &Formatter::Prettier
1609 } else {
1610 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1611 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1612 }
1613 } else {
1614 formatter
1615 };
1616 match formatter {
1617 Formatter::Auto => unreachable!("Auto resolved above"),
1618 Formatter::Prettier => {
1619 let logger = zlog::scoped!(logger => "prettier");
1620 zlog::trace!(logger => "formatting");
1621 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1622
1623 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1624 lsp_store.prettier_store().unwrap().downgrade()
1625 })?;
1626 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1627 .await
1628 .transpose()?;
1629 let Some(diff) = diff else {
1630 zlog::trace!(logger => "No changes");
1631 continue;
1632 };
1633
1634 extend_formatting_transaction(
1635 buffer,
1636 formatting_transaction_id,
1637 cx,
1638 |buffer, cx| {
1639 buffer.apply_diff(diff, cx);
1640 },
1641 )?;
1642 }
1643 Formatter::External { command, arguments } => {
1644 let logger = zlog::scoped!(logger => "command");
1645 zlog::trace!(logger => "formatting");
1646 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1647
1648 let diff = Self::format_via_external_command(
1649 buffer,
1650 &command,
1651 arguments.as_deref(),
1652 cx,
1653 )
1654 .await
1655 .with_context(|| {
1656 format!("Failed to format buffer via external command: {}", command)
1657 })?;
1658 let Some(diff) = diff else {
1659 zlog::trace!(logger => "No changes");
1660 continue;
1661 };
1662
1663 extend_formatting_transaction(
1664 buffer,
1665 formatting_transaction_id,
1666 cx,
1667 |buffer, cx| {
1668 buffer.apply_diff(diff, cx);
1669 },
1670 )?;
1671 }
1672 Formatter::LanguageServer(specifier) => {
1673 let logger = zlog::scoped!(logger => "language-server");
1674 zlog::trace!(logger => "formatting");
1675 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1676
1677 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1678 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1679 continue;
1680 };
1681
1682 let language_server = match specifier {
1683 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1684 adapters_and_servers.iter().find_map(|(adapter, server)| {
1685 if adapter.name.0.as_ref() == name {
1686 Some(server.clone())
1687 } else {
1688 None
1689 }
1690 })
1691 }
1692 settings::LanguageServerFormatterSpecifier::Current => {
1693 adapters_and_servers.first().map(|e| e.1.clone())
1694 }
1695 };
1696
1697 let Some(language_server) = language_server else {
1698 log::debug!(
1699 "No language server found to format buffer '{:?}'. Skipping",
1700 buffer_path_abs.as_path().to_string_lossy()
1701 );
1702 continue;
1703 };
1704
1705 zlog::trace!(
1706 logger =>
1707 "Formatting buffer '{:?}' using language server '{:?}'",
1708 buffer_path_abs.as_path().to_string_lossy(),
1709 language_server.name()
1710 );
1711
1712 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1713 zlog::trace!(logger => "formatting ranges");
1714 Self::format_ranges_via_lsp(
1715 &lsp_store,
1716 &buffer.handle,
1717 ranges,
1718 buffer_path_abs,
1719 &language_server,
1720 &settings,
1721 cx,
1722 )
1723 .await
1724 .context("Failed to format ranges via language server")?
1725 } else {
1726 zlog::trace!(logger => "formatting full");
1727 Self::format_via_lsp(
1728 &lsp_store,
1729 &buffer.handle,
1730 buffer_path_abs,
1731 &language_server,
1732 &settings,
1733 cx,
1734 )
1735 .await
1736 .context("failed to format via language server")?
1737 };
1738
1739 if edits.is_empty() {
1740 zlog::trace!(logger => "No changes");
1741 continue;
1742 }
1743 extend_formatting_transaction(
1744 buffer,
1745 formatting_transaction_id,
1746 cx,
1747 |buffer, cx| {
1748 buffer.edit(edits, None, cx);
1749 },
1750 )?;
1751 }
1752 Formatter::CodeAction(code_action_name) => {
1753 let logger = zlog::scoped!(logger => "code-actions");
1754 zlog::trace!(logger => "formatting");
1755 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1756
1757 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1758 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1759 continue;
1760 };
1761
1762 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1763 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1764
1765 let mut actions_and_servers = Vec::new();
1766
1767 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1768 let actions_result = Self::get_server_code_actions_from_action_kinds(
1769 &lsp_store,
1770 language_server.server_id(),
1771 vec![code_action_kind.clone()],
1772 &buffer.handle,
1773 cx,
1774 )
1775 .await
1776 .with_context(|| {
1777 format!(
1778 "Failed to resolve code action {:?} with language server {}",
1779 code_action_kind,
1780 language_server.name()
1781 )
1782 });
1783 let Ok(actions) = actions_result else {
1784 // note: it may be better to set result to the error and break formatters here
1785 // but for now we try to execute the actions that we can resolve and skip the rest
1786 zlog::error!(
1787 logger =>
1788 "Failed to resolve code action {:?} with language server {}",
1789 code_action_kind,
1790 language_server.name()
1791 );
1792 continue;
1793 };
1794 for action in actions {
1795 actions_and_servers.push((action, index));
1796 }
1797 }
1798
1799 if actions_and_servers.is_empty() {
1800 zlog::warn!(logger => "No code actions were resolved, continuing");
1801 continue;
1802 }
1803
1804 'actions: for (mut action, server_index) in actions_and_servers {
1805 let server = &adapters_and_servers[server_index].1;
1806
1807 let describe_code_action = |action: &CodeAction| {
1808 format!(
1809 "code action '{}' with title \"{}\" on server {}",
1810 action
1811 .lsp_action
1812 .action_kind()
1813 .unwrap_or("unknown".into())
1814 .as_str(),
1815 action.lsp_action.title(),
1816 server.name(),
1817 )
1818 };
1819
1820 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1821
1822 if let Err(err) = Self::try_resolve_code_action(server, &mut action).await {
1823 zlog::error!(
1824 logger =>
1825 "Failed to resolve {}. Error: {}",
1826 describe_code_action(&action),
1827 err
1828 );
1829 continue;
1830 }
1831
1832 if let Some(edit) = action.lsp_action.edit().cloned() {
1833 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1834 // but filters out and logs warnings for code actions that require unreasonably
1835 // difficult handling on our part, such as:
1836 // - applying edits that call commands
1837 // which can result in arbitrary workspace edits being sent from the server that
1838 // have no way of being tied back to the command that initiated them (i.e. we
1839 // can't know which edits are part of the format request, or if the server is done sending
1840 // actions in response to the command)
1841 // - actions that create/delete/modify/rename files other than the one we are formatting
1842 // as we then would need to handle such changes correctly in the local history as well
1843 // as the remote history through the ProjectTransaction
1844 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1845 // Supporting these actions is not impossible, but not supported as of yet.
1846 if edit.changes.is_none() && edit.document_changes.is_none() {
1847 zlog::trace!(
1848 logger =>
1849 "No changes for code action. Skipping {}",
1850 describe_code_action(&action),
1851 );
1852 continue;
1853 }
1854
1855 let mut operations = Vec::new();
1856 if let Some(document_changes) = edit.document_changes {
1857 match document_changes {
1858 lsp::DocumentChanges::Edits(edits) => operations.extend(
1859 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1860 ),
1861 lsp::DocumentChanges::Operations(ops) => operations = ops,
1862 }
1863 } else if let Some(changes) = edit.changes {
1864 operations.extend(changes.into_iter().map(|(uri, edits)| {
1865 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1866 text_document:
1867 lsp::OptionalVersionedTextDocumentIdentifier {
1868 uri,
1869 version: None,
1870 },
1871 edits: edits.into_iter().map(Edit::Plain).collect(),
1872 })
1873 }));
1874 }
1875
1876 let mut edits = Vec::with_capacity(operations.len());
1877
1878 if operations.is_empty() {
1879 zlog::trace!(
1880 logger =>
1881 "No changes for code action. Skipping {}",
1882 describe_code_action(&action),
1883 );
1884 continue;
1885 }
1886 for operation in operations {
1887 let op = match operation {
1888 lsp::DocumentChangeOperation::Edit(op) => op,
1889 lsp::DocumentChangeOperation::Op(_) => {
1890 zlog::warn!(
1891 logger =>
1892 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1893 describe_code_action(&action),
1894 );
1895 continue 'actions;
1896 }
1897 };
1898 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1899 zlog::warn!(
1900 logger =>
1901 "Failed to convert URI '{:?}' to file path. Skipping {}",
1902 &op.text_document.uri,
1903 describe_code_action(&action),
1904 );
1905 continue 'actions;
1906 };
1907 if &file_path != buffer_path_abs {
1908 zlog::warn!(
1909 logger =>
1910 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
1911 file_path,
1912 buffer_path_abs,
1913 describe_code_action(&action),
1914 );
1915 continue 'actions;
1916 }
1917
1918 let mut lsp_edits = Vec::new();
1919 for edit in op.edits {
1920 match edit {
1921 Edit::Plain(edit) => {
1922 if !lsp_edits.contains(&edit) {
1923 lsp_edits.push(edit);
1924 }
1925 }
1926 Edit::Annotated(edit) => {
1927 if !lsp_edits.contains(&edit.text_edit) {
1928 lsp_edits.push(edit.text_edit);
1929 }
1930 }
1931 Edit::Snippet(_) => {
1932 zlog::warn!(
1933 logger =>
1934 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
1935 describe_code_action(&action),
1936 );
1937 continue 'actions;
1938 }
1939 }
1940 }
1941 let edits_result = lsp_store
1942 .update(cx, |lsp_store, cx| {
1943 lsp_store.as_local_mut().unwrap().edits_from_lsp(
1944 &buffer.handle,
1945 lsp_edits,
1946 server.server_id(),
1947 op.text_document.version,
1948 cx,
1949 )
1950 })?
1951 .await;
1952 let Ok(resolved_edits) = edits_result else {
1953 zlog::warn!(
1954 logger =>
1955 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
1956 buffer_path_abs.as_path(),
1957 describe_code_action(&action),
1958 );
1959 continue 'actions;
1960 };
1961 edits.extend(resolved_edits);
1962 }
1963
1964 if edits.is_empty() {
1965 zlog::warn!(logger => "No edits resolved from LSP");
1966 continue;
1967 }
1968
1969 extend_formatting_transaction(
1970 buffer,
1971 formatting_transaction_id,
1972 cx,
1973 |buffer, cx| {
1974 zlog::info!(
1975 "Applying edits {edits:?}. Content: {:?}",
1976 buffer.text()
1977 );
1978 buffer.edit(edits, None, cx);
1979 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
1980 },
1981 )?;
1982 }
1983
1984 if let Some(command) = action.lsp_action.command() {
1985 zlog::warn!(
1986 logger =>
1987 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
1988 &command.command,
1989 );
1990
1991 // bail early if command is invalid
1992 let server_capabilities = server.capabilities();
1993 let available_commands = server_capabilities
1994 .execute_command_provider
1995 .as_ref()
1996 .map(|options| options.commands.as_slice())
1997 .unwrap_or_default();
1998 if !available_commands.contains(&command.command) {
1999 zlog::warn!(
2000 logger =>
2001 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2002 command.command,
2003 server.name(),
2004 );
2005 continue;
2006 }
2007
2008 // noop so we just ensure buffer hasn't been edited since resolving code actions
2009 extend_formatting_transaction(
2010 buffer,
2011 formatting_transaction_id,
2012 cx,
2013 |_, _| {},
2014 )?;
2015 zlog::info!(logger => "Executing command {}", &command.command);
2016
2017 lsp_store.update(cx, |this, _| {
2018 this.as_local_mut()
2019 .unwrap()
2020 .last_workspace_edits_by_language_server
2021 .remove(&server.server_id());
2022 })?;
2023
2024 let execute_command_result = server
2025 .request::<lsp::request::ExecuteCommand>(
2026 lsp::ExecuteCommandParams {
2027 command: command.command.clone(),
2028 arguments: command.arguments.clone().unwrap_or_default(),
2029 ..Default::default()
2030 },
2031 )
2032 .await
2033 .into_response();
2034
2035 if execute_command_result.is_err() {
2036 zlog::error!(
2037 logger =>
2038 "Failed to execute command '{}' as part of {}",
2039 &command.command,
2040 describe_code_action(&action),
2041 );
2042 continue 'actions;
2043 }
2044
2045 let mut project_transaction_command =
2046 lsp_store.update(cx, |this, _| {
2047 this.as_local_mut()
2048 .unwrap()
2049 .last_workspace_edits_by_language_server
2050 .remove(&server.server_id())
2051 .unwrap_or_default()
2052 })?;
2053
2054 if let Some(transaction) =
2055 project_transaction_command.0.remove(&buffer.handle)
2056 {
2057 zlog::trace!(
2058 logger =>
2059 "Successfully captured {} edits that resulted from command {}",
2060 transaction.edit_ids.len(),
2061 &command.command,
2062 );
2063 let transaction_id_project_transaction = transaction.id;
2064 buffer.handle.update(cx, |buffer, _| {
2065 // it may have been removed from history if push_to_history was
2066 // false in deserialize_workspace_edit. If so push it so we
2067 // can merge it with the format transaction
2068 // and pop the combined transaction off the history stack
2069 // later if push_to_history is false
2070 if buffer.get_transaction(transaction.id).is_none() {
2071 buffer.push_transaction(transaction, Instant::now());
2072 }
2073 buffer.merge_transactions(
2074 transaction_id_project_transaction,
2075 formatting_transaction_id,
2076 );
2077 });
2078 }
2079
2080 if !project_transaction_command.0.is_empty() {
2081 let mut extra_buffers = String::new();
2082 for buffer in project_transaction_command.0.keys() {
2083 buffer.read_with(cx, |b, cx| {
2084 if let Some(path) = b.project_path(cx) {
2085 if !extra_buffers.is_empty() {
2086 extra_buffers.push_str(", ");
2087 }
2088 extra_buffers.push_str(path.path.as_unix_str());
2089 }
2090 });
2091 }
2092 zlog::warn!(
2093 logger =>
2094 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2095 &command.command,
2096 extra_buffers,
2097 );
2098 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2099 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2100 // add it so it's included, and merge it into the format transaction when its created later
2101 }
2102 }
2103 }
2104 }
2105 }
2106 }
2107
2108 Ok(())
2109 }
2110
2111 pub async fn format_ranges_via_lsp(
2112 this: &WeakEntity<LspStore>,
2113 buffer_handle: &Entity<Buffer>,
2114 ranges: &[Range<Anchor>],
2115 abs_path: &Path,
2116 language_server: &Arc<LanguageServer>,
2117 settings: &LanguageSettings,
2118 cx: &mut AsyncApp,
2119 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2120 let capabilities = &language_server.capabilities();
2121 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2122 if range_formatting_provider == Some(&OneOf::Left(false)) {
2123 anyhow::bail!(
2124 "{} language server does not support range formatting",
2125 language_server.name()
2126 );
2127 }
2128
2129 let uri = file_path_to_lsp_url(abs_path)?;
2130 let text_document = lsp::TextDocumentIdentifier::new(uri);
2131
2132 let lsp_edits = {
2133 let mut lsp_ranges = Vec::new();
2134 this.update(cx, |_this, cx| {
2135 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2136 // not have been sent to the language server. This seems like a fairly systemic
2137 // issue, though, the resolution probably is not specific to formatting.
2138 //
2139 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2140 // LSP.
2141 let snapshot = buffer_handle.read(cx).snapshot();
2142 for range in ranges {
2143 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2144 }
2145 anyhow::Ok(())
2146 })??;
2147
2148 let mut edits = None;
2149 for range in lsp_ranges {
2150 if let Some(mut edit) = language_server
2151 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2152 text_document: text_document.clone(),
2153 range,
2154 options: lsp_command::lsp_formatting_options(settings),
2155 work_done_progress_params: Default::default(),
2156 })
2157 .await
2158 .into_response()?
2159 {
2160 edits.get_or_insert_with(Vec::new).append(&mut edit);
2161 }
2162 }
2163 edits
2164 };
2165
2166 if let Some(lsp_edits) = lsp_edits {
2167 this.update(cx, |this, cx| {
2168 this.as_local_mut().unwrap().edits_from_lsp(
2169 buffer_handle,
2170 lsp_edits,
2171 language_server.server_id(),
2172 None,
2173 cx,
2174 )
2175 })?
2176 .await
2177 } else {
2178 Ok(Vec::with_capacity(0))
2179 }
2180 }
2181
2182 async fn format_via_lsp(
2183 this: &WeakEntity<LspStore>,
2184 buffer: &Entity<Buffer>,
2185 abs_path: &Path,
2186 language_server: &Arc<LanguageServer>,
2187 settings: &LanguageSettings,
2188 cx: &mut AsyncApp,
2189 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2190 let logger = zlog::scoped!("lsp_format");
2191 zlog::debug!(logger => "Formatting via LSP");
2192
2193 let uri = file_path_to_lsp_url(abs_path)?;
2194 let text_document = lsp::TextDocumentIdentifier::new(uri);
2195 let capabilities = &language_server.capabilities();
2196
2197 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2198 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2199
2200 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2201 let _timer = zlog::time!(logger => "format-full");
2202 language_server
2203 .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
2204 text_document,
2205 options: lsp_command::lsp_formatting_options(settings),
2206 work_done_progress_params: Default::default(),
2207 })
2208 .await
2209 .into_response()?
2210 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2211 let _timer = zlog::time!(logger => "format-range");
2212 let buffer_start = lsp::Position::new(0, 0);
2213 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2214 language_server
2215 .request::<lsp::request::RangeFormatting>(lsp::DocumentRangeFormattingParams {
2216 text_document: text_document.clone(),
2217 range: lsp::Range::new(buffer_start, buffer_end),
2218 options: lsp_command::lsp_formatting_options(settings),
2219 work_done_progress_params: Default::default(),
2220 })
2221 .await
2222 .into_response()?
2223 } else {
2224 None
2225 };
2226
2227 if let Some(lsp_edits) = lsp_edits {
2228 this.update(cx, |this, cx| {
2229 this.as_local_mut().unwrap().edits_from_lsp(
2230 buffer,
2231 lsp_edits,
2232 language_server.server_id(),
2233 None,
2234 cx,
2235 )
2236 })?
2237 .await
2238 } else {
2239 Ok(Vec::with_capacity(0))
2240 }
2241 }
2242
2243 async fn format_via_external_command(
2244 buffer: &FormattableBuffer,
2245 command: &str,
2246 arguments: Option<&[String]>,
2247 cx: &mut AsyncApp,
2248 ) -> Result<Option<Diff>> {
2249 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2250 let file = File::from_dyn(buffer.file())?;
2251 let worktree = file.worktree.read(cx);
2252 let mut worktree_path = worktree.abs_path().to_path_buf();
2253 if worktree.root_entry()?.is_file() {
2254 worktree_path.pop();
2255 }
2256 Some(worktree_path)
2257 });
2258
2259 let mut child = util::command::new_smol_command(command);
2260
2261 if let Some(buffer_env) = buffer.env.as_ref() {
2262 child.envs(buffer_env);
2263 }
2264
2265 if let Some(working_dir_path) = working_dir_path {
2266 child.current_dir(working_dir_path);
2267 }
2268
2269 if let Some(arguments) = arguments {
2270 child.args(arguments.iter().map(|arg| {
2271 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2272 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2273 } else {
2274 arg.replace("{buffer_path}", "Untitled")
2275 }
2276 }));
2277 }
2278
2279 let mut child = child
2280 .stdin(smol::process::Stdio::piped())
2281 .stdout(smol::process::Stdio::piped())
2282 .stderr(smol::process::Stdio::piped())
2283 .spawn()?;
2284
2285 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2286 let text = buffer
2287 .handle
2288 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2289 for chunk in text.chunks() {
2290 stdin.write_all(chunk.as_bytes()).await?;
2291 }
2292 stdin.flush().await?;
2293
2294 let output = child.output().await?;
2295 anyhow::ensure!(
2296 output.status.success(),
2297 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2298 output.status.code(),
2299 String::from_utf8_lossy(&output.stdout),
2300 String::from_utf8_lossy(&output.stderr),
2301 );
2302
2303 let stdout = String::from_utf8(output.stdout)?;
2304 Ok(Some(
2305 buffer
2306 .handle
2307 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2308 .await,
2309 ))
2310 }
2311
2312 async fn try_resolve_code_action(
2313 lang_server: &LanguageServer,
2314 action: &mut CodeAction,
2315 ) -> anyhow::Result<()> {
2316 match &mut action.lsp_action {
2317 LspAction::Action(lsp_action) => {
2318 if !action.resolved
2319 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2320 && lsp_action.data.is_some()
2321 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2322 {
2323 **lsp_action = lang_server
2324 .request::<lsp::request::CodeActionResolveRequest>(*lsp_action.clone())
2325 .await
2326 .into_response()?;
2327 }
2328 }
2329 LspAction::CodeLens(lens) => {
2330 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2331 *lens = lang_server
2332 .request::<lsp::request::CodeLensResolve>(lens.clone())
2333 .await
2334 .into_response()?;
2335 }
2336 }
2337 LspAction::Command(_) => {}
2338 }
2339
2340 action.resolved = true;
2341 anyhow::Ok(())
2342 }
2343
2344 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2345 let buffer = buffer_handle.read(cx);
2346
2347 let file = buffer.file().cloned();
2348
2349 let Some(file) = File::from_dyn(file.as_ref()) else {
2350 return;
2351 };
2352 if !file.is_local() {
2353 return;
2354 }
2355 let path = ProjectPath::from_file(file, cx);
2356 let worktree_id = file.worktree_id(cx);
2357 let language = buffer.language().cloned();
2358
2359 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2360 for (server_id, diagnostics) in
2361 diagnostics.get(file.path()).cloned().unwrap_or_default()
2362 {
2363 self.update_buffer_diagnostics(
2364 buffer_handle,
2365 server_id,
2366 None,
2367 None,
2368 None,
2369 Vec::new(),
2370 diagnostics,
2371 cx,
2372 )
2373 .log_err();
2374 }
2375 }
2376 let Some(language) = language else {
2377 return;
2378 };
2379 let Some(snapshot) = self
2380 .worktree_store
2381 .read(cx)
2382 .worktree_for_id(worktree_id, cx)
2383 .map(|worktree| worktree.read(cx).snapshot())
2384 else {
2385 return;
2386 };
2387 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2388
2389 for server_id in
2390 self.lsp_tree
2391 .get(path, language.name(), language.manifest(), &delegate, cx)
2392 {
2393 let server = self
2394 .language_servers
2395 .get(&server_id)
2396 .and_then(|server_state| {
2397 if let LanguageServerState::Running { server, .. } = server_state {
2398 Some(server.clone())
2399 } else {
2400 None
2401 }
2402 });
2403 let server = match server {
2404 Some(server) => server,
2405 None => continue,
2406 };
2407
2408 buffer_handle.update(cx, |buffer, cx| {
2409 buffer.set_completion_triggers(
2410 server.server_id(),
2411 server
2412 .capabilities()
2413 .completion_provider
2414 .as_ref()
2415 .and_then(|provider| {
2416 provider
2417 .trigger_characters
2418 .as_ref()
2419 .map(|characters| characters.iter().cloned().collect())
2420 })
2421 .unwrap_or_default(),
2422 cx,
2423 );
2424 });
2425 }
2426 }
2427
2428 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2429 buffer.update(cx, |buffer, cx| {
2430 let Some(language) = buffer.language() else {
2431 return;
2432 };
2433 let path = ProjectPath {
2434 worktree_id: old_file.worktree_id(cx),
2435 path: old_file.path.clone(),
2436 };
2437 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2438 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2439 buffer.set_completion_triggers(server_id, Default::default(), cx);
2440 }
2441 });
2442 }
2443
2444 fn update_buffer_diagnostics(
2445 &mut self,
2446 buffer: &Entity<Buffer>,
2447 server_id: LanguageServerId,
2448 registration_id: Option<Option<SharedString>>,
2449 result_id: Option<SharedString>,
2450 version: Option<i32>,
2451 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2452 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2453 cx: &mut Context<LspStore>,
2454 ) -> Result<()> {
2455 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2456 Ordering::Equal
2457 .then_with(|| b.is_primary.cmp(&a.is_primary))
2458 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2459 .then_with(|| a.severity.cmp(&b.severity))
2460 .then_with(|| a.message.cmp(&b.message))
2461 }
2462
2463 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2464 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2465 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2466
2467 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2468 Ordering::Equal
2469 .then_with(|| a.range.start.cmp(&b.range.start))
2470 .then_with(|| b.range.end.cmp(&a.range.end))
2471 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2472 });
2473
2474 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2475
2476 let edits_since_save = std::cell::LazyCell::new(|| {
2477 let saved_version = buffer.read(cx).saved_version();
2478 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2479 });
2480
2481 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2482
2483 for (new_diagnostic, entry) in diagnostics {
2484 let start;
2485 let end;
2486 if new_diagnostic && entry.diagnostic.is_disk_based {
2487 // Some diagnostics are based on files on disk instead of buffers'
2488 // current contents. Adjust these diagnostics' ranges to reflect
2489 // any unsaved edits.
2490 // Do not alter the reused ones though, as their coordinates were stored as anchors
2491 // and were properly adjusted on reuse.
2492 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2493 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2494 } else {
2495 start = entry.range.start;
2496 end = entry.range.end;
2497 }
2498
2499 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2500 ..snapshot.clip_point_utf16(end, Bias::Right);
2501
2502 // Expand empty ranges by one codepoint
2503 if range.start == range.end {
2504 // This will be go to the next boundary when being clipped
2505 range.end.column += 1;
2506 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2507 if range.start == range.end && range.end.column > 0 {
2508 range.start.column -= 1;
2509 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2510 }
2511 }
2512
2513 sanitized_diagnostics.push(DiagnosticEntry {
2514 range,
2515 diagnostic: entry.diagnostic,
2516 });
2517 }
2518 drop(edits_since_save);
2519
2520 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2521 buffer.update(cx, |buffer, cx| {
2522 if let Some(registration_id) = registration_id {
2523 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2524 self.buffer_pull_diagnostics_result_ids
2525 .entry(server_id)
2526 .or_default()
2527 .entry(registration_id)
2528 .or_default()
2529 .insert(abs_path, result_id);
2530 }
2531 }
2532
2533 buffer.update_diagnostics(server_id, set, cx)
2534 });
2535
2536 Ok(())
2537 }
2538
2539 fn register_language_server_for_invisible_worktree(
2540 &mut self,
2541 worktree: &Entity<Worktree>,
2542 language_server_id: LanguageServerId,
2543 cx: &mut App,
2544 ) {
2545 let worktree = worktree.read(cx);
2546 let worktree_id = worktree.id();
2547 debug_assert!(!worktree.is_visible());
2548 let Some(mut origin_seed) = self
2549 .language_server_ids
2550 .iter()
2551 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2552 else {
2553 return;
2554 };
2555 origin_seed.worktree_id = worktree_id;
2556 self.language_server_ids
2557 .entry(origin_seed)
2558 .or_insert_with(|| UnifiedLanguageServer {
2559 id: language_server_id,
2560 project_roots: Default::default(),
2561 });
2562 }
2563
2564 fn register_buffer_with_language_servers(
2565 &mut self,
2566 buffer_handle: &Entity<Buffer>,
2567 only_register_servers: HashSet<LanguageServerSelector>,
2568 cx: &mut Context<LspStore>,
2569 ) {
2570 let buffer = buffer_handle.read(cx);
2571 let buffer_id = buffer.remote_id();
2572
2573 let Some(file) = File::from_dyn(buffer.file()) else {
2574 return;
2575 };
2576 if !file.is_local() {
2577 return;
2578 }
2579
2580 let abs_path = file.abs_path(cx);
2581 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2582 return;
2583 };
2584 let initial_snapshot = buffer.text_snapshot();
2585 let worktree_id = file.worktree_id(cx);
2586
2587 let Some(language) = buffer.language().cloned() else {
2588 return;
2589 };
2590 let path: Arc<RelPath> = file
2591 .path()
2592 .parent()
2593 .map(Arc::from)
2594 .unwrap_or_else(|| file.path().clone());
2595 let Some(worktree) = self
2596 .worktree_store
2597 .read(cx)
2598 .worktree_for_id(worktree_id, cx)
2599 else {
2600 return;
2601 };
2602 let language_name = language.name();
2603 let (reused, delegate, servers) = self
2604 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2605 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2606 .unwrap_or_else(|| {
2607 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2608 let delegate: Arc<dyn ManifestDelegate> =
2609 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2610
2611 let servers = self
2612 .lsp_tree
2613 .walk(
2614 ProjectPath { worktree_id, path },
2615 language.name(),
2616 language.manifest(),
2617 &delegate,
2618 cx,
2619 )
2620 .collect::<Vec<_>>();
2621 (false, lsp_delegate, servers)
2622 });
2623 let servers_and_adapters = servers
2624 .into_iter()
2625 .filter_map(|server_node| {
2626 if reused && server_node.server_id().is_none() {
2627 return None;
2628 }
2629 if !only_register_servers.is_empty() {
2630 if let Some(server_id) = server_node.server_id()
2631 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2632 {
2633 return None;
2634 }
2635 if let Some(name) = server_node.name()
2636 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2637 {
2638 return None;
2639 }
2640 }
2641
2642 let server_id = server_node.server_id_or_init(|disposition| {
2643 let path = &disposition.path;
2644
2645 {
2646 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2647
2648 let server_id = self.get_or_insert_language_server(
2649 &worktree,
2650 delegate.clone(),
2651 disposition,
2652 &language_name,
2653 cx,
2654 );
2655
2656 if let Some(state) = self.language_servers.get(&server_id)
2657 && let Ok(uri) = uri
2658 {
2659 state.add_workspace_folder(uri);
2660 };
2661 server_id
2662 }
2663 })?;
2664 let server_state = self.language_servers.get(&server_id)?;
2665 if let LanguageServerState::Running {
2666 server, adapter, ..
2667 } = server_state
2668 {
2669 Some((server.clone(), adapter.clone()))
2670 } else {
2671 None
2672 }
2673 })
2674 .collect::<Vec<_>>();
2675 for (server, adapter) in servers_and_adapters {
2676 buffer_handle.update(cx, |buffer, cx| {
2677 buffer.set_completion_triggers(
2678 server.server_id(),
2679 server
2680 .capabilities()
2681 .completion_provider
2682 .as_ref()
2683 .and_then(|provider| {
2684 provider
2685 .trigger_characters
2686 .as_ref()
2687 .map(|characters| characters.iter().cloned().collect())
2688 })
2689 .unwrap_or_default(),
2690 cx,
2691 );
2692 });
2693
2694 let snapshot = LspBufferSnapshot {
2695 version: 0,
2696 snapshot: initial_snapshot.clone(),
2697 };
2698
2699 let mut registered = false;
2700 self.buffer_snapshots
2701 .entry(buffer_id)
2702 .or_default()
2703 .entry(server.server_id())
2704 .or_insert_with(|| {
2705 registered = true;
2706 server.register_buffer(
2707 uri.clone(),
2708 adapter.language_id(&language.name()),
2709 0,
2710 initial_snapshot.text(),
2711 );
2712
2713 vec![snapshot]
2714 });
2715
2716 self.buffers_opened_in_servers
2717 .entry(buffer_id)
2718 .or_default()
2719 .insert(server.server_id());
2720 if registered {
2721 cx.emit(LspStoreEvent::LanguageServerUpdate {
2722 language_server_id: server.server_id(),
2723 name: None,
2724 message: proto::update_language_server::Variant::RegisteredForBuffer(
2725 proto::RegisteredForBuffer {
2726 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2727 buffer_id: buffer_id.to_proto(),
2728 },
2729 ),
2730 });
2731 }
2732 }
2733 }
2734
2735 fn reuse_existing_language_server<'lang_name>(
2736 &self,
2737 server_tree: &LanguageServerTree,
2738 worktree: &Entity<Worktree>,
2739 language_name: &'lang_name LanguageName,
2740 cx: &mut App,
2741 ) -> Option<(
2742 Arc<LocalLspAdapterDelegate>,
2743 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2744 )> {
2745 if worktree.read(cx).is_visible() {
2746 return None;
2747 }
2748
2749 let worktree_store = self.worktree_store.read(cx);
2750 let servers = server_tree
2751 .instances
2752 .iter()
2753 .filter(|(worktree_id, _)| {
2754 worktree_store
2755 .worktree_for_id(**worktree_id, cx)
2756 .is_some_and(|worktree| worktree.read(cx).is_visible())
2757 })
2758 .flat_map(|(worktree_id, servers)| {
2759 servers
2760 .roots
2761 .iter()
2762 .flat_map(|(_, language_servers)| language_servers)
2763 .map(move |(_, (server_node, server_languages))| {
2764 (worktree_id, server_node, server_languages)
2765 })
2766 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2767 .map(|(worktree_id, server_node, _)| {
2768 (
2769 *worktree_id,
2770 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2771 )
2772 })
2773 })
2774 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2775 acc.entry(worktree_id)
2776 .or_insert_with(Vec::new)
2777 .push(server_node);
2778 acc
2779 })
2780 .into_values()
2781 .max_by_key(|servers| servers.len())?;
2782
2783 let worktree_id = worktree.read(cx).id();
2784 let apply = move |tree: &mut LanguageServerTree| {
2785 for server_node in &servers {
2786 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2787 }
2788 servers
2789 };
2790
2791 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2792 Some((delegate, apply))
2793 }
2794
2795 pub(crate) fn unregister_old_buffer_from_language_servers(
2796 &mut self,
2797 buffer: &Entity<Buffer>,
2798 old_file: &File,
2799 cx: &mut App,
2800 ) {
2801 let old_path = match old_file.as_local() {
2802 Some(local) => local.abs_path(cx),
2803 None => return,
2804 };
2805
2806 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2807 debug_panic!("{old_path:?} is not parseable as an URI");
2808 return;
2809 };
2810 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2811 }
2812
2813 pub(crate) fn unregister_buffer_from_language_servers(
2814 &mut self,
2815 buffer: &Entity<Buffer>,
2816 file_url: &lsp::Uri,
2817 cx: &mut App,
2818 ) {
2819 buffer.update(cx, |buffer, cx| {
2820 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2821
2822 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2823 if snapshots
2824 .as_mut()
2825 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2826 {
2827 language_server.unregister_buffer(file_url.clone());
2828 }
2829 }
2830 });
2831 }
2832
2833 fn buffer_snapshot_for_lsp_version(
2834 &mut self,
2835 buffer: &Entity<Buffer>,
2836 server_id: LanguageServerId,
2837 version: Option<i32>,
2838 cx: &App,
2839 ) -> Result<TextBufferSnapshot> {
2840 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2841
2842 if let Some(version) = version {
2843 let buffer_id = buffer.read(cx).remote_id();
2844 let snapshots = if let Some(snapshots) = self
2845 .buffer_snapshots
2846 .get_mut(&buffer_id)
2847 .and_then(|m| m.get_mut(&server_id))
2848 {
2849 snapshots
2850 } else if version == 0 {
2851 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2852 // We detect this case and treat it as if the version was `None`.
2853 return Ok(buffer.read(cx).text_snapshot());
2854 } else {
2855 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2856 };
2857
2858 let found_snapshot = snapshots
2859 .binary_search_by_key(&version, |e| e.version)
2860 .map(|ix| snapshots[ix].snapshot.clone())
2861 .map_err(|_| {
2862 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2863 })?;
2864
2865 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2866 Ok(found_snapshot)
2867 } else {
2868 Ok((buffer.read(cx)).text_snapshot())
2869 }
2870 }
2871
2872 async fn get_server_code_actions_from_action_kinds(
2873 lsp_store: &WeakEntity<LspStore>,
2874 language_server_id: LanguageServerId,
2875 code_action_kinds: Vec<lsp::CodeActionKind>,
2876 buffer: &Entity<Buffer>,
2877 cx: &mut AsyncApp,
2878 ) -> Result<Vec<CodeAction>> {
2879 let actions = lsp_store
2880 .update(cx, move |this, cx| {
2881 let request = GetCodeActions {
2882 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
2883 kinds: Some(code_action_kinds),
2884 };
2885 let server = LanguageServerToQuery::Other(language_server_id);
2886 this.request_lsp(buffer.clone(), server, request, cx)
2887 })?
2888 .await?;
2889 Ok(actions)
2890 }
2891
2892 pub async fn execute_code_actions_on_server(
2893 lsp_store: &WeakEntity<LspStore>,
2894 language_server: &Arc<LanguageServer>,
2895
2896 actions: Vec<CodeAction>,
2897 push_to_history: bool,
2898 project_transaction: &mut ProjectTransaction,
2899 cx: &mut AsyncApp,
2900 ) -> anyhow::Result<()> {
2901 for mut action in actions {
2902 Self::try_resolve_code_action(language_server, &mut action)
2903 .await
2904 .context("resolving a formatting code action")?;
2905
2906 if let Some(edit) = action.lsp_action.edit() {
2907 if edit.changes.is_none() && edit.document_changes.is_none() {
2908 continue;
2909 }
2910
2911 let new = Self::deserialize_workspace_edit(
2912 lsp_store.upgrade().context("project dropped")?,
2913 edit.clone(),
2914 push_to_history,
2915 language_server.clone(),
2916 cx,
2917 )
2918 .await?;
2919 project_transaction.0.extend(new.0);
2920 }
2921
2922 if let Some(command) = action.lsp_action.command() {
2923 let server_capabilities = language_server.capabilities();
2924 let available_commands = server_capabilities
2925 .execute_command_provider
2926 .as_ref()
2927 .map(|options| options.commands.as_slice())
2928 .unwrap_or_default();
2929 if available_commands.contains(&command.command) {
2930 lsp_store.update(cx, |lsp_store, _| {
2931 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
2932 mode.last_workspace_edits_by_language_server
2933 .remove(&language_server.server_id());
2934 }
2935 })?;
2936
2937 language_server
2938 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
2939 command: command.command.clone(),
2940 arguments: command.arguments.clone().unwrap_or_default(),
2941 ..Default::default()
2942 })
2943 .await
2944 .into_response()
2945 .context("execute command")?;
2946
2947 lsp_store.update(cx, |this, _| {
2948 if let LspStoreMode::Local(mode) = &mut this.mode {
2949 project_transaction.0.extend(
2950 mode.last_workspace_edits_by_language_server
2951 .remove(&language_server.server_id())
2952 .unwrap_or_default()
2953 .0,
2954 )
2955 }
2956 })?;
2957 } else {
2958 log::warn!(
2959 "Cannot execute a command {} not listed in the language server capabilities",
2960 command.command
2961 )
2962 }
2963 }
2964 }
2965 Ok(())
2966 }
2967
2968 pub async fn deserialize_text_edits(
2969 this: Entity<LspStore>,
2970 buffer_to_edit: Entity<Buffer>,
2971 edits: Vec<lsp::TextEdit>,
2972 push_to_history: bool,
2973 _: Arc<CachedLspAdapter>,
2974 language_server: Arc<LanguageServer>,
2975 cx: &mut AsyncApp,
2976 ) -> Result<Option<Transaction>> {
2977 let edits = this
2978 .update(cx, |this, cx| {
2979 this.as_local_mut().unwrap().edits_from_lsp(
2980 &buffer_to_edit,
2981 edits,
2982 language_server.server_id(),
2983 None,
2984 cx,
2985 )
2986 })
2987 .await?;
2988
2989 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
2990 buffer.finalize_last_transaction();
2991 buffer.start_transaction();
2992 for (range, text) in edits {
2993 buffer.edit([(range, text)], None, cx);
2994 }
2995
2996 if buffer.end_transaction(cx).is_some() {
2997 let transaction = buffer.finalize_last_transaction().unwrap().clone();
2998 if !push_to_history {
2999 buffer.forget_transaction(transaction.id);
3000 }
3001 Some(transaction)
3002 } else {
3003 None
3004 }
3005 });
3006
3007 Ok(transaction)
3008 }
3009
3010 #[allow(clippy::type_complexity)]
3011 pub(crate) fn edits_from_lsp(
3012 &mut self,
3013 buffer: &Entity<Buffer>,
3014 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3015 server_id: LanguageServerId,
3016 version: Option<i32>,
3017 cx: &mut Context<LspStore>,
3018 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3019 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3020 cx.background_spawn(async move {
3021 let snapshot = snapshot?;
3022 let mut lsp_edits = lsp_edits
3023 .into_iter()
3024 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3025 .collect::<Vec<_>>();
3026
3027 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3028
3029 let mut lsp_edits = lsp_edits.into_iter().peekable();
3030 let mut edits = Vec::new();
3031 while let Some((range, mut new_text)) = lsp_edits.next() {
3032 // Clip invalid ranges provided by the language server.
3033 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3034 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3035
3036 // Combine any LSP edits that are adjacent.
3037 //
3038 // Also, combine LSP edits that are separated from each other by only
3039 // a newline. This is important because for some code actions,
3040 // Rust-analyzer rewrites the entire buffer via a series of edits that
3041 // are separated by unchanged newline characters.
3042 //
3043 // In order for the diffing logic below to work properly, any edits that
3044 // cancel each other out must be combined into one.
3045 while let Some((next_range, next_text)) = lsp_edits.peek() {
3046 if next_range.start.0 > range.end {
3047 if next_range.start.0.row > range.end.row + 1
3048 || next_range.start.0.column > 0
3049 || snapshot.clip_point_utf16(
3050 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3051 Bias::Left,
3052 ) > range.end
3053 {
3054 break;
3055 }
3056 new_text.push('\n');
3057 }
3058 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3059 new_text.push_str(next_text);
3060 lsp_edits.next();
3061 }
3062
3063 // For multiline edits, perform a diff of the old and new text so that
3064 // we can identify the changes more precisely, preserving the locations
3065 // of any anchors positioned in the unchanged regions.
3066 if range.end.row > range.start.row {
3067 let offset = range.start.to_offset(&snapshot);
3068 let old_text = snapshot.text_for_range(range).collect::<String>();
3069 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3070 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3071 (
3072 snapshot.anchor_after(offset + range.start)
3073 ..snapshot.anchor_before(offset + range.end),
3074 replacement,
3075 )
3076 }));
3077 } else if range.end == range.start {
3078 let anchor = snapshot.anchor_after(range.start);
3079 edits.push((anchor..anchor, new_text.into()));
3080 } else {
3081 let edit_start = snapshot.anchor_after(range.start);
3082 let edit_end = snapshot.anchor_before(range.end);
3083 edits.push((edit_start..edit_end, new_text.into()));
3084 }
3085 }
3086
3087 Ok(edits)
3088 })
3089 }
3090
3091 pub(crate) async fn deserialize_workspace_edit(
3092 this: Entity<LspStore>,
3093 edit: lsp::WorkspaceEdit,
3094 push_to_history: bool,
3095 language_server: Arc<LanguageServer>,
3096 cx: &mut AsyncApp,
3097 ) -> Result<ProjectTransaction> {
3098 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3099
3100 let mut operations = Vec::new();
3101 if let Some(document_changes) = edit.document_changes {
3102 match document_changes {
3103 lsp::DocumentChanges::Edits(edits) => {
3104 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3105 }
3106 lsp::DocumentChanges::Operations(ops) => operations = ops,
3107 }
3108 } else if let Some(changes) = edit.changes {
3109 operations.extend(changes.into_iter().map(|(uri, edits)| {
3110 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3111 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3112 uri,
3113 version: None,
3114 },
3115 edits: edits.into_iter().map(Edit::Plain).collect(),
3116 })
3117 }));
3118 }
3119
3120 let mut project_transaction = ProjectTransaction::default();
3121 for operation in operations {
3122 match operation {
3123 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3124 let abs_path = op
3125 .uri
3126 .to_file_path()
3127 .map_err(|()| anyhow!("can't convert URI to path"))?;
3128
3129 if let Some(parent_path) = abs_path.parent() {
3130 fs.create_dir(parent_path).await?;
3131 }
3132 if abs_path.ends_with("/") {
3133 fs.create_dir(&abs_path).await?;
3134 } else {
3135 fs.create_file(
3136 &abs_path,
3137 op.options
3138 .map(|options| fs::CreateOptions {
3139 overwrite: options.overwrite.unwrap_or(false),
3140 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3141 })
3142 .unwrap_or_default(),
3143 )
3144 .await?;
3145 }
3146 }
3147
3148 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3149 let source_abs_path = op
3150 .old_uri
3151 .to_file_path()
3152 .map_err(|()| anyhow!("can't convert URI to path"))?;
3153 let target_abs_path = op
3154 .new_uri
3155 .to_file_path()
3156 .map_err(|()| anyhow!("can't convert URI to path"))?;
3157
3158 let options = fs::RenameOptions {
3159 overwrite: op
3160 .options
3161 .as_ref()
3162 .and_then(|options| options.overwrite)
3163 .unwrap_or(false),
3164 ignore_if_exists: op
3165 .options
3166 .as_ref()
3167 .and_then(|options| options.ignore_if_exists)
3168 .unwrap_or(false),
3169 create_parents: true,
3170 };
3171
3172 fs.rename(&source_abs_path, &target_abs_path, options)
3173 .await?;
3174 }
3175
3176 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3177 let abs_path = op
3178 .uri
3179 .to_file_path()
3180 .map_err(|()| anyhow!("can't convert URI to path"))?;
3181 let options = op
3182 .options
3183 .map(|options| fs::RemoveOptions {
3184 recursive: options.recursive.unwrap_or(false),
3185 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3186 })
3187 .unwrap_or_default();
3188 if abs_path.ends_with("/") {
3189 fs.remove_dir(&abs_path, options).await?;
3190 } else {
3191 fs.remove_file(&abs_path, options).await?;
3192 }
3193 }
3194
3195 lsp::DocumentChangeOperation::Edit(op) => {
3196 let buffer_to_edit = this
3197 .update(cx, |this, cx| {
3198 this.open_local_buffer_via_lsp(
3199 op.text_document.uri.clone(),
3200 language_server.server_id(),
3201 cx,
3202 )
3203 })
3204 .await?;
3205
3206 let edits = this
3207 .update(cx, |this, cx| {
3208 let path = buffer_to_edit.read(cx).project_path(cx);
3209 let active_entry = this.active_entry;
3210 let is_active_entry = path.is_some_and(|project_path| {
3211 this.worktree_store
3212 .read(cx)
3213 .entry_for_path(&project_path, cx)
3214 .is_some_and(|entry| Some(entry.id) == active_entry)
3215 });
3216 let local = this.as_local_mut().unwrap();
3217
3218 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3219 for edit in op.edits {
3220 match edit {
3221 Edit::Plain(edit) => {
3222 if !edits.contains(&edit) {
3223 edits.push(edit)
3224 }
3225 }
3226 Edit::Annotated(edit) => {
3227 if !edits.contains(&edit.text_edit) {
3228 edits.push(edit.text_edit)
3229 }
3230 }
3231 Edit::Snippet(edit) => {
3232 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3233 else {
3234 continue;
3235 };
3236
3237 if is_active_entry {
3238 snippet_edits.push((edit.range, snippet));
3239 } else {
3240 // Since this buffer is not focused, apply a normal edit.
3241 let new_edit = TextEdit {
3242 range: edit.range,
3243 new_text: snippet.text,
3244 };
3245 if !edits.contains(&new_edit) {
3246 edits.push(new_edit);
3247 }
3248 }
3249 }
3250 }
3251 }
3252 if !snippet_edits.is_empty() {
3253 let buffer_id = buffer_to_edit.read(cx).remote_id();
3254 let version = if let Some(buffer_version) = op.text_document.version
3255 {
3256 local
3257 .buffer_snapshot_for_lsp_version(
3258 &buffer_to_edit,
3259 language_server.server_id(),
3260 Some(buffer_version),
3261 cx,
3262 )
3263 .ok()
3264 .map(|snapshot| snapshot.version)
3265 } else {
3266 Some(buffer_to_edit.read(cx).saved_version().clone())
3267 };
3268
3269 let most_recent_edit =
3270 version.and_then(|version| version.most_recent());
3271 // Check if the edit that triggered that edit has been made by this participant.
3272
3273 if let Some(most_recent_edit) = most_recent_edit {
3274 cx.emit(LspStoreEvent::SnippetEdit {
3275 buffer_id,
3276 edits: snippet_edits,
3277 most_recent_edit,
3278 });
3279 }
3280 }
3281
3282 local.edits_from_lsp(
3283 &buffer_to_edit,
3284 edits,
3285 language_server.server_id(),
3286 op.text_document.version,
3287 cx,
3288 )
3289 })
3290 .await?;
3291
3292 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3293 buffer.finalize_last_transaction();
3294 buffer.start_transaction();
3295 for (range, text) in edits {
3296 buffer.edit([(range, text)], None, cx);
3297 }
3298
3299 buffer.end_transaction(cx).and_then(|transaction_id| {
3300 if push_to_history {
3301 buffer.finalize_last_transaction();
3302 buffer.get_transaction(transaction_id).cloned()
3303 } else {
3304 buffer.forget_transaction(transaction_id)
3305 }
3306 })
3307 });
3308 if let Some(transaction) = transaction {
3309 project_transaction.0.insert(buffer_to_edit, transaction);
3310 }
3311 }
3312 }
3313 }
3314
3315 Ok(project_transaction)
3316 }
3317
3318 async fn on_lsp_workspace_edit(
3319 this: WeakEntity<LspStore>,
3320 params: lsp::ApplyWorkspaceEditParams,
3321 server_id: LanguageServerId,
3322 cx: &mut AsyncApp,
3323 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3324 let this = this.upgrade().context("project project closed")?;
3325 let language_server = this
3326 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3327 .context("language server not found")?;
3328 let transaction = Self::deserialize_workspace_edit(
3329 this.clone(),
3330 params.edit,
3331 true,
3332 language_server.clone(),
3333 cx,
3334 )
3335 .await
3336 .log_err();
3337 this.update(cx, |this, cx| {
3338 if let Some(transaction) = transaction {
3339 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3340
3341 this.as_local_mut()
3342 .unwrap()
3343 .last_workspace_edits_by_language_server
3344 .insert(server_id, transaction);
3345 }
3346 });
3347 Ok(lsp::ApplyWorkspaceEditResponse {
3348 applied: true,
3349 failed_change: None,
3350 failure_reason: None,
3351 })
3352 }
3353
3354 fn remove_worktree(
3355 &mut self,
3356 id_to_remove: WorktreeId,
3357 cx: &mut Context<LspStore>,
3358 ) -> Vec<LanguageServerId> {
3359 self.restricted_worktrees_tasks.remove(&id_to_remove);
3360 self.diagnostics.remove(&id_to_remove);
3361 self.prettier_store.update(cx, |prettier_store, cx| {
3362 prettier_store.remove_worktree(id_to_remove, cx);
3363 });
3364
3365 let mut servers_to_remove = BTreeSet::default();
3366 let mut servers_to_preserve = HashSet::default();
3367 for (seed, state) in &self.language_server_ids {
3368 if seed.worktree_id == id_to_remove {
3369 servers_to_remove.insert(state.id);
3370 } else {
3371 servers_to_preserve.insert(state.id);
3372 }
3373 }
3374 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3375 self.language_server_ids
3376 .retain(|_, state| !servers_to_remove.contains(&state.id));
3377 for server_id_to_remove in &servers_to_remove {
3378 self.language_server_watched_paths
3379 .remove(server_id_to_remove);
3380 self.language_server_paths_watched_for_rename
3381 .remove(server_id_to_remove);
3382 self.last_workspace_edits_by_language_server
3383 .remove(server_id_to_remove);
3384 self.language_servers.remove(server_id_to_remove);
3385 self.buffer_pull_diagnostics_result_ids
3386 .remove(server_id_to_remove);
3387 self.workspace_pull_diagnostics_result_ids
3388 .remove(server_id_to_remove);
3389 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3390 buffer_servers.remove(server_id_to_remove);
3391 }
3392 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3393 }
3394 servers_to_remove.into_iter().collect()
3395 }
3396
3397 fn rebuild_watched_paths_inner<'a>(
3398 &'a self,
3399 language_server_id: LanguageServerId,
3400 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3401 cx: &mut Context<LspStore>,
3402 ) -> LanguageServerWatchedPathsBuilder {
3403 let worktrees = self
3404 .worktree_store
3405 .read(cx)
3406 .worktrees()
3407 .filter_map(|worktree| {
3408 self.language_servers_for_worktree(worktree.read(cx).id())
3409 .find(|server| server.server_id() == language_server_id)
3410 .map(|_| worktree)
3411 })
3412 .collect::<Vec<_>>();
3413
3414 let mut worktree_globs = HashMap::default();
3415 let mut abs_globs = HashMap::default();
3416 log::trace!(
3417 "Processing new watcher paths for language server with id {}",
3418 language_server_id
3419 );
3420
3421 for watcher in watchers {
3422 if let Some((worktree, literal_prefix, pattern)) =
3423 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3424 {
3425 worktree.update(cx, |worktree, _| {
3426 if let Some((tree, glob)) =
3427 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3428 {
3429 tree.add_path_prefix_to_scan(literal_prefix);
3430 worktree_globs
3431 .entry(tree.id())
3432 .or_insert_with(GlobSetBuilder::new)
3433 .add(glob);
3434 }
3435 });
3436 } else {
3437 let (path, pattern) = match &watcher.glob_pattern {
3438 lsp::GlobPattern::String(s) => {
3439 let watcher_path = SanitizedPath::new(s);
3440 let path = glob_literal_prefix(watcher_path.as_path());
3441 let pattern = watcher_path
3442 .as_path()
3443 .strip_prefix(&path)
3444 .map(|p| p.to_string_lossy().into_owned())
3445 .unwrap_or_else(|e| {
3446 debug_panic!(
3447 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3448 s,
3449 path.display(),
3450 e
3451 );
3452 watcher_path.as_path().to_string_lossy().into_owned()
3453 });
3454 (path, pattern)
3455 }
3456 lsp::GlobPattern::Relative(rp) => {
3457 let Ok(mut base_uri) = match &rp.base_uri {
3458 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3459 lsp::OneOf::Right(base_uri) => base_uri,
3460 }
3461 .to_file_path() else {
3462 continue;
3463 };
3464
3465 let path = glob_literal_prefix(Path::new(&rp.pattern));
3466 let pattern = Path::new(&rp.pattern)
3467 .strip_prefix(&path)
3468 .map(|p| p.to_string_lossy().into_owned())
3469 .unwrap_or_else(|e| {
3470 debug_panic!(
3471 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3472 rp.pattern,
3473 path.display(),
3474 e
3475 );
3476 rp.pattern.clone()
3477 });
3478 base_uri.push(path);
3479 (base_uri, pattern)
3480 }
3481 };
3482
3483 if let Some(glob) = Glob::new(&pattern).log_err() {
3484 if !path
3485 .components()
3486 .any(|c| matches!(c, path::Component::Normal(_)))
3487 {
3488 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3489 // rather than adding a new watcher for `/`.
3490 for worktree in &worktrees {
3491 worktree_globs
3492 .entry(worktree.read(cx).id())
3493 .or_insert_with(GlobSetBuilder::new)
3494 .add(glob.clone());
3495 }
3496 } else {
3497 abs_globs
3498 .entry(path.into())
3499 .or_insert_with(GlobSetBuilder::new)
3500 .add(glob);
3501 }
3502 }
3503 }
3504 }
3505
3506 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3507 for (worktree_id, builder) in worktree_globs {
3508 if let Ok(globset) = builder.build() {
3509 watch_builder.watch_worktree(worktree_id, globset);
3510 }
3511 }
3512 for (abs_path, builder) in abs_globs {
3513 if let Ok(globset) = builder.build() {
3514 watch_builder.watch_abs_path(abs_path, globset);
3515 }
3516 }
3517 watch_builder
3518 }
3519
3520 fn worktree_and_path_for_file_watcher(
3521 worktrees: &[Entity<Worktree>],
3522 watcher: &FileSystemWatcher,
3523 cx: &App,
3524 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3525 worktrees.iter().find_map(|worktree| {
3526 let tree = worktree.read(cx);
3527 let worktree_root_path = tree.abs_path();
3528 let path_style = tree.path_style();
3529 match &watcher.glob_pattern {
3530 lsp::GlobPattern::String(s) => {
3531 let watcher_path = SanitizedPath::new(s);
3532 let relative = watcher_path
3533 .as_path()
3534 .strip_prefix(&worktree_root_path)
3535 .ok()?;
3536 let literal_prefix = glob_literal_prefix(relative);
3537 Some((
3538 worktree.clone(),
3539 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3540 relative.to_string_lossy().into_owned(),
3541 ))
3542 }
3543 lsp::GlobPattern::Relative(rp) => {
3544 let base_uri = match &rp.base_uri {
3545 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3546 lsp::OneOf::Right(base_uri) => base_uri,
3547 }
3548 .to_file_path()
3549 .ok()?;
3550 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3551 let mut literal_prefix = relative.to_owned();
3552 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3553 Some((
3554 worktree.clone(),
3555 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3556 rp.pattern.clone(),
3557 ))
3558 }
3559 }
3560 })
3561 }
3562
3563 fn rebuild_watched_paths(
3564 &mut self,
3565 language_server_id: LanguageServerId,
3566 cx: &mut Context<LspStore>,
3567 ) {
3568 let Some(registrations) = self
3569 .language_server_dynamic_registrations
3570 .get(&language_server_id)
3571 else {
3572 return;
3573 };
3574
3575 let watch_builder = self.rebuild_watched_paths_inner(
3576 language_server_id,
3577 registrations.did_change_watched_files.values().flatten(),
3578 cx,
3579 );
3580 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3581 self.language_server_watched_paths
3582 .insert(language_server_id, watcher);
3583
3584 cx.notify();
3585 }
3586
3587 fn on_lsp_did_change_watched_files(
3588 &mut self,
3589 language_server_id: LanguageServerId,
3590 registration_id: &str,
3591 params: DidChangeWatchedFilesRegistrationOptions,
3592 cx: &mut Context<LspStore>,
3593 ) {
3594 let registrations = self
3595 .language_server_dynamic_registrations
3596 .entry(language_server_id)
3597 .or_default();
3598
3599 registrations
3600 .did_change_watched_files
3601 .insert(registration_id.to_string(), params.watchers);
3602
3603 self.rebuild_watched_paths(language_server_id, cx);
3604 }
3605
3606 fn on_lsp_unregister_did_change_watched_files(
3607 &mut self,
3608 language_server_id: LanguageServerId,
3609 registration_id: &str,
3610 cx: &mut Context<LspStore>,
3611 ) {
3612 let registrations = self
3613 .language_server_dynamic_registrations
3614 .entry(language_server_id)
3615 .or_default();
3616
3617 if registrations
3618 .did_change_watched_files
3619 .remove(registration_id)
3620 .is_some()
3621 {
3622 log::info!(
3623 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3624 language_server_id,
3625 registration_id
3626 );
3627 } else {
3628 log::warn!(
3629 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3630 language_server_id,
3631 registration_id
3632 );
3633 }
3634
3635 self.rebuild_watched_paths(language_server_id, cx);
3636 }
3637
3638 async fn initialization_options_for_adapter(
3639 adapter: Arc<dyn LspAdapter>,
3640 delegate: &Arc<dyn LspAdapterDelegate>,
3641 ) -> Result<Option<serde_json::Value>> {
3642 let Some(mut initialization_config) =
3643 adapter.clone().initialization_options(delegate).await?
3644 else {
3645 return Ok(None);
3646 };
3647
3648 for other_adapter in delegate.registered_lsp_adapters() {
3649 if other_adapter.name() == adapter.name() {
3650 continue;
3651 }
3652 if let Ok(Some(target_config)) = other_adapter
3653 .clone()
3654 .additional_initialization_options(adapter.name(), delegate)
3655 .await
3656 {
3657 merge_json_value_into(target_config.clone(), &mut initialization_config);
3658 }
3659 }
3660
3661 Ok(Some(initialization_config))
3662 }
3663
3664 async fn workspace_configuration_for_adapter(
3665 adapter: Arc<dyn LspAdapter>,
3666 delegate: &Arc<dyn LspAdapterDelegate>,
3667 toolchain: Option<Toolchain>,
3668 requested_uri: Option<Uri>,
3669 cx: &mut AsyncApp,
3670 ) -> Result<serde_json::Value> {
3671 let mut workspace_config = adapter
3672 .clone()
3673 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3674 .await?;
3675
3676 for other_adapter in delegate.registered_lsp_adapters() {
3677 if other_adapter.name() == adapter.name() {
3678 continue;
3679 }
3680 if let Ok(Some(target_config)) = other_adapter
3681 .clone()
3682 .additional_workspace_configuration(adapter.name(), delegate, cx)
3683 .await
3684 {
3685 merge_json_value_into(target_config.clone(), &mut workspace_config);
3686 }
3687 }
3688
3689 Ok(workspace_config)
3690 }
3691
3692 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3693 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3694 Some(server.clone())
3695 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3696 Some(Arc::clone(server))
3697 } else {
3698 None
3699 }
3700 }
3701}
3702
3703fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3704 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3705 cx.emit(LspStoreEvent::LanguageServerUpdate {
3706 language_server_id: server.server_id(),
3707 name: Some(server.name()),
3708 message: proto::update_language_server::Variant::MetadataUpdated(
3709 proto::ServerMetadataUpdated {
3710 capabilities: Some(capabilities),
3711 binary: Some(proto::LanguageServerBinaryInfo {
3712 path: server.binary().path.to_string_lossy().into_owned(),
3713 arguments: server
3714 .binary()
3715 .arguments
3716 .iter()
3717 .map(|arg| arg.to_string_lossy().into_owned())
3718 .collect(),
3719 }),
3720 configuration: serde_json::to_string(server.configuration()).ok(),
3721 workspace_folders: server
3722 .workspace_folders()
3723 .iter()
3724 .map(|uri| uri.to_string())
3725 .collect(),
3726 },
3727 ),
3728 });
3729 }
3730}
3731
3732#[derive(Debug)]
3733pub struct FormattableBuffer {
3734 handle: Entity<Buffer>,
3735 abs_path: Option<PathBuf>,
3736 env: Option<HashMap<String, String>>,
3737 ranges: Option<Vec<Range<Anchor>>>,
3738}
3739
3740pub struct RemoteLspStore {
3741 upstream_client: Option<AnyProtoClient>,
3742 upstream_project_id: u64,
3743}
3744
3745pub(crate) enum LspStoreMode {
3746 Local(LocalLspStore), // ssh host and collab host
3747 Remote(RemoteLspStore), // collab guest
3748}
3749
3750impl LspStoreMode {
3751 fn is_local(&self) -> bool {
3752 matches!(self, LspStoreMode::Local(_))
3753 }
3754}
3755
3756pub struct LspStore {
3757 mode: LspStoreMode,
3758 last_formatting_failure: Option<String>,
3759 downstream_client: Option<(AnyProtoClient, u64)>,
3760 nonce: u128,
3761 buffer_store: Entity<BufferStore>,
3762 worktree_store: Entity<WorktreeStore>,
3763 pub languages: Arc<LanguageRegistry>,
3764 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3765 active_entry: Option<ProjectEntryId>,
3766 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3767 _maintain_buffer_languages: Task<()>,
3768 diagnostic_summaries:
3769 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3770 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3771 lsp_data: HashMap<BufferId, BufferLspData>,
3772 next_hint_id: Arc<AtomicUsize>,
3773}
3774
3775#[derive(Debug)]
3776pub struct BufferLspData {
3777 buffer_version: Global,
3778 document_colors: Option<DocumentColorData>,
3779 code_lens: Option<CodeLensData>,
3780 inlay_hints: BufferInlayHints,
3781 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3782 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3783}
3784
3785#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3786struct LspKey {
3787 request_type: TypeId,
3788 server_queried: Option<LanguageServerId>,
3789}
3790
3791impl BufferLspData {
3792 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3793 Self {
3794 buffer_version: buffer.read(cx).version(),
3795 document_colors: None,
3796 code_lens: None,
3797 inlay_hints: BufferInlayHints::new(buffer, cx),
3798 lsp_requests: HashMap::default(),
3799 chunk_lsp_requests: HashMap::default(),
3800 }
3801 }
3802
3803 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3804 if let Some(document_colors) = &mut self.document_colors {
3805 document_colors.colors.remove(&for_server);
3806 document_colors.cache_version += 1;
3807 }
3808
3809 if let Some(code_lens) = &mut self.code_lens {
3810 code_lens.lens.remove(&for_server);
3811 }
3812
3813 self.inlay_hints.remove_server_data(for_server);
3814 }
3815
3816 #[cfg(any(test, feature = "test-support"))]
3817 pub fn inlay_hints(&self) -> &BufferInlayHints {
3818 &self.inlay_hints
3819 }
3820}
3821
3822#[derive(Debug, Default, Clone)]
3823pub struct DocumentColors {
3824 pub colors: HashSet<DocumentColor>,
3825 pub cache_version: Option<usize>,
3826}
3827
3828type DocumentColorTask = Shared<Task<std::result::Result<DocumentColors, Arc<anyhow::Error>>>>;
3829type CodeLensTask = Shared<Task<std::result::Result<Option<Vec<CodeAction>>, Arc<anyhow::Error>>>>;
3830
3831#[derive(Debug, Default)]
3832struct DocumentColorData {
3833 colors: HashMap<LanguageServerId, HashSet<DocumentColor>>,
3834 cache_version: usize,
3835 colors_update: Option<(Global, DocumentColorTask)>,
3836}
3837
3838#[derive(Debug, Default)]
3839struct CodeLensData {
3840 lens: HashMap<LanguageServerId, Vec<CodeAction>>,
3841 update: Option<(Global, CodeLensTask)>,
3842}
3843
3844#[derive(Debug)]
3845pub enum LspStoreEvent {
3846 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3847 LanguageServerRemoved(LanguageServerId),
3848 LanguageServerUpdate {
3849 language_server_id: LanguageServerId,
3850 name: Option<LanguageServerName>,
3851 message: proto::update_language_server::Variant,
3852 },
3853 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3854 LanguageServerPrompt(LanguageServerPromptRequest),
3855 LanguageDetected {
3856 buffer: Entity<Buffer>,
3857 new_language: Option<Arc<Language>>,
3858 },
3859 Notification(String),
3860 RefreshInlayHints {
3861 server_id: LanguageServerId,
3862 request_id: Option<usize>,
3863 },
3864 RefreshCodeLens,
3865 DiagnosticsUpdated {
3866 server_id: LanguageServerId,
3867 paths: Vec<ProjectPath>,
3868 },
3869 DiskBasedDiagnosticsStarted {
3870 language_server_id: LanguageServerId,
3871 },
3872 DiskBasedDiagnosticsFinished {
3873 language_server_id: LanguageServerId,
3874 },
3875 SnippetEdit {
3876 buffer_id: BufferId,
3877 edits: Vec<(lsp::Range, Snippet)>,
3878 most_recent_edit: clock::Lamport,
3879 },
3880 WorkspaceEditApplied(ProjectTransaction),
3881}
3882
3883#[derive(Clone, Debug, Serialize)]
3884pub struct LanguageServerStatus {
3885 pub name: LanguageServerName,
3886 pub server_version: Option<SharedString>,
3887 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
3888 pub has_pending_diagnostic_updates: bool,
3889 pub progress_tokens: HashSet<ProgressToken>,
3890 pub worktree: Option<WorktreeId>,
3891 pub binary: Option<LanguageServerBinary>,
3892 pub configuration: Option<Value>,
3893 pub workspace_folders: BTreeSet<Uri>,
3894}
3895
3896#[derive(Clone, Debug)]
3897struct CoreSymbol {
3898 pub language_server_name: LanguageServerName,
3899 pub source_worktree_id: WorktreeId,
3900 pub source_language_server_id: LanguageServerId,
3901 pub path: SymbolLocation,
3902 pub name: String,
3903 pub kind: lsp::SymbolKind,
3904 pub range: Range<Unclipped<PointUtf16>>,
3905}
3906
3907#[derive(Clone, Debug, PartialEq, Eq)]
3908pub enum SymbolLocation {
3909 InProject(ProjectPath),
3910 OutsideProject {
3911 abs_path: Arc<Path>,
3912 signature: [u8; 32],
3913 },
3914}
3915
3916impl SymbolLocation {
3917 fn file_name(&self) -> Option<&str> {
3918 match self {
3919 Self::InProject(path) => path.path.file_name(),
3920 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
3921 }
3922 }
3923}
3924
3925impl LspStore {
3926 pub fn init(client: &AnyProtoClient) {
3927 client.add_entity_request_handler(Self::handle_lsp_query);
3928 client.add_entity_message_handler(Self::handle_lsp_query_response);
3929 client.add_entity_request_handler(Self::handle_restart_language_servers);
3930 client.add_entity_request_handler(Self::handle_stop_language_servers);
3931 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
3932 client.add_entity_message_handler(Self::handle_start_language_server);
3933 client.add_entity_message_handler(Self::handle_update_language_server);
3934 client.add_entity_message_handler(Self::handle_language_server_log);
3935 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
3936 client.add_entity_request_handler(Self::handle_format_buffers);
3937 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
3938 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
3939 client.add_entity_request_handler(Self::handle_apply_code_action);
3940 client.add_entity_request_handler(Self::handle_get_project_symbols);
3941 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
3942 client.add_entity_request_handler(Self::handle_get_color_presentation);
3943 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
3944 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
3945 client.add_entity_request_handler(Self::handle_refresh_code_lens);
3946 client.add_entity_request_handler(Self::handle_on_type_formatting);
3947 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
3948 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
3949 client.add_entity_request_handler(Self::handle_rename_project_entry);
3950 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
3951 client.add_entity_request_handler(Self::handle_lsp_get_completions);
3952 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
3953 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
3954 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
3955 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
3956 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
3957
3958 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
3959 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
3960 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
3961 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
3962 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
3963 client.add_entity_request_handler(
3964 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
3965 );
3966 client.add_entity_request_handler(
3967 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
3968 );
3969 client.add_entity_request_handler(
3970 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
3971 );
3972 }
3973
3974 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
3975 match &self.mode {
3976 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
3977 _ => None,
3978 }
3979 }
3980
3981 pub fn as_local(&self) -> Option<&LocalLspStore> {
3982 match &self.mode {
3983 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3984 _ => None,
3985 }
3986 }
3987
3988 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
3989 match &mut self.mode {
3990 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
3991 _ => None,
3992 }
3993 }
3994
3995 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
3996 match &self.mode {
3997 LspStoreMode::Remote(RemoteLspStore {
3998 upstream_client: Some(upstream_client),
3999 upstream_project_id,
4000 ..
4001 }) => Some((upstream_client.clone(), *upstream_project_id)),
4002
4003 LspStoreMode::Remote(RemoteLspStore {
4004 upstream_client: None,
4005 ..
4006 }) => None,
4007 LspStoreMode::Local(_) => None,
4008 }
4009 }
4010
4011 pub fn new_local(
4012 buffer_store: Entity<BufferStore>,
4013 worktree_store: Entity<WorktreeStore>,
4014 prettier_store: Entity<PrettierStore>,
4015 toolchain_store: Entity<LocalToolchainStore>,
4016 environment: Entity<ProjectEnvironment>,
4017 manifest_tree: Entity<ManifestTree>,
4018 languages: Arc<LanguageRegistry>,
4019 http_client: Arc<dyn HttpClient>,
4020 fs: Arc<dyn Fs>,
4021 cx: &mut Context<Self>,
4022 ) -> Self {
4023 let yarn = YarnPathStore::new(fs.clone(), cx);
4024 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4025 .detach();
4026 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4027 .detach();
4028 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4029 .detach();
4030 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4031 .detach();
4032 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4033 .detach();
4034 subscribe_to_binary_statuses(&languages, cx).detach();
4035
4036 let _maintain_workspace_config = {
4037 let (sender, receiver) = watch::channel();
4038 (Self::maintain_workspace_config(receiver, cx), sender)
4039 };
4040
4041 Self {
4042 mode: LspStoreMode::Local(LocalLspStore {
4043 weak: cx.weak_entity(),
4044 worktree_store: worktree_store.clone(),
4045
4046 supplementary_language_servers: Default::default(),
4047 languages: languages.clone(),
4048 language_server_ids: Default::default(),
4049 language_servers: Default::default(),
4050 last_workspace_edits_by_language_server: Default::default(),
4051 language_server_watched_paths: Default::default(),
4052 language_server_paths_watched_for_rename: Default::default(),
4053 language_server_dynamic_registrations: Default::default(),
4054 buffers_being_formatted: Default::default(),
4055 buffer_snapshots: Default::default(),
4056 prettier_store,
4057 environment,
4058 http_client,
4059 fs,
4060 yarn,
4061 next_diagnostic_group_id: Default::default(),
4062 diagnostics: Default::default(),
4063 _subscription: cx.on_app_quit(|this, cx| {
4064 this.as_local_mut()
4065 .unwrap()
4066 .shutdown_language_servers_on_quit(cx)
4067 }),
4068 lsp_tree: LanguageServerTree::new(
4069 manifest_tree,
4070 languages.clone(),
4071 toolchain_store.clone(),
4072 ),
4073 toolchain_store,
4074 registered_buffers: HashMap::default(),
4075 buffers_opened_in_servers: HashMap::default(),
4076 buffer_pull_diagnostics_result_ids: HashMap::default(),
4077 workspace_pull_diagnostics_result_ids: HashMap::default(),
4078 restricted_worktrees_tasks: HashMap::default(),
4079 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4080 .manifest_file_names(),
4081 }),
4082 last_formatting_failure: None,
4083 downstream_client: None,
4084 buffer_store,
4085 worktree_store,
4086 languages: languages.clone(),
4087 language_server_statuses: Default::default(),
4088 nonce: StdRng::from_os_rng().random(),
4089 diagnostic_summaries: HashMap::default(),
4090 lsp_server_capabilities: HashMap::default(),
4091 lsp_data: HashMap::default(),
4092 next_hint_id: Arc::default(),
4093 active_entry: None,
4094 _maintain_workspace_config,
4095 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4096 }
4097 }
4098
4099 fn send_lsp_proto_request<R: LspCommand>(
4100 &self,
4101 buffer: Entity<Buffer>,
4102 client: AnyProtoClient,
4103 upstream_project_id: u64,
4104 request: R,
4105 cx: &mut Context<LspStore>,
4106 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4107 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4108 return Task::ready(Ok(R::Response::default()));
4109 }
4110 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4111 cx.spawn(async move |this, cx| {
4112 let response = client.request(message).await?;
4113 let this = this.upgrade().context("project dropped")?;
4114 request
4115 .response_from_proto(response, this, buffer, cx.clone())
4116 .await
4117 })
4118 }
4119
4120 pub(super) fn new_remote(
4121 buffer_store: Entity<BufferStore>,
4122 worktree_store: Entity<WorktreeStore>,
4123 languages: Arc<LanguageRegistry>,
4124 upstream_client: AnyProtoClient,
4125 project_id: u64,
4126 cx: &mut Context<Self>,
4127 ) -> Self {
4128 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4129 .detach();
4130 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4131 .detach();
4132 subscribe_to_binary_statuses(&languages, cx).detach();
4133 let _maintain_workspace_config = {
4134 let (sender, receiver) = watch::channel();
4135 (Self::maintain_workspace_config(receiver, cx), sender)
4136 };
4137 Self {
4138 mode: LspStoreMode::Remote(RemoteLspStore {
4139 upstream_client: Some(upstream_client),
4140 upstream_project_id: project_id,
4141 }),
4142 downstream_client: None,
4143 last_formatting_failure: None,
4144 buffer_store,
4145 worktree_store,
4146 languages: languages.clone(),
4147 language_server_statuses: Default::default(),
4148 nonce: StdRng::from_os_rng().random(),
4149 diagnostic_summaries: HashMap::default(),
4150 lsp_server_capabilities: HashMap::default(),
4151 next_hint_id: Arc::default(),
4152 lsp_data: HashMap::default(),
4153 active_entry: None,
4154
4155 _maintain_workspace_config,
4156 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4157 }
4158 }
4159
4160 fn on_buffer_store_event(
4161 &mut self,
4162 _: Entity<BufferStore>,
4163 event: &BufferStoreEvent,
4164 cx: &mut Context<Self>,
4165 ) {
4166 match event {
4167 BufferStoreEvent::BufferAdded(buffer) => {
4168 self.on_buffer_added(buffer, cx).log_err();
4169 }
4170 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4171 let buffer_id = buffer.read(cx).remote_id();
4172 if let Some(local) = self.as_local_mut()
4173 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4174 {
4175 local.reset_buffer(buffer, old_file, cx);
4176
4177 if local.registered_buffers.contains_key(&buffer_id) {
4178 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4179 }
4180 }
4181
4182 self.detect_language_for_buffer(buffer, cx);
4183 if let Some(local) = self.as_local_mut() {
4184 local.initialize_buffer(buffer, cx);
4185 if local.registered_buffers.contains_key(&buffer_id) {
4186 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4187 }
4188 }
4189 }
4190 _ => {}
4191 }
4192 }
4193
4194 fn on_worktree_store_event(
4195 &mut self,
4196 _: Entity<WorktreeStore>,
4197 event: &WorktreeStoreEvent,
4198 cx: &mut Context<Self>,
4199 ) {
4200 match event {
4201 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4202 if !worktree.read(cx).is_local() {
4203 return;
4204 }
4205 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4206 worktree::Event::UpdatedEntries(changes) => {
4207 this.update_local_worktree_language_servers(&worktree, changes, cx);
4208 }
4209 worktree::Event::UpdatedGitRepositories(_)
4210 | worktree::Event::DeletedEntry(_) => {}
4211 })
4212 .detach()
4213 }
4214 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4215 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4216 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4217 }
4218 WorktreeStoreEvent::WorktreeReleased(..)
4219 | WorktreeStoreEvent::WorktreeOrderChanged
4220 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4221 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4222 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4223 }
4224 }
4225
4226 fn on_prettier_store_event(
4227 &mut self,
4228 _: Entity<PrettierStore>,
4229 event: &PrettierStoreEvent,
4230 cx: &mut Context<Self>,
4231 ) {
4232 match event {
4233 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4234 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4235 }
4236 PrettierStoreEvent::LanguageServerAdded {
4237 new_server_id,
4238 name,
4239 prettier_server,
4240 } => {
4241 self.register_supplementary_language_server(
4242 *new_server_id,
4243 name.clone(),
4244 prettier_server.clone(),
4245 cx,
4246 );
4247 }
4248 }
4249 }
4250
4251 fn on_toolchain_store_event(
4252 &mut self,
4253 _: Entity<LocalToolchainStore>,
4254 event: &ToolchainStoreEvent,
4255 _: &mut Context<Self>,
4256 ) {
4257 if let ToolchainStoreEvent::ToolchainActivated = event {
4258 self.request_workspace_config_refresh()
4259 }
4260 }
4261
4262 fn request_workspace_config_refresh(&mut self) {
4263 *self._maintain_workspace_config.1.borrow_mut() = ();
4264 }
4265
4266 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4267 self.as_local().map(|local| local.prettier_store.clone())
4268 }
4269
4270 fn on_buffer_event(
4271 &mut self,
4272 buffer: Entity<Buffer>,
4273 event: &language::BufferEvent,
4274 cx: &mut Context<Self>,
4275 ) {
4276 match event {
4277 language::BufferEvent::Edited => {
4278 self.on_buffer_edited(buffer, cx);
4279 }
4280
4281 language::BufferEvent::Saved => {
4282 self.on_buffer_saved(buffer, cx);
4283 }
4284
4285 _ => {}
4286 }
4287 }
4288
4289 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4290 buffer
4291 .read(cx)
4292 .set_language_registry(self.languages.clone());
4293
4294 cx.subscribe(buffer, |this, buffer, event, cx| {
4295 this.on_buffer_event(buffer, event, cx);
4296 })
4297 .detach();
4298
4299 self.detect_language_for_buffer(buffer, cx);
4300 if let Some(local) = self.as_local_mut() {
4301 local.initialize_buffer(buffer, cx);
4302 }
4303
4304 Ok(())
4305 }
4306
4307 pub(crate) fn register_buffer_with_language_servers(
4308 &mut self,
4309 buffer: &Entity<Buffer>,
4310 only_register_servers: HashSet<LanguageServerSelector>,
4311 ignore_refcounts: bool,
4312 cx: &mut Context<Self>,
4313 ) -> OpenLspBufferHandle {
4314 let buffer_id = buffer.read(cx).remote_id();
4315 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4316 if let Some(local) = self.as_local_mut() {
4317 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4318 if !ignore_refcounts {
4319 *refcount += 1;
4320 }
4321
4322 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4323 // 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
4324 // 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
4325 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4326 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4327 return handle;
4328 };
4329 if !file.is_local() {
4330 return handle;
4331 }
4332
4333 if ignore_refcounts || *refcount == 1 {
4334 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4335 }
4336 if !ignore_refcounts {
4337 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4338 let refcount = {
4339 let local = lsp_store.as_local_mut().unwrap();
4340 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4341 debug_panic!("bad refcounting");
4342 return;
4343 };
4344
4345 *refcount -= 1;
4346 *refcount
4347 };
4348 if refcount == 0 {
4349 lsp_store.lsp_data.remove(&buffer_id);
4350 let local = lsp_store.as_local_mut().unwrap();
4351 local.registered_buffers.remove(&buffer_id);
4352
4353 local.buffers_opened_in_servers.remove(&buffer_id);
4354 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4355 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4356
4357 let buffer_abs_path = file.abs_path(cx);
4358 for (_, buffer_pull_diagnostics_result_ids) in
4359 &mut local.buffer_pull_diagnostics_result_ids
4360 {
4361 buffer_pull_diagnostics_result_ids.retain(
4362 |_, buffer_result_ids| {
4363 buffer_result_ids.remove(&buffer_abs_path);
4364 !buffer_result_ids.is_empty()
4365 },
4366 );
4367 }
4368
4369 let diagnostic_updates = local
4370 .language_servers
4371 .keys()
4372 .cloned()
4373 .map(|server_id| DocumentDiagnosticsUpdate {
4374 diagnostics: DocumentDiagnostics {
4375 document_abs_path: buffer_abs_path.clone(),
4376 version: None,
4377 diagnostics: Vec::new(),
4378 },
4379 result_id: None,
4380 registration_id: None,
4381 server_id: server_id,
4382 disk_based_sources: Cow::Borrowed(&[]),
4383 })
4384 .collect::<Vec<_>>();
4385
4386 lsp_store
4387 .merge_diagnostic_entries(
4388 diagnostic_updates,
4389 |_, diagnostic, _| {
4390 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4391 },
4392 cx,
4393 )
4394 .context("Clearing diagnostics for the closed buffer")
4395 .log_err();
4396 }
4397 }
4398 })
4399 .detach();
4400 }
4401 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4402 let buffer_id = buffer.read(cx).remote_id().to_proto();
4403 cx.background_spawn(async move {
4404 upstream_client
4405 .request(proto::RegisterBufferWithLanguageServers {
4406 project_id: upstream_project_id,
4407 buffer_id,
4408 only_servers: only_register_servers
4409 .into_iter()
4410 .map(|selector| {
4411 let selector = match selector {
4412 LanguageServerSelector::Id(language_server_id) => {
4413 proto::language_server_selector::Selector::ServerId(
4414 language_server_id.to_proto(),
4415 )
4416 }
4417 LanguageServerSelector::Name(language_server_name) => {
4418 proto::language_server_selector::Selector::Name(
4419 language_server_name.to_string(),
4420 )
4421 }
4422 };
4423 proto::LanguageServerSelector {
4424 selector: Some(selector),
4425 }
4426 })
4427 .collect(),
4428 })
4429 .await
4430 })
4431 .detach();
4432 } else {
4433 // Our remote connection got closed
4434 }
4435 handle
4436 }
4437
4438 fn maintain_buffer_languages(
4439 languages: Arc<LanguageRegistry>,
4440 cx: &mut Context<Self>,
4441 ) -> Task<()> {
4442 let mut subscription = languages.subscribe();
4443 let mut prev_reload_count = languages.reload_count();
4444 cx.spawn(async move |this, cx| {
4445 while let Some(()) = subscription.next().await {
4446 if let Some(this) = this.upgrade() {
4447 // If the language registry has been reloaded, then remove and
4448 // re-assign the languages on all open buffers.
4449 let reload_count = languages.reload_count();
4450 if reload_count > prev_reload_count {
4451 prev_reload_count = reload_count;
4452 this.update(cx, |this, cx| {
4453 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4454 for buffer in buffer_store.buffers() {
4455 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4456 {
4457 buffer.update(cx, |buffer, cx| {
4458 buffer.set_language_async(None, cx)
4459 });
4460 if let Some(local) = this.as_local_mut() {
4461 local.reset_buffer(&buffer, &f, cx);
4462
4463 if local
4464 .registered_buffers
4465 .contains_key(&buffer.read(cx).remote_id())
4466 && let Some(file_url) =
4467 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4468 {
4469 local.unregister_buffer_from_language_servers(
4470 &buffer, &file_url, cx,
4471 );
4472 }
4473 }
4474 }
4475 }
4476 });
4477 });
4478 }
4479
4480 this.update(cx, |this, cx| {
4481 let mut plain_text_buffers = Vec::new();
4482 let mut buffers_with_unknown_injections = Vec::new();
4483 for handle in this.buffer_store.read(cx).buffers() {
4484 let buffer = handle.read(cx);
4485 if buffer.language().is_none()
4486 || buffer.language() == Some(&*language::PLAIN_TEXT)
4487 {
4488 plain_text_buffers.push(handle);
4489 } else if buffer.contains_unknown_injections() {
4490 buffers_with_unknown_injections.push(handle);
4491 }
4492 }
4493
4494 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4495 // and reused later in the invisible worktrees.
4496 plain_text_buffers.sort_by_key(|buffer| {
4497 Reverse(
4498 File::from_dyn(buffer.read(cx).file())
4499 .map(|file| file.worktree.read(cx).is_visible()),
4500 )
4501 });
4502
4503 for buffer in plain_text_buffers {
4504 this.detect_language_for_buffer(&buffer, cx);
4505 if let Some(local) = this.as_local_mut() {
4506 local.initialize_buffer(&buffer, cx);
4507 if local
4508 .registered_buffers
4509 .contains_key(&buffer.read(cx).remote_id())
4510 {
4511 local.register_buffer_with_language_servers(
4512 &buffer,
4513 HashSet::default(),
4514 cx,
4515 );
4516 }
4517 }
4518 }
4519
4520 for buffer in buffers_with_unknown_injections {
4521 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4522 }
4523 });
4524 }
4525 }
4526 })
4527 }
4528
4529 fn detect_language_for_buffer(
4530 &mut self,
4531 buffer_handle: &Entity<Buffer>,
4532 cx: &mut Context<Self>,
4533 ) -> Option<language::AvailableLanguage> {
4534 // If the buffer has a language, set it and start the language server if we haven't already.
4535 let buffer = buffer_handle.read(cx);
4536 let file = buffer.file()?;
4537
4538 let content = buffer.as_rope();
4539 let available_language = self.languages.language_for_file(file, Some(content), cx);
4540 if let Some(available_language) = &available_language {
4541 if let Some(Ok(Ok(new_language))) = self
4542 .languages
4543 .load_language(available_language)
4544 .now_or_never()
4545 {
4546 self.set_language_for_buffer(buffer_handle, new_language, cx);
4547 }
4548 } else {
4549 cx.emit(LspStoreEvent::LanguageDetected {
4550 buffer: buffer_handle.clone(),
4551 new_language: None,
4552 });
4553 }
4554
4555 available_language
4556 }
4557
4558 pub(crate) fn set_language_for_buffer(
4559 &mut self,
4560 buffer_entity: &Entity<Buffer>,
4561 new_language: Arc<Language>,
4562 cx: &mut Context<Self>,
4563 ) {
4564 let buffer = buffer_entity.read(cx);
4565 let buffer_file = buffer.file().cloned();
4566 let buffer_id = buffer.remote_id();
4567 if let Some(local_store) = self.as_local_mut()
4568 && local_store.registered_buffers.contains_key(&buffer_id)
4569 && let Some(abs_path) =
4570 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4571 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4572 {
4573 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4574 }
4575 buffer_entity.update(cx, |buffer, cx| {
4576 if buffer
4577 .language()
4578 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4579 {
4580 buffer.set_language_async(Some(new_language.clone()), cx);
4581 }
4582 });
4583
4584 let settings =
4585 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4586 let buffer_file = File::from_dyn(buffer_file.as_ref());
4587
4588 let worktree_id = if let Some(file) = buffer_file {
4589 let worktree = file.worktree.clone();
4590
4591 if let Some(local) = self.as_local_mut()
4592 && local.registered_buffers.contains_key(&buffer_id)
4593 {
4594 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4595 }
4596 Some(worktree.read(cx).id())
4597 } else {
4598 None
4599 };
4600
4601 if settings.prettier.allowed
4602 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4603 {
4604 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4605 if let Some(prettier_store) = prettier_store {
4606 prettier_store.update(cx, |prettier_store, cx| {
4607 prettier_store.install_default_prettier(
4608 worktree_id,
4609 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4610 cx,
4611 )
4612 })
4613 }
4614 }
4615
4616 cx.emit(LspStoreEvent::LanguageDetected {
4617 buffer: buffer_entity.clone(),
4618 new_language: Some(new_language),
4619 })
4620 }
4621
4622 pub fn buffer_store(&self) -> Entity<BufferStore> {
4623 self.buffer_store.clone()
4624 }
4625
4626 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4627 self.active_entry = active_entry;
4628 }
4629
4630 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4631 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4632 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4633 {
4634 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4635 summaries
4636 .iter()
4637 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4638 });
4639 if let Some(summary) = summaries.next() {
4640 client
4641 .send(proto::UpdateDiagnosticSummary {
4642 project_id: downstream_project_id,
4643 worktree_id: worktree.id().to_proto(),
4644 summary: Some(summary),
4645 more_summaries: summaries.collect(),
4646 })
4647 .log_err();
4648 }
4649 }
4650 }
4651
4652 fn is_capable_for_proto_request<R>(
4653 &self,
4654 buffer: &Entity<Buffer>,
4655 request: &R,
4656 cx: &App,
4657 ) -> bool
4658 where
4659 R: LspCommand,
4660 {
4661 self.check_if_capable_for_proto_request(
4662 buffer,
4663 |capabilities| {
4664 request.check_capabilities(AdapterServerCapabilities {
4665 server_capabilities: capabilities.clone(),
4666 code_action_kinds: None,
4667 })
4668 },
4669 cx,
4670 )
4671 }
4672
4673 fn check_if_capable_for_proto_request<F>(
4674 &self,
4675 buffer: &Entity<Buffer>,
4676 check: F,
4677 cx: &App,
4678 ) -> bool
4679 where
4680 F: FnMut(&lsp::ServerCapabilities) -> bool,
4681 {
4682 let Some(language) = buffer.read(cx).language().cloned() else {
4683 return false;
4684 };
4685 let registered_language_servers = self
4686 .languages
4687 .lsp_adapters(&language.name())
4688 .into_iter()
4689 .map(|lsp_adapter| lsp_adapter.name())
4690 .collect::<HashSet<_>>();
4691 self.language_server_statuses
4692 .iter()
4693 .filter_map(|(server_id, server_status)| {
4694 // Include servers that are either registered for this language OR
4695 // available to be loaded (for SSH remote mode where adapters like
4696 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4697 // but only loaded on the server side)
4698 let is_relevant = registered_language_servers.contains(&server_status.name)
4699 || self.languages.is_lsp_adapter_available(&server_status.name);
4700 is_relevant.then_some(server_id)
4701 })
4702 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4703 .any(check)
4704 }
4705
4706 fn all_capable_for_proto_request<F>(
4707 &self,
4708 buffer: &Entity<Buffer>,
4709 mut check: F,
4710 cx: &App,
4711 ) -> Vec<lsp::LanguageServerId>
4712 where
4713 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4714 {
4715 let Some(language) = buffer.read(cx).language().cloned() else {
4716 return Vec::default();
4717 };
4718 let registered_language_servers = self
4719 .languages
4720 .lsp_adapters(&language.name())
4721 .into_iter()
4722 .map(|lsp_adapter| lsp_adapter.name())
4723 .collect::<HashSet<_>>();
4724 self.language_server_statuses
4725 .iter()
4726 .filter_map(|(server_id, server_status)| {
4727 // Include servers that are either registered for this language OR
4728 // available to be loaded (for SSH remote mode where adapters like
4729 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4730 // but only loaded on the server side)
4731 let is_relevant = registered_language_servers.contains(&server_status.name)
4732 || self.languages.is_lsp_adapter_available(&server_status.name);
4733 is_relevant.then_some((server_id, &server_status.name))
4734 })
4735 .filter_map(|(server_id, server_name)| {
4736 self.lsp_server_capabilities
4737 .get(server_id)
4738 .map(|c| (server_id, server_name, c))
4739 })
4740 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4741 .map(|(server_id, _, _)| *server_id)
4742 .collect()
4743 }
4744
4745 pub fn request_lsp<R>(
4746 &mut self,
4747 buffer: Entity<Buffer>,
4748 server: LanguageServerToQuery,
4749 request: R,
4750 cx: &mut Context<Self>,
4751 ) -> Task<Result<R::Response>>
4752 where
4753 R: LspCommand,
4754 <R::LspRequest as lsp::request::Request>::Result: Send,
4755 <R::LspRequest as lsp::request::Request>::Params: Send,
4756 {
4757 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4758 return self.send_lsp_proto_request(
4759 buffer,
4760 upstream_client,
4761 upstream_project_id,
4762 request,
4763 cx,
4764 );
4765 }
4766
4767 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4768 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4769 local
4770 .language_servers_for_buffer(buffer, cx)
4771 .find(|(_, server)| {
4772 request.check_capabilities(server.adapter_server_capabilities())
4773 })
4774 .map(|(_, server)| server.clone())
4775 }),
4776 LanguageServerToQuery::Other(id) => self
4777 .language_server_for_local_buffer(buffer, id, cx)
4778 .and_then(|(_, server)| {
4779 request
4780 .check_capabilities(server.adapter_server_capabilities())
4781 .then(|| Arc::clone(server))
4782 }),
4783 }) else {
4784 return Task::ready(Ok(Default::default()));
4785 };
4786
4787 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4788
4789 let Some(file) = file else {
4790 return Task::ready(Ok(Default::default()));
4791 };
4792
4793 let lsp_params = match request.to_lsp_params_or_response(
4794 &file.abs_path(cx),
4795 buffer.read(cx),
4796 &language_server,
4797 cx,
4798 ) {
4799 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4800 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4801 Err(err) => {
4802 let message = format!(
4803 "{} via {} failed: {}",
4804 request.display_name(),
4805 language_server.name(),
4806 err
4807 );
4808 // rust-analyzer likes to error with this when its still loading up
4809 if !message.ends_with("content modified") {
4810 log::warn!("{message}");
4811 }
4812 return Task::ready(Err(anyhow!(message)));
4813 }
4814 };
4815
4816 let status = request.status();
4817 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
4818 return Task::ready(Ok(Default::default()));
4819 }
4820 cx.spawn(async move |this, cx| {
4821 let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
4822
4823 let id = lsp_request.id();
4824 let _cleanup = if status.is_some() {
4825 cx.update(|cx| {
4826 this.update(cx, |this, cx| {
4827 this.on_lsp_work_start(
4828 language_server.server_id(),
4829 ProgressToken::Number(id),
4830 LanguageServerProgress {
4831 is_disk_based_diagnostics_progress: false,
4832 is_cancellable: false,
4833 title: None,
4834 message: status.clone(),
4835 percentage: None,
4836 last_update_at: cx.background_executor().now(),
4837 },
4838 cx,
4839 );
4840 })
4841 })
4842 .log_err();
4843
4844 Some(defer(|| {
4845 cx.update(|cx| {
4846 this.update(cx, |this, cx| {
4847 this.on_lsp_work_end(
4848 language_server.server_id(),
4849 ProgressToken::Number(id),
4850 cx,
4851 );
4852 })
4853 })
4854 .log_err();
4855 }))
4856 } else {
4857 None
4858 };
4859
4860 let result = lsp_request.await.into_response();
4861
4862 let response = result.map_err(|err| {
4863 let message = format!(
4864 "{} via {} failed: {}",
4865 request.display_name(),
4866 language_server.name(),
4867 err
4868 );
4869 // rust-analyzer likes to error with this when its still loading up
4870 if !message.ends_with("content modified") {
4871 log::warn!("{message}");
4872 }
4873 anyhow::anyhow!(message)
4874 })?;
4875
4876 request
4877 .response_from_lsp(
4878 response,
4879 this.upgrade().context("no app context")?,
4880 buffer,
4881 language_server.server_id(),
4882 cx.clone(),
4883 )
4884 .await
4885 })
4886 }
4887
4888 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
4889 let mut language_formatters_to_check = Vec::new();
4890 for buffer in self.buffer_store.read(cx).buffers() {
4891 let buffer = buffer.read(cx);
4892 let buffer_file = File::from_dyn(buffer.file());
4893 let buffer_language = buffer.language();
4894 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
4895 if buffer_language.is_some() {
4896 language_formatters_to_check.push((
4897 buffer_file.map(|f| f.worktree_id(cx)),
4898 settings.into_owned(),
4899 ));
4900 }
4901 }
4902
4903 self.request_workspace_config_refresh();
4904
4905 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
4906 prettier_store.update(cx, |prettier_store, cx| {
4907 prettier_store.on_settings_changed(language_formatters_to_check, cx)
4908 })
4909 }
4910
4911 cx.notify();
4912 }
4913
4914 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
4915 let buffer_store = self.buffer_store.clone();
4916 let Some(local) = self.as_local_mut() else {
4917 return;
4918 };
4919 let mut adapters = BTreeMap::default();
4920 let get_adapter = {
4921 let languages = local.languages.clone();
4922 let environment = local.environment.clone();
4923 let weak = local.weak.clone();
4924 let worktree_store = local.worktree_store.clone();
4925 let http_client = local.http_client.clone();
4926 let fs = local.fs.clone();
4927 move |worktree_id, cx: &mut App| {
4928 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
4929 Some(LocalLspAdapterDelegate::new(
4930 languages.clone(),
4931 &environment,
4932 weak.clone(),
4933 &worktree,
4934 http_client.clone(),
4935 fs.clone(),
4936 cx,
4937 ))
4938 }
4939 };
4940
4941 let mut messages_to_report = Vec::new();
4942 let (new_tree, to_stop) = {
4943 let mut rebase = local.lsp_tree.rebase();
4944 let buffers = buffer_store
4945 .read(cx)
4946 .buffers()
4947 .filter_map(|buffer| {
4948 let raw_buffer = buffer.read(cx);
4949 if !local
4950 .registered_buffers
4951 .contains_key(&raw_buffer.remote_id())
4952 {
4953 return None;
4954 }
4955 let file = File::from_dyn(raw_buffer.file()).cloned()?;
4956 let language = raw_buffer.language().cloned()?;
4957 Some((file, language, raw_buffer.remote_id()))
4958 })
4959 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
4960 for (file, language, buffer_id) in buffers {
4961 let worktree_id = file.worktree_id(cx);
4962 let Some(worktree) = local
4963 .worktree_store
4964 .read(cx)
4965 .worktree_for_id(worktree_id, cx)
4966 else {
4967 continue;
4968 };
4969
4970 if let Some((_, apply)) = local.reuse_existing_language_server(
4971 rebase.server_tree(),
4972 &worktree,
4973 &language.name(),
4974 cx,
4975 ) {
4976 (apply)(rebase.server_tree());
4977 } else if let Some(lsp_delegate) = adapters
4978 .entry(worktree_id)
4979 .or_insert_with(|| get_adapter(worktree_id, cx))
4980 .clone()
4981 {
4982 let delegate =
4983 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
4984 let path = file
4985 .path()
4986 .parent()
4987 .map(Arc::from)
4988 .unwrap_or_else(|| file.path().clone());
4989 let worktree_path = ProjectPath { worktree_id, path };
4990 let abs_path = file.abs_path(cx);
4991 let nodes = rebase
4992 .walk(
4993 worktree_path,
4994 language.name(),
4995 language.manifest(),
4996 delegate.clone(),
4997 cx,
4998 )
4999 .collect::<Vec<_>>();
5000 for node in nodes {
5001 let server_id = node.server_id_or_init(|disposition| {
5002 let path = &disposition.path;
5003 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5004 let key = LanguageServerSeed {
5005 worktree_id,
5006 name: disposition.server_name.clone(),
5007 settings: disposition.settings.clone(),
5008 toolchain: local.toolchain_store.read(cx).active_toolchain(
5009 path.worktree_id,
5010 &path.path,
5011 language.name(),
5012 ),
5013 };
5014 local.language_server_ids.remove(&key);
5015
5016 let server_id = local.get_or_insert_language_server(
5017 &worktree,
5018 lsp_delegate.clone(),
5019 disposition,
5020 &language.name(),
5021 cx,
5022 );
5023 if let Some(state) = local.language_servers.get(&server_id)
5024 && let Ok(uri) = uri
5025 {
5026 state.add_workspace_folder(uri);
5027 };
5028 server_id
5029 });
5030
5031 if let Some(language_server_id) = server_id {
5032 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5033 language_server_id,
5034 name: node.name(),
5035 message:
5036 proto::update_language_server::Variant::RegisteredForBuffer(
5037 proto::RegisteredForBuffer {
5038 buffer_abs_path: abs_path
5039 .to_string_lossy()
5040 .into_owned(),
5041 buffer_id: buffer_id.to_proto(),
5042 },
5043 ),
5044 });
5045 }
5046 }
5047 } else {
5048 continue;
5049 }
5050 }
5051 rebase.finish()
5052 };
5053 for message in messages_to_report {
5054 cx.emit(message);
5055 }
5056 local.lsp_tree = new_tree;
5057 for (id, _) in to_stop {
5058 self.stop_local_language_server(id, cx).detach();
5059 }
5060 }
5061
5062 pub fn apply_code_action(
5063 &self,
5064 buffer_handle: Entity<Buffer>,
5065 mut action: CodeAction,
5066 push_to_history: bool,
5067 cx: &mut Context<Self>,
5068 ) -> Task<Result<ProjectTransaction>> {
5069 if let Some((upstream_client, project_id)) = self.upstream_client() {
5070 let request = proto::ApplyCodeAction {
5071 project_id,
5072 buffer_id: buffer_handle.read(cx).remote_id().into(),
5073 action: Some(Self::serialize_code_action(&action)),
5074 };
5075 let buffer_store = self.buffer_store();
5076 cx.spawn(async move |_, cx| {
5077 let response = upstream_client
5078 .request(request)
5079 .await?
5080 .transaction
5081 .context("missing transaction")?;
5082
5083 buffer_store
5084 .update(cx, |buffer_store, cx| {
5085 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5086 })
5087 .await
5088 })
5089 } else if self.mode.is_local() {
5090 let Some((_, lang_server)) = buffer_handle.update(cx, |buffer, cx| {
5091 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5092 .map(|(adapter, server)| (adapter.clone(), server.clone()))
5093 }) else {
5094 return Task::ready(Ok(ProjectTransaction::default()));
5095 };
5096 cx.spawn(async move |this, cx| {
5097 LocalLspStore::try_resolve_code_action(&lang_server, &mut action)
5098 .await
5099 .context("resolving a code action")?;
5100 if let Some(edit) = action.lsp_action.edit()
5101 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5102 return LocalLspStore::deserialize_workspace_edit(
5103 this.upgrade().context("no app present")?,
5104 edit.clone(),
5105 push_to_history,
5106
5107 lang_server.clone(),
5108 cx,
5109 )
5110 .await;
5111 }
5112
5113 if let Some(command) = action.lsp_action.command() {
5114 let server_capabilities = lang_server.capabilities();
5115 let available_commands = server_capabilities
5116 .execute_command_provider
5117 .as_ref()
5118 .map(|options| options.commands.as_slice())
5119 .unwrap_or_default();
5120 if available_commands.contains(&command.command) {
5121 this.update(cx, |this, _| {
5122 this.as_local_mut()
5123 .unwrap()
5124 .last_workspace_edits_by_language_server
5125 .remove(&lang_server.server_id());
5126 })?;
5127
5128 let _result = lang_server
5129 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5130 command: command.command.clone(),
5131 arguments: command.arguments.clone().unwrap_or_default(),
5132 ..lsp::ExecuteCommandParams::default()
5133 })
5134 .await.into_response()
5135 .context("execute command")?;
5136
5137 return this.update(cx, |this, _| {
5138 this.as_local_mut()
5139 .unwrap()
5140 .last_workspace_edits_by_language_server
5141 .remove(&lang_server.server_id())
5142 .unwrap_or_default()
5143 });
5144 } else {
5145 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5146 }
5147 }
5148
5149 Ok(ProjectTransaction::default())
5150 })
5151 } else {
5152 Task::ready(Err(anyhow!("no upstream client and not local")))
5153 }
5154 }
5155
5156 pub fn apply_code_action_kind(
5157 &mut self,
5158 buffers: HashSet<Entity<Buffer>>,
5159 kind: CodeActionKind,
5160 push_to_history: bool,
5161 cx: &mut Context<Self>,
5162 ) -> Task<anyhow::Result<ProjectTransaction>> {
5163 if self.as_local().is_some() {
5164 cx.spawn(async move |lsp_store, cx| {
5165 let buffers = buffers.into_iter().collect::<Vec<_>>();
5166 let result = LocalLspStore::execute_code_action_kind_locally(
5167 lsp_store.clone(),
5168 buffers,
5169 kind,
5170 push_to_history,
5171 cx,
5172 )
5173 .await;
5174 lsp_store.update(cx, |lsp_store, _| {
5175 lsp_store.update_last_formatting_failure(&result);
5176 })?;
5177 result
5178 })
5179 } else if let Some((client, project_id)) = self.upstream_client() {
5180 let buffer_store = self.buffer_store();
5181 cx.spawn(async move |lsp_store, cx| {
5182 let result = client
5183 .request(proto::ApplyCodeActionKind {
5184 project_id,
5185 kind: kind.as_str().to_owned(),
5186 buffer_ids: buffers
5187 .iter()
5188 .map(|buffer| {
5189 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5190 })
5191 .collect(),
5192 })
5193 .await
5194 .and_then(|result| result.transaction.context("missing transaction"));
5195 lsp_store.update(cx, |lsp_store, _| {
5196 lsp_store.update_last_formatting_failure(&result);
5197 })?;
5198
5199 let transaction_response = result?;
5200 buffer_store
5201 .update(cx, |buffer_store, cx| {
5202 buffer_store.deserialize_project_transaction(
5203 transaction_response,
5204 push_to_history,
5205 cx,
5206 )
5207 })
5208 .await
5209 })
5210 } else {
5211 Task::ready(Ok(ProjectTransaction::default()))
5212 }
5213 }
5214
5215 pub fn resolved_hint(
5216 &mut self,
5217 buffer_id: BufferId,
5218 id: InlayId,
5219 cx: &mut Context<Self>,
5220 ) -> Option<ResolvedHint> {
5221 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5222
5223 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5224 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5225 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5226 let (server_id, resolve_data) = match &hint.resolve_state {
5227 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5228 ResolveState::Resolving => {
5229 return Some(ResolvedHint::Resolving(
5230 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5231 ));
5232 }
5233 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5234 };
5235
5236 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5237 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5238 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5239 id,
5240 cx.spawn(async move |lsp_store, cx| {
5241 let resolved_hint = resolve_task.await;
5242 lsp_store
5243 .update(cx, |lsp_store, _| {
5244 if let Some(old_inlay_hint) = lsp_store
5245 .lsp_data
5246 .get_mut(&buffer_id)
5247 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5248 {
5249 match resolved_hint {
5250 Ok(resolved_hint) => {
5251 *old_inlay_hint = resolved_hint;
5252 }
5253 Err(e) => {
5254 old_inlay_hint.resolve_state =
5255 ResolveState::CanResolve(server_id, resolve_data);
5256 log::error!("Inlay hint resolve failed: {e:#}");
5257 }
5258 }
5259 }
5260 })
5261 .ok();
5262 })
5263 .shared(),
5264 );
5265 debug_assert!(
5266 previous_task.is_none(),
5267 "Did not change hint's resolve state after spawning its resolve"
5268 );
5269 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5270 None
5271 }
5272
5273 fn resolve_inlay_hint(
5274 &self,
5275 mut hint: InlayHint,
5276 buffer: Entity<Buffer>,
5277 server_id: LanguageServerId,
5278 cx: &mut Context<Self>,
5279 ) -> Task<anyhow::Result<InlayHint>> {
5280 if let Some((upstream_client, project_id)) = self.upstream_client() {
5281 if !self.check_if_capable_for_proto_request(&buffer, InlayHints::can_resolve_inlays, cx)
5282 {
5283 hint.resolve_state = ResolveState::Resolved;
5284 return Task::ready(Ok(hint));
5285 }
5286 let request = proto::ResolveInlayHint {
5287 project_id,
5288 buffer_id: buffer.read(cx).remote_id().into(),
5289 language_server_id: server_id.0 as u64,
5290 hint: Some(InlayHints::project_to_proto_hint(hint.clone())),
5291 };
5292 cx.background_spawn(async move {
5293 let response = upstream_client
5294 .request(request)
5295 .await
5296 .context("inlay hints proto request")?;
5297 match response.hint {
5298 Some(resolved_hint) => InlayHints::proto_to_project_hint(resolved_hint)
5299 .context("inlay hints proto resolve response conversion"),
5300 None => Ok(hint),
5301 }
5302 })
5303 } else {
5304 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5305 self.language_server_for_local_buffer(buffer, server_id, cx)
5306 .map(|(_, server)| server.clone())
5307 }) else {
5308 return Task::ready(Ok(hint));
5309 };
5310 if !InlayHints::can_resolve_inlays(&lang_server.capabilities()) {
5311 return Task::ready(Ok(hint));
5312 }
5313 let buffer_snapshot = buffer.read(cx).snapshot();
5314 cx.spawn(async move |_, cx| {
5315 let resolve_task = lang_server.request::<lsp::request::InlayHintResolveRequest>(
5316 InlayHints::project_to_lsp_hint(hint, &buffer_snapshot),
5317 );
5318 let resolved_hint = resolve_task
5319 .await
5320 .into_response()
5321 .context("inlay hint resolve LSP request")?;
5322 let resolved_hint = InlayHints::lsp_to_project_hint(
5323 resolved_hint,
5324 &buffer,
5325 server_id,
5326 ResolveState::Resolved,
5327 false,
5328 cx,
5329 )
5330 .await?;
5331 Ok(resolved_hint)
5332 })
5333 }
5334 }
5335
5336 pub fn resolve_color_presentation(
5337 &mut self,
5338 mut color: DocumentColor,
5339 buffer: Entity<Buffer>,
5340 server_id: LanguageServerId,
5341 cx: &mut Context<Self>,
5342 ) -> Task<Result<DocumentColor>> {
5343 if color.resolved {
5344 return Task::ready(Ok(color));
5345 }
5346
5347 if let Some((upstream_client, project_id)) = self.upstream_client() {
5348 let start = color.lsp_range.start;
5349 let end = color.lsp_range.end;
5350 let request = proto::GetColorPresentation {
5351 project_id,
5352 server_id: server_id.to_proto(),
5353 buffer_id: buffer.read(cx).remote_id().into(),
5354 color: Some(proto::ColorInformation {
5355 red: color.color.red,
5356 green: color.color.green,
5357 blue: color.color.blue,
5358 alpha: color.color.alpha,
5359 lsp_range_start: Some(proto::PointUtf16 {
5360 row: start.line,
5361 column: start.character,
5362 }),
5363 lsp_range_end: Some(proto::PointUtf16 {
5364 row: end.line,
5365 column: end.character,
5366 }),
5367 }),
5368 };
5369 cx.background_spawn(async move {
5370 let response = upstream_client
5371 .request(request)
5372 .await
5373 .context("color presentation proto request")?;
5374 color.resolved = true;
5375 color.color_presentations = response
5376 .presentations
5377 .into_iter()
5378 .map(|presentation| ColorPresentation {
5379 label: SharedString::from(presentation.label),
5380 text_edit: presentation.text_edit.and_then(deserialize_lsp_edit),
5381 additional_text_edits: presentation
5382 .additional_text_edits
5383 .into_iter()
5384 .filter_map(deserialize_lsp_edit)
5385 .collect(),
5386 })
5387 .collect();
5388 Ok(color)
5389 })
5390 } else {
5391 let path = match buffer
5392 .update(cx, |buffer, cx| {
5393 Some(File::from_dyn(buffer.file())?.abs_path(cx))
5394 })
5395 .context("buffer with the missing path")
5396 {
5397 Ok(path) => path,
5398 Err(e) => return Task::ready(Err(e)),
5399 };
5400 let Some(lang_server) = buffer.update(cx, |buffer, cx| {
5401 self.language_server_for_local_buffer(buffer, server_id, cx)
5402 .map(|(_, server)| server.clone())
5403 }) else {
5404 return Task::ready(Ok(color));
5405 };
5406 cx.background_spawn(async move {
5407 let resolve_task = lang_server.request::<lsp::request::ColorPresentationRequest>(
5408 lsp::ColorPresentationParams {
5409 text_document: make_text_document_identifier(&path)?,
5410 color: color.color,
5411 range: color.lsp_range,
5412 work_done_progress_params: Default::default(),
5413 partial_result_params: Default::default(),
5414 },
5415 );
5416 color.color_presentations = resolve_task
5417 .await
5418 .into_response()
5419 .context("color presentation resolve LSP request")?
5420 .into_iter()
5421 .map(|presentation| ColorPresentation {
5422 label: SharedString::from(presentation.label),
5423 text_edit: presentation.text_edit,
5424 additional_text_edits: presentation
5425 .additional_text_edits
5426 .unwrap_or_default(),
5427 })
5428 .collect();
5429 color.resolved = true;
5430 Ok(color)
5431 })
5432 }
5433 }
5434
5435 pub(crate) fn linked_edits(
5436 &mut self,
5437 buffer: &Entity<Buffer>,
5438 position: Anchor,
5439 cx: &mut Context<Self>,
5440 ) -> Task<Result<Vec<Range<Anchor>>>> {
5441 let snapshot = buffer.read(cx).snapshot();
5442 let scope = snapshot.language_scope_at(position);
5443 let Some(server_id) = self
5444 .as_local()
5445 .and_then(|local| {
5446 buffer.update(cx, |buffer, cx| {
5447 local
5448 .language_servers_for_buffer(buffer, cx)
5449 .filter(|(_, server)| {
5450 LinkedEditingRange::check_server_capabilities(server.capabilities())
5451 })
5452 .filter(|(adapter, _)| {
5453 scope
5454 .as_ref()
5455 .map(|scope| scope.language_allowed(&adapter.name))
5456 .unwrap_or(true)
5457 })
5458 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5459 .next()
5460 })
5461 })
5462 .or_else(|| {
5463 self.upstream_client()
5464 .is_some()
5465 .then_some(LanguageServerToQuery::FirstCapable)
5466 })
5467 .filter(|_| {
5468 maybe!({
5469 let language = buffer.read(cx).language_at(position)?;
5470 Some(
5471 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5472 .linked_edits,
5473 )
5474 }) == Some(true)
5475 })
5476 else {
5477 return Task::ready(Ok(Vec::new()));
5478 };
5479
5480 self.request_lsp(
5481 buffer.clone(),
5482 server_id,
5483 LinkedEditingRange { position },
5484 cx,
5485 )
5486 }
5487
5488 fn apply_on_type_formatting(
5489 &mut self,
5490 buffer: Entity<Buffer>,
5491 position: Anchor,
5492 trigger: String,
5493 cx: &mut Context<Self>,
5494 ) -> Task<Result<Option<Transaction>>> {
5495 if let Some((client, project_id)) = self.upstream_client() {
5496 if !self.check_if_capable_for_proto_request(
5497 &buffer,
5498 |capabilities| {
5499 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5500 },
5501 cx,
5502 ) {
5503 return Task::ready(Ok(None));
5504 }
5505 let request = proto::OnTypeFormatting {
5506 project_id,
5507 buffer_id: buffer.read(cx).remote_id().into(),
5508 position: Some(serialize_anchor(&position)),
5509 trigger,
5510 version: serialize_version(&buffer.read(cx).version()),
5511 };
5512 cx.background_spawn(async move {
5513 client
5514 .request(request)
5515 .await?
5516 .transaction
5517 .map(language::proto::deserialize_transaction)
5518 .transpose()
5519 })
5520 } else if let Some(local) = self.as_local_mut() {
5521 let buffer_id = buffer.read(cx).remote_id();
5522 local.buffers_being_formatted.insert(buffer_id);
5523 cx.spawn(async move |this, cx| {
5524 let _cleanup = defer({
5525 let this = this.clone();
5526 let mut cx = cx.clone();
5527 move || {
5528 this.update(&mut cx, |this, _| {
5529 if let Some(local) = this.as_local_mut() {
5530 local.buffers_being_formatted.remove(&buffer_id);
5531 }
5532 })
5533 .ok();
5534 }
5535 });
5536
5537 buffer
5538 .update(cx, |buffer, _| {
5539 buffer.wait_for_edits(Some(position.timestamp))
5540 })
5541 .await?;
5542 this.update(cx, |this, cx| {
5543 let position = position.to_point_utf16(buffer.read(cx));
5544 this.on_type_format(buffer, position, trigger, false, cx)
5545 })?
5546 .await
5547 })
5548 } else {
5549 Task::ready(Err(anyhow!("No upstream client or local language server")))
5550 }
5551 }
5552
5553 pub fn on_type_format<T: ToPointUtf16>(
5554 &mut self,
5555 buffer: Entity<Buffer>,
5556 position: T,
5557 trigger: String,
5558 push_to_history: bool,
5559 cx: &mut Context<Self>,
5560 ) -> Task<Result<Option<Transaction>>> {
5561 let position = position.to_point_utf16(buffer.read(cx));
5562 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5563 }
5564
5565 fn on_type_format_impl(
5566 &mut self,
5567 buffer: Entity<Buffer>,
5568 position: PointUtf16,
5569 trigger: String,
5570 push_to_history: bool,
5571 cx: &mut Context<Self>,
5572 ) -> Task<Result<Option<Transaction>>> {
5573 let options = buffer.update(cx, |buffer, cx| {
5574 lsp_command::lsp_formatting_options(
5575 language_settings(
5576 buffer.language_at(position).map(|l| l.name()),
5577 buffer.file(),
5578 cx,
5579 )
5580 .as_ref(),
5581 )
5582 });
5583
5584 cx.spawn(async move |this, cx| {
5585 if let Some(waiter) =
5586 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5587 {
5588 waiter.await?;
5589 }
5590 cx.update(|cx| {
5591 this.update(cx, |this, cx| {
5592 this.request_lsp(
5593 buffer.clone(),
5594 LanguageServerToQuery::FirstCapable,
5595 OnTypeFormatting {
5596 position,
5597 trigger,
5598 options,
5599 push_to_history,
5600 },
5601 cx,
5602 )
5603 })
5604 })?
5605 .await
5606 })
5607 }
5608
5609 pub fn definitions(
5610 &mut self,
5611 buffer: &Entity<Buffer>,
5612 position: PointUtf16,
5613 cx: &mut Context<Self>,
5614 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5615 if let Some((upstream_client, project_id)) = self.upstream_client() {
5616 let request = GetDefinitions { position };
5617 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5618 return Task::ready(Ok(None));
5619 }
5620 let request_task = upstream_client.request_lsp(
5621 project_id,
5622 None,
5623 LSP_REQUEST_TIMEOUT,
5624 cx.background_executor().clone(),
5625 request.to_proto(project_id, buffer.read(cx)),
5626 );
5627 let buffer = buffer.clone();
5628 cx.spawn(async move |weak_lsp_store, cx| {
5629 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5630 return Ok(None);
5631 };
5632 let Some(responses) = request_task.await? else {
5633 return Ok(None);
5634 };
5635 let actions = join_all(responses.payload.into_iter().map(|response| {
5636 GetDefinitions { position }.response_from_proto(
5637 response.response,
5638 lsp_store.clone(),
5639 buffer.clone(),
5640 cx.clone(),
5641 )
5642 }))
5643 .await;
5644
5645 Ok(Some(
5646 actions
5647 .into_iter()
5648 .collect::<Result<Vec<Vec<_>>>>()?
5649 .into_iter()
5650 .flatten()
5651 .dedup()
5652 .collect(),
5653 ))
5654 })
5655 } else {
5656 let definitions_task = self.request_multiple_lsp_locally(
5657 buffer,
5658 Some(position),
5659 GetDefinitions { position },
5660 cx,
5661 );
5662 cx.background_spawn(async move {
5663 Ok(Some(
5664 definitions_task
5665 .await
5666 .into_iter()
5667 .flat_map(|(_, definitions)| definitions)
5668 .dedup()
5669 .collect(),
5670 ))
5671 })
5672 }
5673 }
5674
5675 pub fn declarations(
5676 &mut self,
5677 buffer: &Entity<Buffer>,
5678 position: PointUtf16,
5679 cx: &mut Context<Self>,
5680 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5681 if let Some((upstream_client, project_id)) = self.upstream_client() {
5682 let request = GetDeclarations { position };
5683 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5684 return Task::ready(Ok(None));
5685 }
5686 let request_task = upstream_client.request_lsp(
5687 project_id,
5688 None,
5689 LSP_REQUEST_TIMEOUT,
5690 cx.background_executor().clone(),
5691 request.to_proto(project_id, buffer.read(cx)),
5692 );
5693 let buffer = buffer.clone();
5694 cx.spawn(async move |weak_lsp_store, cx| {
5695 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5696 return Ok(None);
5697 };
5698 let Some(responses) = request_task.await? else {
5699 return Ok(None);
5700 };
5701 let actions = join_all(responses.payload.into_iter().map(|response| {
5702 GetDeclarations { position }.response_from_proto(
5703 response.response,
5704 lsp_store.clone(),
5705 buffer.clone(),
5706 cx.clone(),
5707 )
5708 }))
5709 .await;
5710
5711 Ok(Some(
5712 actions
5713 .into_iter()
5714 .collect::<Result<Vec<Vec<_>>>>()?
5715 .into_iter()
5716 .flatten()
5717 .dedup()
5718 .collect(),
5719 ))
5720 })
5721 } else {
5722 let declarations_task = self.request_multiple_lsp_locally(
5723 buffer,
5724 Some(position),
5725 GetDeclarations { position },
5726 cx,
5727 );
5728 cx.background_spawn(async move {
5729 Ok(Some(
5730 declarations_task
5731 .await
5732 .into_iter()
5733 .flat_map(|(_, declarations)| declarations)
5734 .dedup()
5735 .collect(),
5736 ))
5737 })
5738 }
5739 }
5740
5741 pub fn type_definitions(
5742 &mut self,
5743 buffer: &Entity<Buffer>,
5744 position: PointUtf16,
5745 cx: &mut Context<Self>,
5746 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5747 if let Some((upstream_client, project_id)) = self.upstream_client() {
5748 let request = GetTypeDefinitions { position };
5749 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5750 return Task::ready(Ok(None));
5751 }
5752 let request_task = upstream_client.request_lsp(
5753 project_id,
5754 None,
5755 LSP_REQUEST_TIMEOUT,
5756 cx.background_executor().clone(),
5757 request.to_proto(project_id, buffer.read(cx)),
5758 );
5759 let buffer = buffer.clone();
5760 cx.spawn(async move |weak_lsp_store, cx| {
5761 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5762 return Ok(None);
5763 };
5764 let Some(responses) = request_task.await? else {
5765 return Ok(None);
5766 };
5767 let actions = join_all(responses.payload.into_iter().map(|response| {
5768 GetTypeDefinitions { position }.response_from_proto(
5769 response.response,
5770 lsp_store.clone(),
5771 buffer.clone(),
5772 cx.clone(),
5773 )
5774 }))
5775 .await;
5776
5777 Ok(Some(
5778 actions
5779 .into_iter()
5780 .collect::<Result<Vec<Vec<_>>>>()?
5781 .into_iter()
5782 .flatten()
5783 .dedup()
5784 .collect(),
5785 ))
5786 })
5787 } else {
5788 let type_definitions_task = self.request_multiple_lsp_locally(
5789 buffer,
5790 Some(position),
5791 GetTypeDefinitions { position },
5792 cx,
5793 );
5794 cx.background_spawn(async move {
5795 Ok(Some(
5796 type_definitions_task
5797 .await
5798 .into_iter()
5799 .flat_map(|(_, type_definitions)| type_definitions)
5800 .dedup()
5801 .collect(),
5802 ))
5803 })
5804 }
5805 }
5806
5807 pub fn implementations(
5808 &mut self,
5809 buffer: &Entity<Buffer>,
5810 position: PointUtf16,
5811 cx: &mut Context<Self>,
5812 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5813 if let Some((upstream_client, project_id)) = self.upstream_client() {
5814 let request = GetImplementations { position };
5815 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5816 return Task::ready(Ok(None));
5817 }
5818 let request_task = upstream_client.request_lsp(
5819 project_id,
5820 None,
5821 LSP_REQUEST_TIMEOUT,
5822 cx.background_executor().clone(),
5823 request.to_proto(project_id, buffer.read(cx)),
5824 );
5825 let buffer = buffer.clone();
5826 cx.spawn(async move |weak_lsp_store, cx| {
5827 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5828 return Ok(None);
5829 };
5830 let Some(responses) = request_task.await? else {
5831 return Ok(None);
5832 };
5833 let actions = join_all(responses.payload.into_iter().map(|response| {
5834 GetImplementations { position }.response_from_proto(
5835 response.response,
5836 lsp_store.clone(),
5837 buffer.clone(),
5838 cx.clone(),
5839 )
5840 }))
5841 .await;
5842
5843 Ok(Some(
5844 actions
5845 .into_iter()
5846 .collect::<Result<Vec<Vec<_>>>>()?
5847 .into_iter()
5848 .flatten()
5849 .dedup()
5850 .collect(),
5851 ))
5852 })
5853 } else {
5854 let implementations_task = self.request_multiple_lsp_locally(
5855 buffer,
5856 Some(position),
5857 GetImplementations { position },
5858 cx,
5859 );
5860 cx.background_spawn(async move {
5861 Ok(Some(
5862 implementations_task
5863 .await
5864 .into_iter()
5865 .flat_map(|(_, implementations)| implementations)
5866 .dedup()
5867 .collect(),
5868 ))
5869 })
5870 }
5871 }
5872
5873 pub fn references(
5874 &mut self,
5875 buffer: &Entity<Buffer>,
5876 position: PointUtf16,
5877 cx: &mut Context<Self>,
5878 ) -> Task<Result<Option<Vec<Location>>>> {
5879 if let Some((upstream_client, project_id)) = self.upstream_client() {
5880 let request = GetReferences { position };
5881 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5882 return Task::ready(Ok(None));
5883 }
5884
5885 let request_task = upstream_client.request_lsp(
5886 project_id,
5887 None,
5888 LSP_REQUEST_TIMEOUT,
5889 cx.background_executor().clone(),
5890 request.to_proto(project_id, buffer.read(cx)),
5891 );
5892 let buffer = buffer.clone();
5893 cx.spawn(async move |weak_lsp_store, cx| {
5894 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5895 return Ok(None);
5896 };
5897 let Some(responses) = request_task.await? else {
5898 return Ok(None);
5899 };
5900
5901 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5902 GetReferences { position }.response_from_proto(
5903 lsp_response.response,
5904 lsp_store.clone(),
5905 buffer.clone(),
5906 cx.clone(),
5907 )
5908 }))
5909 .await
5910 .into_iter()
5911 .collect::<Result<Vec<Vec<_>>>>()?
5912 .into_iter()
5913 .flatten()
5914 .dedup()
5915 .collect();
5916 Ok(Some(locations))
5917 })
5918 } else {
5919 let references_task = self.request_multiple_lsp_locally(
5920 buffer,
5921 Some(position),
5922 GetReferences { position },
5923 cx,
5924 );
5925 cx.background_spawn(async move {
5926 Ok(Some(
5927 references_task
5928 .await
5929 .into_iter()
5930 .flat_map(|(_, references)| references)
5931 .dedup()
5932 .collect(),
5933 ))
5934 })
5935 }
5936 }
5937
5938 pub fn code_actions(
5939 &mut self,
5940 buffer: &Entity<Buffer>,
5941 range: Range<Anchor>,
5942 kinds: Option<Vec<CodeActionKind>>,
5943 cx: &mut Context<Self>,
5944 ) -> Task<Result<Option<Vec<CodeAction>>>> {
5945 if let Some((upstream_client, project_id)) = self.upstream_client() {
5946 let request = GetCodeActions {
5947 range: range.clone(),
5948 kinds: kinds.clone(),
5949 };
5950 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5951 return Task::ready(Ok(None));
5952 }
5953 let request_task = upstream_client.request_lsp(
5954 project_id,
5955 None,
5956 LSP_REQUEST_TIMEOUT,
5957 cx.background_executor().clone(),
5958 request.to_proto(project_id, buffer.read(cx)),
5959 );
5960 let buffer = buffer.clone();
5961 cx.spawn(async move |weak_lsp_store, cx| {
5962 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5963 return Ok(None);
5964 };
5965 let Some(responses) = request_task.await? else {
5966 return Ok(None);
5967 };
5968 let actions = join_all(responses.payload.into_iter().map(|response| {
5969 GetCodeActions {
5970 range: range.clone(),
5971 kinds: kinds.clone(),
5972 }
5973 .response_from_proto(
5974 response.response,
5975 lsp_store.clone(),
5976 buffer.clone(),
5977 cx.clone(),
5978 )
5979 }))
5980 .await;
5981
5982 Ok(Some(
5983 actions
5984 .into_iter()
5985 .collect::<Result<Vec<Vec<_>>>>()?
5986 .into_iter()
5987 .flatten()
5988 .collect(),
5989 ))
5990 })
5991 } else {
5992 let all_actions_task = self.request_multiple_lsp_locally(
5993 buffer,
5994 Some(range.start),
5995 GetCodeActions { range, kinds },
5996 cx,
5997 );
5998 cx.background_spawn(async move {
5999 Ok(Some(
6000 all_actions_task
6001 .await
6002 .into_iter()
6003 .flat_map(|(_, actions)| actions)
6004 .collect(),
6005 ))
6006 })
6007 }
6008 }
6009
6010 pub fn code_lens_actions(
6011 &mut self,
6012 buffer: &Entity<Buffer>,
6013 cx: &mut Context<Self>,
6014 ) -> CodeLensTask {
6015 let version_queried_for = buffer.read(cx).version();
6016 let buffer_id = buffer.read(cx).remote_id();
6017 let existing_servers = self.as_local().map(|local| {
6018 local
6019 .buffers_opened_in_servers
6020 .get(&buffer_id)
6021 .cloned()
6022 .unwrap_or_default()
6023 });
6024
6025 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
6026 if let Some(cached_lens) = &lsp_data.code_lens {
6027 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
6028 let has_different_servers = existing_servers.is_some_and(|existing_servers| {
6029 existing_servers != cached_lens.lens.keys().copied().collect()
6030 });
6031 if !has_different_servers {
6032 return Task::ready(Ok(Some(
6033 cached_lens.lens.values().flatten().cloned().collect(),
6034 )))
6035 .shared();
6036 }
6037 } else if let Some((updating_for, running_update)) = cached_lens.update.as_ref() {
6038 if !version_queried_for.changed_since(updating_for) {
6039 return running_update.clone();
6040 }
6041 }
6042 }
6043 }
6044
6045 let lens_lsp_data = self
6046 .latest_lsp_data(buffer, cx)
6047 .code_lens
6048 .get_or_insert_default();
6049 let buffer = buffer.clone();
6050 let query_version_queried_for = version_queried_for.clone();
6051 let new_task = cx
6052 .spawn(async move |lsp_store, cx| {
6053 cx.background_executor()
6054 .timer(Duration::from_millis(30))
6055 .await;
6056 let fetched_lens = lsp_store
6057 .update(cx, |lsp_store, cx| lsp_store.fetch_code_lens(&buffer, cx))
6058 .map_err(Arc::new)?
6059 .await
6060 .context("fetching code lens")
6061 .map_err(Arc::new);
6062 let fetched_lens = match fetched_lens {
6063 Ok(fetched_lens) => fetched_lens,
6064 Err(e) => {
6065 lsp_store
6066 .update(cx, |lsp_store, _| {
6067 if let Some(lens_lsp_data) = lsp_store
6068 .lsp_data
6069 .get_mut(&buffer_id)
6070 .and_then(|lsp_data| lsp_data.code_lens.as_mut())
6071 {
6072 lens_lsp_data.update = None;
6073 }
6074 })
6075 .ok();
6076 return Err(e);
6077 }
6078 };
6079
6080 lsp_store
6081 .update(cx, |lsp_store, _| {
6082 let lsp_data = lsp_store.current_lsp_data(buffer_id)?;
6083 let code_lens = lsp_data.code_lens.as_mut()?;
6084 if let Some(fetched_lens) = fetched_lens {
6085 if lsp_data.buffer_version == query_version_queried_for {
6086 code_lens.lens.extend(fetched_lens);
6087 } else if !lsp_data
6088 .buffer_version
6089 .changed_since(&query_version_queried_for)
6090 {
6091 lsp_data.buffer_version = query_version_queried_for;
6092 code_lens.lens = fetched_lens;
6093 }
6094 }
6095 code_lens.update = None;
6096 Some(code_lens.lens.values().flatten().cloned().collect())
6097 })
6098 .map_err(Arc::new)
6099 })
6100 .shared();
6101 lens_lsp_data.update = Some((version_queried_for, new_task.clone()));
6102 new_task
6103 }
6104
6105 fn fetch_code_lens(
6106 &mut self,
6107 buffer: &Entity<Buffer>,
6108 cx: &mut Context<Self>,
6109 ) -> Task<Result<Option<HashMap<LanguageServerId, Vec<CodeAction>>>>> {
6110 if let Some((upstream_client, project_id)) = self.upstream_client() {
6111 let request = GetCodeLens;
6112 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6113 return Task::ready(Ok(None));
6114 }
6115 let request_task = upstream_client.request_lsp(
6116 project_id,
6117 None,
6118 LSP_REQUEST_TIMEOUT,
6119 cx.background_executor().clone(),
6120 request.to_proto(project_id, buffer.read(cx)),
6121 );
6122 let buffer = buffer.clone();
6123 cx.spawn(async move |weak_lsp_store, cx| {
6124 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6125 return Ok(None);
6126 };
6127 let Some(responses) = request_task.await? else {
6128 return Ok(None);
6129 };
6130
6131 let code_lens_actions = join_all(responses.payload.into_iter().map(|response| {
6132 let lsp_store = lsp_store.clone();
6133 let buffer = buffer.clone();
6134 let cx = cx.clone();
6135 async move {
6136 (
6137 LanguageServerId::from_proto(response.server_id),
6138 GetCodeLens
6139 .response_from_proto(response.response, lsp_store, buffer, cx)
6140 .await,
6141 )
6142 }
6143 }))
6144 .await;
6145
6146 let mut has_errors = false;
6147 let code_lens_actions = code_lens_actions
6148 .into_iter()
6149 .filter_map(|(server_id, code_lens)| match code_lens {
6150 Ok(code_lens) => Some((server_id, code_lens)),
6151 Err(e) => {
6152 has_errors = true;
6153 log::error!("{e:#}");
6154 None
6155 }
6156 })
6157 .collect::<HashMap<_, _>>();
6158 anyhow::ensure!(
6159 !has_errors || !code_lens_actions.is_empty(),
6160 "Failed to fetch code lens"
6161 );
6162 Ok(Some(code_lens_actions))
6163 })
6164 } else {
6165 let code_lens_actions_task =
6166 self.request_multiple_lsp_locally(buffer, None::<usize>, GetCodeLens, cx);
6167 cx.background_spawn(async move {
6168 Ok(Some(code_lens_actions_task.await.into_iter().collect()))
6169 })
6170 }
6171 }
6172
6173 #[inline(never)]
6174 pub fn completions(
6175 &self,
6176 buffer: &Entity<Buffer>,
6177 position: PointUtf16,
6178 context: CompletionContext,
6179 cx: &mut Context<Self>,
6180 ) -> Task<Result<Vec<CompletionResponse>>> {
6181 let language_registry = self.languages.clone();
6182
6183 if let Some((upstream_client, project_id)) = self.upstream_client() {
6184 let snapshot = buffer.read(cx).snapshot();
6185 let offset = position.to_offset(&snapshot);
6186 let scope = snapshot.language_scope_at(offset);
6187 let capable_lsps = self.all_capable_for_proto_request(
6188 buffer,
6189 |server_name, capabilities| {
6190 capabilities.completion_provider.is_some()
6191 && scope
6192 .as_ref()
6193 .map(|scope| scope.language_allowed(server_name))
6194 .unwrap_or(true)
6195 },
6196 cx,
6197 );
6198 if capable_lsps.is_empty() {
6199 return Task::ready(Ok(Vec::new()));
6200 }
6201
6202 let language = buffer.read(cx).language().cloned();
6203
6204 // In the future, we should provide project guests with the names of LSP adapters,
6205 // so that they can use the correct LSP adapter when computing labels. For now,
6206 // guests just use the first LSP adapter associated with the buffer's language.
6207 let lsp_adapter = language.as_ref().and_then(|language| {
6208 language_registry
6209 .lsp_adapters(&language.name())
6210 .first()
6211 .cloned()
6212 });
6213
6214 let buffer = buffer.clone();
6215
6216 cx.spawn(async move |this, cx| {
6217 let requests = join_all(
6218 capable_lsps
6219 .into_iter()
6220 .map(|id| {
6221 let request = GetCompletions {
6222 position,
6223 context: context.clone(),
6224 server_id: Some(id),
6225 };
6226 let buffer = buffer.clone();
6227 let language = language.clone();
6228 let lsp_adapter = lsp_adapter.clone();
6229 let upstream_client = upstream_client.clone();
6230 let response = this
6231 .update(cx, |this, cx| {
6232 this.send_lsp_proto_request(
6233 buffer,
6234 upstream_client,
6235 project_id,
6236 request,
6237 cx,
6238 )
6239 })
6240 .log_err();
6241 async move {
6242 let response = response?.await.log_err()?;
6243
6244 let completions = populate_labels_for_completions(
6245 response.completions,
6246 language,
6247 lsp_adapter,
6248 )
6249 .await;
6250
6251 Some(CompletionResponse {
6252 completions,
6253 display_options: CompletionDisplayOptions::default(),
6254 is_incomplete: response.is_incomplete,
6255 })
6256 }
6257 })
6258 .collect::<Vec<_>>(),
6259 );
6260 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6261 })
6262 } else if let Some(local) = self.as_local() {
6263 let snapshot = buffer.read(cx).snapshot();
6264 let offset = position.to_offset(&snapshot);
6265 let scope = snapshot.language_scope_at(offset);
6266 let language = snapshot.language().cloned();
6267 let completion_settings = language_settings(
6268 language.as_ref().map(|language| language.name()),
6269 buffer.read(cx).file(),
6270 cx,
6271 )
6272 .completions
6273 .clone();
6274 if !completion_settings.lsp {
6275 return Task::ready(Ok(Vec::new()));
6276 }
6277
6278 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6279 local
6280 .language_servers_for_buffer(buffer, cx)
6281 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6282 .filter(|(adapter, _)| {
6283 scope
6284 .as_ref()
6285 .map(|scope| scope.language_allowed(&adapter.name))
6286 .unwrap_or(true)
6287 })
6288 .map(|(_, server)| server.server_id())
6289 .collect()
6290 });
6291
6292 let buffer = buffer.clone();
6293 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6294 let lsp_timeout = if lsp_timeout > 0 {
6295 Some(Duration::from_millis(lsp_timeout))
6296 } else {
6297 None
6298 };
6299 cx.spawn(async move |this, cx| {
6300 let mut tasks = Vec::with_capacity(server_ids.len());
6301 this.update(cx, |lsp_store, cx| {
6302 for server_id in server_ids {
6303 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6304 let lsp_timeout = lsp_timeout
6305 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6306 let mut timeout = cx.background_spawn(async move {
6307 match lsp_timeout {
6308 Some(lsp_timeout) => {
6309 lsp_timeout.await;
6310 true
6311 },
6312 None => false,
6313 }
6314 }).fuse();
6315 let mut lsp_request = lsp_store.request_lsp(
6316 buffer.clone(),
6317 LanguageServerToQuery::Other(server_id),
6318 GetCompletions {
6319 position,
6320 context: context.clone(),
6321 server_id: Some(server_id),
6322 },
6323 cx,
6324 ).fuse();
6325 let new_task = cx.background_spawn(async move {
6326 select_biased! {
6327 response = lsp_request => anyhow::Ok(Some(response?)),
6328 timeout_happened = timeout => {
6329 if timeout_happened {
6330 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6331 Ok(None)
6332 } else {
6333 let completions = lsp_request.await?;
6334 Ok(Some(completions))
6335 }
6336 },
6337 }
6338 });
6339 tasks.push((lsp_adapter, new_task));
6340 }
6341 })?;
6342
6343 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6344 let completion_response = task.await.ok()??;
6345 let completions = populate_labels_for_completions(
6346 completion_response.completions,
6347 language.clone(),
6348 lsp_adapter,
6349 )
6350 .await;
6351 Some(CompletionResponse {
6352 completions,
6353 display_options: CompletionDisplayOptions::default(),
6354 is_incomplete: completion_response.is_incomplete,
6355 })
6356 });
6357
6358 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6359
6360 Ok(responses.into_iter().flatten().collect())
6361 })
6362 } else {
6363 Task::ready(Err(anyhow!("No upstream client or local language server")))
6364 }
6365 }
6366
6367 pub fn resolve_completions(
6368 &self,
6369 buffer: Entity<Buffer>,
6370 completion_indices: Vec<usize>,
6371 completions: Rc<RefCell<Box<[Completion]>>>,
6372 cx: &mut Context<Self>,
6373 ) -> Task<Result<bool>> {
6374 let client = self.upstream_client();
6375 let buffer_id = buffer.read(cx).remote_id();
6376 let buffer_snapshot = buffer.read(cx).snapshot();
6377
6378 if !self.check_if_capable_for_proto_request(
6379 &buffer,
6380 GetCompletions::can_resolve_completions,
6381 cx,
6382 ) {
6383 return Task::ready(Ok(false));
6384 }
6385 cx.spawn(async move |lsp_store, cx| {
6386 let mut did_resolve = false;
6387 if let Some((client, project_id)) = client {
6388 for completion_index in completion_indices {
6389 let server_id = {
6390 let completion = &completions.borrow()[completion_index];
6391 completion.source.server_id()
6392 };
6393 if let Some(server_id) = server_id {
6394 if Self::resolve_completion_remote(
6395 project_id,
6396 server_id,
6397 buffer_id,
6398 completions.clone(),
6399 completion_index,
6400 client.clone(),
6401 )
6402 .await
6403 .log_err()
6404 .is_some()
6405 {
6406 did_resolve = true;
6407 }
6408 } else {
6409 resolve_word_completion(
6410 &buffer_snapshot,
6411 &mut completions.borrow_mut()[completion_index],
6412 );
6413 }
6414 }
6415 } else {
6416 for completion_index in completion_indices {
6417 let server_id = {
6418 let completion = &completions.borrow()[completion_index];
6419 completion.source.server_id()
6420 };
6421 if let Some(server_id) = server_id {
6422 let server_and_adapter = lsp_store
6423 .read_with(cx, |lsp_store, _| {
6424 let server = lsp_store.language_server_for_id(server_id)?;
6425 let adapter =
6426 lsp_store.language_server_adapter_for_id(server.server_id())?;
6427 Some((server, adapter))
6428 })
6429 .ok()
6430 .flatten();
6431 let Some((server, adapter)) = server_and_adapter else {
6432 continue;
6433 };
6434
6435 let resolved = Self::resolve_completion_local(
6436 server,
6437 completions.clone(),
6438 completion_index,
6439 )
6440 .await
6441 .log_err()
6442 .is_some();
6443 if resolved {
6444 Self::regenerate_completion_labels(
6445 adapter,
6446 &buffer_snapshot,
6447 completions.clone(),
6448 completion_index,
6449 )
6450 .await
6451 .log_err();
6452 did_resolve = true;
6453 }
6454 } else {
6455 resolve_word_completion(
6456 &buffer_snapshot,
6457 &mut completions.borrow_mut()[completion_index],
6458 );
6459 }
6460 }
6461 }
6462
6463 Ok(did_resolve)
6464 })
6465 }
6466
6467 async fn resolve_completion_local(
6468 server: Arc<lsp::LanguageServer>,
6469 completions: Rc<RefCell<Box<[Completion]>>>,
6470 completion_index: usize,
6471 ) -> Result<()> {
6472 let server_id = server.server_id();
6473 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6474 return Ok(());
6475 }
6476
6477 let request = {
6478 let completion = &completions.borrow()[completion_index];
6479 match &completion.source {
6480 CompletionSource::Lsp {
6481 lsp_completion,
6482 resolved,
6483 server_id: completion_server_id,
6484 ..
6485 } => {
6486 if *resolved {
6487 return Ok(());
6488 }
6489 anyhow::ensure!(
6490 server_id == *completion_server_id,
6491 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6492 );
6493 server.request::<lsp::request::ResolveCompletionItem>(*lsp_completion.clone())
6494 }
6495 CompletionSource::BufferWord { .. }
6496 | CompletionSource::Dap { .. }
6497 | CompletionSource::Custom => {
6498 return Ok(());
6499 }
6500 }
6501 };
6502 let resolved_completion = request
6503 .await
6504 .into_response()
6505 .context("resolve completion")?;
6506
6507 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6508 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6509
6510 let mut completions = completions.borrow_mut();
6511 let completion = &mut completions[completion_index];
6512 if let CompletionSource::Lsp {
6513 lsp_completion,
6514 resolved,
6515 server_id: completion_server_id,
6516 ..
6517 } = &mut completion.source
6518 {
6519 if *resolved {
6520 return Ok(());
6521 }
6522 anyhow::ensure!(
6523 server_id == *completion_server_id,
6524 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6525 );
6526 **lsp_completion = resolved_completion;
6527 *resolved = true;
6528 }
6529 Ok(())
6530 }
6531
6532 async fn regenerate_completion_labels(
6533 adapter: Arc<CachedLspAdapter>,
6534 snapshot: &BufferSnapshot,
6535 completions: Rc<RefCell<Box<[Completion]>>>,
6536 completion_index: usize,
6537 ) -> Result<()> {
6538 let completion_item = completions.borrow()[completion_index]
6539 .source
6540 .lsp_completion(true)
6541 .map(Cow::into_owned);
6542 if let Some(lsp_documentation) = completion_item
6543 .as_ref()
6544 .and_then(|completion_item| completion_item.documentation.clone())
6545 {
6546 let mut completions = completions.borrow_mut();
6547 let completion = &mut completions[completion_index];
6548 completion.documentation = Some(lsp_documentation.into());
6549 } else {
6550 let mut completions = completions.borrow_mut();
6551 let completion = &mut completions[completion_index];
6552 completion.documentation = Some(CompletionDocumentation::Undocumented);
6553 }
6554
6555 let mut new_label = match completion_item {
6556 Some(completion_item) => {
6557 // Some language servers always return `detail` lazily via resolve, regardless of
6558 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6559 // See: https://github.com/yioneko/vtsls/issues/213
6560 let language = snapshot.language();
6561 match language {
6562 Some(language) => {
6563 adapter
6564 .labels_for_completions(
6565 std::slice::from_ref(&completion_item),
6566 language,
6567 )
6568 .await?
6569 }
6570 None => Vec::new(),
6571 }
6572 .pop()
6573 .flatten()
6574 .unwrap_or_else(|| {
6575 CodeLabel::fallback_for_completion(
6576 &completion_item,
6577 language.map(|language| language.as_ref()),
6578 )
6579 })
6580 }
6581 None => CodeLabel::plain(
6582 completions.borrow()[completion_index].new_text.clone(),
6583 None,
6584 ),
6585 };
6586 ensure_uniform_list_compatible_label(&mut new_label);
6587
6588 let mut completions = completions.borrow_mut();
6589 let completion = &mut completions[completion_index];
6590 if completion.label.filter_text() == new_label.filter_text() {
6591 completion.label = new_label;
6592 } else {
6593 log::error!(
6594 "Resolved completion changed display label from {} to {}. \
6595 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6596 completion.label.text(),
6597 new_label.text(),
6598 completion.label.filter_text(),
6599 new_label.filter_text()
6600 );
6601 }
6602
6603 Ok(())
6604 }
6605
6606 async fn resolve_completion_remote(
6607 project_id: u64,
6608 server_id: LanguageServerId,
6609 buffer_id: BufferId,
6610 completions: Rc<RefCell<Box<[Completion]>>>,
6611 completion_index: usize,
6612 client: AnyProtoClient,
6613 ) -> Result<()> {
6614 let lsp_completion = {
6615 let completion = &completions.borrow()[completion_index];
6616 match &completion.source {
6617 CompletionSource::Lsp {
6618 lsp_completion,
6619 resolved,
6620 server_id: completion_server_id,
6621 ..
6622 } => {
6623 anyhow::ensure!(
6624 server_id == *completion_server_id,
6625 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6626 );
6627 if *resolved {
6628 return Ok(());
6629 }
6630 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6631 }
6632 CompletionSource::Custom
6633 | CompletionSource::Dap { .. }
6634 | CompletionSource::BufferWord { .. } => {
6635 return Ok(());
6636 }
6637 }
6638 };
6639 let request = proto::ResolveCompletionDocumentation {
6640 project_id,
6641 language_server_id: server_id.0 as u64,
6642 lsp_completion,
6643 buffer_id: buffer_id.into(),
6644 };
6645
6646 let response = client
6647 .request(request)
6648 .await
6649 .context("completion documentation resolve proto request")?;
6650 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6651
6652 let documentation = if response.documentation.is_empty() {
6653 CompletionDocumentation::Undocumented
6654 } else if response.documentation_is_markdown {
6655 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6656 } else if response.documentation.lines().count() <= 1 {
6657 CompletionDocumentation::SingleLine(response.documentation.into())
6658 } else {
6659 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6660 };
6661
6662 let mut completions = completions.borrow_mut();
6663 let completion = &mut completions[completion_index];
6664 completion.documentation = Some(documentation);
6665 if let CompletionSource::Lsp {
6666 insert_range,
6667 lsp_completion,
6668 resolved,
6669 server_id: completion_server_id,
6670 lsp_defaults: _,
6671 } = &mut completion.source
6672 {
6673 let completion_insert_range = response
6674 .old_insert_start
6675 .and_then(deserialize_anchor)
6676 .zip(response.old_insert_end.and_then(deserialize_anchor));
6677 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6678
6679 if *resolved {
6680 return Ok(());
6681 }
6682 anyhow::ensure!(
6683 server_id == *completion_server_id,
6684 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6685 );
6686 **lsp_completion = resolved_lsp_completion;
6687 *resolved = true;
6688 }
6689
6690 let replace_range = response
6691 .old_replace_start
6692 .and_then(deserialize_anchor)
6693 .zip(response.old_replace_end.and_then(deserialize_anchor));
6694 if let Some((old_replace_start, old_replace_end)) = replace_range
6695 && !response.new_text.is_empty()
6696 {
6697 completion.new_text = response.new_text;
6698 completion.replace_range = old_replace_start..old_replace_end;
6699 }
6700
6701 Ok(())
6702 }
6703
6704 pub fn apply_additional_edits_for_completion(
6705 &self,
6706 buffer_handle: Entity<Buffer>,
6707 completions: Rc<RefCell<Box<[Completion]>>>,
6708 completion_index: usize,
6709 push_to_history: bool,
6710 cx: &mut Context<Self>,
6711 ) -> Task<Result<Option<Transaction>>> {
6712 if let Some((client, project_id)) = self.upstream_client() {
6713 let buffer = buffer_handle.read(cx);
6714 let buffer_id = buffer.remote_id();
6715 cx.spawn(async move |_, cx| {
6716 let request = {
6717 let completion = completions.borrow()[completion_index].clone();
6718 proto::ApplyCompletionAdditionalEdits {
6719 project_id,
6720 buffer_id: buffer_id.into(),
6721 completion: Some(Self::serialize_completion(&CoreCompletion {
6722 replace_range: completion.replace_range,
6723 new_text: completion.new_text,
6724 source: completion.source,
6725 })),
6726 }
6727 };
6728
6729 if let Some(transaction) = client.request(request).await?.transaction {
6730 let transaction = language::proto::deserialize_transaction(transaction)?;
6731 buffer_handle
6732 .update(cx, |buffer, _| {
6733 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6734 })
6735 .await?;
6736 if push_to_history {
6737 buffer_handle.update(cx, |buffer, _| {
6738 buffer.push_transaction(transaction.clone(), Instant::now());
6739 buffer.finalize_last_transaction();
6740 });
6741 }
6742 Ok(Some(transaction))
6743 } else {
6744 Ok(None)
6745 }
6746 })
6747 } else {
6748 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6749 let completion = &completions.borrow()[completion_index];
6750 let server_id = completion.source.server_id()?;
6751 Some(
6752 self.language_server_for_local_buffer(buffer, server_id, cx)?
6753 .1
6754 .clone(),
6755 )
6756 }) else {
6757 return Task::ready(Ok(None));
6758 };
6759
6760 cx.spawn(async move |this, cx| {
6761 Self::resolve_completion_local(
6762 server.clone(),
6763 completions.clone(),
6764 completion_index,
6765 )
6766 .await
6767 .context("resolving completion")?;
6768 let completion = completions.borrow()[completion_index].clone();
6769 let additional_text_edits = completion
6770 .source
6771 .lsp_completion(true)
6772 .as_ref()
6773 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6774 if let Some(edits) = additional_text_edits {
6775 let edits = this
6776 .update(cx, |this, cx| {
6777 this.as_local_mut().unwrap().edits_from_lsp(
6778 &buffer_handle,
6779 edits,
6780 server.server_id(),
6781 None,
6782 cx,
6783 )
6784 })?
6785 .await?;
6786
6787 buffer_handle.update(cx, |buffer, cx| {
6788 buffer.finalize_last_transaction();
6789 buffer.start_transaction();
6790
6791 for (range, text) in edits {
6792 let primary = &completion.replace_range;
6793
6794 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6795 // and the primary completion is just an insertion (empty range), then this is likely
6796 // an auto-import scenario and should not be considered overlapping
6797 // https://github.com/zed-industries/zed/issues/26136
6798 let is_file_start_auto_import = {
6799 let snapshot = buffer.snapshot();
6800 let primary_start_point = primary.start.to_point(&snapshot);
6801 let range_start_point = range.start.to_point(&snapshot);
6802
6803 let result = primary_start_point.row == 0
6804 && primary_start_point.column == 0
6805 && range_start_point.row == 0
6806 && range_start_point.column == 0;
6807
6808 result
6809 };
6810
6811 let has_overlap = if is_file_start_auto_import {
6812 false
6813 } else {
6814 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6815 && primary.end.cmp(&range.start, buffer).is_ge();
6816 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6817 && range.end.cmp(&primary.end, buffer).is_ge();
6818 let result = start_within || end_within;
6819 result
6820 };
6821
6822 //Skip additional edits which overlap with the primary completion edit
6823 //https://github.com/zed-industries/zed/pull/1871
6824 if !has_overlap {
6825 buffer.edit([(range, text)], None, cx);
6826 }
6827 }
6828
6829 let transaction = if buffer.end_transaction(cx).is_some() {
6830 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6831 if !push_to_history {
6832 buffer.forget_transaction(transaction.id);
6833 }
6834 Some(transaction)
6835 } else {
6836 None
6837 };
6838 Ok(transaction)
6839 })
6840 } else {
6841 Ok(None)
6842 }
6843 })
6844 }
6845 }
6846
6847 pub fn pull_diagnostics(
6848 &mut self,
6849 buffer: Entity<Buffer>,
6850 cx: &mut Context<Self>,
6851 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6852 let buffer_id = buffer.read(cx).remote_id();
6853
6854 if let Some((client, upstream_project_id)) = self.upstream_client() {
6855 let mut suitable_capabilities = None;
6856 // Are we capable for proto request?
6857 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6858 &buffer,
6859 |capabilities| {
6860 if let Some(caps) = &capabilities.diagnostic_provider {
6861 suitable_capabilities = Some(caps.clone());
6862 true
6863 } else {
6864 false
6865 }
6866 },
6867 cx,
6868 );
6869 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6870 let Some(dynamic_caps) = suitable_capabilities else {
6871 return Task::ready(Ok(None));
6872 };
6873 assert!(any_server_has_diagnostics_provider);
6874
6875 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6876 let request = GetDocumentDiagnostics {
6877 previous_result_id: None,
6878 identifier,
6879 registration_id: None,
6880 };
6881 let request_task = client.request_lsp(
6882 upstream_project_id,
6883 None,
6884 LSP_REQUEST_TIMEOUT,
6885 cx.background_executor().clone(),
6886 request.to_proto(upstream_project_id, buffer.read(cx)),
6887 );
6888 cx.background_spawn(async move {
6889 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6890 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6891 // Do not attempt to further process the dummy responses here.
6892 let _response = request_task.await?;
6893 Ok(None)
6894 })
6895 } else {
6896 let servers = buffer.update(cx, |buffer, cx| {
6897 self.running_language_servers_for_local_buffer(buffer, cx)
6898 .map(|(_, server)| server.clone())
6899 .collect::<Vec<_>>()
6900 });
6901
6902 let pull_diagnostics = servers
6903 .into_iter()
6904 .flat_map(|server| {
6905 let result = maybe!({
6906 let local = self.as_local()?;
6907 let server_id = server.server_id();
6908 let providers_with_identifiers = local
6909 .language_server_dynamic_registrations
6910 .get(&server_id)
6911 .into_iter()
6912 .flat_map(|registrations| registrations.diagnostics.clone())
6913 .collect::<Vec<_>>();
6914 Some(
6915 providers_with_identifiers
6916 .into_iter()
6917 .map(|(registration_id, dynamic_caps)| {
6918 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6919 let registration_id = registration_id.map(SharedString::from);
6920 let result_id = self.result_id_for_buffer_pull(
6921 server_id,
6922 buffer_id,
6923 ®istration_id,
6924 cx,
6925 );
6926 self.request_lsp(
6927 buffer.clone(),
6928 LanguageServerToQuery::Other(server_id),
6929 GetDocumentDiagnostics {
6930 previous_result_id: result_id,
6931 registration_id,
6932 identifier,
6933 },
6934 cx,
6935 )
6936 })
6937 .collect::<Vec<_>>(),
6938 )
6939 });
6940
6941 result.unwrap_or_default()
6942 })
6943 .collect::<Vec<_>>();
6944
6945 cx.background_spawn(async move {
6946 let mut responses = Vec::new();
6947 for diagnostics in join_all(pull_diagnostics).await {
6948 responses.extend(diagnostics?);
6949 }
6950 Ok(Some(responses))
6951 })
6952 }
6953 }
6954
6955 pub fn applicable_inlay_chunks(
6956 &mut self,
6957 buffer: &Entity<Buffer>,
6958 ranges: &[Range<text::Anchor>],
6959 cx: &mut Context<Self>,
6960 ) -> Vec<Range<BufferRow>> {
6961 let buffer_snapshot = buffer.read(cx).snapshot();
6962 let ranges = ranges
6963 .iter()
6964 .map(|range| range.to_point(&buffer_snapshot))
6965 .collect::<Vec<_>>();
6966
6967 self.latest_lsp_data(buffer, cx)
6968 .inlay_hints
6969 .applicable_chunks(ranges.as_slice())
6970 .map(|chunk| chunk.row_range())
6971 .collect()
6972 }
6973
6974 pub fn invalidate_inlay_hints<'a>(
6975 &'a mut self,
6976 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6977 ) {
6978 for buffer_id in for_buffers {
6979 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6980 lsp_data.inlay_hints.clear();
6981 }
6982 }
6983 }
6984
6985 pub fn inlay_hints(
6986 &mut self,
6987 invalidate: InvalidationStrategy,
6988 buffer: Entity<Buffer>,
6989 ranges: Vec<Range<text::Anchor>>,
6990 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6991 cx: &mut Context<Self>,
6992 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6993 let next_hint_id = self.next_hint_id.clone();
6994 let lsp_data = self.latest_lsp_data(&buffer, cx);
6995 let query_version = lsp_data.buffer_version.clone();
6996 let mut lsp_refresh_requested = false;
6997 let for_server = if let InvalidationStrategy::RefreshRequested {
6998 server_id,
6999 request_id,
7000 } = invalidate
7001 {
7002 let invalidated = lsp_data
7003 .inlay_hints
7004 .invalidate_for_server_refresh(server_id, request_id);
7005 lsp_refresh_requested = invalidated;
7006 Some(server_id)
7007 } else {
7008 None
7009 };
7010 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7011 let known_chunks = known_chunks
7012 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7013 .map(|(_, known_chunks)| known_chunks)
7014 .unwrap_or_default();
7015
7016 let buffer_snapshot = buffer.read(cx).snapshot();
7017 let ranges = ranges
7018 .iter()
7019 .map(|range| range.to_point(&buffer_snapshot))
7020 .collect::<Vec<_>>();
7021
7022 let mut hint_fetch_tasks = Vec::new();
7023 let mut cached_inlay_hints = None;
7024 let mut ranges_to_query = None;
7025 let applicable_chunks = existing_inlay_hints
7026 .applicable_chunks(ranges.as_slice())
7027 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7028 .collect::<Vec<_>>();
7029 if applicable_chunks.is_empty() {
7030 return HashMap::default();
7031 }
7032
7033 for row_chunk in applicable_chunks {
7034 match (
7035 existing_inlay_hints
7036 .cached_hints(&row_chunk)
7037 .filter(|_| !lsp_refresh_requested)
7038 .cloned(),
7039 existing_inlay_hints
7040 .fetched_hints(&row_chunk)
7041 .as_ref()
7042 .filter(|_| !lsp_refresh_requested)
7043 .cloned(),
7044 ) {
7045 (None, None) => {
7046 let chunk_range = row_chunk.anchor_range();
7047 ranges_to_query
7048 .get_or_insert_with(Vec::new)
7049 .push((row_chunk, chunk_range));
7050 }
7051 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7052 (Some(cached_hints), None) => {
7053 for (server_id, cached_hints) in cached_hints {
7054 if for_server.is_none_or(|for_server| for_server == server_id) {
7055 cached_inlay_hints
7056 .get_or_insert_with(HashMap::default)
7057 .entry(row_chunk.row_range())
7058 .or_insert_with(HashMap::default)
7059 .entry(server_id)
7060 .or_insert_with(Vec::new)
7061 .extend(cached_hints);
7062 }
7063 }
7064 }
7065 (Some(cached_hints), Some(fetched_hints)) => {
7066 hint_fetch_tasks.push((row_chunk, fetched_hints));
7067 for (server_id, cached_hints) in cached_hints {
7068 if for_server.is_none_or(|for_server| for_server == server_id) {
7069 cached_inlay_hints
7070 .get_or_insert_with(HashMap::default)
7071 .entry(row_chunk.row_range())
7072 .or_insert_with(HashMap::default)
7073 .entry(server_id)
7074 .or_insert_with(Vec::new)
7075 .extend(cached_hints);
7076 }
7077 }
7078 }
7079 }
7080 }
7081
7082 if hint_fetch_tasks.is_empty()
7083 && ranges_to_query
7084 .as_ref()
7085 .is_none_or(|ranges| ranges.is_empty())
7086 && let Some(cached_inlay_hints) = cached_inlay_hints
7087 {
7088 cached_inlay_hints
7089 .into_iter()
7090 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7091 .collect()
7092 } else {
7093 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7094 let next_hint_id = next_hint_id.clone();
7095 let buffer = buffer.clone();
7096 let query_version = query_version.clone();
7097 let new_inlay_hints = cx
7098 .spawn(async move |lsp_store, cx| {
7099 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7100 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7101 })?;
7102 new_fetch_task
7103 .await
7104 .and_then(|new_hints_by_server| {
7105 lsp_store.update(cx, |lsp_store, cx| {
7106 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7107 let update_cache = lsp_data.buffer_version == query_version;
7108 if new_hints_by_server.is_empty() {
7109 if update_cache {
7110 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7111 }
7112 HashMap::default()
7113 } else {
7114 new_hints_by_server
7115 .into_iter()
7116 .map(|(server_id, new_hints)| {
7117 let new_hints = new_hints
7118 .into_iter()
7119 .map(|new_hint| {
7120 (
7121 InlayId::Hint(next_hint_id.fetch_add(
7122 1,
7123 atomic::Ordering::AcqRel,
7124 )),
7125 new_hint,
7126 )
7127 })
7128 .collect::<Vec<_>>();
7129 if update_cache {
7130 lsp_data.inlay_hints.insert_new_hints(
7131 chunk,
7132 server_id,
7133 new_hints.clone(),
7134 );
7135 }
7136 (server_id, new_hints)
7137 })
7138 .collect()
7139 }
7140 })
7141 })
7142 .map_err(Arc::new)
7143 })
7144 .shared();
7145
7146 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7147 *fetch_task = Some(new_inlay_hints.clone());
7148 hint_fetch_tasks.push((chunk, new_inlay_hints));
7149 }
7150
7151 cached_inlay_hints
7152 .unwrap_or_default()
7153 .into_iter()
7154 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7155 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7156 (
7157 chunk.row_range(),
7158 cx.spawn(async move |_, _| {
7159 hints_fetch.await.map_err(|e| {
7160 if e.error_code() != ErrorCode::Internal {
7161 anyhow!(e.error_code())
7162 } else {
7163 anyhow!("{e:#}")
7164 }
7165 })
7166 }),
7167 )
7168 }))
7169 .collect()
7170 }
7171 }
7172
7173 fn fetch_inlay_hints(
7174 &mut self,
7175 for_server: Option<LanguageServerId>,
7176 buffer: &Entity<Buffer>,
7177 range: Range<Anchor>,
7178 cx: &mut Context<Self>,
7179 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7180 let request = InlayHints {
7181 range: range.clone(),
7182 };
7183 if let Some((upstream_client, project_id)) = self.upstream_client() {
7184 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7185 return Task::ready(Ok(HashMap::default()));
7186 }
7187 let request_task = upstream_client.request_lsp(
7188 project_id,
7189 for_server.map(|id| id.to_proto()),
7190 LSP_REQUEST_TIMEOUT,
7191 cx.background_executor().clone(),
7192 request.to_proto(project_id, buffer.read(cx)),
7193 );
7194 let buffer = buffer.clone();
7195 cx.spawn(async move |weak_lsp_store, cx| {
7196 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7197 return Ok(HashMap::default());
7198 };
7199 let Some(responses) = request_task.await? else {
7200 return Ok(HashMap::default());
7201 };
7202
7203 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7204 let lsp_store = lsp_store.clone();
7205 let buffer = buffer.clone();
7206 let cx = cx.clone();
7207 let request = request.clone();
7208 async move {
7209 (
7210 LanguageServerId::from_proto(response.server_id),
7211 request
7212 .response_from_proto(response.response, lsp_store, buffer, cx)
7213 .await,
7214 )
7215 }
7216 }))
7217 .await;
7218
7219 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7220 let mut has_errors = false;
7221 let inlay_hints = inlay_hints
7222 .into_iter()
7223 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7224 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7225 Err(e) => {
7226 has_errors = true;
7227 log::error!("{e:#}");
7228 None
7229 }
7230 })
7231 .map(|(server_id, mut new_hints)| {
7232 new_hints.retain(|hint| {
7233 hint.position.is_valid(&buffer_snapshot)
7234 && range.start.is_valid(&buffer_snapshot)
7235 && range.end.is_valid(&buffer_snapshot)
7236 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7237 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7238 });
7239 (server_id, new_hints)
7240 })
7241 .collect::<HashMap<_, _>>();
7242 anyhow::ensure!(
7243 !has_errors || !inlay_hints.is_empty(),
7244 "Failed to fetch inlay hints"
7245 );
7246 Ok(inlay_hints)
7247 })
7248 } else {
7249 let inlay_hints_task = match for_server {
7250 Some(server_id) => {
7251 let server_task = self.request_lsp(
7252 buffer.clone(),
7253 LanguageServerToQuery::Other(server_id),
7254 request,
7255 cx,
7256 );
7257 cx.background_spawn(async move {
7258 let mut responses = Vec::new();
7259 match server_task.await {
7260 Ok(response) => responses.push((server_id, response)),
7261 // rust-analyzer likes to error with this when its still loading up
7262 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7263 Err(e) => log::error!(
7264 "Error handling response for inlay hints request: {e:#}"
7265 ),
7266 }
7267 responses
7268 })
7269 }
7270 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7271 };
7272 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7273 cx.background_spawn(async move {
7274 Ok(inlay_hints_task
7275 .await
7276 .into_iter()
7277 .map(|(server_id, mut new_hints)| {
7278 new_hints.retain(|hint| {
7279 hint.position.is_valid(&buffer_snapshot)
7280 && range.start.is_valid(&buffer_snapshot)
7281 && range.end.is_valid(&buffer_snapshot)
7282 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7283 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7284 });
7285 (server_id, new_hints)
7286 })
7287 .collect())
7288 })
7289 }
7290 }
7291
7292 fn diagnostic_registration_exists(
7293 &self,
7294 server_id: LanguageServerId,
7295 registration_id: &Option<SharedString>,
7296 ) -> bool {
7297 let Some(local) = self.as_local() else {
7298 return false;
7299 };
7300 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7301 else {
7302 return false;
7303 };
7304 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7305 registrations.diagnostics.contains_key(®istration_key)
7306 }
7307
7308 pub fn pull_diagnostics_for_buffer(
7309 &mut self,
7310 buffer: Entity<Buffer>,
7311 cx: &mut Context<Self>,
7312 ) -> Task<anyhow::Result<()>> {
7313 let diagnostics = self.pull_diagnostics(buffer, cx);
7314 cx.spawn(async move |lsp_store, cx| {
7315 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7316 return Ok(());
7317 };
7318 lsp_store.update(cx, |lsp_store, cx| {
7319 if lsp_store.as_local().is_none() {
7320 return;
7321 }
7322
7323 let mut unchanged_buffers = HashMap::default();
7324 let server_diagnostics_updates = diagnostics
7325 .into_iter()
7326 .filter_map(|diagnostics_set| match diagnostics_set {
7327 LspPullDiagnostics::Response {
7328 server_id,
7329 uri,
7330 diagnostics,
7331 registration_id,
7332 } => Some((server_id, uri, diagnostics, registration_id)),
7333 LspPullDiagnostics::Default => None,
7334 })
7335 .filter(|(server_id, _, _, registration_id)| {
7336 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7337 })
7338 .fold(
7339 HashMap::default(),
7340 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7341 let (result_id, diagnostics) = match diagnostics {
7342 PulledDiagnostics::Unchanged { result_id } => {
7343 unchanged_buffers
7344 .entry(new_registration_id.clone())
7345 .or_insert_with(HashSet::default)
7346 .insert(uri.clone());
7347 (Some(result_id), Vec::new())
7348 }
7349 PulledDiagnostics::Changed {
7350 result_id,
7351 diagnostics,
7352 } => (result_id, diagnostics),
7353 };
7354 let disk_based_sources = Cow::Owned(
7355 lsp_store
7356 .language_server_adapter_for_id(server_id)
7357 .as_ref()
7358 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7359 .unwrap_or(&[])
7360 .to_vec(),
7361 );
7362 acc.entry(server_id)
7363 .or_insert_with(HashMap::default)
7364 .entry(new_registration_id.clone())
7365 .or_insert_with(Vec::new)
7366 .push(DocumentDiagnosticsUpdate {
7367 server_id,
7368 diagnostics: lsp::PublishDiagnosticsParams {
7369 uri,
7370 diagnostics,
7371 version: None,
7372 },
7373 result_id,
7374 disk_based_sources,
7375 registration_id: new_registration_id,
7376 });
7377 acc
7378 },
7379 );
7380
7381 for diagnostic_updates in server_diagnostics_updates.into_values() {
7382 for (registration_id, diagnostic_updates) in diagnostic_updates {
7383 lsp_store
7384 .merge_lsp_diagnostics(
7385 DiagnosticSourceKind::Pulled,
7386 diagnostic_updates,
7387 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7388 DiagnosticSourceKind::Pulled => {
7389 old_diagnostic.registration_id != registration_id
7390 || unchanged_buffers
7391 .get(&old_diagnostic.registration_id)
7392 .is_some_and(|unchanged_buffers| {
7393 unchanged_buffers.contains(&document_uri)
7394 })
7395 }
7396 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7397 true
7398 }
7399 },
7400 cx,
7401 )
7402 .log_err();
7403 }
7404 }
7405 })
7406 })
7407 }
7408
7409 pub fn document_colors(
7410 &mut self,
7411 known_cache_version: Option<usize>,
7412 buffer: Entity<Buffer>,
7413 cx: &mut Context<Self>,
7414 ) -> Option<DocumentColorTask> {
7415 let version_queried_for = buffer.read(cx).version();
7416 let buffer_id = buffer.read(cx).remote_id();
7417
7418 let current_language_servers = self.as_local().map(|local| {
7419 local
7420 .buffers_opened_in_servers
7421 .get(&buffer_id)
7422 .cloned()
7423 .unwrap_or_default()
7424 });
7425
7426 if let Some(lsp_data) = self.current_lsp_data(buffer_id) {
7427 if let Some(cached_colors) = &lsp_data.document_colors {
7428 if !version_queried_for.changed_since(&lsp_data.buffer_version) {
7429 let has_different_servers =
7430 current_language_servers.is_some_and(|current_language_servers| {
7431 current_language_servers
7432 != cached_colors.colors.keys().copied().collect()
7433 });
7434 if !has_different_servers {
7435 let cache_version = cached_colors.cache_version;
7436 if Some(cache_version) == known_cache_version {
7437 return None;
7438 } else {
7439 return Some(
7440 Task::ready(Ok(DocumentColors {
7441 colors: cached_colors
7442 .colors
7443 .values()
7444 .flatten()
7445 .cloned()
7446 .collect(),
7447 cache_version: Some(cache_version),
7448 }))
7449 .shared(),
7450 );
7451 }
7452 }
7453 }
7454 }
7455 }
7456
7457 let color_lsp_data = self
7458 .latest_lsp_data(&buffer, cx)
7459 .document_colors
7460 .get_or_insert_default();
7461 if let Some((updating_for, running_update)) = &color_lsp_data.colors_update
7462 && !version_queried_for.changed_since(updating_for)
7463 {
7464 return Some(running_update.clone());
7465 }
7466 let buffer_version_queried_for = version_queried_for.clone();
7467 let new_task = cx
7468 .spawn(async move |lsp_store, cx| {
7469 cx.background_executor()
7470 .timer(Duration::from_millis(30))
7471 .await;
7472 let fetched_colors = lsp_store
7473 .update(cx, |lsp_store, cx| {
7474 lsp_store.fetch_document_colors_for_buffer(&buffer, cx)
7475 })?
7476 .await
7477 .context("fetching document colors")
7478 .map_err(Arc::new);
7479 let fetched_colors = match fetched_colors {
7480 Ok(fetched_colors) => {
7481 if buffer.update(cx, |buffer, _| {
7482 buffer.version() != buffer_version_queried_for
7483 }) {
7484 return Ok(DocumentColors::default());
7485 }
7486 fetched_colors
7487 }
7488 Err(e) => {
7489 lsp_store
7490 .update(cx, |lsp_store, _| {
7491 if let Some(lsp_data) = lsp_store.lsp_data.get_mut(&buffer_id) {
7492 if let Some(document_colors) = &mut lsp_data.document_colors {
7493 document_colors.colors_update = None;
7494 }
7495 }
7496 })
7497 .ok();
7498 return Err(e);
7499 }
7500 };
7501
7502 lsp_store
7503 .update(cx, |lsp_store, cx| {
7504 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7505 let lsp_colors = lsp_data.document_colors.get_or_insert_default();
7506
7507 if let Some(fetched_colors) = fetched_colors {
7508 if lsp_data.buffer_version == buffer_version_queried_for {
7509 lsp_colors.colors.extend(fetched_colors);
7510 lsp_colors.cache_version += 1;
7511 } else if !lsp_data
7512 .buffer_version
7513 .changed_since(&buffer_version_queried_for)
7514 {
7515 lsp_data.buffer_version = buffer_version_queried_for;
7516 lsp_colors.colors = fetched_colors;
7517 lsp_colors.cache_version += 1;
7518 }
7519 }
7520 lsp_colors.colors_update = None;
7521 let colors = lsp_colors
7522 .colors
7523 .values()
7524 .flatten()
7525 .cloned()
7526 .collect::<HashSet<_>>();
7527 DocumentColors {
7528 colors,
7529 cache_version: Some(lsp_colors.cache_version),
7530 }
7531 })
7532 .map_err(Arc::new)
7533 })
7534 .shared();
7535 color_lsp_data.colors_update = Some((version_queried_for, new_task.clone()));
7536 Some(new_task)
7537 }
7538
7539 fn fetch_document_colors_for_buffer(
7540 &mut self,
7541 buffer: &Entity<Buffer>,
7542 cx: &mut Context<Self>,
7543 ) -> Task<anyhow::Result<Option<HashMap<LanguageServerId, HashSet<DocumentColor>>>>> {
7544 if let Some((client, project_id)) = self.upstream_client() {
7545 let request = GetDocumentColor {};
7546 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7547 return Task::ready(Ok(None));
7548 }
7549
7550 let request_task = client.request_lsp(
7551 project_id,
7552 None,
7553 LSP_REQUEST_TIMEOUT,
7554 cx.background_executor().clone(),
7555 request.to_proto(project_id, buffer.read(cx)),
7556 );
7557 let buffer = buffer.clone();
7558 cx.spawn(async move |lsp_store, cx| {
7559 let Some(lsp_store) = lsp_store.upgrade() else {
7560 return Ok(None);
7561 };
7562 let colors = join_all(
7563 request_task
7564 .await
7565 .log_err()
7566 .flatten()
7567 .map(|response| response.payload)
7568 .unwrap_or_default()
7569 .into_iter()
7570 .map(|color_response| {
7571 let response = request.response_from_proto(
7572 color_response.response,
7573 lsp_store.clone(),
7574 buffer.clone(),
7575 cx.clone(),
7576 );
7577 async move {
7578 (
7579 LanguageServerId::from_proto(color_response.server_id),
7580 response.await.log_err().unwrap_or_default(),
7581 )
7582 }
7583 }),
7584 )
7585 .await
7586 .into_iter()
7587 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7588 acc.entry(server_id)
7589 .or_insert_with(HashSet::default)
7590 .extend(colors);
7591 acc
7592 });
7593 Ok(Some(colors))
7594 })
7595 } else {
7596 let document_colors_task =
7597 self.request_multiple_lsp_locally(buffer, None::<usize>, GetDocumentColor, cx);
7598 cx.background_spawn(async move {
7599 Ok(Some(
7600 document_colors_task
7601 .await
7602 .into_iter()
7603 .fold(HashMap::default(), |mut acc, (server_id, colors)| {
7604 acc.entry(server_id)
7605 .or_insert_with(HashSet::default)
7606 .extend(colors);
7607 acc
7608 })
7609 .into_iter()
7610 .collect(),
7611 ))
7612 })
7613 }
7614 }
7615
7616 pub fn signature_help<T: ToPointUtf16>(
7617 &mut self,
7618 buffer: &Entity<Buffer>,
7619 position: T,
7620 cx: &mut Context<Self>,
7621 ) -> Task<Option<Vec<SignatureHelp>>> {
7622 let position = position.to_point_utf16(buffer.read(cx));
7623
7624 if let Some((client, upstream_project_id)) = self.upstream_client() {
7625 let request = GetSignatureHelp { position };
7626 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7627 return Task::ready(None);
7628 }
7629 let request_task = client.request_lsp(
7630 upstream_project_id,
7631 None,
7632 LSP_REQUEST_TIMEOUT,
7633 cx.background_executor().clone(),
7634 request.to_proto(upstream_project_id, buffer.read(cx)),
7635 );
7636 let buffer = buffer.clone();
7637 cx.spawn(async move |weak_lsp_store, cx| {
7638 let lsp_store = weak_lsp_store.upgrade()?;
7639 let signatures = join_all(
7640 request_task
7641 .await
7642 .log_err()
7643 .flatten()
7644 .map(|response| response.payload)
7645 .unwrap_or_default()
7646 .into_iter()
7647 .map(|response| {
7648 let response = GetSignatureHelp { position }.response_from_proto(
7649 response.response,
7650 lsp_store.clone(),
7651 buffer.clone(),
7652 cx.clone(),
7653 );
7654 async move { response.await.log_err().flatten() }
7655 }),
7656 )
7657 .await
7658 .into_iter()
7659 .flatten()
7660 .collect();
7661 Some(signatures)
7662 })
7663 } else {
7664 let all_actions_task = self.request_multiple_lsp_locally(
7665 buffer,
7666 Some(position),
7667 GetSignatureHelp { position },
7668 cx,
7669 );
7670 cx.background_spawn(async move {
7671 Some(
7672 all_actions_task
7673 .await
7674 .into_iter()
7675 .flat_map(|(_, actions)| actions)
7676 .collect::<Vec<_>>(),
7677 )
7678 })
7679 }
7680 }
7681
7682 pub fn hover(
7683 &mut self,
7684 buffer: &Entity<Buffer>,
7685 position: PointUtf16,
7686 cx: &mut Context<Self>,
7687 ) -> Task<Option<Vec<Hover>>> {
7688 if let Some((client, upstream_project_id)) = self.upstream_client() {
7689 let request = GetHover { position };
7690 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7691 return Task::ready(None);
7692 }
7693 let request_task = client.request_lsp(
7694 upstream_project_id,
7695 None,
7696 LSP_REQUEST_TIMEOUT,
7697 cx.background_executor().clone(),
7698 request.to_proto(upstream_project_id, buffer.read(cx)),
7699 );
7700 let buffer = buffer.clone();
7701 cx.spawn(async move |weak_lsp_store, cx| {
7702 let lsp_store = weak_lsp_store.upgrade()?;
7703 let hovers = join_all(
7704 request_task
7705 .await
7706 .log_err()
7707 .flatten()
7708 .map(|response| response.payload)
7709 .unwrap_or_default()
7710 .into_iter()
7711 .map(|response| {
7712 let response = GetHover { position }.response_from_proto(
7713 response.response,
7714 lsp_store.clone(),
7715 buffer.clone(),
7716 cx.clone(),
7717 );
7718 async move {
7719 response
7720 .await
7721 .log_err()
7722 .flatten()
7723 .and_then(remove_empty_hover_blocks)
7724 }
7725 }),
7726 )
7727 .await
7728 .into_iter()
7729 .flatten()
7730 .collect();
7731 Some(hovers)
7732 })
7733 } else {
7734 let all_actions_task = self.request_multiple_lsp_locally(
7735 buffer,
7736 Some(position),
7737 GetHover { position },
7738 cx,
7739 );
7740 cx.background_spawn(async move {
7741 Some(
7742 all_actions_task
7743 .await
7744 .into_iter()
7745 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7746 .collect::<Vec<Hover>>(),
7747 )
7748 })
7749 }
7750 }
7751
7752 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7753 let language_registry = self.languages.clone();
7754
7755 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7756 let request = upstream_client.request(proto::GetProjectSymbols {
7757 project_id: *project_id,
7758 query: query.to_string(),
7759 });
7760 cx.foreground_executor().spawn(async move {
7761 let response = request.await?;
7762 let mut symbols = Vec::new();
7763 let core_symbols = response
7764 .symbols
7765 .into_iter()
7766 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7767 .collect::<Vec<_>>();
7768 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7769 .await;
7770 Ok(symbols)
7771 })
7772 } else if let Some(local) = self.as_local() {
7773 struct WorkspaceSymbolsResult {
7774 server_id: LanguageServerId,
7775 lsp_adapter: Arc<CachedLspAdapter>,
7776 worktree: WeakEntity<Worktree>,
7777 lsp_symbols: Vec<(String, SymbolKind, lsp::Location)>,
7778 }
7779
7780 let mut requests = Vec::new();
7781 let mut requested_servers = BTreeSet::new();
7782 for (seed, state) in local.language_server_ids.iter() {
7783 let Some(worktree_handle) = self
7784 .worktree_store
7785 .read(cx)
7786 .worktree_for_id(seed.worktree_id, cx)
7787 else {
7788 continue;
7789 };
7790 let worktree = worktree_handle.read(cx);
7791 if !worktree.is_visible() {
7792 continue;
7793 }
7794
7795 if !requested_servers.insert(state.id) {
7796 continue;
7797 }
7798
7799 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7800 Some(LanguageServerState::Running {
7801 adapter, server, ..
7802 }) => (adapter.clone(), server),
7803
7804 _ => continue,
7805 };
7806 let supports_workspace_symbol_request =
7807 match server.capabilities().workspace_symbol_provider {
7808 Some(OneOf::Left(supported)) => supported,
7809 Some(OneOf::Right(_)) => true,
7810 None => false,
7811 };
7812 if !supports_workspace_symbol_request {
7813 continue;
7814 }
7815 let worktree_handle = worktree_handle.clone();
7816 let server_id = server.server_id();
7817 requests.push(
7818 server
7819 .request::<lsp::request::WorkspaceSymbolRequest>(
7820 lsp::WorkspaceSymbolParams {
7821 query: query.to_string(),
7822 ..Default::default()
7823 },
7824 )
7825 .map(move |response| {
7826 let lsp_symbols = response
7827 .into_response()
7828 .context("workspace symbols request")
7829 .log_err()
7830 .flatten()
7831 .map(|symbol_response| match symbol_response {
7832 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7833 flat_responses
7834 .into_iter()
7835 .map(|lsp_symbol| {
7836 (
7837 lsp_symbol.name,
7838 lsp_symbol.kind,
7839 lsp_symbol.location,
7840 )
7841 })
7842 .collect::<Vec<_>>()
7843 }
7844 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7845 nested_responses
7846 .into_iter()
7847 .filter_map(|lsp_symbol| {
7848 let location = match lsp_symbol.location {
7849 OneOf::Left(location) => location,
7850 OneOf::Right(_) => {
7851 log::error!(
7852 "Unexpected: client capabilities \
7853 forbid symbol resolutions in \
7854 workspace.symbol.resolveSupport"
7855 );
7856 return None;
7857 }
7858 };
7859 Some((lsp_symbol.name, lsp_symbol.kind, location))
7860 })
7861 .collect::<Vec<_>>()
7862 }
7863 })
7864 .unwrap_or_default();
7865
7866 WorkspaceSymbolsResult {
7867 server_id,
7868 lsp_adapter,
7869 worktree: worktree_handle.downgrade(),
7870 lsp_symbols,
7871 }
7872 }),
7873 );
7874 }
7875
7876 cx.spawn(async move |this, cx| {
7877 let responses = futures::future::join_all(requests).await;
7878 let this = match this.upgrade() {
7879 Some(this) => this,
7880 None => return Ok(Vec::new()),
7881 };
7882
7883 let mut symbols = Vec::new();
7884 for result in responses {
7885 let core_symbols = this.update(cx, |this, cx| {
7886 result
7887 .lsp_symbols
7888 .into_iter()
7889 .filter_map(|(symbol_name, symbol_kind, symbol_location)| {
7890 let abs_path = symbol_location.uri.to_file_path().ok()?;
7891 let source_worktree = result.worktree.upgrade()?;
7892 let source_worktree_id = source_worktree.read(cx).id();
7893
7894 let path = if let Some((tree, rel_path)) =
7895 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7896 {
7897 let worktree_id = tree.read(cx).id();
7898 SymbolLocation::InProject(ProjectPath {
7899 worktree_id,
7900 path: rel_path,
7901 })
7902 } else {
7903 SymbolLocation::OutsideProject {
7904 signature: this.symbol_signature(&abs_path),
7905 abs_path: abs_path.into(),
7906 }
7907 };
7908
7909 Some(CoreSymbol {
7910 source_language_server_id: result.server_id,
7911 language_server_name: result.lsp_adapter.name.clone(),
7912 source_worktree_id,
7913 path,
7914 kind: symbol_kind,
7915 name: symbol_name,
7916 range: range_from_lsp(symbol_location.range),
7917 })
7918 })
7919 .collect::<Vec<_>>()
7920 });
7921
7922 populate_labels_for_symbols(
7923 core_symbols,
7924 &language_registry,
7925 Some(result.lsp_adapter),
7926 &mut symbols,
7927 )
7928 .await;
7929 }
7930
7931 Ok(symbols)
7932 })
7933 } else {
7934 Task::ready(Err(anyhow!("No upstream client or local language server")))
7935 }
7936 }
7937
7938 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7939 let mut summary = DiagnosticSummary::default();
7940 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7941 summary.error_count += path_summary.error_count;
7942 summary.warning_count += path_summary.warning_count;
7943 }
7944 summary
7945 }
7946
7947 /// Returns the diagnostic summary for a specific project path.
7948 pub fn diagnostic_summary_for_path(
7949 &self,
7950 project_path: &ProjectPath,
7951 _: &App,
7952 ) -> DiagnosticSummary {
7953 if let Some(summaries) = self
7954 .diagnostic_summaries
7955 .get(&project_path.worktree_id)
7956 .and_then(|map| map.get(&project_path.path))
7957 {
7958 let (error_count, warning_count) = summaries.iter().fold(
7959 (0, 0),
7960 |(error_count, warning_count), (_language_server_id, summary)| {
7961 (
7962 error_count + summary.error_count,
7963 warning_count + summary.warning_count,
7964 )
7965 },
7966 );
7967
7968 DiagnosticSummary {
7969 error_count,
7970 warning_count,
7971 }
7972 } else {
7973 DiagnosticSummary::default()
7974 }
7975 }
7976
7977 pub fn diagnostic_summaries<'a>(
7978 &'a self,
7979 include_ignored: bool,
7980 cx: &'a App,
7981 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7982 self.worktree_store
7983 .read(cx)
7984 .visible_worktrees(cx)
7985 .filter_map(|worktree| {
7986 let worktree = worktree.read(cx);
7987 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7988 })
7989 .flat_map(move |(worktree, summaries)| {
7990 let worktree_id = worktree.id();
7991 summaries
7992 .iter()
7993 .filter(move |(path, _)| {
7994 include_ignored
7995 || worktree
7996 .entry_for_path(path.as_ref())
7997 .is_some_and(|entry| !entry.is_ignored)
7998 })
7999 .flat_map(move |(path, summaries)| {
8000 summaries.iter().map(move |(server_id, summary)| {
8001 (
8002 ProjectPath {
8003 worktree_id,
8004 path: path.clone(),
8005 },
8006 *server_id,
8007 *summary,
8008 )
8009 })
8010 })
8011 })
8012 }
8013
8014 pub fn on_buffer_edited(
8015 &mut self,
8016 buffer: Entity<Buffer>,
8017 cx: &mut Context<Self>,
8018 ) -> Option<()> {
8019 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8020 Some(
8021 self.as_local()?
8022 .language_servers_for_buffer(buffer, cx)
8023 .map(|i| i.1.clone())
8024 .collect(),
8025 )
8026 })?;
8027
8028 let buffer = buffer.read(cx);
8029 let file = File::from_dyn(buffer.file())?;
8030 let abs_path = file.as_local()?.abs_path(cx);
8031 let uri = lsp::Uri::from_file_path(&abs_path)
8032 .ok()
8033 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8034 .log_err()?;
8035 let next_snapshot = buffer.text_snapshot();
8036 for language_server in language_servers {
8037 let language_server = language_server.clone();
8038
8039 let buffer_snapshots = self
8040 .as_local_mut()?
8041 .buffer_snapshots
8042 .get_mut(&buffer.remote_id())
8043 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8044 let previous_snapshot = buffer_snapshots.last()?;
8045
8046 let build_incremental_change = || {
8047 buffer
8048 .edits_since::<Dimensions<PointUtf16, usize>>(
8049 previous_snapshot.snapshot.version(),
8050 )
8051 .map(|edit| {
8052 let edit_start = edit.new.start.0;
8053 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8054 let new_text = next_snapshot
8055 .text_for_range(edit.new.start.1..edit.new.end.1)
8056 .collect();
8057 lsp::TextDocumentContentChangeEvent {
8058 range: Some(lsp::Range::new(
8059 point_to_lsp(edit_start),
8060 point_to_lsp(edit_end),
8061 )),
8062 range_length: None,
8063 text: new_text,
8064 }
8065 })
8066 .collect()
8067 };
8068
8069 let document_sync_kind = language_server
8070 .capabilities()
8071 .text_document_sync
8072 .as_ref()
8073 .and_then(|sync| match sync {
8074 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8075 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8076 });
8077
8078 let content_changes: Vec<_> = match document_sync_kind {
8079 Some(lsp::TextDocumentSyncKind::FULL) => {
8080 vec![lsp::TextDocumentContentChangeEvent {
8081 range: None,
8082 range_length: None,
8083 text: next_snapshot.text(),
8084 }]
8085 }
8086 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8087 _ => {
8088 #[cfg(any(test, feature = "test-support"))]
8089 {
8090 build_incremental_change()
8091 }
8092
8093 #[cfg(not(any(test, feature = "test-support")))]
8094 {
8095 continue;
8096 }
8097 }
8098 };
8099
8100 let next_version = previous_snapshot.version + 1;
8101 buffer_snapshots.push(LspBufferSnapshot {
8102 version: next_version,
8103 snapshot: next_snapshot.clone(),
8104 });
8105
8106 language_server
8107 .notify::<lsp::notification::DidChangeTextDocument>(
8108 lsp::DidChangeTextDocumentParams {
8109 text_document: lsp::VersionedTextDocumentIdentifier::new(
8110 uri.clone(),
8111 next_version,
8112 ),
8113 content_changes,
8114 },
8115 )
8116 .ok();
8117 self.pull_workspace_diagnostics(language_server.server_id());
8118 }
8119
8120 None
8121 }
8122
8123 pub fn on_buffer_saved(
8124 &mut self,
8125 buffer: Entity<Buffer>,
8126 cx: &mut Context<Self>,
8127 ) -> Option<()> {
8128 let file = File::from_dyn(buffer.read(cx).file())?;
8129 let worktree_id = file.worktree_id(cx);
8130 let abs_path = file.as_local()?.abs_path(cx);
8131 let text_document = lsp::TextDocumentIdentifier {
8132 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8133 };
8134 let local = self.as_local()?;
8135
8136 for server in local.language_servers_for_worktree(worktree_id) {
8137 if let Some(include_text) = include_text(server.as_ref()) {
8138 let text = if include_text {
8139 Some(buffer.read(cx).text())
8140 } else {
8141 None
8142 };
8143 server
8144 .notify::<lsp::notification::DidSaveTextDocument>(
8145 lsp::DidSaveTextDocumentParams {
8146 text_document: text_document.clone(),
8147 text,
8148 },
8149 )
8150 .ok();
8151 }
8152 }
8153
8154 let language_servers = buffer.update(cx, |buffer, cx| {
8155 local.language_server_ids_for_buffer(buffer, cx)
8156 });
8157 for language_server_id in language_servers {
8158 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8159 }
8160
8161 None
8162 }
8163
8164 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8165 maybe!(async move {
8166 let mut refreshed_servers = HashSet::default();
8167 let servers = lsp_store
8168 .update(cx, |lsp_store, cx| {
8169 let local = lsp_store.as_local()?;
8170
8171 let servers = local
8172 .language_server_ids
8173 .iter()
8174 .filter_map(|(seed, state)| {
8175 let worktree = lsp_store
8176 .worktree_store
8177 .read(cx)
8178 .worktree_for_id(seed.worktree_id, cx);
8179 let delegate: Arc<dyn LspAdapterDelegate> =
8180 worktree.map(|worktree| {
8181 LocalLspAdapterDelegate::new(
8182 local.languages.clone(),
8183 &local.environment,
8184 cx.weak_entity(),
8185 &worktree,
8186 local.http_client.clone(),
8187 local.fs.clone(),
8188 cx,
8189 )
8190 })?;
8191 let server_id = state.id;
8192
8193 let states = local.language_servers.get(&server_id)?;
8194
8195 match states {
8196 LanguageServerState::Starting { .. } => None,
8197 LanguageServerState::Running {
8198 adapter, server, ..
8199 } => {
8200 let adapter = adapter.clone();
8201 let server = server.clone();
8202 refreshed_servers.insert(server.name());
8203 let toolchain = seed.toolchain.clone();
8204 Some(cx.spawn(async move |_, cx| {
8205 let settings =
8206 LocalLspStore::workspace_configuration_for_adapter(
8207 adapter.adapter.clone(),
8208 &delegate,
8209 toolchain,
8210 None,
8211 cx,
8212 )
8213 .await
8214 .ok()?;
8215 server
8216 .notify::<lsp::notification::DidChangeConfiguration>(
8217 lsp::DidChangeConfigurationParams { settings },
8218 )
8219 .ok()?;
8220 Some(())
8221 }))
8222 }
8223 }
8224 })
8225 .collect::<Vec<_>>();
8226
8227 Some(servers)
8228 })
8229 .ok()
8230 .flatten()?;
8231
8232 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8233 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8234 // to stop and unregister its language server wrapper.
8235 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8236 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8237 let _: Vec<Option<()>> = join_all(servers).await;
8238
8239 Some(())
8240 })
8241 .await;
8242 }
8243
8244 fn maintain_workspace_config(
8245 external_refresh_requests: watch::Receiver<()>,
8246 cx: &mut Context<Self>,
8247 ) -> Task<Result<()>> {
8248 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8249 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8250
8251 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8252 *settings_changed_tx.borrow_mut() = ();
8253 });
8254
8255 let mut joint_future =
8256 futures::stream::select(settings_changed_rx, external_refresh_requests);
8257 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8258 // - 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).
8259 // - 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.
8260 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8261 // - 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,
8262 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8263 cx.spawn(async move |this, cx| {
8264 while let Some(()) = joint_future.next().await {
8265 this.update(cx, |this, cx| {
8266 this.refresh_server_tree(cx);
8267 })
8268 .ok();
8269
8270 Self::refresh_workspace_configurations(&this, cx).await;
8271 }
8272
8273 drop(settings_observation);
8274 anyhow::Ok(())
8275 })
8276 }
8277
8278 pub fn running_language_servers_for_local_buffer<'a>(
8279 &'a self,
8280 buffer: &Buffer,
8281 cx: &mut App,
8282 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8283 let local = self.as_local();
8284 let language_server_ids = local
8285 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8286 .unwrap_or_default();
8287
8288 language_server_ids
8289 .into_iter()
8290 .filter_map(
8291 move |server_id| match local?.language_servers.get(&server_id)? {
8292 LanguageServerState::Running {
8293 adapter, server, ..
8294 } => Some((adapter, server)),
8295 _ => None,
8296 },
8297 )
8298 }
8299
8300 pub fn language_servers_for_local_buffer(
8301 &self,
8302 buffer: &Buffer,
8303 cx: &mut App,
8304 ) -> Vec<LanguageServerId> {
8305 let local = self.as_local();
8306 local
8307 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8308 .unwrap_or_default()
8309 }
8310
8311 pub fn language_server_for_local_buffer<'a>(
8312 &'a self,
8313 buffer: &'a Buffer,
8314 server_id: LanguageServerId,
8315 cx: &'a mut App,
8316 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8317 self.as_local()?
8318 .language_servers_for_buffer(buffer, cx)
8319 .find(|(_, s)| s.server_id() == server_id)
8320 }
8321
8322 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8323 self.diagnostic_summaries.remove(&id_to_remove);
8324 if let Some(local) = self.as_local_mut() {
8325 let to_remove = local.remove_worktree(id_to_remove, cx);
8326 for server in to_remove {
8327 self.language_server_statuses.remove(&server);
8328 }
8329 }
8330 }
8331
8332 pub fn shared(
8333 &mut self,
8334 project_id: u64,
8335 downstream_client: AnyProtoClient,
8336 _: &mut Context<Self>,
8337 ) {
8338 self.downstream_client = Some((downstream_client.clone(), project_id));
8339
8340 for (server_id, status) in &self.language_server_statuses {
8341 if let Some(server) = self.language_server_for_id(*server_id) {
8342 downstream_client
8343 .send(proto::StartLanguageServer {
8344 project_id,
8345 server: Some(proto::LanguageServer {
8346 id: server_id.to_proto(),
8347 name: status.name.to_string(),
8348 worktree_id: status.worktree.map(|id| id.to_proto()),
8349 }),
8350 capabilities: serde_json::to_string(&server.capabilities())
8351 .expect("serializing server LSP capabilities"),
8352 })
8353 .log_err();
8354 }
8355 }
8356 }
8357
8358 pub fn disconnected_from_host(&mut self) {
8359 self.downstream_client.take();
8360 }
8361
8362 pub fn disconnected_from_ssh_remote(&mut self) {
8363 if let LspStoreMode::Remote(RemoteLspStore {
8364 upstream_client, ..
8365 }) = &mut self.mode
8366 {
8367 upstream_client.take();
8368 }
8369 }
8370
8371 pub(crate) fn set_language_server_statuses_from_proto(
8372 &mut self,
8373 project: WeakEntity<Project>,
8374 language_servers: Vec<proto::LanguageServer>,
8375 server_capabilities: Vec<String>,
8376 cx: &mut Context<Self>,
8377 ) {
8378 let lsp_logs = cx
8379 .try_global::<GlobalLogStore>()
8380 .map(|lsp_store| lsp_store.0.clone());
8381
8382 self.language_server_statuses = language_servers
8383 .into_iter()
8384 .zip(server_capabilities)
8385 .map(|(server, server_capabilities)| {
8386 let server_id = LanguageServerId(server.id as usize);
8387 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8388 self.lsp_server_capabilities
8389 .insert(server_id, server_capabilities);
8390 }
8391
8392 let name = LanguageServerName::from_proto(server.name);
8393 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8394
8395 if let Some(lsp_logs) = &lsp_logs {
8396 lsp_logs.update(cx, |lsp_logs, cx| {
8397 lsp_logs.add_language_server(
8398 // Only remote clients get their language servers set from proto
8399 LanguageServerKind::Remote {
8400 project: project.clone(),
8401 },
8402 server_id,
8403 Some(name.clone()),
8404 worktree,
8405 None,
8406 cx,
8407 );
8408 });
8409 }
8410
8411 (
8412 server_id,
8413 LanguageServerStatus {
8414 name,
8415 server_version: None,
8416 pending_work: Default::default(),
8417 has_pending_diagnostic_updates: false,
8418 progress_tokens: Default::default(),
8419 worktree,
8420 binary: None,
8421 configuration: None,
8422 workspace_folders: BTreeSet::new(),
8423 },
8424 )
8425 })
8426 .collect();
8427 }
8428
8429 #[cfg(test)]
8430 pub fn update_diagnostic_entries(
8431 &mut self,
8432 server_id: LanguageServerId,
8433 abs_path: PathBuf,
8434 result_id: Option<SharedString>,
8435 version: Option<i32>,
8436 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8437 cx: &mut Context<Self>,
8438 ) -> anyhow::Result<()> {
8439 self.merge_diagnostic_entries(
8440 vec![DocumentDiagnosticsUpdate {
8441 diagnostics: DocumentDiagnostics {
8442 diagnostics,
8443 document_abs_path: abs_path,
8444 version,
8445 },
8446 result_id,
8447 server_id,
8448 disk_based_sources: Cow::Borrowed(&[]),
8449 registration_id: None,
8450 }],
8451 |_, _, _| false,
8452 cx,
8453 )?;
8454 Ok(())
8455 }
8456
8457 pub fn merge_diagnostic_entries<'a>(
8458 &mut self,
8459 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8460 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8461 cx: &mut Context<Self>,
8462 ) -> anyhow::Result<()> {
8463 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8464 let mut updated_diagnostics_paths = HashMap::default();
8465 for mut update in diagnostic_updates {
8466 let abs_path = &update.diagnostics.document_abs_path;
8467 let server_id = update.server_id;
8468 let Some((worktree, relative_path)) =
8469 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8470 else {
8471 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8472 return Ok(());
8473 };
8474
8475 let worktree_id = worktree.read(cx).id();
8476 let project_path = ProjectPath {
8477 worktree_id,
8478 path: relative_path,
8479 };
8480
8481 let document_uri = lsp::Uri::from_file_path(abs_path)
8482 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8483 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8484 let snapshot = buffer_handle.read(cx).snapshot();
8485 let buffer = buffer_handle.read(cx);
8486 let reused_diagnostics = buffer
8487 .buffer_diagnostics(Some(server_id))
8488 .iter()
8489 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8490 .map(|v| {
8491 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8492 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8493 DiagnosticEntry {
8494 range: start..end,
8495 diagnostic: v.diagnostic.clone(),
8496 }
8497 })
8498 .collect::<Vec<_>>();
8499
8500 self.as_local_mut()
8501 .context("cannot merge diagnostics on a remote LspStore")?
8502 .update_buffer_diagnostics(
8503 &buffer_handle,
8504 server_id,
8505 Some(update.registration_id),
8506 update.result_id,
8507 update.diagnostics.version,
8508 update.diagnostics.diagnostics.clone(),
8509 reused_diagnostics.clone(),
8510 cx,
8511 )?;
8512
8513 update.diagnostics.diagnostics.extend(reused_diagnostics);
8514 } else if let Some(local) = self.as_local() {
8515 let reused_diagnostics = local
8516 .diagnostics
8517 .get(&worktree_id)
8518 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8519 .and_then(|diagnostics_by_server_id| {
8520 diagnostics_by_server_id
8521 .binary_search_by_key(&server_id, |e| e.0)
8522 .ok()
8523 .map(|ix| &diagnostics_by_server_id[ix].1)
8524 })
8525 .into_iter()
8526 .flatten()
8527 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8528
8529 update
8530 .diagnostics
8531 .diagnostics
8532 .extend(reused_diagnostics.cloned());
8533 }
8534
8535 let updated = worktree.update(cx, |worktree, cx| {
8536 self.update_worktree_diagnostics(
8537 worktree.id(),
8538 server_id,
8539 project_path.path.clone(),
8540 update.diagnostics.diagnostics,
8541 cx,
8542 )
8543 })?;
8544 match updated {
8545 ControlFlow::Continue(new_summary) => {
8546 if let Some((project_id, new_summary)) = new_summary {
8547 match &mut diagnostics_summary {
8548 Some(diagnostics_summary) => {
8549 diagnostics_summary
8550 .more_summaries
8551 .push(proto::DiagnosticSummary {
8552 path: project_path.path.as_ref().to_proto(),
8553 language_server_id: server_id.0 as u64,
8554 error_count: new_summary.error_count,
8555 warning_count: new_summary.warning_count,
8556 })
8557 }
8558 None => {
8559 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8560 project_id,
8561 worktree_id: worktree_id.to_proto(),
8562 summary: Some(proto::DiagnosticSummary {
8563 path: project_path.path.as_ref().to_proto(),
8564 language_server_id: server_id.0 as u64,
8565 error_count: new_summary.error_count,
8566 warning_count: new_summary.warning_count,
8567 }),
8568 more_summaries: Vec::new(),
8569 })
8570 }
8571 }
8572 }
8573 updated_diagnostics_paths
8574 .entry(server_id)
8575 .or_insert_with(Vec::new)
8576 .push(project_path);
8577 }
8578 ControlFlow::Break(()) => {}
8579 }
8580 }
8581
8582 if let Some((diagnostics_summary, (downstream_client, _))) =
8583 diagnostics_summary.zip(self.downstream_client.as_ref())
8584 {
8585 downstream_client.send(diagnostics_summary).log_err();
8586 }
8587 for (server_id, paths) in updated_diagnostics_paths {
8588 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8589 }
8590 Ok(())
8591 }
8592
8593 fn update_worktree_diagnostics(
8594 &mut self,
8595 worktree_id: WorktreeId,
8596 server_id: LanguageServerId,
8597 path_in_worktree: Arc<RelPath>,
8598 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8599 _: &mut Context<Worktree>,
8600 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8601 let local = match &mut self.mode {
8602 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8603 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8604 };
8605
8606 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8607 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8608 let summaries_by_server_id = summaries_for_tree
8609 .entry(path_in_worktree.clone())
8610 .or_default();
8611
8612 let old_summary = summaries_by_server_id
8613 .remove(&server_id)
8614 .unwrap_or_default();
8615
8616 let new_summary = DiagnosticSummary::new(&diagnostics);
8617 if diagnostics.is_empty() {
8618 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8619 {
8620 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8621 diagnostics_by_server_id.remove(ix);
8622 }
8623 if diagnostics_by_server_id.is_empty() {
8624 diagnostics_for_tree.remove(&path_in_worktree);
8625 }
8626 }
8627 } else {
8628 summaries_by_server_id.insert(server_id, new_summary);
8629 let diagnostics_by_server_id = diagnostics_for_tree
8630 .entry(path_in_worktree.clone())
8631 .or_default();
8632 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8633 Ok(ix) => {
8634 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8635 }
8636 Err(ix) => {
8637 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8638 }
8639 }
8640 }
8641
8642 if !old_summary.is_empty() || !new_summary.is_empty() {
8643 if let Some((_, project_id)) = &self.downstream_client {
8644 Ok(ControlFlow::Continue(Some((
8645 *project_id,
8646 proto::DiagnosticSummary {
8647 path: path_in_worktree.to_proto(),
8648 language_server_id: server_id.0 as u64,
8649 error_count: new_summary.error_count as u32,
8650 warning_count: new_summary.warning_count as u32,
8651 },
8652 ))))
8653 } else {
8654 Ok(ControlFlow::Continue(None))
8655 }
8656 } else {
8657 Ok(ControlFlow::Break(()))
8658 }
8659 }
8660
8661 pub fn open_buffer_for_symbol(
8662 &mut self,
8663 symbol: &Symbol,
8664 cx: &mut Context<Self>,
8665 ) -> Task<Result<Entity<Buffer>>> {
8666 if let Some((client, project_id)) = self.upstream_client() {
8667 let request = client.request(proto::OpenBufferForSymbol {
8668 project_id,
8669 symbol: Some(Self::serialize_symbol(symbol)),
8670 });
8671 cx.spawn(async move |this, cx| {
8672 let response = request.await?;
8673 let buffer_id = BufferId::new(response.buffer_id)?;
8674 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8675 .await
8676 })
8677 } else if let Some(local) = self.as_local() {
8678 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8679 seed.worktree_id == symbol.source_worktree_id
8680 && state.id == symbol.source_language_server_id
8681 && symbol.language_server_name == seed.name
8682 });
8683 if !is_valid {
8684 return Task::ready(Err(anyhow!(
8685 "language server for worktree and language not found"
8686 )));
8687 };
8688
8689 let symbol_abs_path = match &symbol.path {
8690 SymbolLocation::InProject(project_path) => self
8691 .worktree_store
8692 .read(cx)
8693 .absolutize(&project_path, cx)
8694 .context("no such worktree"),
8695 SymbolLocation::OutsideProject {
8696 abs_path,
8697 signature: _,
8698 } => Ok(abs_path.to_path_buf()),
8699 };
8700 let symbol_abs_path = match symbol_abs_path {
8701 Ok(abs_path) => abs_path,
8702 Err(err) => return Task::ready(Err(err)),
8703 };
8704 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8705 uri
8706 } else {
8707 return Task::ready(Err(anyhow!("invalid symbol path")));
8708 };
8709
8710 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8711 } else {
8712 Task::ready(Err(anyhow!("no upstream client or local store")))
8713 }
8714 }
8715
8716 pub(crate) fn open_local_buffer_via_lsp(
8717 &mut self,
8718 abs_path: lsp::Uri,
8719 language_server_id: LanguageServerId,
8720 cx: &mut Context<Self>,
8721 ) -> Task<Result<Entity<Buffer>>> {
8722 cx.spawn(async move |lsp_store, cx| {
8723 // Escape percent-encoded string.
8724 let current_scheme = abs_path.scheme().to_owned();
8725 // Uri is immutable, so we can't modify the scheme
8726
8727 let abs_path = abs_path
8728 .to_file_path()
8729 .map_err(|()| anyhow!("can't convert URI to path"))?;
8730 let p = abs_path.clone();
8731 let yarn_worktree = lsp_store
8732 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8733 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8734 cx.spawn(async move |this, cx| {
8735 let t = this
8736 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8737 .ok()?;
8738 t.await
8739 })
8740 }),
8741 None => Task::ready(None),
8742 })?
8743 .await;
8744 let (worktree_root_target, known_relative_path) =
8745 if let Some((zip_root, relative_path)) = yarn_worktree {
8746 (zip_root, Some(relative_path))
8747 } else {
8748 (Arc::<Path>::from(abs_path.as_path()), None)
8749 };
8750 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8751 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8752 worktree_store.find_worktree(&worktree_root_target, cx)
8753 })
8754 })?;
8755 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8756 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8757 (result.0, relative_path, None)
8758 } else {
8759 let worktree = lsp_store
8760 .update(cx, |lsp_store, cx| {
8761 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8762 worktree_store.create_worktree(&worktree_root_target, false, cx)
8763 })
8764 })?
8765 .await?;
8766 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8767 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8768 lsp_store
8769 .update(cx, |lsp_store, cx| {
8770 if let Some(local) = lsp_store.as_local_mut() {
8771 local.register_language_server_for_invisible_worktree(
8772 &worktree,
8773 language_server_id,
8774 cx,
8775 )
8776 }
8777 match lsp_store.language_server_statuses.get(&language_server_id) {
8778 Some(status) => status.worktree,
8779 None => None,
8780 }
8781 })
8782 .ok()
8783 .flatten()
8784 .zip(Some(worktree_root.clone()))
8785 } else {
8786 None
8787 };
8788 let relative_path = if let Some(known_path) = known_relative_path {
8789 known_path
8790 } else {
8791 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8792 .into_arc()
8793 };
8794 (worktree, relative_path, source_ws)
8795 };
8796 let project_path = ProjectPath {
8797 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8798 path: relative_path,
8799 };
8800 let buffer = lsp_store
8801 .update(cx, |lsp_store, cx| {
8802 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8803 buffer_store.open_buffer(project_path, cx)
8804 })
8805 })?
8806 .await?;
8807 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8808 if let Some((source_ws, worktree_root)) = source_ws {
8809 buffer.update(cx, |buffer, cx| {
8810 let settings = WorktreeSettings::get(
8811 Some(
8812 (&ProjectPath {
8813 worktree_id: source_ws,
8814 path: Arc::from(RelPath::empty()),
8815 })
8816 .into(),
8817 ),
8818 cx,
8819 );
8820 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8821 if is_read_only {
8822 buffer.set_capability(Capability::ReadOnly, cx);
8823 }
8824 });
8825 }
8826 Ok(buffer)
8827 })
8828 }
8829
8830 fn request_multiple_lsp_locally<P, R>(
8831 &mut self,
8832 buffer: &Entity<Buffer>,
8833 position: Option<P>,
8834 request: R,
8835 cx: &mut Context<Self>,
8836 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8837 where
8838 P: ToOffset,
8839 R: LspCommand + Clone,
8840 <R::LspRequest as lsp::request::Request>::Result: Send,
8841 <R::LspRequest as lsp::request::Request>::Params: Send,
8842 {
8843 let Some(local) = self.as_local() else {
8844 return Task::ready(Vec::new());
8845 };
8846
8847 let snapshot = buffer.read(cx).snapshot();
8848 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8849
8850 let server_ids = buffer.update(cx, |buffer, cx| {
8851 local
8852 .language_servers_for_buffer(buffer, cx)
8853 .filter(|(adapter, _)| {
8854 scope
8855 .as_ref()
8856 .map(|scope| scope.language_allowed(&adapter.name))
8857 .unwrap_or(true)
8858 })
8859 .map(|(_, server)| server.server_id())
8860 .filter(|server_id| {
8861 self.as_local().is_none_or(|local| {
8862 local
8863 .buffers_opened_in_servers
8864 .get(&snapshot.remote_id())
8865 .is_some_and(|servers| servers.contains(server_id))
8866 })
8867 })
8868 .collect::<Vec<_>>()
8869 });
8870
8871 let mut response_results = server_ids
8872 .into_iter()
8873 .map(|server_id| {
8874 let task = self.request_lsp(
8875 buffer.clone(),
8876 LanguageServerToQuery::Other(server_id),
8877 request.clone(),
8878 cx,
8879 );
8880 async move { (server_id, task.await) }
8881 })
8882 .collect::<FuturesUnordered<_>>();
8883
8884 cx.background_spawn(async move {
8885 let mut responses = Vec::with_capacity(response_results.len());
8886 while let Some((server_id, response_result)) = response_results.next().await {
8887 match response_result {
8888 Ok(response) => responses.push((server_id, response)),
8889 // rust-analyzer likes to error with this when its still loading up
8890 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8891 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8892 }
8893 }
8894 responses
8895 })
8896 }
8897
8898 async fn handle_lsp_get_completions(
8899 this: Entity<Self>,
8900 envelope: TypedEnvelope<proto::GetCompletions>,
8901 mut cx: AsyncApp,
8902 ) -> Result<proto::GetCompletionsResponse> {
8903 let sender_id = envelope.original_sender_id().unwrap_or_default();
8904
8905 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8906 let buffer_handle = this.update(&mut cx, |this, cx| {
8907 this.buffer_store.read(cx).get_existing(buffer_id)
8908 })?;
8909 let request = GetCompletions::from_proto(
8910 envelope.payload,
8911 this.clone(),
8912 buffer_handle.clone(),
8913 cx.clone(),
8914 )
8915 .await?;
8916
8917 let server_to_query = match request.server_id {
8918 Some(server_id) => LanguageServerToQuery::Other(server_id),
8919 None => LanguageServerToQuery::FirstCapable,
8920 };
8921
8922 let response = this
8923 .update(&mut cx, |this, cx| {
8924 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8925 })
8926 .await?;
8927 this.update(&mut cx, |this, cx| {
8928 Ok(GetCompletions::response_to_proto(
8929 response,
8930 this,
8931 sender_id,
8932 &buffer_handle.read(cx).version(),
8933 cx,
8934 ))
8935 })
8936 }
8937
8938 async fn handle_lsp_command<T: LspCommand>(
8939 this: Entity<Self>,
8940 envelope: TypedEnvelope<T::ProtoRequest>,
8941 mut cx: AsyncApp,
8942 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8943 where
8944 <T::LspRequest as lsp::request::Request>::Params: Send,
8945 <T::LspRequest as lsp::request::Request>::Result: Send,
8946 {
8947 let sender_id = envelope.original_sender_id().unwrap_or_default();
8948 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8949 let buffer_handle = this.update(&mut cx, |this, cx| {
8950 this.buffer_store.read(cx).get_existing(buffer_id)
8951 })?;
8952 let request = T::from_proto(
8953 envelope.payload,
8954 this.clone(),
8955 buffer_handle.clone(),
8956 cx.clone(),
8957 )
8958 .await?;
8959 let response = this
8960 .update(&mut cx, |this, cx| {
8961 this.request_lsp(
8962 buffer_handle.clone(),
8963 LanguageServerToQuery::FirstCapable,
8964 request,
8965 cx,
8966 )
8967 })
8968 .await?;
8969 this.update(&mut cx, |this, cx| {
8970 Ok(T::response_to_proto(
8971 response,
8972 this,
8973 sender_id,
8974 &buffer_handle.read(cx).version(),
8975 cx,
8976 ))
8977 })
8978 }
8979
8980 async fn handle_lsp_query(
8981 lsp_store: Entity<Self>,
8982 envelope: TypedEnvelope<proto::LspQuery>,
8983 mut cx: AsyncApp,
8984 ) -> Result<proto::Ack> {
8985 use proto::lsp_query::Request;
8986 let sender_id = envelope.original_sender_id().unwrap_or_default();
8987 let lsp_query = envelope.payload;
8988 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8989 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8990 match lsp_query.request.context("invalid LSP query request")? {
8991 Request::GetReferences(get_references) => {
8992 let position = get_references.position.clone().and_then(deserialize_anchor);
8993 Self::query_lsp_locally::<GetReferences>(
8994 lsp_store,
8995 server_id,
8996 sender_id,
8997 lsp_request_id,
8998 get_references,
8999 position,
9000 &mut cx,
9001 )
9002 .await?;
9003 }
9004 Request::GetDocumentColor(get_document_color) => {
9005 Self::query_lsp_locally::<GetDocumentColor>(
9006 lsp_store,
9007 server_id,
9008 sender_id,
9009 lsp_request_id,
9010 get_document_color,
9011 None,
9012 &mut cx,
9013 )
9014 .await?;
9015 }
9016 Request::GetHover(get_hover) => {
9017 let position = get_hover.position.clone().and_then(deserialize_anchor);
9018 Self::query_lsp_locally::<GetHover>(
9019 lsp_store,
9020 server_id,
9021 sender_id,
9022 lsp_request_id,
9023 get_hover,
9024 position,
9025 &mut cx,
9026 )
9027 .await?;
9028 }
9029 Request::GetCodeActions(get_code_actions) => {
9030 Self::query_lsp_locally::<GetCodeActions>(
9031 lsp_store,
9032 server_id,
9033 sender_id,
9034 lsp_request_id,
9035 get_code_actions,
9036 None,
9037 &mut cx,
9038 )
9039 .await?;
9040 }
9041 Request::GetSignatureHelp(get_signature_help) => {
9042 let position = get_signature_help
9043 .position
9044 .clone()
9045 .and_then(deserialize_anchor);
9046 Self::query_lsp_locally::<GetSignatureHelp>(
9047 lsp_store,
9048 server_id,
9049 sender_id,
9050 lsp_request_id,
9051 get_signature_help,
9052 position,
9053 &mut cx,
9054 )
9055 .await?;
9056 }
9057 Request::GetCodeLens(get_code_lens) => {
9058 Self::query_lsp_locally::<GetCodeLens>(
9059 lsp_store,
9060 server_id,
9061 sender_id,
9062 lsp_request_id,
9063 get_code_lens,
9064 None,
9065 &mut cx,
9066 )
9067 .await?;
9068 }
9069 Request::GetDefinition(get_definition) => {
9070 let position = get_definition.position.clone().and_then(deserialize_anchor);
9071 Self::query_lsp_locally::<GetDefinitions>(
9072 lsp_store,
9073 server_id,
9074 sender_id,
9075 lsp_request_id,
9076 get_definition,
9077 position,
9078 &mut cx,
9079 )
9080 .await?;
9081 }
9082 Request::GetDeclaration(get_declaration) => {
9083 let position = get_declaration
9084 .position
9085 .clone()
9086 .and_then(deserialize_anchor);
9087 Self::query_lsp_locally::<GetDeclarations>(
9088 lsp_store,
9089 server_id,
9090 sender_id,
9091 lsp_request_id,
9092 get_declaration,
9093 position,
9094 &mut cx,
9095 )
9096 .await?;
9097 }
9098 Request::GetTypeDefinition(get_type_definition) => {
9099 let position = get_type_definition
9100 .position
9101 .clone()
9102 .and_then(deserialize_anchor);
9103 Self::query_lsp_locally::<GetTypeDefinitions>(
9104 lsp_store,
9105 server_id,
9106 sender_id,
9107 lsp_request_id,
9108 get_type_definition,
9109 position,
9110 &mut cx,
9111 )
9112 .await?;
9113 }
9114 Request::GetImplementation(get_implementation) => {
9115 let position = get_implementation
9116 .position
9117 .clone()
9118 .and_then(deserialize_anchor);
9119 Self::query_lsp_locally::<GetImplementations>(
9120 lsp_store,
9121 server_id,
9122 sender_id,
9123 lsp_request_id,
9124 get_implementation,
9125 position,
9126 &mut cx,
9127 )
9128 .await?;
9129 }
9130 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9131 let buffer_id = BufferId::new(get_document_diagnostics.buffer_id())?;
9132 let version = deserialize_version(get_document_diagnostics.buffer_version());
9133 let buffer = lsp_store.update(&mut cx, |this, cx| {
9134 this.buffer_store.read(cx).get_existing(buffer_id)
9135 })?;
9136 buffer
9137 .update(&mut cx, |buffer, _| {
9138 buffer.wait_for_version(version.clone())
9139 })
9140 .await?;
9141 lsp_store.update(&mut cx, |lsp_store, cx| {
9142 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9143 let key = LspKey {
9144 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9145 server_queried: server_id,
9146 };
9147 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9148 ) {
9149 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9150 lsp_requests.clear();
9151 };
9152 }
9153
9154 let existing_queries = lsp_data.lsp_requests.entry(key).or_default();
9155 existing_queries.insert(
9156 lsp_request_id,
9157 cx.spawn(async move |lsp_store, cx| {
9158 let diagnostics_pull = lsp_store.update(cx, |lsp_store, cx| {
9159 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9160 });
9161 if let Ok(diagnostics_pull) = diagnostics_pull {
9162 match diagnostics_pull.await {
9163 Ok(()) => {}
9164 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9165 };
9166 }
9167 }),
9168 );
9169 });
9170 }
9171 Request::InlayHints(inlay_hints) => {
9172 let query_start = inlay_hints
9173 .start
9174 .clone()
9175 .and_then(deserialize_anchor)
9176 .context("invalid inlay hints range start")?;
9177 let query_end = inlay_hints
9178 .end
9179 .clone()
9180 .and_then(deserialize_anchor)
9181 .context("invalid inlay hints range end")?;
9182 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9183 &lsp_store,
9184 server_id,
9185 lsp_request_id,
9186 &inlay_hints,
9187 query_start..query_end,
9188 &mut cx,
9189 )
9190 .await
9191 .context("preparing inlay hints request")?;
9192 Self::query_lsp_locally::<InlayHints>(
9193 lsp_store,
9194 server_id,
9195 sender_id,
9196 lsp_request_id,
9197 inlay_hints,
9198 None,
9199 &mut cx,
9200 )
9201 .await
9202 .context("querying for inlay hints")?
9203 }
9204 }
9205 Ok(proto::Ack {})
9206 }
9207
9208 async fn handle_lsp_query_response(
9209 lsp_store: Entity<Self>,
9210 envelope: TypedEnvelope<proto::LspQueryResponse>,
9211 cx: AsyncApp,
9212 ) -> Result<()> {
9213 lsp_store.read_with(&cx, |lsp_store, _| {
9214 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9215 upstream_client.handle_lsp_response(envelope.clone());
9216 }
9217 });
9218 Ok(())
9219 }
9220
9221 async fn handle_apply_code_action(
9222 this: Entity<Self>,
9223 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9224 mut cx: AsyncApp,
9225 ) -> Result<proto::ApplyCodeActionResponse> {
9226 let sender_id = envelope.original_sender_id().unwrap_or_default();
9227 let action =
9228 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9229 let apply_code_action = this.update(&mut cx, |this, cx| {
9230 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9231 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9232 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9233 })?;
9234
9235 let project_transaction = apply_code_action.await?;
9236 let project_transaction = this.update(&mut cx, |this, cx| {
9237 this.buffer_store.update(cx, |buffer_store, cx| {
9238 buffer_store.serialize_project_transaction_for_peer(
9239 project_transaction,
9240 sender_id,
9241 cx,
9242 )
9243 })
9244 });
9245 Ok(proto::ApplyCodeActionResponse {
9246 transaction: Some(project_transaction),
9247 })
9248 }
9249
9250 async fn handle_register_buffer_with_language_servers(
9251 this: Entity<Self>,
9252 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9253 mut cx: AsyncApp,
9254 ) -> Result<proto::Ack> {
9255 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9256 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9257 this.update(&mut cx, |this, cx| {
9258 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9259 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9260 project_id: upstream_project_id,
9261 buffer_id: buffer_id.to_proto(),
9262 only_servers: envelope.payload.only_servers,
9263 });
9264 }
9265
9266 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9267 anyhow::bail!("buffer is not open");
9268 };
9269
9270 let handle = this.register_buffer_with_language_servers(
9271 &buffer,
9272 envelope
9273 .payload
9274 .only_servers
9275 .into_iter()
9276 .filter_map(|selector| {
9277 Some(match selector.selector? {
9278 proto::language_server_selector::Selector::ServerId(server_id) => {
9279 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9280 }
9281 proto::language_server_selector::Selector::Name(name) => {
9282 LanguageServerSelector::Name(LanguageServerName(
9283 SharedString::from(name),
9284 ))
9285 }
9286 })
9287 })
9288 .collect(),
9289 false,
9290 cx,
9291 );
9292 this.buffer_store().update(cx, |buffer_store, _| {
9293 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9294 });
9295
9296 Ok(())
9297 })?;
9298 Ok(proto::Ack {})
9299 }
9300
9301 async fn handle_rename_project_entry(
9302 this: Entity<Self>,
9303 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9304 mut cx: AsyncApp,
9305 ) -> Result<proto::ProjectEntryResponse> {
9306 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9307 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9308 let new_path =
9309 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9310
9311 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9312 .update(&mut cx, |this, cx| {
9313 let (worktree, entry) = this
9314 .worktree_store
9315 .read(cx)
9316 .worktree_and_entry_for_id(entry_id, cx)?;
9317 let new_worktree = this
9318 .worktree_store
9319 .read(cx)
9320 .worktree_for_id(new_worktree_id, cx)?;
9321 Some((
9322 this.worktree_store.clone(),
9323 worktree,
9324 new_worktree,
9325 entry.clone(),
9326 ))
9327 })
9328 .context("worktree not found")?;
9329 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9330 (worktree.absolutize(&old_entry.path), worktree.id())
9331 });
9332 let new_abs_path =
9333 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9334
9335 let _transaction = Self::will_rename_entry(
9336 this.downgrade(),
9337 old_worktree_id,
9338 &old_abs_path,
9339 &new_abs_path,
9340 old_entry.is_dir(),
9341 cx.clone(),
9342 )
9343 .await;
9344 let response = WorktreeStore::handle_rename_project_entry(
9345 worktree_store,
9346 envelope.payload,
9347 cx.clone(),
9348 )
9349 .await;
9350 this.read_with(&cx, |this, _| {
9351 this.did_rename_entry(
9352 old_worktree_id,
9353 &old_abs_path,
9354 &new_abs_path,
9355 old_entry.is_dir(),
9356 );
9357 });
9358 response
9359 }
9360
9361 async fn handle_update_diagnostic_summary(
9362 this: Entity<Self>,
9363 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9364 mut cx: AsyncApp,
9365 ) -> Result<()> {
9366 this.update(&mut cx, |lsp_store, cx| {
9367 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9368 let mut updated_diagnostics_paths = HashMap::default();
9369 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9370 for message_summary in envelope
9371 .payload
9372 .summary
9373 .into_iter()
9374 .chain(envelope.payload.more_summaries)
9375 {
9376 let project_path = ProjectPath {
9377 worktree_id,
9378 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9379 };
9380 let path = project_path.path.clone();
9381 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9382 let summary = DiagnosticSummary {
9383 error_count: message_summary.error_count as usize,
9384 warning_count: message_summary.warning_count as usize,
9385 };
9386
9387 if summary.is_empty() {
9388 if let Some(worktree_summaries) =
9389 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9390 && let Some(summaries) = worktree_summaries.get_mut(&path)
9391 {
9392 summaries.remove(&server_id);
9393 if summaries.is_empty() {
9394 worktree_summaries.remove(&path);
9395 }
9396 }
9397 } else {
9398 lsp_store
9399 .diagnostic_summaries
9400 .entry(worktree_id)
9401 .or_default()
9402 .entry(path)
9403 .or_default()
9404 .insert(server_id, summary);
9405 }
9406
9407 if let Some((_, project_id)) = &lsp_store.downstream_client {
9408 match &mut diagnostics_summary {
9409 Some(diagnostics_summary) => {
9410 diagnostics_summary
9411 .more_summaries
9412 .push(proto::DiagnosticSummary {
9413 path: project_path.path.as_ref().to_proto(),
9414 language_server_id: server_id.0 as u64,
9415 error_count: summary.error_count as u32,
9416 warning_count: summary.warning_count as u32,
9417 })
9418 }
9419 None => {
9420 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9421 project_id: *project_id,
9422 worktree_id: worktree_id.to_proto(),
9423 summary: Some(proto::DiagnosticSummary {
9424 path: project_path.path.as_ref().to_proto(),
9425 language_server_id: server_id.0 as u64,
9426 error_count: summary.error_count as u32,
9427 warning_count: summary.warning_count as u32,
9428 }),
9429 more_summaries: Vec::new(),
9430 })
9431 }
9432 }
9433 }
9434 updated_diagnostics_paths
9435 .entry(server_id)
9436 .or_insert_with(Vec::new)
9437 .push(project_path);
9438 }
9439
9440 if let Some((diagnostics_summary, (downstream_client, _))) =
9441 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9442 {
9443 downstream_client.send(diagnostics_summary).log_err();
9444 }
9445 for (server_id, paths) in updated_diagnostics_paths {
9446 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9447 }
9448 Ok(())
9449 })
9450 }
9451
9452 async fn handle_start_language_server(
9453 lsp_store: Entity<Self>,
9454 envelope: TypedEnvelope<proto::StartLanguageServer>,
9455 mut cx: AsyncApp,
9456 ) -> Result<()> {
9457 let server = envelope.payload.server.context("invalid server")?;
9458 let server_capabilities =
9459 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9460 .with_context(|| {
9461 format!(
9462 "incorrect server capabilities {}",
9463 envelope.payload.capabilities
9464 )
9465 })?;
9466 lsp_store.update(&mut cx, |lsp_store, cx| {
9467 let server_id = LanguageServerId(server.id as usize);
9468 let server_name = LanguageServerName::from_proto(server.name.clone());
9469 lsp_store
9470 .lsp_server_capabilities
9471 .insert(server_id, server_capabilities);
9472 lsp_store.language_server_statuses.insert(
9473 server_id,
9474 LanguageServerStatus {
9475 name: server_name.clone(),
9476 server_version: None,
9477 pending_work: Default::default(),
9478 has_pending_diagnostic_updates: false,
9479 progress_tokens: Default::default(),
9480 worktree: server.worktree_id.map(WorktreeId::from_proto),
9481 binary: None,
9482 configuration: None,
9483 workspace_folders: BTreeSet::new(),
9484 },
9485 );
9486 cx.emit(LspStoreEvent::LanguageServerAdded(
9487 server_id,
9488 server_name,
9489 server.worktree_id.map(WorktreeId::from_proto),
9490 ));
9491 cx.notify();
9492 });
9493 Ok(())
9494 }
9495
9496 async fn handle_update_language_server(
9497 lsp_store: Entity<Self>,
9498 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9499 mut cx: AsyncApp,
9500 ) -> Result<()> {
9501 lsp_store.update(&mut cx, |lsp_store, cx| {
9502 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9503
9504 match envelope.payload.variant.context("invalid variant")? {
9505 proto::update_language_server::Variant::WorkStart(payload) => {
9506 lsp_store.on_lsp_work_start(
9507 language_server_id,
9508 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9509 .context("invalid progress token value")?,
9510 LanguageServerProgress {
9511 title: payload.title,
9512 is_disk_based_diagnostics_progress: false,
9513 is_cancellable: payload.is_cancellable.unwrap_or(false),
9514 message: payload.message,
9515 percentage: payload.percentage.map(|p| p as usize),
9516 last_update_at: cx.background_executor().now(),
9517 },
9518 cx,
9519 );
9520 }
9521 proto::update_language_server::Variant::WorkProgress(payload) => {
9522 lsp_store.on_lsp_work_progress(
9523 language_server_id,
9524 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9525 .context("invalid progress token value")?,
9526 LanguageServerProgress {
9527 title: None,
9528 is_disk_based_diagnostics_progress: false,
9529 is_cancellable: payload.is_cancellable.unwrap_or(false),
9530 message: payload.message,
9531 percentage: payload.percentage.map(|p| p as usize),
9532 last_update_at: cx.background_executor().now(),
9533 },
9534 cx,
9535 );
9536 }
9537
9538 proto::update_language_server::Variant::WorkEnd(payload) => {
9539 lsp_store.on_lsp_work_end(
9540 language_server_id,
9541 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9542 .context("invalid progress token value")?,
9543 cx,
9544 );
9545 }
9546
9547 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9548 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9549 }
9550
9551 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9552 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9553 }
9554
9555 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9556 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9557 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9558 cx.emit(LspStoreEvent::LanguageServerUpdate {
9559 language_server_id,
9560 name: envelope
9561 .payload
9562 .server_name
9563 .map(SharedString::new)
9564 .map(LanguageServerName),
9565 message: non_lsp,
9566 });
9567 }
9568 }
9569
9570 Ok(())
9571 })
9572 }
9573
9574 async fn handle_language_server_log(
9575 this: Entity<Self>,
9576 envelope: TypedEnvelope<proto::LanguageServerLog>,
9577 mut cx: AsyncApp,
9578 ) -> Result<()> {
9579 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9580 let log_type = envelope
9581 .payload
9582 .log_type
9583 .map(LanguageServerLogType::from_proto)
9584 .context("invalid language server log type")?;
9585
9586 let message = envelope.payload.message;
9587
9588 this.update(&mut cx, |_, cx| {
9589 cx.emit(LspStoreEvent::LanguageServerLog(
9590 language_server_id,
9591 log_type,
9592 message,
9593 ));
9594 });
9595 Ok(())
9596 }
9597
9598 async fn handle_lsp_ext_cancel_flycheck(
9599 lsp_store: Entity<Self>,
9600 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9601 cx: AsyncApp,
9602 ) -> Result<proto::Ack> {
9603 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9604 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9605 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9606 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9607 } else {
9608 None
9609 }
9610 });
9611 if let Some(task) = task {
9612 task.context("handling lsp ext cancel flycheck")?;
9613 }
9614
9615 Ok(proto::Ack {})
9616 }
9617
9618 async fn handle_lsp_ext_run_flycheck(
9619 lsp_store: Entity<Self>,
9620 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9621 mut cx: AsyncApp,
9622 ) -> Result<proto::Ack> {
9623 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9624 lsp_store.update(&mut cx, |lsp_store, cx| {
9625 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9626 let text_document = if envelope.payload.current_file_only {
9627 let buffer_id = envelope
9628 .payload
9629 .buffer_id
9630 .map(|id| BufferId::new(id))
9631 .transpose()?;
9632 buffer_id
9633 .and_then(|buffer_id| {
9634 lsp_store
9635 .buffer_store()
9636 .read(cx)
9637 .get(buffer_id)
9638 .and_then(|buffer| {
9639 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9640 })
9641 .map(|path| make_text_document_identifier(&path))
9642 })
9643 .transpose()?
9644 } else {
9645 None
9646 };
9647 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9648 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9649 )?;
9650 }
9651 anyhow::Ok(())
9652 })?;
9653
9654 Ok(proto::Ack {})
9655 }
9656
9657 async fn handle_lsp_ext_clear_flycheck(
9658 lsp_store: Entity<Self>,
9659 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9660 cx: AsyncApp,
9661 ) -> Result<proto::Ack> {
9662 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9663 lsp_store.read_with(&cx, |lsp_store, _| {
9664 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9665 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9666 } else {
9667 None
9668 }
9669 });
9670
9671 Ok(proto::Ack {})
9672 }
9673
9674 pub fn disk_based_diagnostics_started(
9675 &mut self,
9676 language_server_id: LanguageServerId,
9677 cx: &mut Context<Self>,
9678 ) {
9679 if let Some(language_server_status) =
9680 self.language_server_statuses.get_mut(&language_server_id)
9681 {
9682 language_server_status.has_pending_diagnostic_updates = true;
9683 }
9684
9685 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9686 cx.emit(LspStoreEvent::LanguageServerUpdate {
9687 language_server_id,
9688 name: self
9689 .language_server_adapter_for_id(language_server_id)
9690 .map(|adapter| adapter.name()),
9691 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9692 Default::default(),
9693 ),
9694 })
9695 }
9696
9697 pub fn disk_based_diagnostics_finished(
9698 &mut self,
9699 language_server_id: LanguageServerId,
9700 cx: &mut Context<Self>,
9701 ) {
9702 if let Some(language_server_status) =
9703 self.language_server_statuses.get_mut(&language_server_id)
9704 {
9705 language_server_status.has_pending_diagnostic_updates = false;
9706 }
9707
9708 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9709 cx.emit(LspStoreEvent::LanguageServerUpdate {
9710 language_server_id,
9711 name: self
9712 .language_server_adapter_for_id(language_server_id)
9713 .map(|adapter| adapter.name()),
9714 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9715 Default::default(),
9716 ),
9717 })
9718 }
9719
9720 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9721 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9722 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9723 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9724 // the language server might take some time to publish diagnostics.
9725 fn simulate_disk_based_diagnostics_events_if_needed(
9726 &mut self,
9727 language_server_id: LanguageServerId,
9728 cx: &mut Context<Self>,
9729 ) {
9730 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9731
9732 let Some(LanguageServerState::Running {
9733 simulate_disk_based_diagnostics_completion,
9734 adapter,
9735 ..
9736 }) = self
9737 .as_local_mut()
9738 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9739 else {
9740 return;
9741 };
9742
9743 if adapter.disk_based_diagnostics_progress_token.is_some() {
9744 return;
9745 }
9746
9747 let prev_task =
9748 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9749 cx.background_executor()
9750 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9751 .await;
9752
9753 this.update(cx, |this, cx| {
9754 this.disk_based_diagnostics_finished(language_server_id, cx);
9755
9756 if let Some(LanguageServerState::Running {
9757 simulate_disk_based_diagnostics_completion,
9758 ..
9759 }) = this.as_local_mut().and_then(|local_store| {
9760 local_store.language_servers.get_mut(&language_server_id)
9761 }) {
9762 *simulate_disk_based_diagnostics_completion = None;
9763 }
9764 })
9765 .ok();
9766 }));
9767
9768 if prev_task.is_none() {
9769 self.disk_based_diagnostics_started(language_server_id, cx);
9770 }
9771 }
9772
9773 pub fn language_server_statuses(
9774 &self,
9775 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9776 self.language_server_statuses
9777 .iter()
9778 .map(|(key, value)| (*key, value))
9779 }
9780
9781 pub(super) fn did_rename_entry(
9782 &self,
9783 worktree_id: WorktreeId,
9784 old_path: &Path,
9785 new_path: &Path,
9786 is_dir: bool,
9787 ) {
9788 maybe!({
9789 let local_store = self.as_local()?;
9790
9791 let old_uri = lsp::Uri::from_file_path(old_path)
9792 .ok()
9793 .map(|uri| uri.to_string())?;
9794 let new_uri = lsp::Uri::from_file_path(new_path)
9795 .ok()
9796 .map(|uri| uri.to_string())?;
9797
9798 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9799 let Some(filter) = local_store
9800 .language_server_paths_watched_for_rename
9801 .get(&language_server.server_id())
9802 else {
9803 continue;
9804 };
9805
9806 if filter.should_send_did_rename(&old_uri, is_dir) {
9807 language_server
9808 .notify::<DidRenameFiles>(RenameFilesParams {
9809 files: vec![FileRename {
9810 old_uri: old_uri.clone(),
9811 new_uri: new_uri.clone(),
9812 }],
9813 })
9814 .ok();
9815 }
9816 }
9817 Some(())
9818 });
9819 }
9820
9821 pub(super) fn will_rename_entry(
9822 this: WeakEntity<Self>,
9823 worktree_id: WorktreeId,
9824 old_path: &Path,
9825 new_path: &Path,
9826 is_dir: bool,
9827 cx: AsyncApp,
9828 ) -> Task<ProjectTransaction> {
9829 let old_uri = lsp::Uri::from_file_path(old_path)
9830 .ok()
9831 .map(|uri| uri.to_string());
9832 let new_uri = lsp::Uri::from_file_path(new_path)
9833 .ok()
9834 .map(|uri| uri.to_string());
9835 cx.spawn(async move |cx| {
9836 let mut tasks = vec![];
9837 this.update(cx, |this, cx| {
9838 let local_store = this.as_local()?;
9839 let old_uri = old_uri?;
9840 let new_uri = new_uri?;
9841 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9842 let Some(filter) = local_store
9843 .language_server_paths_watched_for_rename
9844 .get(&language_server.server_id())
9845 else {
9846 continue;
9847 };
9848
9849 if filter.should_send_will_rename(&old_uri, is_dir) {
9850 let apply_edit = cx.spawn({
9851 let old_uri = old_uri.clone();
9852 let new_uri = new_uri.clone();
9853 let language_server = language_server.clone();
9854 async move |this, cx| {
9855 let edit = language_server
9856 .request::<WillRenameFiles>(RenameFilesParams {
9857 files: vec![FileRename { old_uri, new_uri }],
9858 })
9859 .await
9860 .into_response()
9861 .context("will rename files")
9862 .log_err()
9863 .flatten()?;
9864
9865 let transaction = LocalLspStore::deserialize_workspace_edit(
9866 this.upgrade()?,
9867 edit,
9868 false,
9869 language_server.clone(),
9870 cx,
9871 )
9872 .await
9873 .ok()?;
9874 Some(transaction)
9875 }
9876 });
9877 tasks.push(apply_edit);
9878 }
9879 }
9880 Some(())
9881 })
9882 .ok()
9883 .flatten();
9884 let mut merged_transaction = ProjectTransaction::default();
9885 for task in tasks {
9886 // Await on tasks sequentially so that the order of application of edits is deterministic
9887 // (at least with regards to the order of registration of language servers)
9888 if let Some(transaction) = task.await {
9889 for (buffer, buffer_transaction) in transaction.0 {
9890 merged_transaction.0.insert(buffer, buffer_transaction);
9891 }
9892 }
9893 }
9894 merged_transaction
9895 })
9896 }
9897
9898 fn lsp_notify_abs_paths_changed(
9899 &mut self,
9900 server_id: LanguageServerId,
9901 changes: Vec<PathEvent>,
9902 ) {
9903 maybe!({
9904 let server = self.language_server_for_id(server_id)?;
9905 let changes = changes
9906 .into_iter()
9907 .filter_map(|event| {
9908 let typ = match event.kind? {
9909 PathEventKind::Created => lsp::FileChangeType::CREATED,
9910 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9911 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9912 };
9913 Some(lsp::FileEvent {
9914 uri: file_path_to_lsp_url(&event.path).log_err()?,
9915 typ,
9916 })
9917 })
9918 .collect::<Vec<_>>();
9919 if !changes.is_empty() {
9920 server
9921 .notify::<lsp::notification::DidChangeWatchedFiles>(
9922 lsp::DidChangeWatchedFilesParams { changes },
9923 )
9924 .ok();
9925 }
9926 Some(())
9927 });
9928 }
9929
9930 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9931 self.as_local()?.language_server_for_id(id)
9932 }
9933
9934 fn on_lsp_progress(
9935 &mut self,
9936 progress_params: lsp::ProgressParams,
9937 language_server_id: LanguageServerId,
9938 disk_based_diagnostics_progress_token: Option<String>,
9939 cx: &mut Context<Self>,
9940 ) {
9941 match progress_params.value {
9942 lsp::ProgressParamsValue::WorkDone(progress) => {
9943 self.handle_work_done_progress(
9944 progress,
9945 language_server_id,
9946 disk_based_diagnostics_progress_token,
9947 ProgressToken::from_lsp(progress_params.token),
9948 cx,
9949 );
9950 }
9951 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9952 let registration_id = match progress_params.token {
9953 lsp::NumberOrString::Number(_) => None,
9954 lsp::NumberOrString::String(token) => token
9955 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9956 .map(|(_, id)| id.to_owned()),
9957 };
9958 if let Some(LanguageServerState::Running {
9959 workspace_diagnostics_refresh_tasks,
9960 ..
9961 }) = self
9962 .as_local_mut()
9963 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9964 && let Some(workspace_diagnostics) =
9965 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9966 {
9967 workspace_diagnostics.progress_tx.try_send(()).ok();
9968 self.apply_workspace_diagnostic_report(
9969 language_server_id,
9970 report,
9971 registration_id.map(SharedString::from),
9972 cx,
9973 )
9974 }
9975 }
9976 }
9977 }
9978
9979 fn handle_work_done_progress(
9980 &mut self,
9981 progress: lsp::WorkDoneProgress,
9982 language_server_id: LanguageServerId,
9983 disk_based_diagnostics_progress_token: Option<String>,
9984 token: ProgressToken,
9985 cx: &mut Context<Self>,
9986 ) {
9987 let language_server_status =
9988 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9989 status
9990 } else {
9991 return;
9992 };
9993
9994 if !language_server_status.progress_tokens.contains(&token) {
9995 return;
9996 }
9997
9998 let is_disk_based_diagnostics_progress =
9999 if let (Some(disk_based_token), ProgressToken::String(token)) =
10000 (&disk_based_diagnostics_progress_token, &token)
10001 {
10002 token.starts_with(disk_based_token)
10003 } else {
10004 false
10005 };
10006
10007 match progress {
10008 lsp::WorkDoneProgress::Begin(report) => {
10009 if is_disk_based_diagnostics_progress {
10010 self.disk_based_diagnostics_started(language_server_id, cx);
10011 }
10012 self.on_lsp_work_start(
10013 language_server_id,
10014 token.clone(),
10015 LanguageServerProgress {
10016 title: Some(report.title),
10017 is_disk_based_diagnostics_progress,
10018 is_cancellable: report.cancellable.unwrap_or(false),
10019 message: report.message.clone(),
10020 percentage: report.percentage.map(|p| p as usize),
10021 last_update_at: cx.background_executor().now(),
10022 },
10023 cx,
10024 );
10025 }
10026 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10027 language_server_id,
10028 token,
10029 LanguageServerProgress {
10030 title: None,
10031 is_disk_based_diagnostics_progress,
10032 is_cancellable: report.cancellable.unwrap_or(false),
10033 message: report.message,
10034 percentage: report.percentage.map(|p| p as usize),
10035 last_update_at: cx.background_executor().now(),
10036 },
10037 cx,
10038 ),
10039 lsp::WorkDoneProgress::End(_) => {
10040 language_server_status.progress_tokens.remove(&token);
10041 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10042 if is_disk_based_diagnostics_progress {
10043 self.disk_based_diagnostics_finished(language_server_id, cx);
10044 }
10045 }
10046 }
10047 }
10048
10049 fn on_lsp_work_start(
10050 &mut self,
10051 language_server_id: LanguageServerId,
10052 token: ProgressToken,
10053 progress: LanguageServerProgress,
10054 cx: &mut Context<Self>,
10055 ) {
10056 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10057 status.pending_work.insert(token.clone(), progress.clone());
10058 cx.notify();
10059 }
10060 cx.emit(LspStoreEvent::LanguageServerUpdate {
10061 language_server_id,
10062 name: self
10063 .language_server_adapter_for_id(language_server_id)
10064 .map(|adapter| adapter.name()),
10065 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10066 token: Some(token.to_proto()),
10067 title: progress.title,
10068 message: progress.message,
10069 percentage: progress.percentage.map(|p| p as u32),
10070 is_cancellable: Some(progress.is_cancellable),
10071 }),
10072 })
10073 }
10074
10075 fn on_lsp_work_progress(
10076 &mut self,
10077 language_server_id: LanguageServerId,
10078 token: ProgressToken,
10079 progress: LanguageServerProgress,
10080 cx: &mut Context<Self>,
10081 ) {
10082 let mut did_update = false;
10083 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10084 match status.pending_work.entry(token.clone()) {
10085 btree_map::Entry::Vacant(entry) => {
10086 entry.insert(progress.clone());
10087 did_update = true;
10088 }
10089 btree_map::Entry::Occupied(mut entry) => {
10090 let entry = entry.get_mut();
10091 if (progress.last_update_at - entry.last_update_at)
10092 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10093 {
10094 entry.last_update_at = progress.last_update_at;
10095 if progress.message.is_some() {
10096 entry.message = progress.message.clone();
10097 }
10098 if progress.percentage.is_some() {
10099 entry.percentage = progress.percentage;
10100 }
10101 if progress.is_cancellable != entry.is_cancellable {
10102 entry.is_cancellable = progress.is_cancellable;
10103 }
10104 did_update = true;
10105 }
10106 }
10107 }
10108 }
10109
10110 if did_update {
10111 cx.emit(LspStoreEvent::LanguageServerUpdate {
10112 language_server_id,
10113 name: self
10114 .language_server_adapter_for_id(language_server_id)
10115 .map(|adapter| adapter.name()),
10116 message: proto::update_language_server::Variant::WorkProgress(
10117 proto::LspWorkProgress {
10118 token: Some(token.to_proto()),
10119 message: progress.message,
10120 percentage: progress.percentage.map(|p| p as u32),
10121 is_cancellable: Some(progress.is_cancellable),
10122 },
10123 ),
10124 })
10125 }
10126 }
10127
10128 fn on_lsp_work_end(
10129 &mut self,
10130 language_server_id: LanguageServerId,
10131 token: ProgressToken,
10132 cx: &mut Context<Self>,
10133 ) {
10134 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10135 if let Some(work) = status.pending_work.remove(&token)
10136 && !work.is_disk_based_diagnostics_progress
10137 {
10138 cx.emit(LspStoreEvent::RefreshInlayHints {
10139 server_id: language_server_id,
10140 request_id: None,
10141 });
10142 }
10143 cx.notify();
10144 }
10145
10146 cx.emit(LspStoreEvent::LanguageServerUpdate {
10147 language_server_id,
10148 name: self
10149 .language_server_adapter_for_id(language_server_id)
10150 .map(|adapter| adapter.name()),
10151 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10152 token: Some(token.to_proto()),
10153 }),
10154 })
10155 }
10156
10157 pub async fn handle_resolve_completion_documentation(
10158 this: Entity<Self>,
10159 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10160 mut cx: AsyncApp,
10161 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10162 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10163
10164 let completion = this
10165 .read_with(&cx, |this, cx| {
10166 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10167 let server = this
10168 .language_server_for_id(id)
10169 .with_context(|| format!("No language server {id}"))?;
10170
10171 anyhow::Ok(cx.background_spawn(async move {
10172 let can_resolve = server
10173 .capabilities()
10174 .completion_provider
10175 .as_ref()
10176 .and_then(|options| options.resolve_provider)
10177 .unwrap_or(false);
10178 if can_resolve {
10179 server
10180 .request::<lsp::request::ResolveCompletionItem>(lsp_completion)
10181 .await
10182 .into_response()
10183 .context("resolve completion item")
10184 } else {
10185 anyhow::Ok(lsp_completion)
10186 }
10187 }))
10188 })?
10189 .await?;
10190
10191 let mut documentation_is_markdown = false;
10192 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10193 let documentation = match completion.documentation {
10194 Some(lsp::Documentation::String(text)) => text,
10195
10196 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10197 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10198 value
10199 }
10200
10201 _ => String::new(),
10202 };
10203
10204 // If we have a new buffer_id, that means we're talking to a new client
10205 // and want to check for new text_edits in the completion too.
10206 let mut old_replace_start = None;
10207 let mut old_replace_end = None;
10208 let mut old_insert_start = None;
10209 let mut old_insert_end = None;
10210 let mut new_text = String::default();
10211 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10212 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10213 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10214 anyhow::Ok(buffer.read(cx).snapshot())
10215 })?;
10216
10217 if let Some(text_edit) = completion.text_edit.as_ref() {
10218 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10219
10220 if let Some(mut edit) = edit {
10221 LineEnding::normalize(&mut edit.new_text);
10222
10223 new_text = edit.new_text;
10224 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10225 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10226 if let Some(insert_range) = edit.insert_range {
10227 old_insert_start = Some(serialize_anchor(&insert_range.start));
10228 old_insert_end = Some(serialize_anchor(&insert_range.end));
10229 }
10230 }
10231 }
10232 }
10233
10234 Ok(proto::ResolveCompletionDocumentationResponse {
10235 documentation,
10236 documentation_is_markdown,
10237 old_replace_start,
10238 old_replace_end,
10239 new_text,
10240 lsp_completion,
10241 old_insert_start,
10242 old_insert_end,
10243 })
10244 }
10245
10246 async fn handle_on_type_formatting(
10247 this: Entity<Self>,
10248 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10249 mut cx: AsyncApp,
10250 ) -> Result<proto::OnTypeFormattingResponse> {
10251 let on_type_formatting = this.update(&mut cx, |this, cx| {
10252 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10253 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10254 let position = envelope
10255 .payload
10256 .position
10257 .and_then(deserialize_anchor)
10258 .context("invalid position")?;
10259 anyhow::Ok(this.apply_on_type_formatting(
10260 buffer,
10261 position,
10262 envelope.payload.trigger.clone(),
10263 cx,
10264 ))
10265 })?;
10266
10267 let transaction = on_type_formatting
10268 .await?
10269 .as_ref()
10270 .map(language::proto::serialize_transaction);
10271 Ok(proto::OnTypeFormattingResponse { transaction })
10272 }
10273
10274 async fn handle_refresh_inlay_hints(
10275 lsp_store: Entity<Self>,
10276 envelope: TypedEnvelope<proto::RefreshInlayHints>,
10277 mut cx: AsyncApp,
10278 ) -> Result<proto::Ack> {
10279 lsp_store.update(&mut cx, |_, cx| {
10280 cx.emit(LspStoreEvent::RefreshInlayHints {
10281 server_id: LanguageServerId::from_proto(envelope.payload.server_id),
10282 request_id: envelope.payload.request_id.map(|id| id as usize),
10283 });
10284 });
10285 Ok(proto::Ack {})
10286 }
10287
10288 async fn handle_pull_workspace_diagnostics(
10289 lsp_store: Entity<Self>,
10290 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10291 mut cx: AsyncApp,
10292 ) -> Result<proto::Ack> {
10293 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10294 lsp_store.update(&mut cx, |lsp_store, _| {
10295 lsp_store.pull_workspace_diagnostics(server_id);
10296 });
10297 Ok(proto::Ack {})
10298 }
10299
10300 async fn handle_get_color_presentation(
10301 lsp_store: Entity<Self>,
10302 envelope: TypedEnvelope<proto::GetColorPresentation>,
10303 mut cx: AsyncApp,
10304 ) -> Result<proto::GetColorPresentationResponse> {
10305 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10306 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10307 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10308 })?;
10309
10310 let color = envelope
10311 .payload
10312 .color
10313 .context("invalid color resolve request")?;
10314 let start = color
10315 .lsp_range_start
10316 .context("invalid color resolve request")?;
10317 let end = color
10318 .lsp_range_end
10319 .context("invalid color resolve request")?;
10320
10321 let color = DocumentColor {
10322 lsp_range: lsp::Range {
10323 start: point_to_lsp(PointUtf16::new(start.row, start.column)),
10324 end: point_to_lsp(PointUtf16::new(end.row, end.column)),
10325 },
10326 color: lsp::Color {
10327 red: color.red,
10328 green: color.green,
10329 blue: color.blue,
10330 alpha: color.alpha,
10331 },
10332 resolved: false,
10333 color_presentations: Vec::new(),
10334 };
10335 let resolved_color = lsp_store
10336 .update(&mut cx, |lsp_store, cx| {
10337 lsp_store.resolve_color_presentation(
10338 color,
10339 buffer.clone(),
10340 LanguageServerId(envelope.payload.server_id as usize),
10341 cx,
10342 )
10343 })
10344 .await
10345 .context("resolving color presentation")?;
10346
10347 Ok(proto::GetColorPresentationResponse {
10348 presentations: resolved_color
10349 .color_presentations
10350 .into_iter()
10351 .map(|presentation| proto::ColorPresentation {
10352 label: presentation.label.to_string(),
10353 text_edit: presentation.text_edit.map(serialize_lsp_edit),
10354 additional_text_edits: presentation
10355 .additional_text_edits
10356 .into_iter()
10357 .map(serialize_lsp_edit)
10358 .collect(),
10359 })
10360 .collect(),
10361 })
10362 }
10363
10364 async fn handle_resolve_inlay_hint(
10365 lsp_store: Entity<Self>,
10366 envelope: TypedEnvelope<proto::ResolveInlayHint>,
10367 mut cx: AsyncApp,
10368 ) -> Result<proto::ResolveInlayHintResponse> {
10369 let proto_hint = envelope
10370 .payload
10371 .hint
10372 .expect("incorrect protobuf resolve inlay hint message: missing the inlay hint");
10373 let hint = InlayHints::proto_to_project_hint(proto_hint)
10374 .context("resolved proto inlay hint conversion")?;
10375 let buffer = lsp_store.update(&mut cx, |lsp_store, cx| {
10376 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10377 lsp_store.buffer_store.read(cx).get_existing(buffer_id)
10378 })?;
10379 let response_hint = lsp_store
10380 .update(&mut cx, |lsp_store, cx| {
10381 lsp_store.resolve_inlay_hint(
10382 hint,
10383 buffer,
10384 LanguageServerId(envelope.payload.language_server_id as usize),
10385 cx,
10386 )
10387 })
10388 .await
10389 .context("inlay hints fetch")?;
10390 Ok(proto::ResolveInlayHintResponse {
10391 hint: Some(InlayHints::project_to_proto_hint(response_hint)),
10392 })
10393 }
10394
10395 async fn handle_refresh_code_lens(
10396 this: Entity<Self>,
10397 _: TypedEnvelope<proto::RefreshCodeLens>,
10398 mut cx: AsyncApp,
10399 ) -> Result<proto::Ack> {
10400 this.update(&mut cx, |_, cx| {
10401 cx.emit(LspStoreEvent::RefreshCodeLens);
10402 });
10403 Ok(proto::Ack {})
10404 }
10405
10406 async fn handle_open_buffer_for_symbol(
10407 this: Entity<Self>,
10408 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10409 mut cx: AsyncApp,
10410 ) -> Result<proto::OpenBufferForSymbolResponse> {
10411 let peer_id = envelope.original_sender_id().unwrap_or_default();
10412 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10413 let symbol = Self::deserialize_symbol(symbol)?;
10414 this.read_with(&cx, |this, _| {
10415 if let SymbolLocation::OutsideProject {
10416 abs_path,
10417 signature,
10418 } = &symbol.path
10419 {
10420 let new_signature = this.symbol_signature(&abs_path);
10421 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10422 }
10423 Ok(())
10424 })?;
10425 let buffer = this
10426 .update(&mut cx, |this, cx| {
10427 this.open_buffer_for_symbol(
10428 &Symbol {
10429 language_server_name: symbol.language_server_name,
10430 source_worktree_id: symbol.source_worktree_id,
10431 source_language_server_id: symbol.source_language_server_id,
10432 path: symbol.path,
10433 name: symbol.name,
10434 kind: symbol.kind,
10435 range: symbol.range,
10436 label: CodeLabel::default(),
10437 },
10438 cx,
10439 )
10440 })
10441 .await?;
10442
10443 this.update(&mut cx, |this, cx| {
10444 let is_private = buffer
10445 .read(cx)
10446 .file()
10447 .map(|f| f.is_private())
10448 .unwrap_or_default();
10449 if is_private {
10450 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10451 } else {
10452 this.buffer_store
10453 .update(cx, |buffer_store, cx| {
10454 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10455 })
10456 .detach_and_log_err(cx);
10457 let buffer_id = buffer.read(cx).remote_id().to_proto();
10458 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10459 }
10460 })
10461 }
10462
10463 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10464 let mut hasher = Sha256::new();
10465 hasher.update(abs_path.to_string_lossy().as_bytes());
10466 hasher.update(self.nonce.to_be_bytes());
10467 hasher.finalize().as_slice().try_into().unwrap()
10468 }
10469
10470 pub async fn handle_get_project_symbols(
10471 this: Entity<Self>,
10472 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10473 mut cx: AsyncApp,
10474 ) -> Result<proto::GetProjectSymbolsResponse> {
10475 let symbols = this
10476 .update(&mut cx, |this, cx| {
10477 this.symbols(&envelope.payload.query, cx)
10478 })
10479 .await?;
10480
10481 Ok(proto::GetProjectSymbolsResponse {
10482 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10483 })
10484 }
10485
10486 pub async fn handle_restart_language_servers(
10487 this: Entity<Self>,
10488 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10489 mut cx: AsyncApp,
10490 ) -> Result<proto::Ack> {
10491 this.update(&mut cx, |lsp_store, cx| {
10492 let buffers =
10493 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10494 lsp_store.restart_language_servers_for_buffers(
10495 buffers,
10496 envelope
10497 .payload
10498 .only_servers
10499 .into_iter()
10500 .filter_map(|selector| {
10501 Some(match selector.selector? {
10502 proto::language_server_selector::Selector::ServerId(server_id) => {
10503 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10504 }
10505 proto::language_server_selector::Selector::Name(name) => {
10506 LanguageServerSelector::Name(LanguageServerName(
10507 SharedString::from(name),
10508 ))
10509 }
10510 })
10511 })
10512 .collect(),
10513 cx,
10514 );
10515 });
10516
10517 Ok(proto::Ack {})
10518 }
10519
10520 pub async fn handle_stop_language_servers(
10521 lsp_store: Entity<Self>,
10522 envelope: TypedEnvelope<proto::StopLanguageServers>,
10523 mut cx: AsyncApp,
10524 ) -> Result<proto::Ack> {
10525 lsp_store.update(&mut cx, |lsp_store, cx| {
10526 if envelope.payload.all
10527 && envelope.payload.also_servers.is_empty()
10528 && envelope.payload.buffer_ids.is_empty()
10529 {
10530 lsp_store.stop_all_language_servers(cx);
10531 } else {
10532 let buffers =
10533 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10534 lsp_store
10535 .stop_language_servers_for_buffers(
10536 buffers,
10537 envelope
10538 .payload
10539 .also_servers
10540 .into_iter()
10541 .filter_map(|selector| {
10542 Some(match selector.selector? {
10543 proto::language_server_selector::Selector::ServerId(
10544 server_id,
10545 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10546 server_id,
10547 )),
10548 proto::language_server_selector::Selector::Name(name) => {
10549 LanguageServerSelector::Name(LanguageServerName(
10550 SharedString::from(name),
10551 ))
10552 }
10553 })
10554 })
10555 .collect(),
10556 cx,
10557 )
10558 .detach_and_log_err(cx);
10559 }
10560 });
10561
10562 Ok(proto::Ack {})
10563 }
10564
10565 pub async fn handle_cancel_language_server_work(
10566 lsp_store: Entity<Self>,
10567 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10568 mut cx: AsyncApp,
10569 ) -> Result<proto::Ack> {
10570 lsp_store.update(&mut cx, |lsp_store, cx| {
10571 if let Some(work) = envelope.payload.work {
10572 match work {
10573 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10574 let buffers =
10575 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10576 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10577 }
10578 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10579 let server_id = LanguageServerId::from_proto(work.language_server_id);
10580 let token = work
10581 .token
10582 .map(|token| {
10583 ProgressToken::from_proto(token)
10584 .context("invalid work progress token")
10585 })
10586 .transpose()?;
10587 lsp_store.cancel_language_server_work(server_id, token, cx);
10588 }
10589 }
10590 }
10591 anyhow::Ok(())
10592 })?;
10593
10594 Ok(proto::Ack {})
10595 }
10596
10597 fn buffer_ids_to_buffers(
10598 &mut self,
10599 buffer_ids: impl Iterator<Item = u64>,
10600 cx: &mut Context<Self>,
10601 ) -> Vec<Entity<Buffer>> {
10602 buffer_ids
10603 .into_iter()
10604 .flat_map(|buffer_id| {
10605 self.buffer_store
10606 .read(cx)
10607 .get(BufferId::new(buffer_id).log_err()?)
10608 })
10609 .collect::<Vec<_>>()
10610 }
10611
10612 async fn handle_apply_additional_edits_for_completion(
10613 this: Entity<Self>,
10614 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10615 mut cx: AsyncApp,
10616 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10617 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10618 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10619 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10620 let completion = Self::deserialize_completion(
10621 envelope.payload.completion.context("invalid completion")?,
10622 )?;
10623 anyhow::Ok((buffer, completion))
10624 })?;
10625
10626 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10627 this.apply_additional_edits_for_completion(
10628 buffer,
10629 Rc::new(RefCell::new(Box::new([Completion {
10630 replace_range: completion.replace_range,
10631 new_text: completion.new_text,
10632 source: completion.source,
10633 documentation: None,
10634 label: CodeLabel::default(),
10635 match_start: None,
10636 snippet_deduplication_key: None,
10637 insert_text_mode: None,
10638 icon_path: None,
10639 confirm: None,
10640 }]))),
10641 0,
10642 false,
10643 cx,
10644 )
10645 });
10646
10647 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10648 transaction: apply_additional_edits
10649 .await?
10650 .as_ref()
10651 .map(language::proto::serialize_transaction),
10652 })
10653 }
10654
10655 pub fn last_formatting_failure(&self) -> Option<&str> {
10656 self.last_formatting_failure.as_deref()
10657 }
10658
10659 pub fn reset_last_formatting_failure(&mut self) {
10660 self.last_formatting_failure = None;
10661 }
10662
10663 pub fn environment_for_buffer(
10664 &self,
10665 buffer: &Entity<Buffer>,
10666 cx: &mut Context<Self>,
10667 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10668 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10669 environment.update(cx, |env, cx| {
10670 env.buffer_environment(buffer, &self.worktree_store, cx)
10671 })
10672 } else {
10673 Task::ready(None).shared()
10674 }
10675 }
10676
10677 pub fn format(
10678 &mut self,
10679 buffers: HashSet<Entity<Buffer>>,
10680 target: LspFormatTarget,
10681 push_to_history: bool,
10682 trigger: FormatTrigger,
10683 cx: &mut Context<Self>,
10684 ) -> Task<anyhow::Result<ProjectTransaction>> {
10685 let logger = zlog::scoped!("format");
10686 if self.as_local().is_some() {
10687 zlog::trace!(logger => "Formatting locally");
10688 let logger = zlog::scoped!(logger => "local");
10689 let buffers = buffers
10690 .into_iter()
10691 .map(|buffer_handle| {
10692 let buffer = buffer_handle.read(cx);
10693 let buffer_abs_path = File::from_dyn(buffer.file())
10694 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10695
10696 (buffer_handle, buffer_abs_path, buffer.remote_id())
10697 })
10698 .collect::<Vec<_>>();
10699
10700 cx.spawn(async move |lsp_store, cx| {
10701 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10702
10703 for (handle, abs_path, id) in buffers {
10704 let env = lsp_store
10705 .update(cx, |lsp_store, cx| {
10706 lsp_store.environment_for_buffer(&handle, cx)
10707 })?
10708 .await;
10709
10710 let ranges = match &target {
10711 LspFormatTarget::Buffers => None,
10712 LspFormatTarget::Ranges(ranges) => {
10713 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10714 }
10715 };
10716
10717 formattable_buffers.push(FormattableBuffer {
10718 handle,
10719 abs_path,
10720 env,
10721 ranges,
10722 });
10723 }
10724 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10725
10726 let format_timer = zlog::time!(logger => "Formatting buffers");
10727 let result = LocalLspStore::format_locally(
10728 lsp_store.clone(),
10729 formattable_buffers,
10730 push_to_history,
10731 trigger,
10732 logger,
10733 cx,
10734 )
10735 .await;
10736 format_timer.end();
10737
10738 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10739
10740 lsp_store.update(cx, |lsp_store, _| {
10741 lsp_store.update_last_formatting_failure(&result);
10742 })?;
10743
10744 result
10745 })
10746 } else if let Some((client, project_id)) = self.upstream_client() {
10747 zlog::trace!(logger => "Formatting remotely");
10748 let logger = zlog::scoped!(logger => "remote");
10749
10750 let buffer_ranges = match &target {
10751 LspFormatTarget::Buffers => Vec::new(),
10752 LspFormatTarget::Ranges(ranges) => ranges
10753 .iter()
10754 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10755 buffer_id: buffer_id.to_proto(),
10756 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10757 })
10758 .collect(),
10759 };
10760
10761 let buffer_store = self.buffer_store();
10762 cx.spawn(async move |lsp_store, cx| {
10763 zlog::trace!(logger => "Sending remote format request");
10764 let request_timer = zlog::time!(logger => "remote format request");
10765 let result = client
10766 .request(proto::FormatBuffers {
10767 project_id,
10768 trigger: trigger as i32,
10769 buffer_ids: buffers
10770 .iter()
10771 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10772 .collect(),
10773 buffer_ranges,
10774 })
10775 .await
10776 .and_then(|result| result.transaction.context("missing transaction"));
10777 request_timer.end();
10778
10779 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10780
10781 lsp_store.update(cx, |lsp_store, _| {
10782 lsp_store.update_last_formatting_failure(&result);
10783 })?;
10784
10785 let transaction_response = result?;
10786 let _timer = zlog::time!(logger => "deserializing project transaction");
10787 buffer_store
10788 .update(cx, |buffer_store, cx| {
10789 buffer_store.deserialize_project_transaction(
10790 transaction_response,
10791 push_to_history,
10792 cx,
10793 )
10794 })
10795 .await
10796 })
10797 } else {
10798 zlog::trace!(logger => "Not formatting");
10799 Task::ready(Ok(ProjectTransaction::default()))
10800 }
10801 }
10802
10803 async fn handle_format_buffers(
10804 this: Entity<Self>,
10805 envelope: TypedEnvelope<proto::FormatBuffers>,
10806 mut cx: AsyncApp,
10807 ) -> Result<proto::FormatBuffersResponse> {
10808 let sender_id = envelope.original_sender_id().unwrap_or_default();
10809 let format = this.update(&mut cx, |this, cx| {
10810 let mut buffers = HashSet::default();
10811 for buffer_id in &envelope.payload.buffer_ids {
10812 let buffer_id = BufferId::new(*buffer_id)?;
10813 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10814 }
10815
10816 let target = if envelope.payload.buffer_ranges.is_empty() {
10817 LspFormatTarget::Buffers
10818 } else {
10819 let mut ranges_map = BTreeMap::new();
10820 for buffer_range in &envelope.payload.buffer_ranges {
10821 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10822 let ranges: Result<Vec<_>> = buffer_range
10823 .ranges
10824 .iter()
10825 .map(|range| {
10826 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10827 })
10828 .collect();
10829 ranges_map.insert(buffer_id, ranges?);
10830 }
10831 LspFormatTarget::Ranges(ranges_map)
10832 };
10833
10834 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10835 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10836 })?;
10837
10838 let project_transaction = format.await?;
10839 let project_transaction = this.update(&mut cx, |this, cx| {
10840 this.buffer_store.update(cx, |buffer_store, cx| {
10841 buffer_store.serialize_project_transaction_for_peer(
10842 project_transaction,
10843 sender_id,
10844 cx,
10845 )
10846 })
10847 });
10848 Ok(proto::FormatBuffersResponse {
10849 transaction: Some(project_transaction),
10850 })
10851 }
10852
10853 async fn handle_apply_code_action_kind(
10854 this: Entity<Self>,
10855 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10856 mut cx: AsyncApp,
10857 ) -> Result<proto::ApplyCodeActionKindResponse> {
10858 let sender_id = envelope.original_sender_id().unwrap_or_default();
10859 let format = this.update(&mut cx, |this, cx| {
10860 let mut buffers = HashSet::default();
10861 for buffer_id in &envelope.payload.buffer_ids {
10862 let buffer_id = BufferId::new(*buffer_id)?;
10863 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10864 }
10865 let kind = match envelope.payload.kind.as_str() {
10866 "" => CodeActionKind::EMPTY,
10867 "quickfix" => CodeActionKind::QUICKFIX,
10868 "refactor" => CodeActionKind::REFACTOR,
10869 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10870 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10871 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10872 "source" => CodeActionKind::SOURCE,
10873 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10874 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10875 _ => anyhow::bail!(
10876 "Invalid code action kind {}",
10877 envelope.payload.kind.as_str()
10878 ),
10879 };
10880 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10881 })?;
10882
10883 let project_transaction = format.await?;
10884 let project_transaction = this.update(&mut cx, |this, cx| {
10885 this.buffer_store.update(cx, |buffer_store, cx| {
10886 buffer_store.serialize_project_transaction_for_peer(
10887 project_transaction,
10888 sender_id,
10889 cx,
10890 )
10891 })
10892 });
10893 Ok(proto::ApplyCodeActionKindResponse {
10894 transaction: Some(project_transaction),
10895 })
10896 }
10897
10898 async fn shutdown_language_server(
10899 server_state: Option<LanguageServerState>,
10900 name: LanguageServerName,
10901 cx: &mut AsyncApp,
10902 ) {
10903 let server = match server_state {
10904 Some(LanguageServerState::Starting { startup, .. }) => {
10905 let mut timer = cx
10906 .background_executor()
10907 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10908 .fuse();
10909
10910 select! {
10911 server = startup.fuse() => server,
10912 () = timer => {
10913 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10914 None
10915 },
10916 }
10917 }
10918
10919 Some(LanguageServerState::Running { server, .. }) => Some(server),
10920
10921 None => None,
10922 };
10923
10924 if let Some(server) = server
10925 && let Some(shutdown) = server.shutdown()
10926 {
10927 shutdown.await;
10928 }
10929 }
10930
10931 // Returns a list of all of the worktrees which no longer have a language server and the root path
10932 // for the stopped server
10933 fn stop_local_language_server(
10934 &mut self,
10935 server_id: LanguageServerId,
10936 cx: &mut Context<Self>,
10937 ) -> Task<()> {
10938 let local = match &mut self.mode {
10939 LspStoreMode::Local(local) => local,
10940 _ => {
10941 return Task::ready(());
10942 }
10943 };
10944
10945 // Remove this server ID from all entries in the given worktree.
10946 local
10947 .language_server_ids
10948 .retain(|_, state| state.id != server_id);
10949 self.buffer_store.update(cx, |buffer_store, cx| {
10950 for buffer in buffer_store.buffers() {
10951 buffer.update(cx, |buffer, cx| {
10952 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10953 buffer.set_completion_triggers(server_id, Default::default(), cx);
10954 });
10955 }
10956 });
10957
10958 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10959 summaries.retain(|path, summaries_by_server_id| {
10960 if summaries_by_server_id.remove(&server_id).is_some() {
10961 if let Some((client, project_id)) = self.downstream_client.clone() {
10962 client
10963 .send(proto::UpdateDiagnosticSummary {
10964 project_id,
10965 worktree_id: worktree_id.to_proto(),
10966 summary: Some(proto::DiagnosticSummary {
10967 path: path.as_ref().to_proto(),
10968 language_server_id: server_id.0 as u64,
10969 error_count: 0,
10970 warning_count: 0,
10971 }),
10972 more_summaries: Vec::new(),
10973 })
10974 .log_err();
10975 }
10976 !summaries_by_server_id.is_empty()
10977 } else {
10978 true
10979 }
10980 });
10981 }
10982
10983 let local = self.as_local_mut().unwrap();
10984 for diagnostics in local.diagnostics.values_mut() {
10985 diagnostics.retain(|_, diagnostics_by_server_id| {
10986 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10987 diagnostics_by_server_id.remove(ix);
10988 !diagnostics_by_server_id.is_empty()
10989 } else {
10990 true
10991 }
10992 });
10993 }
10994 local.language_server_watched_paths.remove(&server_id);
10995
10996 let server_state = local.language_servers.remove(&server_id);
10997 self.cleanup_lsp_data(server_id);
10998 let name = self
10999 .language_server_statuses
11000 .remove(&server_id)
11001 .map(|status| status.name)
11002 .or_else(|| {
11003 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11004 Some(adapter.name())
11005 } else {
11006 None
11007 }
11008 });
11009
11010 if let Some(name) = name {
11011 log::info!("stopping language server {name}");
11012 self.languages
11013 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11014 cx.notify();
11015
11016 return cx.spawn(async move |lsp_store, cx| {
11017 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11018 lsp_store
11019 .update(cx, |lsp_store, cx| {
11020 lsp_store
11021 .languages
11022 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11023 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11024 cx.notify();
11025 })
11026 .ok();
11027 });
11028 }
11029
11030 if server_state.is_some() {
11031 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11032 }
11033 Task::ready(())
11034 }
11035
11036 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11037 self.shutdown_all_language_servers(cx).detach();
11038 }
11039
11040 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11041 if let Some((client, project_id)) = self.upstream_client() {
11042 let request = client.request(proto::StopLanguageServers {
11043 project_id,
11044 buffer_ids: Vec::new(),
11045 also_servers: Vec::new(),
11046 all: true,
11047 });
11048 cx.background_spawn(async move {
11049 request.await.ok();
11050 })
11051 } else {
11052 let Some(local) = self.as_local_mut() else {
11053 return Task::ready(());
11054 };
11055 let language_servers_to_stop = local
11056 .language_server_ids
11057 .values()
11058 .map(|state| state.id)
11059 .collect();
11060 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11061 let tasks = language_servers_to_stop
11062 .into_iter()
11063 .map(|server| self.stop_local_language_server(server, cx))
11064 .collect::<Vec<_>>();
11065 cx.background_spawn(async move {
11066 futures::future::join_all(tasks).await;
11067 })
11068 }
11069 }
11070
11071 pub fn restart_language_servers_for_buffers(
11072 &mut self,
11073 buffers: Vec<Entity<Buffer>>,
11074 only_restart_servers: HashSet<LanguageServerSelector>,
11075 cx: &mut Context<Self>,
11076 ) {
11077 if let Some((client, project_id)) = self.upstream_client() {
11078 let request = client.request(proto::RestartLanguageServers {
11079 project_id,
11080 buffer_ids: buffers
11081 .into_iter()
11082 .map(|b| b.read(cx).remote_id().to_proto())
11083 .collect(),
11084 only_servers: only_restart_servers
11085 .into_iter()
11086 .map(|selector| {
11087 let selector = match selector {
11088 LanguageServerSelector::Id(language_server_id) => {
11089 proto::language_server_selector::Selector::ServerId(
11090 language_server_id.to_proto(),
11091 )
11092 }
11093 LanguageServerSelector::Name(language_server_name) => {
11094 proto::language_server_selector::Selector::Name(
11095 language_server_name.to_string(),
11096 )
11097 }
11098 };
11099 proto::LanguageServerSelector {
11100 selector: Some(selector),
11101 }
11102 })
11103 .collect(),
11104 all: false,
11105 });
11106 cx.background_spawn(request).detach_and_log_err(cx);
11107 } else {
11108 let stop_task = if only_restart_servers.is_empty() {
11109 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11110 } else {
11111 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11112 };
11113 cx.spawn(async move |lsp_store, cx| {
11114 stop_task.await;
11115 lsp_store.update(cx, |lsp_store, cx| {
11116 for buffer in buffers {
11117 lsp_store.register_buffer_with_language_servers(
11118 &buffer,
11119 only_restart_servers.clone(),
11120 true,
11121 cx,
11122 );
11123 }
11124 })
11125 })
11126 .detach();
11127 }
11128 }
11129
11130 pub fn stop_language_servers_for_buffers(
11131 &mut self,
11132 buffers: Vec<Entity<Buffer>>,
11133 also_stop_servers: HashSet<LanguageServerSelector>,
11134 cx: &mut Context<Self>,
11135 ) -> Task<Result<()>> {
11136 if let Some((client, project_id)) = self.upstream_client() {
11137 let request = client.request(proto::StopLanguageServers {
11138 project_id,
11139 buffer_ids: buffers
11140 .into_iter()
11141 .map(|b| b.read(cx).remote_id().to_proto())
11142 .collect(),
11143 also_servers: also_stop_servers
11144 .into_iter()
11145 .map(|selector| {
11146 let selector = match selector {
11147 LanguageServerSelector::Id(language_server_id) => {
11148 proto::language_server_selector::Selector::ServerId(
11149 language_server_id.to_proto(),
11150 )
11151 }
11152 LanguageServerSelector::Name(language_server_name) => {
11153 proto::language_server_selector::Selector::Name(
11154 language_server_name.to_string(),
11155 )
11156 }
11157 };
11158 proto::LanguageServerSelector {
11159 selector: Some(selector),
11160 }
11161 })
11162 .collect(),
11163 all: false,
11164 });
11165 cx.background_spawn(async move {
11166 let _ = request.await?;
11167 Ok(())
11168 })
11169 } else {
11170 let task =
11171 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11172 cx.background_spawn(async move {
11173 task.await;
11174 Ok(())
11175 })
11176 }
11177 }
11178
11179 fn stop_local_language_servers_for_buffers(
11180 &mut self,
11181 buffers: &[Entity<Buffer>],
11182 also_stop_servers: HashSet<LanguageServerSelector>,
11183 cx: &mut Context<Self>,
11184 ) -> Task<()> {
11185 let Some(local) = self.as_local_mut() else {
11186 return Task::ready(());
11187 };
11188 let mut language_server_names_to_stop = BTreeSet::default();
11189 let mut language_servers_to_stop = also_stop_servers
11190 .into_iter()
11191 .flat_map(|selector| match selector {
11192 LanguageServerSelector::Id(id) => Some(id),
11193 LanguageServerSelector::Name(name) => {
11194 language_server_names_to_stop.insert(name);
11195 None
11196 }
11197 })
11198 .collect::<BTreeSet<_>>();
11199
11200 let mut covered_worktrees = HashSet::default();
11201 for buffer in buffers {
11202 buffer.update(cx, |buffer, cx| {
11203 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11204 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11205 && covered_worktrees.insert(worktree_id)
11206 {
11207 language_server_names_to_stop.retain(|name| {
11208 let old_ids_count = language_servers_to_stop.len();
11209 let all_language_servers_with_this_name = local
11210 .language_server_ids
11211 .iter()
11212 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11213 language_servers_to_stop.extend(all_language_servers_with_this_name);
11214 old_ids_count == language_servers_to_stop.len()
11215 });
11216 }
11217 });
11218 }
11219 for name in language_server_names_to_stop {
11220 language_servers_to_stop.extend(
11221 local
11222 .language_server_ids
11223 .iter()
11224 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11225 );
11226 }
11227
11228 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11229 let tasks = language_servers_to_stop
11230 .into_iter()
11231 .map(|server| self.stop_local_language_server(server, cx))
11232 .collect::<Vec<_>>();
11233
11234 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11235 }
11236
11237 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11238 let (worktree, relative_path) =
11239 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11240
11241 let project_path = ProjectPath {
11242 worktree_id: worktree.read(cx).id(),
11243 path: relative_path,
11244 };
11245
11246 Some(
11247 self.buffer_store()
11248 .read(cx)
11249 .get_by_path(&project_path)?
11250 .read(cx),
11251 )
11252 }
11253
11254 #[cfg(any(test, feature = "test-support"))]
11255 pub fn update_diagnostics(
11256 &mut self,
11257 server_id: LanguageServerId,
11258 diagnostics: lsp::PublishDiagnosticsParams,
11259 result_id: Option<SharedString>,
11260 source_kind: DiagnosticSourceKind,
11261 disk_based_sources: &[String],
11262 cx: &mut Context<Self>,
11263 ) -> Result<()> {
11264 self.merge_lsp_diagnostics(
11265 source_kind,
11266 vec![DocumentDiagnosticsUpdate {
11267 diagnostics,
11268 result_id,
11269 server_id,
11270 disk_based_sources: Cow::Borrowed(disk_based_sources),
11271 registration_id: None,
11272 }],
11273 |_, _, _| false,
11274 cx,
11275 )
11276 }
11277
11278 pub fn merge_lsp_diagnostics(
11279 &mut self,
11280 source_kind: DiagnosticSourceKind,
11281 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11282 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11283 cx: &mut Context<Self>,
11284 ) -> Result<()> {
11285 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11286 let updates = lsp_diagnostics
11287 .into_iter()
11288 .filter_map(|update| {
11289 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11290 Some(DocumentDiagnosticsUpdate {
11291 diagnostics: self.lsp_to_document_diagnostics(
11292 abs_path,
11293 source_kind,
11294 update.server_id,
11295 update.diagnostics,
11296 &update.disk_based_sources,
11297 update.registration_id.clone(),
11298 ),
11299 result_id: update.result_id,
11300 server_id: update.server_id,
11301 disk_based_sources: update.disk_based_sources,
11302 registration_id: update.registration_id,
11303 })
11304 })
11305 .collect();
11306 self.merge_diagnostic_entries(updates, merge, cx)?;
11307 Ok(())
11308 }
11309
11310 fn lsp_to_document_diagnostics(
11311 &mut self,
11312 document_abs_path: PathBuf,
11313 source_kind: DiagnosticSourceKind,
11314 server_id: LanguageServerId,
11315 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11316 disk_based_sources: &[String],
11317 registration_id: Option<SharedString>,
11318 ) -> DocumentDiagnostics {
11319 let mut diagnostics = Vec::default();
11320 let mut primary_diagnostic_group_ids = HashMap::default();
11321 let mut sources_by_group_id = HashMap::default();
11322 let mut supporting_diagnostics = HashMap::default();
11323
11324 let adapter = self.language_server_adapter_for_id(server_id);
11325
11326 // Ensure that primary diagnostics are always the most severe
11327 lsp_diagnostics
11328 .diagnostics
11329 .sort_by_key(|item| item.severity);
11330
11331 for diagnostic in &lsp_diagnostics.diagnostics {
11332 let source = diagnostic.source.as_ref();
11333 let range = range_from_lsp(diagnostic.range);
11334 let is_supporting = diagnostic
11335 .related_information
11336 .as_ref()
11337 .is_some_and(|infos| {
11338 infos.iter().any(|info| {
11339 primary_diagnostic_group_ids.contains_key(&(
11340 source,
11341 diagnostic.code.clone(),
11342 range_from_lsp(info.location.range),
11343 ))
11344 })
11345 });
11346
11347 let is_unnecessary = diagnostic
11348 .tags
11349 .as_ref()
11350 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11351
11352 let underline = self
11353 .language_server_adapter_for_id(server_id)
11354 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11355
11356 if is_supporting {
11357 supporting_diagnostics.insert(
11358 (source, diagnostic.code.clone(), range),
11359 (diagnostic.severity, is_unnecessary),
11360 );
11361 } else {
11362 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11363 let is_disk_based =
11364 source.is_some_and(|source| disk_based_sources.contains(source));
11365
11366 sources_by_group_id.insert(group_id, source);
11367 primary_diagnostic_group_ids
11368 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11369
11370 diagnostics.push(DiagnosticEntry {
11371 range,
11372 diagnostic: Diagnostic {
11373 source: diagnostic.source.clone(),
11374 source_kind,
11375 code: diagnostic.code.clone(),
11376 code_description: diagnostic
11377 .code_description
11378 .as_ref()
11379 .and_then(|d| d.href.clone()),
11380 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11381 markdown: adapter.as_ref().and_then(|adapter| {
11382 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11383 }),
11384 message: diagnostic.message.trim().to_string(),
11385 group_id,
11386 is_primary: true,
11387 is_disk_based,
11388 is_unnecessary,
11389 underline,
11390 data: diagnostic.data.clone(),
11391 registration_id: registration_id.clone(),
11392 },
11393 });
11394 if let Some(infos) = &diagnostic.related_information {
11395 for info in infos {
11396 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11397 let range = range_from_lsp(info.location.range);
11398 diagnostics.push(DiagnosticEntry {
11399 range,
11400 diagnostic: Diagnostic {
11401 source: diagnostic.source.clone(),
11402 source_kind,
11403 code: diagnostic.code.clone(),
11404 code_description: diagnostic
11405 .code_description
11406 .as_ref()
11407 .and_then(|d| d.href.clone()),
11408 severity: DiagnosticSeverity::INFORMATION,
11409 markdown: adapter.as_ref().and_then(|adapter| {
11410 adapter.diagnostic_message_to_markdown(&info.message)
11411 }),
11412 message: info.message.trim().to_string(),
11413 group_id,
11414 is_primary: false,
11415 is_disk_based,
11416 is_unnecessary: false,
11417 underline,
11418 data: diagnostic.data.clone(),
11419 registration_id: registration_id.clone(),
11420 },
11421 });
11422 }
11423 }
11424 }
11425 }
11426 }
11427
11428 for entry in &mut diagnostics {
11429 let diagnostic = &mut entry.diagnostic;
11430 if !diagnostic.is_primary {
11431 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11432 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11433 source,
11434 diagnostic.code.clone(),
11435 entry.range.clone(),
11436 )) {
11437 if let Some(severity) = severity {
11438 diagnostic.severity = severity;
11439 }
11440 diagnostic.is_unnecessary = is_unnecessary;
11441 }
11442 }
11443 }
11444
11445 DocumentDiagnostics {
11446 diagnostics,
11447 document_abs_path,
11448 version: lsp_diagnostics.version,
11449 }
11450 }
11451
11452 fn insert_newly_running_language_server(
11453 &mut self,
11454 adapter: Arc<CachedLspAdapter>,
11455 language_server: Arc<LanguageServer>,
11456 server_id: LanguageServerId,
11457 key: LanguageServerSeed,
11458 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11459 cx: &mut Context<Self>,
11460 ) {
11461 let Some(local) = self.as_local_mut() else {
11462 return;
11463 };
11464 // If the language server for this key doesn't match the server id, don't store the
11465 // server. Which will cause it to be dropped, killing the process
11466 if local
11467 .language_server_ids
11468 .get(&key)
11469 .map(|state| state.id != server_id)
11470 .unwrap_or(false)
11471 {
11472 return;
11473 }
11474
11475 // Update language_servers collection with Running variant of LanguageServerState
11476 // indicating that the server is up and running and ready
11477 let workspace_folders = workspace_folders.lock().clone();
11478 language_server.set_workspace_folders(workspace_folders);
11479
11480 let workspace_diagnostics_refresh_tasks = language_server
11481 .capabilities()
11482 .diagnostic_provider
11483 .and_then(|provider| {
11484 local
11485 .language_server_dynamic_registrations
11486 .entry(server_id)
11487 .or_default()
11488 .diagnostics
11489 .entry(None)
11490 .or_insert(provider.clone());
11491 let workspace_refresher =
11492 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11493
11494 Some((None, workspace_refresher))
11495 })
11496 .into_iter()
11497 .collect();
11498 local.language_servers.insert(
11499 server_id,
11500 LanguageServerState::Running {
11501 workspace_diagnostics_refresh_tasks,
11502 adapter: adapter.clone(),
11503 server: language_server.clone(),
11504 simulate_disk_based_diagnostics_completion: None,
11505 },
11506 );
11507 local
11508 .languages
11509 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11510 if let Some(file_ops_caps) = language_server
11511 .capabilities()
11512 .workspace
11513 .as_ref()
11514 .and_then(|ws| ws.file_operations.as_ref())
11515 {
11516 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11517 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11518 if did_rename_caps.or(will_rename_caps).is_some() {
11519 let watcher = RenamePathsWatchedForServer::default()
11520 .with_did_rename_patterns(did_rename_caps)
11521 .with_will_rename_patterns(will_rename_caps);
11522 local
11523 .language_server_paths_watched_for_rename
11524 .insert(server_id, watcher);
11525 }
11526 }
11527
11528 self.language_server_statuses.insert(
11529 server_id,
11530 LanguageServerStatus {
11531 name: language_server.name(),
11532 server_version: language_server.version(),
11533 pending_work: Default::default(),
11534 has_pending_diagnostic_updates: false,
11535 progress_tokens: Default::default(),
11536 worktree: Some(key.worktree_id),
11537 binary: Some(language_server.binary().clone()),
11538 configuration: Some(language_server.configuration().clone()),
11539 workspace_folders: language_server.workspace_folders(),
11540 },
11541 );
11542
11543 cx.emit(LspStoreEvent::LanguageServerAdded(
11544 server_id,
11545 language_server.name(),
11546 Some(key.worktree_id),
11547 ));
11548
11549 let server_capabilities = language_server.capabilities();
11550 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11551 downstream_client
11552 .send(proto::StartLanguageServer {
11553 project_id: *project_id,
11554 server: Some(proto::LanguageServer {
11555 id: server_id.to_proto(),
11556 name: language_server.name().to_string(),
11557 worktree_id: Some(key.worktree_id.to_proto()),
11558 }),
11559 capabilities: serde_json::to_string(&server_capabilities)
11560 .expect("serializing server LSP capabilities"),
11561 })
11562 .log_err();
11563 }
11564 self.lsp_server_capabilities
11565 .insert(server_id, server_capabilities);
11566
11567 // Tell the language server about every open buffer in the worktree that matches the language.
11568 // Also check for buffers in worktrees that reused this server
11569 let mut worktrees_using_server = vec![key.worktree_id];
11570 if let Some(local) = self.as_local() {
11571 // Find all worktrees that have this server in their language server tree
11572 for (worktree_id, servers) in &local.lsp_tree.instances {
11573 if *worktree_id != key.worktree_id {
11574 for server_map in servers.roots.values() {
11575 if server_map
11576 .values()
11577 .any(|(node, _)| node.id() == Some(server_id))
11578 {
11579 worktrees_using_server.push(*worktree_id);
11580 }
11581 }
11582 }
11583 }
11584 }
11585
11586 let mut buffer_paths_registered = Vec::new();
11587 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11588 let mut lsp_adapters = HashMap::default();
11589 for buffer_handle in buffer_store.buffers() {
11590 let buffer = buffer_handle.read(cx);
11591 let file = match File::from_dyn(buffer.file()) {
11592 Some(file) => file,
11593 None => continue,
11594 };
11595 let language = match buffer.language() {
11596 Some(language) => language,
11597 None => continue,
11598 };
11599
11600 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11601 || !lsp_adapters
11602 .entry(language.name())
11603 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11604 .iter()
11605 .any(|a| a.name == key.name)
11606 {
11607 continue;
11608 }
11609 // didOpen
11610 let file = match file.as_local() {
11611 Some(file) => file,
11612 None => continue,
11613 };
11614
11615 let local = self.as_local_mut().unwrap();
11616
11617 let buffer_id = buffer.remote_id();
11618 if local.registered_buffers.contains_key(&buffer_id) {
11619 let versions = local
11620 .buffer_snapshots
11621 .entry(buffer_id)
11622 .or_default()
11623 .entry(server_id)
11624 .and_modify(|_| {
11625 assert!(
11626 false,
11627 "There should not be an existing snapshot for a newly inserted buffer"
11628 )
11629 })
11630 .or_insert_with(|| {
11631 vec![LspBufferSnapshot {
11632 version: 0,
11633 snapshot: buffer.text_snapshot(),
11634 }]
11635 });
11636
11637 let snapshot = versions.last().unwrap();
11638 let version = snapshot.version;
11639 let initial_snapshot = &snapshot.snapshot;
11640 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11641 language_server.register_buffer(
11642 uri,
11643 adapter.language_id(&language.name()),
11644 version,
11645 initial_snapshot.text(),
11646 );
11647 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11648 local
11649 .buffers_opened_in_servers
11650 .entry(buffer_id)
11651 .or_default()
11652 .insert(server_id);
11653 }
11654 buffer_handle.update(cx, |buffer, cx| {
11655 buffer.set_completion_triggers(
11656 server_id,
11657 language_server
11658 .capabilities()
11659 .completion_provider
11660 .as_ref()
11661 .and_then(|provider| {
11662 provider
11663 .trigger_characters
11664 .as_ref()
11665 .map(|characters| characters.iter().cloned().collect())
11666 })
11667 .unwrap_or_default(),
11668 cx,
11669 )
11670 });
11671 }
11672 });
11673
11674 for (buffer_id, abs_path) in buffer_paths_registered {
11675 cx.emit(LspStoreEvent::LanguageServerUpdate {
11676 language_server_id: server_id,
11677 name: Some(adapter.name()),
11678 message: proto::update_language_server::Variant::RegisteredForBuffer(
11679 proto::RegisteredForBuffer {
11680 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11681 buffer_id: buffer_id.to_proto(),
11682 },
11683 ),
11684 });
11685 }
11686
11687 cx.notify();
11688 }
11689
11690 pub fn language_servers_running_disk_based_diagnostics(
11691 &self,
11692 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11693 self.language_server_statuses
11694 .iter()
11695 .filter_map(|(id, status)| {
11696 if status.has_pending_diagnostic_updates {
11697 Some(*id)
11698 } else {
11699 None
11700 }
11701 })
11702 }
11703
11704 pub(crate) fn cancel_language_server_work_for_buffers(
11705 &mut self,
11706 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11707 cx: &mut Context<Self>,
11708 ) {
11709 if let Some((client, project_id)) = self.upstream_client() {
11710 let request = client.request(proto::CancelLanguageServerWork {
11711 project_id,
11712 work: Some(proto::cancel_language_server_work::Work::Buffers(
11713 proto::cancel_language_server_work::Buffers {
11714 buffer_ids: buffers
11715 .into_iter()
11716 .map(|b| b.read(cx).remote_id().to_proto())
11717 .collect(),
11718 },
11719 )),
11720 });
11721 cx.background_spawn(request).detach_and_log_err(cx);
11722 } else if let Some(local) = self.as_local() {
11723 let servers = buffers
11724 .into_iter()
11725 .flat_map(|buffer| {
11726 buffer.update(cx, |buffer, cx| {
11727 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11728 })
11729 })
11730 .collect::<HashSet<_>>();
11731 for server_id in servers {
11732 self.cancel_language_server_work(server_id, None, cx);
11733 }
11734 }
11735 }
11736
11737 pub(crate) fn cancel_language_server_work(
11738 &mut self,
11739 server_id: LanguageServerId,
11740 token_to_cancel: Option<ProgressToken>,
11741 cx: &mut Context<Self>,
11742 ) {
11743 if let Some(local) = self.as_local() {
11744 let status = self.language_server_statuses.get(&server_id);
11745 let server = local.language_servers.get(&server_id);
11746 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11747 {
11748 for (token, progress) in &status.pending_work {
11749 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11750 && token != token_to_cancel
11751 {
11752 continue;
11753 }
11754 if progress.is_cancellable {
11755 server
11756 .notify::<lsp::notification::WorkDoneProgressCancel>(
11757 WorkDoneProgressCancelParams {
11758 token: token.to_lsp(),
11759 },
11760 )
11761 .ok();
11762 }
11763 }
11764 }
11765 } else if let Some((client, project_id)) = self.upstream_client() {
11766 let request = client.request(proto::CancelLanguageServerWork {
11767 project_id,
11768 work: Some(
11769 proto::cancel_language_server_work::Work::LanguageServerWork(
11770 proto::cancel_language_server_work::LanguageServerWork {
11771 language_server_id: server_id.to_proto(),
11772 token: token_to_cancel.map(|token| token.to_proto()),
11773 },
11774 ),
11775 ),
11776 });
11777 cx.background_spawn(request).detach_and_log_err(cx);
11778 }
11779 }
11780
11781 fn register_supplementary_language_server(
11782 &mut self,
11783 id: LanguageServerId,
11784 name: LanguageServerName,
11785 server: Arc<LanguageServer>,
11786 cx: &mut Context<Self>,
11787 ) {
11788 if let Some(local) = self.as_local_mut() {
11789 local
11790 .supplementary_language_servers
11791 .insert(id, (name.clone(), server));
11792 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11793 }
11794 }
11795
11796 fn unregister_supplementary_language_server(
11797 &mut self,
11798 id: LanguageServerId,
11799 cx: &mut Context<Self>,
11800 ) {
11801 if let Some(local) = self.as_local_mut() {
11802 local.supplementary_language_servers.remove(&id);
11803 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11804 }
11805 }
11806
11807 pub(crate) fn supplementary_language_servers(
11808 &self,
11809 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11810 self.as_local().into_iter().flat_map(|local| {
11811 local
11812 .supplementary_language_servers
11813 .iter()
11814 .map(|(id, (name, _))| (*id, name.clone()))
11815 })
11816 }
11817
11818 pub fn language_server_adapter_for_id(
11819 &self,
11820 id: LanguageServerId,
11821 ) -> Option<Arc<CachedLspAdapter>> {
11822 self.as_local()
11823 .and_then(|local| local.language_servers.get(&id))
11824 .and_then(|language_server_state| match language_server_state {
11825 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11826 _ => None,
11827 })
11828 }
11829
11830 pub(super) fn update_local_worktree_language_servers(
11831 &mut self,
11832 worktree_handle: &Entity<Worktree>,
11833 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11834 cx: &mut Context<Self>,
11835 ) {
11836 if changes.is_empty() {
11837 return;
11838 }
11839
11840 let Some(local) = self.as_local() else { return };
11841
11842 local.prettier_store.update(cx, |prettier_store, cx| {
11843 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11844 });
11845
11846 let worktree_id = worktree_handle.read(cx).id();
11847 let mut language_server_ids = local
11848 .language_server_ids
11849 .iter()
11850 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11851 .collect::<Vec<_>>();
11852 language_server_ids.sort();
11853 language_server_ids.dedup();
11854
11855 // let abs_path = worktree_handle.read(cx).abs_path();
11856 for server_id in &language_server_ids {
11857 if let Some(LanguageServerState::Running { server, .. }) =
11858 local.language_servers.get(server_id)
11859 && let Some(watched_paths) = local
11860 .language_server_watched_paths
11861 .get(server_id)
11862 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11863 {
11864 let params = lsp::DidChangeWatchedFilesParams {
11865 changes: changes
11866 .iter()
11867 .filter_map(|(path, _, change)| {
11868 if !watched_paths.is_match(path.as_std_path()) {
11869 return None;
11870 }
11871 let typ = match change {
11872 PathChange::Loaded => return None,
11873 PathChange::Added => lsp::FileChangeType::CREATED,
11874 PathChange::Removed => lsp::FileChangeType::DELETED,
11875 PathChange::Updated => lsp::FileChangeType::CHANGED,
11876 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11877 };
11878 let uri = lsp::Uri::from_file_path(
11879 worktree_handle.read(cx).absolutize(&path),
11880 )
11881 .ok()?;
11882 Some(lsp::FileEvent { uri, typ })
11883 })
11884 .collect(),
11885 };
11886 if !params.changes.is_empty() {
11887 server
11888 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11889 .ok();
11890 }
11891 }
11892 }
11893 for (path, _, _) in changes {
11894 if let Some(file_name) = path.file_name()
11895 && local.watched_manifest_filenames.contains(file_name)
11896 {
11897 self.request_workspace_config_refresh();
11898 break;
11899 }
11900 }
11901 }
11902
11903 pub fn wait_for_remote_buffer(
11904 &mut self,
11905 id: BufferId,
11906 cx: &mut Context<Self>,
11907 ) -> Task<Result<Entity<Buffer>>> {
11908 self.buffer_store.update(cx, |buffer_store, cx| {
11909 buffer_store.wait_for_remote_buffer(id, cx)
11910 })
11911 }
11912
11913 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11914 let mut result = proto::Symbol {
11915 language_server_name: symbol.language_server_name.0.to_string(),
11916 source_worktree_id: symbol.source_worktree_id.to_proto(),
11917 language_server_id: symbol.source_language_server_id.to_proto(),
11918 name: symbol.name.clone(),
11919 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11920 start: Some(proto::PointUtf16 {
11921 row: symbol.range.start.0.row,
11922 column: symbol.range.start.0.column,
11923 }),
11924 end: Some(proto::PointUtf16 {
11925 row: symbol.range.end.0.row,
11926 column: symbol.range.end.0.column,
11927 }),
11928 worktree_id: Default::default(),
11929 path: Default::default(),
11930 signature: Default::default(),
11931 };
11932 match &symbol.path {
11933 SymbolLocation::InProject(path) => {
11934 result.worktree_id = path.worktree_id.to_proto();
11935 result.path = path.path.to_proto();
11936 }
11937 SymbolLocation::OutsideProject {
11938 abs_path,
11939 signature,
11940 } => {
11941 result.path = abs_path.to_string_lossy().into_owned();
11942 result.signature = signature.to_vec();
11943 }
11944 }
11945 result
11946 }
11947
11948 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11949 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11950 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11951 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11952
11953 let path = if serialized_symbol.signature.is_empty() {
11954 SymbolLocation::InProject(ProjectPath {
11955 worktree_id,
11956 path: RelPath::from_proto(&serialized_symbol.path)
11957 .context("invalid symbol path")?,
11958 })
11959 } else {
11960 SymbolLocation::OutsideProject {
11961 abs_path: Path::new(&serialized_symbol.path).into(),
11962 signature: serialized_symbol
11963 .signature
11964 .try_into()
11965 .map_err(|_| anyhow!("invalid signature"))?,
11966 }
11967 };
11968
11969 let start = serialized_symbol.start.context("invalid start")?;
11970 let end = serialized_symbol.end.context("invalid end")?;
11971 Ok(CoreSymbol {
11972 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11973 source_worktree_id,
11974 source_language_server_id: LanguageServerId::from_proto(
11975 serialized_symbol.language_server_id,
11976 ),
11977 path,
11978 name: serialized_symbol.name,
11979 range: Unclipped(PointUtf16::new(start.row, start.column))
11980 ..Unclipped(PointUtf16::new(end.row, end.column)),
11981 kind,
11982 })
11983 }
11984
11985 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11986 let mut serialized_completion = proto::Completion {
11987 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11988 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11989 new_text: completion.new_text.clone(),
11990 ..proto::Completion::default()
11991 };
11992 match &completion.source {
11993 CompletionSource::Lsp {
11994 insert_range,
11995 server_id,
11996 lsp_completion,
11997 lsp_defaults,
11998 resolved,
11999 } => {
12000 let (old_insert_start, old_insert_end) = insert_range
12001 .as_ref()
12002 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12003 .unzip();
12004
12005 serialized_completion.old_insert_start = old_insert_start;
12006 serialized_completion.old_insert_end = old_insert_end;
12007 serialized_completion.source = proto::completion::Source::Lsp as i32;
12008 serialized_completion.server_id = server_id.0 as u64;
12009 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12010 serialized_completion.lsp_defaults = lsp_defaults
12011 .as_deref()
12012 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12013 serialized_completion.resolved = *resolved;
12014 }
12015 CompletionSource::BufferWord {
12016 word_range,
12017 resolved,
12018 } => {
12019 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12020 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12021 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12022 serialized_completion.resolved = *resolved;
12023 }
12024 CompletionSource::Custom => {
12025 serialized_completion.source = proto::completion::Source::Custom as i32;
12026 serialized_completion.resolved = true;
12027 }
12028 CompletionSource::Dap { sort_text } => {
12029 serialized_completion.source = proto::completion::Source::Dap as i32;
12030 serialized_completion.sort_text = Some(sort_text.clone());
12031 }
12032 }
12033
12034 serialized_completion
12035 }
12036
12037 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12038 let old_replace_start = completion
12039 .old_replace_start
12040 .and_then(deserialize_anchor)
12041 .context("invalid old start")?;
12042 let old_replace_end = completion
12043 .old_replace_end
12044 .and_then(deserialize_anchor)
12045 .context("invalid old end")?;
12046 let insert_range = {
12047 match completion.old_insert_start.zip(completion.old_insert_end) {
12048 Some((start, end)) => {
12049 let start = deserialize_anchor(start).context("invalid insert old start")?;
12050 let end = deserialize_anchor(end).context("invalid insert old end")?;
12051 Some(start..end)
12052 }
12053 None => None,
12054 }
12055 };
12056 Ok(CoreCompletion {
12057 replace_range: old_replace_start..old_replace_end,
12058 new_text: completion.new_text,
12059 source: match proto::completion::Source::from_i32(completion.source) {
12060 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12061 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12062 insert_range,
12063 server_id: LanguageServerId::from_proto(completion.server_id),
12064 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12065 lsp_defaults: completion
12066 .lsp_defaults
12067 .as_deref()
12068 .map(serde_json::from_slice)
12069 .transpose()?,
12070 resolved: completion.resolved,
12071 },
12072 Some(proto::completion::Source::BufferWord) => {
12073 let word_range = completion
12074 .buffer_word_start
12075 .and_then(deserialize_anchor)
12076 .context("invalid buffer word start")?
12077 ..completion
12078 .buffer_word_end
12079 .and_then(deserialize_anchor)
12080 .context("invalid buffer word end")?;
12081 CompletionSource::BufferWord {
12082 word_range,
12083 resolved: completion.resolved,
12084 }
12085 }
12086 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12087 sort_text: completion
12088 .sort_text
12089 .context("expected sort text to exist")?,
12090 },
12091 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12092 },
12093 })
12094 }
12095
12096 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12097 let (kind, lsp_action) = match &action.lsp_action {
12098 LspAction::Action(code_action) => (
12099 proto::code_action::Kind::Action as i32,
12100 serde_json::to_vec(code_action).unwrap(),
12101 ),
12102 LspAction::Command(command) => (
12103 proto::code_action::Kind::Command as i32,
12104 serde_json::to_vec(command).unwrap(),
12105 ),
12106 LspAction::CodeLens(code_lens) => (
12107 proto::code_action::Kind::CodeLens as i32,
12108 serde_json::to_vec(code_lens).unwrap(),
12109 ),
12110 };
12111
12112 proto::CodeAction {
12113 server_id: action.server_id.0 as u64,
12114 start: Some(serialize_anchor(&action.range.start)),
12115 end: Some(serialize_anchor(&action.range.end)),
12116 lsp_action,
12117 kind,
12118 resolved: action.resolved,
12119 }
12120 }
12121
12122 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12123 let start = action
12124 .start
12125 .and_then(deserialize_anchor)
12126 .context("invalid start")?;
12127 let end = action
12128 .end
12129 .and_then(deserialize_anchor)
12130 .context("invalid end")?;
12131 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12132 Some(proto::code_action::Kind::Action) => {
12133 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12134 }
12135 Some(proto::code_action::Kind::Command) => {
12136 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12137 }
12138 Some(proto::code_action::Kind::CodeLens) => {
12139 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12140 }
12141 None => anyhow::bail!("Unknown action kind {}", action.kind),
12142 };
12143 Ok(CodeAction {
12144 server_id: LanguageServerId(action.server_id as usize),
12145 range: start..end,
12146 resolved: action.resolved,
12147 lsp_action,
12148 })
12149 }
12150
12151 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12152 match &formatting_result {
12153 Ok(_) => self.last_formatting_failure = None,
12154 Err(error) => {
12155 let error_string = format!("{error:#}");
12156 log::error!("Formatting failed: {error_string}");
12157 self.last_formatting_failure
12158 .replace(error_string.lines().join(" "));
12159 }
12160 }
12161 }
12162
12163 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12164 self.lsp_server_capabilities.remove(&for_server);
12165 for lsp_data in self.lsp_data.values_mut() {
12166 lsp_data.remove_server_data(for_server);
12167 }
12168 if let Some(local) = self.as_local_mut() {
12169 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12170 local
12171 .workspace_pull_diagnostics_result_ids
12172 .remove(&for_server);
12173 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12174 buffer_servers.remove(&for_server);
12175 }
12176 }
12177 }
12178
12179 pub fn result_id_for_buffer_pull(
12180 &self,
12181 server_id: LanguageServerId,
12182 buffer_id: BufferId,
12183 registration_id: &Option<SharedString>,
12184 cx: &App,
12185 ) -> Option<SharedString> {
12186 let abs_path = self
12187 .buffer_store
12188 .read(cx)
12189 .get(buffer_id)
12190 .and_then(|b| File::from_dyn(b.read(cx).file()))
12191 .map(|f| f.abs_path(cx))?;
12192 self.as_local()?
12193 .buffer_pull_diagnostics_result_ids
12194 .get(&server_id)?
12195 .get(registration_id)?
12196 .get(&abs_path)?
12197 .clone()
12198 }
12199
12200 /// Gets all result_ids for a workspace diagnostics pull request.
12201 /// 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.
12202 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12203 pub fn result_ids_for_workspace_refresh(
12204 &self,
12205 server_id: LanguageServerId,
12206 registration_id: &Option<SharedString>,
12207 ) -> HashMap<PathBuf, SharedString> {
12208 let Some(local) = self.as_local() else {
12209 return HashMap::default();
12210 };
12211 local
12212 .workspace_pull_diagnostics_result_ids
12213 .get(&server_id)
12214 .into_iter()
12215 .filter_map(|diagnostics| diagnostics.get(registration_id))
12216 .flatten()
12217 .filter_map(|(abs_path, result_id)| {
12218 let result_id = local
12219 .buffer_pull_diagnostics_result_ids
12220 .get(&server_id)
12221 .and_then(|buffer_ids_result_ids| {
12222 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12223 })
12224 .cloned()
12225 .flatten()
12226 .or_else(|| result_id.clone())?;
12227 Some((abs_path.clone(), result_id))
12228 })
12229 .collect()
12230 }
12231
12232 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12233 if let Some(LanguageServerState::Running {
12234 workspace_diagnostics_refresh_tasks,
12235 ..
12236 }) = self
12237 .as_local_mut()
12238 .and_then(|local| local.language_servers.get_mut(&server_id))
12239 {
12240 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12241 diagnostics.refresh_tx.try_send(()).ok();
12242 }
12243 }
12244 }
12245
12246 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12247 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12248 /// which requires refreshing both workspace and document diagnostics.
12249 pub fn pull_document_diagnostics_for_server(
12250 &mut self,
12251 server_id: LanguageServerId,
12252 cx: &mut Context<Self>,
12253 ) -> Task<()> {
12254 let buffers_to_pull = self
12255 .as_local()
12256 .into_iter()
12257 .flat_map(|local| {
12258 self.buffer_store.read(cx).buffers().filter(|buffer| {
12259 let buffer_id = buffer.read(cx).remote_id();
12260 local
12261 .buffers_opened_in_servers
12262 .get(&buffer_id)
12263 .is_some_and(|servers| servers.contains(&server_id))
12264 })
12265 })
12266 .collect::<Vec<_>>();
12267
12268 let pulls = join_all(buffers_to_pull.into_iter().map(|buffer| {
12269 let buffer_path = buffer.read(cx).file().map(|f| f.full_path(cx));
12270 let pull_task = self.pull_diagnostics_for_buffer(buffer, cx);
12271 async move { (buffer_path, pull_task.await) }
12272 }));
12273 cx.background_spawn(async move {
12274 for (pull_task_path, pull_task_result) in pulls.await {
12275 if let Err(e) = pull_task_result {
12276 match pull_task_path {
12277 Some(path) => {
12278 log::error!("Failed to pull diagnostics for buffer {path:?}: {e:#}");
12279 }
12280 None => log::error!("Failed to pull diagnostics: {e:#}"),
12281 }
12282 }
12283 }
12284 })
12285 }
12286
12287 fn apply_workspace_diagnostic_report(
12288 &mut self,
12289 server_id: LanguageServerId,
12290 report: lsp::WorkspaceDiagnosticReportResult,
12291 registration_id: Option<SharedString>,
12292 cx: &mut Context<Self>,
12293 ) {
12294 let mut workspace_diagnostics =
12295 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12296 report,
12297 server_id,
12298 registration_id,
12299 );
12300 workspace_diagnostics.retain(|d| match &d.diagnostics {
12301 LspPullDiagnostics::Response {
12302 server_id,
12303 registration_id,
12304 ..
12305 } => self.diagnostic_registration_exists(*server_id, registration_id),
12306 LspPullDiagnostics::Default => false,
12307 });
12308 let mut unchanged_buffers = HashMap::default();
12309 let workspace_diagnostics_updates = workspace_diagnostics
12310 .into_iter()
12311 .filter_map(
12312 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12313 LspPullDiagnostics::Response {
12314 server_id,
12315 uri,
12316 diagnostics,
12317 registration_id,
12318 } => Some((
12319 server_id,
12320 uri,
12321 diagnostics,
12322 workspace_diagnostics.version,
12323 registration_id,
12324 )),
12325 LspPullDiagnostics::Default => None,
12326 },
12327 )
12328 .fold(
12329 HashMap::default(),
12330 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12331 let (result_id, diagnostics) = match diagnostics {
12332 PulledDiagnostics::Unchanged { result_id } => {
12333 unchanged_buffers
12334 .entry(new_registration_id.clone())
12335 .or_insert_with(HashSet::default)
12336 .insert(uri.clone());
12337 (Some(result_id), Vec::new())
12338 }
12339 PulledDiagnostics::Changed {
12340 result_id,
12341 diagnostics,
12342 } => (result_id, diagnostics),
12343 };
12344 let disk_based_sources = Cow::Owned(
12345 self.language_server_adapter_for_id(server_id)
12346 .as_ref()
12347 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12348 .unwrap_or(&[])
12349 .to_vec(),
12350 );
12351
12352 let Some(abs_path) = uri.to_file_path().ok() else {
12353 return acc;
12354 };
12355 let Some((worktree, relative_path)) =
12356 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12357 else {
12358 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12359 return acc;
12360 };
12361 let worktree_id = worktree.read(cx).id();
12362 let project_path = ProjectPath {
12363 worktree_id,
12364 path: relative_path,
12365 };
12366 if let Some(local_lsp_store) = self.as_local_mut() {
12367 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12368 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12369 }
12370 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12371 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12372 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12373 acc.entry(server_id)
12374 .or_insert_with(HashMap::default)
12375 .entry(new_registration_id.clone())
12376 .or_insert_with(Vec::new)
12377 .push(DocumentDiagnosticsUpdate {
12378 server_id,
12379 diagnostics: lsp::PublishDiagnosticsParams {
12380 uri,
12381 diagnostics,
12382 version,
12383 },
12384 result_id,
12385 disk_based_sources,
12386 registration_id: new_registration_id,
12387 });
12388 }
12389 acc
12390 },
12391 );
12392
12393 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12394 for (registration_id, diagnostic_updates) in diagnostic_updates {
12395 self.merge_lsp_diagnostics(
12396 DiagnosticSourceKind::Pulled,
12397 diagnostic_updates,
12398 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12399 DiagnosticSourceKind::Pulled => {
12400 old_diagnostic.registration_id != registration_id
12401 || unchanged_buffers
12402 .get(&old_diagnostic.registration_id)
12403 .is_some_and(|unchanged_buffers| {
12404 unchanged_buffers.contains(&document_uri)
12405 })
12406 }
12407 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12408 },
12409 cx,
12410 )
12411 .log_err();
12412 }
12413 }
12414 }
12415
12416 fn register_server_capabilities(
12417 &mut self,
12418 server_id: LanguageServerId,
12419 params: lsp::RegistrationParams,
12420 cx: &mut Context<Self>,
12421 ) -> anyhow::Result<()> {
12422 let server = self
12423 .language_server_for_id(server_id)
12424 .with_context(|| format!("no server {server_id} found"))?;
12425 for reg in params.registrations {
12426 match reg.method.as_str() {
12427 "workspace/didChangeWatchedFiles" => {
12428 if let Some(options) = reg.register_options {
12429 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12430 let caps = serde_json::from_value(options)?;
12431 local_lsp_store
12432 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12433 true
12434 } else {
12435 false
12436 };
12437 if notify {
12438 notify_server_capabilities_updated(&server, cx);
12439 }
12440 }
12441 }
12442 "workspace/didChangeConfiguration" => {
12443 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12444 }
12445 "workspace/didChangeWorkspaceFolders" => {
12446 // In this case register options is an empty object, we can ignore it
12447 let caps = lsp::WorkspaceFoldersServerCapabilities {
12448 supported: Some(true),
12449 change_notifications: Some(OneOf::Right(reg.id)),
12450 };
12451 server.update_capabilities(|capabilities| {
12452 capabilities
12453 .workspace
12454 .get_or_insert_default()
12455 .workspace_folders = Some(caps);
12456 });
12457 notify_server_capabilities_updated(&server, cx);
12458 }
12459 "workspace/symbol" => {
12460 let options = parse_register_capabilities(reg)?;
12461 server.update_capabilities(|capabilities| {
12462 capabilities.workspace_symbol_provider = Some(options);
12463 });
12464 notify_server_capabilities_updated(&server, cx);
12465 }
12466 "workspace/fileOperations" => {
12467 if let Some(options) = reg.register_options {
12468 let caps = serde_json::from_value(options)?;
12469 server.update_capabilities(|capabilities| {
12470 capabilities
12471 .workspace
12472 .get_or_insert_default()
12473 .file_operations = Some(caps);
12474 });
12475 notify_server_capabilities_updated(&server, cx);
12476 }
12477 }
12478 "workspace/executeCommand" => {
12479 if let Some(options) = reg.register_options {
12480 let options = serde_json::from_value(options)?;
12481 server.update_capabilities(|capabilities| {
12482 capabilities.execute_command_provider = Some(options);
12483 });
12484 notify_server_capabilities_updated(&server, cx);
12485 }
12486 }
12487 "textDocument/rangeFormatting" => {
12488 let options = parse_register_capabilities(reg)?;
12489 server.update_capabilities(|capabilities| {
12490 capabilities.document_range_formatting_provider = Some(options);
12491 });
12492 notify_server_capabilities_updated(&server, cx);
12493 }
12494 "textDocument/onTypeFormatting" => {
12495 if let Some(options) = reg
12496 .register_options
12497 .map(serde_json::from_value)
12498 .transpose()?
12499 {
12500 server.update_capabilities(|capabilities| {
12501 capabilities.document_on_type_formatting_provider = Some(options);
12502 });
12503 notify_server_capabilities_updated(&server, cx);
12504 }
12505 }
12506 "textDocument/formatting" => {
12507 let options = parse_register_capabilities(reg)?;
12508 server.update_capabilities(|capabilities| {
12509 capabilities.document_formatting_provider = Some(options);
12510 });
12511 notify_server_capabilities_updated(&server, cx);
12512 }
12513 "textDocument/rename" => {
12514 let options = parse_register_capabilities(reg)?;
12515 server.update_capabilities(|capabilities| {
12516 capabilities.rename_provider = Some(options);
12517 });
12518 notify_server_capabilities_updated(&server, cx);
12519 }
12520 "textDocument/inlayHint" => {
12521 let options = parse_register_capabilities(reg)?;
12522 server.update_capabilities(|capabilities| {
12523 capabilities.inlay_hint_provider = Some(options);
12524 });
12525 notify_server_capabilities_updated(&server, cx);
12526 }
12527 "textDocument/documentSymbol" => {
12528 let options = parse_register_capabilities(reg)?;
12529 server.update_capabilities(|capabilities| {
12530 capabilities.document_symbol_provider = Some(options);
12531 });
12532 notify_server_capabilities_updated(&server, cx);
12533 }
12534 "textDocument/codeAction" => {
12535 let options = parse_register_capabilities(reg)?;
12536 let provider = match options {
12537 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12538 OneOf::Right(caps) => caps,
12539 };
12540 server.update_capabilities(|capabilities| {
12541 capabilities.code_action_provider = Some(provider);
12542 });
12543 notify_server_capabilities_updated(&server, cx);
12544 }
12545 "textDocument/definition" => {
12546 let options = parse_register_capabilities(reg)?;
12547 server.update_capabilities(|capabilities| {
12548 capabilities.definition_provider = Some(options);
12549 });
12550 notify_server_capabilities_updated(&server, cx);
12551 }
12552 "textDocument/completion" => {
12553 if let Some(caps) = reg
12554 .register_options
12555 .map(serde_json::from_value::<CompletionOptions>)
12556 .transpose()?
12557 {
12558 server.update_capabilities(|capabilities| {
12559 capabilities.completion_provider = Some(caps.clone());
12560 });
12561
12562 if let Some(local) = self.as_local() {
12563 let mut buffers_with_language_server = Vec::new();
12564 for handle in self.buffer_store.read(cx).buffers() {
12565 let buffer_id = handle.read(cx).remote_id();
12566 if local
12567 .buffers_opened_in_servers
12568 .get(&buffer_id)
12569 .filter(|s| s.contains(&server_id))
12570 .is_some()
12571 {
12572 buffers_with_language_server.push(handle);
12573 }
12574 }
12575 let triggers = caps
12576 .trigger_characters
12577 .unwrap_or_default()
12578 .into_iter()
12579 .collect::<BTreeSet<_>>();
12580 for handle in buffers_with_language_server {
12581 let triggers = triggers.clone();
12582 let _ = handle.update(cx, move |buffer, cx| {
12583 buffer.set_completion_triggers(server_id, triggers, cx);
12584 });
12585 }
12586 }
12587 notify_server_capabilities_updated(&server, cx);
12588 }
12589 }
12590 "textDocument/hover" => {
12591 let options = parse_register_capabilities(reg)?;
12592 let provider = match options {
12593 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12594 OneOf::Right(caps) => caps,
12595 };
12596 server.update_capabilities(|capabilities| {
12597 capabilities.hover_provider = Some(provider);
12598 });
12599 notify_server_capabilities_updated(&server, cx);
12600 }
12601 "textDocument/signatureHelp" => {
12602 if let Some(caps) = reg
12603 .register_options
12604 .map(serde_json::from_value)
12605 .transpose()?
12606 {
12607 server.update_capabilities(|capabilities| {
12608 capabilities.signature_help_provider = Some(caps);
12609 });
12610 notify_server_capabilities_updated(&server, cx);
12611 }
12612 }
12613 "textDocument/didChange" => {
12614 if let Some(sync_kind) = reg
12615 .register_options
12616 .and_then(|opts| opts.get("syncKind").cloned())
12617 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12618 .transpose()?
12619 {
12620 server.update_capabilities(|capabilities| {
12621 let mut sync_options =
12622 Self::take_text_document_sync_options(capabilities);
12623 sync_options.change = Some(sync_kind);
12624 capabilities.text_document_sync =
12625 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12626 });
12627 notify_server_capabilities_updated(&server, cx);
12628 }
12629 }
12630 "textDocument/didSave" => {
12631 if let Some(include_text) = reg
12632 .register_options
12633 .map(|opts| {
12634 let transpose = opts
12635 .get("includeText")
12636 .cloned()
12637 .map(serde_json::from_value::<Option<bool>>)
12638 .transpose();
12639 match transpose {
12640 Ok(value) => Ok(value.flatten()),
12641 Err(e) => Err(e),
12642 }
12643 })
12644 .transpose()?
12645 {
12646 server.update_capabilities(|capabilities| {
12647 let mut sync_options =
12648 Self::take_text_document_sync_options(capabilities);
12649 sync_options.save =
12650 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12651 include_text,
12652 }));
12653 capabilities.text_document_sync =
12654 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12655 });
12656 notify_server_capabilities_updated(&server, cx);
12657 }
12658 }
12659 "textDocument/codeLens" => {
12660 if let Some(caps) = reg
12661 .register_options
12662 .map(serde_json::from_value)
12663 .transpose()?
12664 {
12665 server.update_capabilities(|capabilities| {
12666 capabilities.code_lens_provider = Some(caps);
12667 });
12668 notify_server_capabilities_updated(&server, cx);
12669 }
12670 }
12671 "textDocument/diagnostic" => {
12672 if let Some(caps) = reg
12673 .register_options
12674 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12675 .transpose()?
12676 {
12677 let local = self
12678 .as_local_mut()
12679 .context("Expected LSP Store to be local")?;
12680 let state = local
12681 .language_servers
12682 .get_mut(&server_id)
12683 .context("Could not obtain Language Servers state")?;
12684 local
12685 .language_server_dynamic_registrations
12686 .entry(server_id)
12687 .or_default()
12688 .diagnostics
12689 .insert(Some(reg.id.clone()), caps.clone());
12690
12691 let supports_workspace_diagnostics =
12692 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12693 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12694 diagnostic_options.workspace_diagnostics
12695 }
12696 DiagnosticServerCapabilities::RegistrationOptions(
12697 diagnostic_registration_options,
12698 ) => {
12699 diagnostic_registration_options
12700 .diagnostic_options
12701 .workspace_diagnostics
12702 }
12703 };
12704
12705 if supports_workspace_diagnostics(&caps) {
12706 if let LanguageServerState::Running {
12707 workspace_diagnostics_refresh_tasks,
12708 ..
12709 } = state
12710 && let Some(task) = lsp_workspace_diagnostics_refresh(
12711 Some(reg.id.clone()),
12712 caps.clone(),
12713 server.clone(),
12714 cx,
12715 )
12716 {
12717 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12718 }
12719 }
12720
12721 server.update_capabilities(|capabilities| {
12722 capabilities.diagnostic_provider = Some(caps);
12723 });
12724
12725 notify_server_capabilities_updated(&server, cx);
12726
12727 self.pull_document_diagnostics_for_server(server_id, cx)
12728 .detach();
12729 }
12730 }
12731 "textDocument/documentColor" => {
12732 let options = parse_register_capabilities(reg)?;
12733 let provider = match options {
12734 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12735 OneOf::Right(caps) => caps,
12736 };
12737 server.update_capabilities(|capabilities| {
12738 capabilities.color_provider = Some(provider);
12739 });
12740 notify_server_capabilities_updated(&server, cx);
12741 }
12742 _ => log::warn!("unhandled capability registration: {reg:?}"),
12743 }
12744 }
12745
12746 Ok(())
12747 }
12748
12749 fn unregister_server_capabilities(
12750 &mut self,
12751 server_id: LanguageServerId,
12752 params: lsp::UnregistrationParams,
12753 cx: &mut Context<Self>,
12754 ) -> anyhow::Result<()> {
12755 let server = self
12756 .language_server_for_id(server_id)
12757 .with_context(|| format!("no server {server_id} found"))?;
12758 for unreg in params.unregisterations.iter() {
12759 match unreg.method.as_str() {
12760 "workspace/didChangeWatchedFiles" => {
12761 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12762 local_lsp_store
12763 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12764 true
12765 } else {
12766 false
12767 };
12768 if notify {
12769 notify_server_capabilities_updated(&server, cx);
12770 }
12771 }
12772 "workspace/didChangeConfiguration" => {
12773 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12774 }
12775 "workspace/didChangeWorkspaceFolders" => {
12776 server.update_capabilities(|capabilities| {
12777 capabilities
12778 .workspace
12779 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12780 workspace_folders: None,
12781 file_operations: None,
12782 })
12783 .workspace_folders = None;
12784 });
12785 notify_server_capabilities_updated(&server, cx);
12786 }
12787 "workspace/symbol" => {
12788 server.update_capabilities(|capabilities| {
12789 capabilities.workspace_symbol_provider = None
12790 });
12791 notify_server_capabilities_updated(&server, cx);
12792 }
12793 "workspace/fileOperations" => {
12794 server.update_capabilities(|capabilities| {
12795 capabilities
12796 .workspace
12797 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12798 workspace_folders: None,
12799 file_operations: None,
12800 })
12801 .file_operations = None;
12802 });
12803 notify_server_capabilities_updated(&server, cx);
12804 }
12805 "workspace/executeCommand" => {
12806 server.update_capabilities(|capabilities| {
12807 capabilities.execute_command_provider = None;
12808 });
12809 notify_server_capabilities_updated(&server, cx);
12810 }
12811 "textDocument/rangeFormatting" => {
12812 server.update_capabilities(|capabilities| {
12813 capabilities.document_range_formatting_provider = None
12814 });
12815 notify_server_capabilities_updated(&server, cx);
12816 }
12817 "textDocument/onTypeFormatting" => {
12818 server.update_capabilities(|capabilities| {
12819 capabilities.document_on_type_formatting_provider = None;
12820 });
12821 notify_server_capabilities_updated(&server, cx);
12822 }
12823 "textDocument/formatting" => {
12824 server.update_capabilities(|capabilities| {
12825 capabilities.document_formatting_provider = None;
12826 });
12827 notify_server_capabilities_updated(&server, cx);
12828 }
12829 "textDocument/rename" => {
12830 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12831 notify_server_capabilities_updated(&server, cx);
12832 }
12833 "textDocument/codeAction" => {
12834 server.update_capabilities(|capabilities| {
12835 capabilities.code_action_provider = None;
12836 });
12837 notify_server_capabilities_updated(&server, cx);
12838 }
12839 "textDocument/definition" => {
12840 server.update_capabilities(|capabilities| {
12841 capabilities.definition_provider = None;
12842 });
12843 notify_server_capabilities_updated(&server, cx);
12844 }
12845 "textDocument/completion" => {
12846 server.update_capabilities(|capabilities| {
12847 capabilities.completion_provider = None;
12848 });
12849 notify_server_capabilities_updated(&server, cx);
12850 }
12851 "textDocument/hover" => {
12852 server.update_capabilities(|capabilities| {
12853 capabilities.hover_provider = None;
12854 });
12855 notify_server_capabilities_updated(&server, cx);
12856 }
12857 "textDocument/signatureHelp" => {
12858 server.update_capabilities(|capabilities| {
12859 capabilities.signature_help_provider = None;
12860 });
12861 notify_server_capabilities_updated(&server, cx);
12862 }
12863 "textDocument/didChange" => {
12864 server.update_capabilities(|capabilities| {
12865 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12866 sync_options.change = None;
12867 capabilities.text_document_sync =
12868 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12869 });
12870 notify_server_capabilities_updated(&server, cx);
12871 }
12872 "textDocument/didSave" => {
12873 server.update_capabilities(|capabilities| {
12874 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12875 sync_options.save = None;
12876 capabilities.text_document_sync =
12877 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12878 });
12879 notify_server_capabilities_updated(&server, cx);
12880 }
12881 "textDocument/codeLens" => {
12882 server.update_capabilities(|capabilities| {
12883 capabilities.code_lens_provider = None;
12884 });
12885 notify_server_capabilities_updated(&server, cx);
12886 }
12887 "textDocument/diagnostic" => {
12888 let local = self
12889 .as_local_mut()
12890 .context("Expected LSP Store to be local")?;
12891
12892 let state = local
12893 .language_servers
12894 .get_mut(&server_id)
12895 .context("Could not obtain Language Servers state")?;
12896 let registrations = local
12897 .language_server_dynamic_registrations
12898 .get_mut(&server_id)
12899 .with_context(|| {
12900 format!("Expected dynamic registration to exist for server {server_id}")
12901 })?;
12902 registrations.diagnostics
12903 .remove(&Some(unreg.id.clone()))
12904 .with_context(|| format!(
12905 "Attempted to unregister non-existent diagnostic registration with ID {}",
12906 unreg.id)
12907 )?;
12908 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12909
12910 if let LanguageServerState::Running {
12911 workspace_diagnostics_refresh_tasks,
12912 ..
12913 } = state
12914 {
12915 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12916 }
12917
12918 self.clear_unregistered_diagnostics(
12919 server_id,
12920 SharedString::from(unreg.id.clone()),
12921 cx,
12922 )?;
12923
12924 if removed_last_diagnostic_provider {
12925 server.update_capabilities(|capabilities| {
12926 debug_assert!(capabilities.diagnostic_provider.is_some());
12927 capabilities.diagnostic_provider = None;
12928 });
12929 }
12930
12931 notify_server_capabilities_updated(&server, cx);
12932 }
12933 "textDocument/documentColor" => {
12934 server.update_capabilities(|capabilities| {
12935 capabilities.color_provider = None;
12936 });
12937 notify_server_capabilities_updated(&server, cx);
12938 }
12939 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12940 }
12941 }
12942
12943 Ok(())
12944 }
12945
12946 fn clear_unregistered_diagnostics(
12947 &mut self,
12948 server_id: LanguageServerId,
12949 cleared_registration_id: SharedString,
12950 cx: &mut Context<Self>,
12951 ) -> anyhow::Result<()> {
12952 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12953
12954 self.buffer_store.update(cx, |buffer_store, cx| {
12955 for buffer_handle in buffer_store.buffers() {
12956 let buffer = buffer_handle.read(cx);
12957 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12958 let Some(abs_path) = abs_path else {
12959 continue;
12960 };
12961 affected_abs_paths.insert(abs_path);
12962 }
12963 });
12964
12965 let local = self.as_local().context("Expected LSP Store to be local")?;
12966 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12967 let Some(worktree) = self
12968 .worktree_store
12969 .read(cx)
12970 .worktree_for_id(*worktree_id, cx)
12971 else {
12972 continue;
12973 };
12974
12975 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12976 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12977 let has_matching_registration =
12978 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12979 entry.diagnostic.registration_id.as_ref()
12980 == Some(&cleared_registration_id)
12981 });
12982 if has_matching_registration {
12983 let abs_path = worktree.read(cx).absolutize(rel_path);
12984 affected_abs_paths.insert(abs_path);
12985 }
12986 }
12987 }
12988 }
12989
12990 if affected_abs_paths.is_empty() {
12991 return Ok(());
12992 }
12993
12994 // Send a fake diagnostic update which clears the state for the registration ID
12995 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12996 affected_abs_paths
12997 .into_iter()
12998 .map(|abs_path| DocumentDiagnosticsUpdate {
12999 diagnostics: DocumentDiagnostics {
13000 diagnostics: Vec::new(),
13001 document_abs_path: abs_path,
13002 version: None,
13003 },
13004 result_id: None,
13005 registration_id: Some(cleared_registration_id.clone()),
13006 server_id,
13007 disk_based_sources: Cow::Borrowed(&[]),
13008 })
13009 .collect();
13010
13011 let merge_registration_id = cleared_registration_id.clone();
13012 self.merge_diagnostic_entries(
13013 clears,
13014 move |_, diagnostic, _| {
13015 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13016 diagnostic.registration_id != Some(merge_registration_id.clone())
13017 } else {
13018 true
13019 }
13020 },
13021 cx,
13022 )?;
13023
13024 Ok(())
13025 }
13026
13027 async fn deduplicate_range_based_lsp_requests<T>(
13028 lsp_store: &Entity<Self>,
13029 server_id: Option<LanguageServerId>,
13030 lsp_request_id: LspRequestId,
13031 proto_request: &T::ProtoRequest,
13032 range: Range<Anchor>,
13033 cx: &mut AsyncApp,
13034 ) -> Result<()>
13035 where
13036 T: LspCommand,
13037 T::ProtoRequest: proto::LspRequestMessage,
13038 {
13039 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13040 let version = deserialize_version(proto_request.buffer_version());
13041 let buffer = lsp_store.update(cx, |this, cx| {
13042 this.buffer_store.read(cx).get_existing(buffer_id)
13043 })?;
13044 buffer
13045 .update(cx, |buffer, _| buffer.wait_for_version(version))
13046 .await?;
13047 lsp_store.update(cx, |lsp_store, cx| {
13048 let buffer_snapshot = buffer.read(cx).snapshot();
13049 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13050 let chunks_queried_for = lsp_data
13051 .inlay_hints
13052 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13053 .collect::<Vec<_>>();
13054 match chunks_queried_for.as_slice() {
13055 &[chunk] => {
13056 let key = LspKey {
13057 request_type: TypeId::of::<T>(),
13058 server_queried: server_id,
13059 };
13060 let previous_request = lsp_data
13061 .chunk_lsp_requests
13062 .entry(key)
13063 .or_default()
13064 .insert(chunk, lsp_request_id);
13065 if let Some((previous_request, running_requests)) =
13066 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13067 {
13068 running_requests.remove(&previous_request);
13069 }
13070 }
13071 _ambiguous_chunks => {
13072 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13073 // there, a buffer version-based check will be performed and outdated requests discarded.
13074 }
13075 }
13076 anyhow::Ok(())
13077 })?;
13078
13079 Ok(())
13080 }
13081
13082 async fn query_lsp_locally<T>(
13083 lsp_store: Entity<Self>,
13084 for_server_id: Option<LanguageServerId>,
13085 sender_id: proto::PeerId,
13086 lsp_request_id: LspRequestId,
13087 proto_request: T::ProtoRequest,
13088 position: Option<Anchor>,
13089 cx: &mut AsyncApp,
13090 ) -> Result<()>
13091 where
13092 T: LspCommand + Clone,
13093 T::ProtoRequest: proto::LspRequestMessage,
13094 <T::ProtoRequest as proto::RequestMessage>::Response:
13095 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13096 {
13097 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13098 let version = deserialize_version(proto_request.buffer_version());
13099 let buffer = lsp_store.update(cx, |this, cx| {
13100 this.buffer_store.read(cx).get_existing(buffer_id)
13101 })?;
13102 buffer
13103 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13104 .await?;
13105 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13106 let request =
13107 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13108 let key = LspKey {
13109 request_type: TypeId::of::<T>(),
13110 server_queried: for_server_id,
13111 };
13112 lsp_store.update(cx, |lsp_store, cx| {
13113 let request_task = match for_server_id {
13114 Some(server_id) => {
13115 let server_task = lsp_store.request_lsp(
13116 buffer.clone(),
13117 LanguageServerToQuery::Other(server_id),
13118 request.clone(),
13119 cx,
13120 );
13121 cx.background_spawn(async move {
13122 let mut responses = Vec::new();
13123 match server_task.await {
13124 Ok(response) => responses.push((server_id, response)),
13125 // rust-analyzer likes to error with this when its still loading up
13126 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13127 Err(e) => log::error!(
13128 "Error handling response for request {request:?}: {e:#}"
13129 ),
13130 }
13131 responses
13132 })
13133 }
13134 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13135 };
13136 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13137 if T::ProtoRequest::stop_previous_requests() {
13138 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13139 lsp_requests.clear();
13140 }
13141 }
13142 lsp_data.lsp_requests.entry(key).or_default().insert(
13143 lsp_request_id,
13144 cx.spawn(async move |lsp_store, cx| {
13145 let response = request_task.await;
13146 lsp_store
13147 .update(cx, |lsp_store, cx| {
13148 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13149 {
13150 let response = response
13151 .into_iter()
13152 .map(|(server_id, response)| {
13153 (
13154 server_id.to_proto(),
13155 T::response_to_proto(
13156 response,
13157 lsp_store,
13158 sender_id,
13159 &buffer_version,
13160 cx,
13161 )
13162 .into(),
13163 )
13164 })
13165 .collect::<HashMap<_, _>>();
13166 match client.send_lsp_response::<T::ProtoRequest>(
13167 project_id,
13168 lsp_request_id,
13169 response,
13170 ) {
13171 Ok(()) => {}
13172 Err(e) => {
13173 log::error!("Failed to send LSP response: {e:#}",)
13174 }
13175 }
13176 }
13177 })
13178 .ok();
13179 }),
13180 );
13181 });
13182 Ok(())
13183 }
13184
13185 fn take_text_document_sync_options(
13186 capabilities: &mut lsp::ServerCapabilities,
13187 ) -> lsp::TextDocumentSyncOptions {
13188 match capabilities.text_document_sync.take() {
13189 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13190 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13191 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13192 sync_options.change = Some(sync_kind);
13193 sync_options
13194 }
13195 None => lsp::TextDocumentSyncOptions::default(),
13196 }
13197 }
13198
13199 #[cfg(any(test, feature = "test-support"))]
13200 pub fn forget_code_lens_task(&mut self, buffer_id: BufferId) -> Option<CodeLensTask> {
13201 Some(
13202 self.lsp_data
13203 .get_mut(&buffer_id)?
13204 .code_lens
13205 .take()?
13206 .update
13207 .take()?
13208 .1,
13209 )
13210 }
13211
13212 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13213 self.downstream_client.clone()
13214 }
13215
13216 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13217 self.worktree_store.clone()
13218 }
13219
13220 /// Gets what's stored in the LSP data for the given buffer.
13221 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13222 self.lsp_data.get_mut(&buffer_id)
13223 }
13224
13225 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13226 /// new [`BufferLspData`] will be created to replace the previous state.
13227 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13228 let (buffer_id, buffer_version) =
13229 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13230 let lsp_data = self
13231 .lsp_data
13232 .entry(buffer_id)
13233 .or_insert_with(|| BufferLspData::new(buffer, cx));
13234 if buffer_version.changed_since(&lsp_data.buffer_version) {
13235 *lsp_data = BufferLspData::new(buffer, cx);
13236 }
13237 lsp_data
13238 }
13239}
13240
13241// Registration with registerOptions as null, should fallback to true.
13242// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13243fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13244 reg: lsp::Registration,
13245) -> Result<OneOf<bool, T>> {
13246 Ok(match reg.register_options {
13247 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13248 None => OneOf::Left(true),
13249 })
13250}
13251
13252fn subscribe_to_binary_statuses(
13253 languages: &Arc<LanguageRegistry>,
13254 cx: &mut Context<'_, LspStore>,
13255) -> Task<()> {
13256 let mut server_statuses = languages.language_server_binary_statuses();
13257 cx.spawn(async move |lsp_store, cx| {
13258 while let Some((server_name, binary_status)) = server_statuses.next().await {
13259 if lsp_store
13260 .update(cx, |_, cx| {
13261 let mut message = None;
13262 let binary_status = match binary_status {
13263 BinaryStatus::None => proto::ServerBinaryStatus::None,
13264 BinaryStatus::CheckingForUpdate => {
13265 proto::ServerBinaryStatus::CheckingForUpdate
13266 }
13267 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13268 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13269 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13270 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13271 BinaryStatus::Failed { error } => {
13272 message = Some(error);
13273 proto::ServerBinaryStatus::Failed
13274 }
13275 };
13276 cx.emit(LspStoreEvent::LanguageServerUpdate {
13277 // Binary updates are about the binary that might not have any language server id at that point.
13278 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13279 language_server_id: LanguageServerId(0),
13280 name: Some(server_name),
13281 message: proto::update_language_server::Variant::StatusUpdate(
13282 proto::StatusUpdate {
13283 message,
13284 status: Some(proto::status_update::Status::Binary(
13285 binary_status as i32,
13286 )),
13287 },
13288 ),
13289 });
13290 })
13291 .is_err()
13292 {
13293 break;
13294 }
13295 }
13296 })
13297}
13298
13299fn lsp_workspace_diagnostics_refresh(
13300 registration_id: Option<String>,
13301 options: DiagnosticServerCapabilities,
13302 server: Arc<LanguageServer>,
13303 cx: &mut Context<'_, LspStore>,
13304) -> Option<WorkspaceRefreshTask> {
13305 let identifier = workspace_diagnostic_identifier(&options)?;
13306 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13307
13308 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13309 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13310 refresh_tx.try_send(()).ok();
13311
13312 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13313 let mut attempts = 0;
13314 let max_attempts = 50;
13315 let mut requests = 0;
13316
13317 loop {
13318 let Some(()) = refresh_rx.recv().await else {
13319 return;
13320 };
13321
13322 'request: loop {
13323 requests += 1;
13324 if attempts > max_attempts {
13325 log::error!(
13326 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13327 );
13328 return;
13329 }
13330 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13331 cx.background_executor()
13332 .timer(Duration::from_millis(backoff_millis))
13333 .await;
13334 attempts += 1;
13335
13336 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13337 lsp_store
13338 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13339 .into_iter()
13340 .filter_map(|(abs_path, result_id)| {
13341 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13342 Some(lsp::PreviousResultId {
13343 uri,
13344 value: result_id.to_string(),
13345 })
13346 })
13347 .collect()
13348 }) else {
13349 return;
13350 };
13351
13352 let token = if let Some(registration_id) = ®istration_id {
13353 format!(
13354 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13355 server.server_id(),
13356 )
13357 } else {
13358 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13359 };
13360
13361 progress_rx.try_recv().ok();
13362 let timer =
13363 LanguageServer::default_request_timer(cx.background_executor().clone()).fuse();
13364 let progress = pin!(progress_rx.recv().fuse());
13365 let response_result = server
13366 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13367 lsp::WorkspaceDiagnosticParams {
13368 previous_result_ids,
13369 identifier: identifier.clone(),
13370 work_done_progress_params: Default::default(),
13371 partial_result_params: lsp::PartialResultParams {
13372 partial_result_token: Some(lsp::ProgressToken::String(token)),
13373 },
13374 },
13375 select(timer, progress).then(|either| match either {
13376 Either::Left((message, ..)) => ready(message).left_future(),
13377 Either::Right(..) => pending::<String>().right_future(),
13378 }),
13379 )
13380 .await;
13381
13382 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13383 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13384 match response_result {
13385 ConnectionResult::Timeout => {
13386 log::error!("Timeout during workspace diagnostics pull");
13387 continue 'request;
13388 }
13389 ConnectionResult::ConnectionReset => {
13390 log::error!("Server closed a workspace diagnostics pull request");
13391 continue 'request;
13392 }
13393 ConnectionResult::Result(Err(e)) => {
13394 log::error!("Error during workspace diagnostics pull: {e:#}");
13395 break 'request;
13396 }
13397 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13398 attempts = 0;
13399 if lsp_store
13400 .update(cx, |lsp_store, cx| {
13401 lsp_store.apply_workspace_diagnostic_report(
13402 server.server_id(),
13403 pulled_diagnostics,
13404 registration_id_shared.clone(),
13405 cx,
13406 )
13407 })
13408 .is_err()
13409 {
13410 return;
13411 }
13412 break 'request;
13413 }
13414 }
13415 }
13416 }
13417 });
13418
13419 Some(WorkspaceRefreshTask {
13420 refresh_tx,
13421 progress_tx,
13422 task: workspace_query_language_server,
13423 })
13424}
13425
13426fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<String> {
13427 match &options {
13428 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13429 diagnostic_options.identifier.clone()
13430 }
13431 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13432 let diagnostic_options = ®istration_options.diagnostic_options;
13433 diagnostic_options.identifier.clone()
13434 }
13435 }
13436}
13437
13438fn workspace_diagnostic_identifier(
13439 options: &DiagnosticServerCapabilities,
13440) -> Option<Option<String>> {
13441 match &options {
13442 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13443 if !diagnostic_options.workspace_diagnostics {
13444 return None;
13445 }
13446 Some(diagnostic_options.identifier.clone())
13447 }
13448 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13449 let diagnostic_options = ®istration_options.diagnostic_options;
13450 if !diagnostic_options.workspace_diagnostics {
13451 return None;
13452 }
13453 Some(diagnostic_options.identifier.clone())
13454 }
13455 }
13456}
13457
13458fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13459 let CompletionSource::BufferWord {
13460 word_range,
13461 resolved,
13462 } = &mut completion.source
13463 else {
13464 return;
13465 };
13466 if *resolved {
13467 return;
13468 }
13469
13470 if completion.new_text
13471 != snapshot
13472 .text_for_range(word_range.clone())
13473 .collect::<String>()
13474 {
13475 return;
13476 }
13477
13478 let mut offset = 0;
13479 for chunk in snapshot.chunks(word_range.clone(), true) {
13480 let end_offset = offset + chunk.text.len();
13481 if let Some(highlight_id) = chunk.syntax_highlight_id {
13482 completion
13483 .label
13484 .runs
13485 .push((offset..end_offset, highlight_id));
13486 }
13487 offset = end_offset;
13488 }
13489 *resolved = true;
13490}
13491
13492impl EventEmitter<LspStoreEvent> for LspStore {}
13493
13494fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13495 hover
13496 .contents
13497 .retain(|hover_block| !hover_block.text.trim().is_empty());
13498 if hover.contents.is_empty() {
13499 None
13500 } else {
13501 Some(hover)
13502 }
13503}
13504
13505async fn populate_labels_for_completions(
13506 new_completions: Vec<CoreCompletion>,
13507 language: Option<Arc<Language>>,
13508 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13509) -> Vec<Completion> {
13510 let lsp_completions = new_completions
13511 .iter()
13512 .filter_map(|new_completion| {
13513 new_completion
13514 .source
13515 .lsp_completion(true)
13516 .map(|lsp_completion| lsp_completion.into_owned())
13517 })
13518 .collect::<Vec<_>>();
13519
13520 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13521 lsp_adapter
13522 .labels_for_completions(&lsp_completions, language)
13523 .await
13524 .log_err()
13525 .unwrap_or_default()
13526 } else {
13527 Vec::new()
13528 }
13529 .into_iter()
13530 .fuse();
13531
13532 let mut completions = Vec::new();
13533 for completion in new_completions {
13534 match completion.source.lsp_completion(true) {
13535 Some(lsp_completion) => {
13536 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13537
13538 let mut label = labels.next().flatten().unwrap_or_else(|| {
13539 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13540 });
13541 ensure_uniform_list_compatible_label(&mut label);
13542 completions.push(Completion {
13543 label,
13544 documentation,
13545 replace_range: completion.replace_range,
13546 new_text: completion.new_text,
13547 insert_text_mode: lsp_completion.insert_text_mode,
13548 source: completion.source,
13549 icon_path: None,
13550 confirm: None,
13551 match_start: None,
13552 snippet_deduplication_key: None,
13553 });
13554 }
13555 None => {
13556 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13557 ensure_uniform_list_compatible_label(&mut label);
13558 completions.push(Completion {
13559 label,
13560 documentation: None,
13561 replace_range: completion.replace_range,
13562 new_text: completion.new_text,
13563 source: completion.source,
13564 insert_text_mode: None,
13565 icon_path: None,
13566 confirm: None,
13567 match_start: None,
13568 snippet_deduplication_key: None,
13569 });
13570 }
13571 }
13572 }
13573 completions
13574}
13575
13576#[derive(Debug)]
13577pub enum LanguageServerToQuery {
13578 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13579 FirstCapable,
13580 /// Query a specific language server.
13581 Other(LanguageServerId),
13582}
13583
13584#[derive(Default)]
13585struct RenamePathsWatchedForServer {
13586 did_rename: Vec<RenameActionPredicate>,
13587 will_rename: Vec<RenameActionPredicate>,
13588}
13589
13590impl RenamePathsWatchedForServer {
13591 fn with_did_rename_patterns(
13592 mut self,
13593 did_rename: Option<&FileOperationRegistrationOptions>,
13594 ) -> Self {
13595 if let Some(did_rename) = did_rename {
13596 self.did_rename = did_rename
13597 .filters
13598 .iter()
13599 .filter_map(|filter| filter.try_into().log_err())
13600 .collect();
13601 }
13602 self
13603 }
13604 fn with_will_rename_patterns(
13605 mut self,
13606 will_rename: Option<&FileOperationRegistrationOptions>,
13607 ) -> Self {
13608 if let Some(will_rename) = will_rename {
13609 self.will_rename = will_rename
13610 .filters
13611 .iter()
13612 .filter_map(|filter| filter.try_into().log_err())
13613 .collect();
13614 }
13615 self
13616 }
13617
13618 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13619 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13620 }
13621 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13622 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13623 }
13624}
13625
13626impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13627 type Error = globset::Error;
13628 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13629 Ok(Self {
13630 kind: ops.pattern.matches.clone(),
13631 glob: GlobBuilder::new(&ops.pattern.glob)
13632 .case_insensitive(
13633 ops.pattern
13634 .options
13635 .as_ref()
13636 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13637 )
13638 .build()?
13639 .compile_matcher(),
13640 })
13641 }
13642}
13643struct RenameActionPredicate {
13644 glob: GlobMatcher,
13645 kind: Option<FileOperationPatternKind>,
13646}
13647
13648impl RenameActionPredicate {
13649 // Returns true if language server should be notified
13650 fn eval(&self, path: &str, is_dir: bool) -> bool {
13651 self.kind.as_ref().is_none_or(|kind| {
13652 let expected_kind = if is_dir {
13653 FileOperationPatternKind::Folder
13654 } else {
13655 FileOperationPatternKind::File
13656 };
13657 kind == &expected_kind
13658 }) && self.glob.is_match(path)
13659 }
13660}
13661
13662#[derive(Default)]
13663struct LanguageServerWatchedPaths {
13664 worktree_paths: HashMap<WorktreeId, GlobSet>,
13665 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13666}
13667
13668#[derive(Default)]
13669struct LanguageServerWatchedPathsBuilder {
13670 worktree_paths: HashMap<WorktreeId, GlobSet>,
13671 abs_paths: HashMap<Arc<Path>, GlobSet>,
13672}
13673
13674impl LanguageServerWatchedPathsBuilder {
13675 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13676 self.worktree_paths.insert(worktree_id, glob_set);
13677 }
13678 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13679 self.abs_paths.insert(path, glob_set);
13680 }
13681 fn build(
13682 self,
13683 fs: Arc<dyn Fs>,
13684 language_server_id: LanguageServerId,
13685 cx: &mut Context<LspStore>,
13686 ) -> LanguageServerWatchedPaths {
13687 let lsp_store = cx.weak_entity();
13688
13689 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13690 let abs_paths = self
13691 .abs_paths
13692 .into_iter()
13693 .map(|(abs_path, globset)| {
13694 let task = cx.spawn({
13695 let abs_path = abs_path.clone();
13696 let fs = fs.clone();
13697
13698 let lsp_store = lsp_store.clone();
13699 async move |_, cx| {
13700 maybe!(async move {
13701 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13702 while let Some(update) = push_updates.0.next().await {
13703 let action = lsp_store
13704 .update(cx, |this, _| {
13705 let Some(local) = this.as_local() else {
13706 return ControlFlow::Break(());
13707 };
13708 let Some(watcher) = local
13709 .language_server_watched_paths
13710 .get(&language_server_id)
13711 else {
13712 return ControlFlow::Break(());
13713 };
13714 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13715 "Watched abs path is not registered with a watcher",
13716 );
13717 let matching_entries = update
13718 .into_iter()
13719 .filter(|event| globs.is_match(&event.path))
13720 .collect::<Vec<_>>();
13721 this.lsp_notify_abs_paths_changed(
13722 language_server_id,
13723 matching_entries,
13724 );
13725 ControlFlow::Continue(())
13726 })
13727 .ok()?;
13728
13729 if action.is_break() {
13730 break;
13731 }
13732 }
13733 Some(())
13734 })
13735 .await;
13736 }
13737 });
13738 (abs_path, (globset, task))
13739 })
13740 .collect();
13741 LanguageServerWatchedPaths {
13742 worktree_paths: self.worktree_paths,
13743 abs_paths,
13744 }
13745 }
13746}
13747
13748struct LspBufferSnapshot {
13749 version: i32,
13750 snapshot: TextBufferSnapshot,
13751}
13752
13753/// A prompt requested by LSP server.
13754#[derive(Clone, Debug)]
13755pub struct LanguageServerPromptRequest {
13756 pub id: usize,
13757 pub level: PromptLevel,
13758 pub message: String,
13759 pub actions: Vec<MessageActionItem>,
13760 pub lsp_name: String,
13761 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13762}
13763
13764impl LanguageServerPromptRequest {
13765 pub fn new(
13766 level: PromptLevel,
13767 message: String,
13768 actions: Vec<MessageActionItem>,
13769 lsp_name: String,
13770 response_channel: smol::channel::Sender<MessageActionItem>,
13771 ) -> Self {
13772 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13773 LanguageServerPromptRequest {
13774 id,
13775 level,
13776 message,
13777 actions,
13778 lsp_name,
13779 response_channel,
13780 }
13781 }
13782 pub async fn respond(self, index: usize) -> Option<()> {
13783 if let Some(response) = self.actions.into_iter().nth(index) {
13784 self.response_channel.send(response).await.ok()
13785 } else {
13786 None
13787 }
13788 }
13789
13790 #[cfg(any(test, feature = "test-support"))]
13791 pub fn test(
13792 level: PromptLevel,
13793 message: String,
13794 actions: Vec<MessageActionItem>,
13795 lsp_name: String,
13796 ) -> Self {
13797 let (tx, _rx) = smol::channel::unbounded();
13798 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13799 }
13800}
13801impl PartialEq for LanguageServerPromptRequest {
13802 fn eq(&self, other: &Self) -> bool {
13803 self.message == other.message && self.actions == other.actions
13804 }
13805}
13806
13807#[derive(Clone, Debug, PartialEq)]
13808pub enum LanguageServerLogType {
13809 Log(MessageType),
13810 Trace { verbose_info: Option<String> },
13811 Rpc { received: bool },
13812}
13813
13814impl LanguageServerLogType {
13815 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13816 match self {
13817 Self::Log(log_type) => {
13818 use proto::log_message::LogLevel;
13819 let level = match *log_type {
13820 MessageType::ERROR => LogLevel::Error,
13821 MessageType::WARNING => LogLevel::Warning,
13822 MessageType::INFO => LogLevel::Info,
13823 MessageType::LOG => LogLevel::Log,
13824 other => {
13825 log::warn!("Unknown lsp log message type: {other:?}");
13826 LogLevel::Log
13827 }
13828 };
13829 proto::language_server_log::LogType::Log(proto::LogMessage {
13830 level: level as i32,
13831 })
13832 }
13833 Self::Trace { verbose_info } => {
13834 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13835 verbose_info: verbose_info.to_owned(),
13836 })
13837 }
13838 Self::Rpc { received } => {
13839 let kind = if *received {
13840 proto::rpc_message::Kind::Received
13841 } else {
13842 proto::rpc_message::Kind::Sent
13843 };
13844 let kind = kind as i32;
13845 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13846 }
13847 }
13848 }
13849
13850 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13851 use proto::log_message::LogLevel;
13852 use proto::rpc_message;
13853 match log_type {
13854 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13855 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13856 LogLevel::Error => MessageType::ERROR,
13857 LogLevel::Warning => MessageType::WARNING,
13858 LogLevel::Info => MessageType::INFO,
13859 LogLevel::Log => MessageType::LOG,
13860 },
13861 ),
13862 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13863 verbose_info: trace_message.verbose_info,
13864 },
13865 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13866 received: match rpc_message::Kind::from_i32(message.kind)
13867 .unwrap_or(rpc_message::Kind::Received)
13868 {
13869 rpc_message::Kind::Received => true,
13870 rpc_message::Kind::Sent => false,
13871 },
13872 },
13873 }
13874 }
13875}
13876
13877pub struct WorkspaceRefreshTask {
13878 refresh_tx: mpsc::Sender<()>,
13879 progress_tx: mpsc::Sender<()>,
13880 #[allow(dead_code)]
13881 task: Task<()>,
13882}
13883
13884pub enum LanguageServerState {
13885 Starting {
13886 startup: Task<Option<Arc<LanguageServer>>>,
13887 /// List of language servers that will be added to the workspace once it's initialization completes.
13888 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13889 },
13890
13891 Running {
13892 adapter: Arc<CachedLspAdapter>,
13893 server: Arc<LanguageServer>,
13894 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13895 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13896 },
13897}
13898
13899impl LanguageServerState {
13900 fn add_workspace_folder(&self, uri: Uri) {
13901 match self {
13902 LanguageServerState::Starting {
13903 pending_workspace_folders,
13904 ..
13905 } => {
13906 pending_workspace_folders.lock().insert(uri);
13907 }
13908 LanguageServerState::Running { server, .. } => {
13909 server.add_workspace_folder(uri);
13910 }
13911 }
13912 }
13913 fn _remove_workspace_folder(&self, uri: Uri) {
13914 match self {
13915 LanguageServerState::Starting {
13916 pending_workspace_folders,
13917 ..
13918 } => {
13919 pending_workspace_folders.lock().remove(&uri);
13920 }
13921 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13922 }
13923 }
13924}
13925
13926impl std::fmt::Debug for LanguageServerState {
13927 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13928 match self {
13929 LanguageServerState::Starting { .. } => {
13930 f.debug_struct("LanguageServerState::Starting").finish()
13931 }
13932 LanguageServerState::Running { .. } => {
13933 f.debug_struct("LanguageServerState::Running").finish()
13934 }
13935 }
13936 }
13937}
13938
13939#[derive(Clone, Debug, Serialize)]
13940pub struct LanguageServerProgress {
13941 pub is_disk_based_diagnostics_progress: bool,
13942 pub is_cancellable: bool,
13943 pub title: Option<String>,
13944 pub message: Option<String>,
13945 pub percentage: Option<usize>,
13946 #[serde(skip_serializing)]
13947 pub last_update_at: Instant,
13948}
13949
13950#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13951pub struct DiagnosticSummary {
13952 pub error_count: usize,
13953 pub warning_count: usize,
13954}
13955
13956impl DiagnosticSummary {
13957 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13958 let mut this = Self {
13959 error_count: 0,
13960 warning_count: 0,
13961 };
13962
13963 for entry in diagnostics {
13964 if entry.diagnostic.is_primary {
13965 match entry.diagnostic.severity {
13966 DiagnosticSeverity::ERROR => this.error_count += 1,
13967 DiagnosticSeverity::WARNING => this.warning_count += 1,
13968 _ => {}
13969 }
13970 }
13971 }
13972
13973 this
13974 }
13975
13976 pub fn is_empty(&self) -> bool {
13977 self.error_count == 0 && self.warning_count == 0
13978 }
13979
13980 pub fn to_proto(
13981 self,
13982 language_server_id: LanguageServerId,
13983 path: &RelPath,
13984 ) -> proto::DiagnosticSummary {
13985 proto::DiagnosticSummary {
13986 path: path.to_proto(),
13987 language_server_id: language_server_id.0 as u64,
13988 error_count: self.error_count as u32,
13989 warning_count: self.warning_count as u32,
13990 }
13991 }
13992}
13993
13994#[derive(Clone, Debug)]
13995pub enum CompletionDocumentation {
13996 /// There is no documentation for this completion.
13997 Undocumented,
13998 /// A single line of documentation.
13999 SingleLine(SharedString),
14000 /// Multiple lines of plain text documentation.
14001 MultiLinePlainText(SharedString),
14002 /// Markdown documentation.
14003 MultiLineMarkdown(SharedString),
14004 /// Both single line and multiple lines of plain text documentation.
14005 SingleLineAndMultiLinePlainText {
14006 single_line: SharedString,
14007 plain_text: Option<SharedString>,
14008 },
14009}
14010
14011impl CompletionDocumentation {
14012 #[cfg(any(test, feature = "test-support"))]
14013 pub fn text(&self) -> SharedString {
14014 match self {
14015 CompletionDocumentation::Undocumented => "".into(),
14016 CompletionDocumentation::SingleLine(s) => s.clone(),
14017 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14018 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14019 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14020 single_line.clone()
14021 }
14022 }
14023 }
14024}
14025
14026impl From<lsp::Documentation> for CompletionDocumentation {
14027 fn from(docs: lsp::Documentation) -> Self {
14028 match docs {
14029 lsp::Documentation::String(text) => {
14030 if text.lines().count() <= 1 {
14031 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14032 } else {
14033 CompletionDocumentation::MultiLinePlainText(text.into())
14034 }
14035 }
14036
14037 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14038 lsp::MarkupKind::PlainText => {
14039 if value.lines().count() <= 1 {
14040 CompletionDocumentation::SingleLine(value.into())
14041 } else {
14042 CompletionDocumentation::MultiLinePlainText(value.into())
14043 }
14044 }
14045
14046 lsp::MarkupKind::Markdown => {
14047 CompletionDocumentation::MultiLineMarkdown(value.into())
14048 }
14049 },
14050 }
14051 }
14052}
14053
14054pub enum ResolvedHint {
14055 Resolved(InlayHint),
14056 Resolving(Shared<Task<()>>),
14057}
14058
14059fn glob_literal_prefix(glob: &Path) -> PathBuf {
14060 glob.components()
14061 .take_while(|component| match component {
14062 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14063 _ => true,
14064 })
14065 .collect()
14066}
14067
14068pub struct SshLspAdapter {
14069 name: LanguageServerName,
14070 binary: LanguageServerBinary,
14071 initialization_options: Option<String>,
14072 code_action_kinds: Option<Vec<CodeActionKind>>,
14073}
14074
14075impl SshLspAdapter {
14076 pub fn new(
14077 name: LanguageServerName,
14078 binary: LanguageServerBinary,
14079 initialization_options: Option<String>,
14080 code_action_kinds: Option<String>,
14081 ) -> Self {
14082 Self {
14083 name,
14084 binary,
14085 initialization_options,
14086 code_action_kinds: code_action_kinds
14087 .as_ref()
14088 .and_then(|c| serde_json::from_str(c).ok()),
14089 }
14090 }
14091}
14092
14093impl LspInstaller for SshLspAdapter {
14094 type BinaryVersion = ();
14095 async fn check_if_user_installed(
14096 &self,
14097 _: &dyn LspAdapterDelegate,
14098 _: Option<Toolchain>,
14099 _: &AsyncApp,
14100 ) -> Option<LanguageServerBinary> {
14101 Some(self.binary.clone())
14102 }
14103
14104 async fn cached_server_binary(
14105 &self,
14106 _: PathBuf,
14107 _: &dyn LspAdapterDelegate,
14108 ) -> Option<LanguageServerBinary> {
14109 None
14110 }
14111
14112 async fn fetch_latest_server_version(
14113 &self,
14114 _: &dyn LspAdapterDelegate,
14115 _: bool,
14116 _: &mut AsyncApp,
14117 ) -> Result<()> {
14118 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14119 }
14120
14121 async fn fetch_server_binary(
14122 &self,
14123 _: (),
14124 _: PathBuf,
14125 _: &dyn LspAdapterDelegate,
14126 ) -> Result<LanguageServerBinary> {
14127 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14128 }
14129}
14130
14131#[async_trait(?Send)]
14132impl LspAdapter for SshLspAdapter {
14133 fn name(&self) -> LanguageServerName {
14134 self.name.clone()
14135 }
14136
14137 async fn initialization_options(
14138 self: Arc<Self>,
14139 _: &Arc<dyn LspAdapterDelegate>,
14140 ) -> Result<Option<serde_json::Value>> {
14141 let Some(options) = &self.initialization_options else {
14142 return Ok(None);
14143 };
14144 let result = serde_json::from_str(options)?;
14145 Ok(result)
14146 }
14147
14148 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14149 self.code_action_kinds.clone()
14150 }
14151}
14152
14153pub fn language_server_settings<'a>(
14154 delegate: &'a dyn LspAdapterDelegate,
14155 language: &LanguageServerName,
14156 cx: &'a App,
14157) -> Option<&'a LspSettings> {
14158 language_server_settings_for(
14159 SettingsLocation {
14160 worktree_id: delegate.worktree_id(),
14161 path: RelPath::empty(),
14162 },
14163 language,
14164 cx,
14165 )
14166}
14167
14168pub fn language_server_settings_for<'a>(
14169 location: SettingsLocation<'a>,
14170 language: &LanguageServerName,
14171 cx: &'a App,
14172) -> Option<&'a LspSettings> {
14173 ProjectSettings::get(Some(location), cx).lsp.get(language)
14174}
14175
14176pub struct LocalLspAdapterDelegate {
14177 lsp_store: WeakEntity<LspStore>,
14178 worktree: worktree::Snapshot,
14179 fs: Arc<dyn Fs>,
14180 http_client: Arc<dyn HttpClient>,
14181 language_registry: Arc<LanguageRegistry>,
14182 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14183}
14184
14185impl LocalLspAdapterDelegate {
14186 pub fn new(
14187 language_registry: Arc<LanguageRegistry>,
14188 environment: &Entity<ProjectEnvironment>,
14189 lsp_store: WeakEntity<LspStore>,
14190 worktree: &Entity<Worktree>,
14191 http_client: Arc<dyn HttpClient>,
14192 fs: Arc<dyn Fs>,
14193 cx: &mut App,
14194 ) -> Arc<Self> {
14195 let load_shell_env_task =
14196 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14197
14198 Arc::new(Self {
14199 lsp_store,
14200 worktree: worktree.read(cx).snapshot(),
14201 fs,
14202 http_client,
14203 language_registry,
14204 load_shell_env_task,
14205 })
14206 }
14207
14208 pub fn from_local_lsp(
14209 local: &LocalLspStore,
14210 worktree: &Entity<Worktree>,
14211 cx: &mut App,
14212 ) -> Arc<Self> {
14213 Self::new(
14214 local.languages.clone(),
14215 &local.environment,
14216 local.weak.clone(),
14217 worktree,
14218 local.http_client.clone(),
14219 local.fs.clone(),
14220 cx,
14221 )
14222 }
14223}
14224
14225#[async_trait]
14226impl LspAdapterDelegate for LocalLspAdapterDelegate {
14227 fn show_notification(&self, message: &str, cx: &mut App) {
14228 self.lsp_store
14229 .update(cx, |_, cx| {
14230 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14231 })
14232 .ok();
14233 }
14234
14235 fn http_client(&self) -> Arc<dyn HttpClient> {
14236 self.http_client.clone()
14237 }
14238
14239 fn worktree_id(&self) -> WorktreeId {
14240 self.worktree.id()
14241 }
14242
14243 fn worktree_root_path(&self) -> &Path {
14244 self.worktree.abs_path().as_ref()
14245 }
14246
14247 fn resolve_executable_path(&self, path: PathBuf) -> PathBuf {
14248 self.worktree.resolve_executable_path(path)
14249 }
14250
14251 async fn shell_env(&self) -> HashMap<String, String> {
14252 let task = self.load_shell_env_task.clone();
14253 task.await.unwrap_or_default()
14254 }
14255
14256 async fn npm_package_installed_version(
14257 &self,
14258 package_name: &str,
14259 ) -> Result<Option<(PathBuf, Version)>> {
14260 let local_package_directory = self.worktree_root_path();
14261 let node_modules_directory = local_package_directory.join("node_modules");
14262
14263 if let Some(version) =
14264 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14265 {
14266 return Ok(Some((node_modules_directory, version)));
14267 }
14268 let Some(npm) = self.which("npm".as_ref()).await else {
14269 log::warn!(
14270 "Failed to find npm executable for {:?}",
14271 local_package_directory
14272 );
14273 return Ok(None);
14274 };
14275
14276 let env = self.shell_env().await;
14277 let output = util::command::new_smol_command(&npm)
14278 .args(["root", "-g"])
14279 .envs(env)
14280 .current_dir(local_package_directory)
14281 .output()
14282 .await?;
14283 let global_node_modules =
14284 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14285
14286 if let Some(version) =
14287 read_package_installed_version(global_node_modules.clone(), package_name).await?
14288 {
14289 return Ok(Some((global_node_modules, version)));
14290 }
14291 return Ok(None);
14292 }
14293
14294 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14295 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14296 if self.fs.is_file(&worktree_abs_path).await {
14297 worktree_abs_path.pop();
14298 }
14299
14300 let env = self.shell_env().await;
14301
14302 let shell_path = env.get("PATH").cloned();
14303
14304 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14305 }
14306
14307 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14308 let mut working_dir = self.worktree_root_path().to_path_buf();
14309 if self.fs.is_file(&working_dir).await {
14310 working_dir.pop();
14311 }
14312 let output = util::command::new_smol_command(&command.path)
14313 .args(command.arguments)
14314 .envs(command.env.clone().unwrap_or_default())
14315 .current_dir(working_dir)
14316 .output()
14317 .await?;
14318
14319 anyhow::ensure!(
14320 output.status.success(),
14321 "{}, stdout: {:?}, stderr: {:?}",
14322 output.status,
14323 String::from_utf8_lossy(&output.stdout),
14324 String::from_utf8_lossy(&output.stderr)
14325 );
14326 Ok(())
14327 }
14328
14329 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14330 self.language_registry
14331 .update_lsp_binary_status(server_name, status);
14332 }
14333
14334 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14335 self.language_registry
14336 .all_lsp_adapters()
14337 .into_iter()
14338 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14339 .collect()
14340 }
14341
14342 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14343 let dir = self.language_registry.language_server_download_dir(name)?;
14344
14345 if !dir.exists() {
14346 smol::fs::create_dir_all(&dir)
14347 .await
14348 .context("failed to create container directory")
14349 .log_err()?;
14350 }
14351
14352 Some(dir)
14353 }
14354
14355 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14356 let entry = self
14357 .worktree
14358 .entry_for_path(path)
14359 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14360 let abs_path = self.worktree.absolutize(&entry.path);
14361 self.fs.load(&abs_path).await
14362 }
14363}
14364
14365async fn populate_labels_for_symbols(
14366 symbols: Vec<CoreSymbol>,
14367 language_registry: &Arc<LanguageRegistry>,
14368 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14369 output: &mut Vec<Symbol>,
14370) {
14371 #[allow(clippy::mutable_key_type)]
14372 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14373
14374 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14375 for symbol in symbols {
14376 let Some(file_name) = symbol.path.file_name() else {
14377 continue;
14378 };
14379 let language = language_registry
14380 .load_language_for_file_path(Path::new(file_name))
14381 .await
14382 .ok()
14383 .or_else(|| {
14384 unknown_paths.insert(file_name.into());
14385 None
14386 });
14387 symbols_by_language
14388 .entry(language)
14389 .or_default()
14390 .push(symbol);
14391 }
14392
14393 for unknown_path in unknown_paths {
14394 log::info!("no language found for symbol in file {unknown_path:?}");
14395 }
14396
14397 let mut label_params = Vec::new();
14398 for (language, mut symbols) in symbols_by_language {
14399 label_params.clear();
14400 label_params.extend(
14401 symbols
14402 .iter_mut()
14403 .map(|symbol| (mem::take(&mut symbol.name), symbol.kind)),
14404 );
14405
14406 let mut labels = Vec::new();
14407 if let Some(language) = language {
14408 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14409 language_registry
14410 .lsp_adapters(&language.name())
14411 .first()
14412 .cloned()
14413 });
14414 if let Some(lsp_adapter) = lsp_adapter {
14415 labels = lsp_adapter
14416 .labels_for_symbols(&label_params, &language)
14417 .await
14418 .log_err()
14419 .unwrap_or_default();
14420 }
14421 }
14422
14423 for ((symbol, (name, _)), label) in symbols
14424 .into_iter()
14425 .zip(label_params.drain(..))
14426 .zip(labels.into_iter().chain(iter::repeat(None)))
14427 {
14428 output.push(Symbol {
14429 language_server_name: symbol.language_server_name,
14430 source_worktree_id: symbol.source_worktree_id,
14431 source_language_server_id: symbol.source_language_server_id,
14432 path: symbol.path,
14433 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14434 name,
14435 kind: symbol.kind,
14436 range: symbol.range,
14437 });
14438 }
14439 }
14440}
14441
14442fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14443 match server.capabilities().text_document_sync.as_ref()? {
14444 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14445 // Server wants didSave but didn't specify includeText.
14446 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14447 // Server doesn't want didSave at all.
14448 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14449 // Server provided SaveOptions.
14450 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14451 Some(save_options.include_text.unwrap_or(false))
14452 }
14453 },
14454 // We do not have any save info. Kind affects didChange only.
14455 lsp::TextDocumentSyncCapability::Kind(_) => None,
14456 }
14457}
14458
14459/// Completion items are displayed in a `UniformList`.
14460/// Usually, those items are single-line strings, but in LSP responses,
14461/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14462/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14463/// 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,
14464/// breaking the completions menu presentation.
14465///
14466/// 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.
14467fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14468 let mut new_text = String::with_capacity(label.text.len());
14469 let mut offset_map = vec![0; label.text.len() + 1];
14470 let mut last_char_was_space = false;
14471 let mut new_idx = 0;
14472 let chars = label.text.char_indices().fuse();
14473 let mut newlines_removed = false;
14474
14475 for (idx, c) in chars {
14476 offset_map[idx] = new_idx;
14477
14478 match c {
14479 '\n' if last_char_was_space => {
14480 newlines_removed = true;
14481 }
14482 '\t' | ' ' if last_char_was_space => {}
14483 '\n' if !last_char_was_space => {
14484 new_text.push(' ');
14485 new_idx += 1;
14486 last_char_was_space = true;
14487 newlines_removed = true;
14488 }
14489 ' ' | '\t' => {
14490 new_text.push(' ');
14491 new_idx += 1;
14492 last_char_was_space = true;
14493 }
14494 _ => {
14495 new_text.push(c);
14496 new_idx += c.len_utf8();
14497 last_char_was_space = false;
14498 }
14499 }
14500 }
14501 offset_map[label.text.len()] = new_idx;
14502
14503 // Only modify the label if newlines were removed.
14504 if !newlines_removed {
14505 return;
14506 }
14507
14508 let last_index = new_idx;
14509 let mut run_ranges_errors = Vec::new();
14510 label.runs.retain_mut(|(range, _)| {
14511 match offset_map.get(range.start) {
14512 Some(&start) => range.start = start,
14513 None => {
14514 run_ranges_errors.push(range.clone());
14515 return false;
14516 }
14517 }
14518
14519 match offset_map.get(range.end) {
14520 Some(&end) => range.end = end,
14521 None => {
14522 run_ranges_errors.push(range.clone());
14523 range.end = last_index;
14524 }
14525 }
14526 true
14527 });
14528 if !run_ranges_errors.is_empty() {
14529 log::error!(
14530 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14531 label.text
14532 );
14533 }
14534
14535 let mut wrong_filter_range = None;
14536 if label.filter_range == (0..label.text.len()) {
14537 label.filter_range = 0..new_text.len();
14538 } else {
14539 let mut original_filter_range = Some(label.filter_range.clone());
14540 match offset_map.get(label.filter_range.start) {
14541 Some(&start) => label.filter_range.start = start,
14542 None => {
14543 wrong_filter_range = original_filter_range.take();
14544 label.filter_range.start = last_index;
14545 }
14546 }
14547
14548 match offset_map.get(label.filter_range.end) {
14549 Some(&end) => label.filter_range.end = end,
14550 None => {
14551 wrong_filter_range = original_filter_range.take();
14552 label.filter_range.end = last_index;
14553 }
14554 }
14555 }
14556 if let Some(wrong_filter_range) = wrong_filter_range {
14557 log::error!(
14558 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14559 label.text
14560 );
14561 }
14562
14563 label.text = new_text;
14564}
14565
14566#[cfg(test)]
14567mod tests {
14568 use language::HighlightId;
14569
14570 use super::*;
14571
14572 #[test]
14573 fn test_glob_literal_prefix() {
14574 assert_eq!(glob_literal_prefix(Path::new("**/*.js")), Path::new(""));
14575 assert_eq!(
14576 glob_literal_prefix(Path::new("node_modules/**/*.js")),
14577 Path::new("node_modules")
14578 );
14579 assert_eq!(
14580 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14581 Path::new("foo")
14582 );
14583 assert_eq!(
14584 glob_literal_prefix(Path::new("foo/bar/baz.js")),
14585 Path::new("foo/bar/baz.js")
14586 );
14587
14588 #[cfg(target_os = "windows")]
14589 {
14590 assert_eq!(glob_literal_prefix(Path::new("**\\*.js")), Path::new(""));
14591 assert_eq!(
14592 glob_literal_prefix(Path::new("node_modules\\**/*.js")),
14593 Path::new("node_modules")
14594 );
14595 assert_eq!(
14596 glob_literal_prefix(Path::new("foo/{bar,baz}.js")),
14597 Path::new("foo")
14598 );
14599 assert_eq!(
14600 glob_literal_prefix(Path::new("foo\\bar\\baz.js")),
14601 Path::new("foo/bar/baz.js")
14602 );
14603 }
14604 }
14605
14606 #[test]
14607 fn test_multi_len_chars_normalization() {
14608 let mut label = CodeLabel::new(
14609 "myElˇ (parameter) myElˇ: {\n foo: string;\n}".to_string(),
14610 0..6,
14611 vec![(0..6, HighlightId(1))],
14612 );
14613 ensure_uniform_list_compatible_label(&mut label);
14614 assert_eq!(
14615 label,
14616 CodeLabel::new(
14617 "myElˇ (parameter) myElˇ: { foo: string; }".to_string(),
14618 0..6,
14619 vec![(0..6, HighlightId(1))],
14620 )
14621 );
14622 }
14623
14624 #[test]
14625 fn test_trailing_newline_in_completion_documentation() {
14626 let doc = lsp::Documentation::String(
14627 "Inappropriate argument value (of correct type).\n".to_string(),
14628 );
14629 let completion_doc: CompletionDocumentation = doc.into();
14630 assert!(
14631 matches!(completion_doc, CompletionDocumentation::SingleLine(s) if s == "Inappropriate argument value (of correct type).")
14632 );
14633
14634 let doc = lsp::Documentation::String(" some value \n".to_string());
14635 let completion_doc: CompletionDocumentation = doc.into();
14636 assert!(matches!(
14637 completion_doc,
14638 CompletionDocumentation::SingleLine(s) if s == "some value"
14639 ));
14640 }
14641}