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;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
77 Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 language_settings,
81 },
82 point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153pub use semantic_tokens::{
154 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
155};
156
157pub use worktree::{
158 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
159 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
160};
161
162const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
163pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
164const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
165const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
166static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
167
168#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
169pub enum ProgressToken {
170 Number(i32),
171 String(SharedString),
172}
173
174impl std::fmt::Display for ProgressToken {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Number(number) => write!(f, "{number}"),
178 Self::String(string) => write!(f, "{string}"),
179 }
180 }
181}
182
183impl ProgressToken {
184 fn from_lsp(value: lsp::NumberOrString) -> Self {
185 match value {
186 lsp::NumberOrString::Number(number) => Self::Number(number),
187 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
188 }
189 }
190
191 fn to_lsp(&self) -> lsp::NumberOrString {
192 match self {
193 Self::Number(number) => lsp::NumberOrString::Number(*number),
194 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
195 }
196 }
197
198 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
199 Some(match value.value? {
200 proto::progress_token::Value::Number(number) => Self::Number(number),
201 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
202 })
203 }
204
205 fn to_proto(&self) -> proto::ProgressToken {
206 proto::ProgressToken {
207 value: Some(match self {
208 Self::Number(number) => proto::progress_token::Value::Number(*number),
209 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
210 }),
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum FormatTrigger {
217 Save,
218 Manual,
219}
220
221pub enum LspFormatTarget {
222 Buffers,
223 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
228
229struct OpenLspBuffer(Entity<Buffer>);
230
231impl FormatTrigger {
232 fn from_proto(value: i32) -> FormatTrigger {
233 match value {
234 0 => FormatTrigger::Save,
235 1 => FormatTrigger::Manual,
236 _ => FormatTrigger::Save,
237 }
238 }
239}
240
241#[derive(Clone)]
242struct UnifiedLanguageServer {
243 id: LanguageServerId,
244 project_roots: HashSet<Arc<RelPath>>,
245}
246
247/// Settings that affect language server identity.
248///
249/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
250/// updated via `workspace/didChangeConfiguration` without restarting the server.
251#[derive(Clone, Debug, Hash, PartialEq, Eq)]
252struct LanguageServerSeedSettings {
253 binary: Option<BinarySettings>,
254 initialization_options: Option<serde_json::Value>,
255}
256
257#[derive(Clone, Debug, Hash, PartialEq, Eq)]
258struct LanguageServerSeed {
259 worktree_id: WorktreeId,
260 name: LanguageServerName,
261 toolchain: Option<Toolchain>,
262 settings: LanguageServerSeedSettings,
263}
264
265#[derive(Debug)]
266pub struct DocumentDiagnosticsUpdate<'a, D> {
267 pub diagnostics: D,
268 pub result_id: Option<SharedString>,
269 pub registration_id: Option<SharedString>,
270 pub server_id: LanguageServerId,
271 pub disk_based_sources: Cow<'a, [String]>,
272}
273
274pub struct DocumentDiagnostics {
275 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 document_abs_path: PathBuf,
277 version: Option<i32>,
278}
279
280#[derive(Default, Debug)]
281struct DynamicRegistrations {
282 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
283 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
284}
285
286pub struct LocalLspStore {
287 weak: WeakEntity<LspStore>,
288 pub worktree_store: Entity<WorktreeStore>,
289 toolchain_store: Entity<LocalToolchainStore>,
290 http_client: Arc<dyn HttpClient>,
291 environment: Entity<ProjectEnvironment>,
292 fs: Arc<dyn Fs>,
293 languages: Arc<LanguageRegistry>,
294 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
295 yarn: Entity<YarnPathStore>,
296 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
297 buffers_being_formatted: HashSet<BufferId>,
298 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
299 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
300 watched_manifest_filenames: HashSet<ManifestName>,
301 language_server_paths_watched_for_rename:
302 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
303 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
304 supplementary_language_servers:
305 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
306 prettier_store: Entity<PrettierStore>,
307 next_diagnostic_group_id: usize,
308 diagnostics: HashMap<
309 WorktreeId,
310 HashMap<
311 Arc<RelPath>,
312 Vec<(
313 LanguageServerId,
314 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
315 )>,
316 >,
317 >,
318 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
319 _subscription: gpui::Subscription,
320 lsp_tree: LanguageServerTree,
321 registered_buffers: HashMap<BufferId, usize>,
322 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
323 buffer_pull_diagnostics_result_ids: HashMap<
324 LanguageServerId,
325 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
326 >,
327 workspace_pull_diagnostics_result_ids: HashMap<
328 LanguageServerId,
329 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
330 >,
331 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
332
333 buffers_to_refresh_hash_set: HashSet<BufferId>,
334 buffers_to_refresh_queue: VecDeque<BufferId>,
335 _background_diagnostics_worker: Shared<Task<()>>,
336}
337
338impl LocalLspStore {
339 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
340 pub fn running_language_server_for_id(
341 &self,
342 id: LanguageServerId,
343 ) -> Option<&Arc<LanguageServer>> {
344 let language_server_state = self.language_servers.get(&id)?;
345
346 match language_server_state {
347 LanguageServerState::Running { server, .. } => Some(server),
348 LanguageServerState::Starting { .. } => None,
349 }
350 }
351
352 fn get_or_insert_language_server(
353 &mut self,
354 worktree_handle: &Entity<Worktree>,
355 delegate: Arc<LocalLspAdapterDelegate>,
356 disposition: &Arc<LaunchDisposition>,
357 language_name: &LanguageName,
358 cx: &mut App,
359 ) -> LanguageServerId {
360 let key = LanguageServerSeed {
361 worktree_id: worktree_handle.read(cx).id(),
362 name: disposition.server_name.clone(),
363 settings: LanguageServerSeedSettings {
364 binary: disposition.settings.binary.clone(),
365 initialization_options: disposition.settings.initialization_options.clone(),
366 },
367 toolchain: disposition.toolchain.clone(),
368 };
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 state.id
372 } else {
373 let adapter = self
374 .languages
375 .lsp_adapters(language_name)
376 .into_iter()
377 .find(|adapter| adapter.name() == disposition.server_name)
378 .expect("To find LSP adapter");
379 let new_language_server_id = self.start_language_server(
380 worktree_handle,
381 delegate,
382 adapter,
383 disposition.settings.clone(),
384 key.clone(),
385 language_name.clone(),
386 cx,
387 );
388 if let Some(state) = self.language_server_ids.get_mut(&key) {
389 state.project_roots.insert(disposition.path.path.clone());
390 } else {
391 debug_assert!(
392 false,
393 "Expected `start_language_server` to ensure that `key` exists in a map"
394 );
395 }
396 new_language_server_id
397 }
398 }
399
400 fn start_language_server(
401 &mut self,
402 worktree_handle: &Entity<Worktree>,
403 delegate: Arc<LocalLspAdapterDelegate>,
404 adapter: Arc<CachedLspAdapter>,
405 settings: Arc<LspSettings>,
406 key: LanguageServerSeed,
407 language_name: LanguageName,
408 cx: &mut App,
409 ) -> LanguageServerId {
410 let worktree = worktree_handle.read(cx);
411
412 let worktree_id = worktree.id();
413 let worktree_abs_path = worktree.abs_path();
414 let toolchain = key.toolchain.clone();
415 let override_options = settings.initialization_options.clone();
416
417 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
418
419 let server_id = self.languages.next_language_server_id();
420 log::trace!(
421 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
422 adapter.name.0
423 );
424
425 let wait_until_worktree_trust =
426 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
427 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
428 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
429 });
430 if can_trust {
431 self.restricted_worktrees_tasks.remove(&worktree_id);
432 None
433 } else {
434 match self.restricted_worktrees_tasks.entry(worktree_id) {
435 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
436 hash_map::Entry::Vacant(v) => {
437 let (mut tx, rx) = watch::channel::<bool>();
438 let lsp_store = self.weak.clone();
439 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
440 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
441 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
442 tx.blocking_send(true).ok();
443 lsp_store
444 .update(cx, |lsp_store, _| {
445 if let Some(local_lsp_store) =
446 lsp_store.as_local_mut()
447 {
448 local_lsp_store
449 .restricted_worktrees_tasks
450 .remove(&worktree_id);
451 }
452 })
453 .ok();
454 }
455 }
456 });
457 v.insert((subscription, rx.clone()));
458 Some(rx)
459 }
460 }
461 }
462 });
463 let update_binary_status = wait_until_worktree_trust.is_none();
464
465 let binary = self.get_language_server_binary(
466 worktree_abs_path.clone(),
467 adapter.clone(),
468 settings,
469 toolchain.clone(),
470 delegate.clone(),
471 true,
472 wait_until_worktree_trust,
473 cx,
474 );
475 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
476
477 let pending_server = cx.spawn({
478 let adapter = adapter.clone();
479 let server_name = adapter.name.clone();
480 let stderr_capture = stderr_capture.clone();
481 #[cfg(any(test, feature = "test-support"))]
482 let lsp_store = self.weak.clone();
483 let pending_workspace_folders = pending_workspace_folders.clone();
484 async move |cx| {
485 let binary = binary.await?;
486 #[cfg(any(test, feature = "test-support"))]
487 if let Some(server) = lsp_store
488 .update(&mut cx.clone(), |this, cx| {
489 this.languages.create_fake_language_server(
490 server_id,
491 &server_name,
492 binary.clone(),
493 &mut cx.to_async(),
494 )
495 })
496 .ok()
497 .flatten()
498 {
499 return Ok(server);
500 }
501
502 let code_action_kinds = adapter.code_action_kinds();
503 lsp::LanguageServer::new(
504 stderr_capture,
505 server_id,
506 server_name,
507 binary,
508 &worktree_abs_path,
509 code_action_kinds,
510 Some(pending_workspace_folders),
511 cx,
512 )
513 }
514 });
515
516 let startup = {
517 let server_name = adapter.name.0.clone();
518 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
519 let key = key.clone();
520 let adapter = adapter.clone();
521 let lsp_store = self.weak.clone();
522 let pending_workspace_folders = pending_workspace_folders.clone();
523 let pull_diagnostics = ProjectSettings::get_global(cx)
524 .diagnostics
525 .lsp_pull_diagnostics
526 .enabled;
527 let settings_location = SettingsLocation {
528 worktree_id,
529 path: RelPath::empty(),
530 };
531 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
532 .language(Some(settings_location), Some(&language_name), cx)
533 .semantic_tokens
534 .use_tree_sitter();
535 cx.spawn(async move |cx| {
536 let result = async {
537 let language_server = pending_server.await?;
538
539 let workspace_config = Self::workspace_configuration_for_adapter(
540 adapter.adapter.clone(),
541 &delegate,
542 toolchain,
543 None,
544 cx,
545 )
546 .await?;
547
548 let mut initialization_options = Self::initialization_options_for_adapter(
549 adapter.adapter.clone(),
550 &delegate,
551 cx,
552 )
553 .await?;
554
555 match (&mut initialization_options, override_options) {
556 (Some(initialization_options), Some(override_options)) => {
557 merge_json_value_into(override_options, initialization_options);
558 }
559 (None, override_options) => initialization_options = override_options,
560 _ => {}
561 }
562
563 let initialization_params = cx.update(|cx| {
564 let mut params = language_server.default_initialize_params(
565 pull_diagnostics,
566 augments_syntax_tokens,
567 cx,
568 );
569 params.initialization_options = initialization_options;
570 adapter.adapter.prepare_initialize_params(params, cx)
571 })?;
572
573 Self::setup_lsp_messages(
574 lsp_store.clone(),
575 &language_server,
576 delegate.clone(),
577 adapter.clone(),
578 );
579
580 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
581 settings: workspace_config,
582 };
583 let language_server = cx
584 .update(|cx| {
585 let request_timeout = ProjectSettings::get_global(cx)
586 .global_lsp_settings
587 .get_request_timeout();
588
589 language_server.initialize(
590 initialization_params,
591 Arc::new(did_change_configuration_params.clone()),
592 request_timeout,
593 cx,
594 )
595 })
596 .await
597 .inspect_err(|_| {
598 if let Some(lsp_store) = lsp_store.upgrade() {
599 lsp_store.update(cx, |lsp_store, cx| {
600 lsp_store.cleanup_lsp_data(server_id);
601 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
602 });
603 }
604 })?;
605
606 language_server.notify::<lsp::notification::DidChangeConfiguration>(
607 did_change_configuration_params,
608 )?;
609
610 anyhow::Ok(language_server)
611 }
612 .await;
613
614 match result {
615 Ok(server) => {
616 lsp_store
617 .update(cx, |lsp_store, cx| {
618 lsp_store.insert_newly_running_language_server(
619 adapter,
620 server.clone(),
621 server_id,
622 key,
623 pending_workspace_folders,
624 cx,
625 );
626 })
627 .ok();
628 stderr_capture.lock().take();
629 Some(server)
630 }
631
632 Err(err) => {
633 let log = stderr_capture.lock().take().unwrap_or_default();
634 delegate.update_status(
635 adapter.name(),
636 BinaryStatus::Failed {
637 error: if log.is_empty() {
638 format!("{err:#}")
639 } else {
640 format!("{err:#}\n-- stderr --\n{log}")
641 },
642 },
643 );
644 log::error!(
645 "Failed to start language server {server_name:?}: {}",
646 redact_command(&format!("{err:?}"))
647 );
648 if !log.is_empty() {
649 log::error!("server stderr: {}", redact_command(&log));
650 }
651 None
652 }
653 }
654 })
655 };
656 let state = LanguageServerState::Starting {
657 startup,
658 pending_workspace_folders,
659 };
660
661 if update_binary_status {
662 self.languages
663 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
664 }
665
666 self.language_servers.insert(server_id, state);
667 self.language_server_ids
668 .entry(key)
669 .or_insert(UnifiedLanguageServer {
670 id: server_id,
671 project_roots: Default::default(),
672 });
673 server_id
674 }
675
676 fn get_language_server_binary(
677 &self,
678 worktree_abs_path: Arc<Path>,
679 adapter: Arc<CachedLspAdapter>,
680 settings: Arc<LspSettings>,
681 toolchain: Option<Toolchain>,
682 delegate: Arc<dyn LspAdapterDelegate>,
683 allow_binary_download: bool,
684 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
685 cx: &mut App,
686 ) -> Task<Result<LanguageServerBinary>> {
687 if let Some(settings) = &settings.binary
688 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
689 {
690 let settings = settings.clone();
691 let languages = self.languages.clone();
692 return cx.background_spawn(async move {
693 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
694 let already_trusted = *wait_until_worktree_trust.borrow();
695 if !already_trusted {
696 log::info!(
697 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
698 adapter.name(),
699 );
700 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
701 if worktree_trusted {
702 break;
703 }
704 }
705 log::info!(
706 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
707 adapter.name(),
708 );
709 }
710 languages
711 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
712 }
713 let mut env = delegate.shell_env().await;
714 env.extend(settings.env.unwrap_or_default());
715
716 Ok(LanguageServerBinary {
717 path: delegate.resolve_relative_path(path),
718 env: Some(env),
719 arguments: settings
720 .arguments
721 .unwrap_or_default()
722 .iter()
723 .map(Into::into)
724 .collect(),
725 })
726 });
727 }
728 let lsp_binary_options = LanguageServerBinaryOptions {
729 allow_path_lookup: !settings
730 .binary
731 .as_ref()
732 .and_then(|b| b.ignore_system_version)
733 .unwrap_or_default(),
734 allow_binary_download,
735 pre_release: settings
736 .fetch
737 .as_ref()
738 .and_then(|f| f.pre_release)
739 .unwrap_or(false),
740 };
741
742 cx.spawn(async move |cx| {
743 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
744 let already_trusted = *wait_until_worktree_trust.borrow();
745 if !already_trusted {
746 log::info!(
747 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
748 adapter.name(),
749 );
750 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
751 if worktree_trusted {
752 break;
753 }
754 }
755 log::info!(
756 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
757 adapter.name(),
758 );
759 }
760 }
761
762 let (existing_binary, maybe_download_binary) = adapter
763 .clone()
764 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
765 .await
766 .await;
767
768 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
769
770 let mut binary = match (existing_binary, maybe_download_binary) {
771 (binary, None) => binary?,
772 (Err(_), Some(downloader)) => downloader.await?,
773 (Ok(existing_binary), Some(downloader)) => {
774 let mut download_timeout = cx
775 .background_executor()
776 .timer(SERVER_DOWNLOAD_TIMEOUT)
777 .fuse();
778 let mut downloader = downloader.fuse();
779 futures::select! {
780 _ = download_timeout => {
781 // Return existing binary and kick the existing work to the background.
782 cx.spawn(async move |_| downloader.await).detach();
783 Ok(existing_binary)
784 },
785 downloaded_or_existing_binary = downloader => {
786 // If download fails, this results in the existing binary.
787 downloaded_or_existing_binary
788 }
789 }?
790 }
791 };
792 let mut shell_env = delegate.shell_env().await;
793
794 shell_env.extend(binary.env.unwrap_or_default());
795
796 if let Some(settings) = settings.binary.as_ref() {
797 if let Some(arguments) = &settings.arguments {
798 binary.arguments = arguments.iter().map(Into::into).collect();
799 }
800 if let Some(env) = &settings.env {
801 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
802 }
803 }
804
805 binary.env = Some(shell_env);
806 Ok(binary)
807 })
808 }
809
810 fn setup_lsp_messages(
811 lsp_store: WeakEntity<LspStore>,
812 language_server: &LanguageServer,
813 delegate: Arc<dyn LspAdapterDelegate>,
814 adapter: Arc<CachedLspAdapter>,
815 ) {
816 let name = language_server.name();
817 let server_id = language_server.server_id();
818 language_server
819 .on_notification::<lsp::notification::PublishDiagnostics, _>({
820 let adapter = adapter.clone();
821 let this = lsp_store.clone();
822 move |mut params, cx| {
823 let adapter = adapter.clone();
824 if let Some(this) = this.upgrade() {
825 this.update(cx, |this, cx| {
826 {
827 let buffer = params
828 .uri
829 .to_file_path()
830 .map(|file_path| this.get_buffer(&file_path, cx))
831 .ok()
832 .flatten();
833 adapter.process_diagnostics(&mut params, server_id, buffer);
834 }
835
836 this.merge_lsp_diagnostics(
837 DiagnosticSourceKind::Pushed,
838 vec![DocumentDiagnosticsUpdate {
839 server_id,
840 diagnostics: params,
841 result_id: None,
842 disk_based_sources: Cow::Borrowed(
843 &adapter.disk_based_diagnostic_sources,
844 ),
845 registration_id: None,
846 }],
847 |_, diagnostic, cx| match diagnostic.source_kind {
848 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
849 adapter.retain_old_diagnostic(diagnostic, cx)
850 }
851 DiagnosticSourceKind::Pulled => true,
852 },
853 cx,
854 )
855 .log_err();
856 });
857 }
858 }
859 })
860 .detach();
861 language_server
862 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
863 let adapter = adapter.adapter.clone();
864 let delegate = delegate.clone();
865 let this = lsp_store.clone();
866 move |params, cx| {
867 let adapter = adapter.clone();
868 let delegate = delegate.clone();
869 let this = this.clone();
870 let mut cx = cx.clone();
871 async move {
872 let toolchain_for_id = this
873 .update(&mut cx, |this, _| {
874 this.as_local()?.language_server_ids.iter().find_map(
875 |(seed, value)| {
876 (value.id == server_id).then(|| seed.toolchain.clone())
877 },
878 )
879 })?
880 .context("Expected the LSP store to be in a local mode")?;
881
882 let mut scope_uri_to_workspace_config = BTreeMap::new();
883 for item in ¶ms.items {
884 let scope_uri = item.scope_uri.clone();
885 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
886 scope_uri_to_workspace_config.entry(scope_uri.clone())
887 else {
888 // We've already queried workspace configuration of this URI.
889 continue;
890 };
891 let workspace_config = Self::workspace_configuration_for_adapter(
892 adapter.clone(),
893 &delegate,
894 toolchain_for_id.clone(),
895 scope_uri,
896 &mut cx,
897 )
898 .await?;
899 new_scope_uri.insert(workspace_config);
900 }
901
902 Ok(params
903 .items
904 .into_iter()
905 .filter_map(|item| {
906 let workspace_config =
907 scope_uri_to_workspace_config.get(&item.scope_uri)?;
908 if let Some(section) = &item.section {
909 Some(
910 workspace_config
911 .get(section)
912 .cloned()
913 .unwrap_or(serde_json::Value::Null),
914 )
915 } else {
916 Some(workspace_config.clone())
917 }
918 })
919 .collect())
920 }
921 }
922 })
923 .detach();
924
925 language_server
926 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
927 let this = lsp_store.clone();
928 move |_, cx| {
929 let this = this.clone();
930 let cx = cx.clone();
931 async move {
932 let Some(server) =
933 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
934 else {
935 return Ok(None);
936 };
937 let root = server.workspace_folders();
938 Ok(Some(
939 root.into_iter()
940 .map(|uri| WorkspaceFolder {
941 uri,
942 name: Default::default(),
943 })
944 .collect(),
945 ))
946 }
947 }
948 })
949 .detach();
950 // Even though we don't have handling for these requests, respond to them to
951 // avoid stalling any language server like `gopls` which waits for a response
952 // to these requests when initializing.
953 language_server
954 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
955 let this = lsp_store.clone();
956 move |params, cx| {
957 let this = this.clone();
958 let mut cx = cx.clone();
959 async move {
960 this.update(&mut cx, |this, _| {
961 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
962 {
963 status
964 .progress_tokens
965 .insert(ProgressToken::from_lsp(params.token));
966 }
967 })?;
968
969 Ok(())
970 }
971 }
972 })
973 .detach();
974
975 language_server
976 .on_request::<lsp::request::RegisterCapability, _, _>({
977 let lsp_store = lsp_store.clone();
978 move |params, cx| {
979 let lsp_store = lsp_store.clone();
980 let mut cx = cx.clone();
981 async move {
982 lsp_store
983 .update(&mut cx, |lsp_store, cx| {
984 if lsp_store.as_local().is_some() {
985 match lsp_store
986 .register_server_capabilities(server_id, params, cx)
987 {
988 Ok(()) => {}
989 Err(e) => {
990 log::error!(
991 "Failed to register server capabilities: {e:#}"
992 );
993 }
994 };
995 }
996 })
997 .ok();
998 Ok(())
999 }
1000 }
1001 })
1002 .detach();
1003
1004 language_server
1005 .on_request::<lsp::request::UnregisterCapability, _, _>({
1006 let lsp_store = lsp_store.clone();
1007 move |params, cx| {
1008 let lsp_store = lsp_store.clone();
1009 let mut cx = cx.clone();
1010 async move {
1011 lsp_store
1012 .update(&mut cx, |lsp_store, cx| {
1013 if lsp_store.as_local().is_some() {
1014 match lsp_store
1015 .unregister_server_capabilities(server_id, params, cx)
1016 {
1017 Ok(()) => {}
1018 Err(e) => {
1019 log::error!(
1020 "Failed to unregister server capabilities: {e:#}"
1021 );
1022 }
1023 }
1024 }
1025 })
1026 .ok();
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1035 let this = lsp_store.clone();
1036 move |params, cx| {
1037 let mut cx = cx.clone();
1038 let this = this.clone();
1039 async move {
1040 LocalLspStore::on_lsp_workspace_edit(
1041 this.clone(),
1042 params,
1043 server_id,
1044 &mut cx,
1045 )
1046 .await
1047 }
1048 }
1049 })
1050 .detach();
1051
1052 language_server
1053 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1054 let lsp_store = lsp_store.clone();
1055 let request_id = Arc::new(AtomicUsize::new(0));
1056 move |(), cx| {
1057 let lsp_store = lsp_store.clone();
1058 let request_id = request_id.clone();
1059 let mut cx = cx.clone();
1060 async move {
1061 lsp_store
1062 .update(&mut cx, |lsp_store, cx| {
1063 let request_id =
1064 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1065 cx.emit(LspStoreEvent::RefreshInlayHints {
1066 server_id,
1067 request_id,
1068 });
1069 lsp_store
1070 .downstream_client
1071 .as_ref()
1072 .map(|(client, project_id)| {
1073 client.send(proto::RefreshInlayHints {
1074 project_id: *project_id,
1075 server_id: server_id.to_proto(),
1076 request_id: request_id.map(|id| id as u64),
1077 })
1078 })
1079 })?
1080 .transpose()?;
1081 Ok(())
1082 }
1083 }
1084 })
1085 .detach();
1086
1087 language_server
1088 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1089 let this = lsp_store.clone();
1090 move |(), cx| {
1091 let this = this.clone();
1092 let mut cx = cx.clone();
1093 async move {
1094 this.update(&mut cx, |this, cx| {
1095 cx.emit(LspStoreEvent::RefreshCodeLens);
1096 this.downstream_client.as_ref().map(|(client, project_id)| {
1097 client.send(proto::RefreshCodeLens {
1098 project_id: *project_id,
1099 })
1100 })
1101 })?
1102 .transpose()?;
1103 Ok(())
1104 }
1105 }
1106 })
1107 .detach();
1108
1109 language_server
1110 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1111 let lsp_store = lsp_store.clone();
1112 let request_id = Arc::new(AtomicUsize::new(0));
1113 move |(), cx| {
1114 let lsp_store = lsp_store.clone();
1115 let request_id = request_id.clone();
1116 let mut cx = cx.clone();
1117 async move {
1118 lsp_store
1119 .update(&mut cx, |lsp_store, cx| {
1120 let request_id =
1121 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1122 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1123 server_id,
1124 request_id,
1125 });
1126 lsp_store
1127 .downstream_client
1128 .as_ref()
1129 .map(|(client, project_id)| {
1130 client.send(proto::RefreshSemanticTokens {
1131 project_id: *project_id,
1132 server_id: server_id.to_proto(),
1133 request_id: request_id.map(|id| id as u64),
1134 })
1135 })
1136 })?
1137 .transpose()?;
1138 Ok(())
1139 }
1140 }
1141 })
1142 .detach();
1143
1144 language_server
1145 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1146 let this = lsp_store.clone();
1147 move |(), cx| {
1148 let this = this.clone();
1149 let mut cx = cx.clone();
1150 async move {
1151 this.update(&mut cx, |lsp_store, cx| {
1152 lsp_store.pull_workspace_diagnostics(server_id);
1153 lsp_store
1154 .downstream_client
1155 .as_ref()
1156 .map(|(client, project_id)| {
1157 client.send(proto::PullWorkspaceDiagnostics {
1158 project_id: *project_id,
1159 server_id: server_id.to_proto(),
1160 })
1161 })
1162 .transpose()?;
1163 anyhow::Ok(
1164 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1165 )
1166 })??
1167 .await;
1168 Ok(())
1169 }
1170 }
1171 })
1172 .detach();
1173
1174 language_server
1175 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1176 let this = lsp_store.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 move |params, cx| {
1180 let this = this.clone();
1181 let name = name.to_string();
1182 let adapter = adapter.clone();
1183 let mut cx = cx.clone();
1184 async move {
1185 let actions = params.actions.unwrap_or_default();
1186 let message = params.message.clone();
1187 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1188 let level = match params.typ {
1189 lsp::MessageType::ERROR => PromptLevel::Critical,
1190 lsp::MessageType::WARNING => PromptLevel::Warning,
1191 _ => PromptLevel::Info,
1192 };
1193 let request = LanguageServerPromptRequest::new(
1194 level,
1195 params.message,
1196 actions,
1197 name.clone(),
1198 tx,
1199 );
1200
1201 let did_update = this
1202 .update(&mut cx, |_, cx| {
1203 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1204 })
1205 .is_ok();
1206 if did_update {
1207 let response = rx.recv().await.ok();
1208 if let Some(ref selected_action) = response {
1209 let context = language::PromptResponseContext {
1210 message,
1211 selected_action: selected_action.clone(),
1212 };
1213 adapter.process_prompt_response(&context, &mut cx)
1214 }
1215
1216 Ok(response)
1217 } else {
1218 Ok(None)
1219 }
1220 }
1221 }
1222 })
1223 .detach();
1224 language_server
1225 .on_notification::<lsp::notification::ShowMessage, _>({
1226 let this = lsp_store.clone();
1227 let name = name.to_string();
1228 move |params, cx| {
1229 let this = this.clone();
1230 let name = name.to_string();
1231 let mut cx = cx.clone();
1232
1233 let (tx, _) = smol::channel::bounded(1);
1234 let level = match params.typ {
1235 lsp::MessageType::ERROR => PromptLevel::Critical,
1236 lsp::MessageType::WARNING => PromptLevel::Warning,
1237 _ => PromptLevel::Info,
1238 };
1239 let request =
1240 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1241
1242 let _ = this.update(&mut cx, |_, cx| {
1243 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1244 });
1245 }
1246 })
1247 .detach();
1248
1249 let disk_based_diagnostics_progress_token =
1250 adapter.disk_based_diagnostics_progress_token.clone();
1251
1252 language_server
1253 .on_notification::<lsp::notification::Progress, _>({
1254 let this = lsp_store.clone();
1255 move |params, cx| {
1256 if let Some(this) = this.upgrade() {
1257 this.update(cx, |this, cx| {
1258 this.on_lsp_progress(
1259 params,
1260 server_id,
1261 disk_based_diagnostics_progress_token.clone(),
1262 cx,
1263 );
1264 });
1265 }
1266 }
1267 })
1268 .detach();
1269
1270 language_server
1271 .on_notification::<lsp::notification::LogMessage, _>({
1272 let this = lsp_store.clone();
1273 move |params, cx| {
1274 if let Some(this) = this.upgrade() {
1275 this.update(cx, |_, cx| {
1276 cx.emit(LspStoreEvent::LanguageServerLog(
1277 server_id,
1278 LanguageServerLogType::Log(params.typ),
1279 params.message,
1280 ));
1281 });
1282 }
1283 }
1284 })
1285 .detach();
1286
1287 language_server
1288 .on_notification::<lsp::notification::LogTrace, _>({
1289 let this = lsp_store.clone();
1290 move |params, cx| {
1291 let mut cx = cx.clone();
1292 if let Some(this) = this.upgrade() {
1293 this.update(&mut cx, |_, cx| {
1294 cx.emit(LspStoreEvent::LanguageServerLog(
1295 server_id,
1296 LanguageServerLogType::Trace {
1297 verbose_info: params.verbose,
1298 },
1299 params.message,
1300 ));
1301 });
1302 }
1303 }
1304 })
1305 .detach();
1306
1307 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1309 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1310 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1311 }
1312
1313 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1314 let shutdown_futures = self
1315 .language_servers
1316 .drain()
1317 .map(|(_, server_state)| Self::shutdown_server(server_state))
1318 .collect::<Vec<_>>();
1319
1320 async move {
1321 join_all(shutdown_futures).await;
1322 }
1323 }
1324
1325 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1326 match server_state {
1327 LanguageServerState::Running { server, .. } => {
1328 if let Some(shutdown) = server.shutdown() {
1329 shutdown.await;
1330 }
1331 }
1332 LanguageServerState::Starting { startup, .. } => {
1333 if let Some(server) = startup.await
1334 && let Some(shutdown) = server.shutdown()
1335 {
1336 shutdown.await;
1337 }
1338 }
1339 }
1340 Ok(())
1341 }
1342
1343 fn language_servers_for_worktree(
1344 &self,
1345 worktree_id: WorktreeId,
1346 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1347 self.language_server_ids
1348 .iter()
1349 .filter_map(move |(seed, state)| {
1350 if seed.worktree_id != worktree_id {
1351 return None;
1352 }
1353
1354 if let Some(LanguageServerState::Running { server, .. }) =
1355 self.language_servers.get(&state.id)
1356 {
1357 Some(server)
1358 } else {
1359 None
1360 }
1361 })
1362 }
1363
1364 fn language_server_ids_for_project_path(
1365 &self,
1366 project_path: ProjectPath,
1367 language: &Language,
1368 cx: &mut App,
1369 ) -> Vec<LanguageServerId> {
1370 let Some(worktree) = self
1371 .worktree_store
1372 .read(cx)
1373 .worktree_for_id(project_path.worktree_id, cx)
1374 else {
1375 return Vec::new();
1376 };
1377 let delegate: Arc<dyn ManifestDelegate> =
1378 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1379
1380 self.lsp_tree
1381 .get(
1382 project_path,
1383 language.name(),
1384 language.manifest(),
1385 &delegate,
1386 cx,
1387 )
1388 .collect::<Vec<_>>()
1389 }
1390
1391 fn language_server_ids_for_buffer(
1392 &self,
1393 buffer: &Buffer,
1394 cx: &mut App,
1395 ) -> Vec<LanguageServerId> {
1396 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1397 let worktree_id = file.worktree_id(cx);
1398
1399 let path: Arc<RelPath> = file
1400 .path()
1401 .parent()
1402 .map(Arc::from)
1403 .unwrap_or_else(|| file.path().clone());
1404 let worktree_path = ProjectPath { worktree_id, path };
1405 self.language_server_ids_for_project_path(worktree_path, language, cx)
1406 } else {
1407 Vec::new()
1408 }
1409 }
1410
1411 fn language_servers_for_buffer<'a>(
1412 &'a self,
1413 buffer: &'a Buffer,
1414 cx: &'a mut App,
1415 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1416 self.language_server_ids_for_buffer(buffer, cx)
1417 .into_iter()
1418 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1419 LanguageServerState::Running {
1420 adapter, server, ..
1421 } => Some((adapter, server)),
1422 _ => None,
1423 })
1424 }
1425
1426 async fn execute_code_action_kind_locally(
1427 lsp_store: WeakEntity<LspStore>,
1428 mut buffers: Vec<Entity<Buffer>>,
1429 kind: CodeActionKind,
1430 push_to_history: bool,
1431 cx: &mut AsyncApp,
1432 ) -> anyhow::Result<ProjectTransaction> {
1433 // Do not allow multiple concurrent code actions requests for the
1434 // same buffer.
1435 lsp_store.update(cx, |this, cx| {
1436 let this = this.as_local_mut().unwrap();
1437 buffers.retain(|buffer| {
1438 this.buffers_being_formatted
1439 .insert(buffer.read(cx).remote_id())
1440 });
1441 })?;
1442 let _cleanup = defer({
1443 let this = lsp_store.clone();
1444 let mut cx = cx.clone();
1445 let buffers = &buffers;
1446 move || {
1447 this.update(&mut cx, |this, cx| {
1448 let this = this.as_local_mut().unwrap();
1449 for buffer in buffers {
1450 this.buffers_being_formatted
1451 .remove(&buffer.read(cx).remote_id());
1452 }
1453 })
1454 .ok();
1455 }
1456 });
1457 let mut project_transaction = ProjectTransaction::default();
1458
1459 for buffer in &buffers {
1460 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1461 buffer.update(cx, |buffer, cx| {
1462 lsp_store
1463 .as_local()
1464 .unwrap()
1465 .language_servers_for_buffer(buffer, cx)
1466 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1467 .collect::<Vec<_>>()
1468 })
1469 })?;
1470 for (_, language_server) in adapters_and_servers.iter() {
1471 let actions = Self::get_server_code_actions_from_action_kinds(
1472 &lsp_store,
1473 language_server.server_id(),
1474 vec![kind.clone()],
1475 buffer,
1476 cx,
1477 )
1478 .await?;
1479 Self::execute_code_actions_on_server(
1480 &lsp_store,
1481 language_server,
1482 actions,
1483 push_to_history,
1484 &mut project_transaction,
1485 cx,
1486 )
1487 .await?;
1488 }
1489 }
1490 Ok(project_transaction)
1491 }
1492
1493 async fn format_locally(
1494 lsp_store: WeakEntity<LspStore>,
1495 mut buffers: Vec<FormattableBuffer>,
1496 push_to_history: bool,
1497 trigger: FormatTrigger,
1498 logger: zlog::Logger,
1499 cx: &mut AsyncApp,
1500 ) -> anyhow::Result<ProjectTransaction> {
1501 // Do not allow multiple concurrent formatting requests for the
1502 // same buffer.
1503 lsp_store.update(cx, |this, cx| {
1504 let this = this.as_local_mut().unwrap();
1505 buffers.retain(|buffer| {
1506 this.buffers_being_formatted
1507 .insert(buffer.handle.read(cx).remote_id())
1508 });
1509 })?;
1510
1511 let _cleanup = defer({
1512 let this = lsp_store.clone();
1513 let mut cx = cx.clone();
1514 let buffers = &buffers;
1515 move || {
1516 this.update(&mut cx, |this, cx| {
1517 let this = this.as_local_mut().unwrap();
1518 for buffer in buffers {
1519 this.buffers_being_formatted
1520 .remove(&buffer.handle.read(cx).remote_id());
1521 }
1522 })
1523 .ok();
1524 }
1525 });
1526
1527 let mut project_transaction = ProjectTransaction::default();
1528
1529 for buffer in &buffers {
1530 zlog::debug!(
1531 logger =>
1532 "formatting buffer '{:?}'",
1533 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1534 );
1535 // Create an empty transaction to hold all of the formatting edits.
1536 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1537 // ensure no transactions created while formatting are
1538 // grouped with the previous transaction in the history
1539 // based on the transaction group interval
1540 buffer.finalize_last_transaction();
1541 buffer
1542 .start_transaction()
1543 .context("transaction already open")?;
1544 buffer.end_transaction(cx);
1545 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1546 buffer.finalize_last_transaction();
1547 anyhow::Ok(transaction_id)
1548 })?;
1549
1550 let result = Self::format_buffer_locally(
1551 lsp_store.clone(),
1552 buffer,
1553 formatting_transaction_id,
1554 trigger,
1555 logger,
1556 cx,
1557 )
1558 .await;
1559
1560 buffer.handle.update(cx, |buffer, cx| {
1561 let Some(formatting_transaction) =
1562 buffer.get_transaction(formatting_transaction_id).cloned()
1563 else {
1564 zlog::warn!(logger => "no formatting transaction");
1565 return;
1566 };
1567 if formatting_transaction.edit_ids.is_empty() {
1568 zlog::debug!(logger => "no changes made while formatting");
1569 buffer.forget_transaction(formatting_transaction_id);
1570 return;
1571 }
1572 if !push_to_history {
1573 zlog::trace!(logger => "forgetting format transaction");
1574 buffer.forget_transaction(formatting_transaction.id);
1575 }
1576 project_transaction
1577 .0
1578 .insert(cx.entity(), formatting_transaction);
1579 });
1580
1581 result?;
1582 }
1583
1584 Ok(project_transaction)
1585 }
1586
1587 async fn format_buffer_locally(
1588 lsp_store: WeakEntity<LspStore>,
1589 buffer: &FormattableBuffer,
1590 formatting_transaction_id: clock::Lamport,
1591 trigger: FormatTrigger,
1592 logger: zlog::Logger,
1593 cx: &mut AsyncApp,
1594 ) -> Result<()> {
1595 let (adapters_and_servers, settings, request_timeout) =
1596 lsp_store.update(cx, |lsp_store, cx| {
1597 buffer.handle.update(cx, |buffer, cx| {
1598 let adapters_and_servers = lsp_store
1599 .as_local()
1600 .unwrap()
1601 .language_servers_for_buffer(buffer, cx)
1602 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1603 .collect::<Vec<_>>();
1604 let settings =
1605 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1606 .into_owned();
1607 let request_timeout = ProjectSettings::get_global(cx)
1608 .global_lsp_settings
1609 .get_request_timeout();
1610 (adapters_and_servers, settings, request_timeout)
1611 })
1612 })?;
1613
1614 /// Apply edits to the buffer that will become part of the formatting transaction.
1615 /// Fails if the buffer has been edited since the start of that transaction.
1616 fn extend_formatting_transaction(
1617 buffer: &FormattableBuffer,
1618 formatting_transaction_id: text::TransactionId,
1619 cx: &mut AsyncApp,
1620 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1621 ) -> anyhow::Result<()> {
1622 buffer.handle.update(cx, |buffer, cx| {
1623 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1624 if last_transaction_id != Some(formatting_transaction_id) {
1625 anyhow::bail!("Buffer edited while formatting. Aborting")
1626 }
1627 buffer.start_transaction();
1628 operation(buffer, cx);
1629 if let Some(transaction_id) = buffer.end_transaction(cx) {
1630 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1631 }
1632 Ok(())
1633 })
1634 }
1635
1636 // handle whitespace formatting
1637 if settings.remove_trailing_whitespace_on_save {
1638 zlog::trace!(logger => "removing trailing whitespace");
1639 let diff = buffer
1640 .handle
1641 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1642 .await;
1643 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1644 buffer.apply_diff(diff, cx);
1645 })?;
1646 }
1647
1648 if settings.ensure_final_newline_on_save {
1649 zlog::trace!(logger => "ensuring final newline");
1650 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1651 buffer.ensure_final_newline(cx);
1652 })?;
1653 }
1654
1655 // Formatter for `code_actions_on_format` that runs before
1656 // the rest of the formatters
1657 let mut code_actions_on_format_formatters = None;
1658 let should_run_code_actions_on_format = !matches!(
1659 (trigger, &settings.format_on_save),
1660 (FormatTrigger::Save, &FormatOnSave::Off)
1661 );
1662 if should_run_code_actions_on_format {
1663 let have_code_actions_to_run_on_format = settings
1664 .code_actions_on_format
1665 .values()
1666 .any(|enabled| *enabled);
1667 if have_code_actions_to_run_on_format {
1668 zlog::trace!(logger => "going to run code actions on format");
1669 code_actions_on_format_formatters = Some(
1670 settings
1671 .code_actions_on_format
1672 .iter()
1673 .filter_map(|(action, enabled)| enabled.then_some(action))
1674 .cloned()
1675 .map(Formatter::CodeAction)
1676 .collect::<Vec<_>>(),
1677 );
1678 }
1679 }
1680
1681 let formatters = match (trigger, &settings.format_on_save) {
1682 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1683 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1684 settings.formatter.as_ref()
1685 }
1686 };
1687
1688 let formatters = code_actions_on_format_formatters
1689 .iter()
1690 .flatten()
1691 .chain(formatters);
1692
1693 for formatter in formatters {
1694 let formatter = if formatter == &Formatter::Auto {
1695 if settings.prettier.allowed {
1696 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1697 &Formatter::Prettier
1698 } else {
1699 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1700 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1701 }
1702 } else {
1703 formatter
1704 };
1705 match formatter {
1706 Formatter::Auto => unreachable!("Auto resolved above"),
1707 Formatter::Prettier => {
1708 let logger = zlog::scoped!(logger => "prettier");
1709 zlog::trace!(logger => "formatting");
1710 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1711
1712 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1713 lsp_store.prettier_store().unwrap().downgrade()
1714 })?;
1715 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1716 .await
1717 .transpose()?;
1718 let Some(diff) = diff else {
1719 zlog::trace!(logger => "No changes");
1720 continue;
1721 };
1722
1723 extend_formatting_transaction(
1724 buffer,
1725 formatting_transaction_id,
1726 cx,
1727 |buffer, cx| {
1728 buffer.apply_diff(diff, cx);
1729 },
1730 )?;
1731 }
1732 Formatter::External { command, arguments } => {
1733 let logger = zlog::scoped!(logger => "command");
1734 zlog::trace!(logger => "formatting");
1735 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1736
1737 let diff = Self::format_via_external_command(
1738 buffer,
1739 &command,
1740 arguments.as_deref(),
1741 cx,
1742 )
1743 .await
1744 .with_context(|| {
1745 format!("Failed to format buffer via external command: {}", command)
1746 })?;
1747 let Some(diff) = diff else {
1748 zlog::trace!(logger => "No changes");
1749 continue;
1750 };
1751
1752 extend_formatting_transaction(
1753 buffer,
1754 formatting_transaction_id,
1755 cx,
1756 |buffer, cx| {
1757 buffer.apply_diff(diff, cx);
1758 },
1759 )?;
1760 }
1761 Formatter::LanguageServer(specifier) => {
1762 let logger = zlog::scoped!(logger => "language-server");
1763 zlog::trace!(logger => "formatting");
1764 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1765
1766 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1767 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1768 continue;
1769 };
1770
1771 let language_server = match specifier {
1772 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1773 adapters_and_servers.iter().find_map(|(adapter, server)| {
1774 if adapter.name.0.as_ref() == name {
1775 Some(server.clone())
1776 } else {
1777 None
1778 }
1779 })
1780 }
1781 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1782 .iter()
1783 .find(|(_, server)| Self::server_supports_formatting(server))
1784 .map(|(_, server)| server.clone()),
1785 };
1786
1787 let Some(language_server) = language_server else {
1788 log::debug!(
1789 "No language server found to format buffer '{:?}'. Skipping",
1790 buffer_path_abs.as_path().to_string_lossy()
1791 );
1792 continue;
1793 };
1794
1795 zlog::trace!(
1796 logger =>
1797 "Formatting buffer '{:?}' using language server '{:?}'",
1798 buffer_path_abs.as_path().to_string_lossy(),
1799 language_server.name()
1800 );
1801
1802 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1803 zlog::trace!(logger => "formatting ranges");
1804 Self::format_ranges_via_lsp(
1805 &lsp_store,
1806 &buffer.handle,
1807 ranges,
1808 buffer_path_abs,
1809 &language_server,
1810 &settings,
1811 cx,
1812 )
1813 .await
1814 .context("Failed to format ranges via language server")?
1815 } else {
1816 zlog::trace!(logger => "formatting full");
1817 Self::format_via_lsp(
1818 &lsp_store,
1819 &buffer.handle,
1820 buffer_path_abs,
1821 &language_server,
1822 &settings,
1823 cx,
1824 )
1825 .await
1826 .context("failed to format via language server")?
1827 };
1828
1829 if edits.is_empty() {
1830 zlog::trace!(logger => "No changes");
1831 continue;
1832 }
1833 extend_formatting_transaction(
1834 buffer,
1835 formatting_transaction_id,
1836 cx,
1837 |buffer, cx| {
1838 buffer.edit(edits, None, cx);
1839 },
1840 )?;
1841 }
1842 Formatter::CodeAction(code_action_name) => {
1843 let logger = zlog::scoped!(logger => "code-actions");
1844 zlog::trace!(logger => "formatting");
1845 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1846
1847 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1848 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1849 continue;
1850 };
1851
1852 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1853 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1854
1855 let mut actions_and_servers = Vec::new();
1856
1857 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1858 let actions_result = Self::get_server_code_actions_from_action_kinds(
1859 &lsp_store,
1860 language_server.server_id(),
1861 vec![code_action_kind.clone()],
1862 &buffer.handle,
1863 cx,
1864 )
1865 .await
1866 .with_context(|| {
1867 format!(
1868 "Failed to resolve code action {:?} with language server {}",
1869 code_action_kind,
1870 language_server.name()
1871 )
1872 });
1873 let Ok(actions) = actions_result else {
1874 // note: it may be better to set result to the error and break formatters here
1875 // but for now we try to execute the actions that we can resolve and skip the rest
1876 zlog::error!(
1877 logger =>
1878 "Failed to resolve code action {:?} with language server {}",
1879 code_action_kind,
1880 language_server.name()
1881 );
1882 continue;
1883 };
1884 for action in actions {
1885 actions_and_servers.push((action, index));
1886 }
1887 }
1888
1889 if actions_and_servers.is_empty() {
1890 zlog::warn!(logger => "No code actions were resolved, continuing");
1891 continue;
1892 }
1893
1894 'actions: for (mut action, server_index) in actions_and_servers {
1895 let server = &adapters_and_servers[server_index].1;
1896
1897 let describe_code_action = |action: &CodeAction| {
1898 format!(
1899 "code action '{}' with title \"{}\" on server {}",
1900 action
1901 .lsp_action
1902 .action_kind()
1903 .unwrap_or("unknown".into())
1904 .as_str(),
1905 action.lsp_action.title(),
1906 server.name(),
1907 )
1908 };
1909
1910 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1911
1912 if let Err(err) =
1913 Self::try_resolve_code_action(server, &mut action, request_timeout)
1914 .await
1915 {
1916 zlog::error!(
1917 logger =>
1918 "Failed to resolve {}. Error: {}",
1919 describe_code_action(&action),
1920 err
1921 );
1922 continue;
1923 }
1924
1925 if let Some(edit) = action.lsp_action.edit().cloned() {
1926 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1927 // but filters out and logs warnings for code actions that require unreasonably
1928 // difficult handling on our part, such as:
1929 // - applying edits that call commands
1930 // which can result in arbitrary workspace edits being sent from the server that
1931 // have no way of being tied back to the command that initiated them (i.e. we
1932 // can't know which edits are part of the format request, or if the server is done sending
1933 // actions in response to the command)
1934 // - actions that create/delete/modify/rename files other than the one we are formatting
1935 // as we then would need to handle such changes correctly in the local history as well
1936 // as the remote history through the ProjectTransaction
1937 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1938 // Supporting these actions is not impossible, but not supported as of yet.
1939 if edit.changes.is_none() && edit.document_changes.is_none() {
1940 zlog::trace!(
1941 logger =>
1942 "No changes for code action. Skipping {}",
1943 describe_code_action(&action),
1944 );
1945 continue;
1946 }
1947
1948 let mut operations = Vec::new();
1949 if let Some(document_changes) = edit.document_changes {
1950 match document_changes {
1951 lsp::DocumentChanges::Edits(edits) => operations.extend(
1952 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1953 ),
1954 lsp::DocumentChanges::Operations(ops) => operations = ops,
1955 }
1956 } else if let Some(changes) = edit.changes {
1957 operations.extend(changes.into_iter().map(|(uri, edits)| {
1958 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1959 text_document:
1960 lsp::OptionalVersionedTextDocumentIdentifier {
1961 uri,
1962 version: None,
1963 },
1964 edits: edits.into_iter().map(Edit::Plain).collect(),
1965 })
1966 }));
1967 }
1968
1969 let mut edits = Vec::with_capacity(operations.len());
1970
1971 if operations.is_empty() {
1972 zlog::trace!(
1973 logger =>
1974 "No changes for code action. Skipping {}",
1975 describe_code_action(&action),
1976 );
1977 continue;
1978 }
1979 for operation in operations {
1980 let op = match operation {
1981 lsp::DocumentChangeOperation::Edit(op) => op,
1982 lsp::DocumentChangeOperation::Op(_) => {
1983 zlog::warn!(
1984 logger =>
1985 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1986 describe_code_action(&action),
1987 );
1988 continue 'actions;
1989 }
1990 };
1991 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1992 zlog::warn!(
1993 logger =>
1994 "Failed to convert URI '{:?}' to file path. Skipping {}",
1995 &op.text_document.uri,
1996 describe_code_action(&action),
1997 );
1998 continue 'actions;
1999 };
2000 if &file_path != buffer_path_abs {
2001 zlog::warn!(
2002 logger =>
2003 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2004 file_path,
2005 buffer_path_abs,
2006 describe_code_action(&action),
2007 );
2008 continue 'actions;
2009 }
2010
2011 let mut lsp_edits = Vec::new();
2012 for edit in op.edits {
2013 match edit {
2014 Edit::Plain(edit) => {
2015 if !lsp_edits.contains(&edit) {
2016 lsp_edits.push(edit);
2017 }
2018 }
2019 Edit::Annotated(edit) => {
2020 if !lsp_edits.contains(&edit.text_edit) {
2021 lsp_edits.push(edit.text_edit);
2022 }
2023 }
2024 Edit::Snippet(_) => {
2025 zlog::warn!(
2026 logger =>
2027 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2028 describe_code_action(&action),
2029 );
2030 continue 'actions;
2031 }
2032 }
2033 }
2034 let edits_result = lsp_store
2035 .update(cx, |lsp_store, cx| {
2036 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2037 &buffer.handle,
2038 lsp_edits,
2039 server.server_id(),
2040 op.text_document.version,
2041 cx,
2042 )
2043 })?
2044 .await;
2045 let Ok(resolved_edits) = edits_result else {
2046 zlog::warn!(
2047 logger =>
2048 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2049 buffer_path_abs.as_path(),
2050 describe_code_action(&action),
2051 );
2052 continue 'actions;
2053 };
2054 edits.extend(resolved_edits);
2055 }
2056
2057 if edits.is_empty() {
2058 zlog::warn!(logger => "No edits resolved from LSP");
2059 continue;
2060 }
2061
2062 extend_formatting_transaction(
2063 buffer,
2064 formatting_transaction_id,
2065 cx,
2066 |buffer, cx| {
2067 zlog::info!(
2068 "Applying edits {edits:?}. Content: {:?}",
2069 buffer.text()
2070 );
2071 buffer.edit(edits, None, cx);
2072 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2073 },
2074 )?;
2075 }
2076
2077 // bail early if command is invalid
2078 let Some(command) = action.lsp_action.command() else {
2079 continue;
2080 };
2081
2082 zlog::warn!(
2083 logger =>
2084 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2085 &command.command,
2086 );
2087
2088 let server_capabilities = server.capabilities();
2089 let available_commands = server_capabilities
2090 .execute_command_provider
2091 .as_ref()
2092 .map(|options| options.commands.as_slice())
2093 .unwrap_or_default();
2094 if !available_commands.contains(&command.command) {
2095 zlog::warn!(
2096 logger =>
2097 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2098 command.command,
2099 server.name(),
2100 );
2101 continue;
2102 }
2103
2104 // noop so we just ensure buffer hasn't been edited since resolving code actions
2105 extend_formatting_transaction(
2106 buffer,
2107 formatting_transaction_id,
2108 cx,
2109 |_, _| {},
2110 )?;
2111 zlog::info!(logger => "Executing command {}", &command.command);
2112
2113 lsp_store.update(cx, |this, _| {
2114 this.as_local_mut()
2115 .unwrap()
2116 .last_workspace_edits_by_language_server
2117 .remove(&server.server_id());
2118 })?;
2119
2120 let execute_command_result = server
2121 .request::<lsp::request::ExecuteCommand>(
2122 lsp::ExecuteCommandParams {
2123 command: command.command.clone(),
2124 arguments: command.arguments.clone().unwrap_or_default(),
2125 ..Default::default()
2126 },
2127 request_timeout,
2128 )
2129 .await
2130 .into_response();
2131
2132 if execute_command_result.is_err() {
2133 zlog::error!(
2134 logger =>
2135 "Failed to execute command '{}' as part of {}",
2136 &command.command,
2137 describe_code_action(&action),
2138 );
2139 continue 'actions;
2140 }
2141
2142 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2143 this.as_local_mut()
2144 .unwrap()
2145 .last_workspace_edits_by_language_server
2146 .remove(&server.server_id())
2147 .unwrap_or_default()
2148 })?;
2149
2150 if let Some(transaction) =
2151 project_transaction_command.0.remove(&buffer.handle)
2152 {
2153 zlog::trace!(
2154 logger =>
2155 "Successfully captured {} edits that resulted from command {}",
2156 transaction.edit_ids.len(),
2157 &command.command,
2158 );
2159 let transaction_id_project_transaction = transaction.id;
2160 buffer.handle.update(cx, |buffer, _| {
2161 // it may have been removed from history if push_to_history was
2162 // false in deserialize_workspace_edit. If so push it so we
2163 // can merge it with the format transaction
2164 // and pop the combined transaction off the history stack
2165 // later if push_to_history is false
2166 if buffer.get_transaction(transaction.id).is_none() {
2167 buffer.push_transaction(transaction, Instant::now());
2168 }
2169 buffer.merge_transactions(
2170 transaction_id_project_transaction,
2171 formatting_transaction_id,
2172 );
2173 });
2174 }
2175
2176 if project_transaction_command.0.is_empty() {
2177 continue;
2178 }
2179
2180 let mut extra_buffers = String::new();
2181 for buffer in project_transaction_command.0.keys() {
2182 buffer.read_with(cx, |b, cx| {
2183 let Some(path) = b.project_path(cx) else {
2184 return;
2185 };
2186
2187 if !extra_buffers.is_empty() {
2188 extra_buffers.push_str(", ");
2189 }
2190 extra_buffers.push_str(path.path.as_unix_str());
2191 });
2192 }
2193 zlog::warn!(
2194 logger =>
2195 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2196 &command.command,
2197 extra_buffers,
2198 );
2199 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2200 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2201 // add it so it's included, and merge it into the format transaction when its created later
2202 }
2203 }
2204 }
2205 }
2206
2207 Ok(())
2208 }
2209
2210 pub async fn format_ranges_via_lsp(
2211 this: &WeakEntity<LspStore>,
2212 buffer_handle: &Entity<Buffer>,
2213 ranges: &[Range<Anchor>],
2214 abs_path: &Path,
2215 language_server: &Arc<LanguageServer>,
2216 settings: &LanguageSettings,
2217 cx: &mut AsyncApp,
2218 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2219 let capabilities = &language_server.capabilities();
2220 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2221 if range_formatting_provider == Some(&OneOf::Left(false)) {
2222 anyhow::bail!(
2223 "{} language server does not support range formatting",
2224 language_server.name()
2225 );
2226 }
2227
2228 let uri = file_path_to_lsp_url(abs_path)?;
2229 let text_document = lsp::TextDocumentIdentifier::new(uri);
2230
2231 let request_timeout = cx.update(|app| {
2232 ProjectSettings::get_global(app)
2233 .global_lsp_settings
2234 .get_request_timeout()
2235 });
2236 let lsp_edits = {
2237 let mut lsp_ranges = Vec::new();
2238 this.update(cx, |_this, cx| {
2239 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2240 // not have been sent to the language server. This seems like a fairly systemic
2241 // issue, though, the resolution probably is not specific to formatting.
2242 //
2243 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2244 // LSP.
2245 let snapshot = buffer_handle.read(cx).snapshot();
2246 for range in ranges {
2247 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2248 }
2249 anyhow::Ok(())
2250 })??;
2251
2252 let mut edits = None;
2253 for range in lsp_ranges {
2254 if let Some(mut edit) = language_server
2255 .request::<lsp::request::RangeFormatting>(
2256 lsp::DocumentRangeFormattingParams {
2257 text_document: text_document.clone(),
2258 range,
2259 options: lsp_command::lsp_formatting_options(settings),
2260 work_done_progress_params: Default::default(),
2261 },
2262 request_timeout,
2263 )
2264 .await
2265 .into_response()?
2266 {
2267 edits.get_or_insert_with(Vec::new).append(&mut edit);
2268 }
2269 }
2270 edits
2271 };
2272
2273 if let Some(lsp_edits) = lsp_edits {
2274 this.update(cx, |this, cx| {
2275 this.as_local_mut().unwrap().edits_from_lsp(
2276 buffer_handle,
2277 lsp_edits,
2278 language_server.server_id(),
2279 None,
2280 cx,
2281 )
2282 })?
2283 .await
2284 } else {
2285 Ok(Vec::with_capacity(0))
2286 }
2287 }
2288
2289 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2290 let capabilities = server.capabilities();
2291 let formatting = capabilities.document_formatting_provider.as_ref();
2292 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2293 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2294 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2295 }
2296
2297 async fn format_via_lsp(
2298 this: &WeakEntity<LspStore>,
2299 buffer: &Entity<Buffer>,
2300 abs_path: &Path,
2301 language_server: &Arc<LanguageServer>,
2302 settings: &LanguageSettings,
2303 cx: &mut AsyncApp,
2304 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2305 let logger = zlog::scoped!("lsp_format");
2306 zlog::debug!(logger => "Formatting via LSP");
2307
2308 let uri = file_path_to_lsp_url(abs_path)?;
2309 let text_document = lsp::TextDocumentIdentifier::new(uri);
2310 let capabilities = &language_server.capabilities();
2311
2312 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2313 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2314
2315 let request_timeout = cx.update(|app| {
2316 ProjectSettings::get_global(app)
2317 .global_lsp_settings
2318 .get_request_timeout()
2319 });
2320
2321 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2322 let _timer = zlog::time!(logger => "format-full");
2323 language_server
2324 .request::<lsp::request::Formatting>(
2325 lsp::DocumentFormattingParams {
2326 text_document,
2327 options: lsp_command::lsp_formatting_options(settings),
2328 work_done_progress_params: Default::default(),
2329 },
2330 request_timeout,
2331 )
2332 .await
2333 .into_response()?
2334 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2335 let _timer = zlog::time!(logger => "format-range");
2336 let buffer_start = lsp::Position::new(0, 0);
2337 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2338 language_server
2339 .request::<lsp::request::RangeFormatting>(
2340 lsp::DocumentRangeFormattingParams {
2341 text_document: text_document.clone(),
2342 range: lsp::Range::new(buffer_start, buffer_end),
2343 options: lsp_command::lsp_formatting_options(settings),
2344 work_done_progress_params: Default::default(),
2345 },
2346 request_timeout,
2347 )
2348 .await
2349 .into_response()?
2350 } else {
2351 None
2352 };
2353
2354 if let Some(lsp_edits) = lsp_edits {
2355 this.update(cx, |this, cx| {
2356 this.as_local_mut().unwrap().edits_from_lsp(
2357 buffer,
2358 lsp_edits,
2359 language_server.server_id(),
2360 None,
2361 cx,
2362 )
2363 })?
2364 .await
2365 } else {
2366 Ok(Vec::with_capacity(0))
2367 }
2368 }
2369
2370 async fn format_via_external_command(
2371 buffer: &FormattableBuffer,
2372 command: &str,
2373 arguments: Option<&[String]>,
2374 cx: &mut AsyncApp,
2375 ) -> Result<Option<Diff>> {
2376 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2377 let file = File::from_dyn(buffer.file())?;
2378 let worktree = file.worktree.read(cx);
2379 let mut worktree_path = worktree.abs_path().to_path_buf();
2380 if worktree.root_entry()?.is_file() {
2381 worktree_path.pop();
2382 }
2383 Some(worktree_path)
2384 });
2385
2386 use util::command::Stdio;
2387 let mut child = util::command::new_command(command);
2388
2389 if let Some(buffer_env) = buffer.env.as_ref() {
2390 child.envs(buffer_env);
2391 }
2392
2393 if let Some(working_dir_path) = working_dir_path {
2394 child.current_dir(working_dir_path);
2395 }
2396
2397 if let Some(arguments) = arguments {
2398 child.args(arguments.iter().map(|arg| {
2399 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2400 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2401 } else {
2402 arg.replace("{buffer_path}", "Untitled")
2403 }
2404 }));
2405 }
2406
2407 let mut child = child
2408 .stdin(Stdio::piped())
2409 .stdout(Stdio::piped())
2410 .stderr(Stdio::piped())
2411 .spawn()?;
2412
2413 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2414 let text = buffer
2415 .handle
2416 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2417 for chunk in text.chunks() {
2418 stdin.write_all(chunk.as_bytes()).await?;
2419 }
2420 stdin.flush().await?;
2421
2422 let output = child.output().await?;
2423 anyhow::ensure!(
2424 output.status.success(),
2425 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2426 output.status.code(),
2427 String::from_utf8_lossy(&output.stdout),
2428 String::from_utf8_lossy(&output.stderr),
2429 );
2430
2431 let stdout = String::from_utf8(output.stdout)?;
2432 Ok(Some(
2433 buffer
2434 .handle
2435 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2436 .await,
2437 ))
2438 }
2439
2440 async fn try_resolve_code_action(
2441 lang_server: &LanguageServer,
2442 action: &mut CodeAction,
2443 request_timeout: Duration,
2444 ) -> anyhow::Result<()> {
2445 match &mut action.lsp_action {
2446 LspAction::Action(lsp_action) => {
2447 if !action.resolved
2448 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2449 && lsp_action.data.is_some()
2450 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2451 {
2452 **lsp_action = lang_server
2453 .request::<lsp::request::CodeActionResolveRequest>(
2454 *lsp_action.clone(),
2455 request_timeout,
2456 )
2457 .await
2458 .into_response()?;
2459 }
2460 }
2461 LspAction::CodeLens(lens) => {
2462 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2463 *lens = lang_server
2464 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2465 .await
2466 .into_response()?;
2467 }
2468 }
2469 LspAction::Command(_) => {}
2470 }
2471
2472 action.resolved = true;
2473 anyhow::Ok(())
2474 }
2475
2476 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2477 let buffer = buffer_handle.read(cx);
2478
2479 let file = buffer.file().cloned();
2480
2481 let Some(file) = File::from_dyn(file.as_ref()) else {
2482 return;
2483 };
2484 if !file.is_local() {
2485 return;
2486 }
2487 let path = ProjectPath::from_file(file, cx);
2488 let worktree_id = file.worktree_id(cx);
2489 let language = buffer.language().cloned();
2490
2491 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2492 for (server_id, diagnostics) in
2493 diagnostics.get(file.path()).cloned().unwrap_or_default()
2494 {
2495 self.update_buffer_diagnostics(
2496 buffer_handle,
2497 server_id,
2498 None,
2499 None,
2500 None,
2501 Vec::new(),
2502 diagnostics,
2503 cx,
2504 )
2505 .log_err();
2506 }
2507 }
2508 let Some(language) = language else {
2509 return;
2510 };
2511 let Some(snapshot) = self
2512 .worktree_store
2513 .read(cx)
2514 .worktree_for_id(worktree_id, cx)
2515 .map(|worktree| worktree.read(cx).snapshot())
2516 else {
2517 return;
2518 };
2519 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2520
2521 for server_id in
2522 self.lsp_tree
2523 .get(path, language.name(), language.manifest(), &delegate, cx)
2524 {
2525 let server = self
2526 .language_servers
2527 .get(&server_id)
2528 .and_then(|server_state| {
2529 if let LanguageServerState::Running { server, .. } = server_state {
2530 Some(server.clone())
2531 } else {
2532 None
2533 }
2534 });
2535 let server = match server {
2536 Some(server) => server,
2537 None => continue,
2538 };
2539
2540 buffer_handle.update(cx, |buffer, cx| {
2541 buffer.set_completion_triggers(
2542 server.server_id(),
2543 server
2544 .capabilities()
2545 .completion_provider
2546 .as_ref()
2547 .and_then(|provider| {
2548 provider
2549 .trigger_characters
2550 .as_ref()
2551 .map(|characters| characters.iter().cloned().collect())
2552 })
2553 .unwrap_or_default(),
2554 cx,
2555 );
2556 });
2557 }
2558 }
2559
2560 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2561 buffer.update(cx, |buffer, cx| {
2562 let Some(language) = buffer.language() else {
2563 return;
2564 };
2565 let path = ProjectPath {
2566 worktree_id: old_file.worktree_id(cx),
2567 path: old_file.path.clone(),
2568 };
2569 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2570 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2571 buffer.set_completion_triggers(server_id, Default::default(), cx);
2572 }
2573 });
2574 }
2575
2576 fn update_buffer_diagnostics(
2577 &mut self,
2578 buffer: &Entity<Buffer>,
2579 server_id: LanguageServerId,
2580 registration_id: Option<Option<SharedString>>,
2581 result_id: Option<SharedString>,
2582 version: Option<i32>,
2583 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2584 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2585 cx: &mut Context<LspStore>,
2586 ) -> Result<()> {
2587 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2588 Ordering::Equal
2589 .then_with(|| b.is_primary.cmp(&a.is_primary))
2590 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2591 .then_with(|| a.severity.cmp(&b.severity))
2592 .then_with(|| a.message.cmp(&b.message))
2593 }
2594
2595 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2596 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2597 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2598
2599 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2600 Ordering::Equal
2601 .then_with(|| a.range.start.cmp(&b.range.start))
2602 .then_with(|| b.range.end.cmp(&a.range.end))
2603 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2604 });
2605
2606 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2607
2608 let edits_since_save = std::cell::LazyCell::new(|| {
2609 let saved_version = buffer.read(cx).saved_version();
2610 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2611 });
2612
2613 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2614
2615 for (new_diagnostic, entry) in diagnostics {
2616 let start;
2617 let end;
2618 if new_diagnostic && entry.diagnostic.is_disk_based {
2619 // Some diagnostics are based on files on disk instead of buffers'
2620 // current contents. Adjust these diagnostics' ranges to reflect
2621 // any unsaved edits.
2622 // Do not alter the reused ones though, as their coordinates were stored as anchors
2623 // and were properly adjusted on reuse.
2624 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2625 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2626 } else {
2627 start = entry.range.start;
2628 end = entry.range.end;
2629 }
2630
2631 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2632 ..snapshot.clip_point_utf16(end, Bias::Right);
2633
2634 // Expand empty ranges by one codepoint
2635 if range.start == range.end {
2636 // This will be go to the next boundary when being clipped
2637 range.end.column += 1;
2638 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2639 if range.start == range.end && range.end.column > 0 {
2640 range.start.column -= 1;
2641 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2642 }
2643 }
2644
2645 sanitized_diagnostics.push(DiagnosticEntry {
2646 range,
2647 diagnostic: entry.diagnostic,
2648 });
2649 }
2650 drop(edits_since_save);
2651
2652 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2653 buffer.update(cx, |buffer, cx| {
2654 if let Some(registration_id) = registration_id {
2655 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2656 self.buffer_pull_diagnostics_result_ids
2657 .entry(server_id)
2658 .or_default()
2659 .entry(registration_id)
2660 .or_default()
2661 .insert(abs_path, result_id);
2662 }
2663 }
2664
2665 buffer.update_diagnostics(server_id, set, cx)
2666 });
2667
2668 Ok(())
2669 }
2670
2671 fn register_language_server_for_invisible_worktree(
2672 &mut self,
2673 worktree: &Entity<Worktree>,
2674 language_server_id: LanguageServerId,
2675 cx: &mut App,
2676 ) {
2677 let worktree = worktree.read(cx);
2678 let worktree_id = worktree.id();
2679 debug_assert!(!worktree.is_visible());
2680 let Some(mut origin_seed) = self
2681 .language_server_ids
2682 .iter()
2683 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2684 else {
2685 return;
2686 };
2687 origin_seed.worktree_id = worktree_id;
2688 self.language_server_ids
2689 .entry(origin_seed)
2690 .or_insert_with(|| UnifiedLanguageServer {
2691 id: language_server_id,
2692 project_roots: Default::default(),
2693 });
2694 }
2695
2696 fn register_buffer_with_language_servers(
2697 &mut self,
2698 buffer_handle: &Entity<Buffer>,
2699 only_register_servers: HashSet<LanguageServerSelector>,
2700 cx: &mut Context<LspStore>,
2701 ) {
2702 let buffer = buffer_handle.read(cx);
2703 let buffer_id = buffer.remote_id();
2704
2705 let Some(file) = File::from_dyn(buffer.file()) else {
2706 return;
2707 };
2708 if !file.is_local() {
2709 return;
2710 }
2711
2712 let abs_path = file.abs_path(cx);
2713 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2714 return;
2715 };
2716 let initial_snapshot = buffer.text_snapshot();
2717 let worktree_id = file.worktree_id(cx);
2718
2719 let Some(language) = buffer.language().cloned() else {
2720 return;
2721 };
2722 let path: Arc<RelPath> = file
2723 .path()
2724 .parent()
2725 .map(Arc::from)
2726 .unwrap_or_else(|| file.path().clone());
2727 let Some(worktree) = self
2728 .worktree_store
2729 .read(cx)
2730 .worktree_for_id(worktree_id, cx)
2731 else {
2732 return;
2733 };
2734 let language_name = language.name();
2735 let (reused, delegate, servers) = self
2736 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2737 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2738 .unwrap_or_else(|| {
2739 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2740 let delegate: Arc<dyn ManifestDelegate> =
2741 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2742
2743 let servers = self
2744 .lsp_tree
2745 .walk(
2746 ProjectPath { worktree_id, path },
2747 language.name(),
2748 language.manifest(),
2749 &delegate,
2750 cx,
2751 )
2752 .collect::<Vec<_>>();
2753 (false, lsp_delegate, servers)
2754 });
2755 let servers_and_adapters = servers
2756 .into_iter()
2757 .filter_map(|server_node| {
2758 if reused && server_node.server_id().is_none() {
2759 return None;
2760 }
2761 if !only_register_servers.is_empty() {
2762 if let Some(server_id) = server_node.server_id()
2763 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2764 {
2765 return None;
2766 }
2767 if let Some(name) = server_node.name()
2768 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2769 {
2770 return None;
2771 }
2772 }
2773
2774 let server_id = server_node.server_id_or_init(|disposition| {
2775 let path = &disposition.path;
2776
2777 {
2778 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2779
2780 let server_id = self.get_or_insert_language_server(
2781 &worktree,
2782 delegate.clone(),
2783 disposition,
2784 &language_name,
2785 cx,
2786 );
2787
2788 if let Some(state) = self.language_servers.get(&server_id)
2789 && let Ok(uri) = uri
2790 {
2791 state.add_workspace_folder(uri);
2792 };
2793 server_id
2794 }
2795 })?;
2796 let server_state = self.language_servers.get(&server_id)?;
2797 if let LanguageServerState::Running {
2798 server, adapter, ..
2799 } = server_state
2800 {
2801 Some((server.clone(), adapter.clone()))
2802 } else {
2803 None
2804 }
2805 })
2806 .collect::<Vec<_>>();
2807 for (server, adapter) in servers_and_adapters {
2808 buffer_handle.update(cx, |buffer, cx| {
2809 buffer.set_completion_triggers(
2810 server.server_id(),
2811 server
2812 .capabilities()
2813 .completion_provider
2814 .as_ref()
2815 .and_then(|provider| {
2816 provider
2817 .trigger_characters
2818 .as_ref()
2819 .map(|characters| characters.iter().cloned().collect())
2820 })
2821 .unwrap_or_default(),
2822 cx,
2823 );
2824 });
2825
2826 let snapshot = LspBufferSnapshot {
2827 version: 0,
2828 snapshot: initial_snapshot.clone(),
2829 };
2830
2831 let mut registered = false;
2832 self.buffer_snapshots
2833 .entry(buffer_id)
2834 .or_default()
2835 .entry(server.server_id())
2836 .or_insert_with(|| {
2837 registered = true;
2838 server.register_buffer(
2839 uri.clone(),
2840 adapter.language_id(&language.name()),
2841 0,
2842 initial_snapshot.text(),
2843 );
2844
2845 vec![snapshot]
2846 });
2847
2848 self.buffers_opened_in_servers
2849 .entry(buffer_id)
2850 .or_default()
2851 .insert(server.server_id());
2852 if registered {
2853 cx.emit(LspStoreEvent::LanguageServerUpdate {
2854 language_server_id: server.server_id(),
2855 name: None,
2856 message: proto::update_language_server::Variant::RegisteredForBuffer(
2857 proto::RegisteredForBuffer {
2858 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2859 buffer_id: buffer_id.to_proto(),
2860 },
2861 ),
2862 });
2863 }
2864 }
2865 }
2866
2867 fn reuse_existing_language_server<'lang_name>(
2868 &self,
2869 server_tree: &LanguageServerTree,
2870 worktree: &Entity<Worktree>,
2871 language_name: &'lang_name LanguageName,
2872 cx: &mut App,
2873 ) -> Option<(
2874 Arc<LocalLspAdapterDelegate>,
2875 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2876 )> {
2877 if worktree.read(cx).is_visible() {
2878 return None;
2879 }
2880
2881 let worktree_store = self.worktree_store.read(cx);
2882 let servers = server_tree
2883 .instances
2884 .iter()
2885 .filter(|(worktree_id, _)| {
2886 worktree_store
2887 .worktree_for_id(**worktree_id, cx)
2888 .is_some_and(|worktree| worktree.read(cx).is_visible())
2889 })
2890 .flat_map(|(worktree_id, servers)| {
2891 servers
2892 .roots
2893 .iter()
2894 .flat_map(|(_, language_servers)| language_servers)
2895 .map(move |(_, (server_node, server_languages))| {
2896 (worktree_id, server_node, server_languages)
2897 })
2898 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2899 .map(|(worktree_id, server_node, _)| {
2900 (
2901 *worktree_id,
2902 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2903 )
2904 })
2905 })
2906 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2907 acc.entry(worktree_id)
2908 .or_insert_with(Vec::new)
2909 .push(server_node);
2910 acc
2911 })
2912 .into_values()
2913 .max_by_key(|servers| servers.len())?;
2914
2915 let worktree_id = worktree.read(cx).id();
2916 let apply = move |tree: &mut LanguageServerTree| {
2917 for server_node in &servers {
2918 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2919 }
2920 servers
2921 };
2922
2923 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2924 Some((delegate, apply))
2925 }
2926
2927 pub(crate) fn unregister_old_buffer_from_language_servers(
2928 &mut self,
2929 buffer: &Entity<Buffer>,
2930 old_file: &File,
2931 cx: &mut App,
2932 ) {
2933 let old_path = match old_file.as_local() {
2934 Some(local) => local.abs_path(cx),
2935 None => return,
2936 };
2937
2938 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2939 debug_panic!("{old_path:?} is not parseable as an URI");
2940 return;
2941 };
2942 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2943 }
2944
2945 pub(crate) fn unregister_buffer_from_language_servers(
2946 &mut self,
2947 buffer: &Entity<Buffer>,
2948 file_url: &lsp::Uri,
2949 cx: &mut App,
2950 ) {
2951 buffer.update(cx, |buffer, cx| {
2952 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2953
2954 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2955 if snapshots
2956 .as_mut()
2957 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2958 {
2959 language_server.unregister_buffer(file_url.clone());
2960 }
2961 }
2962 });
2963 }
2964
2965 fn buffer_snapshot_for_lsp_version(
2966 &mut self,
2967 buffer: &Entity<Buffer>,
2968 server_id: LanguageServerId,
2969 version: Option<i32>,
2970 cx: &App,
2971 ) -> Result<TextBufferSnapshot> {
2972 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2973
2974 if let Some(version) = version {
2975 let buffer_id = buffer.read(cx).remote_id();
2976 let snapshots = if let Some(snapshots) = self
2977 .buffer_snapshots
2978 .get_mut(&buffer_id)
2979 .and_then(|m| m.get_mut(&server_id))
2980 {
2981 snapshots
2982 } else if version == 0 {
2983 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2984 // We detect this case and treat it as if the version was `None`.
2985 return Ok(buffer.read(cx).text_snapshot());
2986 } else {
2987 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2988 };
2989
2990 let found_snapshot = snapshots
2991 .binary_search_by_key(&version, |e| e.version)
2992 .map(|ix| snapshots[ix].snapshot.clone())
2993 .map_err(|_| {
2994 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2995 })?;
2996
2997 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2998 Ok(found_snapshot)
2999 } else {
3000 Ok((buffer.read(cx)).text_snapshot())
3001 }
3002 }
3003
3004 async fn get_server_code_actions_from_action_kinds(
3005 lsp_store: &WeakEntity<LspStore>,
3006 language_server_id: LanguageServerId,
3007 code_action_kinds: Vec<lsp::CodeActionKind>,
3008 buffer: &Entity<Buffer>,
3009 cx: &mut AsyncApp,
3010 ) -> Result<Vec<CodeAction>> {
3011 let actions = lsp_store
3012 .update(cx, move |this, cx| {
3013 let request = GetCodeActions {
3014 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3015 kinds: Some(code_action_kinds),
3016 };
3017 let server = LanguageServerToQuery::Other(language_server_id);
3018 this.request_lsp(buffer.clone(), server, request, cx)
3019 })?
3020 .await?;
3021 Ok(actions)
3022 }
3023
3024 pub async fn execute_code_actions_on_server(
3025 lsp_store: &WeakEntity<LspStore>,
3026 language_server: &Arc<LanguageServer>,
3027 actions: Vec<CodeAction>,
3028 push_to_history: bool,
3029 project_transaction: &mut ProjectTransaction,
3030 cx: &mut AsyncApp,
3031 ) -> anyhow::Result<()> {
3032 let request_timeout = cx.update(|app| {
3033 ProjectSettings::get_global(app)
3034 .global_lsp_settings
3035 .get_request_timeout()
3036 });
3037
3038 for mut action in actions {
3039 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3040 .await
3041 .context("resolving a formatting code action")?;
3042
3043 if let Some(edit) = action.lsp_action.edit() {
3044 if edit.changes.is_none() && edit.document_changes.is_none() {
3045 continue;
3046 }
3047
3048 let new = Self::deserialize_workspace_edit(
3049 lsp_store.upgrade().context("project dropped")?,
3050 edit.clone(),
3051 push_to_history,
3052 language_server.clone(),
3053 cx,
3054 )
3055 .await?;
3056 project_transaction.0.extend(new.0);
3057 }
3058
3059 let Some(command) = action.lsp_action.command() else {
3060 continue;
3061 };
3062
3063 let server_capabilities = language_server.capabilities();
3064 let available_commands = server_capabilities
3065 .execute_command_provider
3066 .as_ref()
3067 .map(|options| options.commands.as_slice())
3068 .unwrap_or_default();
3069 if !available_commands.contains(&command.command) {
3070 log::warn!(
3071 "Cannot execute a command {} not listed in the language server capabilities",
3072 command.command
3073 );
3074 continue;
3075 }
3076
3077 lsp_store.update(cx, |lsp_store, _| {
3078 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3079 mode.last_workspace_edits_by_language_server
3080 .remove(&language_server.server_id());
3081 }
3082 })?;
3083
3084 language_server
3085 .request::<lsp::request::ExecuteCommand>(
3086 lsp::ExecuteCommandParams {
3087 command: command.command.clone(),
3088 arguments: command.arguments.clone().unwrap_or_default(),
3089 ..Default::default()
3090 },
3091 request_timeout,
3092 )
3093 .await
3094 .into_response()
3095 .context("execute command")?;
3096
3097 lsp_store.update(cx, |this, _| {
3098 if let LspStoreMode::Local(mode) = &mut this.mode {
3099 project_transaction.0.extend(
3100 mode.last_workspace_edits_by_language_server
3101 .remove(&language_server.server_id())
3102 .unwrap_or_default()
3103 .0,
3104 )
3105 }
3106 })?;
3107 }
3108 Ok(())
3109 }
3110
3111 pub async fn deserialize_text_edits(
3112 this: Entity<LspStore>,
3113 buffer_to_edit: Entity<Buffer>,
3114 edits: Vec<lsp::TextEdit>,
3115 push_to_history: bool,
3116 _: Arc<CachedLspAdapter>,
3117 language_server: Arc<LanguageServer>,
3118 cx: &mut AsyncApp,
3119 ) -> Result<Option<Transaction>> {
3120 let edits = this
3121 .update(cx, |this, cx| {
3122 this.as_local_mut().unwrap().edits_from_lsp(
3123 &buffer_to_edit,
3124 edits,
3125 language_server.server_id(),
3126 None,
3127 cx,
3128 )
3129 })
3130 .await?;
3131
3132 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3133 buffer.finalize_last_transaction();
3134 buffer.start_transaction();
3135 for (range, text) in edits {
3136 buffer.edit([(range, text)], None, cx);
3137 }
3138
3139 if buffer.end_transaction(cx).is_some() {
3140 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3141 if !push_to_history {
3142 buffer.forget_transaction(transaction.id);
3143 }
3144 Some(transaction)
3145 } else {
3146 None
3147 }
3148 });
3149
3150 Ok(transaction)
3151 }
3152
3153 #[allow(clippy::type_complexity)]
3154 pub fn edits_from_lsp(
3155 &mut self,
3156 buffer: &Entity<Buffer>,
3157 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3158 server_id: LanguageServerId,
3159 version: Option<i32>,
3160 cx: &mut Context<LspStore>,
3161 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3162 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3163 cx.background_spawn(async move {
3164 let snapshot = snapshot?;
3165 let mut lsp_edits = lsp_edits
3166 .into_iter()
3167 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3168 .collect::<Vec<_>>();
3169
3170 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3171
3172 let mut lsp_edits = lsp_edits.into_iter().peekable();
3173 let mut edits = Vec::new();
3174 while let Some((range, mut new_text)) = lsp_edits.next() {
3175 // Clip invalid ranges provided by the language server.
3176 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3177 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3178
3179 // Combine any LSP edits that are adjacent.
3180 //
3181 // Also, combine LSP edits that are separated from each other by only
3182 // a newline. This is important because for some code actions,
3183 // Rust-analyzer rewrites the entire buffer via a series of edits that
3184 // are separated by unchanged newline characters.
3185 //
3186 // In order for the diffing logic below to work properly, any edits that
3187 // cancel each other out must be combined into one.
3188 while let Some((next_range, next_text)) = lsp_edits.peek() {
3189 if next_range.start.0 > range.end {
3190 if next_range.start.0.row > range.end.row + 1
3191 || next_range.start.0.column > 0
3192 || snapshot.clip_point_utf16(
3193 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3194 Bias::Left,
3195 ) > range.end
3196 {
3197 break;
3198 }
3199 new_text.push('\n');
3200 }
3201 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3202 new_text.push_str(next_text);
3203 lsp_edits.next();
3204 }
3205
3206 // For multiline edits, perform a diff of the old and new text so that
3207 // we can identify the changes more precisely, preserving the locations
3208 // of any anchors positioned in the unchanged regions.
3209 if range.end.row > range.start.row {
3210 let offset = range.start.to_offset(&snapshot);
3211 let old_text = snapshot.text_for_range(range).collect::<String>();
3212 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3213 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3214 (
3215 snapshot.anchor_after(offset + range.start)
3216 ..snapshot.anchor_before(offset + range.end),
3217 replacement,
3218 )
3219 }));
3220 } else if range.end == range.start {
3221 let anchor = snapshot.anchor_after(range.start);
3222 edits.push((anchor..anchor, new_text.into()));
3223 } else {
3224 let edit_start = snapshot.anchor_after(range.start);
3225 let edit_end = snapshot.anchor_before(range.end);
3226 edits.push((edit_start..edit_end, new_text.into()));
3227 }
3228 }
3229
3230 Ok(edits)
3231 })
3232 }
3233
3234 pub(crate) async fn deserialize_workspace_edit(
3235 this: Entity<LspStore>,
3236 edit: lsp::WorkspaceEdit,
3237 push_to_history: bool,
3238 language_server: Arc<LanguageServer>,
3239 cx: &mut AsyncApp,
3240 ) -> Result<ProjectTransaction> {
3241 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3242
3243 let mut operations = Vec::new();
3244 if let Some(document_changes) = edit.document_changes {
3245 match document_changes {
3246 lsp::DocumentChanges::Edits(edits) => {
3247 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3248 }
3249 lsp::DocumentChanges::Operations(ops) => operations = ops,
3250 }
3251 } else if let Some(changes) = edit.changes {
3252 operations.extend(changes.into_iter().map(|(uri, edits)| {
3253 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3254 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3255 uri,
3256 version: None,
3257 },
3258 edits: edits.into_iter().map(Edit::Plain).collect(),
3259 })
3260 }));
3261 }
3262
3263 let mut project_transaction = ProjectTransaction::default();
3264 for operation in operations {
3265 match operation {
3266 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3267 let abs_path = op
3268 .uri
3269 .to_file_path()
3270 .map_err(|()| anyhow!("can't convert URI to path"))?;
3271
3272 if let Some(parent_path) = abs_path.parent() {
3273 fs.create_dir(parent_path).await?;
3274 }
3275 if abs_path.ends_with("/") {
3276 fs.create_dir(&abs_path).await?;
3277 } else {
3278 fs.create_file(
3279 &abs_path,
3280 op.options
3281 .map(|options| fs::CreateOptions {
3282 overwrite: options.overwrite.unwrap_or(false),
3283 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3284 })
3285 .unwrap_or_default(),
3286 )
3287 .await?;
3288 }
3289 }
3290
3291 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3292 let source_abs_path = op
3293 .old_uri
3294 .to_file_path()
3295 .map_err(|()| anyhow!("can't convert URI to path"))?;
3296 let target_abs_path = op
3297 .new_uri
3298 .to_file_path()
3299 .map_err(|()| anyhow!("can't convert URI to path"))?;
3300
3301 let options = fs::RenameOptions {
3302 overwrite: op
3303 .options
3304 .as_ref()
3305 .and_then(|options| options.overwrite)
3306 .unwrap_or(false),
3307 ignore_if_exists: op
3308 .options
3309 .as_ref()
3310 .and_then(|options| options.ignore_if_exists)
3311 .unwrap_or(false),
3312 create_parents: true,
3313 };
3314
3315 fs.rename(&source_abs_path, &target_abs_path, options)
3316 .await?;
3317 }
3318
3319 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3320 let abs_path = op
3321 .uri
3322 .to_file_path()
3323 .map_err(|()| anyhow!("can't convert URI to path"))?;
3324 let options = op
3325 .options
3326 .map(|options| fs::RemoveOptions {
3327 recursive: options.recursive.unwrap_or(false),
3328 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3329 })
3330 .unwrap_or_default();
3331 if abs_path.ends_with("/") {
3332 fs.remove_dir(&abs_path, options).await?;
3333 } else {
3334 fs.remove_file(&abs_path, options).await?;
3335 }
3336 }
3337
3338 lsp::DocumentChangeOperation::Edit(op) => {
3339 let buffer_to_edit = this
3340 .update(cx, |this, cx| {
3341 this.open_local_buffer_via_lsp(
3342 op.text_document.uri.clone(),
3343 language_server.server_id(),
3344 cx,
3345 )
3346 })
3347 .await?;
3348
3349 let edits = this
3350 .update(cx, |this, cx| {
3351 let path = buffer_to_edit.read(cx).project_path(cx);
3352 let active_entry = this.active_entry;
3353 let is_active_entry = path.is_some_and(|project_path| {
3354 this.worktree_store
3355 .read(cx)
3356 .entry_for_path(&project_path, cx)
3357 .is_some_and(|entry| Some(entry.id) == active_entry)
3358 });
3359 let local = this.as_local_mut().unwrap();
3360
3361 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3362 for edit in op.edits {
3363 match edit {
3364 Edit::Plain(edit) => {
3365 if !edits.contains(&edit) {
3366 edits.push(edit)
3367 }
3368 }
3369 Edit::Annotated(edit) => {
3370 if !edits.contains(&edit.text_edit) {
3371 edits.push(edit.text_edit)
3372 }
3373 }
3374 Edit::Snippet(edit) => {
3375 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3376 else {
3377 continue;
3378 };
3379
3380 if is_active_entry {
3381 snippet_edits.push((edit.range, snippet));
3382 } else {
3383 // Since this buffer is not focused, apply a normal edit.
3384 let new_edit = TextEdit {
3385 range: edit.range,
3386 new_text: snippet.text,
3387 };
3388 if !edits.contains(&new_edit) {
3389 edits.push(new_edit);
3390 }
3391 }
3392 }
3393 }
3394 }
3395 if !snippet_edits.is_empty() {
3396 let buffer_id = buffer_to_edit.read(cx).remote_id();
3397 let version = if let Some(buffer_version) = op.text_document.version
3398 {
3399 local
3400 .buffer_snapshot_for_lsp_version(
3401 &buffer_to_edit,
3402 language_server.server_id(),
3403 Some(buffer_version),
3404 cx,
3405 )
3406 .ok()
3407 .map(|snapshot| snapshot.version)
3408 } else {
3409 Some(buffer_to_edit.read(cx).saved_version().clone())
3410 };
3411
3412 let most_recent_edit =
3413 version.and_then(|version| version.most_recent());
3414 // Check if the edit that triggered that edit has been made by this participant.
3415
3416 if let Some(most_recent_edit) = most_recent_edit {
3417 cx.emit(LspStoreEvent::SnippetEdit {
3418 buffer_id,
3419 edits: snippet_edits,
3420 most_recent_edit,
3421 });
3422 }
3423 }
3424
3425 local.edits_from_lsp(
3426 &buffer_to_edit,
3427 edits,
3428 language_server.server_id(),
3429 op.text_document.version,
3430 cx,
3431 )
3432 })
3433 .await?;
3434
3435 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3436 buffer.finalize_last_transaction();
3437 buffer.start_transaction();
3438 for (range, text) in edits {
3439 buffer.edit([(range, text)], None, cx);
3440 }
3441
3442 buffer.end_transaction(cx).and_then(|transaction_id| {
3443 if push_to_history {
3444 buffer.finalize_last_transaction();
3445 buffer.get_transaction(transaction_id).cloned()
3446 } else {
3447 buffer.forget_transaction(transaction_id)
3448 }
3449 })
3450 });
3451 if let Some(transaction) = transaction {
3452 project_transaction.0.insert(buffer_to_edit, transaction);
3453 }
3454 }
3455 }
3456 }
3457
3458 Ok(project_transaction)
3459 }
3460
3461 async fn on_lsp_workspace_edit(
3462 this: WeakEntity<LspStore>,
3463 params: lsp::ApplyWorkspaceEditParams,
3464 server_id: LanguageServerId,
3465 cx: &mut AsyncApp,
3466 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3467 let this = this.upgrade().context("project project closed")?;
3468 let language_server = this
3469 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3470 .context("language server not found")?;
3471 let transaction = Self::deserialize_workspace_edit(
3472 this.clone(),
3473 params.edit,
3474 true,
3475 language_server.clone(),
3476 cx,
3477 )
3478 .await
3479 .log_err();
3480 this.update(cx, |this, cx| {
3481 if let Some(transaction) = transaction {
3482 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3483
3484 this.as_local_mut()
3485 .unwrap()
3486 .last_workspace_edits_by_language_server
3487 .insert(server_id, transaction);
3488 }
3489 });
3490 Ok(lsp::ApplyWorkspaceEditResponse {
3491 applied: true,
3492 failed_change: None,
3493 failure_reason: None,
3494 })
3495 }
3496
3497 fn remove_worktree(
3498 &mut self,
3499 id_to_remove: WorktreeId,
3500 cx: &mut Context<LspStore>,
3501 ) -> Vec<LanguageServerId> {
3502 self.restricted_worktrees_tasks.remove(&id_to_remove);
3503 self.diagnostics.remove(&id_to_remove);
3504 self.prettier_store.update(cx, |prettier_store, cx| {
3505 prettier_store.remove_worktree(id_to_remove, cx);
3506 });
3507
3508 let mut servers_to_remove = BTreeSet::default();
3509 let mut servers_to_preserve = HashSet::default();
3510 for (seed, state) in &self.language_server_ids {
3511 if seed.worktree_id == id_to_remove {
3512 servers_to_remove.insert(state.id);
3513 } else {
3514 servers_to_preserve.insert(state.id);
3515 }
3516 }
3517 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3518 self.language_server_ids
3519 .retain(|_, state| !servers_to_remove.contains(&state.id));
3520 for server_id_to_remove in &servers_to_remove {
3521 self.language_server_watched_paths
3522 .remove(server_id_to_remove);
3523 self.language_server_paths_watched_for_rename
3524 .remove(server_id_to_remove);
3525 self.last_workspace_edits_by_language_server
3526 .remove(server_id_to_remove);
3527 self.language_servers.remove(server_id_to_remove);
3528 self.buffer_pull_diagnostics_result_ids
3529 .remove(server_id_to_remove);
3530 self.workspace_pull_diagnostics_result_ids
3531 .remove(server_id_to_remove);
3532 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3533 buffer_servers.remove(server_id_to_remove);
3534 }
3535 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3536 }
3537 servers_to_remove.into_iter().collect()
3538 }
3539
3540 fn rebuild_watched_paths_inner<'a>(
3541 &'a self,
3542 language_server_id: LanguageServerId,
3543 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3544 cx: &mut Context<LspStore>,
3545 ) -> LanguageServerWatchedPathsBuilder {
3546 let worktrees = self
3547 .worktree_store
3548 .read(cx)
3549 .worktrees()
3550 .filter_map(|worktree| {
3551 self.language_servers_for_worktree(worktree.read(cx).id())
3552 .find(|server| server.server_id() == language_server_id)
3553 .map(|_| worktree)
3554 })
3555 .collect::<Vec<_>>();
3556
3557 let mut worktree_globs = HashMap::default();
3558 let mut abs_globs = HashMap::default();
3559 log::trace!(
3560 "Processing new watcher paths for language server with id {}",
3561 language_server_id
3562 );
3563
3564 for watcher in watchers {
3565 if let Some((worktree, literal_prefix, pattern)) =
3566 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3567 {
3568 worktree.update(cx, |worktree, _| {
3569 if let Some((tree, glob)) =
3570 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3571 {
3572 tree.add_path_prefix_to_scan(literal_prefix);
3573 worktree_globs
3574 .entry(tree.id())
3575 .or_insert_with(GlobSetBuilder::new)
3576 .add(glob);
3577 }
3578 });
3579 } else {
3580 let (path, pattern) = match &watcher.glob_pattern {
3581 lsp::GlobPattern::String(s) => {
3582 let watcher_path = SanitizedPath::new(s);
3583 let path = glob_literal_prefix(watcher_path.as_path());
3584 let pattern = watcher_path
3585 .as_path()
3586 .strip_prefix(&path)
3587 .map(|p| p.to_string_lossy().into_owned())
3588 .unwrap_or_else(|e| {
3589 debug_panic!(
3590 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3591 s,
3592 path.display(),
3593 e
3594 );
3595 watcher_path.as_path().to_string_lossy().into_owned()
3596 });
3597 (path, pattern)
3598 }
3599 lsp::GlobPattern::Relative(rp) => {
3600 let Ok(mut base_uri) = match &rp.base_uri {
3601 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3602 lsp::OneOf::Right(base_uri) => base_uri,
3603 }
3604 .to_file_path() else {
3605 continue;
3606 };
3607
3608 let path = glob_literal_prefix(Path::new(&rp.pattern));
3609 let pattern = Path::new(&rp.pattern)
3610 .strip_prefix(&path)
3611 .map(|p| p.to_string_lossy().into_owned())
3612 .unwrap_or_else(|e| {
3613 debug_panic!(
3614 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3615 rp.pattern,
3616 path.display(),
3617 e
3618 );
3619 rp.pattern.clone()
3620 });
3621 base_uri.push(path);
3622 (base_uri, pattern)
3623 }
3624 };
3625
3626 if let Some(glob) = Glob::new(&pattern).log_err() {
3627 if !path
3628 .components()
3629 .any(|c| matches!(c, path::Component::Normal(_)))
3630 {
3631 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3632 // rather than adding a new watcher for `/`.
3633 for worktree in &worktrees {
3634 worktree_globs
3635 .entry(worktree.read(cx).id())
3636 .or_insert_with(GlobSetBuilder::new)
3637 .add(glob.clone());
3638 }
3639 } else {
3640 abs_globs
3641 .entry(path.into())
3642 .or_insert_with(GlobSetBuilder::new)
3643 .add(glob);
3644 }
3645 }
3646 }
3647 }
3648
3649 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3650 for (worktree_id, builder) in worktree_globs {
3651 if let Ok(globset) = builder.build() {
3652 watch_builder.watch_worktree(worktree_id, globset);
3653 }
3654 }
3655 for (abs_path, builder) in abs_globs {
3656 if let Ok(globset) = builder.build() {
3657 watch_builder.watch_abs_path(abs_path, globset);
3658 }
3659 }
3660 watch_builder
3661 }
3662
3663 fn worktree_and_path_for_file_watcher(
3664 worktrees: &[Entity<Worktree>],
3665 watcher: &FileSystemWatcher,
3666 cx: &App,
3667 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3668 worktrees.iter().find_map(|worktree| {
3669 let tree = worktree.read(cx);
3670 let worktree_root_path = tree.abs_path();
3671 let path_style = tree.path_style();
3672 match &watcher.glob_pattern {
3673 lsp::GlobPattern::String(s) => {
3674 let watcher_path = SanitizedPath::new(s);
3675 let relative = watcher_path
3676 .as_path()
3677 .strip_prefix(&worktree_root_path)
3678 .ok()?;
3679 let literal_prefix = glob_literal_prefix(relative);
3680 Some((
3681 worktree.clone(),
3682 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3683 relative.to_string_lossy().into_owned(),
3684 ))
3685 }
3686 lsp::GlobPattern::Relative(rp) => {
3687 let base_uri = match &rp.base_uri {
3688 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3689 lsp::OneOf::Right(base_uri) => base_uri,
3690 }
3691 .to_file_path()
3692 .ok()?;
3693 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3694 let mut literal_prefix = relative.to_owned();
3695 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3696 Some((
3697 worktree.clone(),
3698 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3699 rp.pattern.clone(),
3700 ))
3701 }
3702 }
3703 })
3704 }
3705
3706 fn rebuild_watched_paths(
3707 &mut self,
3708 language_server_id: LanguageServerId,
3709 cx: &mut Context<LspStore>,
3710 ) {
3711 let Some(registrations) = self
3712 .language_server_dynamic_registrations
3713 .get(&language_server_id)
3714 else {
3715 return;
3716 };
3717
3718 let watch_builder = self.rebuild_watched_paths_inner(
3719 language_server_id,
3720 registrations.did_change_watched_files.values().flatten(),
3721 cx,
3722 );
3723 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3724 self.language_server_watched_paths
3725 .insert(language_server_id, watcher);
3726
3727 cx.notify();
3728 }
3729
3730 fn on_lsp_did_change_watched_files(
3731 &mut self,
3732 language_server_id: LanguageServerId,
3733 registration_id: &str,
3734 params: DidChangeWatchedFilesRegistrationOptions,
3735 cx: &mut Context<LspStore>,
3736 ) {
3737 let registrations = self
3738 .language_server_dynamic_registrations
3739 .entry(language_server_id)
3740 .or_default();
3741
3742 registrations
3743 .did_change_watched_files
3744 .insert(registration_id.to_string(), params.watchers);
3745
3746 self.rebuild_watched_paths(language_server_id, cx);
3747 }
3748
3749 fn on_lsp_unregister_did_change_watched_files(
3750 &mut self,
3751 language_server_id: LanguageServerId,
3752 registration_id: &str,
3753 cx: &mut Context<LspStore>,
3754 ) {
3755 let registrations = self
3756 .language_server_dynamic_registrations
3757 .entry(language_server_id)
3758 .or_default();
3759
3760 if registrations
3761 .did_change_watched_files
3762 .remove(registration_id)
3763 .is_some()
3764 {
3765 log::info!(
3766 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3767 language_server_id,
3768 registration_id
3769 );
3770 } else {
3771 log::warn!(
3772 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3773 language_server_id,
3774 registration_id
3775 );
3776 }
3777
3778 self.rebuild_watched_paths(language_server_id, cx);
3779 }
3780
3781 async fn initialization_options_for_adapter(
3782 adapter: Arc<dyn LspAdapter>,
3783 delegate: &Arc<dyn LspAdapterDelegate>,
3784 cx: &mut AsyncApp,
3785 ) -> Result<Option<serde_json::Value>> {
3786 let Some(mut initialization_config) =
3787 adapter.clone().initialization_options(delegate, cx).await?
3788 else {
3789 return Ok(None);
3790 };
3791
3792 for other_adapter in delegate.registered_lsp_adapters() {
3793 if other_adapter.name() == adapter.name() {
3794 continue;
3795 }
3796 if let Ok(Some(target_config)) = other_adapter
3797 .clone()
3798 .additional_initialization_options(adapter.name(), delegate)
3799 .await
3800 {
3801 merge_json_value_into(target_config.clone(), &mut initialization_config);
3802 }
3803 }
3804
3805 Ok(Some(initialization_config))
3806 }
3807
3808 async fn workspace_configuration_for_adapter(
3809 adapter: Arc<dyn LspAdapter>,
3810 delegate: &Arc<dyn LspAdapterDelegate>,
3811 toolchain: Option<Toolchain>,
3812 requested_uri: Option<Uri>,
3813 cx: &mut AsyncApp,
3814 ) -> Result<serde_json::Value> {
3815 let mut workspace_config = adapter
3816 .clone()
3817 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3818 .await?;
3819
3820 for other_adapter in delegate.registered_lsp_adapters() {
3821 if other_adapter.name() == adapter.name() {
3822 continue;
3823 }
3824 if let Ok(Some(target_config)) = other_adapter
3825 .clone()
3826 .additional_workspace_configuration(adapter.name(), delegate, cx)
3827 .await
3828 {
3829 merge_json_value_into(target_config.clone(), &mut workspace_config);
3830 }
3831 }
3832
3833 Ok(workspace_config)
3834 }
3835
3836 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3837 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3838 Some(server.clone())
3839 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3840 Some(Arc::clone(server))
3841 } else {
3842 None
3843 }
3844 }
3845}
3846
3847fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3848 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3849 cx.emit(LspStoreEvent::LanguageServerUpdate {
3850 language_server_id: server.server_id(),
3851 name: Some(server.name()),
3852 message: proto::update_language_server::Variant::MetadataUpdated(
3853 proto::ServerMetadataUpdated {
3854 capabilities: Some(capabilities),
3855 binary: Some(proto::LanguageServerBinaryInfo {
3856 path: server.binary().path.to_string_lossy().into_owned(),
3857 arguments: server
3858 .binary()
3859 .arguments
3860 .iter()
3861 .map(|arg| arg.to_string_lossy().into_owned())
3862 .collect(),
3863 }),
3864 configuration: serde_json::to_string(server.configuration()).ok(),
3865 workspace_folders: server
3866 .workspace_folders()
3867 .iter()
3868 .map(|uri| uri.to_string())
3869 .collect(),
3870 },
3871 ),
3872 });
3873 }
3874}
3875
3876#[derive(Debug)]
3877pub struct FormattableBuffer {
3878 handle: Entity<Buffer>,
3879 abs_path: Option<PathBuf>,
3880 env: Option<HashMap<String, String>>,
3881 ranges: Option<Vec<Range<Anchor>>>,
3882}
3883
3884pub struct RemoteLspStore {
3885 upstream_client: Option<AnyProtoClient>,
3886 upstream_project_id: u64,
3887}
3888
3889pub(crate) enum LspStoreMode {
3890 Local(LocalLspStore), // ssh host and collab host
3891 Remote(RemoteLspStore), // collab guest
3892}
3893
3894impl LspStoreMode {
3895 fn is_local(&self) -> bool {
3896 matches!(self, LspStoreMode::Local(_))
3897 }
3898}
3899
3900pub struct LspStore {
3901 mode: LspStoreMode,
3902 last_formatting_failure: Option<String>,
3903 downstream_client: Option<(AnyProtoClient, u64)>,
3904 nonce: u128,
3905 buffer_store: Entity<BufferStore>,
3906 worktree_store: Entity<WorktreeStore>,
3907 pub languages: Arc<LanguageRegistry>,
3908 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3909 active_entry: Option<ProjectEntryId>,
3910 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3911 _maintain_buffer_languages: Task<()>,
3912 diagnostic_summaries:
3913 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3914 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3915 semantic_token_config: SemanticTokenConfig,
3916 lsp_data: HashMap<BufferId, BufferLspData>,
3917 next_hint_id: Arc<AtomicUsize>,
3918}
3919
3920#[derive(Debug)]
3921pub struct BufferLspData {
3922 buffer_version: Global,
3923 document_colors: Option<DocumentColorData>,
3924 code_lens: Option<CodeLensData>,
3925 semantic_tokens: Option<SemanticTokensData>,
3926 folding_ranges: Option<FoldingRangeData>,
3927 document_symbols: Option<DocumentSymbolsData>,
3928 inlay_hints: BufferInlayHints,
3929 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3930 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3931}
3932
3933#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3934struct LspKey {
3935 request_type: TypeId,
3936 server_queried: Option<LanguageServerId>,
3937}
3938
3939impl BufferLspData {
3940 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3941 Self {
3942 buffer_version: buffer.read(cx).version(),
3943 document_colors: None,
3944 code_lens: None,
3945 semantic_tokens: None,
3946 folding_ranges: None,
3947 document_symbols: None,
3948 inlay_hints: BufferInlayHints::new(buffer, cx),
3949 lsp_requests: HashMap::default(),
3950 chunk_lsp_requests: HashMap::default(),
3951 }
3952 }
3953
3954 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3955 if let Some(document_colors) = &mut self.document_colors {
3956 document_colors.remove_server_data(for_server);
3957 }
3958
3959 if let Some(code_lens) = &mut self.code_lens {
3960 code_lens.remove_server_data(for_server);
3961 }
3962
3963 self.inlay_hints.remove_server_data(for_server);
3964
3965 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3966 semantic_tokens.remove_server_data(for_server);
3967 }
3968
3969 if let Some(folding_ranges) = &mut self.folding_ranges {
3970 folding_ranges.ranges.remove(&for_server);
3971 }
3972
3973 if let Some(document_symbols) = &mut self.document_symbols {
3974 document_symbols.remove_server_data(for_server);
3975 }
3976 }
3977
3978 #[cfg(any(test, feature = "test-support"))]
3979 pub fn inlay_hints(&self) -> &BufferInlayHints {
3980 &self.inlay_hints
3981 }
3982}
3983
3984#[derive(Debug)]
3985pub enum LspStoreEvent {
3986 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3987 LanguageServerRemoved(LanguageServerId),
3988 LanguageServerUpdate {
3989 language_server_id: LanguageServerId,
3990 name: Option<LanguageServerName>,
3991 message: proto::update_language_server::Variant,
3992 },
3993 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3994 LanguageServerPrompt(LanguageServerPromptRequest),
3995 LanguageDetected {
3996 buffer: Entity<Buffer>,
3997 new_language: Option<Arc<Language>>,
3998 },
3999 Notification(String),
4000 RefreshInlayHints {
4001 server_id: LanguageServerId,
4002 request_id: Option<usize>,
4003 },
4004 RefreshSemanticTokens {
4005 server_id: LanguageServerId,
4006 request_id: Option<usize>,
4007 },
4008 RefreshCodeLens,
4009 DiagnosticsUpdated {
4010 server_id: LanguageServerId,
4011 paths: Vec<ProjectPath>,
4012 },
4013 DiskBasedDiagnosticsStarted {
4014 language_server_id: LanguageServerId,
4015 },
4016 DiskBasedDiagnosticsFinished {
4017 language_server_id: LanguageServerId,
4018 },
4019 SnippetEdit {
4020 buffer_id: BufferId,
4021 edits: Vec<(lsp::Range, Snippet)>,
4022 most_recent_edit: clock::Lamport,
4023 },
4024 WorkspaceEditApplied(ProjectTransaction),
4025}
4026
4027#[derive(Clone, Debug, Serialize)]
4028pub struct LanguageServerStatus {
4029 pub name: LanguageServerName,
4030 pub server_version: Option<SharedString>,
4031 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4032 pub has_pending_diagnostic_updates: bool,
4033 pub progress_tokens: HashSet<ProgressToken>,
4034 pub worktree: Option<WorktreeId>,
4035 pub binary: Option<LanguageServerBinary>,
4036 pub configuration: Option<Value>,
4037 pub workspace_folders: BTreeSet<Uri>,
4038 pub process_id: Option<u32>,
4039}
4040
4041#[derive(Clone, Debug)]
4042struct CoreSymbol {
4043 pub language_server_name: LanguageServerName,
4044 pub source_worktree_id: WorktreeId,
4045 pub source_language_server_id: LanguageServerId,
4046 pub path: SymbolLocation,
4047 pub name: String,
4048 pub kind: lsp::SymbolKind,
4049 pub range: Range<Unclipped<PointUtf16>>,
4050 pub container_name: Option<String>,
4051}
4052
4053#[derive(Clone, Debug, PartialEq, Eq)]
4054pub enum SymbolLocation {
4055 InProject(ProjectPath),
4056 OutsideProject {
4057 abs_path: Arc<Path>,
4058 signature: [u8; 32],
4059 },
4060}
4061
4062impl SymbolLocation {
4063 fn file_name(&self) -> Option<&str> {
4064 match self {
4065 Self::InProject(path) => path.path.file_name(),
4066 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4067 }
4068 }
4069}
4070
4071impl LspStore {
4072 pub fn init(client: &AnyProtoClient) {
4073 client.add_entity_request_handler(Self::handle_lsp_query);
4074 client.add_entity_message_handler(Self::handle_lsp_query_response);
4075 client.add_entity_request_handler(Self::handle_restart_language_servers);
4076 client.add_entity_request_handler(Self::handle_stop_language_servers);
4077 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4078 client.add_entity_message_handler(Self::handle_start_language_server);
4079 client.add_entity_message_handler(Self::handle_update_language_server);
4080 client.add_entity_message_handler(Self::handle_language_server_log);
4081 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4082 client.add_entity_request_handler(Self::handle_format_buffers);
4083 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4084 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4085 client.add_entity_request_handler(Self::handle_apply_code_action);
4086 client.add_entity_request_handler(Self::handle_get_project_symbols);
4087 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4088 client.add_entity_request_handler(Self::handle_get_color_presentation);
4089 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4090 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4091 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4092 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4093 client.add_entity_request_handler(Self::handle_on_type_formatting);
4094 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4095 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4096 client.add_entity_request_handler(Self::handle_rename_project_entry);
4097 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4098 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4099 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4100 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4101 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4102 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4103 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4104
4105 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4106 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4107 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4108 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4109 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4110 client.add_entity_request_handler(
4111 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4112 );
4113 client.add_entity_request_handler(
4114 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4115 );
4116 client.add_entity_request_handler(
4117 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4118 );
4119 }
4120
4121 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4122 match &self.mode {
4123 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4124 _ => None,
4125 }
4126 }
4127
4128 pub fn as_local(&self) -> Option<&LocalLspStore> {
4129 match &self.mode {
4130 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4131 _ => None,
4132 }
4133 }
4134
4135 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4136 match &mut self.mode {
4137 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4138 _ => None,
4139 }
4140 }
4141
4142 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4143 match &self.mode {
4144 LspStoreMode::Remote(RemoteLspStore {
4145 upstream_client: Some(upstream_client),
4146 upstream_project_id,
4147 ..
4148 }) => Some((upstream_client.clone(), *upstream_project_id)),
4149
4150 LspStoreMode::Remote(RemoteLspStore {
4151 upstream_client: None,
4152 ..
4153 }) => None,
4154 LspStoreMode::Local(_) => None,
4155 }
4156 }
4157
4158 pub fn new_local(
4159 buffer_store: Entity<BufferStore>,
4160 worktree_store: Entity<WorktreeStore>,
4161 prettier_store: Entity<PrettierStore>,
4162 toolchain_store: Entity<LocalToolchainStore>,
4163 environment: Entity<ProjectEnvironment>,
4164 manifest_tree: Entity<ManifestTree>,
4165 languages: Arc<LanguageRegistry>,
4166 http_client: Arc<dyn HttpClient>,
4167 fs: Arc<dyn Fs>,
4168 cx: &mut Context<Self>,
4169 ) -> Self {
4170 let yarn = YarnPathStore::new(fs.clone(), cx);
4171 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4172 .detach();
4173 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4174 .detach();
4175 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4176 .detach();
4177 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4178 .detach();
4179 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4180 .detach();
4181 subscribe_to_binary_statuses(&languages, cx).detach();
4182
4183 let _maintain_workspace_config = {
4184 let (sender, receiver) = watch::channel();
4185 (Self::maintain_workspace_config(receiver, cx), sender)
4186 };
4187
4188 Self {
4189 mode: LspStoreMode::Local(LocalLspStore {
4190 weak: cx.weak_entity(),
4191 worktree_store: worktree_store.clone(),
4192
4193 supplementary_language_servers: Default::default(),
4194 languages: languages.clone(),
4195 language_server_ids: Default::default(),
4196 language_servers: Default::default(),
4197 last_workspace_edits_by_language_server: Default::default(),
4198 language_server_watched_paths: Default::default(),
4199 language_server_paths_watched_for_rename: Default::default(),
4200 language_server_dynamic_registrations: Default::default(),
4201 buffers_being_formatted: Default::default(),
4202 buffers_to_refresh_hash_set: HashSet::default(),
4203 buffers_to_refresh_queue: VecDeque::new(),
4204 _background_diagnostics_worker: Task::ready(()).shared(),
4205 buffer_snapshots: Default::default(),
4206 prettier_store,
4207 environment,
4208 http_client,
4209 fs,
4210 yarn,
4211 next_diagnostic_group_id: Default::default(),
4212 diagnostics: Default::default(),
4213 _subscription: cx.on_app_quit(|this, _| {
4214 this.as_local_mut()
4215 .unwrap()
4216 .shutdown_language_servers_on_quit()
4217 }),
4218 lsp_tree: LanguageServerTree::new(
4219 manifest_tree,
4220 languages.clone(),
4221 toolchain_store.clone(),
4222 ),
4223 toolchain_store,
4224 registered_buffers: HashMap::default(),
4225 buffers_opened_in_servers: HashMap::default(),
4226 buffer_pull_diagnostics_result_ids: HashMap::default(),
4227 workspace_pull_diagnostics_result_ids: HashMap::default(),
4228 restricted_worktrees_tasks: HashMap::default(),
4229 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4230 .manifest_file_names(),
4231 }),
4232 last_formatting_failure: None,
4233 downstream_client: None,
4234 buffer_store,
4235 worktree_store,
4236 languages: languages.clone(),
4237 language_server_statuses: Default::default(),
4238 nonce: StdRng::from_os_rng().random(),
4239 diagnostic_summaries: HashMap::default(),
4240 lsp_server_capabilities: HashMap::default(),
4241 semantic_token_config: SemanticTokenConfig::new(cx),
4242 lsp_data: HashMap::default(),
4243 next_hint_id: Arc::default(),
4244 active_entry: None,
4245 _maintain_workspace_config,
4246 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4247 }
4248 }
4249
4250 fn send_lsp_proto_request<R: LspCommand>(
4251 &self,
4252 buffer: Entity<Buffer>,
4253 client: AnyProtoClient,
4254 upstream_project_id: u64,
4255 request: R,
4256 cx: &mut Context<LspStore>,
4257 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4258 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4259 return Task::ready(Ok(R::Response::default()));
4260 }
4261 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4262 cx.spawn(async move |this, cx| {
4263 let response = client.request(message).await?;
4264 let this = this.upgrade().context("project dropped")?;
4265 request
4266 .response_from_proto(response, this, buffer, cx.clone())
4267 .await
4268 })
4269 }
4270
4271 pub(super) fn new_remote(
4272 buffer_store: Entity<BufferStore>,
4273 worktree_store: Entity<WorktreeStore>,
4274 languages: Arc<LanguageRegistry>,
4275 upstream_client: AnyProtoClient,
4276 project_id: u64,
4277 cx: &mut Context<Self>,
4278 ) -> Self {
4279 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4280 .detach();
4281 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4282 .detach();
4283 subscribe_to_binary_statuses(&languages, cx).detach();
4284 let _maintain_workspace_config = {
4285 let (sender, receiver) = watch::channel();
4286 (Self::maintain_workspace_config(receiver, cx), sender)
4287 };
4288 Self {
4289 mode: LspStoreMode::Remote(RemoteLspStore {
4290 upstream_client: Some(upstream_client),
4291 upstream_project_id: project_id,
4292 }),
4293 downstream_client: None,
4294 last_formatting_failure: None,
4295 buffer_store,
4296 worktree_store,
4297 languages: languages.clone(),
4298 language_server_statuses: Default::default(),
4299 nonce: StdRng::from_os_rng().random(),
4300 diagnostic_summaries: HashMap::default(),
4301 lsp_server_capabilities: HashMap::default(),
4302 semantic_token_config: SemanticTokenConfig::new(cx),
4303 next_hint_id: Arc::default(),
4304 lsp_data: HashMap::default(),
4305 active_entry: None,
4306
4307 _maintain_workspace_config,
4308 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4309 }
4310 }
4311
4312 fn on_buffer_store_event(
4313 &mut self,
4314 _: Entity<BufferStore>,
4315 event: &BufferStoreEvent,
4316 cx: &mut Context<Self>,
4317 ) {
4318 match event {
4319 BufferStoreEvent::BufferAdded(buffer) => {
4320 self.on_buffer_added(buffer, cx).log_err();
4321 }
4322 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4323 let buffer_id = buffer.read(cx).remote_id();
4324 if let Some(local) = self.as_local_mut()
4325 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4326 {
4327 local.reset_buffer(buffer, old_file, cx);
4328
4329 if local.registered_buffers.contains_key(&buffer_id) {
4330 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4331 }
4332 }
4333
4334 self.detect_language_for_buffer(buffer, cx);
4335 if let Some(local) = self.as_local_mut() {
4336 local.initialize_buffer(buffer, cx);
4337 if local.registered_buffers.contains_key(&buffer_id) {
4338 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4339 }
4340 }
4341 }
4342 _ => {}
4343 }
4344 }
4345
4346 fn on_worktree_store_event(
4347 &mut self,
4348 _: Entity<WorktreeStore>,
4349 event: &WorktreeStoreEvent,
4350 cx: &mut Context<Self>,
4351 ) {
4352 match event {
4353 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4354 if !worktree.read(cx).is_local() {
4355 return;
4356 }
4357 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4358 worktree::Event::UpdatedEntries(changes) => {
4359 this.update_local_worktree_language_servers(&worktree, changes, cx);
4360 }
4361 worktree::Event::UpdatedGitRepositories(_)
4362 | worktree::Event::DeletedEntry(_) => {}
4363 })
4364 .detach()
4365 }
4366 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4367 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4368 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4369 }
4370 WorktreeStoreEvent::WorktreeReleased(..)
4371 | WorktreeStoreEvent::WorktreeOrderChanged
4372 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4373 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4374 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4375 }
4376 }
4377
4378 fn on_prettier_store_event(
4379 &mut self,
4380 _: Entity<PrettierStore>,
4381 event: &PrettierStoreEvent,
4382 cx: &mut Context<Self>,
4383 ) {
4384 match event {
4385 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4386 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4387 }
4388 PrettierStoreEvent::LanguageServerAdded {
4389 new_server_id,
4390 name,
4391 prettier_server,
4392 } => {
4393 self.register_supplementary_language_server(
4394 *new_server_id,
4395 name.clone(),
4396 prettier_server.clone(),
4397 cx,
4398 );
4399 }
4400 }
4401 }
4402
4403 fn on_toolchain_store_event(
4404 &mut self,
4405 _: Entity<LocalToolchainStore>,
4406 event: &ToolchainStoreEvent,
4407 _: &mut Context<Self>,
4408 ) {
4409 if let ToolchainStoreEvent::ToolchainActivated = event {
4410 self.request_workspace_config_refresh()
4411 }
4412 }
4413
4414 fn request_workspace_config_refresh(&mut self) {
4415 *self._maintain_workspace_config.1.borrow_mut() = ();
4416 }
4417
4418 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4419 self.as_local().map(|local| local.prettier_store.clone())
4420 }
4421
4422 fn on_buffer_event(
4423 &mut self,
4424 buffer: Entity<Buffer>,
4425 event: &language::BufferEvent,
4426 cx: &mut Context<Self>,
4427 ) {
4428 match event {
4429 language::BufferEvent::Edited { .. } => {
4430 self.on_buffer_edited(buffer, cx);
4431 }
4432
4433 language::BufferEvent::Saved => {
4434 self.on_buffer_saved(buffer, cx);
4435 }
4436
4437 _ => {}
4438 }
4439 }
4440
4441 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4442 buffer
4443 .read(cx)
4444 .set_language_registry(self.languages.clone());
4445
4446 cx.subscribe(buffer, |this, buffer, event, cx| {
4447 this.on_buffer_event(buffer, event, cx);
4448 })
4449 .detach();
4450
4451 self.detect_language_for_buffer(buffer, cx);
4452 if let Some(local) = self.as_local_mut() {
4453 local.initialize_buffer(buffer, cx);
4454 }
4455
4456 Ok(())
4457 }
4458
4459 pub fn refresh_background_diagnostics_for_buffers(
4460 &mut self,
4461 buffers: HashSet<BufferId>,
4462 cx: &mut Context<Self>,
4463 ) -> Shared<Task<()>> {
4464 let Some(local) = self.as_local_mut() else {
4465 return Task::ready(()).shared();
4466 };
4467 for buffer in buffers {
4468 if local.buffers_to_refresh_hash_set.insert(buffer) {
4469 local.buffers_to_refresh_queue.push_back(buffer);
4470 if local.buffers_to_refresh_queue.len() == 1 {
4471 local._background_diagnostics_worker =
4472 Self::background_diagnostics_worker(cx).shared();
4473 }
4474 }
4475 }
4476
4477 local._background_diagnostics_worker.clone()
4478 }
4479
4480 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4481 let buffer_store = self.buffer_store.clone();
4482 let local = self.as_local_mut()?;
4483 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4484 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4485 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4486 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4487 }
4488 }
4489 None
4490 }
4491
4492 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4493 cx.spawn(async move |this, cx| {
4494 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4495 task.await.log_err();
4496 }
4497 })
4498 }
4499
4500 pub(crate) fn register_buffer_with_language_servers(
4501 &mut self,
4502 buffer: &Entity<Buffer>,
4503 only_register_servers: HashSet<LanguageServerSelector>,
4504 ignore_refcounts: bool,
4505 cx: &mut Context<Self>,
4506 ) -> OpenLspBufferHandle {
4507 let buffer_id = buffer.read(cx).remote_id();
4508 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4509 if let Some(local) = self.as_local_mut() {
4510 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4511 if !ignore_refcounts {
4512 *refcount += 1;
4513 }
4514
4515 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4516 // 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
4517 // 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
4518 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4519 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4520 return handle;
4521 };
4522 if !file.is_local() {
4523 return handle;
4524 }
4525
4526 if ignore_refcounts || *refcount == 1 {
4527 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4528 }
4529 if !ignore_refcounts {
4530 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4531 let refcount = {
4532 let local = lsp_store.as_local_mut().unwrap();
4533 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4534 debug_panic!("bad refcounting");
4535 return;
4536 };
4537
4538 *refcount -= 1;
4539 *refcount
4540 };
4541 if refcount == 0 {
4542 lsp_store.lsp_data.remove(&buffer_id);
4543 let local = lsp_store.as_local_mut().unwrap();
4544 local.registered_buffers.remove(&buffer_id);
4545
4546 local.buffers_opened_in_servers.remove(&buffer_id);
4547 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4548 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4549
4550 let buffer_abs_path = file.abs_path(cx);
4551 for (_, buffer_pull_diagnostics_result_ids) in
4552 &mut local.buffer_pull_diagnostics_result_ids
4553 {
4554 buffer_pull_diagnostics_result_ids.retain(
4555 |_, buffer_result_ids| {
4556 buffer_result_ids.remove(&buffer_abs_path);
4557 !buffer_result_ids.is_empty()
4558 },
4559 );
4560 }
4561
4562 let diagnostic_updates = local
4563 .language_servers
4564 .keys()
4565 .cloned()
4566 .map(|server_id| DocumentDiagnosticsUpdate {
4567 diagnostics: DocumentDiagnostics {
4568 document_abs_path: buffer_abs_path.clone(),
4569 version: None,
4570 diagnostics: Vec::new(),
4571 },
4572 result_id: None,
4573 registration_id: None,
4574 server_id,
4575 disk_based_sources: Cow::Borrowed(&[]),
4576 })
4577 .collect::<Vec<_>>();
4578
4579 lsp_store
4580 .merge_diagnostic_entries(
4581 diagnostic_updates,
4582 |_, diagnostic, _| {
4583 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4584 },
4585 cx,
4586 )
4587 .context("Clearing diagnostics for the closed buffer")
4588 .log_err();
4589 }
4590 }
4591 })
4592 .detach();
4593 }
4594 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4595 let buffer_id = buffer.read(cx).remote_id().to_proto();
4596 cx.background_spawn(async move {
4597 upstream_client
4598 .request(proto::RegisterBufferWithLanguageServers {
4599 project_id: upstream_project_id,
4600 buffer_id,
4601 only_servers: only_register_servers
4602 .into_iter()
4603 .map(|selector| {
4604 let selector = match selector {
4605 LanguageServerSelector::Id(language_server_id) => {
4606 proto::language_server_selector::Selector::ServerId(
4607 language_server_id.to_proto(),
4608 )
4609 }
4610 LanguageServerSelector::Name(language_server_name) => {
4611 proto::language_server_selector::Selector::Name(
4612 language_server_name.to_string(),
4613 )
4614 }
4615 };
4616 proto::LanguageServerSelector {
4617 selector: Some(selector),
4618 }
4619 })
4620 .collect(),
4621 })
4622 .await
4623 })
4624 .detach();
4625 } else {
4626 // Our remote connection got closed
4627 }
4628 handle
4629 }
4630
4631 fn maintain_buffer_languages(
4632 languages: Arc<LanguageRegistry>,
4633 cx: &mut Context<Self>,
4634 ) -> Task<()> {
4635 let mut subscription = languages.subscribe();
4636 let mut prev_reload_count = languages.reload_count();
4637 cx.spawn(async move |this, cx| {
4638 while let Some(()) = subscription.next().await {
4639 if let Some(this) = this.upgrade() {
4640 // If the language registry has been reloaded, then remove and
4641 // re-assign the languages on all open buffers.
4642 let reload_count = languages.reload_count();
4643 if reload_count > prev_reload_count {
4644 prev_reload_count = reload_count;
4645 this.update(cx, |this, cx| {
4646 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4647 for buffer in buffer_store.buffers() {
4648 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4649 {
4650 buffer.update(cx, |buffer, cx| {
4651 buffer.set_language_async(None, cx)
4652 });
4653 if let Some(local) = this.as_local_mut() {
4654 local.reset_buffer(&buffer, &f, cx);
4655
4656 if local
4657 .registered_buffers
4658 .contains_key(&buffer.read(cx).remote_id())
4659 && let Some(file_url) =
4660 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4661 {
4662 local.unregister_buffer_from_language_servers(
4663 &buffer, &file_url, cx,
4664 );
4665 }
4666 }
4667 }
4668 }
4669 });
4670 });
4671 }
4672
4673 this.update(cx, |this, cx| {
4674 let mut plain_text_buffers = Vec::new();
4675 let mut buffers_with_unknown_injections = Vec::new();
4676 for handle in this.buffer_store.read(cx).buffers() {
4677 let buffer = handle.read(cx);
4678 if buffer.language().is_none()
4679 || buffer.language() == Some(&*language::PLAIN_TEXT)
4680 {
4681 plain_text_buffers.push(handle);
4682 } else if buffer.contains_unknown_injections() {
4683 buffers_with_unknown_injections.push(handle);
4684 }
4685 }
4686
4687 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4688 // and reused later in the invisible worktrees.
4689 plain_text_buffers.sort_by_key(|buffer| {
4690 Reverse(
4691 File::from_dyn(buffer.read(cx).file())
4692 .map(|file| file.worktree.read(cx).is_visible()),
4693 )
4694 });
4695
4696 for buffer in plain_text_buffers {
4697 this.detect_language_for_buffer(&buffer, cx);
4698 if let Some(local) = this.as_local_mut() {
4699 local.initialize_buffer(&buffer, cx);
4700 if local
4701 .registered_buffers
4702 .contains_key(&buffer.read(cx).remote_id())
4703 {
4704 local.register_buffer_with_language_servers(
4705 &buffer,
4706 HashSet::default(),
4707 cx,
4708 );
4709 }
4710 }
4711 }
4712
4713 for buffer in buffers_with_unknown_injections {
4714 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4715 }
4716 });
4717 }
4718 }
4719 })
4720 }
4721
4722 fn detect_language_for_buffer(
4723 &mut self,
4724 buffer_handle: &Entity<Buffer>,
4725 cx: &mut Context<Self>,
4726 ) -> Option<language::AvailableLanguage> {
4727 // If the buffer has a language, set it and start the language server if we haven't already.
4728 let buffer = buffer_handle.read(cx);
4729 let file = buffer.file()?;
4730
4731 let content = buffer.as_rope();
4732 let available_language = self.languages.language_for_file(file, Some(content), cx);
4733 if let Some(available_language) = &available_language {
4734 if let Some(Ok(Ok(new_language))) = self
4735 .languages
4736 .load_language(available_language)
4737 .now_or_never()
4738 {
4739 self.set_language_for_buffer(buffer_handle, new_language, cx);
4740 }
4741 } else {
4742 cx.emit(LspStoreEvent::LanguageDetected {
4743 buffer: buffer_handle.clone(),
4744 new_language: None,
4745 });
4746 }
4747
4748 available_language
4749 }
4750
4751 pub(crate) fn set_language_for_buffer(
4752 &mut self,
4753 buffer_entity: &Entity<Buffer>,
4754 new_language: Arc<Language>,
4755 cx: &mut Context<Self>,
4756 ) {
4757 let buffer = buffer_entity.read(cx);
4758 let buffer_file = buffer.file().cloned();
4759 let buffer_id = buffer.remote_id();
4760 if let Some(local_store) = self.as_local_mut()
4761 && local_store.registered_buffers.contains_key(&buffer_id)
4762 && let Some(abs_path) =
4763 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4764 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4765 {
4766 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4767 }
4768 buffer_entity.update(cx, |buffer, cx| {
4769 if buffer
4770 .language()
4771 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4772 {
4773 buffer.set_language_async(Some(new_language.clone()), cx);
4774 }
4775 });
4776
4777 let settings =
4778 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4779 let buffer_file = File::from_dyn(buffer_file.as_ref());
4780
4781 let worktree_id = if let Some(file) = buffer_file {
4782 let worktree = file.worktree.clone();
4783
4784 if let Some(local) = self.as_local_mut()
4785 && local.registered_buffers.contains_key(&buffer_id)
4786 {
4787 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4788 }
4789 Some(worktree.read(cx).id())
4790 } else {
4791 None
4792 };
4793
4794 if settings.prettier.allowed
4795 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4796 {
4797 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4798 if let Some(prettier_store) = prettier_store {
4799 prettier_store.update(cx, |prettier_store, cx| {
4800 prettier_store.install_default_prettier(
4801 worktree_id,
4802 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4803 cx,
4804 )
4805 })
4806 }
4807 }
4808
4809 cx.emit(LspStoreEvent::LanguageDetected {
4810 buffer: buffer_entity.clone(),
4811 new_language: Some(new_language),
4812 })
4813 }
4814
4815 pub fn buffer_store(&self) -> Entity<BufferStore> {
4816 self.buffer_store.clone()
4817 }
4818
4819 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4820 self.active_entry = active_entry;
4821 }
4822
4823 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4824 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4825 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4826 {
4827 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4828 summaries
4829 .iter()
4830 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4831 });
4832 if let Some(summary) = summaries.next() {
4833 client
4834 .send(proto::UpdateDiagnosticSummary {
4835 project_id: downstream_project_id,
4836 worktree_id: worktree.id().to_proto(),
4837 summary: Some(summary),
4838 more_summaries: summaries.collect(),
4839 })
4840 .log_err();
4841 }
4842 }
4843 }
4844
4845 fn is_capable_for_proto_request<R>(
4846 &self,
4847 buffer: &Entity<Buffer>,
4848 request: &R,
4849 cx: &App,
4850 ) -> bool
4851 where
4852 R: LspCommand,
4853 {
4854 self.check_if_capable_for_proto_request(
4855 buffer,
4856 |capabilities| {
4857 request.check_capabilities(AdapterServerCapabilities {
4858 server_capabilities: capabilities.clone(),
4859 code_action_kinds: None,
4860 })
4861 },
4862 cx,
4863 )
4864 }
4865
4866 fn check_if_capable_for_proto_request<F>(
4867 &self,
4868 buffer: &Entity<Buffer>,
4869 check: F,
4870 cx: &App,
4871 ) -> bool
4872 where
4873 F: FnMut(&lsp::ServerCapabilities) -> bool,
4874 {
4875 let Some(language) = buffer.read(cx).language().cloned() else {
4876 return false;
4877 };
4878 let registered_language_servers = self
4879 .languages
4880 .lsp_adapters(&language.name())
4881 .into_iter()
4882 .map(|lsp_adapter| lsp_adapter.name())
4883 .collect::<HashSet<_>>();
4884 self.language_server_statuses
4885 .iter()
4886 .filter_map(|(server_id, server_status)| {
4887 // Include servers that are either registered for this language OR
4888 // available to be loaded (for SSH remote mode where adapters like
4889 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4890 // but only loaded on the server side)
4891 let is_relevant = registered_language_servers.contains(&server_status.name)
4892 || self.languages.is_lsp_adapter_available(&server_status.name);
4893 is_relevant.then_some(server_id)
4894 })
4895 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4896 .any(check)
4897 }
4898
4899 fn all_capable_for_proto_request<F>(
4900 &self,
4901 buffer: &Entity<Buffer>,
4902 mut check: F,
4903 cx: &App,
4904 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4905 where
4906 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4907 {
4908 let Some(language) = buffer.read(cx).language().cloned() else {
4909 return Vec::default();
4910 };
4911 let registered_language_servers = self
4912 .languages
4913 .lsp_adapters(&language.name())
4914 .into_iter()
4915 .map(|lsp_adapter| lsp_adapter.name())
4916 .collect::<HashSet<_>>();
4917 self.language_server_statuses
4918 .iter()
4919 .filter_map(|(server_id, server_status)| {
4920 // Include servers that are either registered for this language OR
4921 // available to be loaded (for SSH remote mode where adapters like
4922 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4923 // but only loaded on the server side)
4924 let is_relevant = registered_language_servers.contains(&server_status.name)
4925 || self.languages.is_lsp_adapter_available(&server_status.name);
4926 is_relevant.then_some((server_id, &server_status.name))
4927 })
4928 .filter_map(|(server_id, server_name)| {
4929 self.lsp_server_capabilities
4930 .get(server_id)
4931 .map(|c| (server_id, server_name, c))
4932 })
4933 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4934 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
4935 .collect()
4936 }
4937
4938 pub fn request_lsp<R>(
4939 &mut self,
4940 buffer: Entity<Buffer>,
4941 server: LanguageServerToQuery,
4942 request: R,
4943 cx: &mut Context<Self>,
4944 ) -> Task<Result<R::Response>>
4945 where
4946 R: LspCommand,
4947 <R::LspRequest as lsp::request::Request>::Result: Send,
4948 <R::LspRequest as lsp::request::Request>::Params: Send,
4949 {
4950 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4951 return self.send_lsp_proto_request(
4952 buffer,
4953 upstream_client,
4954 upstream_project_id,
4955 request,
4956 cx,
4957 );
4958 }
4959
4960 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4961 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4962 local
4963 .language_servers_for_buffer(buffer, cx)
4964 .find(|(_, server)| {
4965 request.check_capabilities(server.adapter_server_capabilities())
4966 })
4967 .map(|(_, server)| server.clone())
4968 }),
4969 LanguageServerToQuery::Other(id) => self
4970 .language_server_for_local_buffer(buffer, id, cx)
4971 .and_then(|(_, server)| {
4972 request
4973 .check_capabilities(server.adapter_server_capabilities())
4974 .then(|| Arc::clone(server))
4975 }),
4976 }) else {
4977 return Task::ready(Ok(Default::default()));
4978 };
4979
4980 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4981
4982 let Some(file) = file else {
4983 return Task::ready(Ok(Default::default()));
4984 };
4985
4986 let lsp_params = match request.to_lsp_params_or_response(
4987 &file.abs_path(cx),
4988 buffer.read(cx),
4989 &language_server,
4990 cx,
4991 ) {
4992 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4993 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4994 Err(err) => {
4995 let message = format!(
4996 "{} via {} failed: {}",
4997 request.display_name(),
4998 language_server.name(),
4999 err
5000 );
5001 // rust-analyzer likes to error with this when its still loading up
5002 if !message.ends_with("content modified") {
5003 log::warn!("{message}");
5004 }
5005 return Task::ready(Err(anyhow!(message)));
5006 }
5007 };
5008
5009 let status = request.status();
5010 let request_timeout = ProjectSettings::get_global(cx)
5011 .global_lsp_settings
5012 .get_request_timeout();
5013
5014 cx.spawn(async move |this, cx| {
5015 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5016
5017 let id = lsp_request.id();
5018 let _cleanup = if status.is_some() {
5019 cx.update(|cx| {
5020 this.update(cx, |this, cx| {
5021 this.on_lsp_work_start(
5022 language_server.server_id(),
5023 ProgressToken::Number(id),
5024 LanguageServerProgress {
5025 is_disk_based_diagnostics_progress: false,
5026 is_cancellable: false,
5027 title: None,
5028 message: status.clone(),
5029 percentage: None,
5030 last_update_at: cx.background_executor().now(),
5031 },
5032 cx,
5033 );
5034 })
5035 })
5036 .log_err();
5037
5038 Some(defer(|| {
5039 cx.update(|cx| {
5040 this.update(cx, |this, cx| {
5041 this.on_lsp_work_end(
5042 language_server.server_id(),
5043 ProgressToken::Number(id),
5044 cx,
5045 );
5046 })
5047 })
5048 .log_err();
5049 }))
5050 } else {
5051 None
5052 };
5053
5054 let result = lsp_request.await.into_response();
5055
5056 let response = result.map_err(|err| {
5057 let message = format!(
5058 "{} via {} failed: {}",
5059 request.display_name(),
5060 language_server.name(),
5061 err
5062 );
5063 // rust-analyzer likes to error with this when its still loading up
5064 if !message.ends_with("content modified") {
5065 log::warn!("{message}");
5066 }
5067 anyhow::anyhow!(message)
5068 })?;
5069
5070 request
5071 .response_from_lsp(
5072 response,
5073 this.upgrade().context("no app context")?,
5074 buffer,
5075 language_server.server_id(),
5076 cx.clone(),
5077 )
5078 .await
5079 })
5080 }
5081
5082 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5083 let mut language_formatters_to_check = Vec::new();
5084 for buffer in self.buffer_store.read(cx).buffers() {
5085 let buffer = buffer.read(cx);
5086 let buffer_file = File::from_dyn(buffer.file());
5087 let buffer_language = buffer.language();
5088 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5089 if buffer_language.is_some() {
5090 language_formatters_to_check.push((
5091 buffer_file.map(|f| f.worktree_id(cx)),
5092 settings.into_owned(),
5093 ));
5094 }
5095 }
5096
5097 self.request_workspace_config_refresh();
5098
5099 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5100 prettier_store.update(cx, |prettier_store, cx| {
5101 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5102 })
5103 }
5104
5105 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5106 .global_lsp_settings
5107 .semantic_token_rules
5108 .clone();
5109 self.semantic_token_config
5110 .update_rules(new_semantic_token_rules);
5111 // Always clear cached stylizers so that changes to language-specific
5112 // semantic token rules (e.g. from extension install/uninstall) are
5113 // picked up. Stylizers are recreated lazily, so this is cheap.
5114 self.semantic_token_config.clear_stylizers();
5115
5116 let new_global_semantic_tokens_mode =
5117 all_language_settings(None, cx).defaults.semantic_tokens;
5118 if self
5119 .semantic_token_config
5120 .update_global_mode(new_global_semantic_tokens_mode)
5121 {
5122 self.restart_all_language_servers(cx);
5123 }
5124
5125 cx.notify();
5126 }
5127
5128 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5129 let buffer_store = self.buffer_store.clone();
5130 let Some(local) = self.as_local_mut() else {
5131 return;
5132 };
5133 let mut adapters = BTreeMap::default();
5134 let get_adapter = {
5135 let languages = local.languages.clone();
5136 let environment = local.environment.clone();
5137 let weak = local.weak.clone();
5138 let worktree_store = local.worktree_store.clone();
5139 let http_client = local.http_client.clone();
5140 let fs = local.fs.clone();
5141 move |worktree_id, cx: &mut App| {
5142 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5143 Some(LocalLspAdapterDelegate::new(
5144 languages.clone(),
5145 &environment,
5146 weak.clone(),
5147 &worktree,
5148 http_client.clone(),
5149 fs.clone(),
5150 cx,
5151 ))
5152 }
5153 };
5154
5155 let mut messages_to_report = Vec::new();
5156 let (new_tree, to_stop) = {
5157 let mut rebase = local.lsp_tree.rebase();
5158 let buffers = buffer_store
5159 .read(cx)
5160 .buffers()
5161 .filter_map(|buffer| {
5162 let raw_buffer = buffer.read(cx);
5163 if !local
5164 .registered_buffers
5165 .contains_key(&raw_buffer.remote_id())
5166 {
5167 return None;
5168 }
5169 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5170 let language = raw_buffer.language().cloned()?;
5171 Some((file, language, raw_buffer.remote_id()))
5172 })
5173 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5174 for (file, language, buffer_id) in buffers {
5175 let worktree_id = file.worktree_id(cx);
5176 let Some(worktree) = local
5177 .worktree_store
5178 .read(cx)
5179 .worktree_for_id(worktree_id, cx)
5180 else {
5181 continue;
5182 };
5183
5184 if let Some((_, apply)) = local.reuse_existing_language_server(
5185 rebase.server_tree(),
5186 &worktree,
5187 &language.name(),
5188 cx,
5189 ) {
5190 (apply)(rebase.server_tree());
5191 } else if let Some(lsp_delegate) = adapters
5192 .entry(worktree_id)
5193 .or_insert_with(|| get_adapter(worktree_id, cx))
5194 .clone()
5195 {
5196 let delegate =
5197 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5198 let path = file
5199 .path()
5200 .parent()
5201 .map(Arc::from)
5202 .unwrap_or_else(|| file.path().clone());
5203 let worktree_path = ProjectPath { worktree_id, path };
5204 let abs_path = file.abs_path(cx);
5205 let nodes = rebase
5206 .walk(
5207 worktree_path,
5208 language.name(),
5209 language.manifest(),
5210 delegate.clone(),
5211 cx,
5212 )
5213 .collect::<Vec<_>>();
5214 for node in nodes {
5215 let server_id = node.server_id_or_init(|disposition| {
5216 let path = &disposition.path;
5217 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5218 let key = LanguageServerSeed {
5219 worktree_id,
5220 name: disposition.server_name.clone(),
5221 settings: LanguageServerSeedSettings {
5222 binary: disposition.settings.binary.clone(),
5223 initialization_options: disposition
5224 .settings
5225 .initialization_options
5226 .clone(),
5227 },
5228 toolchain: local.toolchain_store.read(cx).active_toolchain(
5229 path.worktree_id,
5230 &path.path,
5231 language.name(),
5232 ),
5233 };
5234 local.language_server_ids.remove(&key);
5235
5236 let server_id = local.get_or_insert_language_server(
5237 &worktree,
5238 lsp_delegate.clone(),
5239 disposition,
5240 &language.name(),
5241 cx,
5242 );
5243 if let Some(state) = local.language_servers.get(&server_id)
5244 && let Ok(uri) = uri
5245 {
5246 state.add_workspace_folder(uri);
5247 };
5248 server_id
5249 });
5250
5251 if let Some(language_server_id) = server_id {
5252 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5253 language_server_id,
5254 name: node.name(),
5255 message:
5256 proto::update_language_server::Variant::RegisteredForBuffer(
5257 proto::RegisteredForBuffer {
5258 buffer_abs_path: abs_path
5259 .to_string_lossy()
5260 .into_owned(),
5261 buffer_id: buffer_id.to_proto(),
5262 },
5263 ),
5264 });
5265 }
5266 }
5267 } else {
5268 continue;
5269 }
5270 }
5271 rebase.finish()
5272 };
5273 for message in messages_to_report {
5274 cx.emit(message);
5275 }
5276 local.lsp_tree = new_tree;
5277 for (id, _) in to_stop {
5278 self.stop_local_language_server(id, cx).detach();
5279 }
5280 }
5281
5282 pub fn apply_code_action(
5283 &self,
5284 buffer_handle: Entity<Buffer>,
5285 mut action: CodeAction,
5286 push_to_history: bool,
5287 cx: &mut Context<Self>,
5288 ) -> Task<Result<ProjectTransaction>> {
5289 if let Some((upstream_client, project_id)) = self.upstream_client() {
5290 let request = proto::ApplyCodeAction {
5291 project_id,
5292 buffer_id: buffer_handle.read(cx).remote_id().into(),
5293 action: Some(Self::serialize_code_action(&action)),
5294 };
5295 let buffer_store = self.buffer_store();
5296 cx.spawn(async move |_, cx| {
5297 let response = upstream_client
5298 .request(request)
5299 .await?
5300 .transaction
5301 .context("missing transaction")?;
5302
5303 buffer_store
5304 .update(cx, |buffer_store, cx| {
5305 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5306 })
5307 .await
5308 })
5309 } else if self.mode.is_local() {
5310 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5311 let request_timeout = ProjectSettings::get_global(cx)
5312 .global_lsp_settings
5313 .get_request_timeout();
5314 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5315 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5316 }) else {
5317 return Task::ready(Ok(ProjectTransaction::default()));
5318 };
5319
5320 cx.spawn(async move |this, cx| {
5321 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5322 .await
5323 .context("resolving a code action")?;
5324 if let Some(edit) = action.lsp_action.edit()
5325 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5326 return LocalLspStore::deserialize_workspace_edit(
5327 this.upgrade().context("no app present")?,
5328 edit.clone(),
5329 push_to_history,
5330
5331 lang_server.clone(),
5332 cx,
5333 )
5334 .await;
5335 }
5336
5337 let Some(command) = action.lsp_action.command() else {
5338 return Ok(ProjectTransaction::default())
5339 };
5340
5341 let server_capabilities = lang_server.capabilities();
5342 let available_commands = server_capabilities
5343 .execute_command_provider
5344 .as_ref()
5345 .map(|options| options.commands.as_slice())
5346 .unwrap_or_default();
5347
5348 if !available_commands.contains(&command.command) {
5349 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5350 return Ok(ProjectTransaction::default())
5351 }
5352
5353 let request_timeout = cx.update(|app|
5354 ProjectSettings::get_global(app)
5355 .global_lsp_settings
5356 .get_request_timeout()
5357 );
5358
5359 this.update(cx, |this, _| {
5360 this.as_local_mut()
5361 .unwrap()
5362 .last_workspace_edits_by_language_server
5363 .remove(&lang_server.server_id());
5364 })?;
5365
5366 let _result = lang_server
5367 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5368 command: command.command.clone(),
5369 arguments: command.arguments.clone().unwrap_or_default(),
5370 ..lsp::ExecuteCommandParams::default()
5371 }, request_timeout)
5372 .await.into_response()
5373 .context("execute command")?;
5374
5375 return this.update(cx, |this, _| {
5376 this.as_local_mut()
5377 .unwrap()
5378 .last_workspace_edits_by_language_server
5379 .remove(&lang_server.server_id())
5380 .unwrap_or_default()
5381 });
5382 })
5383 } else {
5384 Task::ready(Err(anyhow!("no upstream client and not local")))
5385 }
5386 }
5387
5388 pub fn apply_code_action_kind(
5389 &mut self,
5390 buffers: HashSet<Entity<Buffer>>,
5391 kind: CodeActionKind,
5392 push_to_history: bool,
5393 cx: &mut Context<Self>,
5394 ) -> Task<anyhow::Result<ProjectTransaction>> {
5395 if self.as_local().is_some() {
5396 cx.spawn(async move |lsp_store, cx| {
5397 let buffers = buffers.into_iter().collect::<Vec<_>>();
5398 let result = LocalLspStore::execute_code_action_kind_locally(
5399 lsp_store.clone(),
5400 buffers,
5401 kind,
5402 push_to_history,
5403 cx,
5404 )
5405 .await;
5406 lsp_store.update(cx, |lsp_store, _| {
5407 lsp_store.update_last_formatting_failure(&result);
5408 })?;
5409 result
5410 })
5411 } else if let Some((client, project_id)) = self.upstream_client() {
5412 let buffer_store = self.buffer_store();
5413 cx.spawn(async move |lsp_store, cx| {
5414 let result = client
5415 .request(proto::ApplyCodeActionKind {
5416 project_id,
5417 kind: kind.as_str().to_owned(),
5418 buffer_ids: buffers
5419 .iter()
5420 .map(|buffer| {
5421 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5422 })
5423 .collect(),
5424 })
5425 .await
5426 .and_then(|result| result.transaction.context("missing transaction"));
5427 lsp_store.update(cx, |lsp_store, _| {
5428 lsp_store.update_last_formatting_failure(&result);
5429 })?;
5430
5431 let transaction_response = result?;
5432 buffer_store
5433 .update(cx, |buffer_store, cx| {
5434 buffer_store.deserialize_project_transaction(
5435 transaction_response,
5436 push_to_history,
5437 cx,
5438 )
5439 })
5440 .await
5441 })
5442 } else {
5443 Task::ready(Ok(ProjectTransaction::default()))
5444 }
5445 }
5446
5447 pub fn resolved_hint(
5448 &mut self,
5449 buffer_id: BufferId,
5450 id: InlayId,
5451 cx: &mut Context<Self>,
5452 ) -> Option<ResolvedHint> {
5453 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5454
5455 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5456 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5457 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5458 let (server_id, resolve_data) = match &hint.resolve_state {
5459 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5460 ResolveState::Resolving => {
5461 return Some(ResolvedHint::Resolving(
5462 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5463 ));
5464 }
5465 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5466 };
5467
5468 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5469 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5470 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5471 id,
5472 cx.spawn(async move |lsp_store, cx| {
5473 let resolved_hint = resolve_task.await;
5474 lsp_store
5475 .update(cx, |lsp_store, _| {
5476 if let Some(old_inlay_hint) = lsp_store
5477 .lsp_data
5478 .get_mut(&buffer_id)
5479 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5480 {
5481 match resolved_hint {
5482 Ok(resolved_hint) => {
5483 *old_inlay_hint = resolved_hint;
5484 }
5485 Err(e) => {
5486 old_inlay_hint.resolve_state =
5487 ResolveState::CanResolve(server_id, resolve_data);
5488 log::error!("Inlay hint resolve failed: {e:#}");
5489 }
5490 }
5491 }
5492 })
5493 .ok();
5494 })
5495 .shared(),
5496 );
5497 debug_assert!(
5498 previous_task.is_none(),
5499 "Did not change hint's resolve state after spawning its resolve"
5500 );
5501 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5502 None
5503 }
5504
5505 pub(crate) fn linked_edits(
5506 &mut self,
5507 buffer: &Entity<Buffer>,
5508 position: Anchor,
5509 cx: &mut Context<Self>,
5510 ) -> Task<Result<Vec<Range<Anchor>>>> {
5511 let snapshot = buffer.read(cx).snapshot();
5512 let scope = snapshot.language_scope_at(position);
5513 let Some(server_id) = self
5514 .as_local()
5515 .and_then(|local| {
5516 buffer.update(cx, |buffer, cx| {
5517 local
5518 .language_servers_for_buffer(buffer, cx)
5519 .filter(|(_, server)| {
5520 LinkedEditingRange::check_server_capabilities(server.capabilities())
5521 })
5522 .filter(|(adapter, _)| {
5523 scope
5524 .as_ref()
5525 .map(|scope| scope.language_allowed(&adapter.name))
5526 .unwrap_or(true)
5527 })
5528 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5529 .next()
5530 })
5531 })
5532 .or_else(|| {
5533 self.upstream_client()
5534 .is_some()
5535 .then_some(LanguageServerToQuery::FirstCapable)
5536 })
5537 .filter(|_| {
5538 maybe!({
5539 let language = buffer.read(cx).language_at(position)?;
5540 Some(
5541 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5542 .linked_edits,
5543 )
5544 }) == Some(true)
5545 })
5546 else {
5547 return Task::ready(Ok(Vec::new()));
5548 };
5549
5550 self.request_lsp(
5551 buffer.clone(),
5552 server_id,
5553 LinkedEditingRange { position },
5554 cx,
5555 )
5556 }
5557
5558 fn apply_on_type_formatting(
5559 &mut self,
5560 buffer: Entity<Buffer>,
5561 position: Anchor,
5562 trigger: String,
5563 cx: &mut Context<Self>,
5564 ) -> Task<Result<Option<Transaction>>> {
5565 if let Some((client, project_id)) = self.upstream_client() {
5566 if !self.check_if_capable_for_proto_request(
5567 &buffer,
5568 |capabilities| {
5569 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5570 },
5571 cx,
5572 ) {
5573 return Task::ready(Ok(None));
5574 }
5575 let request = proto::OnTypeFormatting {
5576 project_id,
5577 buffer_id: buffer.read(cx).remote_id().into(),
5578 position: Some(serialize_anchor(&position)),
5579 trigger,
5580 version: serialize_version(&buffer.read(cx).version()),
5581 };
5582 cx.background_spawn(async move {
5583 client
5584 .request(request)
5585 .await?
5586 .transaction
5587 .map(language::proto::deserialize_transaction)
5588 .transpose()
5589 })
5590 } else if let Some(local) = self.as_local_mut() {
5591 let buffer_id = buffer.read(cx).remote_id();
5592 local.buffers_being_formatted.insert(buffer_id);
5593 cx.spawn(async move |this, cx| {
5594 let _cleanup = defer({
5595 let this = this.clone();
5596 let mut cx = cx.clone();
5597 move || {
5598 this.update(&mut cx, |this, _| {
5599 if let Some(local) = this.as_local_mut() {
5600 local.buffers_being_formatted.remove(&buffer_id);
5601 }
5602 })
5603 .ok();
5604 }
5605 });
5606
5607 buffer
5608 .update(cx, |buffer, _| {
5609 buffer.wait_for_edits(Some(position.timestamp()))
5610 })
5611 .await?;
5612 this.update(cx, |this, cx| {
5613 let position = position.to_point_utf16(buffer.read(cx));
5614 this.on_type_format(buffer, position, trigger, false, cx)
5615 })?
5616 .await
5617 })
5618 } else {
5619 Task::ready(Err(anyhow!("No upstream client or local language server")))
5620 }
5621 }
5622
5623 pub fn on_type_format<T: ToPointUtf16>(
5624 &mut self,
5625 buffer: Entity<Buffer>,
5626 position: T,
5627 trigger: String,
5628 push_to_history: bool,
5629 cx: &mut Context<Self>,
5630 ) -> Task<Result<Option<Transaction>>> {
5631 let position = position.to_point_utf16(buffer.read(cx));
5632 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5633 }
5634
5635 fn on_type_format_impl(
5636 &mut self,
5637 buffer: Entity<Buffer>,
5638 position: PointUtf16,
5639 trigger: String,
5640 push_to_history: bool,
5641 cx: &mut Context<Self>,
5642 ) -> Task<Result<Option<Transaction>>> {
5643 let options = buffer.update(cx, |buffer, cx| {
5644 lsp_command::lsp_formatting_options(
5645 language_settings(
5646 buffer.language_at(position).map(|l| l.name()),
5647 buffer.file(),
5648 cx,
5649 )
5650 .as_ref(),
5651 )
5652 });
5653
5654 cx.spawn(async move |this, cx| {
5655 if let Some(waiter) =
5656 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5657 {
5658 waiter.await?;
5659 }
5660 cx.update(|cx| {
5661 this.update(cx, |this, cx| {
5662 this.request_lsp(
5663 buffer.clone(),
5664 LanguageServerToQuery::FirstCapable,
5665 OnTypeFormatting {
5666 position,
5667 trigger,
5668 options,
5669 push_to_history,
5670 },
5671 cx,
5672 )
5673 })
5674 })?
5675 .await
5676 })
5677 }
5678
5679 pub fn definitions(
5680 &mut self,
5681 buffer: &Entity<Buffer>,
5682 position: PointUtf16,
5683 cx: &mut Context<Self>,
5684 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5685 if let Some((upstream_client, project_id)) = self.upstream_client() {
5686 let request = GetDefinitions { position };
5687 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5688 return Task::ready(Ok(None));
5689 }
5690
5691 let request_timeout = ProjectSettings::get_global(cx)
5692 .global_lsp_settings
5693 .get_request_timeout();
5694
5695 let request_task = upstream_client.request_lsp(
5696 project_id,
5697 None,
5698 request_timeout,
5699 cx.background_executor().clone(),
5700 request.to_proto(project_id, buffer.read(cx)),
5701 );
5702 let buffer = buffer.clone();
5703 cx.spawn(async move |weak_lsp_store, cx| {
5704 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5705 return Ok(None);
5706 };
5707 let Some(responses) = request_task.await? else {
5708 return Ok(None);
5709 };
5710 let actions = join_all(responses.payload.into_iter().map(|response| {
5711 GetDefinitions { position }.response_from_proto(
5712 response.response,
5713 lsp_store.clone(),
5714 buffer.clone(),
5715 cx.clone(),
5716 )
5717 }))
5718 .await;
5719
5720 Ok(Some(
5721 actions
5722 .into_iter()
5723 .collect::<Result<Vec<Vec<_>>>>()?
5724 .into_iter()
5725 .flatten()
5726 .dedup()
5727 .collect(),
5728 ))
5729 })
5730 } else {
5731 let definitions_task = self.request_multiple_lsp_locally(
5732 buffer,
5733 Some(position),
5734 GetDefinitions { position },
5735 cx,
5736 );
5737 cx.background_spawn(async move {
5738 Ok(Some(
5739 definitions_task
5740 .await
5741 .into_iter()
5742 .flat_map(|(_, definitions)| definitions)
5743 .dedup()
5744 .collect(),
5745 ))
5746 })
5747 }
5748 }
5749
5750 pub fn declarations(
5751 &mut self,
5752 buffer: &Entity<Buffer>,
5753 position: PointUtf16,
5754 cx: &mut Context<Self>,
5755 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5756 if let Some((upstream_client, project_id)) = self.upstream_client() {
5757 let request = GetDeclarations { position };
5758 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5759 return Task::ready(Ok(None));
5760 }
5761 let request_timeout = ProjectSettings::get_global(cx)
5762 .global_lsp_settings
5763 .get_request_timeout();
5764 let request_task = upstream_client.request_lsp(
5765 project_id,
5766 None,
5767 request_timeout,
5768 cx.background_executor().clone(),
5769 request.to_proto(project_id, buffer.read(cx)),
5770 );
5771 let buffer = buffer.clone();
5772 cx.spawn(async move |weak_lsp_store, cx| {
5773 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5774 return Ok(None);
5775 };
5776 let Some(responses) = request_task.await? else {
5777 return Ok(None);
5778 };
5779 let actions = join_all(responses.payload.into_iter().map(|response| {
5780 GetDeclarations { position }.response_from_proto(
5781 response.response,
5782 lsp_store.clone(),
5783 buffer.clone(),
5784 cx.clone(),
5785 )
5786 }))
5787 .await;
5788
5789 Ok(Some(
5790 actions
5791 .into_iter()
5792 .collect::<Result<Vec<Vec<_>>>>()?
5793 .into_iter()
5794 .flatten()
5795 .dedup()
5796 .collect(),
5797 ))
5798 })
5799 } else {
5800 let declarations_task = self.request_multiple_lsp_locally(
5801 buffer,
5802 Some(position),
5803 GetDeclarations { position },
5804 cx,
5805 );
5806 cx.background_spawn(async move {
5807 Ok(Some(
5808 declarations_task
5809 .await
5810 .into_iter()
5811 .flat_map(|(_, declarations)| declarations)
5812 .dedup()
5813 .collect(),
5814 ))
5815 })
5816 }
5817 }
5818
5819 pub fn type_definitions(
5820 &mut self,
5821 buffer: &Entity<Buffer>,
5822 position: PointUtf16,
5823 cx: &mut Context<Self>,
5824 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5825 if let Some((upstream_client, project_id)) = self.upstream_client() {
5826 let request = GetTypeDefinitions { position };
5827 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5828 return Task::ready(Ok(None));
5829 }
5830 let request_timeout = ProjectSettings::get_global(cx)
5831 .global_lsp_settings
5832 .get_request_timeout();
5833 let request_task = upstream_client.request_lsp(
5834 project_id,
5835 None,
5836 request_timeout,
5837 cx.background_executor().clone(),
5838 request.to_proto(project_id, buffer.read(cx)),
5839 );
5840 let buffer = buffer.clone();
5841 cx.spawn(async move |weak_lsp_store, cx| {
5842 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5843 return Ok(None);
5844 };
5845 let Some(responses) = request_task.await? else {
5846 return Ok(None);
5847 };
5848 let actions = join_all(responses.payload.into_iter().map(|response| {
5849 GetTypeDefinitions { position }.response_from_proto(
5850 response.response,
5851 lsp_store.clone(),
5852 buffer.clone(),
5853 cx.clone(),
5854 )
5855 }))
5856 .await;
5857
5858 Ok(Some(
5859 actions
5860 .into_iter()
5861 .collect::<Result<Vec<Vec<_>>>>()?
5862 .into_iter()
5863 .flatten()
5864 .dedup()
5865 .collect(),
5866 ))
5867 })
5868 } else {
5869 let type_definitions_task = self.request_multiple_lsp_locally(
5870 buffer,
5871 Some(position),
5872 GetTypeDefinitions { position },
5873 cx,
5874 );
5875 cx.background_spawn(async move {
5876 Ok(Some(
5877 type_definitions_task
5878 .await
5879 .into_iter()
5880 .flat_map(|(_, type_definitions)| type_definitions)
5881 .dedup()
5882 .collect(),
5883 ))
5884 })
5885 }
5886 }
5887
5888 pub fn implementations(
5889 &mut self,
5890 buffer: &Entity<Buffer>,
5891 position: PointUtf16,
5892 cx: &mut Context<Self>,
5893 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5894 if let Some((upstream_client, project_id)) = self.upstream_client() {
5895 let request = GetImplementations { position };
5896 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5897 return Task::ready(Ok(None));
5898 }
5899
5900 let request_timeout = ProjectSettings::get_global(cx)
5901 .global_lsp_settings
5902 .get_request_timeout();
5903 let request_task = upstream_client.request_lsp(
5904 project_id,
5905 None,
5906 request_timeout,
5907 cx.background_executor().clone(),
5908 request.to_proto(project_id, buffer.read(cx)),
5909 );
5910 let buffer = buffer.clone();
5911 cx.spawn(async move |weak_lsp_store, cx| {
5912 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5913 return Ok(None);
5914 };
5915 let Some(responses) = request_task.await? else {
5916 return Ok(None);
5917 };
5918 let actions = join_all(responses.payload.into_iter().map(|response| {
5919 GetImplementations { position }.response_from_proto(
5920 response.response,
5921 lsp_store.clone(),
5922 buffer.clone(),
5923 cx.clone(),
5924 )
5925 }))
5926 .await;
5927
5928 Ok(Some(
5929 actions
5930 .into_iter()
5931 .collect::<Result<Vec<Vec<_>>>>()?
5932 .into_iter()
5933 .flatten()
5934 .dedup()
5935 .collect(),
5936 ))
5937 })
5938 } else {
5939 let implementations_task = self.request_multiple_lsp_locally(
5940 buffer,
5941 Some(position),
5942 GetImplementations { position },
5943 cx,
5944 );
5945 cx.background_spawn(async move {
5946 Ok(Some(
5947 implementations_task
5948 .await
5949 .into_iter()
5950 .flat_map(|(_, implementations)| implementations)
5951 .dedup()
5952 .collect(),
5953 ))
5954 })
5955 }
5956 }
5957
5958 pub fn references(
5959 &mut self,
5960 buffer: &Entity<Buffer>,
5961 position: PointUtf16,
5962 cx: &mut Context<Self>,
5963 ) -> Task<Result<Option<Vec<Location>>>> {
5964 if let Some((upstream_client, project_id)) = self.upstream_client() {
5965 let request = GetReferences { position };
5966 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5967 return Task::ready(Ok(None));
5968 }
5969
5970 let request_timeout = ProjectSettings::get_global(cx)
5971 .global_lsp_settings
5972 .get_request_timeout();
5973 let request_task = upstream_client.request_lsp(
5974 project_id,
5975 None,
5976 request_timeout,
5977 cx.background_executor().clone(),
5978 request.to_proto(project_id, buffer.read(cx)),
5979 );
5980 let buffer = buffer.clone();
5981 cx.spawn(async move |weak_lsp_store, cx| {
5982 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5983 return Ok(None);
5984 };
5985 let Some(responses) = request_task.await? else {
5986 return Ok(None);
5987 };
5988
5989 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5990 GetReferences { position }.response_from_proto(
5991 lsp_response.response,
5992 lsp_store.clone(),
5993 buffer.clone(),
5994 cx.clone(),
5995 )
5996 }))
5997 .await
5998 .into_iter()
5999 .collect::<Result<Vec<Vec<_>>>>()?
6000 .into_iter()
6001 .flatten()
6002 .dedup()
6003 .collect();
6004 Ok(Some(locations))
6005 })
6006 } else {
6007 let references_task = self.request_multiple_lsp_locally(
6008 buffer,
6009 Some(position),
6010 GetReferences { position },
6011 cx,
6012 );
6013 cx.background_spawn(async move {
6014 Ok(Some(
6015 references_task
6016 .await
6017 .into_iter()
6018 .flat_map(|(_, references)| references)
6019 .dedup()
6020 .collect(),
6021 ))
6022 })
6023 }
6024 }
6025
6026 pub fn code_actions(
6027 &mut self,
6028 buffer: &Entity<Buffer>,
6029 range: Range<Anchor>,
6030 kinds: Option<Vec<CodeActionKind>>,
6031 cx: &mut Context<Self>,
6032 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6033 if let Some((upstream_client, project_id)) = self.upstream_client() {
6034 let request = GetCodeActions {
6035 range: range.clone(),
6036 kinds: kinds.clone(),
6037 };
6038 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6039 return Task::ready(Ok(None));
6040 }
6041 let request_timeout = ProjectSettings::get_global(cx)
6042 .global_lsp_settings
6043 .get_request_timeout();
6044 let request_task = upstream_client.request_lsp(
6045 project_id,
6046 None,
6047 request_timeout,
6048 cx.background_executor().clone(),
6049 request.to_proto(project_id, buffer.read(cx)),
6050 );
6051 let buffer = buffer.clone();
6052 cx.spawn(async move |weak_lsp_store, cx| {
6053 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6054 return Ok(None);
6055 };
6056 let Some(responses) = request_task.await? else {
6057 return Ok(None);
6058 };
6059 let actions = join_all(responses.payload.into_iter().map(|response| {
6060 GetCodeActions {
6061 range: range.clone(),
6062 kinds: kinds.clone(),
6063 }
6064 .response_from_proto(
6065 response.response,
6066 lsp_store.clone(),
6067 buffer.clone(),
6068 cx.clone(),
6069 )
6070 }))
6071 .await;
6072
6073 Ok(Some(
6074 actions
6075 .into_iter()
6076 .collect::<Result<Vec<Vec<_>>>>()?
6077 .into_iter()
6078 .flatten()
6079 .collect(),
6080 ))
6081 })
6082 } else {
6083 let all_actions_task = self.request_multiple_lsp_locally(
6084 buffer,
6085 Some(range.start),
6086 GetCodeActions { range, kinds },
6087 cx,
6088 );
6089 cx.background_spawn(async move {
6090 Ok(Some(
6091 all_actions_task
6092 .await
6093 .into_iter()
6094 .flat_map(|(_, actions)| actions)
6095 .collect(),
6096 ))
6097 })
6098 }
6099 }
6100
6101 #[inline(never)]
6102 pub fn completions(
6103 &self,
6104 buffer: &Entity<Buffer>,
6105 position: PointUtf16,
6106 context: CompletionContext,
6107 cx: &mut Context<Self>,
6108 ) -> Task<Result<Vec<CompletionResponse>>> {
6109 let language_registry = self.languages.clone();
6110
6111 if let Some((upstream_client, project_id)) = self.upstream_client() {
6112 let snapshot = buffer.read(cx).snapshot();
6113 let offset = position.to_offset(&snapshot);
6114 let scope = snapshot.language_scope_at(offset);
6115 let capable_lsps = self.all_capable_for_proto_request(
6116 buffer,
6117 |server_name, capabilities| {
6118 capabilities.completion_provider.is_some()
6119 && scope
6120 .as_ref()
6121 .map(|scope| scope.language_allowed(server_name))
6122 .unwrap_or(true)
6123 },
6124 cx,
6125 );
6126 if capable_lsps.is_empty() {
6127 return Task::ready(Ok(Vec::new()));
6128 }
6129
6130 let language = buffer.read(cx).language().cloned();
6131
6132 let buffer = buffer.clone();
6133
6134 cx.spawn(async move |this, cx| {
6135 let requests = join_all(
6136 capable_lsps
6137 .into_iter()
6138 .map(|(id, server_name)| {
6139 let request = GetCompletions {
6140 position,
6141 context: context.clone(),
6142 server_id: Some(id),
6143 };
6144 let buffer = buffer.clone();
6145 let language = language.clone();
6146 let lsp_adapter = language.as_ref().and_then(|language| {
6147 let adapters = language_registry.lsp_adapters(&language.name());
6148 adapters
6149 .iter()
6150 .find(|adapter| adapter.name() == server_name)
6151 .or_else(|| adapters.first())
6152 .cloned()
6153 });
6154 let upstream_client = upstream_client.clone();
6155 let response = this
6156 .update(cx, |this, cx| {
6157 this.send_lsp_proto_request(
6158 buffer,
6159 upstream_client,
6160 project_id,
6161 request,
6162 cx,
6163 )
6164 })
6165 .log_err();
6166 async move {
6167 let response = response?.await.log_err()?;
6168
6169 let completions = populate_labels_for_completions(
6170 response.completions,
6171 language,
6172 lsp_adapter,
6173 )
6174 .await;
6175
6176 Some(CompletionResponse {
6177 completions,
6178 display_options: CompletionDisplayOptions::default(),
6179 is_incomplete: response.is_incomplete,
6180 })
6181 }
6182 })
6183 .collect::<Vec<_>>(),
6184 );
6185 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6186 })
6187 } else if let Some(local) = self.as_local() {
6188 let snapshot = buffer.read(cx).snapshot();
6189 let offset = position.to_offset(&snapshot);
6190 let scope = snapshot.language_scope_at(offset);
6191 let language = snapshot.language().cloned();
6192 let completion_settings = language_settings(
6193 language.as_ref().map(|language| language.name()),
6194 buffer.read(cx).file(),
6195 cx,
6196 )
6197 .completions
6198 .clone();
6199 if !completion_settings.lsp {
6200 return Task::ready(Ok(Vec::new()));
6201 }
6202
6203 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6204 local
6205 .language_servers_for_buffer(buffer, cx)
6206 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6207 .filter(|(adapter, _)| {
6208 scope
6209 .as_ref()
6210 .map(|scope| scope.language_allowed(&adapter.name))
6211 .unwrap_or(true)
6212 })
6213 .map(|(_, server)| server.server_id())
6214 .collect()
6215 });
6216
6217 let buffer = buffer.clone();
6218 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6219 let lsp_timeout = if lsp_timeout > 0 {
6220 Some(Duration::from_millis(lsp_timeout))
6221 } else {
6222 None
6223 };
6224 cx.spawn(async move |this, cx| {
6225 let mut tasks = Vec::with_capacity(server_ids.len());
6226 this.update(cx, |lsp_store, cx| {
6227 for server_id in server_ids {
6228 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6229 let lsp_timeout = lsp_timeout
6230 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6231 let mut timeout = cx.background_spawn(async move {
6232 match lsp_timeout {
6233 Some(lsp_timeout) => {
6234 lsp_timeout.await;
6235 true
6236 },
6237 None => false,
6238 }
6239 }).fuse();
6240 let mut lsp_request = lsp_store.request_lsp(
6241 buffer.clone(),
6242 LanguageServerToQuery::Other(server_id),
6243 GetCompletions {
6244 position,
6245 context: context.clone(),
6246 server_id: Some(server_id),
6247 },
6248 cx,
6249 ).fuse();
6250 let new_task = cx.background_spawn(async move {
6251 select_biased! {
6252 response = lsp_request => anyhow::Ok(Some(response?)),
6253 timeout_happened = timeout => {
6254 if timeout_happened {
6255 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6256 Ok(None)
6257 } else {
6258 let completions = lsp_request.await?;
6259 Ok(Some(completions))
6260 }
6261 },
6262 }
6263 });
6264 tasks.push((lsp_adapter, new_task));
6265 }
6266 })?;
6267
6268 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6269 let completion_response = task.await.ok()??;
6270 let completions = populate_labels_for_completions(
6271 completion_response.completions,
6272 language.clone(),
6273 lsp_adapter,
6274 )
6275 .await;
6276 Some(CompletionResponse {
6277 completions,
6278 display_options: CompletionDisplayOptions::default(),
6279 is_incomplete: completion_response.is_incomplete,
6280 })
6281 });
6282
6283 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6284
6285 Ok(responses.into_iter().flatten().collect())
6286 })
6287 } else {
6288 Task::ready(Err(anyhow!("No upstream client or local language server")))
6289 }
6290 }
6291
6292 pub fn resolve_completions(
6293 &self,
6294 buffer: Entity<Buffer>,
6295 completion_indices: Vec<usize>,
6296 completions: Rc<RefCell<Box<[Completion]>>>,
6297 cx: &mut Context<Self>,
6298 ) -> Task<Result<bool>> {
6299 let client = self.upstream_client();
6300 let buffer_id = buffer.read(cx).remote_id();
6301 let buffer_snapshot = buffer.read(cx).snapshot();
6302
6303 if !self.check_if_capable_for_proto_request(
6304 &buffer,
6305 GetCompletions::can_resolve_completions,
6306 cx,
6307 ) {
6308 return Task::ready(Ok(false));
6309 }
6310 cx.spawn(async move |lsp_store, cx| {
6311 let request_timeout = cx.update(|app| {
6312 ProjectSettings::get_global(app)
6313 .global_lsp_settings
6314 .get_request_timeout()
6315 });
6316
6317 let mut did_resolve = false;
6318 if let Some((client, project_id)) = client {
6319 for completion_index in completion_indices {
6320 let server_id = {
6321 let completion = &completions.borrow()[completion_index];
6322 completion.source.server_id()
6323 };
6324 if let Some(server_id) = server_id {
6325 if Self::resolve_completion_remote(
6326 project_id,
6327 server_id,
6328 buffer_id,
6329 completions.clone(),
6330 completion_index,
6331 client.clone(),
6332 )
6333 .await
6334 .log_err()
6335 .is_some()
6336 {
6337 did_resolve = true;
6338 }
6339 } else {
6340 resolve_word_completion(
6341 &buffer_snapshot,
6342 &mut completions.borrow_mut()[completion_index],
6343 );
6344 }
6345 }
6346 } else {
6347 for completion_index in completion_indices {
6348 let server_id = {
6349 let completion = &completions.borrow()[completion_index];
6350 completion.source.server_id()
6351 };
6352 if let Some(server_id) = server_id {
6353 let server_and_adapter = lsp_store
6354 .read_with(cx, |lsp_store, _| {
6355 let server = lsp_store.language_server_for_id(server_id)?;
6356 let adapter =
6357 lsp_store.language_server_adapter_for_id(server.server_id())?;
6358 Some((server, adapter))
6359 })
6360 .ok()
6361 .flatten();
6362 let Some((server, adapter)) = server_and_adapter else {
6363 continue;
6364 };
6365
6366 let resolved = Self::resolve_completion_local(
6367 server,
6368 completions.clone(),
6369 completion_index,
6370 request_timeout,
6371 )
6372 .await
6373 .log_err()
6374 .is_some();
6375 if resolved {
6376 Self::regenerate_completion_labels(
6377 adapter,
6378 &buffer_snapshot,
6379 completions.clone(),
6380 completion_index,
6381 )
6382 .await
6383 .log_err();
6384 did_resolve = true;
6385 }
6386 } else {
6387 resolve_word_completion(
6388 &buffer_snapshot,
6389 &mut completions.borrow_mut()[completion_index],
6390 );
6391 }
6392 }
6393 }
6394
6395 Ok(did_resolve)
6396 })
6397 }
6398
6399 async fn resolve_completion_local(
6400 server: Arc<lsp::LanguageServer>,
6401 completions: Rc<RefCell<Box<[Completion]>>>,
6402 completion_index: usize,
6403 request_timeout: Duration,
6404 ) -> Result<()> {
6405 let server_id = server.server_id();
6406 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6407 return Ok(());
6408 }
6409
6410 let request = {
6411 let completion = &completions.borrow()[completion_index];
6412 match &completion.source {
6413 CompletionSource::Lsp {
6414 lsp_completion,
6415 resolved,
6416 server_id: completion_server_id,
6417 ..
6418 } => {
6419 if *resolved {
6420 return Ok(());
6421 }
6422 anyhow::ensure!(
6423 server_id == *completion_server_id,
6424 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6425 );
6426 server.request::<lsp::request::ResolveCompletionItem>(
6427 *lsp_completion.clone(),
6428 request_timeout,
6429 )
6430 }
6431 CompletionSource::BufferWord { .. }
6432 | CompletionSource::Dap { .. }
6433 | CompletionSource::Custom => {
6434 return Ok(());
6435 }
6436 }
6437 };
6438 let resolved_completion = request
6439 .await
6440 .into_response()
6441 .context("resolve completion")?;
6442
6443 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6444 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6445
6446 let mut completions = completions.borrow_mut();
6447 let completion = &mut completions[completion_index];
6448 if let CompletionSource::Lsp {
6449 lsp_completion,
6450 resolved,
6451 server_id: completion_server_id,
6452 ..
6453 } = &mut completion.source
6454 {
6455 if *resolved {
6456 return Ok(());
6457 }
6458 anyhow::ensure!(
6459 server_id == *completion_server_id,
6460 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6461 );
6462 **lsp_completion = resolved_completion;
6463 *resolved = true;
6464 }
6465 Ok(())
6466 }
6467
6468 async fn regenerate_completion_labels(
6469 adapter: Arc<CachedLspAdapter>,
6470 snapshot: &BufferSnapshot,
6471 completions: Rc<RefCell<Box<[Completion]>>>,
6472 completion_index: usize,
6473 ) -> Result<()> {
6474 let completion_item = completions.borrow()[completion_index]
6475 .source
6476 .lsp_completion(true)
6477 .map(Cow::into_owned);
6478 if let Some(lsp_documentation) = completion_item
6479 .as_ref()
6480 .and_then(|completion_item| completion_item.documentation.clone())
6481 {
6482 let mut completions = completions.borrow_mut();
6483 let completion = &mut completions[completion_index];
6484 completion.documentation = Some(lsp_documentation.into());
6485 } else {
6486 let mut completions = completions.borrow_mut();
6487 let completion = &mut completions[completion_index];
6488 completion.documentation = Some(CompletionDocumentation::Undocumented);
6489 }
6490
6491 let mut new_label = match completion_item {
6492 Some(completion_item) => {
6493 // Some language servers always return `detail` lazily via resolve, regardless of
6494 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6495 // See: https://github.com/yioneko/vtsls/issues/213
6496 let language = snapshot.language();
6497 match language {
6498 Some(language) => {
6499 adapter
6500 .labels_for_completions(
6501 std::slice::from_ref(&completion_item),
6502 language,
6503 )
6504 .await?
6505 }
6506 None => Vec::new(),
6507 }
6508 .pop()
6509 .flatten()
6510 .unwrap_or_else(|| {
6511 CodeLabel::fallback_for_completion(
6512 &completion_item,
6513 language.map(|language| language.as_ref()),
6514 )
6515 })
6516 }
6517 None => CodeLabel::plain(
6518 completions.borrow()[completion_index].new_text.clone(),
6519 None,
6520 ),
6521 };
6522 ensure_uniform_list_compatible_label(&mut new_label);
6523
6524 let mut completions = completions.borrow_mut();
6525 let completion = &mut completions[completion_index];
6526 if completion.label.filter_text() == new_label.filter_text() {
6527 completion.label = new_label;
6528 } else {
6529 log::error!(
6530 "Resolved completion changed display label from {} to {}. \
6531 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6532 completion.label.text(),
6533 new_label.text(),
6534 completion.label.filter_text(),
6535 new_label.filter_text()
6536 );
6537 }
6538
6539 Ok(())
6540 }
6541
6542 async fn resolve_completion_remote(
6543 project_id: u64,
6544 server_id: LanguageServerId,
6545 buffer_id: BufferId,
6546 completions: Rc<RefCell<Box<[Completion]>>>,
6547 completion_index: usize,
6548 client: AnyProtoClient,
6549 ) -> Result<()> {
6550 let lsp_completion = {
6551 let completion = &completions.borrow()[completion_index];
6552 match &completion.source {
6553 CompletionSource::Lsp {
6554 lsp_completion,
6555 resolved,
6556 server_id: completion_server_id,
6557 ..
6558 } => {
6559 anyhow::ensure!(
6560 server_id == *completion_server_id,
6561 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6562 );
6563 if *resolved {
6564 return Ok(());
6565 }
6566 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6567 }
6568 CompletionSource::Custom
6569 | CompletionSource::Dap { .. }
6570 | CompletionSource::BufferWord { .. } => {
6571 return Ok(());
6572 }
6573 }
6574 };
6575 let request = proto::ResolveCompletionDocumentation {
6576 project_id,
6577 language_server_id: server_id.0 as u64,
6578 lsp_completion,
6579 buffer_id: buffer_id.into(),
6580 };
6581
6582 let response = client
6583 .request(request)
6584 .await
6585 .context("completion documentation resolve proto request")?;
6586 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6587
6588 let documentation = if response.documentation.is_empty() {
6589 CompletionDocumentation::Undocumented
6590 } else if response.documentation_is_markdown {
6591 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6592 } else if response.documentation.lines().count() <= 1 {
6593 CompletionDocumentation::SingleLine(response.documentation.into())
6594 } else {
6595 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6596 };
6597
6598 let mut completions = completions.borrow_mut();
6599 let completion = &mut completions[completion_index];
6600 completion.documentation = Some(documentation);
6601 if let CompletionSource::Lsp {
6602 insert_range,
6603 lsp_completion,
6604 resolved,
6605 server_id: completion_server_id,
6606 lsp_defaults: _,
6607 } = &mut completion.source
6608 {
6609 let completion_insert_range = response
6610 .old_insert_start
6611 .and_then(deserialize_anchor)
6612 .zip(response.old_insert_end.and_then(deserialize_anchor));
6613 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6614
6615 if *resolved {
6616 return Ok(());
6617 }
6618 anyhow::ensure!(
6619 server_id == *completion_server_id,
6620 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6621 );
6622 **lsp_completion = resolved_lsp_completion;
6623 *resolved = true;
6624 }
6625
6626 let replace_range = response
6627 .old_replace_start
6628 .and_then(deserialize_anchor)
6629 .zip(response.old_replace_end.and_then(deserialize_anchor));
6630 if let Some((old_replace_start, old_replace_end)) = replace_range
6631 && !response.new_text.is_empty()
6632 {
6633 completion.new_text = response.new_text;
6634 completion.replace_range = old_replace_start..old_replace_end;
6635 }
6636
6637 Ok(())
6638 }
6639
6640 pub fn apply_additional_edits_for_completion(
6641 &self,
6642 buffer_handle: Entity<Buffer>,
6643 completions: Rc<RefCell<Box<[Completion]>>>,
6644 completion_index: usize,
6645 push_to_history: bool,
6646 all_commit_ranges: Vec<Range<language::Anchor>>,
6647 cx: &mut Context<Self>,
6648 ) -> Task<Result<Option<Transaction>>> {
6649 if let Some((client, project_id)) = self.upstream_client() {
6650 let buffer = buffer_handle.read(cx);
6651 let buffer_id = buffer.remote_id();
6652 cx.spawn(async move |_, cx| {
6653 let request = {
6654 let completion = completions.borrow()[completion_index].clone();
6655 proto::ApplyCompletionAdditionalEdits {
6656 project_id,
6657 buffer_id: buffer_id.into(),
6658 completion: Some(Self::serialize_completion(&CoreCompletion {
6659 replace_range: completion.replace_range,
6660 new_text: completion.new_text,
6661 source: completion.source,
6662 })),
6663 all_commit_ranges: all_commit_ranges
6664 .iter()
6665 .cloned()
6666 .map(language::proto::serialize_anchor_range)
6667 .collect(),
6668 }
6669 };
6670
6671 let Some(transaction) = client.request(request).await?.transaction else {
6672 return Ok(None);
6673 };
6674
6675 let transaction = language::proto::deserialize_transaction(transaction)?;
6676 buffer_handle
6677 .update(cx, |buffer, _| {
6678 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6679 })
6680 .await?;
6681 if push_to_history {
6682 buffer_handle.update(cx, |buffer, _| {
6683 buffer.push_transaction(transaction.clone(), Instant::now());
6684 buffer.finalize_last_transaction();
6685 });
6686 }
6687 Ok(Some(transaction))
6688 })
6689 } else {
6690 let request_timeout = ProjectSettings::get_global(cx)
6691 .global_lsp_settings
6692 .get_request_timeout();
6693
6694 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6695 let completion = &completions.borrow()[completion_index];
6696 let server_id = completion.source.server_id()?;
6697 Some(
6698 self.language_server_for_local_buffer(buffer, server_id, cx)?
6699 .1
6700 .clone(),
6701 )
6702 }) else {
6703 return Task::ready(Ok(None));
6704 };
6705
6706 cx.spawn(async move |this, cx| {
6707 Self::resolve_completion_local(
6708 server.clone(),
6709 completions.clone(),
6710 completion_index,
6711 request_timeout,
6712 )
6713 .await
6714 .context("resolving completion")?;
6715 let completion = completions.borrow()[completion_index].clone();
6716 let additional_text_edits = completion
6717 .source
6718 .lsp_completion(true)
6719 .as_ref()
6720 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6721 if let Some(edits) = additional_text_edits {
6722 let edits = this
6723 .update(cx, |this, cx| {
6724 this.as_local_mut().unwrap().edits_from_lsp(
6725 &buffer_handle,
6726 edits,
6727 server.server_id(),
6728 None,
6729 cx,
6730 )
6731 })?
6732 .await?;
6733
6734 buffer_handle.update(cx, |buffer, cx| {
6735 buffer.finalize_last_transaction();
6736 buffer.start_transaction();
6737
6738 for (range, text) in edits {
6739 let primary = &completion.replace_range;
6740
6741 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6742 // and the primary completion is just an insertion (empty range), then this is likely
6743 // an auto-import scenario and should not be considered overlapping
6744 // https://github.com/zed-industries/zed/issues/26136
6745 let is_file_start_auto_import = {
6746 let snapshot = buffer.snapshot();
6747 let primary_start_point = primary.start.to_point(&snapshot);
6748 let range_start_point = range.start.to_point(&snapshot);
6749
6750 let result = primary_start_point.row == 0
6751 && primary_start_point.column == 0
6752 && range_start_point.row == 0
6753 && range_start_point.column == 0;
6754
6755 result
6756 };
6757
6758 let has_overlap = if is_file_start_auto_import {
6759 false
6760 } else {
6761 all_commit_ranges.iter().any(|commit_range| {
6762 let start_within =
6763 commit_range.start.cmp(&range.start, buffer).is_le()
6764 && commit_range.end.cmp(&range.start, buffer).is_ge();
6765 let end_within =
6766 range.start.cmp(&commit_range.end, buffer).is_le()
6767 && range.end.cmp(&commit_range.end, buffer).is_ge();
6768 start_within || end_within
6769 })
6770 };
6771
6772 //Skip additional edits which overlap with the primary completion edit
6773 //https://github.com/zed-industries/zed/pull/1871
6774 if !has_overlap {
6775 buffer.edit([(range, text)], None, cx);
6776 }
6777 }
6778
6779 let transaction = if buffer.end_transaction(cx).is_some() {
6780 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6781 if !push_to_history {
6782 buffer.forget_transaction(transaction.id);
6783 }
6784 Some(transaction)
6785 } else {
6786 None
6787 };
6788 Ok(transaction)
6789 })
6790 } else {
6791 Ok(None)
6792 }
6793 })
6794 }
6795 }
6796
6797 pub fn pull_diagnostics(
6798 &mut self,
6799 buffer: Entity<Buffer>,
6800 cx: &mut Context<Self>,
6801 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6802 let buffer_id = buffer.read(cx).remote_id();
6803
6804 if let Some((client, upstream_project_id)) = self.upstream_client() {
6805 let mut suitable_capabilities = None;
6806 // Are we capable for proto request?
6807 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6808 &buffer,
6809 |capabilities| {
6810 if let Some(caps) = &capabilities.diagnostic_provider {
6811 suitable_capabilities = Some(caps.clone());
6812 true
6813 } else {
6814 false
6815 }
6816 },
6817 cx,
6818 );
6819 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6820 let Some(dynamic_caps) = suitable_capabilities else {
6821 return Task::ready(Ok(None));
6822 };
6823 assert!(any_server_has_diagnostics_provider);
6824
6825 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6826 let request = GetDocumentDiagnostics {
6827 previous_result_id: None,
6828 identifier,
6829 registration_id: None,
6830 };
6831 let request_timeout = ProjectSettings::get_global(cx)
6832 .global_lsp_settings
6833 .get_request_timeout();
6834 let request_task = client.request_lsp(
6835 upstream_project_id,
6836 None,
6837 request_timeout,
6838 cx.background_executor().clone(),
6839 request.to_proto(upstream_project_id, buffer.read(cx)),
6840 );
6841 cx.background_spawn(async move {
6842 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6843 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6844 // Do not attempt to further process the dummy responses here.
6845 let _response = request_task.await?;
6846 Ok(None)
6847 })
6848 } else {
6849 let servers = buffer.update(cx, |buffer, cx| {
6850 self.running_language_servers_for_local_buffer(buffer, cx)
6851 .map(|(_, server)| server.clone())
6852 .collect::<Vec<_>>()
6853 });
6854
6855 let pull_diagnostics = servers
6856 .into_iter()
6857 .flat_map(|server| {
6858 let result = maybe!({
6859 let local = self.as_local()?;
6860 let server_id = server.server_id();
6861 let providers_with_identifiers = local
6862 .language_server_dynamic_registrations
6863 .get(&server_id)
6864 .into_iter()
6865 .flat_map(|registrations| registrations.diagnostics.clone())
6866 .collect::<Vec<_>>();
6867 Some(
6868 providers_with_identifiers
6869 .into_iter()
6870 .map(|(registration_id, dynamic_caps)| {
6871 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6872 let registration_id = registration_id.map(SharedString::from);
6873 let result_id = self.result_id_for_buffer_pull(
6874 server_id,
6875 buffer_id,
6876 ®istration_id,
6877 cx,
6878 );
6879 self.request_lsp(
6880 buffer.clone(),
6881 LanguageServerToQuery::Other(server_id),
6882 GetDocumentDiagnostics {
6883 previous_result_id: result_id,
6884 registration_id,
6885 identifier,
6886 },
6887 cx,
6888 )
6889 })
6890 .collect::<Vec<_>>(),
6891 )
6892 });
6893
6894 result.unwrap_or_default()
6895 })
6896 .collect::<Vec<_>>();
6897
6898 cx.background_spawn(async move {
6899 let mut responses = Vec::new();
6900 for diagnostics in join_all(pull_diagnostics).await {
6901 responses.extend(diagnostics?);
6902 }
6903 Ok(Some(responses))
6904 })
6905 }
6906 }
6907
6908 pub fn applicable_inlay_chunks(
6909 &mut self,
6910 buffer: &Entity<Buffer>,
6911 ranges: &[Range<text::Anchor>],
6912 cx: &mut Context<Self>,
6913 ) -> Vec<Range<BufferRow>> {
6914 let buffer_snapshot = buffer.read(cx).snapshot();
6915 let ranges = ranges
6916 .iter()
6917 .map(|range| range.to_point(&buffer_snapshot))
6918 .collect::<Vec<_>>();
6919
6920 self.latest_lsp_data(buffer, cx)
6921 .inlay_hints
6922 .applicable_chunks(ranges.as_slice())
6923 .map(|chunk| chunk.row_range())
6924 .collect()
6925 }
6926
6927 pub fn invalidate_inlay_hints<'a>(
6928 &'a mut self,
6929 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6930 ) {
6931 for buffer_id in for_buffers {
6932 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6933 lsp_data.inlay_hints.clear();
6934 }
6935 }
6936 }
6937
6938 pub fn inlay_hints(
6939 &mut self,
6940 invalidate: InvalidationStrategy,
6941 buffer: Entity<Buffer>,
6942 ranges: Vec<Range<text::Anchor>>,
6943 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6944 cx: &mut Context<Self>,
6945 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6946 let next_hint_id = self.next_hint_id.clone();
6947 let lsp_data = self.latest_lsp_data(&buffer, cx);
6948 let query_version = lsp_data.buffer_version.clone();
6949 let mut lsp_refresh_requested = false;
6950 let for_server = if let InvalidationStrategy::RefreshRequested {
6951 server_id,
6952 request_id,
6953 } = invalidate
6954 {
6955 let invalidated = lsp_data
6956 .inlay_hints
6957 .invalidate_for_server_refresh(server_id, request_id);
6958 lsp_refresh_requested = invalidated;
6959 Some(server_id)
6960 } else {
6961 None
6962 };
6963 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6964 let known_chunks = known_chunks
6965 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6966 .map(|(_, known_chunks)| known_chunks)
6967 .unwrap_or_default();
6968
6969 let buffer_snapshot = buffer.read(cx).snapshot();
6970 let ranges = ranges
6971 .iter()
6972 .map(|range| range.to_point(&buffer_snapshot))
6973 .collect::<Vec<_>>();
6974
6975 let mut hint_fetch_tasks = Vec::new();
6976 let mut cached_inlay_hints = None;
6977 let mut ranges_to_query = None;
6978 let applicable_chunks = existing_inlay_hints
6979 .applicable_chunks(ranges.as_slice())
6980 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6981 .collect::<Vec<_>>();
6982 if applicable_chunks.is_empty() {
6983 return HashMap::default();
6984 }
6985
6986 for row_chunk in applicable_chunks {
6987 match (
6988 existing_inlay_hints
6989 .cached_hints(&row_chunk)
6990 .filter(|_| !lsp_refresh_requested)
6991 .cloned(),
6992 existing_inlay_hints
6993 .fetched_hints(&row_chunk)
6994 .as_ref()
6995 .filter(|_| !lsp_refresh_requested)
6996 .cloned(),
6997 ) {
6998 (None, None) => {
6999 let chunk_range = row_chunk.anchor_range();
7000 ranges_to_query
7001 .get_or_insert_with(Vec::new)
7002 .push((row_chunk, chunk_range));
7003 }
7004 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7005 (Some(cached_hints), None) => {
7006 for (server_id, cached_hints) in cached_hints {
7007 if for_server.is_none_or(|for_server| for_server == server_id) {
7008 cached_inlay_hints
7009 .get_or_insert_with(HashMap::default)
7010 .entry(row_chunk.row_range())
7011 .or_insert_with(HashMap::default)
7012 .entry(server_id)
7013 .or_insert_with(Vec::new)
7014 .extend(cached_hints);
7015 }
7016 }
7017 }
7018 (Some(cached_hints), Some(fetched_hints)) => {
7019 hint_fetch_tasks.push((row_chunk, fetched_hints));
7020 for (server_id, cached_hints) in cached_hints {
7021 if for_server.is_none_or(|for_server| for_server == server_id) {
7022 cached_inlay_hints
7023 .get_or_insert_with(HashMap::default)
7024 .entry(row_chunk.row_range())
7025 .or_insert_with(HashMap::default)
7026 .entry(server_id)
7027 .or_insert_with(Vec::new)
7028 .extend(cached_hints);
7029 }
7030 }
7031 }
7032 }
7033 }
7034
7035 if hint_fetch_tasks.is_empty()
7036 && ranges_to_query
7037 .as_ref()
7038 .is_none_or(|ranges| ranges.is_empty())
7039 && let Some(cached_inlay_hints) = cached_inlay_hints
7040 {
7041 cached_inlay_hints
7042 .into_iter()
7043 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7044 .collect()
7045 } else {
7046 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7047 // When a server refresh was requested, other servers' cached hints
7048 // are unaffected by the refresh and must be included in the result.
7049 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7050 // removes all visible hints but only adds back the requesting
7051 // server's new hints, permanently losing other servers' hints.
7052 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7053 lsp_data
7054 .inlay_hints
7055 .cached_hints(&chunk)
7056 .cloned()
7057 .unwrap_or_default()
7058 } else {
7059 HashMap::default()
7060 };
7061
7062 let next_hint_id = next_hint_id.clone();
7063 let buffer = buffer.clone();
7064 let query_version = query_version.clone();
7065 let new_inlay_hints = cx
7066 .spawn(async move |lsp_store, cx| {
7067 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7068 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7069 })?;
7070 new_fetch_task
7071 .await
7072 .and_then(|new_hints_by_server| {
7073 lsp_store.update(cx, |lsp_store, cx| {
7074 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7075 let update_cache = lsp_data.buffer_version == query_version;
7076 if new_hints_by_server.is_empty() {
7077 if update_cache {
7078 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7079 }
7080 other_servers_cached
7081 } else {
7082 let mut result = other_servers_cached;
7083 for (server_id, new_hints) in new_hints_by_server {
7084 let new_hints = new_hints
7085 .into_iter()
7086 .map(|new_hint| {
7087 (
7088 InlayId::Hint(next_hint_id.fetch_add(
7089 1,
7090 atomic::Ordering::AcqRel,
7091 )),
7092 new_hint,
7093 )
7094 })
7095 .collect::<Vec<_>>();
7096 if update_cache {
7097 lsp_data.inlay_hints.insert_new_hints(
7098 chunk,
7099 server_id,
7100 new_hints.clone(),
7101 );
7102 }
7103 result.insert(server_id, new_hints);
7104 }
7105 result
7106 }
7107 })
7108 })
7109 .map_err(Arc::new)
7110 })
7111 .shared();
7112
7113 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7114 *fetch_task = Some(new_inlay_hints.clone());
7115 hint_fetch_tasks.push((chunk, new_inlay_hints));
7116 }
7117
7118 cached_inlay_hints
7119 .unwrap_or_default()
7120 .into_iter()
7121 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7122 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7123 (
7124 chunk.row_range(),
7125 cx.spawn(async move |_, _| {
7126 hints_fetch.await.map_err(|e| {
7127 if e.error_code() != ErrorCode::Internal {
7128 anyhow!(e.error_code())
7129 } else {
7130 anyhow!("{e:#}")
7131 }
7132 })
7133 }),
7134 )
7135 }))
7136 .collect()
7137 }
7138 }
7139
7140 fn fetch_inlay_hints(
7141 &mut self,
7142 for_server: Option<LanguageServerId>,
7143 buffer: &Entity<Buffer>,
7144 range: Range<Anchor>,
7145 cx: &mut Context<Self>,
7146 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7147 let request = InlayHints {
7148 range: range.clone(),
7149 };
7150 if let Some((upstream_client, project_id)) = self.upstream_client() {
7151 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7152 return Task::ready(Ok(HashMap::default()));
7153 }
7154 let request_timeout = ProjectSettings::get_global(cx)
7155 .global_lsp_settings
7156 .get_request_timeout();
7157 let request_task = upstream_client.request_lsp(
7158 project_id,
7159 for_server.map(|id| id.to_proto()),
7160 request_timeout,
7161 cx.background_executor().clone(),
7162 request.to_proto(project_id, buffer.read(cx)),
7163 );
7164 let buffer = buffer.clone();
7165 cx.spawn(async move |weak_lsp_store, cx| {
7166 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7167 return Ok(HashMap::default());
7168 };
7169 let Some(responses) = request_task.await? else {
7170 return Ok(HashMap::default());
7171 };
7172
7173 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7174 let lsp_store = lsp_store.clone();
7175 let buffer = buffer.clone();
7176 let cx = cx.clone();
7177 let request = request.clone();
7178 async move {
7179 (
7180 LanguageServerId::from_proto(response.server_id),
7181 request
7182 .response_from_proto(response.response, lsp_store, buffer, cx)
7183 .await,
7184 )
7185 }
7186 }))
7187 .await;
7188
7189 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7190 let mut has_errors = false;
7191 let inlay_hints = inlay_hints
7192 .into_iter()
7193 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7194 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7195 Err(e) => {
7196 has_errors = true;
7197 log::error!("{e:#}");
7198 None
7199 }
7200 })
7201 .map(|(server_id, mut new_hints)| {
7202 new_hints.retain(|hint| {
7203 hint.position.is_valid(&buffer_snapshot)
7204 && range.start.is_valid(&buffer_snapshot)
7205 && range.end.is_valid(&buffer_snapshot)
7206 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7207 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7208 });
7209 (server_id, new_hints)
7210 })
7211 .collect::<HashMap<_, _>>();
7212 anyhow::ensure!(
7213 !has_errors || !inlay_hints.is_empty(),
7214 "Failed to fetch inlay hints"
7215 );
7216 Ok(inlay_hints)
7217 })
7218 } else {
7219 let inlay_hints_task = match for_server {
7220 Some(server_id) => {
7221 let server_task = self.request_lsp(
7222 buffer.clone(),
7223 LanguageServerToQuery::Other(server_id),
7224 request,
7225 cx,
7226 );
7227 cx.background_spawn(async move {
7228 let mut responses = Vec::new();
7229 match server_task.await {
7230 Ok(response) => responses.push((server_id, response)),
7231 // rust-analyzer likes to error with this when its still loading up
7232 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7233 Err(e) => log::error!(
7234 "Error handling response for inlay hints request: {e:#}"
7235 ),
7236 }
7237 responses
7238 })
7239 }
7240 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7241 };
7242 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7243 cx.background_spawn(async move {
7244 Ok(inlay_hints_task
7245 .await
7246 .into_iter()
7247 .map(|(server_id, mut new_hints)| {
7248 new_hints.retain(|hint| {
7249 hint.position.is_valid(&buffer_snapshot)
7250 && range.start.is_valid(&buffer_snapshot)
7251 && range.end.is_valid(&buffer_snapshot)
7252 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7253 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7254 });
7255 (server_id, new_hints)
7256 })
7257 .collect())
7258 })
7259 }
7260 }
7261
7262 fn diagnostic_registration_exists(
7263 &self,
7264 server_id: LanguageServerId,
7265 registration_id: &Option<SharedString>,
7266 ) -> bool {
7267 let Some(local) = self.as_local() else {
7268 return false;
7269 };
7270 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7271 else {
7272 return false;
7273 };
7274 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7275 registrations.diagnostics.contains_key(®istration_key)
7276 }
7277
7278 pub fn pull_diagnostics_for_buffer(
7279 &mut self,
7280 buffer: Entity<Buffer>,
7281 cx: &mut Context<Self>,
7282 ) -> Task<anyhow::Result<()>> {
7283 let diagnostics = self.pull_diagnostics(buffer, cx);
7284 cx.spawn(async move |lsp_store, cx| {
7285 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7286 return Ok(());
7287 };
7288 lsp_store.update(cx, |lsp_store, cx| {
7289 if lsp_store.as_local().is_none() {
7290 return;
7291 }
7292
7293 let mut unchanged_buffers = HashMap::default();
7294 let server_diagnostics_updates = diagnostics
7295 .into_iter()
7296 .filter_map(|diagnostics_set| match diagnostics_set {
7297 LspPullDiagnostics::Response {
7298 server_id,
7299 uri,
7300 diagnostics,
7301 registration_id,
7302 } => Some((server_id, uri, diagnostics, registration_id)),
7303 LspPullDiagnostics::Default => None,
7304 })
7305 .filter(|(server_id, _, _, registration_id)| {
7306 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7307 })
7308 .fold(
7309 HashMap::default(),
7310 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7311 let (result_id, diagnostics) = match diagnostics {
7312 PulledDiagnostics::Unchanged { result_id } => {
7313 unchanged_buffers
7314 .entry(new_registration_id.clone())
7315 .or_insert_with(HashSet::default)
7316 .insert(uri.clone());
7317 (Some(result_id), Vec::new())
7318 }
7319 PulledDiagnostics::Changed {
7320 result_id,
7321 diagnostics,
7322 } => (result_id, diagnostics),
7323 };
7324 let disk_based_sources = Cow::Owned(
7325 lsp_store
7326 .language_server_adapter_for_id(server_id)
7327 .as_ref()
7328 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7329 .unwrap_or(&[])
7330 .to_vec(),
7331 );
7332 acc.entry(server_id)
7333 .or_insert_with(HashMap::default)
7334 .entry(new_registration_id.clone())
7335 .or_insert_with(Vec::new)
7336 .push(DocumentDiagnosticsUpdate {
7337 server_id,
7338 diagnostics: lsp::PublishDiagnosticsParams {
7339 uri,
7340 diagnostics,
7341 version: None,
7342 },
7343 result_id: result_id.map(SharedString::new),
7344 disk_based_sources,
7345 registration_id: new_registration_id,
7346 });
7347 acc
7348 },
7349 );
7350
7351 for diagnostic_updates in server_diagnostics_updates.into_values() {
7352 for (registration_id, diagnostic_updates) in diagnostic_updates {
7353 lsp_store
7354 .merge_lsp_diagnostics(
7355 DiagnosticSourceKind::Pulled,
7356 diagnostic_updates,
7357 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7358 DiagnosticSourceKind::Pulled => {
7359 old_diagnostic.registration_id != registration_id
7360 || unchanged_buffers
7361 .get(&old_diagnostic.registration_id)
7362 .is_some_and(|unchanged_buffers| {
7363 unchanged_buffers.contains(&document_uri)
7364 })
7365 }
7366 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7367 true
7368 }
7369 },
7370 cx,
7371 )
7372 .log_err();
7373 }
7374 }
7375 })
7376 })
7377 }
7378
7379 pub fn signature_help<T: ToPointUtf16>(
7380 &mut self,
7381 buffer: &Entity<Buffer>,
7382 position: T,
7383 cx: &mut Context<Self>,
7384 ) -> Task<Option<Vec<SignatureHelp>>> {
7385 let position = position.to_point_utf16(buffer.read(cx));
7386
7387 if let Some((client, upstream_project_id)) = self.upstream_client() {
7388 let request = GetSignatureHelp { position };
7389 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7390 return Task::ready(None);
7391 }
7392 let request_timeout = ProjectSettings::get_global(cx)
7393 .global_lsp_settings
7394 .get_request_timeout();
7395 let request_task = client.request_lsp(
7396 upstream_project_id,
7397 None,
7398 request_timeout,
7399 cx.background_executor().clone(),
7400 request.to_proto(upstream_project_id, buffer.read(cx)),
7401 );
7402 let buffer = buffer.clone();
7403 cx.spawn(async move |weak_lsp_store, cx| {
7404 let lsp_store = weak_lsp_store.upgrade()?;
7405 let signatures = join_all(
7406 request_task
7407 .await
7408 .log_err()
7409 .flatten()
7410 .map(|response| response.payload)
7411 .unwrap_or_default()
7412 .into_iter()
7413 .map(|response| {
7414 let response = GetSignatureHelp { position }.response_from_proto(
7415 response.response,
7416 lsp_store.clone(),
7417 buffer.clone(),
7418 cx.clone(),
7419 );
7420 async move { response.await.log_err().flatten() }
7421 }),
7422 )
7423 .await
7424 .into_iter()
7425 .flatten()
7426 .collect();
7427 Some(signatures)
7428 })
7429 } else {
7430 let all_actions_task = self.request_multiple_lsp_locally(
7431 buffer,
7432 Some(position),
7433 GetSignatureHelp { position },
7434 cx,
7435 );
7436 cx.background_spawn(async move {
7437 Some(
7438 all_actions_task
7439 .await
7440 .into_iter()
7441 .flat_map(|(_, actions)| actions)
7442 .collect::<Vec<_>>(),
7443 )
7444 })
7445 }
7446 }
7447
7448 pub fn hover(
7449 &mut self,
7450 buffer: &Entity<Buffer>,
7451 position: PointUtf16,
7452 cx: &mut Context<Self>,
7453 ) -> Task<Option<Vec<Hover>>> {
7454 if let Some((client, upstream_project_id)) = self.upstream_client() {
7455 let request = GetHover { position };
7456 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7457 return Task::ready(None);
7458 }
7459 let request_timeout = ProjectSettings::get_global(cx)
7460 .global_lsp_settings
7461 .get_request_timeout();
7462 let request_task = client.request_lsp(
7463 upstream_project_id,
7464 None,
7465 request_timeout,
7466 cx.background_executor().clone(),
7467 request.to_proto(upstream_project_id, buffer.read(cx)),
7468 );
7469 let buffer = buffer.clone();
7470 cx.spawn(async move |weak_lsp_store, cx| {
7471 let lsp_store = weak_lsp_store.upgrade()?;
7472 let hovers = join_all(
7473 request_task
7474 .await
7475 .log_err()
7476 .flatten()
7477 .map(|response| response.payload)
7478 .unwrap_or_default()
7479 .into_iter()
7480 .map(|response| {
7481 let response = GetHover { position }.response_from_proto(
7482 response.response,
7483 lsp_store.clone(),
7484 buffer.clone(),
7485 cx.clone(),
7486 );
7487 async move {
7488 response
7489 .await
7490 .log_err()
7491 .flatten()
7492 .and_then(remove_empty_hover_blocks)
7493 }
7494 }),
7495 )
7496 .await
7497 .into_iter()
7498 .flatten()
7499 .collect();
7500 Some(hovers)
7501 })
7502 } else {
7503 let all_actions_task = self.request_multiple_lsp_locally(
7504 buffer,
7505 Some(position),
7506 GetHover { position },
7507 cx,
7508 );
7509 cx.background_spawn(async move {
7510 Some(
7511 all_actions_task
7512 .await
7513 .into_iter()
7514 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7515 .collect::<Vec<Hover>>(),
7516 )
7517 })
7518 }
7519 }
7520
7521 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7522 let language_registry = self.languages.clone();
7523
7524 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7525 let request = upstream_client.request(proto::GetProjectSymbols {
7526 project_id: *project_id,
7527 query: query.to_string(),
7528 });
7529 cx.foreground_executor().spawn(async move {
7530 let response = request.await?;
7531 let mut symbols = Vec::new();
7532 let core_symbols = response
7533 .symbols
7534 .into_iter()
7535 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7536 .collect::<Vec<_>>();
7537 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7538 .await;
7539 Ok(symbols)
7540 })
7541 } else if let Some(local) = self.as_local() {
7542 struct WorkspaceSymbolsResult {
7543 server_id: LanguageServerId,
7544 lsp_adapter: Arc<CachedLspAdapter>,
7545 worktree: WeakEntity<Worktree>,
7546 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7547 }
7548
7549 let mut requests = Vec::new();
7550 let mut requested_servers = BTreeSet::new();
7551 let request_timeout = ProjectSettings::get_global(cx)
7552 .global_lsp_settings
7553 .get_request_timeout();
7554
7555 for (seed, state) in local.language_server_ids.iter() {
7556 let Some(worktree_handle) = self
7557 .worktree_store
7558 .read(cx)
7559 .worktree_for_id(seed.worktree_id, cx)
7560 else {
7561 continue;
7562 };
7563
7564 let worktree = worktree_handle.read(cx);
7565 if !worktree.is_visible() {
7566 continue;
7567 }
7568
7569 if !requested_servers.insert(state.id) {
7570 continue;
7571 }
7572
7573 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7574 Some(LanguageServerState::Running {
7575 adapter, server, ..
7576 }) => (adapter.clone(), server),
7577
7578 _ => continue,
7579 };
7580
7581 let supports_workspace_symbol_request =
7582 match server.capabilities().workspace_symbol_provider {
7583 Some(OneOf::Left(supported)) => supported,
7584 Some(OneOf::Right(_)) => true,
7585 None => false,
7586 };
7587
7588 if !supports_workspace_symbol_request {
7589 continue;
7590 }
7591
7592 let worktree_handle = worktree_handle.clone();
7593 let server_id = server.server_id();
7594 requests.push(
7595 server
7596 .request::<lsp::request::WorkspaceSymbolRequest>(
7597 lsp::WorkspaceSymbolParams {
7598 query: query.to_string(),
7599 ..Default::default()
7600 },
7601 request_timeout,
7602 )
7603 .map(move |response| {
7604 let lsp_symbols = response
7605 .into_response()
7606 .context("workspace symbols request")
7607 .log_err()
7608 .flatten()
7609 .map(|symbol_response| match symbol_response {
7610 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7611 flat_responses
7612 .into_iter()
7613 .map(|lsp_symbol| {
7614 (
7615 lsp_symbol.name,
7616 lsp_symbol.kind,
7617 lsp_symbol.location,
7618 lsp_symbol.container_name,
7619 )
7620 })
7621 .collect::<Vec<_>>()
7622 }
7623 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7624 nested_responses
7625 .into_iter()
7626 .filter_map(|lsp_symbol| {
7627 let location = match lsp_symbol.location {
7628 OneOf::Left(location) => location,
7629 OneOf::Right(_) => {
7630 log::error!(
7631 "Unexpected: client capabilities \
7632 forbid symbol resolutions in \
7633 workspace.symbol.resolveSupport"
7634 );
7635 return None;
7636 }
7637 };
7638 Some((
7639 lsp_symbol.name,
7640 lsp_symbol.kind,
7641 location,
7642 lsp_symbol.container_name,
7643 ))
7644 })
7645 .collect::<Vec<_>>()
7646 }
7647 })
7648 .unwrap_or_default();
7649
7650 WorkspaceSymbolsResult {
7651 server_id,
7652 lsp_adapter,
7653 worktree: worktree_handle.downgrade(),
7654 lsp_symbols,
7655 }
7656 }),
7657 );
7658 }
7659
7660 cx.spawn(async move |this, cx| {
7661 let responses = futures::future::join_all(requests).await;
7662 let this = match this.upgrade() {
7663 Some(this) => this,
7664 None => return Ok(Vec::new()),
7665 };
7666
7667 let mut symbols = Vec::new();
7668 for result in responses {
7669 let core_symbols = this.update(cx, |this, cx| {
7670 result
7671 .lsp_symbols
7672 .into_iter()
7673 .filter_map(
7674 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7675 let abs_path = symbol_location.uri.to_file_path().ok()?;
7676 let source_worktree = result.worktree.upgrade()?;
7677 let source_worktree_id = source_worktree.read(cx).id();
7678
7679 let path = if let Some((tree, rel_path)) =
7680 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7681 {
7682 let worktree_id = tree.read(cx).id();
7683 SymbolLocation::InProject(ProjectPath {
7684 worktree_id,
7685 path: rel_path,
7686 })
7687 } else {
7688 SymbolLocation::OutsideProject {
7689 signature: this.symbol_signature(&abs_path),
7690 abs_path: abs_path.into(),
7691 }
7692 };
7693
7694 Some(CoreSymbol {
7695 source_language_server_id: result.server_id,
7696 language_server_name: result.lsp_adapter.name.clone(),
7697 source_worktree_id,
7698 path,
7699 kind: symbol_kind,
7700 name: collapse_newlines(&symbol_name, "↵ "),
7701 range: range_from_lsp(symbol_location.range),
7702 container_name: container_name
7703 .map(|c| collapse_newlines(&c, "↵ ")),
7704 })
7705 },
7706 )
7707 .collect::<Vec<_>>()
7708 });
7709
7710 populate_labels_for_symbols(
7711 core_symbols,
7712 &language_registry,
7713 Some(result.lsp_adapter),
7714 &mut symbols,
7715 )
7716 .await;
7717 }
7718
7719 Ok(symbols)
7720 })
7721 } else {
7722 Task::ready(Err(anyhow!("No upstream client or local language server")))
7723 }
7724 }
7725
7726 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7727 let mut summary = DiagnosticSummary::default();
7728 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7729 summary.error_count += path_summary.error_count;
7730 summary.warning_count += path_summary.warning_count;
7731 }
7732 summary
7733 }
7734
7735 /// Returns the diagnostic summary for a specific project path.
7736 pub fn diagnostic_summary_for_path(
7737 &self,
7738 project_path: &ProjectPath,
7739 _: &App,
7740 ) -> DiagnosticSummary {
7741 if let Some(summaries) = self
7742 .diagnostic_summaries
7743 .get(&project_path.worktree_id)
7744 .and_then(|map| map.get(&project_path.path))
7745 {
7746 let (error_count, warning_count) = summaries.iter().fold(
7747 (0, 0),
7748 |(error_count, warning_count), (_language_server_id, summary)| {
7749 (
7750 error_count + summary.error_count,
7751 warning_count + summary.warning_count,
7752 )
7753 },
7754 );
7755
7756 DiagnosticSummary {
7757 error_count,
7758 warning_count,
7759 }
7760 } else {
7761 DiagnosticSummary::default()
7762 }
7763 }
7764
7765 pub fn diagnostic_summaries<'a>(
7766 &'a self,
7767 include_ignored: bool,
7768 cx: &'a App,
7769 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7770 self.worktree_store
7771 .read(cx)
7772 .visible_worktrees(cx)
7773 .filter_map(|worktree| {
7774 let worktree = worktree.read(cx);
7775 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7776 })
7777 .flat_map(move |(worktree, summaries)| {
7778 let worktree_id = worktree.id();
7779 summaries
7780 .iter()
7781 .filter(move |(path, _)| {
7782 include_ignored
7783 || worktree
7784 .entry_for_path(path.as_ref())
7785 .is_some_and(|entry| !entry.is_ignored)
7786 })
7787 .flat_map(move |(path, summaries)| {
7788 summaries.iter().map(move |(server_id, summary)| {
7789 (
7790 ProjectPath {
7791 worktree_id,
7792 path: path.clone(),
7793 },
7794 *server_id,
7795 *summary,
7796 )
7797 })
7798 })
7799 })
7800 }
7801
7802 pub fn on_buffer_edited(
7803 &mut self,
7804 buffer: Entity<Buffer>,
7805 cx: &mut Context<Self>,
7806 ) -> Option<()> {
7807 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7808 Some(
7809 self.as_local()?
7810 .language_servers_for_buffer(buffer, cx)
7811 .map(|i| i.1.clone())
7812 .collect(),
7813 )
7814 })?;
7815
7816 let buffer = buffer.read(cx);
7817 let file = File::from_dyn(buffer.file())?;
7818 let abs_path = file.as_local()?.abs_path(cx);
7819 let uri = lsp::Uri::from_file_path(&abs_path)
7820 .ok()
7821 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7822 .log_err()?;
7823 let next_snapshot = buffer.text_snapshot();
7824 for language_server in language_servers {
7825 let language_server = language_server.clone();
7826
7827 let buffer_snapshots = self
7828 .as_local_mut()?
7829 .buffer_snapshots
7830 .get_mut(&buffer.remote_id())
7831 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7832 let previous_snapshot = buffer_snapshots.last()?;
7833
7834 let build_incremental_change = || {
7835 buffer
7836 .edits_since::<Dimensions<PointUtf16, usize>>(
7837 previous_snapshot.snapshot.version(),
7838 )
7839 .map(|edit| {
7840 let edit_start = edit.new.start.0;
7841 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7842 let new_text = next_snapshot
7843 .text_for_range(edit.new.start.1..edit.new.end.1)
7844 .collect();
7845 lsp::TextDocumentContentChangeEvent {
7846 range: Some(lsp::Range::new(
7847 point_to_lsp(edit_start),
7848 point_to_lsp(edit_end),
7849 )),
7850 range_length: None,
7851 text: new_text,
7852 }
7853 })
7854 .collect()
7855 };
7856
7857 let document_sync_kind = language_server
7858 .capabilities()
7859 .text_document_sync
7860 .as_ref()
7861 .and_then(|sync| match sync {
7862 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7863 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7864 });
7865
7866 let content_changes: Vec<_> = match document_sync_kind {
7867 Some(lsp::TextDocumentSyncKind::FULL) => {
7868 vec![lsp::TextDocumentContentChangeEvent {
7869 range: None,
7870 range_length: None,
7871 text: next_snapshot.text(),
7872 }]
7873 }
7874 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7875 _ => {
7876 #[cfg(any(test, feature = "test-support"))]
7877 {
7878 build_incremental_change()
7879 }
7880
7881 #[cfg(not(any(test, feature = "test-support")))]
7882 {
7883 continue;
7884 }
7885 }
7886 };
7887
7888 let next_version = previous_snapshot.version + 1;
7889 buffer_snapshots.push(LspBufferSnapshot {
7890 version: next_version,
7891 snapshot: next_snapshot.clone(),
7892 });
7893
7894 language_server
7895 .notify::<lsp::notification::DidChangeTextDocument>(
7896 lsp::DidChangeTextDocumentParams {
7897 text_document: lsp::VersionedTextDocumentIdentifier::new(
7898 uri.clone(),
7899 next_version,
7900 ),
7901 content_changes,
7902 },
7903 )
7904 .ok();
7905 self.pull_workspace_diagnostics(language_server.server_id());
7906 }
7907
7908 None
7909 }
7910
7911 pub fn on_buffer_saved(
7912 &mut self,
7913 buffer: Entity<Buffer>,
7914 cx: &mut Context<Self>,
7915 ) -> Option<()> {
7916 let file = File::from_dyn(buffer.read(cx).file())?;
7917 let worktree_id = file.worktree_id(cx);
7918 let abs_path = file.as_local()?.abs_path(cx);
7919 let text_document = lsp::TextDocumentIdentifier {
7920 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7921 };
7922 let local = self.as_local()?;
7923
7924 for server in local.language_servers_for_worktree(worktree_id) {
7925 if let Some(include_text) = include_text(server.as_ref()) {
7926 let text = if include_text {
7927 Some(buffer.read(cx).text())
7928 } else {
7929 None
7930 };
7931 server
7932 .notify::<lsp::notification::DidSaveTextDocument>(
7933 lsp::DidSaveTextDocumentParams {
7934 text_document: text_document.clone(),
7935 text,
7936 },
7937 )
7938 .ok();
7939 }
7940 }
7941
7942 let language_servers = buffer.update(cx, |buffer, cx| {
7943 local.language_server_ids_for_buffer(buffer, cx)
7944 });
7945 for language_server_id in language_servers {
7946 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7947 }
7948
7949 None
7950 }
7951
7952 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7953 maybe!(async move {
7954 let mut refreshed_servers = HashSet::default();
7955 let servers = lsp_store
7956 .update(cx, |lsp_store, cx| {
7957 let local = lsp_store.as_local()?;
7958
7959 let servers = local
7960 .language_server_ids
7961 .iter()
7962 .filter_map(|(seed, state)| {
7963 let worktree = lsp_store
7964 .worktree_store
7965 .read(cx)
7966 .worktree_for_id(seed.worktree_id, cx);
7967 let delegate: Arc<dyn LspAdapterDelegate> =
7968 worktree.map(|worktree| {
7969 LocalLspAdapterDelegate::new(
7970 local.languages.clone(),
7971 &local.environment,
7972 cx.weak_entity(),
7973 &worktree,
7974 local.http_client.clone(),
7975 local.fs.clone(),
7976 cx,
7977 )
7978 })?;
7979 let server_id = state.id;
7980
7981 let states = local.language_servers.get(&server_id)?;
7982
7983 match states {
7984 LanguageServerState::Starting { .. } => None,
7985 LanguageServerState::Running {
7986 adapter, server, ..
7987 } => {
7988 let adapter = adapter.clone();
7989 let server = server.clone();
7990 refreshed_servers.insert(server.name());
7991 let toolchain = seed.toolchain.clone();
7992 Some(cx.spawn(async move |_, cx| {
7993 let settings =
7994 LocalLspStore::workspace_configuration_for_adapter(
7995 adapter.adapter.clone(),
7996 &delegate,
7997 toolchain,
7998 None,
7999 cx,
8000 )
8001 .await
8002 .ok()?;
8003 server
8004 .notify::<lsp::notification::DidChangeConfiguration>(
8005 lsp::DidChangeConfigurationParams { settings },
8006 )
8007 .ok()?;
8008 Some(())
8009 }))
8010 }
8011 }
8012 })
8013 .collect::<Vec<_>>();
8014
8015 Some(servers)
8016 })
8017 .ok()
8018 .flatten()?;
8019
8020 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8021 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8022 // to stop and unregister its language server wrapper.
8023 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8024 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8025 let _: Vec<Option<()>> = join_all(servers).await;
8026
8027 Some(())
8028 })
8029 .await;
8030 }
8031
8032 fn maintain_workspace_config(
8033 external_refresh_requests: watch::Receiver<()>,
8034 cx: &mut Context<Self>,
8035 ) -> Task<Result<()>> {
8036 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8037 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8038
8039 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8040 *settings_changed_tx.borrow_mut() = ();
8041 });
8042
8043 let mut joint_future =
8044 futures::stream::select(settings_changed_rx, external_refresh_requests);
8045 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8046 // - 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).
8047 // - 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.
8048 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8049 // - 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,
8050 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8051 cx.spawn(async move |this, cx| {
8052 while let Some(()) = joint_future.next().await {
8053 this.update(cx, |this, cx| {
8054 this.refresh_server_tree(cx);
8055 })
8056 .ok();
8057
8058 Self::refresh_workspace_configurations(&this, cx).await;
8059 }
8060
8061 drop(settings_observation);
8062 anyhow::Ok(())
8063 })
8064 }
8065
8066 pub fn running_language_servers_for_local_buffer<'a>(
8067 &'a self,
8068 buffer: &Buffer,
8069 cx: &mut App,
8070 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8071 let local = self.as_local();
8072 let language_server_ids = local
8073 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8074 .unwrap_or_default();
8075
8076 language_server_ids
8077 .into_iter()
8078 .filter_map(
8079 move |server_id| match local?.language_servers.get(&server_id)? {
8080 LanguageServerState::Running {
8081 adapter, server, ..
8082 } => Some((adapter, server)),
8083 _ => None,
8084 },
8085 )
8086 }
8087
8088 pub fn language_servers_for_local_buffer(
8089 &self,
8090 buffer: &Buffer,
8091 cx: &mut App,
8092 ) -> Vec<LanguageServerId> {
8093 let local = self.as_local();
8094 local
8095 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8096 .unwrap_or_default()
8097 }
8098
8099 pub fn language_server_for_local_buffer<'a>(
8100 &'a self,
8101 buffer: &'a Buffer,
8102 server_id: LanguageServerId,
8103 cx: &'a mut App,
8104 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8105 self.as_local()?
8106 .language_servers_for_buffer(buffer, cx)
8107 .find(|(_, s)| s.server_id() == server_id)
8108 }
8109
8110 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8111 self.diagnostic_summaries.remove(&id_to_remove);
8112 if let Some(local) = self.as_local_mut() {
8113 let to_remove = local.remove_worktree(id_to_remove, cx);
8114 for server in to_remove {
8115 self.language_server_statuses.remove(&server);
8116 }
8117 }
8118 }
8119
8120 pub fn shared(
8121 &mut self,
8122 project_id: u64,
8123 downstream_client: AnyProtoClient,
8124 _: &mut Context<Self>,
8125 ) {
8126 self.downstream_client = Some((downstream_client.clone(), project_id));
8127
8128 for (server_id, status) in &self.language_server_statuses {
8129 if let Some(server) = self.language_server_for_id(*server_id) {
8130 downstream_client
8131 .send(proto::StartLanguageServer {
8132 project_id,
8133 server: Some(proto::LanguageServer {
8134 id: server_id.to_proto(),
8135 name: status.name.to_string(),
8136 worktree_id: status.worktree.map(|id| id.to_proto()),
8137 }),
8138 capabilities: serde_json::to_string(&server.capabilities())
8139 .expect("serializing server LSP capabilities"),
8140 })
8141 .log_err();
8142 }
8143 }
8144 }
8145
8146 pub fn disconnected_from_host(&mut self) {
8147 self.downstream_client.take();
8148 }
8149
8150 pub fn disconnected_from_ssh_remote(&mut self) {
8151 if let LspStoreMode::Remote(RemoteLspStore {
8152 upstream_client, ..
8153 }) = &mut self.mode
8154 {
8155 upstream_client.take();
8156 }
8157 }
8158
8159 pub(crate) fn set_language_server_statuses_from_proto(
8160 &mut self,
8161 project: WeakEntity<Project>,
8162 language_servers: Vec<proto::LanguageServer>,
8163 server_capabilities: Vec<String>,
8164 cx: &mut Context<Self>,
8165 ) {
8166 let lsp_logs = cx
8167 .try_global::<GlobalLogStore>()
8168 .map(|lsp_store| lsp_store.0.clone());
8169
8170 self.language_server_statuses = language_servers
8171 .into_iter()
8172 .zip(server_capabilities)
8173 .map(|(server, server_capabilities)| {
8174 let server_id = LanguageServerId(server.id as usize);
8175 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8176 self.lsp_server_capabilities
8177 .insert(server_id, server_capabilities);
8178 }
8179
8180 let name = LanguageServerName::from_proto(server.name);
8181 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8182
8183 if let Some(lsp_logs) = &lsp_logs {
8184 lsp_logs.update(cx, |lsp_logs, cx| {
8185 lsp_logs.add_language_server(
8186 // Only remote clients get their language servers set from proto
8187 LanguageServerKind::Remote {
8188 project: project.clone(),
8189 },
8190 server_id,
8191 Some(name.clone()),
8192 worktree,
8193 None,
8194 cx,
8195 );
8196 });
8197 }
8198
8199 (
8200 server_id,
8201 LanguageServerStatus {
8202 name,
8203 server_version: None,
8204 pending_work: Default::default(),
8205 has_pending_diagnostic_updates: false,
8206 progress_tokens: Default::default(),
8207 worktree,
8208 binary: None,
8209 configuration: None,
8210 workspace_folders: BTreeSet::new(),
8211 process_id: None,
8212 },
8213 )
8214 })
8215 .collect();
8216 }
8217
8218 #[cfg(feature = "test-support")]
8219 pub fn update_diagnostic_entries(
8220 &mut self,
8221 server_id: LanguageServerId,
8222 abs_path: PathBuf,
8223 result_id: Option<SharedString>,
8224 version: Option<i32>,
8225 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8226 cx: &mut Context<Self>,
8227 ) -> anyhow::Result<()> {
8228 self.merge_diagnostic_entries(
8229 vec![DocumentDiagnosticsUpdate {
8230 diagnostics: DocumentDiagnostics {
8231 diagnostics,
8232 document_abs_path: abs_path,
8233 version,
8234 },
8235 result_id,
8236 server_id,
8237 disk_based_sources: Cow::Borrowed(&[]),
8238 registration_id: None,
8239 }],
8240 |_, _, _| false,
8241 cx,
8242 )?;
8243 Ok(())
8244 }
8245
8246 pub fn merge_diagnostic_entries<'a>(
8247 &mut self,
8248 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8249 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8250 cx: &mut Context<Self>,
8251 ) -> anyhow::Result<()> {
8252 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8253 let mut updated_diagnostics_paths = HashMap::default();
8254 for mut update in diagnostic_updates {
8255 let abs_path = &update.diagnostics.document_abs_path;
8256 let server_id = update.server_id;
8257 let Some((worktree, relative_path)) =
8258 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8259 else {
8260 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8261 return Ok(());
8262 };
8263
8264 let worktree_id = worktree.read(cx).id();
8265 let project_path = ProjectPath {
8266 worktree_id,
8267 path: relative_path,
8268 };
8269
8270 let document_uri = lsp::Uri::from_file_path(abs_path)
8271 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8272 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8273 let snapshot = buffer_handle.read(cx).snapshot();
8274 let buffer = buffer_handle.read(cx);
8275 let reused_diagnostics = buffer
8276 .buffer_diagnostics(Some(server_id))
8277 .iter()
8278 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8279 .map(|v| {
8280 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8281 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8282 DiagnosticEntry {
8283 range: start..end,
8284 diagnostic: v.diagnostic.clone(),
8285 }
8286 })
8287 .collect::<Vec<_>>();
8288
8289 self.as_local_mut()
8290 .context("cannot merge diagnostics on a remote LspStore")?
8291 .update_buffer_diagnostics(
8292 &buffer_handle,
8293 server_id,
8294 Some(update.registration_id),
8295 update.result_id,
8296 update.diagnostics.version,
8297 update.diagnostics.diagnostics.clone(),
8298 reused_diagnostics.clone(),
8299 cx,
8300 )?;
8301
8302 update.diagnostics.diagnostics.extend(reused_diagnostics);
8303 } else if let Some(local) = self.as_local() {
8304 let reused_diagnostics = local
8305 .diagnostics
8306 .get(&worktree_id)
8307 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8308 .and_then(|diagnostics_by_server_id| {
8309 diagnostics_by_server_id
8310 .binary_search_by_key(&server_id, |e| e.0)
8311 .ok()
8312 .map(|ix| &diagnostics_by_server_id[ix].1)
8313 })
8314 .into_iter()
8315 .flatten()
8316 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8317
8318 update
8319 .diagnostics
8320 .diagnostics
8321 .extend(reused_diagnostics.cloned());
8322 }
8323
8324 let updated = worktree.update(cx, |worktree, cx| {
8325 self.update_worktree_diagnostics(
8326 worktree.id(),
8327 server_id,
8328 project_path.path.clone(),
8329 update.diagnostics.diagnostics,
8330 cx,
8331 )
8332 })?;
8333 match updated {
8334 ControlFlow::Continue(new_summary) => {
8335 if let Some((project_id, new_summary)) = new_summary {
8336 match &mut diagnostics_summary {
8337 Some(diagnostics_summary) => {
8338 diagnostics_summary
8339 .more_summaries
8340 .push(proto::DiagnosticSummary {
8341 path: project_path.path.as_ref().to_proto(),
8342 language_server_id: server_id.0 as u64,
8343 error_count: new_summary.error_count,
8344 warning_count: new_summary.warning_count,
8345 })
8346 }
8347 None => {
8348 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8349 project_id,
8350 worktree_id: worktree_id.to_proto(),
8351 summary: Some(proto::DiagnosticSummary {
8352 path: project_path.path.as_ref().to_proto(),
8353 language_server_id: server_id.0 as u64,
8354 error_count: new_summary.error_count,
8355 warning_count: new_summary.warning_count,
8356 }),
8357 more_summaries: Vec::new(),
8358 })
8359 }
8360 }
8361 }
8362 updated_diagnostics_paths
8363 .entry(server_id)
8364 .or_insert_with(Vec::new)
8365 .push(project_path);
8366 }
8367 ControlFlow::Break(()) => {}
8368 }
8369 }
8370
8371 if let Some((diagnostics_summary, (downstream_client, _))) =
8372 diagnostics_summary.zip(self.downstream_client.as_ref())
8373 {
8374 downstream_client.send(diagnostics_summary).log_err();
8375 }
8376 for (server_id, paths) in updated_diagnostics_paths {
8377 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8378 }
8379 Ok(())
8380 }
8381
8382 fn update_worktree_diagnostics(
8383 &mut self,
8384 worktree_id: WorktreeId,
8385 server_id: LanguageServerId,
8386 path_in_worktree: Arc<RelPath>,
8387 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8388 _: &mut Context<Worktree>,
8389 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8390 let local = match &mut self.mode {
8391 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8392 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8393 };
8394
8395 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8396 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8397 let summaries_by_server_id = summaries_for_tree
8398 .entry(path_in_worktree.clone())
8399 .or_default();
8400
8401 let old_summary = summaries_by_server_id
8402 .remove(&server_id)
8403 .unwrap_or_default();
8404
8405 let new_summary = DiagnosticSummary::new(&diagnostics);
8406 if diagnostics.is_empty() {
8407 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8408 {
8409 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8410 diagnostics_by_server_id.remove(ix);
8411 }
8412 if diagnostics_by_server_id.is_empty() {
8413 diagnostics_for_tree.remove(&path_in_worktree);
8414 }
8415 }
8416 } else {
8417 summaries_by_server_id.insert(server_id, new_summary);
8418 let diagnostics_by_server_id = diagnostics_for_tree
8419 .entry(path_in_worktree.clone())
8420 .or_default();
8421 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8422 Ok(ix) => {
8423 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8424 }
8425 Err(ix) => {
8426 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8427 }
8428 }
8429 }
8430
8431 if !old_summary.is_empty() || !new_summary.is_empty() {
8432 if let Some((_, project_id)) = &self.downstream_client {
8433 Ok(ControlFlow::Continue(Some((
8434 *project_id,
8435 proto::DiagnosticSummary {
8436 path: path_in_worktree.to_proto(),
8437 language_server_id: server_id.0 as u64,
8438 error_count: new_summary.error_count as u32,
8439 warning_count: new_summary.warning_count as u32,
8440 },
8441 ))))
8442 } else {
8443 Ok(ControlFlow::Continue(None))
8444 }
8445 } else {
8446 Ok(ControlFlow::Break(()))
8447 }
8448 }
8449
8450 pub fn open_buffer_for_symbol(
8451 &mut self,
8452 symbol: &Symbol,
8453 cx: &mut Context<Self>,
8454 ) -> Task<Result<Entity<Buffer>>> {
8455 if let Some((client, project_id)) = self.upstream_client() {
8456 let request = client.request(proto::OpenBufferForSymbol {
8457 project_id,
8458 symbol: Some(Self::serialize_symbol(symbol)),
8459 });
8460 cx.spawn(async move |this, cx| {
8461 let response = request.await?;
8462 let buffer_id = BufferId::new(response.buffer_id)?;
8463 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8464 .await
8465 })
8466 } else if let Some(local) = self.as_local() {
8467 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8468 seed.worktree_id == symbol.source_worktree_id
8469 && state.id == symbol.source_language_server_id
8470 && symbol.language_server_name == seed.name
8471 });
8472 if !is_valid {
8473 return Task::ready(Err(anyhow!(
8474 "language server for worktree and language not found"
8475 )));
8476 };
8477
8478 let symbol_abs_path = match &symbol.path {
8479 SymbolLocation::InProject(project_path) => self
8480 .worktree_store
8481 .read(cx)
8482 .absolutize(&project_path, cx)
8483 .context("no such worktree"),
8484 SymbolLocation::OutsideProject {
8485 abs_path,
8486 signature: _,
8487 } => Ok(abs_path.to_path_buf()),
8488 };
8489 let symbol_abs_path = match symbol_abs_path {
8490 Ok(abs_path) => abs_path,
8491 Err(err) => return Task::ready(Err(err)),
8492 };
8493 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8494 uri
8495 } else {
8496 return Task::ready(Err(anyhow!("invalid symbol path")));
8497 };
8498
8499 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8500 } else {
8501 Task::ready(Err(anyhow!("no upstream client or local store")))
8502 }
8503 }
8504
8505 pub(crate) fn open_local_buffer_via_lsp(
8506 &mut self,
8507 abs_path: lsp::Uri,
8508 language_server_id: LanguageServerId,
8509 cx: &mut Context<Self>,
8510 ) -> Task<Result<Entity<Buffer>>> {
8511 let path_style = self.worktree_store.read(cx).path_style();
8512 cx.spawn(async move |lsp_store, cx| {
8513 // Escape percent-encoded string.
8514 let current_scheme = abs_path.scheme().to_owned();
8515 // Uri is immutable, so we can't modify the scheme
8516
8517 let abs_path = abs_path
8518 .to_file_path_ext(path_style)
8519 .map_err(|()| anyhow!("can't convert URI to path"))?;
8520 let p = abs_path.clone();
8521 let yarn_worktree = lsp_store
8522 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8523 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8524 cx.spawn(async move |this, cx| {
8525 let t = this
8526 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8527 .ok()?;
8528 t.await
8529 })
8530 }),
8531 None => Task::ready(None),
8532 })?
8533 .await;
8534 let (worktree_root_target, known_relative_path) =
8535 if let Some((zip_root, relative_path)) = yarn_worktree {
8536 (zip_root, Some(relative_path))
8537 } else {
8538 (Arc::<Path>::from(abs_path.as_path()), None)
8539 };
8540 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8541 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8542 worktree_store.find_worktree(&worktree_root_target, cx)
8543 })
8544 })?;
8545 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8546 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8547 (result.0, relative_path, None)
8548 } else {
8549 let worktree = lsp_store
8550 .update(cx, |lsp_store, cx| {
8551 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8552 worktree_store.create_worktree(&worktree_root_target, false, cx)
8553 })
8554 })?
8555 .await?;
8556 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8557 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8558 lsp_store
8559 .update(cx, |lsp_store, cx| {
8560 if let Some(local) = lsp_store.as_local_mut() {
8561 local.register_language_server_for_invisible_worktree(
8562 &worktree,
8563 language_server_id,
8564 cx,
8565 )
8566 }
8567 match lsp_store.language_server_statuses.get(&language_server_id) {
8568 Some(status) => status.worktree,
8569 None => None,
8570 }
8571 })
8572 .ok()
8573 .flatten()
8574 .zip(Some(worktree_root.clone()))
8575 } else {
8576 None
8577 };
8578 let relative_path = if let Some(known_path) = known_relative_path {
8579 known_path
8580 } else {
8581 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8582 .into_arc()
8583 };
8584 (worktree, relative_path, source_ws)
8585 };
8586 let project_path = ProjectPath {
8587 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8588 path: relative_path,
8589 };
8590 let buffer = lsp_store
8591 .update(cx, |lsp_store, cx| {
8592 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8593 buffer_store.open_buffer(project_path, cx)
8594 })
8595 })?
8596 .await?;
8597 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8598 if let Some((source_ws, worktree_root)) = source_ws {
8599 buffer.update(cx, |buffer, cx| {
8600 let settings = WorktreeSettings::get(
8601 Some(
8602 (&ProjectPath {
8603 worktree_id: source_ws,
8604 path: Arc::from(RelPath::empty()),
8605 })
8606 .into(),
8607 ),
8608 cx,
8609 );
8610 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8611 if is_read_only {
8612 buffer.set_capability(Capability::ReadOnly, cx);
8613 }
8614 });
8615 }
8616 Ok(buffer)
8617 })
8618 }
8619
8620 fn local_lsp_servers_for_buffer(
8621 &self,
8622 buffer: &Entity<Buffer>,
8623 cx: &mut Context<Self>,
8624 ) -> Vec<LanguageServerId> {
8625 let Some(local) = self.as_local() else {
8626 return Vec::new();
8627 };
8628
8629 let snapshot = buffer.read(cx).snapshot();
8630
8631 buffer.update(cx, |buffer, cx| {
8632 local
8633 .language_servers_for_buffer(buffer, cx)
8634 .map(|(_, server)| server.server_id())
8635 .filter(|server_id| {
8636 self.as_local().is_none_or(|local| {
8637 local
8638 .buffers_opened_in_servers
8639 .get(&snapshot.remote_id())
8640 .is_some_and(|servers| servers.contains(server_id))
8641 })
8642 })
8643 .collect()
8644 })
8645 }
8646
8647 fn request_multiple_lsp_locally<P, R>(
8648 &mut self,
8649 buffer: &Entity<Buffer>,
8650 position: Option<P>,
8651 request: R,
8652 cx: &mut Context<Self>,
8653 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8654 where
8655 P: ToOffset,
8656 R: LspCommand + Clone,
8657 <R::LspRequest as lsp::request::Request>::Result: Send,
8658 <R::LspRequest as lsp::request::Request>::Params: Send,
8659 {
8660 let Some(local) = self.as_local() else {
8661 return Task::ready(Vec::new());
8662 };
8663
8664 let snapshot = buffer.read(cx).snapshot();
8665 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8666
8667 let server_ids = buffer.update(cx, |buffer, cx| {
8668 local
8669 .language_servers_for_buffer(buffer, cx)
8670 .filter(|(adapter, _)| {
8671 scope
8672 .as_ref()
8673 .map(|scope| scope.language_allowed(&adapter.name))
8674 .unwrap_or(true)
8675 })
8676 .map(|(_, server)| server.server_id())
8677 .filter(|server_id| {
8678 self.as_local().is_none_or(|local| {
8679 local
8680 .buffers_opened_in_servers
8681 .get(&snapshot.remote_id())
8682 .is_some_and(|servers| servers.contains(server_id))
8683 })
8684 })
8685 .collect::<Vec<_>>()
8686 });
8687
8688 let mut response_results = server_ids
8689 .into_iter()
8690 .map(|server_id| {
8691 let task = self.request_lsp(
8692 buffer.clone(),
8693 LanguageServerToQuery::Other(server_id),
8694 request.clone(),
8695 cx,
8696 );
8697 async move { (server_id, task.await) }
8698 })
8699 .collect::<FuturesUnordered<_>>();
8700
8701 cx.background_spawn(async move {
8702 let mut responses = Vec::with_capacity(response_results.len());
8703 while let Some((server_id, response_result)) = response_results.next().await {
8704 match response_result {
8705 Ok(response) => responses.push((server_id, response)),
8706 // rust-analyzer likes to error with this when its still loading up
8707 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8708 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8709 }
8710 }
8711 responses
8712 })
8713 }
8714
8715 async fn handle_lsp_get_completions(
8716 this: Entity<Self>,
8717 envelope: TypedEnvelope<proto::GetCompletions>,
8718 mut cx: AsyncApp,
8719 ) -> Result<proto::GetCompletionsResponse> {
8720 let sender_id = envelope.original_sender_id().unwrap_or_default();
8721
8722 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8723 let buffer_handle = this.update(&mut cx, |this, cx| {
8724 this.buffer_store.read(cx).get_existing(buffer_id)
8725 })?;
8726 let request = GetCompletions::from_proto(
8727 envelope.payload,
8728 this.clone(),
8729 buffer_handle.clone(),
8730 cx.clone(),
8731 )
8732 .await?;
8733
8734 let server_to_query = match request.server_id {
8735 Some(server_id) => LanguageServerToQuery::Other(server_id),
8736 None => LanguageServerToQuery::FirstCapable,
8737 };
8738
8739 let response = this
8740 .update(&mut cx, |this, cx| {
8741 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8742 })
8743 .await?;
8744 this.update(&mut cx, |this, cx| {
8745 Ok(GetCompletions::response_to_proto(
8746 response,
8747 this,
8748 sender_id,
8749 &buffer_handle.read(cx).version(),
8750 cx,
8751 ))
8752 })
8753 }
8754
8755 async fn handle_lsp_command<T: LspCommand>(
8756 this: Entity<Self>,
8757 envelope: TypedEnvelope<T::ProtoRequest>,
8758 mut cx: AsyncApp,
8759 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8760 where
8761 <T::LspRequest as lsp::request::Request>::Params: Send,
8762 <T::LspRequest as lsp::request::Request>::Result: Send,
8763 {
8764 let sender_id = envelope.original_sender_id().unwrap_or_default();
8765 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8766 let buffer_handle = this.update(&mut cx, |this, cx| {
8767 this.buffer_store.read(cx).get_existing(buffer_id)
8768 })?;
8769 let request = T::from_proto(
8770 envelope.payload,
8771 this.clone(),
8772 buffer_handle.clone(),
8773 cx.clone(),
8774 )
8775 .await?;
8776 let response = this
8777 .update(&mut cx, |this, cx| {
8778 this.request_lsp(
8779 buffer_handle.clone(),
8780 LanguageServerToQuery::FirstCapable,
8781 request,
8782 cx,
8783 )
8784 })
8785 .await?;
8786 this.update(&mut cx, |this, cx| {
8787 Ok(T::response_to_proto(
8788 response,
8789 this,
8790 sender_id,
8791 &buffer_handle.read(cx).version(),
8792 cx,
8793 ))
8794 })
8795 }
8796
8797 async fn handle_lsp_query(
8798 lsp_store: Entity<Self>,
8799 envelope: TypedEnvelope<proto::LspQuery>,
8800 mut cx: AsyncApp,
8801 ) -> Result<proto::Ack> {
8802 use proto::lsp_query::Request;
8803 let sender_id = envelope.original_sender_id().unwrap_or_default();
8804 let lsp_query = envelope.payload;
8805 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8806 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8807 match lsp_query.request.context("invalid LSP query request")? {
8808 Request::GetReferences(get_references) => {
8809 let position = get_references.position.clone().and_then(deserialize_anchor);
8810 Self::query_lsp_locally::<GetReferences>(
8811 lsp_store,
8812 server_id,
8813 sender_id,
8814 lsp_request_id,
8815 get_references,
8816 position,
8817 &mut cx,
8818 )
8819 .await?;
8820 }
8821 Request::GetDocumentColor(get_document_color) => {
8822 Self::query_lsp_locally::<GetDocumentColor>(
8823 lsp_store,
8824 server_id,
8825 sender_id,
8826 lsp_request_id,
8827 get_document_color,
8828 None,
8829 &mut cx,
8830 )
8831 .await?;
8832 }
8833 Request::GetFoldingRanges(get_folding_ranges) => {
8834 Self::query_lsp_locally::<GetFoldingRanges>(
8835 lsp_store,
8836 server_id,
8837 sender_id,
8838 lsp_request_id,
8839 get_folding_ranges,
8840 None,
8841 &mut cx,
8842 )
8843 .await?;
8844 }
8845 Request::GetDocumentSymbols(get_document_symbols) => {
8846 Self::query_lsp_locally::<GetDocumentSymbols>(
8847 lsp_store,
8848 server_id,
8849 sender_id,
8850 lsp_request_id,
8851 get_document_symbols,
8852 None,
8853 &mut cx,
8854 )
8855 .await?;
8856 }
8857 Request::GetHover(get_hover) => {
8858 let position = get_hover.position.clone().and_then(deserialize_anchor);
8859 Self::query_lsp_locally::<GetHover>(
8860 lsp_store,
8861 server_id,
8862 sender_id,
8863 lsp_request_id,
8864 get_hover,
8865 position,
8866 &mut cx,
8867 )
8868 .await?;
8869 }
8870 Request::GetCodeActions(get_code_actions) => {
8871 Self::query_lsp_locally::<GetCodeActions>(
8872 lsp_store,
8873 server_id,
8874 sender_id,
8875 lsp_request_id,
8876 get_code_actions,
8877 None,
8878 &mut cx,
8879 )
8880 .await?;
8881 }
8882 Request::GetSignatureHelp(get_signature_help) => {
8883 let position = get_signature_help
8884 .position
8885 .clone()
8886 .and_then(deserialize_anchor);
8887 Self::query_lsp_locally::<GetSignatureHelp>(
8888 lsp_store,
8889 server_id,
8890 sender_id,
8891 lsp_request_id,
8892 get_signature_help,
8893 position,
8894 &mut cx,
8895 )
8896 .await?;
8897 }
8898 Request::GetCodeLens(get_code_lens) => {
8899 Self::query_lsp_locally::<GetCodeLens>(
8900 lsp_store,
8901 server_id,
8902 sender_id,
8903 lsp_request_id,
8904 get_code_lens,
8905 None,
8906 &mut cx,
8907 )
8908 .await?;
8909 }
8910 Request::GetDefinition(get_definition) => {
8911 let position = get_definition.position.clone().and_then(deserialize_anchor);
8912 Self::query_lsp_locally::<GetDefinitions>(
8913 lsp_store,
8914 server_id,
8915 sender_id,
8916 lsp_request_id,
8917 get_definition,
8918 position,
8919 &mut cx,
8920 )
8921 .await?;
8922 }
8923 Request::GetDeclaration(get_declaration) => {
8924 let position = get_declaration
8925 .position
8926 .clone()
8927 .and_then(deserialize_anchor);
8928 Self::query_lsp_locally::<GetDeclarations>(
8929 lsp_store,
8930 server_id,
8931 sender_id,
8932 lsp_request_id,
8933 get_declaration,
8934 position,
8935 &mut cx,
8936 )
8937 .await?;
8938 }
8939 Request::GetTypeDefinition(get_type_definition) => {
8940 let position = get_type_definition
8941 .position
8942 .clone()
8943 .and_then(deserialize_anchor);
8944 Self::query_lsp_locally::<GetTypeDefinitions>(
8945 lsp_store,
8946 server_id,
8947 sender_id,
8948 lsp_request_id,
8949 get_type_definition,
8950 position,
8951 &mut cx,
8952 )
8953 .await?;
8954 }
8955 Request::GetImplementation(get_implementation) => {
8956 let position = get_implementation
8957 .position
8958 .clone()
8959 .and_then(deserialize_anchor);
8960 Self::query_lsp_locally::<GetImplementations>(
8961 lsp_store,
8962 server_id,
8963 sender_id,
8964 lsp_request_id,
8965 get_implementation,
8966 position,
8967 &mut cx,
8968 )
8969 .await?;
8970 }
8971 Request::InlayHints(inlay_hints) => {
8972 let query_start = inlay_hints
8973 .start
8974 .clone()
8975 .and_then(deserialize_anchor)
8976 .context("invalid inlay hints range start")?;
8977 let query_end = inlay_hints
8978 .end
8979 .clone()
8980 .and_then(deserialize_anchor)
8981 .context("invalid inlay hints range end")?;
8982 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8983 &lsp_store,
8984 server_id,
8985 lsp_request_id,
8986 &inlay_hints,
8987 query_start..query_end,
8988 &mut cx,
8989 )
8990 .await
8991 .context("preparing inlay hints request")?;
8992 Self::query_lsp_locally::<InlayHints>(
8993 lsp_store,
8994 server_id,
8995 sender_id,
8996 lsp_request_id,
8997 inlay_hints,
8998 None,
8999 &mut cx,
9000 )
9001 .await
9002 .context("querying for inlay hints")?
9003 }
9004 //////////////////////////////
9005 // Below are LSP queries that need to fetch more data,
9006 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9007 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9008 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9009 &lsp_store,
9010 &get_document_diagnostics,
9011 &mut cx,
9012 )
9013 .await?;
9014 lsp_store.update(&mut cx, |lsp_store, cx| {
9015 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9016 let key = LspKey {
9017 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9018 server_queried: server_id,
9019 };
9020 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9021 ) {
9022 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9023 lsp_requests.clear();
9024 };
9025 }
9026
9027 lsp_data.lsp_requests.entry(key).or_default().insert(
9028 lsp_request_id,
9029 cx.spawn(async move |lsp_store, cx| {
9030 let diagnostics_pull = lsp_store
9031 .update(cx, |lsp_store, cx| {
9032 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9033 })
9034 .ok();
9035 if let Some(diagnostics_pull) = diagnostics_pull {
9036 match diagnostics_pull.await {
9037 Ok(()) => {}
9038 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9039 };
9040 }
9041 }),
9042 );
9043 });
9044 }
9045 Request::SemanticTokens(semantic_tokens) => {
9046 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9047 &lsp_store,
9048 &semantic_tokens,
9049 &mut cx,
9050 )
9051 .await?;
9052 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9053 lsp_store.update(&mut cx, |lsp_store, cx| {
9054 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9055 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9056 let key = LspKey {
9057 request_type: TypeId::of::<SemanticTokensFull>(),
9058 server_queried: server_id,
9059 };
9060 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9061 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9062 lsp_requests.clear();
9063 };
9064 }
9065
9066 lsp_data.lsp_requests.entry(key).or_default().insert(
9067 lsp_request_id,
9068 cx.spawn(async move |lsp_store, cx| {
9069 let tokens_fetch = lsp_store
9070 .update(cx, |lsp_store, cx| {
9071 lsp_store
9072 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9073 })
9074 .ok();
9075 if let Some(tokens_fetch) = tokens_fetch {
9076 let new_tokens = tokens_fetch.await;
9077 if let Some(new_tokens) = new_tokens {
9078 lsp_store
9079 .update(cx, |lsp_store, cx| {
9080 let response = new_tokens
9081 .into_iter()
9082 .map(|(server_id, response)| {
9083 (
9084 server_id.to_proto(),
9085 SemanticTokensFull::response_to_proto(
9086 response,
9087 lsp_store,
9088 sender_id,
9089 &buffer_version,
9090 cx,
9091 ),
9092 )
9093 })
9094 .collect::<HashMap<_, _>>();
9095 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9096 project_id,
9097 lsp_request_id,
9098 response,
9099 ) {
9100 Ok(()) => {}
9101 Err(e) => {
9102 log::error!(
9103 "Failed to send semantic tokens LSP response: {e:#}",
9104 )
9105 }
9106 }
9107 })
9108 .ok();
9109 }
9110 }
9111 }),
9112 );
9113 }
9114 });
9115 }
9116 }
9117 Ok(proto::Ack {})
9118 }
9119
9120 async fn handle_lsp_query_response(
9121 lsp_store: Entity<Self>,
9122 envelope: TypedEnvelope<proto::LspQueryResponse>,
9123 cx: AsyncApp,
9124 ) -> Result<()> {
9125 lsp_store.read_with(&cx, |lsp_store, _| {
9126 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9127 upstream_client.handle_lsp_response(envelope.clone());
9128 }
9129 });
9130 Ok(())
9131 }
9132
9133 async fn handle_apply_code_action(
9134 this: Entity<Self>,
9135 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9136 mut cx: AsyncApp,
9137 ) -> Result<proto::ApplyCodeActionResponse> {
9138 let sender_id = envelope.original_sender_id().unwrap_or_default();
9139 let action =
9140 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9141 let apply_code_action = this.update(&mut cx, |this, cx| {
9142 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9143 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9144 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9145 })?;
9146
9147 let project_transaction = apply_code_action.await?;
9148 let project_transaction = this.update(&mut cx, |this, cx| {
9149 this.buffer_store.update(cx, |buffer_store, cx| {
9150 buffer_store.serialize_project_transaction_for_peer(
9151 project_transaction,
9152 sender_id,
9153 cx,
9154 )
9155 })
9156 });
9157 Ok(proto::ApplyCodeActionResponse {
9158 transaction: Some(project_transaction),
9159 })
9160 }
9161
9162 async fn handle_register_buffer_with_language_servers(
9163 this: Entity<Self>,
9164 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9165 mut cx: AsyncApp,
9166 ) -> Result<proto::Ack> {
9167 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9168 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9169 this.update(&mut cx, |this, cx| {
9170 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9171 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9172 project_id: upstream_project_id,
9173 buffer_id: buffer_id.to_proto(),
9174 only_servers: envelope.payload.only_servers,
9175 });
9176 }
9177
9178 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9179 anyhow::bail!("buffer is not open");
9180 };
9181
9182 let handle = this.register_buffer_with_language_servers(
9183 &buffer,
9184 envelope
9185 .payload
9186 .only_servers
9187 .into_iter()
9188 .filter_map(|selector| {
9189 Some(match selector.selector? {
9190 proto::language_server_selector::Selector::ServerId(server_id) => {
9191 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9192 }
9193 proto::language_server_selector::Selector::Name(name) => {
9194 LanguageServerSelector::Name(LanguageServerName(
9195 SharedString::from(name),
9196 ))
9197 }
9198 })
9199 })
9200 .collect(),
9201 false,
9202 cx,
9203 );
9204 // Pull diagnostics for the buffer even if it was already registered.
9205 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9206 // but it's unclear if we need it.
9207 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9208 .detach();
9209 this.buffer_store().update(cx, |buffer_store, _| {
9210 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9211 });
9212
9213 Ok(())
9214 })?;
9215 Ok(proto::Ack {})
9216 }
9217
9218 async fn handle_rename_project_entry(
9219 this: Entity<Self>,
9220 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9221 mut cx: AsyncApp,
9222 ) -> Result<proto::ProjectEntryResponse> {
9223 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9224 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9225 let new_path =
9226 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9227
9228 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9229 .update(&mut cx, |this, cx| {
9230 let (worktree, entry) = this
9231 .worktree_store
9232 .read(cx)
9233 .worktree_and_entry_for_id(entry_id, cx)?;
9234 let new_worktree = this
9235 .worktree_store
9236 .read(cx)
9237 .worktree_for_id(new_worktree_id, cx)?;
9238 Some((
9239 this.worktree_store.clone(),
9240 worktree,
9241 new_worktree,
9242 entry.clone(),
9243 ))
9244 })
9245 .context("worktree not found")?;
9246 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9247 (worktree.absolutize(&old_entry.path), worktree.id())
9248 });
9249 let new_abs_path =
9250 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9251
9252 let _transaction = Self::will_rename_entry(
9253 this.downgrade(),
9254 old_worktree_id,
9255 &old_abs_path,
9256 &new_abs_path,
9257 old_entry.is_dir(),
9258 cx.clone(),
9259 )
9260 .await;
9261 let response = WorktreeStore::handle_rename_project_entry(
9262 worktree_store,
9263 envelope.payload,
9264 cx.clone(),
9265 )
9266 .await;
9267 this.read_with(&cx, |this, _| {
9268 this.did_rename_entry(
9269 old_worktree_id,
9270 &old_abs_path,
9271 &new_abs_path,
9272 old_entry.is_dir(),
9273 );
9274 });
9275 response
9276 }
9277
9278 async fn handle_update_diagnostic_summary(
9279 this: Entity<Self>,
9280 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9281 mut cx: AsyncApp,
9282 ) -> Result<()> {
9283 this.update(&mut cx, |lsp_store, cx| {
9284 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9285 let mut updated_diagnostics_paths = HashMap::default();
9286 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9287 for message_summary in envelope
9288 .payload
9289 .summary
9290 .into_iter()
9291 .chain(envelope.payload.more_summaries)
9292 {
9293 let project_path = ProjectPath {
9294 worktree_id,
9295 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9296 };
9297 let path = project_path.path.clone();
9298 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9299 let summary = DiagnosticSummary {
9300 error_count: message_summary.error_count as usize,
9301 warning_count: message_summary.warning_count as usize,
9302 };
9303
9304 if summary.is_empty() {
9305 if let Some(worktree_summaries) =
9306 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9307 && let Some(summaries) = worktree_summaries.get_mut(&path)
9308 {
9309 summaries.remove(&server_id);
9310 if summaries.is_empty() {
9311 worktree_summaries.remove(&path);
9312 }
9313 }
9314 } else {
9315 lsp_store
9316 .diagnostic_summaries
9317 .entry(worktree_id)
9318 .or_default()
9319 .entry(path)
9320 .or_default()
9321 .insert(server_id, summary);
9322 }
9323
9324 if let Some((_, project_id)) = &lsp_store.downstream_client {
9325 match &mut diagnostics_summary {
9326 Some(diagnostics_summary) => {
9327 diagnostics_summary
9328 .more_summaries
9329 .push(proto::DiagnosticSummary {
9330 path: project_path.path.as_ref().to_proto(),
9331 language_server_id: server_id.0 as u64,
9332 error_count: summary.error_count as u32,
9333 warning_count: summary.warning_count as u32,
9334 })
9335 }
9336 None => {
9337 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9338 project_id: *project_id,
9339 worktree_id: worktree_id.to_proto(),
9340 summary: Some(proto::DiagnosticSummary {
9341 path: project_path.path.as_ref().to_proto(),
9342 language_server_id: server_id.0 as u64,
9343 error_count: summary.error_count as u32,
9344 warning_count: summary.warning_count as u32,
9345 }),
9346 more_summaries: Vec::new(),
9347 })
9348 }
9349 }
9350 }
9351 updated_diagnostics_paths
9352 .entry(server_id)
9353 .or_insert_with(Vec::new)
9354 .push(project_path);
9355 }
9356
9357 if let Some((diagnostics_summary, (downstream_client, _))) =
9358 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9359 {
9360 downstream_client.send(diagnostics_summary).log_err();
9361 }
9362 for (server_id, paths) in updated_diagnostics_paths {
9363 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9364 }
9365 Ok(())
9366 })
9367 }
9368
9369 async fn handle_start_language_server(
9370 lsp_store: Entity<Self>,
9371 envelope: TypedEnvelope<proto::StartLanguageServer>,
9372 mut cx: AsyncApp,
9373 ) -> Result<()> {
9374 let server = envelope.payload.server.context("invalid server")?;
9375 let server_capabilities =
9376 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9377 .with_context(|| {
9378 format!(
9379 "incorrect server capabilities {}",
9380 envelope.payload.capabilities
9381 )
9382 })?;
9383 lsp_store.update(&mut cx, |lsp_store, cx| {
9384 let server_id = LanguageServerId(server.id as usize);
9385 let server_name = LanguageServerName::from_proto(server.name.clone());
9386 lsp_store
9387 .lsp_server_capabilities
9388 .insert(server_id, server_capabilities);
9389 lsp_store.language_server_statuses.insert(
9390 server_id,
9391 LanguageServerStatus {
9392 name: server_name.clone(),
9393 server_version: None,
9394 pending_work: Default::default(),
9395 has_pending_diagnostic_updates: false,
9396 progress_tokens: Default::default(),
9397 worktree: server.worktree_id.map(WorktreeId::from_proto),
9398 binary: None,
9399 configuration: None,
9400 workspace_folders: BTreeSet::new(),
9401 process_id: None,
9402 },
9403 );
9404 cx.emit(LspStoreEvent::LanguageServerAdded(
9405 server_id,
9406 server_name,
9407 server.worktree_id.map(WorktreeId::from_proto),
9408 ));
9409 cx.notify();
9410 });
9411 Ok(())
9412 }
9413
9414 async fn handle_update_language_server(
9415 lsp_store: Entity<Self>,
9416 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9417 mut cx: AsyncApp,
9418 ) -> Result<()> {
9419 lsp_store.update(&mut cx, |lsp_store, cx| {
9420 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9421
9422 match envelope.payload.variant.context("invalid variant")? {
9423 proto::update_language_server::Variant::WorkStart(payload) => {
9424 lsp_store.on_lsp_work_start(
9425 language_server_id,
9426 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9427 .context("invalid progress token value")?,
9428 LanguageServerProgress {
9429 title: payload.title,
9430 is_disk_based_diagnostics_progress: false,
9431 is_cancellable: payload.is_cancellable.unwrap_or(false),
9432 message: payload.message,
9433 percentage: payload.percentage.map(|p| p as usize),
9434 last_update_at: cx.background_executor().now(),
9435 },
9436 cx,
9437 );
9438 }
9439 proto::update_language_server::Variant::WorkProgress(payload) => {
9440 lsp_store.on_lsp_work_progress(
9441 language_server_id,
9442 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9443 .context("invalid progress token value")?,
9444 LanguageServerProgress {
9445 title: None,
9446 is_disk_based_diagnostics_progress: false,
9447 is_cancellable: payload.is_cancellable.unwrap_or(false),
9448 message: payload.message,
9449 percentage: payload.percentage.map(|p| p as usize),
9450 last_update_at: cx.background_executor().now(),
9451 },
9452 cx,
9453 );
9454 }
9455
9456 proto::update_language_server::Variant::WorkEnd(payload) => {
9457 lsp_store.on_lsp_work_end(
9458 language_server_id,
9459 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9460 .context("invalid progress token value")?,
9461 cx,
9462 );
9463 }
9464
9465 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9466 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9467 }
9468
9469 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9470 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9471 }
9472
9473 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9474 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9475 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9476 cx.emit(LspStoreEvent::LanguageServerUpdate {
9477 language_server_id,
9478 name: envelope
9479 .payload
9480 .server_name
9481 .map(SharedString::new)
9482 .map(LanguageServerName),
9483 message: non_lsp,
9484 });
9485 }
9486 }
9487
9488 Ok(())
9489 })
9490 }
9491
9492 async fn handle_language_server_log(
9493 this: Entity<Self>,
9494 envelope: TypedEnvelope<proto::LanguageServerLog>,
9495 mut cx: AsyncApp,
9496 ) -> Result<()> {
9497 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9498 let log_type = envelope
9499 .payload
9500 .log_type
9501 .map(LanguageServerLogType::from_proto)
9502 .context("invalid language server log type")?;
9503
9504 let message = envelope.payload.message;
9505
9506 this.update(&mut cx, |_, cx| {
9507 cx.emit(LspStoreEvent::LanguageServerLog(
9508 language_server_id,
9509 log_type,
9510 message,
9511 ));
9512 });
9513 Ok(())
9514 }
9515
9516 async fn handle_lsp_ext_cancel_flycheck(
9517 lsp_store: Entity<Self>,
9518 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9519 cx: AsyncApp,
9520 ) -> Result<proto::Ack> {
9521 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9522 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9523 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9524 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9525 } else {
9526 None
9527 }
9528 });
9529 if let Some(task) = task {
9530 task.context("handling lsp ext cancel flycheck")?;
9531 }
9532
9533 Ok(proto::Ack {})
9534 }
9535
9536 async fn handle_lsp_ext_run_flycheck(
9537 lsp_store: Entity<Self>,
9538 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9539 mut cx: AsyncApp,
9540 ) -> Result<proto::Ack> {
9541 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9542 lsp_store.update(&mut cx, |lsp_store, cx| {
9543 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9544 let text_document = if envelope.payload.current_file_only {
9545 let buffer_id = envelope
9546 .payload
9547 .buffer_id
9548 .map(|id| BufferId::new(id))
9549 .transpose()?;
9550 buffer_id
9551 .and_then(|buffer_id| {
9552 lsp_store
9553 .buffer_store()
9554 .read(cx)
9555 .get(buffer_id)
9556 .and_then(|buffer| {
9557 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9558 })
9559 .map(|path| make_text_document_identifier(&path))
9560 })
9561 .transpose()?
9562 } else {
9563 None
9564 };
9565 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9566 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9567 )?;
9568 }
9569 anyhow::Ok(())
9570 })?;
9571
9572 Ok(proto::Ack {})
9573 }
9574
9575 async fn handle_lsp_ext_clear_flycheck(
9576 lsp_store: Entity<Self>,
9577 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9578 cx: AsyncApp,
9579 ) -> Result<proto::Ack> {
9580 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9581 lsp_store.read_with(&cx, |lsp_store, _| {
9582 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9583 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9584 } else {
9585 None
9586 }
9587 });
9588
9589 Ok(proto::Ack {})
9590 }
9591
9592 pub fn disk_based_diagnostics_started(
9593 &mut self,
9594 language_server_id: LanguageServerId,
9595 cx: &mut Context<Self>,
9596 ) {
9597 if let Some(language_server_status) =
9598 self.language_server_statuses.get_mut(&language_server_id)
9599 {
9600 language_server_status.has_pending_diagnostic_updates = true;
9601 }
9602
9603 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9604 cx.emit(LspStoreEvent::LanguageServerUpdate {
9605 language_server_id,
9606 name: self
9607 .language_server_adapter_for_id(language_server_id)
9608 .map(|adapter| adapter.name()),
9609 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9610 Default::default(),
9611 ),
9612 })
9613 }
9614
9615 pub fn disk_based_diagnostics_finished(
9616 &mut self,
9617 language_server_id: LanguageServerId,
9618 cx: &mut Context<Self>,
9619 ) {
9620 if let Some(language_server_status) =
9621 self.language_server_statuses.get_mut(&language_server_id)
9622 {
9623 language_server_status.has_pending_diagnostic_updates = false;
9624 }
9625
9626 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9627 cx.emit(LspStoreEvent::LanguageServerUpdate {
9628 language_server_id,
9629 name: self
9630 .language_server_adapter_for_id(language_server_id)
9631 .map(|adapter| adapter.name()),
9632 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9633 Default::default(),
9634 ),
9635 })
9636 }
9637
9638 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9639 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9640 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9641 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9642 // the language server might take some time to publish diagnostics.
9643 fn simulate_disk_based_diagnostics_events_if_needed(
9644 &mut self,
9645 language_server_id: LanguageServerId,
9646 cx: &mut Context<Self>,
9647 ) {
9648 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9649
9650 let Some(LanguageServerState::Running {
9651 simulate_disk_based_diagnostics_completion,
9652 adapter,
9653 ..
9654 }) = self
9655 .as_local_mut()
9656 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9657 else {
9658 return;
9659 };
9660
9661 if adapter.disk_based_diagnostics_progress_token.is_some() {
9662 return;
9663 }
9664
9665 let prev_task =
9666 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9667 cx.background_executor()
9668 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9669 .await;
9670
9671 this.update(cx, |this, cx| {
9672 this.disk_based_diagnostics_finished(language_server_id, cx);
9673
9674 if let Some(LanguageServerState::Running {
9675 simulate_disk_based_diagnostics_completion,
9676 ..
9677 }) = this.as_local_mut().and_then(|local_store| {
9678 local_store.language_servers.get_mut(&language_server_id)
9679 }) {
9680 *simulate_disk_based_diagnostics_completion = None;
9681 }
9682 })
9683 .ok();
9684 }));
9685
9686 if prev_task.is_none() {
9687 self.disk_based_diagnostics_started(language_server_id, cx);
9688 }
9689 }
9690
9691 pub fn language_server_statuses(
9692 &self,
9693 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9694 self.language_server_statuses
9695 .iter()
9696 .map(|(key, value)| (*key, value))
9697 }
9698
9699 pub(super) fn did_rename_entry(
9700 &self,
9701 worktree_id: WorktreeId,
9702 old_path: &Path,
9703 new_path: &Path,
9704 is_dir: bool,
9705 ) {
9706 maybe!({
9707 let local_store = self.as_local()?;
9708
9709 let old_uri = lsp::Uri::from_file_path(old_path)
9710 .ok()
9711 .map(|uri| uri.to_string())?;
9712 let new_uri = lsp::Uri::from_file_path(new_path)
9713 .ok()
9714 .map(|uri| uri.to_string())?;
9715
9716 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9717 let Some(filter) = local_store
9718 .language_server_paths_watched_for_rename
9719 .get(&language_server.server_id())
9720 else {
9721 continue;
9722 };
9723
9724 if filter.should_send_did_rename(&old_uri, is_dir) {
9725 language_server
9726 .notify::<DidRenameFiles>(RenameFilesParams {
9727 files: vec![FileRename {
9728 old_uri: old_uri.clone(),
9729 new_uri: new_uri.clone(),
9730 }],
9731 })
9732 .ok();
9733 }
9734 }
9735 Some(())
9736 });
9737 }
9738
9739 pub(super) fn will_rename_entry(
9740 this: WeakEntity<Self>,
9741 worktree_id: WorktreeId,
9742 old_path: &Path,
9743 new_path: &Path,
9744 is_dir: bool,
9745 cx: AsyncApp,
9746 ) -> Task<ProjectTransaction> {
9747 let old_uri = lsp::Uri::from_file_path(old_path)
9748 .ok()
9749 .map(|uri| uri.to_string());
9750 let new_uri = lsp::Uri::from_file_path(new_path)
9751 .ok()
9752 .map(|uri| uri.to_string());
9753 cx.spawn(async move |cx| {
9754 let mut tasks = vec![];
9755 this.update(cx, |this, cx| {
9756 let local_store = this.as_local()?;
9757 let old_uri = old_uri?;
9758 let new_uri = new_uri?;
9759 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9760 let Some(filter) = local_store
9761 .language_server_paths_watched_for_rename
9762 .get(&language_server.server_id())
9763 else {
9764 continue;
9765 };
9766
9767 if !filter.should_send_will_rename(&old_uri, is_dir) {
9768 continue;
9769 }
9770 let request_timeout = ProjectSettings::get_global(cx)
9771 .global_lsp_settings
9772 .get_request_timeout();
9773
9774 let apply_edit = cx.spawn({
9775 let old_uri = old_uri.clone();
9776 let new_uri = new_uri.clone();
9777 let language_server = language_server.clone();
9778 async move |this, cx| {
9779 let edit = language_server
9780 .request::<WillRenameFiles>(
9781 RenameFilesParams {
9782 files: vec![FileRename { old_uri, new_uri }],
9783 },
9784 request_timeout,
9785 )
9786 .await
9787 .into_response()
9788 .context("will rename files")
9789 .log_err()
9790 .flatten()?;
9791
9792 LocalLspStore::deserialize_workspace_edit(
9793 this.upgrade()?,
9794 edit,
9795 false,
9796 language_server.clone(),
9797 cx,
9798 )
9799 .await
9800 .ok()
9801 }
9802 });
9803 tasks.push(apply_edit);
9804 }
9805 Some(())
9806 })
9807 .ok()
9808 .flatten();
9809 let mut merged_transaction = ProjectTransaction::default();
9810 for task in tasks {
9811 // Await on tasks sequentially so that the order of application of edits is deterministic
9812 // (at least with regards to the order of registration of language servers)
9813 if let Some(transaction) = task.await {
9814 for (buffer, buffer_transaction) in transaction.0 {
9815 merged_transaction.0.insert(buffer, buffer_transaction);
9816 }
9817 }
9818 }
9819 merged_transaction
9820 })
9821 }
9822
9823 fn lsp_notify_abs_paths_changed(
9824 &mut self,
9825 server_id: LanguageServerId,
9826 changes: Vec<PathEvent>,
9827 ) {
9828 maybe!({
9829 let server = self.language_server_for_id(server_id)?;
9830 let changes = changes
9831 .into_iter()
9832 .filter_map(|event| {
9833 let typ = match event.kind? {
9834 PathEventKind::Created => lsp::FileChangeType::CREATED,
9835 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9836 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9837 };
9838 Some(lsp::FileEvent {
9839 uri: file_path_to_lsp_url(&event.path).log_err()?,
9840 typ,
9841 })
9842 })
9843 .collect::<Vec<_>>();
9844 if !changes.is_empty() {
9845 server
9846 .notify::<lsp::notification::DidChangeWatchedFiles>(
9847 lsp::DidChangeWatchedFilesParams { changes },
9848 )
9849 .ok();
9850 }
9851 Some(())
9852 });
9853 }
9854
9855 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9856 self.as_local()?.language_server_for_id(id)
9857 }
9858
9859 fn on_lsp_progress(
9860 &mut self,
9861 progress_params: lsp::ProgressParams,
9862 language_server_id: LanguageServerId,
9863 disk_based_diagnostics_progress_token: Option<String>,
9864 cx: &mut Context<Self>,
9865 ) {
9866 match progress_params.value {
9867 lsp::ProgressParamsValue::WorkDone(progress) => {
9868 self.handle_work_done_progress(
9869 progress,
9870 language_server_id,
9871 disk_based_diagnostics_progress_token,
9872 ProgressToken::from_lsp(progress_params.token),
9873 cx,
9874 );
9875 }
9876 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9877 let registration_id = match progress_params.token {
9878 lsp::NumberOrString::Number(_) => None,
9879 lsp::NumberOrString::String(token) => token
9880 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9881 .map(|(_, id)| id.to_owned()),
9882 };
9883 if let Some(LanguageServerState::Running {
9884 workspace_diagnostics_refresh_tasks,
9885 ..
9886 }) = self
9887 .as_local_mut()
9888 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9889 && let Some(workspace_diagnostics) =
9890 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9891 {
9892 workspace_diagnostics.progress_tx.try_send(()).ok();
9893 self.apply_workspace_diagnostic_report(
9894 language_server_id,
9895 report,
9896 registration_id.map(SharedString::from),
9897 cx,
9898 )
9899 }
9900 }
9901 }
9902 }
9903
9904 fn handle_work_done_progress(
9905 &mut self,
9906 progress: lsp::WorkDoneProgress,
9907 language_server_id: LanguageServerId,
9908 disk_based_diagnostics_progress_token: Option<String>,
9909 token: ProgressToken,
9910 cx: &mut Context<Self>,
9911 ) {
9912 let language_server_status =
9913 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9914 status
9915 } else {
9916 return;
9917 };
9918
9919 if !language_server_status.progress_tokens.contains(&token) {
9920 return;
9921 }
9922
9923 let is_disk_based_diagnostics_progress =
9924 if let (Some(disk_based_token), ProgressToken::String(token)) =
9925 (&disk_based_diagnostics_progress_token, &token)
9926 {
9927 token.starts_with(disk_based_token)
9928 } else {
9929 false
9930 };
9931
9932 match progress {
9933 lsp::WorkDoneProgress::Begin(report) => {
9934 if is_disk_based_diagnostics_progress {
9935 self.disk_based_diagnostics_started(language_server_id, cx);
9936 }
9937 self.on_lsp_work_start(
9938 language_server_id,
9939 token.clone(),
9940 LanguageServerProgress {
9941 title: Some(report.title),
9942 is_disk_based_diagnostics_progress,
9943 is_cancellable: report.cancellable.unwrap_or(false),
9944 message: report.message.clone(),
9945 percentage: report.percentage.map(|p| p as usize),
9946 last_update_at: cx.background_executor().now(),
9947 },
9948 cx,
9949 );
9950 }
9951 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9952 language_server_id,
9953 token,
9954 LanguageServerProgress {
9955 title: None,
9956 is_disk_based_diagnostics_progress,
9957 is_cancellable: report.cancellable.unwrap_or(false),
9958 message: report.message,
9959 percentage: report.percentage.map(|p| p as usize),
9960 last_update_at: cx.background_executor().now(),
9961 },
9962 cx,
9963 ),
9964 lsp::WorkDoneProgress::End(_) => {
9965 language_server_status.progress_tokens.remove(&token);
9966 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9967 if is_disk_based_diagnostics_progress {
9968 self.disk_based_diagnostics_finished(language_server_id, cx);
9969 }
9970 }
9971 }
9972 }
9973
9974 fn on_lsp_work_start(
9975 &mut self,
9976 language_server_id: LanguageServerId,
9977 token: ProgressToken,
9978 progress: LanguageServerProgress,
9979 cx: &mut Context<Self>,
9980 ) {
9981 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9982 status.pending_work.insert(token.clone(), progress.clone());
9983 cx.notify();
9984 }
9985 cx.emit(LspStoreEvent::LanguageServerUpdate {
9986 language_server_id,
9987 name: self
9988 .language_server_adapter_for_id(language_server_id)
9989 .map(|adapter| adapter.name()),
9990 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9991 token: Some(token.to_proto()),
9992 title: progress.title,
9993 message: progress.message,
9994 percentage: progress.percentage.map(|p| p as u32),
9995 is_cancellable: Some(progress.is_cancellable),
9996 }),
9997 })
9998 }
9999
10000 fn on_lsp_work_progress(
10001 &mut self,
10002 language_server_id: LanguageServerId,
10003 token: ProgressToken,
10004 progress: LanguageServerProgress,
10005 cx: &mut Context<Self>,
10006 ) {
10007 let mut did_update = false;
10008 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10009 match status.pending_work.entry(token.clone()) {
10010 btree_map::Entry::Vacant(entry) => {
10011 entry.insert(progress.clone());
10012 did_update = true;
10013 }
10014 btree_map::Entry::Occupied(mut entry) => {
10015 let entry = entry.get_mut();
10016 if (progress.last_update_at - entry.last_update_at)
10017 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10018 {
10019 entry.last_update_at = progress.last_update_at;
10020 if progress.message.is_some() {
10021 entry.message = progress.message.clone();
10022 }
10023 if progress.percentage.is_some() {
10024 entry.percentage = progress.percentage;
10025 }
10026 if progress.is_cancellable != entry.is_cancellable {
10027 entry.is_cancellable = progress.is_cancellable;
10028 }
10029 did_update = true;
10030 }
10031 }
10032 }
10033 }
10034
10035 if did_update {
10036 cx.emit(LspStoreEvent::LanguageServerUpdate {
10037 language_server_id,
10038 name: self
10039 .language_server_adapter_for_id(language_server_id)
10040 .map(|adapter| adapter.name()),
10041 message: proto::update_language_server::Variant::WorkProgress(
10042 proto::LspWorkProgress {
10043 token: Some(token.to_proto()),
10044 message: progress.message,
10045 percentage: progress.percentage.map(|p| p as u32),
10046 is_cancellable: Some(progress.is_cancellable),
10047 },
10048 ),
10049 })
10050 }
10051 }
10052
10053 fn on_lsp_work_end(
10054 &mut self,
10055 language_server_id: LanguageServerId,
10056 token: ProgressToken,
10057 cx: &mut Context<Self>,
10058 ) {
10059 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10060 if let Some(work) = status.pending_work.remove(&token)
10061 && !work.is_disk_based_diagnostics_progress
10062 {
10063 cx.emit(LspStoreEvent::RefreshInlayHints {
10064 server_id: language_server_id,
10065 request_id: None,
10066 });
10067 }
10068 cx.notify();
10069 }
10070
10071 cx.emit(LspStoreEvent::LanguageServerUpdate {
10072 language_server_id,
10073 name: self
10074 .language_server_adapter_for_id(language_server_id)
10075 .map(|adapter| adapter.name()),
10076 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10077 token: Some(token.to_proto()),
10078 }),
10079 })
10080 }
10081
10082 pub async fn handle_resolve_completion_documentation(
10083 this: Entity<Self>,
10084 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10085 mut cx: AsyncApp,
10086 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10087 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10088
10089 let completion = this
10090 .read_with(&cx, |this, cx| {
10091 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10092 let server = this
10093 .language_server_for_id(id)
10094 .with_context(|| format!("No language server {id}"))?;
10095
10096 let request_timeout = ProjectSettings::get_global(cx)
10097 .global_lsp_settings
10098 .get_request_timeout();
10099
10100 anyhow::Ok(cx.background_spawn(async move {
10101 let can_resolve = server
10102 .capabilities()
10103 .completion_provider
10104 .as_ref()
10105 .and_then(|options| options.resolve_provider)
10106 .unwrap_or(false);
10107 if can_resolve {
10108 server
10109 .request::<lsp::request::ResolveCompletionItem>(
10110 lsp_completion,
10111 request_timeout,
10112 )
10113 .await
10114 .into_response()
10115 .context("resolve completion item")
10116 } else {
10117 anyhow::Ok(lsp_completion)
10118 }
10119 }))
10120 })?
10121 .await?;
10122
10123 let mut documentation_is_markdown = false;
10124 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10125 let documentation = match completion.documentation {
10126 Some(lsp::Documentation::String(text)) => text,
10127
10128 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10129 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10130 value
10131 }
10132
10133 _ => String::new(),
10134 };
10135
10136 // If we have a new buffer_id, that means we're talking to a new client
10137 // and want to check for new text_edits in the completion too.
10138 let mut old_replace_start = None;
10139 let mut old_replace_end = None;
10140 let mut old_insert_start = None;
10141 let mut old_insert_end = None;
10142 let mut new_text = String::default();
10143 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10144 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10145 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10146 anyhow::Ok(buffer.read(cx).snapshot())
10147 })?;
10148
10149 if let Some(text_edit) = completion.text_edit.as_ref() {
10150 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10151
10152 if let Some(mut edit) = edit {
10153 LineEnding::normalize(&mut edit.new_text);
10154
10155 new_text = edit.new_text;
10156 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10157 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10158 if let Some(insert_range) = edit.insert_range {
10159 old_insert_start = Some(serialize_anchor(&insert_range.start));
10160 old_insert_end = Some(serialize_anchor(&insert_range.end));
10161 }
10162 }
10163 }
10164 }
10165
10166 Ok(proto::ResolveCompletionDocumentationResponse {
10167 documentation,
10168 documentation_is_markdown,
10169 old_replace_start,
10170 old_replace_end,
10171 new_text,
10172 lsp_completion,
10173 old_insert_start,
10174 old_insert_end,
10175 })
10176 }
10177
10178 async fn handle_on_type_formatting(
10179 this: Entity<Self>,
10180 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10181 mut cx: AsyncApp,
10182 ) -> Result<proto::OnTypeFormattingResponse> {
10183 let on_type_formatting = this.update(&mut cx, |this, cx| {
10184 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10185 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10186 let position = envelope
10187 .payload
10188 .position
10189 .and_then(deserialize_anchor)
10190 .context("invalid position")?;
10191 anyhow::Ok(this.apply_on_type_formatting(
10192 buffer,
10193 position,
10194 envelope.payload.trigger.clone(),
10195 cx,
10196 ))
10197 })?;
10198
10199 let transaction = on_type_formatting
10200 .await?
10201 .as_ref()
10202 .map(language::proto::serialize_transaction);
10203 Ok(proto::OnTypeFormattingResponse { transaction })
10204 }
10205
10206 async fn handle_pull_workspace_diagnostics(
10207 lsp_store: Entity<Self>,
10208 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10209 mut cx: AsyncApp,
10210 ) -> Result<proto::Ack> {
10211 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10212 lsp_store.update(&mut cx, |lsp_store, _| {
10213 lsp_store.pull_workspace_diagnostics(server_id);
10214 });
10215 Ok(proto::Ack {})
10216 }
10217
10218 async fn handle_open_buffer_for_symbol(
10219 this: Entity<Self>,
10220 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10221 mut cx: AsyncApp,
10222 ) -> Result<proto::OpenBufferForSymbolResponse> {
10223 let peer_id = envelope.original_sender_id().unwrap_or_default();
10224 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10225 let symbol = Self::deserialize_symbol(symbol)?;
10226 this.read_with(&cx, |this, _| {
10227 if let SymbolLocation::OutsideProject {
10228 abs_path,
10229 signature,
10230 } = &symbol.path
10231 {
10232 let new_signature = this.symbol_signature(&abs_path);
10233 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10234 }
10235 Ok(())
10236 })?;
10237 let buffer = this
10238 .update(&mut cx, |this, cx| {
10239 this.open_buffer_for_symbol(
10240 &Symbol {
10241 language_server_name: symbol.language_server_name,
10242 source_worktree_id: symbol.source_worktree_id,
10243 source_language_server_id: symbol.source_language_server_id,
10244 path: symbol.path,
10245 name: symbol.name,
10246 kind: symbol.kind,
10247 range: symbol.range,
10248 label: CodeLabel::default(),
10249 container_name: symbol.container_name,
10250 },
10251 cx,
10252 )
10253 })
10254 .await?;
10255
10256 this.update(&mut cx, |this, cx| {
10257 let is_private = buffer
10258 .read(cx)
10259 .file()
10260 .map(|f| f.is_private())
10261 .unwrap_or_default();
10262 if is_private {
10263 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10264 } else {
10265 this.buffer_store
10266 .update(cx, |buffer_store, cx| {
10267 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10268 })
10269 .detach_and_log_err(cx);
10270 let buffer_id = buffer.read(cx).remote_id().to_proto();
10271 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10272 }
10273 })
10274 }
10275
10276 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10277 let mut hasher = Sha256::new();
10278 hasher.update(abs_path.to_string_lossy().as_bytes());
10279 hasher.update(self.nonce.to_be_bytes());
10280 hasher.finalize().as_slice().try_into().unwrap()
10281 }
10282
10283 pub async fn handle_get_project_symbols(
10284 this: Entity<Self>,
10285 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10286 mut cx: AsyncApp,
10287 ) -> Result<proto::GetProjectSymbolsResponse> {
10288 let symbols = this
10289 .update(&mut cx, |this, cx| {
10290 this.symbols(&envelope.payload.query, cx)
10291 })
10292 .await?;
10293
10294 Ok(proto::GetProjectSymbolsResponse {
10295 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10296 })
10297 }
10298
10299 pub async fn handle_restart_language_servers(
10300 this: Entity<Self>,
10301 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10302 mut cx: AsyncApp,
10303 ) -> Result<proto::Ack> {
10304 this.update(&mut cx, |lsp_store, cx| {
10305 let buffers =
10306 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10307 lsp_store.restart_language_servers_for_buffers(
10308 buffers,
10309 envelope
10310 .payload
10311 .only_servers
10312 .into_iter()
10313 .filter_map(|selector| {
10314 Some(match selector.selector? {
10315 proto::language_server_selector::Selector::ServerId(server_id) => {
10316 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10317 }
10318 proto::language_server_selector::Selector::Name(name) => {
10319 LanguageServerSelector::Name(LanguageServerName(
10320 SharedString::from(name),
10321 ))
10322 }
10323 })
10324 })
10325 .collect(),
10326 cx,
10327 );
10328 });
10329
10330 Ok(proto::Ack {})
10331 }
10332
10333 pub async fn handle_stop_language_servers(
10334 lsp_store: Entity<Self>,
10335 envelope: TypedEnvelope<proto::StopLanguageServers>,
10336 mut cx: AsyncApp,
10337 ) -> Result<proto::Ack> {
10338 lsp_store.update(&mut cx, |lsp_store, cx| {
10339 if envelope.payload.all
10340 && envelope.payload.also_servers.is_empty()
10341 && envelope.payload.buffer_ids.is_empty()
10342 {
10343 lsp_store.stop_all_language_servers(cx);
10344 } else {
10345 let buffers =
10346 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10347 lsp_store
10348 .stop_language_servers_for_buffers(
10349 buffers,
10350 envelope
10351 .payload
10352 .also_servers
10353 .into_iter()
10354 .filter_map(|selector| {
10355 Some(match selector.selector? {
10356 proto::language_server_selector::Selector::ServerId(
10357 server_id,
10358 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10359 server_id,
10360 )),
10361 proto::language_server_selector::Selector::Name(name) => {
10362 LanguageServerSelector::Name(LanguageServerName(
10363 SharedString::from(name),
10364 ))
10365 }
10366 })
10367 })
10368 .collect(),
10369 cx,
10370 )
10371 .detach_and_log_err(cx);
10372 }
10373 });
10374
10375 Ok(proto::Ack {})
10376 }
10377
10378 pub async fn handle_cancel_language_server_work(
10379 lsp_store: Entity<Self>,
10380 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10381 mut cx: AsyncApp,
10382 ) -> Result<proto::Ack> {
10383 lsp_store.update(&mut cx, |lsp_store, cx| {
10384 if let Some(work) = envelope.payload.work {
10385 match work {
10386 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10387 let buffers =
10388 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10389 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10390 }
10391 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10392 let server_id = LanguageServerId::from_proto(work.language_server_id);
10393 let token = work
10394 .token
10395 .map(|token| {
10396 ProgressToken::from_proto(token)
10397 .context("invalid work progress token")
10398 })
10399 .transpose()?;
10400 lsp_store.cancel_language_server_work(server_id, token, cx);
10401 }
10402 }
10403 }
10404 anyhow::Ok(())
10405 })?;
10406
10407 Ok(proto::Ack {})
10408 }
10409
10410 fn buffer_ids_to_buffers(
10411 &mut self,
10412 buffer_ids: impl Iterator<Item = u64>,
10413 cx: &mut Context<Self>,
10414 ) -> Vec<Entity<Buffer>> {
10415 buffer_ids
10416 .into_iter()
10417 .flat_map(|buffer_id| {
10418 self.buffer_store
10419 .read(cx)
10420 .get(BufferId::new(buffer_id).log_err()?)
10421 })
10422 .collect::<Vec<_>>()
10423 }
10424
10425 async fn handle_apply_additional_edits_for_completion(
10426 this: Entity<Self>,
10427 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10428 mut cx: AsyncApp,
10429 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10430 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10431 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10432 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10433 let completion = Self::deserialize_completion(
10434 envelope.payload.completion.context("invalid completion")?,
10435 )?;
10436 let all_commit_ranges = envelope
10437 .payload
10438 .all_commit_ranges
10439 .into_iter()
10440 .map(language::proto::deserialize_anchor_range)
10441 .collect::<Result<Vec<_>, _>>()?;
10442 anyhow::Ok((buffer, completion, all_commit_ranges))
10443 })?;
10444
10445 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10446 this.apply_additional_edits_for_completion(
10447 buffer,
10448 Rc::new(RefCell::new(Box::new([Completion {
10449 replace_range: completion.replace_range,
10450 new_text: completion.new_text,
10451 source: completion.source,
10452 documentation: None,
10453 label: CodeLabel::default(),
10454 match_start: None,
10455 snippet_deduplication_key: None,
10456 insert_text_mode: None,
10457 icon_path: None,
10458 confirm: None,
10459 }]))),
10460 0,
10461 false,
10462 all_commit_ranges,
10463 cx,
10464 )
10465 });
10466
10467 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10468 transaction: apply_additional_edits
10469 .await?
10470 .as_ref()
10471 .map(language::proto::serialize_transaction),
10472 })
10473 }
10474
10475 pub fn last_formatting_failure(&self) -> Option<&str> {
10476 self.last_formatting_failure.as_deref()
10477 }
10478
10479 pub fn reset_last_formatting_failure(&mut self) {
10480 self.last_formatting_failure = None;
10481 }
10482
10483 pub fn environment_for_buffer(
10484 &self,
10485 buffer: &Entity<Buffer>,
10486 cx: &mut Context<Self>,
10487 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10488 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10489 environment.update(cx, |env, cx| {
10490 env.buffer_environment(buffer, &self.worktree_store, cx)
10491 })
10492 } else {
10493 Task::ready(None).shared()
10494 }
10495 }
10496
10497 pub fn format(
10498 &mut self,
10499 buffers: HashSet<Entity<Buffer>>,
10500 target: LspFormatTarget,
10501 push_to_history: bool,
10502 trigger: FormatTrigger,
10503 cx: &mut Context<Self>,
10504 ) -> Task<anyhow::Result<ProjectTransaction>> {
10505 let logger = zlog::scoped!("format");
10506 if self.as_local().is_some() {
10507 zlog::trace!(logger => "Formatting locally");
10508 let logger = zlog::scoped!(logger => "local");
10509 let buffers = buffers
10510 .into_iter()
10511 .map(|buffer_handle| {
10512 let buffer = buffer_handle.read(cx);
10513 let buffer_abs_path = File::from_dyn(buffer.file())
10514 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10515
10516 (buffer_handle, buffer_abs_path, buffer.remote_id())
10517 })
10518 .collect::<Vec<_>>();
10519
10520 cx.spawn(async move |lsp_store, cx| {
10521 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10522
10523 for (handle, abs_path, id) in buffers {
10524 let env = lsp_store
10525 .update(cx, |lsp_store, cx| {
10526 lsp_store.environment_for_buffer(&handle, cx)
10527 })?
10528 .await;
10529
10530 let ranges = match &target {
10531 LspFormatTarget::Buffers => None,
10532 LspFormatTarget::Ranges(ranges) => {
10533 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10534 }
10535 };
10536
10537 formattable_buffers.push(FormattableBuffer {
10538 handle,
10539 abs_path,
10540 env,
10541 ranges,
10542 });
10543 }
10544 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10545
10546 let format_timer = zlog::time!(logger => "Formatting buffers");
10547 let result = LocalLspStore::format_locally(
10548 lsp_store.clone(),
10549 formattable_buffers,
10550 push_to_history,
10551 trigger,
10552 logger,
10553 cx,
10554 )
10555 .await;
10556 format_timer.end();
10557
10558 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10559
10560 lsp_store.update(cx, |lsp_store, _| {
10561 lsp_store.update_last_formatting_failure(&result);
10562 })?;
10563
10564 result
10565 })
10566 } else if let Some((client, project_id)) = self.upstream_client() {
10567 zlog::trace!(logger => "Formatting remotely");
10568 let logger = zlog::scoped!(logger => "remote");
10569
10570 let buffer_ranges = match &target {
10571 LspFormatTarget::Buffers => Vec::new(),
10572 LspFormatTarget::Ranges(ranges) => ranges
10573 .iter()
10574 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10575 buffer_id: buffer_id.to_proto(),
10576 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10577 })
10578 .collect(),
10579 };
10580
10581 let buffer_store = self.buffer_store();
10582 cx.spawn(async move |lsp_store, cx| {
10583 zlog::trace!(logger => "Sending remote format request");
10584 let request_timer = zlog::time!(logger => "remote format request");
10585 let result = client
10586 .request(proto::FormatBuffers {
10587 project_id,
10588 trigger: trigger as i32,
10589 buffer_ids: buffers
10590 .iter()
10591 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10592 .collect(),
10593 buffer_ranges,
10594 })
10595 .await
10596 .and_then(|result| result.transaction.context("missing transaction"));
10597 request_timer.end();
10598
10599 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10600
10601 lsp_store.update(cx, |lsp_store, _| {
10602 lsp_store.update_last_formatting_failure(&result);
10603 })?;
10604
10605 let transaction_response = result?;
10606 let _timer = zlog::time!(logger => "deserializing project transaction");
10607 buffer_store
10608 .update(cx, |buffer_store, cx| {
10609 buffer_store.deserialize_project_transaction(
10610 transaction_response,
10611 push_to_history,
10612 cx,
10613 )
10614 })
10615 .await
10616 })
10617 } else {
10618 zlog::trace!(logger => "Not formatting");
10619 Task::ready(Ok(ProjectTransaction::default()))
10620 }
10621 }
10622
10623 async fn handle_format_buffers(
10624 this: Entity<Self>,
10625 envelope: TypedEnvelope<proto::FormatBuffers>,
10626 mut cx: AsyncApp,
10627 ) -> Result<proto::FormatBuffersResponse> {
10628 let sender_id = envelope.original_sender_id().unwrap_or_default();
10629 let format = this.update(&mut cx, |this, cx| {
10630 let mut buffers = HashSet::default();
10631 for buffer_id in &envelope.payload.buffer_ids {
10632 let buffer_id = BufferId::new(*buffer_id)?;
10633 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10634 }
10635
10636 let target = if envelope.payload.buffer_ranges.is_empty() {
10637 LspFormatTarget::Buffers
10638 } else {
10639 let mut ranges_map = BTreeMap::new();
10640 for buffer_range in &envelope.payload.buffer_ranges {
10641 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10642 let ranges: Result<Vec<_>> = buffer_range
10643 .ranges
10644 .iter()
10645 .map(|range| {
10646 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10647 })
10648 .collect();
10649 ranges_map.insert(buffer_id, ranges?);
10650 }
10651 LspFormatTarget::Ranges(ranges_map)
10652 };
10653
10654 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10655 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10656 })?;
10657
10658 let project_transaction = format.await?;
10659 let project_transaction = this.update(&mut cx, |this, cx| {
10660 this.buffer_store.update(cx, |buffer_store, cx| {
10661 buffer_store.serialize_project_transaction_for_peer(
10662 project_transaction,
10663 sender_id,
10664 cx,
10665 )
10666 })
10667 });
10668 Ok(proto::FormatBuffersResponse {
10669 transaction: Some(project_transaction),
10670 })
10671 }
10672
10673 async fn handle_apply_code_action_kind(
10674 this: Entity<Self>,
10675 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10676 mut cx: AsyncApp,
10677 ) -> Result<proto::ApplyCodeActionKindResponse> {
10678 let sender_id = envelope.original_sender_id().unwrap_or_default();
10679 let format = this.update(&mut cx, |this, cx| {
10680 let mut buffers = HashSet::default();
10681 for buffer_id in &envelope.payload.buffer_ids {
10682 let buffer_id = BufferId::new(*buffer_id)?;
10683 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10684 }
10685 let kind = match envelope.payload.kind.as_str() {
10686 "" => CodeActionKind::EMPTY,
10687 "quickfix" => CodeActionKind::QUICKFIX,
10688 "refactor" => CodeActionKind::REFACTOR,
10689 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10690 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10691 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10692 "source" => CodeActionKind::SOURCE,
10693 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10694 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10695 _ => anyhow::bail!(
10696 "Invalid code action kind {}",
10697 envelope.payload.kind.as_str()
10698 ),
10699 };
10700 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10701 })?;
10702
10703 let project_transaction = format.await?;
10704 let project_transaction = this.update(&mut cx, |this, cx| {
10705 this.buffer_store.update(cx, |buffer_store, cx| {
10706 buffer_store.serialize_project_transaction_for_peer(
10707 project_transaction,
10708 sender_id,
10709 cx,
10710 )
10711 })
10712 });
10713 Ok(proto::ApplyCodeActionKindResponse {
10714 transaction: Some(project_transaction),
10715 })
10716 }
10717
10718 async fn shutdown_language_server(
10719 server_state: Option<LanguageServerState>,
10720 name: LanguageServerName,
10721 cx: &mut AsyncApp,
10722 ) {
10723 let server = match server_state {
10724 Some(LanguageServerState::Starting { startup, .. }) => {
10725 let mut timer = cx
10726 .background_executor()
10727 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10728 .fuse();
10729
10730 select! {
10731 server = startup.fuse() => server,
10732 () = timer => {
10733 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10734 None
10735 },
10736 }
10737 }
10738
10739 Some(LanguageServerState::Running { server, .. }) => Some(server),
10740
10741 None => None,
10742 };
10743
10744 let Some(server) = server else { return };
10745 if let Some(shutdown) = server.shutdown() {
10746 shutdown.await;
10747 }
10748 }
10749
10750 // Returns a list of all of the worktrees which no longer have a language server and the root path
10751 // for the stopped server
10752 fn stop_local_language_server(
10753 &mut self,
10754 server_id: LanguageServerId,
10755 cx: &mut Context<Self>,
10756 ) -> Task<()> {
10757 let local = match &mut self.mode {
10758 LspStoreMode::Local(local) => local,
10759 _ => {
10760 return Task::ready(());
10761 }
10762 };
10763
10764 // Remove this server ID from all entries in the given worktree.
10765 local
10766 .language_server_ids
10767 .retain(|_, state| state.id != server_id);
10768 self.buffer_store.update(cx, |buffer_store, cx| {
10769 for buffer in buffer_store.buffers() {
10770 buffer.update(cx, |buffer, cx| {
10771 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10772 buffer.set_completion_triggers(server_id, Default::default(), cx);
10773 });
10774 }
10775 });
10776
10777 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10778 summaries.retain(|path, summaries_by_server_id| {
10779 if summaries_by_server_id.remove(&server_id).is_some() {
10780 if let Some((client, project_id)) = self.downstream_client.clone() {
10781 client
10782 .send(proto::UpdateDiagnosticSummary {
10783 project_id,
10784 worktree_id: worktree_id.to_proto(),
10785 summary: Some(proto::DiagnosticSummary {
10786 path: path.as_ref().to_proto(),
10787 language_server_id: server_id.0 as u64,
10788 error_count: 0,
10789 warning_count: 0,
10790 }),
10791 more_summaries: Vec::new(),
10792 })
10793 .log_err();
10794 }
10795 !summaries_by_server_id.is_empty()
10796 } else {
10797 true
10798 }
10799 });
10800 }
10801
10802 let local = self.as_local_mut().unwrap();
10803 for diagnostics in local.diagnostics.values_mut() {
10804 diagnostics.retain(|_, diagnostics_by_server_id| {
10805 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10806 diagnostics_by_server_id.remove(ix);
10807 !diagnostics_by_server_id.is_empty()
10808 } else {
10809 true
10810 }
10811 });
10812 }
10813 local.language_server_watched_paths.remove(&server_id);
10814
10815 let server_state = local.language_servers.remove(&server_id);
10816 self.cleanup_lsp_data(server_id);
10817 let name = self
10818 .language_server_statuses
10819 .remove(&server_id)
10820 .map(|status| status.name)
10821 .or_else(|| {
10822 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10823 Some(adapter.name())
10824 } else {
10825 None
10826 }
10827 });
10828
10829 if let Some(name) = name {
10830 log::info!("stopping language server {name}");
10831 self.languages
10832 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10833 cx.notify();
10834
10835 return cx.spawn(async move |lsp_store, cx| {
10836 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10837 lsp_store
10838 .update(cx, |lsp_store, cx| {
10839 lsp_store
10840 .languages
10841 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10842 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10843 cx.notify();
10844 })
10845 .ok();
10846 });
10847 }
10848
10849 if server_state.is_some() {
10850 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10851 }
10852 Task::ready(())
10853 }
10854
10855 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10856 self.shutdown_all_language_servers(cx).detach();
10857 }
10858
10859 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10860 if let Some((client, project_id)) = self.upstream_client() {
10861 let request = client.request(proto::StopLanguageServers {
10862 project_id,
10863 buffer_ids: Vec::new(),
10864 also_servers: Vec::new(),
10865 all: true,
10866 });
10867 cx.background_spawn(async move {
10868 request.await.ok();
10869 })
10870 } else {
10871 let Some(local) = self.as_local_mut() else {
10872 return Task::ready(());
10873 };
10874 let language_servers_to_stop = local
10875 .language_server_ids
10876 .values()
10877 .map(|state| state.id)
10878 .collect();
10879 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10880 let tasks = language_servers_to_stop
10881 .into_iter()
10882 .map(|server| self.stop_local_language_server(server, cx))
10883 .collect::<Vec<_>>();
10884 cx.background_spawn(async move {
10885 futures::future::join_all(tasks).await;
10886 })
10887 }
10888 }
10889
10890 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10891 let buffers = self.buffer_store.read(cx).buffers().collect();
10892 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10893 }
10894
10895 pub fn restart_language_servers_for_buffers(
10896 &mut self,
10897 buffers: Vec<Entity<Buffer>>,
10898 only_restart_servers: HashSet<LanguageServerSelector>,
10899 cx: &mut Context<Self>,
10900 ) {
10901 if let Some((client, project_id)) = self.upstream_client() {
10902 let request = client.request(proto::RestartLanguageServers {
10903 project_id,
10904 buffer_ids: buffers
10905 .into_iter()
10906 .map(|b| b.read(cx).remote_id().to_proto())
10907 .collect(),
10908 only_servers: only_restart_servers
10909 .into_iter()
10910 .map(|selector| {
10911 let selector = match selector {
10912 LanguageServerSelector::Id(language_server_id) => {
10913 proto::language_server_selector::Selector::ServerId(
10914 language_server_id.to_proto(),
10915 )
10916 }
10917 LanguageServerSelector::Name(language_server_name) => {
10918 proto::language_server_selector::Selector::Name(
10919 language_server_name.to_string(),
10920 )
10921 }
10922 };
10923 proto::LanguageServerSelector {
10924 selector: Some(selector),
10925 }
10926 })
10927 .collect(),
10928 all: false,
10929 });
10930 cx.background_spawn(request).detach_and_log_err(cx);
10931 } else {
10932 let stop_task = if only_restart_servers.is_empty() {
10933 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10934 } else {
10935 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10936 };
10937 cx.spawn(async move |lsp_store, cx| {
10938 stop_task.await;
10939 lsp_store.update(cx, |lsp_store, cx| {
10940 for buffer in buffers {
10941 lsp_store.register_buffer_with_language_servers(
10942 &buffer,
10943 only_restart_servers.clone(),
10944 true,
10945 cx,
10946 );
10947 }
10948 })
10949 })
10950 .detach();
10951 }
10952 }
10953
10954 pub fn stop_language_servers_for_buffers(
10955 &mut self,
10956 buffers: Vec<Entity<Buffer>>,
10957 also_stop_servers: HashSet<LanguageServerSelector>,
10958 cx: &mut Context<Self>,
10959 ) -> Task<Result<()>> {
10960 if let Some((client, project_id)) = self.upstream_client() {
10961 let request = client.request(proto::StopLanguageServers {
10962 project_id,
10963 buffer_ids: buffers
10964 .into_iter()
10965 .map(|b| b.read(cx).remote_id().to_proto())
10966 .collect(),
10967 also_servers: also_stop_servers
10968 .into_iter()
10969 .map(|selector| {
10970 let selector = match selector {
10971 LanguageServerSelector::Id(language_server_id) => {
10972 proto::language_server_selector::Selector::ServerId(
10973 language_server_id.to_proto(),
10974 )
10975 }
10976 LanguageServerSelector::Name(language_server_name) => {
10977 proto::language_server_selector::Selector::Name(
10978 language_server_name.to_string(),
10979 )
10980 }
10981 };
10982 proto::LanguageServerSelector {
10983 selector: Some(selector),
10984 }
10985 })
10986 .collect(),
10987 all: false,
10988 });
10989 cx.background_spawn(async move {
10990 let _ = request.await?;
10991 Ok(())
10992 })
10993 } else {
10994 let task =
10995 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10996 cx.background_spawn(async move {
10997 task.await;
10998 Ok(())
10999 })
11000 }
11001 }
11002
11003 fn stop_local_language_servers_for_buffers(
11004 &mut self,
11005 buffers: &[Entity<Buffer>],
11006 also_stop_servers: HashSet<LanguageServerSelector>,
11007 cx: &mut Context<Self>,
11008 ) -> Task<()> {
11009 let Some(local) = self.as_local_mut() else {
11010 return Task::ready(());
11011 };
11012 let mut language_server_names_to_stop = BTreeSet::default();
11013 let mut language_servers_to_stop = also_stop_servers
11014 .into_iter()
11015 .flat_map(|selector| match selector {
11016 LanguageServerSelector::Id(id) => Some(id),
11017 LanguageServerSelector::Name(name) => {
11018 language_server_names_to_stop.insert(name);
11019 None
11020 }
11021 })
11022 .collect::<BTreeSet<_>>();
11023
11024 let mut covered_worktrees = HashSet::default();
11025 for buffer in buffers {
11026 buffer.update(cx, |buffer, cx| {
11027 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11028 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11029 && covered_worktrees.insert(worktree_id)
11030 {
11031 language_server_names_to_stop.retain(|name| {
11032 let old_ids_count = language_servers_to_stop.len();
11033 let all_language_servers_with_this_name = local
11034 .language_server_ids
11035 .iter()
11036 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11037 language_servers_to_stop.extend(all_language_servers_with_this_name);
11038 old_ids_count == language_servers_to_stop.len()
11039 });
11040 }
11041 });
11042 }
11043 for name in language_server_names_to_stop {
11044 language_servers_to_stop.extend(
11045 local
11046 .language_server_ids
11047 .iter()
11048 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11049 );
11050 }
11051
11052 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11053 let tasks = language_servers_to_stop
11054 .into_iter()
11055 .map(|server| self.stop_local_language_server(server, cx))
11056 .collect::<Vec<_>>();
11057
11058 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11059 }
11060
11061 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11062 let (worktree, relative_path) =
11063 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11064
11065 let project_path = ProjectPath {
11066 worktree_id: worktree.read(cx).id(),
11067 path: relative_path,
11068 };
11069
11070 Some(
11071 self.buffer_store()
11072 .read(cx)
11073 .get_by_path(&project_path)?
11074 .read(cx),
11075 )
11076 }
11077
11078 #[cfg(any(test, feature = "test-support"))]
11079 pub fn update_diagnostics(
11080 &mut self,
11081 server_id: LanguageServerId,
11082 diagnostics: lsp::PublishDiagnosticsParams,
11083 result_id: Option<SharedString>,
11084 source_kind: DiagnosticSourceKind,
11085 disk_based_sources: &[String],
11086 cx: &mut Context<Self>,
11087 ) -> Result<()> {
11088 self.merge_lsp_diagnostics(
11089 source_kind,
11090 vec![DocumentDiagnosticsUpdate {
11091 diagnostics,
11092 result_id,
11093 server_id,
11094 disk_based_sources: Cow::Borrowed(disk_based_sources),
11095 registration_id: None,
11096 }],
11097 |_, _, _| false,
11098 cx,
11099 )
11100 }
11101
11102 pub fn merge_lsp_diagnostics(
11103 &mut self,
11104 source_kind: DiagnosticSourceKind,
11105 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11106 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11107 cx: &mut Context<Self>,
11108 ) -> Result<()> {
11109 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11110 let updates = lsp_diagnostics
11111 .into_iter()
11112 .filter_map(|update| {
11113 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11114 Some(DocumentDiagnosticsUpdate {
11115 diagnostics: self.lsp_to_document_diagnostics(
11116 abs_path,
11117 source_kind,
11118 update.server_id,
11119 update.diagnostics,
11120 &update.disk_based_sources,
11121 update.registration_id.clone(),
11122 ),
11123 result_id: update.result_id,
11124 server_id: update.server_id,
11125 disk_based_sources: update.disk_based_sources,
11126 registration_id: update.registration_id,
11127 })
11128 })
11129 .collect();
11130 self.merge_diagnostic_entries(updates, merge, cx)?;
11131 Ok(())
11132 }
11133
11134 fn lsp_to_document_diagnostics(
11135 &mut self,
11136 document_abs_path: PathBuf,
11137 source_kind: DiagnosticSourceKind,
11138 server_id: LanguageServerId,
11139 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11140 disk_based_sources: &[String],
11141 registration_id: Option<SharedString>,
11142 ) -> DocumentDiagnostics {
11143 let mut diagnostics = Vec::default();
11144 let mut primary_diagnostic_group_ids = HashMap::default();
11145 let mut sources_by_group_id = HashMap::default();
11146 let mut supporting_diagnostics = HashMap::default();
11147
11148 let adapter = self.language_server_adapter_for_id(server_id);
11149
11150 // Ensure that primary diagnostics are always the most severe
11151 lsp_diagnostics
11152 .diagnostics
11153 .sort_by_key(|item| item.severity);
11154
11155 for diagnostic in &lsp_diagnostics.diagnostics {
11156 let source = diagnostic.source.as_ref();
11157 let range = range_from_lsp(diagnostic.range);
11158 let is_supporting = diagnostic
11159 .related_information
11160 .as_ref()
11161 .is_some_and(|infos| {
11162 infos.iter().any(|info| {
11163 primary_diagnostic_group_ids.contains_key(&(
11164 source,
11165 diagnostic.code.clone(),
11166 range_from_lsp(info.location.range),
11167 ))
11168 })
11169 });
11170
11171 let is_unnecessary = diagnostic
11172 .tags
11173 .as_ref()
11174 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11175
11176 let underline = self
11177 .language_server_adapter_for_id(server_id)
11178 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11179
11180 if is_supporting {
11181 supporting_diagnostics.insert(
11182 (source, diagnostic.code.clone(), range),
11183 (diagnostic.severity, is_unnecessary),
11184 );
11185 } else {
11186 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11187 let is_disk_based =
11188 source.is_some_and(|source| disk_based_sources.contains(source));
11189
11190 sources_by_group_id.insert(group_id, source);
11191 primary_diagnostic_group_ids
11192 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11193
11194 diagnostics.push(DiagnosticEntry {
11195 range,
11196 diagnostic: Diagnostic {
11197 source: diagnostic.source.clone(),
11198 source_kind,
11199 code: diagnostic.code.clone(),
11200 code_description: diagnostic
11201 .code_description
11202 .as_ref()
11203 .and_then(|d| d.href.clone()),
11204 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11205 markdown: adapter.as_ref().and_then(|adapter| {
11206 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11207 }),
11208 message: diagnostic.message.trim().to_string(),
11209 group_id,
11210 is_primary: true,
11211 is_disk_based,
11212 is_unnecessary,
11213 underline,
11214 data: diagnostic.data.clone(),
11215 registration_id: registration_id.clone(),
11216 },
11217 });
11218 if let Some(infos) = &diagnostic.related_information {
11219 for info in infos {
11220 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11221 let range = range_from_lsp(info.location.range);
11222 diagnostics.push(DiagnosticEntry {
11223 range,
11224 diagnostic: Diagnostic {
11225 source: diagnostic.source.clone(),
11226 source_kind,
11227 code: diagnostic.code.clone(),
11228 code_description: diagnostic
11229 .code_description
11230 .as_ref()
11231 .and_then(|d| d.href.clone()),
11232 severity: DiagnosticSeverity::INFORMATION,
11233 markdown: adapter.as_ref().and_then(|adapter| {
11234 adapter.diagnostic_message_to_markdown(&info.message)
11235 }),
11236 message: info.message.trim().to_string(),
11237 group_id,
11238 is_primary: false,
11239 is_disk_based,
11240 is_unnecessary: false,
11241 underline,
11242 data: diagnostic.data.clone(),
11243 registration_id: registration_id.clone(),
11244 },
11245 });
11246 }
11247 }
11248 }
11249 }
11250 }
11251
11252 for entry in &mut diagnostics {
11253 let diagnostic = &mut entry.diagnostic;
11254 if !diagnostic.is_primary {
11255 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11256 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11257 source,
11258 diagnostic.code.clone(),
11259 entry.range.clone(),
11260 )) {
11261 if let Some(severity) = severity {
11262 diagnostic.severity = severity;
11263 }
11264 diagnostic.is_unnecessary = is_unnecessary;
11265 }
11266 }
11267 }
11268
11269 DocumentDiagnostics {
11270 diagnostics,
11271 document_abs_path,
11272 version: lsp_diagnostics.version,
11273 }
11274 }
11275
11276 fn insert_newly_running_language_server(
11277 &mut self,
11278 adapter: Arc<CachedLspAdapter>,
11279 language_server: Arc<LanguageServer>,
11280 server_id: LanguageServerId,
11281 key: LanguageServerSeed,
11282 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11283 cx: &mut Context<Self>,
11284 ) {
11285 let Some(local) = self.as_local_mut() else {
11286 return;
11287 };
11288 // If the language server for this key doesn't match the server id, don't store the
11289 // server. Which will cause it to be dropped, killing the process
11290 if local
11291 .language_server_ids
11292 .get(&key)
11293 .map(|state| state.id != server_id)
11294 .unwrap_or(false)
11295 {
11296 return;
11297 }
11298
11299 // Update language_servers collection with Running variant of LanguageServerState
11300 // indicating that the server is up and running and ready
11301 let workspace_folders = workspace_folders.lock().clone();
11302 language_server.set_workspace_folders(workspace_folders);
11303
11304 let workspace_diagnostics_refresh_tasks = language_server
11305 .capabilities()
11306 .diagnostic_provider
11307 .and_then(|provider| {
11308 local
11309 .language_server_dynamic_registrations
11310 .entry(server_id)
11311 .or_default()
11312 .diagnostics
11313 .entry(None)
11314 .or_insert(provider.clone());
11315 let workspace_refresher =
11316 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11317
11318 Some((None, workspace_refresher))
11319 })
11320 .into_iter()
11321 .collect();
11322 local.language_servers.insert(
11323 server_id,
11324 LanguageServerState::Running {
11325 workspace_diagnostics_refresh_tasks,
11326 adapter: adapter.clone(),
11327 server: language_server.clone(),
11328 simulate_disk_based_diagnostics_completion: None,
11329 },
11330 );
11331 local
11332 .languages
11333 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11334 if let Some(file_ops_caps) = language_server
11335 .capabilities()
11336 .workspace
11337 .as_ref()
11338 .and_then(|ws| ws.file_operations.as_ref())
11339 {
11340 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11341 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11342 if did_rename_caps.or(will_rename_caps).is_some() {
11343 let watcher = RenamePathsWatchedForServer::default()
11344 .with_did_rename_patterns(did_rename_caps)
11345 .with_will_rename_patterns(will_rename_caps);
11346 local
11347 .language_server_paths_watched_for_rename
11348 .insert(server_id, watcher);
11349 }
11350 }
11351
11352 self.language_server_statuses.insert(
11353 server_id,
11354 LanguageServerStatus {
11355 name: language_server.name(),
11356 server_version: language_server.version(),
11357 pending_work: Default::default(),
11358 has_pending_diagnostic_updates: false,
11359 progress_tokens: Default::default(),
11360 worktree: Some(key.worktree_id),
11361 binary: Some(language_server.binary().clone()),
11362 configuration: Some(language_server.configuration().clone()),
11363 workspace_folders: language_server.workspace_folders(),
11364 process_id: language_server.process_id(),
11365 },
11366 );
11367
11368 cx.emit(LspStoreEvent::LanguageServerAdded(
11369 server_id,
11370 language_server.name(),
11371 Some(key.worktree_id),
11372 ));
11373
11374 let server_capabilities = language_server.capabilities();
11375 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11376 downstream_client
11377 .send(proto::StartLanguageServer {
11378 project_id: *project_id,
11379 server: Some(proto::LanguageServer {
11380 id: server_id.to_proto(),
11381 name: language_server.name().to_string(),
11382 worktree_id: Some(key.worktree_id.to_proto()),
11383 }),
11384 capabilities: serde_json::to_string(&server_capabilities)
11385 .expect("serializing server LSP capabilities"),
11386 })
11387 .log_err();
11388 }
11389 self.lsp_server_capabilities
11390 .insert(server_id, server_capabilities);
11391
11392 // Tell the language server about every open buffer in the worktree that matches the language.
11393 // Also check for buffers in worktrees that reused this server
11394 let mut worktrees_using_server = vec![key.worktree_id];
11395 if let Some(local) = self.as_local() {
11396 // Find all worktrees that have this server in their language server tree
11397 for (worktree_id, servers) in &local.lsp_tree.instances {
11398 if *worktree_id != key.worktree_id {
11399 for server_map in servers.roots.values() {
11400 if server_map
11401 .values()
11402 .any(|(node, _)| node.id() == Some(server_id))
11403 {
11404 worktrees_using_server.push(*worktree_id);
11405 }
11406 }
11407 }
11408 }
11409 }
11410
11411 let mut buffer_paths_registered = Vec::new();
11412 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11413 let mut lsp_adapters = HashMap::default();
11414 for buffer_handle in buffer_store.buffers() {
11415 let buffer = buffer_handle.read(cx);
11416 let file = match File::from_dyn(buffer.file()) {
11417 Some(file) => file,
11418 None => continue,
11419 };
11420 let language = match buffer.language() {
11421 Some(language) => language,
11422 None => continue,
11423 };
11424
11425 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11426 || !lsp_adapters
11427 .entry(language.name())
11428 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11429 .iter()
11430 .any(|a| a.name == key.name)
11431 {
11432 continue;
11433 }
11434 // didOpen
11435 let file = match file.as_local() {
11436 Some(file) => file,
11437 None => continue,
11438 };
11439
11440 let local = self.as_local_mut().unwrap();
11441
11442 let buffer_id = buffer.remote_id();
11443 if local.registered_buffers.contains_key(&buffer_id) {
11444 let abs_path = file.abs_path(cx);
11445 let uri = match lsp::Uri::from_file_path(&abs_path) {
11446 Ok(uri) => uri,
11447 Err(()) => {
11448 log::error!("failed to convert path to URI: {:?}", abs_path);
11449 continue;
11450 }
11451 };
11452
11453 let versions = local
11454 .buffer_snapshots
11455 .entry(buffer_id)
11456 .or_default()
11457 .entry(server_id)
11458 .and_modify(|_| {
11459 assert!(
11460 false,
11461 "There should not be an existing snapshot for a newly inserted buffer"
11462 )
11463 })
11464 .or_insert_with(|| {
11465 vec![LspBufferSnapshot {
11466 version: 0,
11467 snapshot: buffer.text_snapshot(),
11468 }]
11469 });
11470
11471 let snapshot = versions.last().unwrap();
11472 let version = snapshot.version;
11473 let initial_snapshot = &snapshot.snapshot;
11474 language_server.register_buffer(
11475 uri,
11476 adapter.language_id(&language.name()),
11477 version,
11478 initial_snapshot.text(),
11479 );
11480 buffer_paths_registered.push((buffer_id, abs_path));
11481 local
11482 .buffers_opened_in_servers
11483 .entry(buffer_id)
11484 .or_default()
11485 .insert(server_id);
11486 }
11487 buffer_handle.update(cx, |buffer, cx| {
11488 buffer.set_completion_triggers(
11489 server_id,
11490 language_server
11491 .capabilities()
11492 .completion_provider
11493 .as_ref()
11494 .and_then(|provider| {
11495 provider
11496 .trigger_characters
11497 .as_ref()
11498 .map(|characters| characters.iter().cloned().collect())
11499 })
11500 .unwrap_or_default(),
11501 cx,
11502 )
11503 });
11504 }
11505 });
11506
11507 for (buffer_id, abs_path) in buffer_paths_registered {
11508 cx.emit(LspStoreEvent::LanguageServerUpdate {
11509 language_server_id: server_id,
11510 name: Some(adapter.name()),
11511 message: proto::update_language_server::Variant::RegisteredForBuffer(
11512 proto::RegisteredForBuffer {
11513 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11514 buffer_id: buffer_id.to_proto(),
11515 },
11516 ),
11517 });
11518 }
11519
11520 cx.notify();
11521 }
11522
11523 pub fn language_servers_running_disk_based_diagnostics(
11524 &self,
11525 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11526 self.language_server_statuses
11527 .iter()
11528 .filter_map(|(id, status)| {
11529 if status.has_pending_diagnostic_updates {
11530 Some(*id)
11531 } else {
11532 None
11533 }
11534 })
11535 }
11536
11537 pub(crate) fn cancel_language_server_work_for_buffers(
11538 &mut self,
11539 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11540 cx: &mut Context<Self>,
11541 ) {
11542 if let Some((client, project_id)) = self.upstream_client() {
11543 let request = client.request(proto::CancelLanguageServerWork {
11544 project_id,
11545 work: Some(proto::cancel_language_server_work::Work::Buffers(
11546 proto::cancel_language_server_work::Buffers {
11547 buffer_ids: buffers
11548 .into_iter()
11549 .map(|b| b.read(cx).remote_id().to_proto())
11550 .collect(),
11551 },
11552 )),
11553 });
11554 cx.background_spawn(request).detach_and_log_err(cx);
11555 } else if let Some(local) = self.as_local() {
11556 let servers = buffers
11557 .into_iter()
11558 .flat_map(|buffer| {
11559 buffer.update(cx, |buffer, cx| {
11560 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11561 })
11562 })
11563 .collect::<HashSet<_>>();
11564 for server_id in servers {
11565 self.cancel_language_server_work(server_id, None, cx);
11566 }
11567 }
11568 }
11569
11570 pub(crate) fn cancel_language_server_work(
11571 &mut self,
11572 server_id: LanguageServerId,
11573 token_to_cancel: Option<ProgressToken>,
11574 cx: &mut Context<Self>,
11575 ) {
11576 if let Some(local) = self.as_local() {
11577 let status = self.language_server_statuses.get(&server_id);
11578 let server = local.language_servers.get(&server_id);
11579 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11580 {
11581 for (token, progress) in &status.pending_work {
11582 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11583 && token != token_to_cancel
11584 {
11585 continue;
11586 }
11587 if progress.is_cancellable {
11588 server
11589 .notify::<lsp::notification::WorkDoneProgressCancel>(
11590 WorkDoneProgressCancelParams {
11591 token: token.to_lsp(),
11592 },
11593 )
11594 .ok();
11595 }
11596 }
11597 }
11598 } else if let Some((client, project_id)) = self.upstream_client() {
11599 let request = client.request(proto::CancelLanguageServerWork {
11600 project_id,
11601 work: Some(
11602 proto::cancel_language_server_work::Work::LanguageServerWork(
11603 proto::cancel_language_server_work::LanguageServerWork {
11604 language_server_id: server_id.to_proto(),
11605 token: token_to_cancel.map(|token| token.to_proto()),
11606 },
11607 ),
11608 ),
11609 });
11610 cx.background_spawn(request).detach_and_log_err(cx);
11611 }
11612 }
11613
11614 fn register_supplementary_language_server(
11615 &mut self,
11616 id: LanguageServerId,
11617 name: LanguageServerName,
11618 server: Arc<LanguageServer>,
11619 cx: &mut Context<Self>,
11620 ) {
11621 if let Some(local) = self.as_local_mut() {
11622 local
11623 .supplementary_language_servers
11624 .insert(id, (name.clone(), server));
11625 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11626 }
11627 }
11628
11629 fn unregister_supplementary_language_server(
11630 &mut self,
11631 id: LanguageServerId,
11632 cx: &mut Context<Self>,
11633 ) {
11634 if let Some(local) = self.as_local_mut() {
11635 local.supplementary_language_servers.remove(&id);
11636 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11637 }
11638 }
11639
11640 pub(crate) fn supplementary_language_servers(
11641 &self,
11642 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11643 self.as_local().into_iter().flat_map(|local| {
11644 local
11645 .supplementary_language_servers
11646 .iter()
11647 .map(|(id, (name, _))| (*id, name.clone()))
11648 })
11649 }
11650
11651 pub fn language_server_adapter_for_id(
11652 &self,
11653 id: LanguageServerId,
11654 ) -> Option<Arc<CachedLspAdapter>> {
11655 self.as_local()
11656 .and_then(|local| local.language_servers.get(&id))
11657 .and_then(|language_server_state| match language_server_state {
11658 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11659 _ => None,
11660 })
11661 }
11662
11663 pub(super) fn update_local_worktree_language_servers(
11664 &mut self,
11665 worktree_handle: &Entity<Worktree>,
11666 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11667 cx: &mut Context<Self>,
11668 ) {
11669 if changes.is_empty() {
11670 return;
11671 }
11672
11673 let Some(local) = self.as_local() else { return };
11674
11675 local.prettier_store.update(cx, |prettier_store, cx| {
11676 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11677 });
11678
11679 let worktree_id = worktree_handle.read(cx).id();
11680 let mut language_server_ids = local
11681 .language_server_ids
11682 .iter()
11683 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11684 .collect::<Vec<_>>();
11685 language_server_ids.sort();
11686 language_server_ids.dedup();
11687
11688 // let abs_path = worktree_handle.read(cx).abs_path();
11689 for server_id in &language_server_ids {
11690 if let Some(LanguageServerState::Running { server, .. }) =
11691 local.language_servers.get(server_id)
11692 && let Some(watched_paths) = local
11693 .language_server_watched_paths
11694 .get(server_id)
11695 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11696 {
11697 let params = lsp::DidChangeWatchedFilesParams {
11698 changes: changes
11699 .iter()
11700 .filter_map(|(path, _, change)| {
11701 if !watched_paths.is_match(path.as_std_path()) {
11702 return None;
11703 }
11704 let typ = match change {
11705 PathChange::Loaded => return None,
11706 PathChange::Added => lsp::FileChangeType::CREATED,
11707 PathChange::Removed => lsp::FileChangeType::DELETED,
11708 PathChange::Updated => lsp::FileChangeType::CHANGED,
11709 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11710 };
11711 let uri = lsp::Uri::from_file_path(
11712 worktree_handle.read(cx).absolutize(&path),
11713 )
11714 .ok()?;
11715 Some(lsp::FileEvent { uri, typ })
11716 })
11717 .collect(),
11718 };
11719 if !params.changes.is_empty() {
11720 server
11721 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11722 .ok();
11723 }
11724 }
11725 }
11726 for (path, _, _) in changes {
11727 if let Some(file_name) = path.file_name()
11728 && local.watched_manifest_filenames.contains(file_name)
11729 {
11730 self.request_workspace_config_refresh();
11731 break;
11732 }
11733 }
11734 }
11735
11736 pub fn wait_for_remote_buffer(
11737 &mut self,
11738 id: BufferId,
11739 cx: &mut Context<Self>,
11740 ) -> Task<Result<Entity<Buffer>>> {
11741 self.buffer_store.update(cx, |buffer_store, cx| {
11742 buffer_store.wait_for_remote_buffer(id, cx)
11743 })
11744 }
11745
11746 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11747 let mut result = proto::Symbol {
11748 language_server_name: symbol.language_server_name.0.to_string(),
11749 source_worktree_id: symbol.source_worktree_id.to_proto(),
11750 language_server_id: symbol.source_language_server_id.to_proto(),
11751 name: symbol.name.clone(),
11752 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11753 start: Some(proto::PointUtf16 {
11754 row: symbol.range.start.0.row,
11755 column: symbol.range.start.0.column,
11756 }),
11757 end: Some(proto::PointUtf16 {
11758 row: symbol.range.end.0.row,
11759 column: symbol.range.end.0.column,
11760 }),
11761 worktree_id: Default::default(),
11762 path: Default::default(),
11763 signature: Default::default(),
11764 container_name: symbol.container_name.clone(),
11765 };
11766 match &symbol.path {
11767 SymbolLocation::InProject(path) => {
11768 result.worktree_id = path.worktree_id.to_proto();
11769 result.path = path.path.to_proto();
11770 }
11771 SymbolLocation::OutsideProject {
11772 abs_path,
11773 signature,
11774 } => {
11775 result.path = abs_path.to_string_lossy().into_owned();
11776 result.signature = signature.to_vec();
11777 }
11778 }
11779 result
11780 }
11781
11782 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11783 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11784 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11785 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11786
11787 let path = if serialized_symbol.signature.is_empty() {
11788 SymbolLocation::InProject(ProjectPath {
11789 worktree_id,
11790 path: RelPath::from_proto(&serialized_symbol.path)
11791 .context("invalid symbol path")?,
11792 })
11793 } else {
11794 SymbolLocation::OutsideProject {
11795 abs_path: Path::new(&serialized_symbol.path).into(),
11796 signature: serialized_symbol
11797 .signature
11798 .try_into()
11799 .map_err(|_| anyhow!("invalid signature"))?,
11800 }
11801 };
11802
11803 let start = serialized_symbol.start.context("invalid start")?;
11804 let end = serialized_symbol.end.context("invalid end")?;
11805 Ok(CoreSymbol {
11806 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11807 source_worktree_id,
11808 source_language_server_id: LanguageServerId::from_proto(
11809 serialized_symbol.language_server_id,
11810 ),
11811 path,
11812 name: serialized_symbol.name,
11813 range: Unclipped(PointUtf16::new(start.row, start.column))
11814 ..Unclipped(PointUtf16::new(end.row, end.column)),
11815 kind,
11816 container_name: serialized_symbol.container_name,
11817 })
11818 }
11819
11820 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11821 let mut serialized_completion = proto::Completion {
11822 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11823 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11824 new_text: completion.new_text.clone(),
11825 ..proto::Completion::default()
11826 };
11827 match &completion.source {
11828 CompletionSource::Lsp {
11829 insert_range,
11830 server_id,
11831 lsp_completion,
11832 lsp_defaults,
11833 resolved,
11834 } => {
11835 let (old_insert_start, old_insert_end) = insert_range
11836 .as_ref()
11837 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11838 .unzip();
11839
11840 serialized_completion.old_insert_start = old_insert_start;
11841 serialized_completion.old_insert_end = old_insert_end;
11842 serialized_completion.source = proto::completion::Source::Lsp as i32;
11843 serialized_completion.server_id = server_id.0 as u64;
11844 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11845 serialized_completion.lsp_defaults = lsp_defaults
11846 .as_deref()
11847 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11848 serialized_completion.resolved = *resolved;
11849 }
11850 CompletionSource::BufferWord {
11851 word_range,
11852 resolved,
11853 } => {
11854 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11855 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11856 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11857 serialized_completion.resolved = *resolved;
11858 }
11859 CompletionSource::Custom => {
11860 serialized_completion.source = proto::completion::Source::Custom as i32;
11861 serialized_completion.resolved = true;
11862 }
11863 CompletionSource::Dap { sort_text } => {
11864 serialized_completion.source = proto::completion::Source::Dap as i32;
11865 serialized_completion.sort_text = Some(sort_text.clone());
11866 }
11867 }
11868
11869 serialized_completion
11870 }
11871
11872 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11873 let old_replace_start = completion
11874 .old_replace_start
11875 .and_then(deserialize_anchor)
11876 .context("invalid old start")?;
11877 let old_replace_end = completion
11878 .old_replace_end
11879 .and_then(deserialize_anchor)
11880 .context("invalid old end")?;
11881 let insert_range = {
11882 match completion.old_insert_start.zip(completion.old_insert_end) {
11883 Some((start, end)) => {
11884 let start = deserialize_anchor(start).context("invalid insert old start")?;
11885 let end = deserialize_anchor(end).context("invalid insert old end")?;
11886 Some(start..end)
11887 }
11888 None => None,
11889 }
11890 };
11891 Ok(CoreCompletion {
11892 replace_range: old_replace_start..old_replace_end,
11893 new_text: completion.new_text,
11894 source: match proto::completion::Source::from_i32(completion.source) {
11895 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11896 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11897 insert_range,
11898 server_id: LanguageServerId::from_proto(completion.server_id),
11899 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11900 lsp_defaults: completion
11901 .lsp_defaults
11902 .as_deref()
11903 .map(serde_json::from_slice)
11904 .transpose()?,
11905 resolved: completion.resolved,
11906 },
11907 Some(proto::completion::Source::BufferWord) => {
11908 let word_range = completion
11909 .buffer_word_start
11910 .and_then(deserialize_anchor)
11911 .context("invalid buffer word start")?
11912 ..completion
11913 .buffer_word_end
11914 .and_then(deserialize_anchor)
11915 .context("invalid buffer word end")?;
11916 CompletionSource::BufferWord {
11917 word_range,
11918 resolved: completion.resolved,
11919 }
11920 }
11921 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11922 sort_text: completion
11923 .sort_text
11924 .context("expected sort text to exist")?,
11925 },
11926 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11927 },
11928 })
11929 }
11930
11931 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11932 let (kind, lsp_action) = match &action.lsp_action {
11933 LspAction::Action(code_action) => (
11934 proto::code_action::Kind::Action as i32,
11935 serde_json::to_vec(code_action).unwrap(),
11936 ),
11937 LspAction::Command(command) => (
11938 proto::code_action::Kind::Command as i32,
11939 serde_json::to_vec(command).unwrap(),
11940 ),
11941 LspAction::CodeLens(code_lens) => (
11942 proto::code_action::Kind::CodeLens as i32,
11943 serde_json::to_vec(code_lens).unwrap(),
11944 ),
11945 };
11946
11947 proto::CodeAction {
11948 server_id: action.server_id.0 as u64,
11949 start: Some(serialize_anchor(&action.range.start)),
11950 end: Some(serialize_anchor(&action.range.end)),
11951 lsp_action,
11952 kind,
11953 resolved: action.resolved,
11954 }
11955 }
11956
11957 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11958 let start = action
11959 .start
11960 .and_then(deserialize_anchor)
11961 .context("invalid start")?;
11962 let end = action
11963 .end
11964 .and_then(deserialize_anchor)
11965 .context("invalid end")?;
11966 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11967 Some(proto::code_action::Kind::Action) => {
11968 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11969 }
11970 Some(proto::code_action::Kind::Command) => {
11971 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11972 }
11973 Some(proto::code_action::Kind::CodeLens) => {
11974 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11975 }
11976 None => anyhow::bail!("Unknown action kind {}", action.kind),
11977 };
11978 Ok(CodeAction {
11979 server_id: LanguageServerId(action.server_id as usize),
11980 range: start..end,
11981 resolved: action.resolved,
11982 lsp_action,
11983 })
11984 }
11985
11986 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11987 match &formatting_result {
11988 Ok(_) => self.last_formatting_failure = None,
11989 Err(error) => {
11990 let error_string = format!("{error:#}");
11991 log::error!("Formatting failed: {error_string}");
11992 self.last_formatting_failure
11993 .replace(error_string.lines().join(" "));
11994 }
11995 }
11996 }
11997
11998 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11999 self.lsp_server_capabilities.remove(&for_server);
12000 self.semantic_token_config.remove_server_data(for_server);
12001 for lsp_data in self.lsp_data.values_mut() {
12002 lsp_data.remove_server_data(for_server);
12003 }
12004 if let Some(local) = self.as_local_mut() {
12005 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12006 local
12007 .workspace_pull_diagnostics_result_ids
12008 .remove(&for_server);
12009 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12010 buffer_servers.remove(&for_server);
12011 }
12012 }
12013 }
12014
12015 pub fn result_id_for_buffer_pull(
12016 &self,
12017 server_id: LanguageServerId,
12018 buffer_id: BufferId,
12019 registration_id: &Option<SharedString>,
12020 cx: &App,
12021 ) -> Option<SharedString> {
12022 let abs_path = self
12023 .buffer_store
12024 .read(cx)
12025 .get(buffer_id)
12026 .and_then(|b| File::from_dyn(b.read(cx).file()))
12027 .map(|f| f.abs_path(cx))?;
12028 self.as_local()?
12029 .buffer_pull_diagnostics_result_ids
12030 .get(&server_id)?
12031 .get(registration_id)?
12032 .get(&abs_path)?
12033 .clone()
12034 }
12035
12036 /// Gets all result_ids for a workspace diagnostics pull request.
12037 /// 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.
12038 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12039 pub fn result_ids_for_workspace_refresh(
12040 &self,
12041 server_id: LanguageServerId,
12042 registration_id: &Option<SharedString>,
12043 ) -> HashMap<PathBuf, SharedString> {
12044 let Some(local) = self.as_local() else {
12045 return HashMap::default();
12046 };
12047 local
12048 .workspace_pull_diagnostics_result_ids
12049 .get(&server_id)
12050 .into_iter()
12051 .filter_map(|diagnostics| diagnostics.get(registration_id))
12052 .flatten()
12053 .filter_map(|(abs_path, result_id)| {
12054 let result_id = local
12055 .buffer_pull_diagnostics_result_ids
12056 .get(&server_id)
12057 .and_then(|buffer_ids_result_ids| {
12058 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12059 })
12060 .cloned()
12061 .flatten()
12062 .or_else(|| result_id.clone())?;
12063 Some((abs_path.clone(), result_id))
12064 })
12065 .collect()
12066 }
12067
12068 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12069 if let Some(LanguageServerState::Running {
12070 workspace_diagnostics_refresh_tasks,
12071 ..
12072 }) = self
12073 .as_local_mut()
12074 .and_then(|local| local.language_servers.get_mut(&server_id))
12075 {
12076 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12077 diagnostics.refresh_tx.try_send(()).ok();
12078 }
12079 }
12080 }
12081
12082 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12083 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12084 /// which requires refreshing both workspace and document diagnostics.
12085 pub fn pull_document_diagnostics_for_server(
12086 &mut self,
12087 server_id: LanguageServerId,
12088 source_buffer_id: Option<BufferId>,
12089 cx: &mut Context<Self>,
12090 ) -> Shared<Task<()>> {
12091 let Some(local) = self.as_local_mut() else {
12092 return Task::ready(()).shared();
12093 };
12094 let mut buffers_to_refresh = HashSet::default();
12095 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12096 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12097 buffers_to_refresh.insert(*buffer_id);
12098 }
12099 }
12100
12101 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12102 }
12103
12104 pub fn pull_document_diagnostics_for_buffer_edit(
12105 &mut self,
12106 buffer_id: BufferId,
12107 cx: &mut Context<Self>,
12108 ) {
12109 let Some(local) = self.as_local_mut() else {
12110 return;
12111 };
12112 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12113 else {
12114 return;
12115 };
12116 for server_id in languages_servers {
12117 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12118 }
12119 }
12120
12121 fn apply_workspace_diagnostic_report(
12122 &mut self,
12123 server_id: LanguageServerId,
12124 report: lsp::WorkspaceDiagnosticReportResult,
12125 registration_id: Option<SharedString>,
12126 cx: &mut Context<Self>,
12127 ) {
12128 let mut workspace_diagnostics =
12129 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12130 report,
12131 server_id,
12132 registration_id,
12133 );
12134 workspace_diagnostics.retain(|d| match &d.diagnostics {
12135 LspPullDiagnostics::Response {
12136 server_id,
12137 registration_id,
12138 ..
12139 } => self.diagnostic_registration_exists(*server_id, registration_id),
12140 LspPullDiagnostics::Default => false,
12141 });
12142 let mut unchanged_buffers = HashMap::default();
12143 let workspace_diagnostics_updates = workspace_diagnostics
12144 .into_iter()
12145 .filter_map(
12146 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12147 LspPullDiagnostics::Response {
12148 server_id,
12149 uri,
12150 diagnostics,
12151 registration_id,
12152 } => Some((
12153 server_id,
12154 uri,
12155 diagnostics,
12156 workspace_diagnostics.version,
12157 registration_id,
12158 )),
12159 LspPullDiagnostics::Default => None,
12160 },
12161 )
12162 .fold(
12163 HashMap::default(),
12164 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12165 let (result_id, diagnostics) = match diagnostics {
12166 PulledDiagnostics::Unchanged { result_id } => {
12167 unchanged_buffers
12168 .entry(new_registration_id.clone())
12169 .or_insert_with(HashSet::default)
12170 .insert(uri.clone());
12171 (Some(result_id), Vec::new())
12172 }
12173 PulledDiagnostics::Changed {
12174 result_id,
12175 diagnostics,
12176 } => (result_id, diagnostics),
12177 };
12178 let disk_based_sources = Cow::Owned(
12179 self.language_server_adapter_for_id(server_id)
12180 .as_ref()
12181 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12182 .unwrap_or(&[])
12183 .to_vec(),
12184 );
12185
12186 let Some(abs_path) = uri.to_file_path().ok() else {
12187 return acc;
12188 };
12189 let Some((worktree, relative_path)) =
12190 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12191 else {
12192 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12193 return acc;
12194 };
12195 let worktree_id = worktree.read(cx).id();
12196 let project_path = ProjectPath {
12197 worktree_id,
12198 path: relative_path,
12199 };
12200 if let Some(local_lsp_store) = self.as_local_mut() {
12201 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12202 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12203 }
12204 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12205 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12206 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12207 acc.entry(server_id)
12208 .or_insert_with(HashMap::default)
12209 .entry(new_registration_id.clone())
12210 .or_insert_with(Vec::new)
12211 .push(DocumentDiagnosticsUpdate {
12212 server_id,
12213 diagnostics: lsp::PublishDiagnosticsParams {
12214 uri,
12215 diagnostics,
12216 version,
12217 },
12218 result_id: result_id.map(SharedString::new),
12219 disk_based_sources,
12220 registration_id: new_registration_id,
12221 });
12222 }
12223 acc
12224 },
12225 );
12226
12227 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12228 for (registration_id, diagnostic_updates) in diagnostic_updates {
12229 self.merge_lsp_diagnostics(
12230 DiagnosticSourceKind::Pulled,
12231 diagnostic_updates,
12232 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12233 DiagnosticSourceKind::Pulled => {
12234 old_diagnostic.registration_id != registration_id
12235 || unchanged_buffers
12236 .get(&old_diagnostic.registration_id)
12237 .is_some_and(|unchanged_buffers| {
12238 unchanged_buffers.contains(&document_uri)
12239 })
12240 }
12241 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12242 },
12243 cx,
12244 )
12245 .log_err();
12246 }
12247 }
12248 }
12249
12250 fn register_server_capabilities(
12251 &mut self,
12252 server_id: LanguageServerId,
12253 params: lsp::RegistrationParams,
12254 cx: &mut Context<Self>,
12255 ) -> anyhow::Result<()> {
12256 let server = self
12257 .language_server_for_id(server_id)
12258 .with_context(|| format!("no server {server_id} found"))?;
12259 for reg in params.registrations {
12260 match reg.method.as_str() {
12261 "workspace/didChangeWatchedFiles" => {
12262 if let Some(options) = reg.register_options {
12263 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12264 let caps = serde_json::from_value(options)?;
12265 local_lsp_store
12266 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12267 true
12268 } else {
12269 false
12270 };
12271 if notify {
12272 notify_server_capabilities_updated(&server, cx);
12273 }
12274 }
12275 }
12276 "workspace/didChangeConfiguration" => {
12277 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12278 }
12279 "workspace/didChangeWorkspaceFolders" => {
12280 // In this case register options is an empty object, we can ignore it
12281 let caps = lsp::WorkspaceFoldersServerCapabilities {
12282 supported: Some(true),
12283 change_notifications: Some(OneOf::Right(reg.id)),
12284 };
12285 server.update_capabilities(|capabilities| {
12286 capabilities
12287 .workspace
12288 .get_or_insert_default()
12289 .workspace_folders = Some(caps);
12290 });
12291 notify_server_capabilities_updated(&server, cx);
12292 }
12293 "workspace/symbol" => {
12294 let options = parse_register_capabilities(reg)?;
12295 server.update_capabilities(|capabilities| {
12296 capabilities.workspace_symbol_provider = Some(options);
12297 });
12298 notify_server_capabilities_updated(&server, cx);
12299 }
12300 "workspace/fileOperations" => {
12301 if let Some(options) = reg.register_options {
12302 let caps = serde_json::from_value(options)?;
12303 server.update_capabilities(|capabilities| {
12304 capabilities
12305 .workspace
12306 .get_or_insert_default()
12307 .file_operations = Some(caps);
12308 });
12309 notify_server_capabilities_updated(&server, cx);
12310 }
12311 }
12312 "workspace/executeCommand" => {
12313 if let Some(options) = reg.register_options {
12314 let options = serde_json::from_value(options)?;
12315 server.update_capabilities(|capabilities| {
12316 capabilities.execute_command_provider = Some(options);
12317 });
12318 notify_server_capabilities_updated(&server, cx);
12319 }
12320 }
12321 "textDocument/rangeFormatting" => {
12322 let options = parse_register_capabilities(reg)?;
12323 server.update_capabilities(|capabilities| {
12324 capabilities.document_range_formatting_provider = Some(options);
12325 });
12326 notify_server_capabilities_updated(&server, cx);
12327 }
12328 "textDocument/onTypeFormatting" => {
12329 if let Some(options) = reg
12330 .register_options
12331 .map(serde_json::from_value)
12332 .transpose()?
12333 {
12334 server.update_capabilities(|capabilities| {
12335 capabilities.document_on_type_formatting_provider = Some(options);
12336 });
12337 notify_server_capabilities_updated(&server, cx);
12338 }
12339 }
12340 "textDocument/formatting" => {
12341 let options = parse_register_capabilities(reg)?;
12342 server.update_capabilities(|capabilities| {
12343 capabilities.document_formatting_provider = Some(options);
12344 });
12345 notify_server_capabilities_updated(&server, cx);
12346 }
12347 "textDocument/rename" => {
12348 let options = parse_register_capabilities(reg)?;
12349 server.update_capabilities(|capabilities| {
12350 capabilities.rename_provider = Some(options);
12351 });
12352 notify_server_capabilities_updated(&server, cx);
12353 }
12354 "textDocument/inlayHint" => {
12355 let options = parse_register_capabilities(reg)?;
12356 server.update_capabilities(|capabilities| {
12357 capabilities.inlay_hint_provider = Some(options);
12358 });
12359 notify_server_capabilities_updated(&server, cx);
12360 }
12361 "textDocument/documentSymbol" => {
12362 let options = parse_register_capabilities(reg)?;
12363 server.update_capabilities(|capabilities| {
12364 capabilities.document_symbol_provider = Some(options);
12365 });
12366 notify_server_capabilities_updated(&server, cx);
12367 }
12368 "textDocument/codeAction" => {
12369 let options = parse_register_capabilities(reg)?;
12370 let provider = match options {
12371 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12372 OneOf::Right(caps) => caps,
12373 };
12374 server.update_capabilities(|capabilities| {
12375 capabilities.code_action_provider = Some(provider);
12376 });
12377 notify_server_capabilities_updated(&server, cx);
12378 }
12379 "textDocument/definition" => {
12380 let options = parse_register_capabilities(reg)?;
12381 server.update_capabilities(|capabilities| {
12382 capabilities.definition_provider = Some(options);
12383 });
12384 notify_server_capabilities_updated(&server, cx);
12385 }
12386 "textDocument/completion" => {
12387 if let Some(caps) = reg
12388 .register_options
12389 .map(serde_json::from_value::<CompletionOptions>)
12390 .transpose()?
12391 {
12392 server.update_capabilities(|capabilities| {
12393 capabilities.completion_provider = Some(caps.clone());
12394 });
12395
12396 if let Some(local) = self.as_local() {
12397 let mut buffers_with_language_server = Vec::new();
12398 for handle in self.buffer_store.read(cx).buffers() {
12399 let buffer_id = handle.read(cx).remote_id();
12400 if local
12401 .buffers_opened_in_servers
12402 .get(&buffer_id)
12403 .filter(|s| s.contains(&server_id))
12404 .is_some()
12405 {
12406 buffers_with_language_server.push(handle);
12407 }
12408 }
12409 let triggers = caps
12410 .trigger_characters
12411 .unwrap_or_default()
12412 .into_iter()
12413 .collect::<BTreeSet<_>>();
12414 for handle in buffers_with_language_server {
12415 let triggers = triggers.clone();
12416 let _ = handle.update(cx, move |buffer, cx| {
12417 buffer.set_completion_triggers(server_id, triggers, cx);
12418 });
12419 }
12420 }
12421 notify_server_capabilities_updated(&server, cx);
12422 }
12423 }
12424 "textDocument/hover" => {
12425 let options = parse_register_capabilities(reg)?;
12426 let provider = match options {
12427 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12428 OneOf::Right(caps) => caps,
12429 };
12430 server.update_capabilities(|capabilities| {
12431 capabilities.hover_provider = Some(provider);
12432 });
12433 notify_server_capabilities_updated(&server, cx);
12434 }
12435 "textDocument/signatureHelp" => {
12436 if let Some(caps) = reg
12437 .register_options
12438 .map(serde_json::from_value)
12439 .transpose()?
12440 {
12441 server.update_capabilities(|capabilities| {
12442 capabilities.signature_help_provider = Some(caps);
12443 });
12444 notify_server_capabilities_updated(&server, cx);
12445 }
12446 }
12447 "textDocument/didChange" => {
12448 if let Some(sync_kind) = reg
12449 .register_options
12450 .and_then(|opts| opts.get("syncKind").cloned())
12451 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12452 .transpose()?
12453 {
12454 server.update_capabilities(|capabilities| {
12455 let mut sync_options =
12456 Self::take_text_document_sync_options(capabilities);
12457 sync_options.change = Some(sync_kind);
12458 capabilities.text_document_sync =
12459 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12460 });
12461 notify_server_capabilities_updated(&server, cx);
12462 }
12463 }
12464 "textDocument/didSave" => {
12465 if let Some(include_text) = reg
12466 .register_options
12467 .map(|opts| {
12468 let transpose = opts
12469 .get("includeText")
12470 .cloned()
12471 .map(serde_json::from_value::<Option<bool>>)
12472 .transpose();
12473 match transpose {
12474 Ok(value) => Ok(value.flatten()),
12475 Err(e) => Err(e),
12476 }
12477 })
12478 .transpose()?
12479 {
12480 server.update_capabilities(|capabilities| {
12481 let mut sync_options =
12482 Self::take_text_document_sync_options(capabilities);
12483 sync_options.save =
12484 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12485 include_text,
12486 }));
12487 capabilities.text_document_sync =
12488 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12489 });
12490 notify_server_capabilities_updated(&server, cx);
12491 }
12492 }
12493 "textDocument/codeLens" => {
12494 if let Some(caps) = reg
12495 .register_options
12496 .map(serde_json::from_value)
12497 .transpose()?
12498 {
12499 server.update_capabilities(|capabilities| {
12500 capabilities.code_lens_provider = Some(caps);
12501 });
12502 notify_server_capabilities_updated(&server, cx);
12503 }
12504 }
12505 "textDocument/diagnostic" => {
12506 if let Some(caps) = reg
12507 .register_options
12508 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12509 .transpose()?
12510 {
12511 let local = self
12512 .as_local_mut()
12513 .context("Expected LSP Store to be local")?;
12514 let state = local
12515 .language_servers
12516 .get_mut(&server_id)
12517 .context("Could not obtain Language Servers state")?;
12518 local
12519 .language_server_dynamic_registrations
12520 .entry(server_id)
12521 .or_default()
12522 .diagnostics
12523 .insert(Some(reg.id.clone()), caps.clone());
12524
12525 let supports_workspace_diagnostics =
12526 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12527 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12528 diagnostic_options.workspace_diagnostics
12529 }
12530 DiagnosticServerCapabilities::RegistrationOptions(
12531 diagnostic_registration_options,
12532 ) => {
12533 diagnostic_registration_options
12534 .diagnostic_options
12535 .workspace_diagnostics
12536 }
12537 };
12538
12539 if supports_workspace_diagnostics(&caps) {
12540 if let LanguageServerState::Running {
12541 workspace_diagnostics_refresh_tasks,
12542 ..
12543 } = state
12544 && let Some(task) = lsp_workspace_diagnostics_refresh(
12545 Some(reg.id.clone()),
12546 caps.clone(),
12547 server.clone(),
12548 cx,
12549 )
12550 {
12551 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12552 }
12553 }
12554
12555 server.update_capabilities(|capabilities| {
12556 capabilities.diagnostic_provider = Some(caps);
12557 });
12558
12559 notify_server_capabilities_updated(&server, cx);
12560
12561 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12562 }
12563 }
12564 "textDocument/documentColor" => {
12565 let options = parse_register_capabilities(reg)?;
12566 let provider = match options {
12567 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12568 OneOf::Right(caps) => caps,
12569 };
12570 server.update_capabilities(|capabilities| {
12571 capabilities.color_provider = Some(provider);
12572 });
12573 notify_server_capabilities_updated(&server, cx);
12574 }
12575 "textDocument/foldingRange" => {
12576 let options = parse_register_capabilities(reg)?;
12577 let provider = match options {
12578 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12579 OneOf::Right(caps) => caps,
12580 };
12581 server.update_capabilities(|capabilities| {
12582 capabilities.folding_range_provider = Some(provider);
12583 });
12584 notify_server_capabilities_updated(&server, cx);
12585 }
12586 _ => log::warn!("unhandled capability registration: {reg:?}"),
12587 }
12588 }
12589
12590 Ok(())
12591 }
12592
12593 fn unregister_server_capabilities(
12594 &mut self,
12595 server_id: LanguageServerId,
12596 params: lsp::UnregistrationParams,
12597 cx: &mut Context<Self>,
12598 ) -> anyhow::Result<()> {
12599 let server = self
12600 .language_server_for_id(server_id)
12601 .with_context(|| format!("no server {server_id} found"))?;
12602 for unreg in params.unregisterations.iter() {
12603 match unreg.method.as_str() {
12604 "workspace/didChangeWatchedFiles" => {
12605 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12606 local_lsp_store
12607 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12608 true
12609 } else {
12610 false
12611 };
12612 if notify {
12613 notify_server_capabilities_updated(&server, cx);
12614 }
12615 }
12616 "workspace/didChangeConfiguration" => {
12617 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12618 }
12619 "workspace/didChangeWorkspaceFolders" => {
12620 server.update_capabilities(|capabilities| {
12621 capabilities
12622 .workspace
12623 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12624 workspace_folders: None,
12625 file_operations: None,
12626 })
12627 .workspace_folders = None;
12628 });
12629 notify_server_capabilities_updated(&server, cx);
12630 }
12631 "workspace/symbol" => {
12632 server.update_capabilities(|capabilities| {
12633 capabilities.workspace_symbol_provider = None
12634 });
12635 notify_server_capabilities_updated(&server, cx);
12636 }
12637 "workspace/fileOperations" => {
12638 server.update_capabilities(|capabilities| {
12639 capabilities
12640 .workspace
12641 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12642 workspace_folders: None,
12643 file_operations: None,
12644 })
12645 .file_operations = None;
12646 });
12647 notify_server_capabilities_updated(&server, cx);
12648 }
12649 "workspace/executeCommand" => {
12650 server.update_capabilities(|capabilities| {
12651 capabilities.execute_command_provider = None;
12652 });
12653 notify_server_capabilities_updated(&server, cx);
12654 }
12655 "textDocument/rangeFormatting" => {
12656 server.update_capabilities(|capabilities| {
12657 capabilities.document_range_formatting_provider = None
12658 });
12659 notify_server_capabilities_updated(&server, cx);
12660 }
12661 "textDocument/onTypeFormatting" => {
12662 server.update_capabilities(|capabilities| {
12663 capabilities.document_on_type_formatting_provider = None;
12664 });
12665 notify_server_capabilities_updated(&server, cx);
12666 }
12667 "textDocument/formatting" => {
12668 server.update_capabilities(|capabilities| {
12669 capabilities.document_formatting_provider = None;
12670 });
12671 notify_server_capabilities_updated(&server, cx);
12672 }
12673 "textDocument/rename" => {
12674 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12675 notify_server_capabilities_updated(&server, cx);
12676 }
12677 "textDocument/codeAction" => {
12678 server.update_capabilities(|capabilities| {
12679 capabilities.code_action_provider = None;
12680 });
12681 notify_server_capabilities_updated(&server, cx);
12682 }
12683 "textDocument/definition" => {
12684 server.update_capabilities(|capabilities| {
12685 capabilities.definition_provider = None;
12686 });
12687 notify_server_capabilities_updated(&server, cx);
12688 }
12689 "textDocument/completion" => {
12690 server.update_capabilities(|capabilities| {
12691 capabilities.completion_provider = None;
12692 });
12693 notify_server_capabilities_updated(&server, cx);
12694 }
12695 "textDocument/hover" => {
12696 server.update_capabilities(|capabilities| {
12697 capabilities.hover_provider = None;
12698 });
12699 notify_server_capabilities_updated(&server, cx);
12700 }
12701 "textDocument/signatureHelp" => {
12702 server.update_capabilities(|capabilities| {
12703 capabilities.signature_help_provider = None;
12704 });
12705 notify_server_capabilities_updated(&server, cx);
12706 }
12707 "textDocument/didChange" => {
12708 server.update_capabilities(|capabilities| {
12709 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12710 sync_options.change = None;
12711 capabilities.text_document_sync =
12712 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12713 });
12714 notify_server_capabilities_updated(&server, cx);
12715 }
12716 "textDocument/didSave" => {
12717 server.update_capabilities(|capabilities| {
12718 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12719 sync_options.save = None;
12720 capabilities.text_document_sync =
12721 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12722 });
12723 notify_server_capabilities_updated(&server, cx);
12724 }
12725 "textDocument/codeLens" => {
12726 server.update_capabilities(|capabilities| {
12727 capabilities.code_lens_provider = None;
12728 });
12729 notify_server_capabilities_updated(&server, cx);
12730 }
12731 "textDocument/diagnostic" => {
12732 let local = self
12733 .as_local_mut()
12734 .context("Expected LSP Store to be local")?;
12735
12736 let state = local
12737 .language_servers
12738 .get_mut(&server_id)
12739 .context("Could not obtain Language Servers state")?;
12740 let registrations = local
12741 .language_server_dynamic_registrations
12742 .get_mut(&server_id)
12743 .with_context(|| {
12744 format!("Expected dynamic registration to exist for server {server_id}")
12745 })?;
12746 registrations.diagnostics
12747 .remove(&Some(unreg.id.clone()))
12748 .with_context(|| format!(
12749 "Attempted to unregister non-existent diagnostic registration with ID {}",
12750 unreg.id)
12751 )?;
12752 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12753
12754 if let LanguageServerState::Running {
12755 workspace_diagnostics_refresh_tasks,
12756 ..
12757 } = state
12758 {
12759 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12760 }
12761
12762 self.clear_unregistered_diagnostics(
12763 server_id,
12764 SharedString::from(unreg.id.clone()),
12765 cx,
12766 )?;
12767
12768 if removed_last_diagnostic_provider {
12769 server.update_capabilities(|capabilities| {
12770 debug_assert!(capabilities.diagnostic_provider.is_some());
12771 capabilities.diagnostic_provider = None;
12772 });
12773 }
12774
12775 notify_server_capabilities_updated(&server, cx);
12776 }
12777 "textDocument/documentColor" => {
12778 server.update_capabilities(|capabilities| {
12779 capabilities.color_provider = None;
12780 });
12781 notify_server_capabilities_updated(&server, cx);
12782 }
12783 "textDocument/foldingRange" => {
12784 server.update_capabilities(|capabilities| {
12785 capabilities.folding_range_provider = None;
12786 });
12787 notify_server_capabilities_updated(&server, cx);
12788 }
12789 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12790 }
12791 }
12792
12793 Ok(())
12794 }
12795
12796 fn clear_unregistered_diagnostics(
12797 &mut self,
12798 server_id: LanguageServerId,
12799 cleared_registration_id: SharedString,
12800 cx: &mut Context<Self>,
12801 ) -> anyhow::Result<()> {
12802 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12803
12804 self.buffer_store.update(cx, |buffer_store, cx| {
12805 for buffer_handle in buffer_store.buffers() {
12806 let buffer = buffer_handle.read(cx);
12807 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12808 let Some(abs_path) = abs_path else {
12809 continue;
12810 };
12811 affected_abs_paths.insert(abs_path);
12812 }
12813 });
12814
12815 let local = self.as_local().context("Expected LSP Store to be local")?;
12816 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12817 let Some(worktree) = self
12818 .worktree_store
12819 .read(cx)
12820 .worktree_for_id(*worktree_id, cx)
12821 else {
12822 continue;
12823 };
12824
12825 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12826 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12827 let has_matching_registration =
12828 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12829 entry.diagnostic.registration_id.as_ref()
12830 == Some(&cleared_registration_id)
12831 });
12832 if has_matching_registration {
12833 let abs_path = worktree.read(cx).absolutize(rel_path);
12834 affected_abs_paths.insert(abs_path);
12835 }
12836 }
12837 }
12838 }
12839
12840 if affected_abs_paths.is_empty() {
12841 return Ok(());
12842 }
12843
12844 // Send a fake diagnostic update which clears the state for the registration ID
12845 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12846 affected_abs_paths
12847 .into_iter()
12848 .map(|abs_path| DocumentDiagnosticsUpdate {
12849 diagnostics: DocumentDiagnostics {
12850 diagnostics: Vec::new(),
12851 document_abs_path: abs_path,
12852 version: None,
12853 },
12854 result_id: None,
12855 registration_id: Some(cleared_registration_id.clone()),
12856 server_id,
12857 disk_based_sources: Cow::Borrowed(&[]),
12858 })
12859 .collect();
12860
12861 let merge_registration_id = cleared_registration_id.clone();
12862 self.merge_diagnostic_entries(
12863 clears,
12864 move |_, diagnostic, _| {
12865 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12866 diagnostic.registration_id != Some(merge_registration_id.clone())
12867 } else {
12868 true
12869 }
12870 },
12871 cx,
12872 )?;
12873
12874 Ok(())
12875 }
12876
12877 async fn deduplicate_range_based_lsp_requests<T>(
12878 lsp_store: &Entity<Self>,
12879 server_id: Option<LanguageServerId>,
12880 lsp_request_id: LspRequestId,
12881 proto_request: &T::ProtoRequest,
12882 range: Range<Anchor>,
12883 cx: &mut AsyncApp,
12884 ) -> Result<()>
12885 where
12886 T: LspCommand,
12887 T::ProtoRequest: proto::LspRequestMessage,
12888 {
12889 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12890 let version = deserialize_version(proto_request.buffer_version());
12891 let buffer = lsp_store.update(cx, |this, cx| {
12892 this.buffer_store.read(cx).get_existing(buffer_id)
12893 })?;
12894 buffer
12895 .update(cx, |buffer, _| buffer.wait_for_version(version))
12896 .await?;
12897 lsp_store.update(cx, |lsp_store, cx| {
12898 let buffer_snapshot = buffer.read(cx).snapshot();
12899 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12900 let chunks_queried_for = lsp_data
12901 .inlay_hints
12902 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12903 .collect::<Vec<_>>();
12904 match chunks_queried_for.as_slice() {
12905 &[chunk] => {
12906 let key = LspKey {
12907 request_type: TypeId::of::<T>(),
12908 server_queried: server_id,
12909 };
12910 let previous_request = lsp_data
12911 .chunk_lsp_requests
12912 .entry(key)
12913 .or_default()
12914 .insert(chunk, lsp_request_id);
12915 if let Some((previous_request, running_requests)) =
12916 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12917 {
12918 running_requests.remove(&previous_request);
12919 }
12920 }
12921 _ambiguous_chunks => {
12922 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12923 // there, a buffer version-based check will be performed and outdated requests discarded.
12924 }
12925 }
12926 anyhow::Ok(())
12927 })?;
12928
12929 Ok(())
12930 }
12931
12932 async fn query_lsp_locally<T>(
12933 lsp_store: Entity<Self>,
12934 for_server_id: Option<LanguageServerId>,
12935 sender_id: proto::PeerId,
12936 lsp_request_id: LspRequestId,
12937 proto_request: T::ProtoRequest,
12938 position: Option<Anchor>,
12939 cx: &mut AsyncApp,
12940 ) -> Result<()>
12941 where
12942 T: LspCommand + Clone,
12943 T::ProtoRequest: proto::LspRequestMessage,
12944 <T::ProtoRequest as proto::RequestMessage>::Response:
12945 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12946 {
12947 let (buffer_version, buffer) =
12948 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12949 let request =
12950 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12951 let key = LspKey {
12952 request_type: TypeId::of::<T>(),
12953 server_queried: for_server_id,
12954 };
12955 lsp_store.update(cx, |lsp_store, cx| {
12956 let request_task = match for_server_id {
12957 Some(server_id) => {
12958 let server_task = lsp_store.request_lsp(
12959 buffer.clone(),
12960 LanguageServerToQuery::Other(server_id),
12961 request.clone(),
12962 cx,
12963 );
12964 cx.background_spawn(async move {
12965 let mut responses = Vec::new();
12966 match server_task.await {
12967 Ok(response) => responses.push((server_id, response)),
12968 // rust-analyzer likes to error with this when its still loading up
12969 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12970 Err(e) => log::error!(
12971 "Error handling response for request {request:?}: {e:#}"
12972 ),
12973 }
12974 responses
12975 })
12976 }
12977 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12978 };
12979 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12980 if T::ProtoRequest::stop_previous_requests() {
12981 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12982 lsp_requests.clear();
12983 }
12984 }
12985 lsp_data.lsp_requests.entry(key).or_default().insert(
12986 lsp_request_id,
12987 cx.spawn(async move |lsp_store, cx| {
12988 let response = request_task.await;
12989 lsp_store
12990 .update(cx, |lsp_store, cx| {
12991 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12992 {
12993 let response = response
12994 .into_iter()
12995 .map(|(server_id, response)| {
12996 (
12997 server_id.to_proto(),
12998 T::response_to_proto(
12999 response,
13000 lsp_store,
13001 sender_id,
13002 &buffer_version,
13003 cx,
13004 )
13005 .into(),
13006 )
13007 })
13008 .collect::<HashMap<_, _>>();
13009 match client.send_lsp_response::<T::ProtoRequest>(
13010 project_id,
13011 lsp_request_id,
13012 response,
13013 ) {
13014 Ok(()) => {}
13015 Err(e) => {
13016 log::error!("Failed to send LSP response: {e:#}",)
13017 }
13018 }
13019 }
13020 })
13021 .ok();
13022 }),
13023 );
13024 });
13025 Ok(())
13026 }
13027
13028 async fn wait_for_buffer_version<T>(
13029 lsp_store: &Entity<Self>,
13030 proto_request: &T::ProtoRequest,
13031 cx: &mut AsyncApp,
13032 ) -> Result<(Global, Entity<Buffer>)>
13033 where
13034 T: LspCommand,
13035 T::ProtoRequest: proto::LspRequestMessage,
13036 {
13037 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13038 let version = deserialize_version(proto_request.buffer_version());
13039 let buffer = lsp_store.update(cx, |this, cx| {
13040 this.buffer_store.read(cx).get_existing(buffer_id)
13041 })?;
13042 buffer
13043 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13044 .await?;
13045 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13046 Ok((buffer_version, buffer))
13047 }
13048
13049 fn take_text_document_sync_options(
13050 capabilities: &mut lsp::ServerCapabilities,
13051 ) -> lsp::TextDocumentSyncOptions {
13052 match capabilities.text_document_sync.take() {
13053 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13054 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13055 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13056 sync_options.change = Some(sync_kind);
13057 sync_options
13058 }
13059 None => lsp::TextDocumentSyncOptions::default(),
13060 }
13061 }
13062
13063 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13064 self.downstream_client.clone()
13065 }
13066
13067 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13068 self.worktree_store.clone()
13069 }
13070
13071 /// Gets what's stored in the LSP data for the given buffer.
13072 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13073 self.lsp_data.get_mut(&buffer_id)
13074 }
13075
13076 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13077 /// new [`BufferLspData`] will be created to replace the previous state.
13078 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13079 let (buffer_id, buffer_version) =
13080 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13081 let lsp_data = self
13082 .lsp_data
13083 .entry(buffer_id)
13084 .or_insert_with(|| BufferLspData::new(buffer, cx));
13085 if buffer_version.changed_since(&lsp_data.buffer_version) {
13086 // To send delta requests for semantic tokens, the previous tokens
13087 // need to be kept between buffer changes.
13088 let semantic_tokens = lsp_data.semantic_tokens.take();
13089 *lsp_data = BufferLspData::new(buffer, cx);
13090 lsp_data.semantic_tokens = semantic_tokens;
13091 }
13092 lsp_data
13093 }
13094}
13095
13096// Registration with registerOptions as null, should fallback to true.
13097// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13098fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13099 reg: lsp::Registration,
13100) -> Result<OneOf<bool, T>> {
13101 Ok(match reg.register_options {
13102 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13103 None => OneOf::Left(true),
13104 })
13105}
13106
13107fn subscribe_to_binary_statuses(
13108 languages: &Arc<LanguageRegistry>,
13109 cx: &mut Context<'_, LspStore>,
13110) -> Task<()> {
13111 let mut server_statuses = languages.language_server_binary_statuses();
13112 cx.spawn(async move |lsp_store, cx| {
13113 while let Some((server_name, binary_status)) = server_statuses.next().await {
13114 if lsp_store
13115 .update(cx, |_, cx| {
13116 let mut message = None;
13117 let binary_status = match binary_status {
13118 BinaryStatus::None => proto::ServerBinaryStatus::None,
13119 BinaryStatus::CheckingForUpdate => {
13120 proto::ServerBinaryStatus::CheckingForUpdate
13121 }
13122 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13123 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13124 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13125 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13126 BinaryStatus::Failed { error } => {
13127 message = Some(error);
13128 proto::ServerBinaryStatus::Failed
13129 }
13130 };
13131 cx.emit(LspStoreEvent::LanguageServerUpdate {
13132 // Binary updates are about the binary that might not have any language server id at that point.
13133 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13134 language_server_id: LanguageServerId(0),
13135 name: Some(server_name),
13136 message: proto::update_language_server::Variant::StatusUpdate(
13137 proto::StatusUpdate {
13138 message,
13139 status: Some(proto::status_update::Status::Binary(
13140 binary_status as i32,
13141 )),
13142 },
13143 ),
13144 });
13145 })
13146 .is_err()
13147 {
13148 break;
13149 }
13150 }
13151 })
13152}
13153
13154fn lsp_workspace_diagnostics_refresh(
13155 registration_id: Option<String>,
13156 options: DiagnosticServerCapabilities,
13157 server: Arc<LanguageServer>,
13158 cx: &mut Context<'_, LspStore>,
13159) -> Option<WorkspaceRefreshTask> {
13160 let identifier = workspace_diagnostic_identifier(&options)?;
13161 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13162
13163 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13164 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13165 refresh_tx.try_send(()).ok();
13166
13167 let request_timeout = ProjectSettings::get_global(cx)
13168 .global_lsp_settings
13169 .get_request_timeout();
13170
13171 // Clamp timeout duration at a minimum of [`DEFAULT_LSP_REQUEST_TIMEOUT`] to mitigate useless loops from re-trying connections with smaller timeouts from project settings.
13172 // This allows users to increase the duration if need be
13173 let timeout = if request_timeout != Duration::ZERO {
13174 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13175 } else {
13176 request_timeout
13177 };
13178
13179 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13180 let mut attempts = 0;
13181 let max_attempts = 50;
13182 let mut requests = 0;
13183
13184 loop {
13185 let Some(()) = refresh_rx.recv().await else {
13186 return;
13187 };
13188
13189 'request: loop {
13190 requests += 1;
13191 if attempts > max_attempts {
13192 log::error!(
13193 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13194 );
13195 return;
13196 }
13197 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13198 cx.background_executor()
13199 .timer(Duration::from_millis(backoff_millis))
13200 .await;
13201 attempts += 1;
13202
13203 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13204 lsp_store
13205 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13206 .into_iter()
13207 .filter_map(|(abs_path, result_id)| {
13208 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13209 Some(lsp::PreviousResultId {
13210 uri,
13211 value: result_id.to_string(),
13212 })
13213 })
13214 .collect()
13215 }) else {
13216 return;
13217 };
13218
13219 let token = if let Some(registration_id) = ®istration_id {
13220 format!(
13221 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13222 server.server_id(),
13223 )
13224 } else {
13225 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13226 };
13227
13228 progress_rx.try_recv().ok();
13229 let timer = server.request_timer(timeout).fuse();
13230 let progress = pin!(progress_rx.recv().fuse());
13231 let response_result = server
13232 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13233 lsp::WorkspaceDiagnosticParams {
13234 previous_result_ids,
13235 identifier: identifier.clone(),
13236 work_done_progress_params: Default::default(),
13237 partial_result_params: lsp::PartialResultParams {
13238 partial_result_token: Some(lsp::ProgressToken::String(token)),
13239 },
13240 },
13241 select(timer, progress).then(|either| match either {
13242 Either::Left((message, ..)) => ready(message).left_future(),
13243 Either::Right(..) => pending::<String>().right_future(),
13244 }),
13245 )
13246 .await;
13247
13248 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13249 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13250 match response_result {
13251 ConnectionResult::Timeout => {
13252 log::error!("Timeout during workspace diagnostics pull");
13253 continue 'request;
13254 }
13255 ConnectionResult::ConnectionReset => {
13256 log::error!("Server closed a workspace diagnostics pull request");
13257 continue 'request;
13258 }
13259 ConnectionResult::Result(Err(e)) => {
13260 log::error!("Error during workspace diagnostics pull: {e:#}");
13261 break 'request;
13262 }
13263 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13264 attempts = 0;
13265 if lsp_store
13266 .update(cx, |lsp_store, cx| {
13267 lsp_store.apply_workspace_diagnostic_report(
13268 server.server_id(),
13269 pulled_diagnostics,
13270 registration_id_shared.clone(),
13271 cx,
13272 )
13273 })
13274 .is_err()
13275 {
13276 return;
13277 }
13278 break 'request;
13279 }
13280 }
13281 }
13282 }
13283 });
13284
13285 Some(WorkspaceRefreshTask {
13286 refresh_tx,
13287 progress_tx,
13288 task: workspace_query_language_server,
13289 })
13290}
13291
13292fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13293 match &options {
13294 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13295 .identifier
13296 .as_deref()
13297 .map(SharedString::new),
13298 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13299 let diagnostic_options = ®istration_options.diagnostic_options;
13300 diagnostic_options
13301 .identifier
13302 .as_deref()
13303 .map(SharedString::new)
13304 }
13305 }
13306}
13307
13308fn workspace_diagnostic_identifier(
13309 options: &DiagnosticServerCapabilities,
13310) -> Option<Option<String>> {
13311 match &options {
13312 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13313 if !diagnostic_options.workspace_diagnostics {
13314 return None;
13315 }
13316 Some(diagnostic_options.identifier.clone())
13317 }
13318 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13319 let diagnostic_options = ®istration_options.diagnostic_options;
13320 if !diagnostic_options.workspace_diagnostics {
13321 return None;
13322 }
13323 Some(diagnostic_options.identifier.clone())
13324 }
13325 }
13326}
13327
13328fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13329 let CompletionSource::BufferWord {
13330 word_range,
13331 resolved,
13332 } = &mut completion.source
13333 else {
13334 return;
13335 };
13336 if *resolved {
13337 return;
13338 }
13339
13340 if completion.new_text
13341 != snapshot
13342 .text_for_range(word_range.clone())
13343 .collect::<String>()
13344 {
13345 return;
13346 }
13347
13348 let mut offset = 0;
13349 for chunk in snapshot.chunks(word_range.clone(), true) {
13350 let end_offset = offset + chunk.text.len();
13351 if let Some(highlight_id) = chunk.syntax_highlight_id {
13352 completion
13353 .label
13354 .runs
13355 .push((offset..end_offset, highlight_id));
13356 }
13357 offset = end_offset;
13358 }
13359 *resolved = true;
13360}
13361
13362impl EventEmitter<LspStoreEvent> for LspStore {}
13363
13364fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13365 hover
13366 .contents
13367 .retain(|hover_block| !hover_block.text.trim().is_empty());
13368 if hover.contents.is_empty() {
13369 None
13370 } else {
13371 Some(hover)
13372 }
13373}
13374
13375async fn populate_labels_for_completions(
13376 new_completions: Vec<CoreCompletion>,
13377 language: Option<Arc<Language>>,
13378 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13379) -> Vec<Completion> {
13380 let lsp_completions = new_completions
13381 .iter()
13382 .filter_map(|new_completion| {
13383 new_completion
13384 .source
13385 .lsp_completion(true)
13386 .map(|lsp_completion| lsp_completion.into_owned())
13387 })
13388 .collect::<Vec<_>>();
13389
13390 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13391 lsp_adapter
13392 .labels_for_completions(&lsp_completions, language)
13393 .await
13394 .log_err()
13395 .unwrap_or_default()
13396 } else {
13397 Vec::new()
13398 }
13399 .into_iter()
13400 .fuse();
13401
13402 let mut completions = Vec::new();
13403 for completion in new_completions {
13404 match completion.source.lsp_completion(true) {
13405 Some(lsp_completion) => {
13406 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13407
13408 let mut label = labels.next().flatten().unwrap_or_else(|| {
13409 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13410 });
13411 ensure_uniform_list_compatible_label(&mut label);
13412 completions.push(Completion {
13413 label,
13414 documentation,
13415 replace_range: completion.replace_range,
13416 new_text: completion.new_text,
13417 insert_text_mode: lsp_completion.insert_text_mode,
13418 source: completion.source,
13419 icon_path: None,
13420 confirm: None,
13421 match_start: None,
13422 snippet_deduplication_key: None,
13423 });
13424 }
13425 None => {
13426 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13427 ensure_uniform_list_compatible_label(&mut label);
13428 completions.push(Completion {
13429 label,
13430 documentation: None,
13431 replace_range: completion.replace_range,
13432 new_text: completion.new_text,
13433 source: completion.source,
13434 insert_text_mode: None,
13435 icon_path: None,
13436 confirm: None,
13437 match_start: None,
13438 snippet_deduplication_key: None,
13439 });
13440 }
13441 }
13442 }
13443 completions
13444}
13445
13446#[derive(Debug)]
13447pub enum LanguageServerToQuery {
13448 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13449 FirstCapable,
13450 /// Query a specific language server.
13451 Other(LanguageServerId),
13452}
13453
13454#[derive(Default)]
13455struct RenamePathsWatchedForServer {
13456 did_rename: Vec<RenameActionPredicate>,
13457 will_rename: Vec<RenameActionPredicate>,
13458}
13459
13460impl RenamePathsWatchedForServer {
13461 fn with_did_rename_patterns(
13462 mut self,
13463 did_rename: Option<&FileOperationRegistrationOptions>,
13464 ) -> Self {
13465 if let Some(did_rename) = did_rename {
13466 self.did_rename = did_rename
13467 .filters
13468 .iter()
13469 .filter_map(|filter| filter.try_into().log_err())
13470 .collect();
13471 }
13472 self
13473 }
13474 fn with_will_rename_patterns(
13475 mut self,
13476 will_rename: Option<&FileOperationRegistrationOptions>,
13477 ) -> Self {
13478 if let Some(will_rename) = will_rename {
13479 self.will_rename = will_rename
13480 .filters
13481 .iter()
13482 .filter_map(|filter| filter.try_into().log_err())
13483 .collect();
13484 }
13485 self
13486 }
13487
13488 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13489 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13490 }
13491 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13492 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13493 }
13494}
13495
13496impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13497 type Error = globset::Error;
13498 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13499 Ok(Self {
13500 kind: ops.pattern.matches.clone(),
13501 glob: GlobBuilder::new(&ops.pattern.glob)
13502 .case_insensitive(
13503 ops.pattern
13504 .options
13505 .as_ref()
13506 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13507 )
13508 .build()?
13509 .compile_matcher(),
13510 })
13511 }
13512}
13513struct RenameActionPredicate {
13514 glob: GlobMatcher,
13515 kind: Option<FileOperationPatternKind>,
13516}
13517
13518impl RenameActionPredicate {
13519 // Returns true if language server should be notified
13520 fn eval(&self, path: &str, is_dir: bool) -> bool {
13521 self.kind.as_ref().is_none_or(|kind| {
13522 let expected_kind = if is_dir {
13523 FileOperationPatternKind::Folder
13524 } else {
13525 FileOperationPatternKind::File
13526 };
13527 kind == &expected_kind
13528 }) && self.glob.is_match(path)
13529 }
13530}
13531
13532#[derive(Default)]
13533struct LanguageServerWatchedPaths {
13534 worktree_paths: HashMap<WorktreeId, GlobSet>,
13535 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13536}
13537
13538#[derive(Default)]
13539struct LanguageServerWatchedPathsBuilder {
13540 worktree_paths: HashMap<WorktreeId, GlobSet>,
13541 abs_paths: HashMap<Arc<Path>, GlobSet>,
13542}
13543
13544impl LanguageServerWatchedPathsBuilder {
13545 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13546 self.worktree_paths.insert(worktree_id, glob_set);
13547 }
13548 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13549 self.abs_paths.insert(path, glob_set);
13550 }
13551 fn build(
13552 self,
13553 fs: Arc<dyn Fs>,
13554 language_server_id: LanguageServerId,
13555 cx: &mut Context<LspStore>,
13556 ) -> LanguageServerWatchedPaths {
13557 let lsp_store = cx.weak_entity();
13558
13559 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13560 let abs_paths = self
13561 .abs_paths
13562 .into_iter()
13563 .map(|(abs_path, globset)| {
13564 let task = cx.spawn({
13565 let abs_path = abs_path.clone();
13566 let fs = fs.clone();
13567
13568 let lsp_store = lsp_store.clone();
13569 async move |_, cx| {
13570 maybe!(async move {
13571 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13572 while let Some(update) = push_updates.0.next().await {
13573 let action = lsp_store
13574 .update(cx, |this, _| {
13575 let Some(local) = this.as_local() else {
13576 return ControlFlow::Break(());
13577 };
13578 let Some(watcher) = local
13579 .language_server_watched_paths
13580 .get(&language_server_id)
13581 else {
13582 return ControlFlow::Break(());
13583 };
13584 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13585 "Watched abs path is not registered with a watcher",
13586 );
13587 let matching_entries = update
13588 .into_iter()
13589 .filter(|event| globs.is_match(&event.path))
13590 .collect::<Vec<_>>();
13591 this.lsp_notify_abs_paths_changed(
13592 language_server_id,
13593 matching_entries,
13594 );
13595 ControlFlow::Continue(())
13596 })
13597 .ok()?;
13598
13599 if action.is_break() {
13600 break;
13601 }
13602 }
13603 Some(())
13604 })
13605 .await;
13606 }
13607 });
13608 (abs_path, (globset, task))
13609 })
13610 .collect();
13611 LanguageServerWatchedPaths {
13612 worktree_paths: self.worktree_paths,
13613 abs_paths,
13614 }
13615 }
13616}
13617
13618struct LspBufferSnapshot {
13619 version: i32,
13620 snapshot: TextBufferSnapshot,
13621}
13622
13623/// A prompt requested by LSP server.
13624#[derive(Clone, Debug)]
13625pub struct LanguageServerPromptRequest {
13626 pub id: usize,
13627 pub level: PromptLevel,
13628 pub message: String,
13629 pub actions: Vec<MessageActionItem>,
13630 pub lsp_name: String,
13631 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13632}
13633
13634impl LanguageServerPromptRequest {
13635 pub fn new(
13636 level: PromptLevel,
13637 message: String,
13638 actions: Vec<MessageActionItem>,
13639 lsp_name: String,
13640 response_channel: smol::channel::Sender<MessageActionItem>,
13641 ) -> Self {
13642 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13643 LanguageServerPromptRequest {
13644 id,
13645 level,
13646 message,
13647 actions,
13648 lsp_name,
13649 response_channel,
13650 }
13651 }
13652 pub async fn respond(self, index: usize) -> Option<()> {
13653 if let Some(response) = self.actions.into_iter().nth(index) {
13654 self.response_channel.send(response).await.ok()
13655 } else {
13656 None
13657 }
13658 }
13659
13660 #[cfg(any(test, feature = "test-support"))]
13661 pub fn test(
13662 level: PromptLevel,
13663 message: String,
13664 actions: Vec<MessageActionItem>,
13665 lsp_name: String,
13666 ) -> Self {
13667 let (tx, _rx) = smol::channel::unbounded();
13668 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13669 }
13670}
13671impl PartialEq for LanguageServerPromptRequest {
13672 fn eq(&self, other: &Self) -> bool {
13673 self.message == other.message && self.actions == other.actions
13674 }
13675}
13676
13677#[derive(Clone, Debug, PartialEq)]
13678pub enum LanguageServerLogType {
13679 Log(MessageType),
13680 Trace { verbose_info: Option<String> },
13681 Rpc { received: bool },
13682}
13683
13684impl LanguageServerLogType {
13685 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13686 match self {
13687 Self::Log(log_type) => {
13688 use proto::log_message::LogLevel;
13689 let level = match *log_type {
13690 MessageType::ERROR => LogLevel::Error,
13691 MessageType::WARNING => LogLevel::Warning,
13692 MessageType::INFO => LogLevel::Info,
13693 MessageType::LOG => LogLevel::Log,
13694 other => {
13695 log::warn!("Unknown lsp log message type: {other:?}");
13696 LogLevel::Log
13697 }
13698 };
13699 proto::language_server_log::LogType::Log(proto::LogMessage {
13700 level: level as i32,
13701 })
13702 }
13703 Self::Trace { verbose_info } => {
13704 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13705 verbose_info: verbose_info.to_owned(),
13706 })
13707 }
13708 Self::Rpc { received } => {
13709 let kind = if *received {
13710 proto::rpc_message::Kind::Received
13711 } else {
13712 proto::rpc_message::Kind::Sent
13713 };
13714 let kind = kind as i32;
13715 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13716 }
13717 }
13718 }
13719
13720 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13721 use proto::log_message::LogLevel;
13722 use proto::rpc_message;
13723 match log_type {
13724 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13725 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13726 LogLevel::Error => MessageType::ERROR,
13727 LogLevel::Warning => MessageType::WARNING,
13728 LogLevel::Info => MessageType::INFO,
13729 LogLevel::Log => MessageType::LOG,
13730 },
13731 ),
13732 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13733 verbose_info: trace_message.verbose_info,
13734 },
13735 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13736 received: match rpc_message::Kind::from_i32(message.kind)
13737 .unwrap_or(rpc_message::Kind::Received)
13738 {
13739 rpc_message::Kind::Received => true,
13740 rpc_message::Kind::Sent => false,
13741 },
13742 },
13743 }
13744 }
13745}
13746
13747pub struct WorkspaceRefreshTask {
13748 refresh_tx: mpsc::Sender<()>,
13749 progress_tx: mpsc::Sender<()>,
13750 #[allow(dead_code)]
13751 task: Task<()>,
13752}
13753
13754pub enum LanguageServerState {
13755 Starting {
13756 startup: Task<Option<Arc<LanguageServer>>>,
13757 /// List of language servers that will be added to the workspace once it's initialization completes.
13758 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13759 },
13760
13761 Running {
13762 adapter: Arc<CachedLspAdapter>,
13763 server: Arc<LanguageServer>,
13764 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13765 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13766 },
13767}
13768
13769impl LanguageServerState {
13770 fn add_workspace_folder(&self, uri: Uri) {
13771 match self {
13772 LanguageServerState::Starting {
13773 pending_workspace_folders,
13774 ..
13775 } => {
13776 pending_workspace_folders.lock().insert(uri);
13777 }
13778 LanguageServerState::Running { server, .. } => {
13779 server.add_workspace_folder(uri);
13780 }
13781 }
13782 }
13783 fn _remove_workspace_folder(&self, uri: Uri) {
13784 match self {
13785 LanguageServerState::Starting {
13786 pending_workspace_folders,
13787 ..
13788 } => {
13789 pending_workspace_folders.lock().remove(&uri);
13790 }
13791 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13792 }
13793 }
13794}
13795
13796impl std::fmt::Debug for LanguageServerState {
13797 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13798 match self {
13799 LanguageServerState::Starting { .. } => {
13800 f.debug_struct("LanguageServerState::Starting").finish()
13801 }
13802 LanguageServerState::Running { .. } => {
13803 f.debug_struct("LanguageServerState::Running").finish()
13804 }
13805 }
13806 }
13807}
13808
13809#[derive(Clone, Debug, Serialize)]
13810pub struct LanguageServerProgress {
13811 pub is_disk_based_diagnostics_progress: bool,
13812 pub is_cancellable: bool,
13813 pub title: Option<String>,
13814 pub message: Option<String>,
13815 pub percentage: Option<usize>,
13816 #[serde(skip_serializing)]
13817 pub last_update_at: Instant,
13818}
13819
13820#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13821pub struct DiagnosticSummary {
13822 pub error_count: usize,
13823 pub warning_count: usize,
13824}
13825
13826impl DiagnosticSummary {
13827 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13828 let mut this = Self {
13829 error_count: 0,
13830 warning_count: 0,
13831 };
13832
13833 for entry in diagnostics {
13834 if entry.diagnostic.is_primary {
13835 match entry.diagnostic.severity {
13836 DiagnosticSeverity::ERROR => this.error_count += 1,
13837 DiagnosticSeverity::WARNING => this.warning_count += 1,
13838 _ => {}
13839 }
13840 }
13841 }
13842
13843 this
13844 }
13845
13846 pub fn is_empty(&self) -> bool {
13847 self.error_count == 0 && self.warning_count == 0
13848 }
13849
13850 pub fn to_proto(
13851 self,
13852 language_server_id: LanguageServerId,
13853 path: &RelPath,
13854 ) -> proto::DiagnosticSummary {
13855 proto::DiagnosticSummary {
13856 path: path.to_proto(),
13857 language_server_id: language_server_id.0 as u64,
13858 error_count: self.error_count as u32,
13859 warning_count: self.warning_count as u32,
13860 }
13861 }
13862}
13863
13864#[derive(Clone, Debug)]
13865pub enum CompletionDocumentation {
13866 /// There is no documentation for this completion.
13867 Undocumented,
13868 /// A single line of documentation.
13869 SingleLine(SharedString),
13870 /// Multiple lines of plain text documentation.
13871 MultiLinePlainText(SharedString),
13872 /// Markdown documentation.
13873 MultiLineMarkdown(SharedString),
13874 /// Both single line and multiple lines of plain text documentation.
13875 SingleLineAndMultiLinePlainText {
13876 single_line: SharedString,
13877 plain_text: Option<SharedString>,
13878 },
13879}
13880
13881impl CompletionDocumentation {
13882 #[cfg(any(test, feature = "test-support"))]
13883 pub fn text(&self) -> SharedString {
13884 match self {
13885 CompletionDocumentation::Undocumented => "".into(),
13886 CompletionDocumentation::SingleLine(s) => s.clone(),
13887 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13888 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13889 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13890 single_line.clone()
13891 }
13892 }
13893 }
13894}
13895
13896impl From<lsp::Documentation> for CompletionDocumentation {
13897 fn from(docs: lsp::Documentation) -> Self {
13898 match docs {
13899 lsp::Documentation::String(text) => {
13900 if text.lines().count() <= 1 {
13901 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13902 } else {
13903 CompletionDocumentation::MultiLinePlainText(text.into())
13904 }
13905 }
13906
13907 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13908 lsp::MarkupKind::PlainText => {
13909 if value.lines().count() <= 1 {
13910 CompletionDocumentation::SingleLine(value.into())
13911 } else {
13912 CompletionDocumentation::MultiLinePlainText(value.into())
13913 }
13914 }
13915
13916 lsp::MarkupKind::Markdown => {
13917 CompletionDocumentation::MultiLineMarkdown(value.into())
13918 }
13919 },
13920 }
13921 }
13922}
13923
13924pub enum ResolvedHint {
13925 Resolved(InlayHint),
13926 Resolving(Shared<Task<()>>),
13927}
13928
13929pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13930 glob.components()
13931 .take_while(|component| match component {
13932 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13933 _ => true,
13934 })
13935 .collect()
13936}
13937
13938pub struct SshLspAdapter {
13939 name: LanguageServerName,
13940 binary: LanguageServerBinary,
13941 initialization_options: Option<String>,
13942 code_action_kinds: Option<Vec<CodeActionKind>>,
13943}
13944
13945impl SshLspAdapter {
13946 pub fn new(
13947 name: LanguageServerName,
13948 binary: LanguageServerBinary,
13949 initialization_options: Option<String>,
13950 code_action_kinds: Option<String>,
13951 ) -> Self {
13952 Self {
13953 name,
13954 binary,
13955 initialization_options,
13956 code_action_kinds: code_action_kinds
13957 .as_ref()
13958 .and_then(|c| serde_json::from_str(c).ok()),
13959 }
13960 }
13961}
13962
13963impl LspInstaller for SshLspAdapter {
13964 type BinaryVersion = ();
13965 async fn check_if_user_installed(
13966 &self,
13967 _: &dyn LspAdapterDelegate,
13968 _: Option<Toolchain>,
13969 _: &AsyncApp,
13970 ) -> Option<LanguageServerBinary> {
13971 Some(self.binary.clone())
13972 }
13973
13974 async fn cached_server_binary(
13975 &self,
13976 _: PathBuf,
13977 _: &dyn LspAdapterDelegate,
13978 ) -> Option<LanguageServerBinary> {
13979 None
13980 }
13981
13982 async fn fetch_latest_server_version(
13983 &self,
13984 _: &dyn LspAdapterDelegate,
13985 _: bool,
13986 _: &mut AsyncApp,
13987 ) -> Result<()> {
13988 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13989 }
13990
13991 async fn fetch_server_binary(
13992 &self,
13993 _: (),
13994 _: PathBuf,
13995 _: &dyn LspAdapterDelegate,
13996 ) -> Result<LanguageServerBinary> {
13997 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13998 }
13999}
14000
14001#[async_trait(?Send)]
14002impl LspAdapter for SshLspAdapter {
14003 fn name(&self) -> LanguageServerName {
14004 self.name.clone()
14005 }
14006
14007 async fn initialization_options(
14008 self: Arc<Self>,
14009 _: &Arc<dyn LspAdapterDelegate>,
14010 _: &mut AsyncApp,
14011 ) -> Result<Option<serde_json::Value>> {
14012 let Some(options) = &self.initialization_options else {
14013 return Ok(None);
14014 };
14015 let result = serde_json::from_str(options)?;
14016 Ok(result)
14017 }
14018
14019 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14020 self.code_action_kinds.clone()
14021 }
14022}
14023
14024pub fn language_server_settings<'a>(
14025 delegate: &'a dyn LspAdapterDelegate,
14026 language: &LanguageServerName,
14027 cx: &'a App,
14028) -> Option<&'a LspSettings> {
14029 language_server_settings_for(
14030 SettingsLocation {
14031 worktree_id: delegate.worktree_id(),
14032 path: RelPath::empty(),
14033 },
14034 language,
14035 cx,
14036 )
14037}
14038
14039pub fn language_server_settings_for<'a>(
14040 location: SettingsLocation<'a>,
14041 language: &LanguageServerName,
14042 cx: &'a App,
14043) -> Option<&'a LspSettings> {
14044 ProjectSettings::get(Some(location), cx).lsp.get(language)
14045}
14046
14047pub struct LocalLspAdapterDelegate {
14048 lsp_store: WeakEntity<LspStore>,
14049 worktree: worktree::Snapshot,
14050 fs: Arc<dyn Fs>,
14051 http_client: Arc<dyn HttpClient>,
14052 language_registry: Arc<LanguageRegistry>,
14053 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14054}
14055
14056impl LocalLspAdapterDelegate {
14057 pub fn new(
14058 language_registry: Arc<LanguageRegistry>,
14059 environment: &Entity<ProjectEnvironment>,
14060 lsp_store: WeakEntity<LspStore>,
14061 worktree: &Entity<Worktree>,
14062 http_client: Arc<dyn HttpClient>,
14063 fs: Arc<dyn Fs>,
14064 cx: &mut App,
14065 ) -> Arc<Self> {
14066 let load_shell_env_task =
14067 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14068
14069 Arc::new(Self {
14070 lsp_store,
14071 worktree: worktree.read(cx).snapshot(),
14072 fs,
14073 http_client,
14074 language_registry,
14075 load_shell_env_task,
14076 })
14077 }
14078
14079 pub fn from_local_lsp(
14080 local: &LocalLspStore,
14081 worktree: &Entity<Worktree>,
14082 cx: &mut App,
14083 ) -> Arc<Self> {
14084 Self::new(
14085 local.languages.clone(),
14086 &local.environment,
14087 local.weak.clone(),
14088 worktree,
14089 local.http_client.clone(),
14090 local.fs.clone(),
14091 cx,
14092 )
14093 }
14094}
14095
14096#[async_trait]
14097impl LspAdapterDelegate for LocalLspAdapterDelegate {
14098 fn show_notification(&self, message: &str, cx: &mut App) {
14099 self.lsp_store
14100 .update(cx, |_, cx| {
14101 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14102 })
14103 .ok();
14104 }
14105
14106 fn http_client(&self) -> Arc<dyn HttpClient> {
14107 self.http_client.clone()
14108 }
14109
14110 fn worktree_id(&self) -> WorktreeId {
14111 self.worktree.id()
14112 }
14113
14114 fn worktree_root_path(&self) -> &Path {
14115 self.worktree.abs_path().as_ref()
14116 }
14117
14118 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14119 self.worktree.resolve_relative_path(path)
14120 }
14121
14122 async fn shell_env(&self) -> HashMap<String, String> {
14123 let task = self.load_shell_env_task.clone();
14124 task.await.unwrap_or_default()
14125 }
14126
14127 async fn npm_package_installed_version(
14128 &self,
14129 package_name: &str,
14130 ) -> Result<Option<(PathBuf, Version)>> {
14131 let local_package_directory = self.worktree_root_path();
14132 let node_modules_directory = local_package_directory.join("node_modules");
14133
14134 if let Some(version) =
14135 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14136 {
14137 return Ok(Some((node_modules_directory, version)));
14138 }
14139 let Some(npm) = self.which("npm".as_ref()).await else {
14140 log::warn!(
14141 "Failed to find npm executable for {:?}",
14142 local_package_directory
14143 );
14144 return Ok(None);
14145 };
14146
14147 let env = self.shell_env().await;
14148 let output = util::command::new_command(&npm)
14149 .args(["root", "-g"])
14150 .envs(env)
14151 .current_dir(local_package_directory)
14152 .output()
14153 .await?;
14154 let global_node_modules =
14155 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14156
14157 if let Some(version) =
14158 read_package_installed_version(global_node_modules.clone(), package_name).await?
14159 {
14160 return Ok(Some((global_node_modules, version)));
14161 }
14162 return Ok(None);
14163 }
14164
14165 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14166 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14167 if self.fs.is_file(&worktree_abs_path).await {
14168 worktree_abs_path.pop();
14169 }
14170
14171 let env = self.shell_env().await;
14172
14173 let shell_path = env.get("PATH").cloned();
14174
14175 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14176 }
14177
14178 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14179 let mut working_dir = self.worktree_root_path().to_path_buf();
14180 if self.fs.is_file(&working_dir).await {
14181 working_dir.pop();
14182 }
14183 let output = util::command::new_command(&command.path)
14184 .args(command.arguments)
14185 .envs(command.env.clone().unwrap_or_default())
14186 .current_dir(working_dir)
14187 .output()
14188 .await?;
14189
14190 anyhow::ensure!(
14191 output.status.success(),
14192 "{}, stdout: {:?}, stderr: {:?}",
14193 output.status,
14194 String::from_utf8_lossy(&output.stdout),
14195 String::from_utf8_lossy(&output.stderr)
14196 );
14197 Ok(())
14198 }
14199
14200 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14201 self.language_registry
14202 .update_lsp_binary_status(server_name, status);
14203 }
14204
14205 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14206 self.language_registry
14207 .all_lsp_adapters()
14208 .into_iter()
14209 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14210 .collect()
14211 }
14212
14213 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14214 let dir = self.language_registry.language_server_download_dir(name)?;
14215
14216 if !dir.exists() {
14217 smol::fs::create_dir_all(&dir)
14218 .await
14219 .context("failed to create container directory")
14220 .log_err()?;
14221 }
14222
14223 Some(dir)
14224 }
14225
14226 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14227 let entry = self
14228 .worktree
14229 .entry_for_path(path)
14230 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14231 let abs_path = self.worktree.absolutize(&entry.path);
14232 self.fs.load(&abs_path).await
14233 }
14234}
14235
14236async fn populate_labels_for_symbols(
14237 symbols: Vec<CoreSymbol>,
14238 language_registry: &Arc<LanguageRegistry>,
14239 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14240 output: &mut Vec<Symbol>,
14241) {
14242 #[allow(clippy::mutable_key_type)]
14243 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14244
14245 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14246 for symbol in symbols {
14247 let Some(file_name) = symbol.path.file_name() else {
14248 continue;
14249 };
14250 let language = language_registry
14251 .load_language_for_file_path(Path::new(file_name))
14252 .await
14253 .ok()
14254 .or_else(|| {
14255 unknown_paths.insert(file_name.into());
14256 None
14257 });
14258 symbols_by_language
14259 .entry(language)
14260 .or_default()
14261 .push(symbol);
14262 }
14263
14264 for unknown_path in unknown_paths {
14265 log::info!("no language found for symbol in file {unknown_path:?}");
14266 }
14267
14268 let mut label_params = Vec::new();
14269 for (language, mut symbols) in symbols_by_language {
14270 label_params.clear();
14271 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14272 name: mem::take(&mut symbol.name),
14273 kind: symbol.kind,
14274 container_name: symbol.container_name.take(),
14275 }));
14276
14277 let mut labels = Vec::new();
14278 if let Some(language) = language {
14279 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14280 language_registry
14281 .lsp_adapters(&language.name())
14282 .first()
14283 .cloned()
14284 });
14285 if let Some(lsp_adapter) = lsp_adapter {
14286 labels = lsp_adapter
14287 .labels_for_symbols(&label_params, &language)
14288 .await
14289 .log_err()
14290 .unwrap_or_default();
14291 }
14292 }
14293
14294 for (
14295 (
14296 symbol,
14297 language::Symbol {
14298 name,
14299 container_name,
14300 ..
14301 },
14302 ),
14303 label,
14304 ) in symbols
14305 .into_iter()
14306 .zip(label_params.drain(..))
14307 .zip(labels.into_iter().chain(iter::repeat(None)))
14308 {
14309 output.push(Symbol {
14310 language_server_name: symbol.language_server_name,
14311 source_worktree_id: symbol.source_worktree_id,
14312 source_language_server_id: symbol.source_language_server_id,
14313 path: symbol.path,
14314 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14315 name,
14316 kind: symbol.kind,
14317 range: symbol.range,
14318 container_name,
14319 });
14320 }
14321 }
14322}
14323
14324pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14325 text.lines()
14326 .map(|line| line.trim())
14327 .filter(|line| !line.is_empty())
14328 .join(separator)
14329}
14330
14331fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14332 match server.capabilities().text_document_sync.as_ref()? {
14333 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14334 // Server wants didSave but didn't specify includeText.
14335 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14336 // Server doesn't want didSave at all.
14337 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14338 // Server provided SaveOptions.
14339 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14340 Some(save_options.include_text.unwrap_or(false))
14341 }
14342 },
14343 // We do not have any save info. Kind affects didChange only.
14344 lsp::TextDocumentSyncCapability::Kind(_) => None,
14345 }
14346}
14347
14348/// Completion items are displayed in a `UniformList`.
14349/// Usually, those items are single-line strings, but in LSP responses,
14350/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14351/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14352/// 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,
14353/// breaking the completions menu presentation.
14354///
14355/// 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.
14356pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14357 let mut new_text = String::with_capacity(label.text.len());
14358 let mut offset_map = vec![0; label.text.len() + 1];
14359 let mut last_char_was_space = false;
14360 let mut new_idx = 0;
14361 let chars = label.text.char_indices().fuse();
14362 let mut newlines_removed = false;
14363
14364 for (idx, c) in chars {
14365 offset_map[idx] = new_idx;
14366
14367 match c {
14368 '\n' if last_char_was_space => {
14369 newlines_removed = true;
14370 }
14371 '\t' | ' ' if last_char_was_space => {}
14372 '\n' if !last_char_was_space => {
14373 new_text.push(' ');
14374 new_idx += 1;
14375 last_char_was_space = true;
14376 newlines_removed = true;
14377 }
14378 ' ' | '\t' => {
14379 new_text.push(' ');
14380 new_idx += 1;
14381 last_char_was_space = true;
14382 }
14383 _ => {
14384 new_text.push(c);
14385 new_idx += c.len_utf8();
14386 last_char_was_space = false;
14387 }
14388 }
14389 }
14390 offset_map[label.text.len()] = new_idx;
14391
14392 // Only modify the label if newlines were removed.
14393 if !newlines_removed {
14394 return;
14395 }
14396
14397 let last_index = new_idx;
14398 let mut run_ranges_errors = Vec::new();
14399 label.runs.retain_mut(|(range, _)| {
14400 match offset_map.get(range.start) {
14401 Some(&start) => range.start = start,
14402 None => {
14403 run_ranges_errors.push(range.clone());
14404 return false;
14405 }
14406 }
14407
14408 match offset_map.get(range.end) {
14409 Some(&end) => range.end = end,
14410 None => {
14411 run_ranges_errors.push(range.clone());
14412 range.end = last_index;
14413 }
14414 }
14415 true
14416 });
14417 if !run_ranges_errors.is_empty() {
14418 log::error!(
14419 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14420 label.text
14421 );
14422 }
14423
14424 let mut wrong_filter_range = None;
14425 if label.filter_range == (0..label.text.len()) {
14426 label.filter_range = 0..new_text.len();
14427 } else {
14428 let mut original_filter_range = Some(label.filter_range.clone());
14429 match offset_map.get(label.filter_range.start) {
14430 Some(&start) => label.filter_range.start = start,
14431 None => {
14432 wrong_filter_range = original_filter_range.take();
14433 label.filter_range.start = last_index;
14434 }
14435 }
14436
14437 match offset_map.get(label.filter_range.end) {
14438 Some(&end) => label.filter_range.end = end,
14439 None => {
14440 wrong_filter_range = original_filter_range.take();
14441 label.filter_range.end = last_index;
14442 }
14443 }
14444 }
14445 if let Some(wrong_filter_range) = wrong_filter_range {
14446 log::error!(
14447 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14448 label.text
14449 );
14450 }
14451
14452 label.text = new_text;
14453}