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 CodeLabelExt, Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff,
75 File as _, Language, LanguageAwareStyling, LanguageName, LanguageRegistry, LocalFile,
76 LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate, ManifestName, ModelineSettings,
77 OffsetUtf16, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToOffsetUtf16, ToPointUtf16,
78 Toolchain, Transaction, Unclipped,
79 language_settings::{
80 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, LineEndingSetting,
81 all_language_settings,
82 },
83 modeline, point_to_lsp,
84 proto::{
85 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
86 serialize_anchor_range, serialize_version,
87 },
88 range_from_lsp, range_to_lsp,
89 row_chunk::RowChunk,
90};
91use lsp::{
92 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
93 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
94 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
95 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
96 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
97 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
98 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
99 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
100};
101use node_runtime::read_package_installed_version;
102use parking_lot::Mutex;
103use postage::{mpsc, sink::Sink, stream::Stream, watch};
104use rand::prelude::*;
105use rpc::{
106 AnyProtoClient, ErrorCode, ErrorExt as _,
107 proto::{LspRequestId, LspRequestMessage as _},
108};
109use semver::Version;
110use serde::Serialize;
111use serde_json::Value;
112use settings::{Settings, SettingsLocation, SettingsStore};
113use sha2::{Digest, Sha256};
114use snippet::Snippet;
115use std::{
116 any::TypeId,
117 borrow::Cow,
118 cell::RefCell,
119 cmp::{Ordering, Reverse},
120 collections::{VecDeque, hash_map},
121 convert::TryInto,
122 ffi::OsStr,
123 future::ready,
124 iter, mem,
125 ops::{ControlFlow, Range},
126 path::{self, Path, PathBuf},
127 pin::pin,
128 rc::Rc,
129 sync::{
130 Arc,
131 atomic::{self, AtomicUsize},
132 },
133 time::{Duration, Instant},
134 vec,
135};
136use sum_tree::Dimensions;
137use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
138
139use util::{
140 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
141 paths::{PathStyle, SanitizedPath, UrlExt},
142 post_inc,
143 redact::redact_command,
144 rel_path::RelPath,
145};
146
147pub use document_colors::DocumentColors;
148pub use folding_ranges::LspFoldingRange;
149pub use fs::*;
150pub use language::Location;
151pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
152#[cfg(any(test, feature = "test-support"))]
153pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
154#[cfg(any(test, feature = "test-support"))]
155pub use prettier::RANGE_FORMAT_SUFFIX as TEST_PRETTIER_RANGE_FORMAT_SUFFIX;
156pub use semantic_tokens::{
157 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
158};
159
160pub use worktree::{
161 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
162 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
163};
164
165const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
166pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
167const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
168const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
169static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
170
171#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
172pub enum ProgressToken {
173 Number(i32),
174 String(SharedString),
175}
176
177impl std::fmt::Display for ProgressToken {
178 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179 match self {
180 Self::Number(number) => write!(f, "{number}"),
181 Self::String(string) => write!(f, "{string}"),
182 }
183 }
184}
185
186impl ProgressToken {
187 fn from_lsp(value: lsp::NumberOrString) -> Self {
188 match value {
189 lsp::NumberOrString::Number(number) => Self::Number(number),
190 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
191 }
192 }
193
194 fn to_lsp(&self) -> lsp::NumberOrString {
195 match self {
196 Self::Number(number) => lsp::NumberOrString::Number(*number),
197 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
198 }
199 }
200
201 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
202 Some(match value.value? {
203 proto::progress_token::Value::Number(number) => Self::Number(number),
204 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
205 })
206 }
207
208 fn to_proto(&self) -> proto::ProgressToken {
209 proto::ProgressToken {
210 value: Some(match self {
211 Self::Number(number) => proto::progress_token::Value::Number(*number),
212 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
213 }),
214 }
215 }
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq)]
219pub enum FormatTrigger {
220 Save,
221 Manual,
222}
223
224pub enum LspFormatTarget {
225 Buffers,
226 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
227}
228
229#[derive(Debug, Clone, PartialEq, Eq, Hash)]
230pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
231
232struct OpenLspBuffer(Entity<Buffer>);
233
234impl FormatTrigger {
235 fn from_proto(value: i32) -> FormatTrigger {
236 match value {
237 0 => FormatTrigger::Save,
238 1 => FormatTrigger::Manual,
239 _ => FormatTrigger::Save,
240 }
241 }
242}
243
244#[derive(Clone)]
245struct UnifiedLanguageServer {
246 id: LanguageServerId,
247 project_roots: HashSet<Arc<RelPath>>,
248}
249
250/// Settings that affect language server identity.
251///
252/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
253/// updated via `workspace/didChangeConfiguration` without restarting the server.
254#[derive(Clone, Debug, Hash, PartialEq, Eq)]
255struct LanguageServerSeedSettings {
256 binary: Option<BinarySettings>,
257 initialization_options: Option<serde_json::Value>,
258}
259
260#[derive(Clone, Debug, Hash, PartialEq, Eq)]
261struct LanguageServerSeed {
262 worktree_id: WorktreeId,
263 name: LanguageServerName,
264 toolchain: Option<Toolchain>,
265 settings: LanguageServerSeedSettings,
266}
267
268#[derive(Debug)]
269pub struct DocumentDiagnosticsUpdate<'a, D> {
270 pub diagnostics: D,
271 pub result_id: Option<SharedString>,
272 pub registration_id: Option<SharedString>,
273 pub server_id: LanguageServerId,
274 pub disk_based_sources: Cow<'a, [String]>,
275}
276
277pub struct DocumentDiagnostics {
278 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
279 document_abs_path: PathBuf,
280 version: Option<i32>,
281}
282
283#[derive(Default, Debug)]
284struct DynamicRegistrations {
285 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
286 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
287}
288
289pub struct LocalLspStore {
290 weak: WeakEntity<LspStore>,
291 pub worktree_store: Entity<WorktreeStore>,
292 toolchain_store: Entity<LocalToolchainStore>,
293 http_client: Arc<dyn HttpClient>,
294 environment: Entity<ProjectEnvironment>,
295 fs: Arc<dyn Fs>,
296 languages: Arc<LanguageRegistry>,
297 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
298 yarn: Entity<YarnPathStore>,
299 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
300 buffers_being_formatted: HashSet<BufferId>,
301 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
302 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
303 watched_manifest_filenames: HashSet<ManifestName>,
304 language_server_paths_watched_for_rename:
305 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
306 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
307 supplementary_language_servers:
308 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
309 prettier_store: Entity<PrettierStore>,
310 next_diagnostic_group_id: usize,
311 diagnostics: HashMap<
312 WorktreeId,
313 HashMap<
314 Arc<RelPath>,
315 Vec<(
316 LanguageServerId,
317 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
318 )>,
319 >,
320 >,
321 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
322 _subscription: gpui::Subscription,
323 lsp_tree: LanguageServerTree,
324 registered_buffers: HashMap<BufferId, usize>,
325 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
326 buffer_pull_diagnostics_result_ids: HashMap<
327 LanguageServerId,
328 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
329 >,
330 workspace_pull_diagnostics_result_ids: HashMap<
331 LanguageServerId,
332 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
333 >,
334 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
335
336 buffers_to_refresh_hash_set: HashSet<BufferId>,
337 buffers_to_refresh_queue: VecDeque<BufferId>,
338 _background_diagnostics_worker: Shared<Task<()>>,
339}
340
341impl LocalLspStore {
342 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
343 pub fn running_language_server_for_id(
344 &self,
345 id: LanguageServerId,
346 ) -> Option<&Arc<LanguageServer>> {
347 let language_server_state = self.language_servers.get(&id)?;
348
349 match language_server_state {
350 LanguageServerState::Running { server, .. } => Some(server),
351 LanguageServerState::Starting { .. } => None,
352 }
353 }
354
355 fn get_or_insert_language_server(
356 &mut self,
357 worktree_handle: &Entity<Worktree>,
358 delegate: Arc<LocalLspAdapterDelegate>,
359 disposition: &Arc<LaunchDisposition>,
360 language_name: &LanguageName,
361 cx: &mut App,
362 ) -> LanguageServerId {
363 let key = LanguageServerSeed {
364 worktree_id: worktree_handle.read(cx).id(),
365 name: disposition.server_name.clone(),
366 settings: LanguageServerSeedSettings {
367 binary: disposition.settings.binary.clone(),
368 initialization_options: disposition.settings.initialization_options.clone(),
369 },
370 toolchain: disposition.toolchain.clone(),
371 };
372 if let Some(state) = self.language_server_ids.get_mut(&key) {
373 state.project_roots.insert(disposition.path.path.clone());
374 state.id
375 } else {
376 let adapter = self
377 .languages
378 .lsp_adapters(language_name)
379 .into_iter()
380 .find(|adapter| adapter.name() == disposition.server_name)
381 .expect("To find LSP adapter");
382 let new_language_server_id = self.start_language_server(
383 worktree_handle,
384 delegate,
385 adapter,
386 disposition.settings.clone(),
387 key.clone(),
388 language_name.clone(),
389 cx,
390 );
391 if let Some(state) = self.language_server_ids.get_mut(&key) {
392 state.project_roots.insert(disposition.path.path.clone());
393 } else {
394 debug_assert!(
395 false,
396 "Expected `start_language_server` to ensure that `key` exists in a map"
397 );
398 }
399 new_language_server_id
400 }
401 }
402
403 fn start_language_server(
404 &mut self,
405 worktree_handle: &Entity<Worktree>,
406 delegate: Arc<LocalLspAdapterDelegate>,
407 adapter: Arc<CachedLspAdapter>,
408 settings: Arc<LspSettings>,
409 key: LanguageServerSeed,
410 language_name: LanguageName,
411 cx: &mut App,
412 ) -> LanguageServerId {
413 let worktree = worktree_handle.read(cx);
414
415 let worktree_id = worktree.id();
416 let worktree_abs_path = worktree.abs_path();
417 let toolchain = key.toolchain.clone();
418 let override_options = settings.initialization_options.clone();
419
420 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
421
422 let server_id = self.languages.next_language_server_id();
423 log::trace!(
424 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
425 adapter.name.0
426 );
427
428 let wait_until_worktree_trust =
429 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
430 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
431 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
432 });
433 if can_trust {
434 self.restricted_worktrees_tasks.remove(&worktree_id);
435 None
436 } else {
437 match self.restricted_worktrees_tasks.entry(worktree_id) {
438 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
439 hash_map::Entry::Vacant(v) => {
440 let (mut tx, rx) = watch::channel::<bool>();
441 let lsp_store = self.weak.clone();
442 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
443 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
444 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
445 tx.blocking_send(true).ok();
446 lsp_store
447 .update(cx, |lsp_store, _| {
448 if let Some(local_lsp_store) =
449 lsp_store.as_local_mut()
450 {
451 local_lsp_store
452 .restricted_worktrees_tasks
453 .remove(&worktree_id);
454 }
455 })
456 .ok();
457 }
458 }
459 });
460 v.insert((subscription, rx.clone()));
461 Some(rx)
462 }
463 }
464 }
465 });
466 let update_binary_status = wait_until_worktree_trust.is_none();
467
468 let binary = self.get_language_server_binary(
469 worktree_abs_path.clone(),
470 adapter.clone(),
471 settings,
472 toolchain.clone(),
473 delegate.clone(),
474 true,
475 wait_until_worktree_trust,
476 cx,
477 );
478 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
479
480 let pending_server = cx.spawn({
481 let adapter = adapter.clone();
482 let server_name = adapter.name.clone();
483 let stderr_capture = stderr_capture.clone();
484 #[cfg(any(test, feature = "test-support"))]
485 let lsp_store = self.weak.clone();
486 let pending_workspace_folders = pending_workspace_folders.clone();
487 async move |cx| {
488 let binary = binary.await?;
489 #[cfg(any(test, feature = "test-support"))]
490 if let Some(server) = lsp_store
491 .update(&mut cx.clone(), |this, cx| {
492 this.languages.create_fake_language_server(
493 server_id,
494 &server_name,
495 binary.clone(),
496 &mut cx.to_async(),
497 )
498 })
499 .ok()
500 .flatten()
501 {
502 return Ok(server);
503 }
504
505 let code_action_kinds = adapter.code_action_kinds();
506 lsp::LanguageServer::new(
507 stderr_capture,
508 server_id,
509 server_name,
510 binary,
511 &worktree_abs_path,
512 code_action_kinds,
513 Some(pending_workspace_folders),
514 cx,
515 )
516 }
517 });
518
519 let startup = {
520 let server_name = adapter.name.0.clone();
521 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
522 let key = key.clone();
523 let adapter = adapter.clone();
524 let lsp_store = self.weak.clone();
525 let pending_workspace_folders = pending_workspace_folders.clone();
526 let pull_diagnostics = ProjectSettings::get_global(cx)
527 .diagnostics
528 .lsp_pull_diagnostics
529 .enabled;
530 let settings_location = SettingsLocation {
531 worktree_id,
532 path: RelPath::empty(),
533 };
534 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
535 .language(Some(settings_location), Some(&language_name), cx)
536 .semantic_tokens
537 .use_tree_sitter();
538 cx.spawn(async move |cx| {
539 let result = async {
540 let language_server = pending_server.await?;
541
542 let workspace_config = Self::workspace_configuration_for_adapter(
543 adapter.adapter.clone(),
544 &delegate,
545 toolchain,
546 None,
547 cx,
548 )
549 .await?;
550
551 let mut initialization_options = Self::initialization_options_for_adapter(
552 adapter.adapter.clone(),
553 &delegate,
554 cx,
555 )
556 .await?;
557
558 match (&mut initialization_options, override_options) {
559 (Some(initialization_options), Some(override_options)) => {
560 merge_json_value_into(override_options, initialization_options);
561 }
562 (None, override_options) => initialization_options = override_options,
563 _ => {}
564 }
565
566 let initialization_params = cx.update(|cx| {
567 let mut params = language_server.default_initialize_params(
568 pull_diagnostics,
569 augments_syntax_tokens,
570 cx,
571 );
572 params.initialization_options = initialization_options;
573 adapter.adapter.prepare_initialize_params(params, cx)
574 })?;
575
576 Self::setup_lsp_messages(
577 lsp_store.clone(),
578 &language_server,
579 delegate.clone(),
580 adapter.clone(),
581 );
582
583 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
584 settings: workspace_config,
585 };
586 let language_server = cx
587 .update(|cx| {
588 let request_timeout = ProjectSettings::get_global(cx)
589 .global_lsp_settings
590 .get_request_timeout();
591
592 language_server.initialize(
593 initialization_params,
594 Arc::new(did_change_configuration_params.clone()),
595 request_timeout,
596 cx,
597 )
598 })
599 .await
600 .inspect_err(|_| {
601 if let Some(lsp_store) = lsp_store.upgrade() {
602 lsp_store.update(cx, |lsp_store, cx| {
603 lsp_store.cleanup_lsp_data(server_id);
604 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
605 });
606 }
607 })?;
608
609 language_server.notify::<lsp::notification::DidChangeConfiguration>(
610 did_change_configuration_params,
611 )?;
612
613 anyhow::Ok(language_server)
614 }
615 .await;
616
617 match result {
618 Ok(server) => {
619 lsp_store
620 .update(cx, |lsp_store, cx| {
621 lsp_store.insert_newly_running_language_server(
622 adapter,
623 server.clone(),
624 server_id,
625 key,
626 pending_workspace_folders,
627 cx,
628 );
629 })
630 .ok();
631 stderr_capture.lock().take();
632 Some(server)
633 }
634
635 Err(err) => {
636 let log = stderr_capture.lock().take().unwrap_or_default();
637 delegate.update_status(
638 adapter.name(),
639 BinaryStatus::Failed {
640 error: if log.is_empty() {
641 format!("{err:#}")
642 } else {
643 format!("{err:#}\n-- stderr --\n{log}")
644 },
645 },
646 );
647 log::error!(
648 "Failed to start language server {server_name:?}: {}",
649 redact_command(&format!("{err:?}"))
650 );
651 if !log.is_empty() {
652 log::error!("server stderr: {}", redact_command(&log));
653 }
654 None
655 }
656 }
657 })
658 };
659 let state = LanguageServerState::Starting {
660 startup,
661 pending_workspace_folders,
662 };
663
664 if update_binary_status {
665 self.languages
666 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
667 }
668
669 self.language_servers.insert(server_id, state);
670 self.language_server_ids
671 .entry(key)
672 .or_insert(UnifiedLanguageServer {
673 id: server_id,
674 project_roots: Default::default(),
675 });
676 server_id
677 }
678
679 fn get_language_server_binary(
680 &self,
681 worktree_abs_path: Arc<Path>,
682 adapter: Arc<CachedLspAdapter>,
683 settings: Arc<LspSettings>,
684 toolchain: Option<Toolchain>,
685 delegate: Arc<dyn LspAdapterDelegate>,
686 allow_binary_download: bool,
687 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
688 cx: &mut App,
689 ) -> Task<Result<LanguageServerBinary>> {
690 if let Some(settings) = &settings.binary
691 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
692 {
693 let settings = settings.clone();
694 let languages = self.languages.clone();
695 return cx.background_spawn(async move {
696 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
697 let already_trusted = *wait_until_worktree_trust.borrow();
698 if !already_trusted {
699 log::info!(
700 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
701 adapter.name(),
702 );
703 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
704 if worktree_trusted {
705 break;
706 }
707 }
708 log::info!(
709 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
710 adapter.name(),
711 );
712 }
713 languages
714 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
715 }
716 let mut env = delegate.shell_env().await;
717 env.extend(settings.env.unwrap_or_default());
718
719 Ok(LanguageServerBinary {
720 path: delegate.resolve_relative_path(path),
721 env: Some(env),
722 arguments: settings
723 .arguments
724 .unwrap_or_default()
725 .iter()
726 .map(Into::into)
727 .collect(),
728 })
729 });
730 }
731 let lsp_binary_options = LanguageServerBinaryOptions {
732 allow_path_lookup: !settings
733 .binary
734 .as_ref()
735 .and_then(|b| b.ignore_system_version)
736 .unwrap_or_default(),
737 allow_binary_download,
738 pre_release: settings
739 .fetch
740 .as_ref()
741 .and_then(|f| f.pre_release)
742 .unwrap_or(false),
743 };
744
745 cx.spawn(async move |cx| {
746 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
747 let already_trusted = *wait_until_worktree_trust.borrow();
748 if !already_trusted {
749 log::info!(
750 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
751 adapter.name(),
752 );
753 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
754 if worktree_trusted {
755 break;
756 }
757 }
758 log::info!(
759 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
760 adapter.name(),
761 );
762 }
763 }
764
765 let (existing_binary, maybe_download_binary) = adapter
766 .clone()
767 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
768 .await
769 .await;
770
771 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
772
773 let mut binary = match (existing_binary, maybe_download_binary) {
774 (binary, None) => binary?,
775 (Err(_), Some(downloader)) => downloader.await?,
776 (Ok(existing_binary), Some(downloader)) => {
777 let mut download_timeout = cx
778 .background_executor()
779 .timer(SERVER_DOWNLOAD_TIMEOUT)
780 .fuse();
781 let mut downloader = downloader.fuse();
782 futures::select! {
783 _ = download_timeout => {
784 // Return existing binary and kick the existing work to the background.
785 cx.spawn(async move |_| downloader.await).detach();
786 Ok(existing_binary)
787 },
788 downloaded_or_existing_binary = downloader => {
789 // If download fails, this results in the existing binary.
790 downloaded_or_existing_binary
791 }
792 }?
793 }
794 };
795 let mut shell_env = delegate.shell_env().await;
796
797 shell_env.extend(binary.env.unwrap_or_default());
798
799 if let Some(settings) = settings.binary.as_ref() {
800 if let Some(arguments) = &settings.arguments {
801 binary.arguments = arguments.iter().map(Into::into).collect();
802 }
803 if let Some(env) = &settings.env {
804 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
805 }
806 }
807
808 binary.env = Some(shell_env);
809 Ok(binary)
810 })
811 }
812
813 fn setup_lsp_messages(
814 lsp_store: WeakEntity<LspStore>,
815 language_server: &LanguageServer,
816 delegate: Arc<dyn LspAdapterDelegate>,
817 adapter: Arc<CachedLspAdapter>,
818 ) {
819 let name = language_server.name();
820 let server_id = language_server.server_id();
821 language_server
822 .on_notification::<lsp::notification::PublishDiagnostics, _>({
823 let adapter = adapter.clone();
824 let this = lsp_store.clone();
825 move |mut params, cx| {
826 let adapter = adapter.clone();
827 if let Some(this) = this.upgrade() {
828 this.update(cx, |this, cx| {
829 adapter.process_diagnostics(&mut params, server_id);
830
831 this.merge_lsp_diagnostics(
832 DiagnosticSourceKind::Pushed,
833 vec![DocumentDiagnosticsUpdate {
834 server_id,
835 diagnostics: params,
836 result_id: None,
837 disk_based_sources: Cow::Borrowed(
838 &adapter.disk_based_diagnostic_sources,
839 ),
840 registration_id: None,
841 }],
842 |_, diagnostic, _cx| match diagnostic.source_kind {
843 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
844 adapter.retain_old_diagnostic(diagnostic)
845 }
846 DiagnosticSourceKind::Pulled => true,
847 },
848 cx,
849 )
850 .log_err();
851 });
852 }
853 }
854 })
855 .detach();
856 language_server
857 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
858 let adapter = adapter.adapter.clone();
859 let delegate = delegate.clone();
860 let this = lsp_store.clone();
861 move |params, cx| {
862 let adapter = adapter.clone();
863 let delegate = delegate.clone();
864 let this = this.clone();
865 let mut cx = cx.clone();
866 async move {
867 let toolchain_for_id = this
868 .update(&mut cx, |this, _| {
869 this.as_local()?.language_server_ids.iter().find_map(
870 |(seed, value)| {
871 (value.id == server_id).then(|| seed.toolchain.clone())
872 },
873 )
874 })?
875 .context("Expected the LSP store to be in a local mode")?;
876
877 let mut scope_uri_to_workspace_config = BTreeMap::new();
878 for item in ¶ms.items {
879 let scope_uri = item.scope_uri.clone();
880 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
881 scope_uri_to_workspace_config.entry(scope_uri.clone())
882 else {
883 // We've already queried workspace configuration of this URI.
884 continue;
885 };
886 let workspace_config = Self::workspace_configuration_for_adapter(
887 adapter.clone(),
888 &delegate,
889 toolchain_for_id.clone(),
890 scope_uri,
891 &mut cx,
892 )
893 .await?;
894 new_scope_uri.insert(workspace_config);
895 }
896
897 Ok(params
898 .items
899 .into_iter()
900 .filter_map(|item| {
901 let workspace_config =
902 scope_uri_to_workspace_config.get(&item.scope_uri)?;
903 if let Some(section) = &item.section {
904 Some(
905 workspace_config
906 .get(section)
907 .cloned()
908 .unwrap_or(serde_json::Value::Null),
909 )
910 } else {
911 Some(workspace_config.clone())
912 }
913 })
914 .collect())
915 }
916 }
917 })
918 .detach();
919
920 language_server
921 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
922 let this = lsp_store.clone();
923 move |_, cx| {
924 let this = this.clone();
925 let cx = cx.clone();
926 async move {
927 let Some(server) =
928 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
929 else {
930 return Ok(None);
931 };
932 let root = server.workspace_folders();
933 Ok(Some(
934 root.into_iter()
935 .map(|uri| WorkspaceFolder {
936 uri,
937 name: Default::default(),
938 })
939 .collect(),
940 ))
941 }
942 }
943 })
944 .detach();
945 // Even though we don't have handling for these requests, respond to them to
946 // avoid stalling any language server like `gopls` which waits for a response
947 // to these requests when initializing.
948 language_server
949 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
950 let this = lsp_store.clone();
951 move |params, cx| {
952 let this = this.clone();
953 let mut cx = cx.clone();
954 async move {
955 this.update(&mut cx, |this, _| {
956 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
957 {
958 status
959 .progress_tokens
960 .insert(ProgressToken::from_lsp(params.token));
961 }
962 })?;
963
964 Ok(())
965 }
966 }
967 })
968 .detach();
969
970 language_server
971 .on_request::<lsp::request::RegisterCapability, _, _>({
972 let lsp_store = lsp_store.clone();
973 move |params, cx| {
974 let lsp_store = lsp_store.clone();
975 let mut cx = cx.clone();
976 async move {
977 lsp_store
978 .update(&mut cx, |lsp_store, cx| {
979 if lsp_store.as_local().is_some() {
980 match lsp_store
981 .register_server_capabilities(server_id, params, cx)
982 {
983 Ok(()) => {}
984 Err(e) => {
985 log::error!(
986 "Failed to register server capabilities: {e:#}"
987 );
988 }
989 };
990 }
991 })
992 .ok();
993 Ok(())
994 }
995 }
996 })
997 .detach();
998
999 language_server
1000 .on_request::<lsp::request::UnregisterCapability, _, _>({
1001 let lsp_store = lsp_store.clone();
1002 move |params, cx| {
1003 let lsp_store = lsp_store.clone();
1004 let mut cx = cx.clone();
1005 async move {
1006 lsp_store
1007 .update(&mut cx, |lsp_store, cx| {
1008 if lsp_store.as_local().is_some() {
1009 match lsp_store
1010 .unregister_server_capabilities(server_id, params, cx)
1011 {
1012 Ok(()) => {}
1013 Err(e) => {
1014 log::error!(
1015 "Failed to unregister server capabilities: {e:#}"
1016 );
1017 }
1018 }
1019 }
1020 })
1021 .ok();
1022 Ok(())
1023 }
1024 }
1025 })
1026 .detach();
1027
1028 language_server
1029 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1030 let this = lsp_store.clone();
1031 move |params, cx| {
1032 let mut cx = cx.clone();
1033 let this = this.clone();
1034 async move {
1035 LocalLspStore::on_lsp_workspace_edit(
1036 this.clone(),
1037 params,
1038 server_id,
1039 &mut cx,
1040 )
1041 .await
1042 }
1043 }
1044 })
1045 .detach();
1046
1047 language_server
1048 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1049 let lsp_store = lsp_store.clone();
1050 let request_id = Arc::new(AtomicUsize::new(0));
1051 move |(), cx| {
1052 let lsp_store = lsp_store.clone();
1053 let request_id = request_id.clone();
1054 let mut cx = cx.clone();
1055 async move {
1056 lsp_store
1057 .update(&mut cx, |lsp_store, cx| {
1058 let request_id =
1059 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1060 cx.emit(LspStoreEvent::RefreshInlayHints {
1061 server_id,
1062 request_id,
1063 });
1064 lsp_store
1065 .downstream_client
1066 .as_ref()
1067 .map(|(client, project_id)| {
1068 client.send(proto::RefreshInlayHints {
1069 project_id: *project_id,
1070 server_id: server_id.to_proto(),
1071 request_id: request_id.map(|id| id as u64),
1072 })
1073 })
1074 })?
1075 .transpose()?;
1076 Ok(())
1077 }
1078 }
1079 })
1080 .detach();
1081
1082 language_server
1083 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1084 let this = lsp_store.clone();
1085 move |(), cx| {
1086 let this = this.clone();
1087 let mut cx = cx.clone();
1088 async move {
1089 this.update(&mut cx, |this, cx| {
1090 this.invalidate_code_lens();
1091 cx.emit(LspStoreEvent::RefreshCodeLens);
1092 this.downstream_client.as_ref().map(|(client, project_id)| {
1093 client.send(proto::RefreshCodeLens {
1094 project_id: *project_id,
1095 })
1096 })
1097 })?
1098 .transpose()?;
1099 Ok(())
1100 }
1101 }
1102 })
1103 .detach();
1104
1105 language_server
1106 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1107 let lsp_store = lsp_store.clone();
1108 let request_id = Arc::new(AtomicUsize::new(0));
1109 move |(), cx| {
1110 let lsp_store = lsp_store.clone();
1111 let request_id = request_id.clone();
1112 let mut cx = cx.clone();
1113 async move {
1114 lsp_store
1115 .update(&mut cx, |lsp_store, cx| {
1116 let request_id =
1117 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1118 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1119 server_id,
1120 request_id,
1121 });
1122 lsp_store
1123 .downstream_client
1124 .as_ref()
1125 .map(|(client, project_id)| {
1126 client.send(proto::RefreshSemanticTokens {
1127 project_id: *project_id,
1128 server_id: server_id.to_proto(),
1129 request_id: request_id.map(|id| id as u64),
1130 })
1131 })
1132 })?
1133 .transpose()?;
1134 Ok(())
1135 }
1136 }
1137 })
1138 .detach();
1139
1140 language_server
1141 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1142 let this = lsp_store.clone();
1143 move |(), cx| {
1144 let this = this.clone();
1145 let mut cx = cx.clone();
1146 async move {
1147 this.update(&mut cx, |lsp_store, cx| {
1148 lsp_store.pull_workspace_diagnostics(server_id);
1149 lsp_store
1150 .downstream_client
1151 .as_ref()
1152 .map(|(client, project_id)| {
1153 client.send(proto::PullWorkspaceDiagnostics {
1154 project_id: *project_id,
1155 server_id: server_id.to_proto(),
1156 })
1157 })
1158 .transpose()?;
1159 anyhow::Ok(
1160 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1161 )
1162 })??
1163 .await;
1164 Ok(())
1165 }
1166 }
1167 })
1168 .detach();
1169
1170 language_server
1171 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1172 let this = lsp_store.clone();
1173 let name = name.to_string();
1174 let adapter = adapter.clone();
1175 move |params, cx| {
1176 let this = this.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 let mut cx = cx.clone();
1180 async move {
1181 let actions = params.actions.unwrap_or_default();
1182 let message = params.message.clone();
1183 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1184 let level = match params.typ {
1185 lsp::MessageType::ERROR => PromptLevel::Critical,
1186 lsp::MessageType::WARNING => PromptLevel::Warning,
1187 _ => PromptLevel::Info,
1188 };
1189 let request = LanguageServerPromptRequest::new(
1190 level,
1191 params.message,
1192 actions,
1193 name.clone(),
1194 tx,
1195 );
1196
1197 let did_update = this
1198 .update(&mut cx, |_, cx| {
1199 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1200 })
1201 .is_ok();
1202 if did_update {
1203 let response = rx.recv().await.ok();
1204 if let Some(ref selected_action) = response {
1205 let context = language::PromptResponseContext {
1206 message,
1207 selected_action: selected_action.clone(),
1208 };
1209 adapter.process_prompt_response(&context, &mut cx)
1210 }
1211
1212 Ok(response)
1213 } else {
1214 Ok(None)
1215 }
1216 }
1217 }
1218 })
1219 .detach();
1220 language_server
1221 .on_notification::<lsp::notification::ShowMessage, _>({
1222 let this = lsp_store.clone();
1223 let name = name.to_string();
1224 move |params, cx| {
1225 let this = this.clone();
1226 let name = name.to_string();
1227 let mut cx = cx.clone();
1228
1229 let (tx, _) = smol::channel::bounded(1);
1230 let level = match params.typ {
1231 lsp::MessageType::ERROR => PromptLevel::Critical,
1232 lsp::MessageType::WARNING => PromptLevel::Warning,
1233 _ => PromptLevel::Info,
1234 };
1235 let request =
1236 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1237
1238 let _ = this.update(&mut cx, |_, cx| {
1239 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1240 });
1241 }
1242 })
1243 .detach();
1244
1245 let disk_based_diagnostics_progress_token =
1246 adapter.disk_based_diagnostics_progress_token.clone();
1247
1248 language_server
1249 .on_notification::<lsp::notification::Progress, _>({
1250 let this = lsp_store.clone();
1251 move |params, cx| {
1252 if let Some(this) = this.upgrade() {
1253 this.update(cx, |this, cx| {
1254 this.on_lsp_progress(
1255 params,
1256 server_id,
1257 disk_based_diagnostics_progress_token.clone(),
1258 cx,
1259 );
1260 });
1261 }
1262 }
1263 })
1264 .detach();
1265
1266 language_server
1267 .on_notification::<lsp::notification::LogMessage, _>({
1268 let this = lsp_store.clone();
1269 move |params, cx| {
1270 if let Some(this) = this.upgrade() {
1271 this.update(cx, |_, cx| {
1272 cx.emit(LspStoreEvent::LanguageServerLog(
1273 server_id,
1274 LanguageServerLogType::Log(params.typ),
1275 params.message,
1276 ));
1277 });
1278 }
1279 }
1280 })
1281 .detach();
1282
1283 language_server
1284 .on_notification::<lsp::notification::LogTrace, _>({
1285 let this = lsp_store.clone();
1286 move |params, cx| {
1287 let mut cx = cx.clone();
1288 if let Some(this) = this.upgrade() {
1289 this.update(&mut cx, |_, cx| {
1290 cx.emit(LspStoreEvent::LanguageServerLog(
1291 server_id,
1292 LanguageServerLogType::Trace {
1293 verbose_info: params.verbose,
1294 },
1295 params.message,
1296 ));
1297 });
1298 }
1299 }
1300 })
1301 .detach();
1302
1303 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1304 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1305 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1306 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1307 }
1308
1309 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1310 let shutdown_futures = self
1311 .language_servers
1312 .drain()
1313 .map(|(_, server_state)| Self::shutdown_server(server_state))
1314 .collect::<Vec<_>>();
1315
1316 async move {
1317 join_all(shutdown_futures).await;
1318 }
1319 }
1320
1321 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1322 match server_state {
1323 LanguageServerState::Running { server, .. } => {
1324 if let Some(shutdown) = server.shutdown() {
1325 shutdown.await;
1326 }
1327 }
1328 LanguageServerState::Starting { startup, .. } => {
1329 if let Some(server) = startup.await
1330 && let Some(shutdown) = server.shutdown()
1331 {
1332 shutdown.await;
1333 }
1334 }
1335 }
1336 Ok(())
1337 }
1338
1339 fn language_servers_for_worktree(
1340 &self,
1341 worktree_id: WorktreeId,
1342 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1343 self.language_server_ids
1344 .iter()
1345 .filter_map(move |(seed, state)| {
1346 if seed.worktree_id != worktree_id {
1347 return None;
1348 }
1349
1350 if let Some(LanguageServerState::Running { server, .. }) =
1351 self.language_servers.get(&state.id)
1352 {
1353 Some(server)
1354 } else {
1355 None
1356 }
1357 })
1358 }
1359
1360 fn language_server_ids_for_project_path(
1361 &self,
1362 project_path: ProjectPath,
1363 language: &Language,
1364 cx: &mut App,
1365 ) -> Vec<LanguageServerId> {
1366 let Some(worktree) = self
1367 .worktree_store
1368 .read(cx)
1369 .worktree_for_id(project_path.worktree_id, cx)
1370 else {
1371 return Vec::new();
1372 };
1373 let delegate: Arc<dyn ManifestDelegate> =
1374 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1375
1376 self.lsp_tree
1377 .get(
1378 project_path,
1379 language.name(),
1380 language.manifest(),
1381 &delegate,
1382 cx,
1383 )
1384 .collect::<Vec<_>>()
1385 }
1386
1387 fn language_server_ids_for_buffer(
1388 &self,
1389 buffer: &Buffer,
1390 cx: &mut App,
1391 ) -> Vec<LanguageServerId> {
1392 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1393 let worktree_id = file.worktree_id(cx);
1394
1395 let path: Arc<RelPath> = file
1396 .path()
1397 .parent()
1398 .map(Arc::from)
1399 .unwrap_or_else(|| file.path().clone());
1400 let worktree_path = ProjectPath { worktree_id, path };
1401 self.language_server_ids_for_project_path(worktree_path, language, cx)
1402 } else {
1403 Vec::new()
1404 }
1405 }
1406
1407 fn language_servers_for_buffer<'a>(
1408 &'a self,
1409 buffer: &'a Buffer,
1410 cx: &'a mut App,
1411 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1412 self.language_server_ids_for_buffer(buffer, cx)
1413 .into_iter()
1414 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1415 LanguageServerState::Running {
1416 adapter, server, ..
1417 } => Some((adapter, server)),
1418 _ => None,
1419 })
1420 }
1421
1422 async fn execute_code_action_kind_locally(
1423 lsp_store: WeakEntity<LspStore>,
1424 mut buffers: Vec<Entity<Buffer>>,
1425 kind: CodeActionKind,
1426 push_to_history: bool,
1427 cx: &mut AsyncApp,
1428 ) -> anyhow::Result<ProjectTransaction> {
1429 // Do not allow multiple concurrent code actions requests for the
1430 // same buffer.
1431 lsp_store.update(cx, |this, cx| {
1432 let this = this.as_local_mut().unwrap();
1433 buffers.retain(|buffer| {
1434 this.buffers_being_formatted
1435 .insert(buffer.read(cx).remote_id())
1436 });
1437 })?;
1438 let _cleanup = defer({
1439 let this = lsp_store.clone();
1440 let mut cx = cx.clone();
1441 let buffers = &buffers;
1442 move || {
1443 this.update(&mut cx, |this, cx| {
1444 let this = this.as_local_mut().unwrap();
1445 for buffer in buffers {
1446 this.buffers_being_formatted
1447 .remove(&buffer.read(cx).remote_id());
1448 }
1449 })
1450 .ok();
1451 }
1452 });
1453 let mut project_transaction = ProjectTransaction::default();
1454
1455 for buffer in &buffers {
1456 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1457 buffer.update(cx, |buffer, cx| {
1458 lsp_store
1459 .as_local()
1460 .unwrap()
1461 .language_servers_for_buffer(buffer, cx)
1462 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1463 .collect::<Vec<_>>()
1464 })
1465 })?;
1466 for (_, language_server) in adapters_and_servers.iter() {
1467 let actions = Self::get_server_code_actions_from_action_kinds(
1468 &lsp_store,
1469 language_server.server_id(),
1470 vec![kind.clone()],
1471 buffer,
1472 cx,
1473 )
1474 .await?;
1475 Self::execute_code_actions_on_server(
1476 &lsp_store,
1477 language_server,
1478 actions,
1479 push_to_history,
1480 &mut project_transaction,
1481 cx,
1482 )
1483 .await?;
1484 }
1485 }
1486 Ok(project_transaction)
1487 }
1488
1489 async fn format_locally(
1490 lsp_store: WeakEntity<LspStore>,
1491 mut buffers: Vec<FormattableBuffer>,
1492 push_to_history: bool,
1493 trigger: FormatTrigger,
1494 logger: zlog::Logger,
1495 cx: &mut AsyncApp,
1496 ) -> anyhow::Result<ProjectTransaction> {
1497 // Do not allow multiple concurrent formatting requests for the
1498 // same buffer.
1499 lsp_store.update(cx, |this, cx| {
1500 let this = this.as_local_mut().unwrap();
1501 buffers.retain(|buffer| {
1502 this.buffers_being_formatted
1503 .insert(buffer.handle.read(cx).remote_id())
1504 });
1505 })?;
1506
1507 let _cleanup = defer({
1508 let this = lsp_store.clone();
1509 let mut cx = cx.clone();
1510 let buffers = &buffers;
1511 move || {
1512 this.update(&mut cx, |this, cx| {
1513 let this = this.as_local_mut().unwrap();
1514 for buffer in buffers {
1515 this.buffers_being_formatted
1516 .remove(&buffer.handle.read(cx).remote_id());
1517 }
1518 })
1519 .ok();
1520 }
1521 });
1522
1523 let mut project_transaction = ProjectTransaction::default();
1524
1525 for buffer in &buffers {
1526 zlog::debug!(
1527 logger =>
1528 "formatting buffer '{:?}'",
1529 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1530 );
1531 // Create an empty transaction to hold all of the formatting edits.
1532 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1533 // ensure no transactions created while formatting are
1534 // grouped with the previous transaction in the history
1535 // based on the transaction group interval
1536 buffer.finalize_last_transaction();
1537 buffer
1538 .start_transaction()
1539 .context("transaction already open")?;
1540 buffer.end_transaction(cx);
1541 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1542 buffer.finalize_last_transaction();
1543 anyhow::Ok(transaction_id)
1544 })?;
1545
1546 let result = Self::format_buffer_locally(
1547 lsp_store.clone(),
1548 buffer,
1549 formatting_transaction_id,
1550 trigger,
1551 logger,
1552 cx,
1553 )
1554 .await;
1555
1556 buffer.handle.update(cx, |buffer, cx| {
1557 let Some(formatting_transaction) =
1558 buffer.get_transaction(formatting_transaction_id).cloned()
1559 else {
1560 zlog::warn!(logger => "no formatting transaction");
1561 return;
1562 };
1563 if formatting_transaction.edit_ids.is_empty() {
1564 zlog::debug!(logger => "no changes made while formatting");
1565 buffer.forget_transaction(formatting_transaction_id);
1566 return;
1567 }
1568 if !push_to_history {
1569 zlog::trace!(logger => "forgetting format transaction");
1570 buffer.forget_transaction(formatting_transaction.id);
1571 }
1572 project_transaction
1573 .0
1574 .insert(cx.entity(), formatting_transaction);
1575 });
1576
1577 result?;
1578 }
1579
1580 Ok(project_transaction)
1581 }
1582
1583 async fn format_buffer_locally(
1584 lsp_store: WeakEntity<LspStore>,
1585 buffer: &FormattableBuffer,
1586 formatting_transaction_id: clock::Lamport,
1587 trigger: FormatTrigger,
1588 logger: zlog::Logger,
1589 cx: &mut AsyncApp,
1590 ) -> Result<()> {
1591 let (adapters_and_servers, settings, request_timeout) =
1592 lsp_store.update(cx, |lsp_store, cx| {
1593 buffer.handle.update(cx, |buffer, cx| {
1594 let adapters_and_servers = lsp_store
1595 .as_local()
1596 .unwrap()
1597 .language_servers_for_buffer(buffer, cx)
1598 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1599 .collect::<Vec<_>>();
1600 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1601 let request_timeout = ProjectSettings::get_global(cx)
1602 .global_lsp_settings
1603 .get_request_timeout();
1604 (adapters_and_servers, settings, request_timeout)
1605 })
1606 })?;
1607 let had_existing_line_endings = buffer
1608 .handle
1609 .read_with(cx, |buffer, _| buffer.max_point().row > 0);
1610
1611 // handle whitespace formatting
1612 if settings.remove_trailing_whitespace_on_save {
1613 zlog::trace!(logger => "removing trailing whitespace");
1614 let diff = buffer
1615 .handle
1616 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1617 .await;
1618 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1619 buffer.apply_diff(diff, cx);
1620 })?;
1621 }
1622
1623 if settings.ensure_final_newline_on_save {
1624 zlog::trace!(logger => "ensuring final newline");
1625 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1626 buffer.ensure_final_newline(cx);
1627 })?;
1628 }
1629
1630 let line_ending_policy = match settings.line_ending {
1631 LineEndingSetting::Detect => None,
1632 LineEndingSetting::PreferLf => Some((LineEnding::Unix, true)),
1633 LineEndingSetting::PreferCrlf => Some((LineEnding::Windows, true)),
1634 LineEndingSetting::EnforceLf => Some((LineEnding::Unix, false)),
1635 LineEndingSetting::EnforceCrlf => Some((LineEnding::Windows, false)),
1636 };
1637 if let Some((desired_line_ending, preserve_existing)) = line_ending_policy {
1638 buffer.handle.update(cx, |buffer, cx| {
1639 if buffer.line_ending() == desired_line_ending {
1640 return;
1641 }
1642 if preserve_existing && had_existing_line_endings {
1643 zlog::trace!(
1644 logger => "preserving existing line endings ({}) on save",
1645 buffer.line_ending().label()
1646 );
1647 return;
1648 }
1649 zlog::trace!(logger => "normalizing line endings to {}", desired_line_ending.label());
1650 buffer.set_line_ending(desired_line_ending, cx);
1651 });
1652 }
1653
1654 // Formatter for `code_actions_on_format` that runs before
1655 // the rest of the formatters
1656 let mut code_actions_on_format_formatters = None;
1657 let should_run_code_actions_on_format = !matches!(
1658 (trigger, &settings.format_on_save),
1659 (FormatTrigger::Save, &FormatOnSave::Off)
1660 );
1661 if should_run_code_actions_on_format {
1662 let have_code_actions_to_run_on_format = settings
1663 .code_actions_on_format
1664 .values()
1665 .any(|enabled| *enabled);
1666 if have_code_actions_to_run_on_format {
1667 zlog::trace!(logger => "going to run code actions on format");
1668 code_actions_on_format_formatters = Some(
1669 settings
1670 .code_actions_on_format
1671 .iter()
1672 .filter_map(|(action, enabled)| enabled.then_some(action))
1673 .cloned()
1674 .map(Formatter::CodeAction)
1675 .collect::<Vec<_>>(),
1676 );
1677 }
1678 }
1679
1680 let formatters = match (trigger, &settings.format_on_save) {
1681 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1682 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1683 settings.formatter.as_ref()
1684 }
1685 };
1686
1687 let formatters = code_actions_on_format_formatters
1688 .iter()
1689 .flatten()
1690 .chain(formatters);
1691
1692 for formatter in formatters {
1693 let formatter = if formatter == &Formatter::Auto {
1694 if settings.prettier.allowed {
1695 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1696 &Formatter::Prettier
1697 } else {
1698 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1699 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1700 }
1701 } else {
1702 formatter
1703 };
1704 if let Err(err) = Self::apply_formatter(
1705 formatter,
1706 &lsp_store,
1707 buffer,
1708 formatting_transaction_id,
1709 &adapters_and_servers,
1710 &settings,
1711 request_timeout,
1712 logger,
1713 cx,
1714 )
1715 .await
1716 {
1717 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1718 }
1719 }
1720
1721 Ok(())
1722 }
1723
1724 async fn apply_formatter(
1725 formatter: &Formatter,
1726 lsp_store: &WeakEntity<LspStore>,
1727 buffer: &FormattableBuffer,
1728 formatting_transaction_id: clock::Lamport,
1729 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1730 settings: &LanguageSettings,
1731 request_timeout: Duration,
1732 logger: zlog::Logger,
1733 cx: &mut AsyncApp,
1734 ) -> anyhow::Result<()> {
1735 match formatter {
1736 Formatter::None => {
1737 zlog::trace!(logger => "skipping formatter 'none'");
1738 return Ok(());
1739 }
1740 Formatter::Auto => {
1741 debug_panic!("Auto resolved above");
1742 return Ok(());
1743 }
1744 Formatter::Prettier => {
1745 let logger = zlog::scoped!(logger => "prettier");
1746 zlog::trace!(logger => "formatting");
1747 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1748
1749 // When selection ranges are provided (via FormatSelections), we pass the
1750 // encompassing UTF-16 range to Prettier so it can scope its formatting.
1751 // After diffing, we filter the resulting edits to only keep those that
1752 // overlap with the original byte-level selection ranges.
1753 let (range_utf16, byte_ranges) = match buffer.ranges.as_ref() {
1754 Some(ranges) if !ranges.is_empty() => {
1755 let (utf16_range, byte_ranges) =
1756 buffer.handle.read_with(cx, |buffer, _cx| {
1757 let snapshot = buffer.snapshot();
1758 let mut min_start_utf16 = OffsetUtf16(usize::MAX);
1759 let mut max_end_utf16 = OffsetUtf16(0);
1760 let mut byte_ranges = Vec::with_capacity(ranges.len());
1761 for range in ranges {
1762 let start_utf16 = range.start.to_offset_utf16(&snapshot);
1763 let end_utf16 = range.end.to_offset_utf16(&snapshot);
1764 min_start_utf16.0 = min_start_utf16.0.min(start_utf16.0);
1765 max_end_utf16.0 = max_end_utf16.0.max(end_utf16.0);
1766
1767 let start_byte = range.start.to_offset(&snapshot);
1768 let end_byte = range.end.to_offset(&snapshot);
1769 byte_ranges.push(start_byte..end_byte);
1770 }
1771 (min_start_utf16..max_end_utf16, byte_ranges)
1772 });
1773 (Some(utf16_range), Some(byte_ranges))
1774 }
1775 _ => (None, None),
1776 };
1777
1778 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1779 lsp_store.prettier_store().unwrap().downgrade()
1780 })?;
1781 let diff = prettier_store::format_with_prettier(
1782 &prettier,
1783 &buffer.handle,
1784 range_utf16,
1785 cx,
1786 )
1787 .await
1788 .transpose()?;
1789 let Some(mut diff) = diff else {
1790 zlog::trace!(logger => "No changes");
1791 return Ok(());
1792 };
1793
1794 if let Some(byte_ranges) = byte_ranges {
1795 diff.edits.retain(|(edit_range, _)| {
1796 byte_ranges.iter().any(|selection_range| {
1797 edit_range.start < selection_range.end
1798 && edit_range.end > selection_range.start
1799 })
1800 });
1801 if diff.edits.is_empty() {
1802 zlog::trace!(logger => "No changes within selection");
1803 return Ok(());
1804 }
1805 }
1806
1807 extend_formatting_transaction(
1808 buffer,
1809 formatting_transaction_id,
1810 cx,
1811 |buffer, cx| {
1812 buffer.apply_diff(diff, cx);
1813 },
1814 )?;
1815 }
1816 Formatter::External { command, arguments } => {
1817 let logger = zlog::scoped!(logger => "command");
1818
1819 if buffer.ranges.is_some() {
1820 zlog::debug!(logger => "External formatter does not support range formatting; skipping");
1821 return Ok(());
1822 }
1823
1824 zlog::trace!(logger => "formatting");
1825 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1826
1827 let diff =
1828 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1829 .await
1830 .with_context(|| {
1831 format!("Failed to format buffer via external command: {}", command)
1832 })?;
1833 let Some(diff) = diff else {
1834 zlog::trace!(logger => "No changes");
1835 return Ok(());
1836 };
1837
1838 extend_formatting_transaction(
1839 buffer,
1840 formatting_transaction_id,
1841 cx,
1842 |buffer, cx| {
1843 buffer.apply_diff(diff, cx);
1844 },
1845 )?;
1846 }
1847 Formatter::LanguageServer(specifier) => {
1848 let logger = zlog::scoped!(logger => "language-server");
1849 zlog::trace!(logger => "formatting");
1850 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1851
1852 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1853 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1854 return Ok(());
1855 };
1856
1857 let language_server = match specifier {
1858 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1859 adapters_and_servers.iter().find_map(|(adapter, server)| {
1860 if adapter.name.0.as_ref() == name {
1861 Some(server.clone())
1862 } else {
1863 None
1864 }
1865 })
1866 }
1867 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1868 .iter()
1869 .find(|(_, server)| Self::server_supports_formatting(server))
1870 .map(|(_, server)| server.clone()),
1871 };
1872
1873 let Some(language_server) = language_server else {
1874 log::debug!(
1875 "No language server found to format buffer '{:?}'. Skipping",
1876 buffer_path_abs.as_path().to_string_lossy()
1877 );
1878 return Ok(());
1879 };
1880
1881 zlog::trace!(
1882 logger =>
1883 "Formatting buffer '{:?}' using language server '{:?}'",
1884 buffer_path_abs.as_path().to_string_lossy(),
1885 language_server.name()
1886 );
1887
1888 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1889 zlog::trace!(logger => "formatting ranges");
1890 Self::format_ranges_via_lsp(
1891 &lsp_store,
1892 &buffer.handle,
1893 ranges,
1894 buffer_path_abs,
1895 &language_server,
1896 &settings,
1897 cx,
1898 )
1899 .await
1900 .context("Failed to format ranges via language server")?
1901 } else {
1902 zlog::trace!(logger => "formatting full");
1903 Self::format_via_lsp(
1904 &lsp_store,
1905 &buffer.handle,
1906 buffer_path_abs,
1907 &language_server,
1908 &settings,
1909 cx,
1910 )
1911 .await
1912 .context("failed to format via language server")?
1913 };
1914
1915 if edits.is_empty() {
1916 zlog::trace!(logger => "No changes");
1917 return Ok(());
1918 }
1919 extend_formatting_transaction(
1920 buffer,
1921 formatting_transaction_id,
1922 cx,
1923 |buffer, cx| {
1924 buffer.edit(edits, None, cx);
1925 },
1926 )?;
1927 }
1928 Formatter::CodeAction(code_action_name) => {
1929 let logger = zlog::scoped!(logger => "code-actions");
1930 zlog::trace!(logger => "formatting");
1931 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1932
1933 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1934 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1935 return Ok(());
1936 };
1937
1938 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1939 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1940
1941 let mut actions_and_servers = Vec::new();
1942
1943 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1944 let actions_result = Self::get_server_code_actions_from_action_kinds(
1945 &lsp_store,
1946 language_server.server_id(),
1947 vec![code_action_kind.clone()],
1948 &buffer.handle,
1949 cx,
1950 )
1951 .await
1952 .with_context(|| {
1953 format!(
1954 "Failed to resolve code action {:?} with language server {}",
1955 code_action_kind,
1956 language_server.name()
1957 )
1958 });
1959 let Ok(actions) = actions_result else {
1960 // note: it may be better to set result to the error and break formatters here
1961 // but for now we try to execute the actions that we can resolve and skip the rest
1962 zlog::error!(
1963 logger =>
1964 "Failed to resolve code action {:?} with language server {}",
1965 code_action_kind,
1966 language_server.name()
1967 );
1968 continue;
1969 };
1970 for action in actions {
1971 actions_and_servers.push((action, index));
1972 }
1973 }
1974
1975 if actions_and_servers.is_empty() {
1976 zlog::warn!(logger => "No code actions were resolved, continuing");
1977 return Ok(());
1978 }
1979
1980 'actions: for (mut action, server_index) in actions_and_servers {
1981 let server = &adapters_and_servers[server_index].1;
1982
1983 let describe_code_action = |action: &CodeAction| {
1984 format!(
1985 "code action '{}' with title \"{}\" on server {}",
1986 action
1987 .lsp_action
1988 .action_kind()
1989 .unwrap_or("unknown".into())
1990 .as_str(),
1991 action.lsp_action.title(),
1992 server.name(),
1993 )
1994 };
1995
1996 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1997
1998 if let Err(err) =
1999 Self::try_resolve_code_action(server, &mut action, request_timeout).await
2000 {
2001 zlog::error!(
2002 logger =>
2003 "Failed to resolve {}. Error: {}",
2004 describe_code_action(&action),
2005 err
2006 );
2007 continue;
2008 }
2009
2010 if let Some(edit) = action.lsp_action.edit().cloned() {
2011 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
2012 // but filters out and logs warnings for code actions that require unreasonably
2013 // difficult handling on our part, such as:
2014 // - applying edits that call commands
2015 // which can result in arbitrary workspace edits being sent from the server that
2016 // have no way of being tied back to the command that initiated them (i.e. we
2017 // can't know which edits are part of the format request, or if the server is done sending
2018 // actions in response to the command)
2019 // - actions that create/delete/modify/rename files other than the one we are formatting
2020 // as we then would need to handle such changes correctly in the local history as well
2021 // as the remote history through the ProjectTransaction
2022 // - actions with snippet edits, as these simply don't make sense in the context of a format request
2023 // Supporting these actions is not impossible, but not supported as of yet.
2024 if edit.changes.is_none() && edit.document_changes.is_none() {
2025 zlog::trace!(
2026 logger =>
2027 "No changes for code action. Skipping {}",
2028 describe_code_action(&action),
2029 );
2030 continue;
2031 }
2032
2033 let mut operations = Vec::new();
2034 if let Some(document_changes) = edit.document_changes {
2035 match document_changes {
2036 lsp::DocumentChanges::Edits(edits) => operations.extend(
2037 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
2038 ),
2039 lsp::DocumentChanges::Operations(ops) => operations = ops,
2040 }
2041 } else if let Some(changes) = edit.changes {
2042 operations.extend(changes.into_iter().map(|(uri, edits)| {
2043 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2044 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2045 uri,
2046 version: None,
2047 },
2048 edits: edits.into_iter().map(Edit::Plain).collect(),
2049 })
2050 }));
2051 }
2052
2053 let mut edits = Vec::with_capacity(operations.len());
2054
2055 if operations.is_empty() {
2056 zlog::trace!(
2057 logger =>
2058 "No changes for code action. Skipping {}",
2059 describe_code_action(&action),
2060 );
2061 continue;
2062 }
2063 for operation in operations {
2064 let op = match operation {
2065 lsp::DocumentChangeOperation::Edit(op) => op,
2066 lsp::DocumentChangeOperation::Op(_) => {
2067 zlog::warn!(
2068 logger =>
2069 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
2070 describe_code_action(&action),
2071 );
2072 continue 'actions;
2073 }
2074 };
2075 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2076 zlog::warn!(
2077 logger =>
2078 "Failed to convert URI '{:?}' to file path. Skipping {}",
2079 &op.text_document.uri,
2080 describe_code_action(&action),
2081 );
2082 continue 'actions;
2083 };
2084 if &file_path != buffer_path_abs {
2085 zlog::warn!(
2086 logger =>
2087 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2088 file_path,
2089 buffer_path_abs,
2090 describe_code_action(&action),
2091 );
2092 continue 'actions;
2093 }
2094
2095 let mut lsp_edits = Vec::new();
2096 for edit in op.edits {
2097 match edit {
2098 Edit::Plain(edit) => {
2099 if !lsp_edits.contains(&edit) {
2100 lsp_edits.push(edit);
2101 }
2102 }
2103 Edit::Annotated(edit) => {
2104 if !lsp_edits.contains(&edit.text_edit) {
2105 lsp_edits.push(edit.text_edit);
2106 }
2107 }
2108 Edit::Snippet(_) => {
2109 zlog::warn!(
2110 logger =>
2111 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2112 describe_code_action(&action),
2113 );
2114 continue 'actions;
2115 }
2116 }
2117 }
2118 let edits_result = lsp_store
2119 .update(cx, |lsp_store, cx| {
2120 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2121 &buffer.handle,
2122 lsp_edits,
2123 server.server_id(),
2124 op.text_document.version,
2125 cx,
2126 )
2127 })?
2128 .await;
2129 let Ok(resolved_edits) = edits_result else {
2130 zlog::warn!(
2131 logger =>
2132 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2133 buffer_path_abs.as_path(),
2134 describe_code_action(&action),
2135 );
2136 continue 'actions;
2137 };
2138 edits.extend(resolved_edits);
2139 }
2140
2141 if edits.is_empty() {
2142 zlog::warn!(logger => "No edits resolved from LSP");
2143 continue;
2144 }
2145
2146 extend_formatting_transaction(
2147 buffer,
2148 formatting_transaction_id,
2149 cx,
2150 |buffer, cx| {
2151 zlog::info!(
2152 "Applying edits {edits:?}. Content: {:?}",
2153 buffer.text()
2154 );
2155 buffer.edit(edits, None, cx);
2156 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2157 },
2158 )?;
2159 }
2160
2161 let Some(command) = action.lsp_action.command() else {
2162 continue;
2163 };
2164
2165 zlog::warn!(
2166 logger =>
2167 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2168 &command.command,
2169 );
2170
2171 let server_capabilities = server.capabilities();
2172 let available_commands = server_capabilities
2173 .execute_command_provider
2174 .as_ref()
2175 .map(|options| options.commands.as_slice())
2176 .unwrap_or_default();
2177 if !available_commands.contains(&command.command) {
2178 zlog::warn!(
2179 logger =>
2180 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2181 command.command,
2182 server.name(),
2183 );
2184 continue;
2185 }
2186
2187 extend_formatting_transaction(
2188 buffer,
2189 formatting_transaction_id,
2190 cx,
2191 |_, _| {},
2192 )?;
2193 zlog::info!(logger => "Executing command {}", &command.command);
2194
2195 lsp_store.update(cx, |this, _| {
2196 this.as_local_mut()
2197 .unwrap()
2198 .last_workspace_edits_by_language_server
2199 .remove(&server.server_id());
2200 })?;
2201
2202 let execute_command_result = server
2203 .request::<lsp::request::ExecuteCommand>(
2204 lsp::ExecuteCommandParams {
2205 command: command.command.clone(),
2206 arguments: command.arguments.clone().unwrap_or_default(),
2207 ..Default::default()
2208 },
2209 request_timeout,
2210 )
2211 .await
2212 .into_response();
2213
2214 if execute_command_result.is_err() {
2215 zlog::error!(
2216 logger =>
2217 "Failed to execute command '{}' as part of {}",
2218 &command.command,
2219 describe_code_action(&action),
2220 );
2221 continue 'actions;
2222 }
2223
2224 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2225 this.as_local_mut()
2226 .unwrap()
2227 .last_workspace_edits_by_language_server
2228 .remove(&server.server_id())
2229 .unwrap_or_default()
2230 })?;
2231
2232 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2233 {
2234 zlog::trace!(
2235 logger =>
2236 "Successfully captured {} edits that resulted from command {}",
2237 transaction.edit_ids.len(),
2238 &command.command,
2239 );
2240 let transaction_id_project_transaction = transaction.id;
2241 buffer.handle.update(cx, |buffer, _| {
2242 // it may have been removed from history if push_to_history was
2243 // false in deserialize_workspace_edit. If so push it so we
2244 // can merge it with the format transaction
2245 // and pop the combined transaction off the history stack
2246 // later if push_to_history is false
2247 if buffer.get_transaction(transaction.id).is_none() {
2248 buffer.push_transaction(transaction, Instant::now());
2249 }
2250 buffer.merge_transactions(
2251 transaction_id_project_transaction,
2252 formatting_transaction_id,
2253 );
2254 });
2255 }
2256
2257 if project_transaction_command.0.is_empty() {
2258 continue;
2259 }
2260
2261 let mut extra_buffers = String::new();
2262 for buffer in project_transaction_command.0.keys() {
2263 buffer.read_with(cx, |b, cx| {
2264 let Some(path) = b.project_path(cx) else {
2265 return;
2266 };
2267
2268 if !extra_buffers.is_empty() {
2269 extra_buffers.push_str(", ");
2270 }
2271 extra_buffers.push_str(path.path.as_unix_str());
2272 });
2273 }
2274 zlog::warn!(
2275 logger =>
2276 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2277 &command.command,
2278 extra_buffers,
2279 );
2280 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2281 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2282 // add it so it's included, and merge it into the format transaction when its created later
2283 }
2284 }
2285 }
2286
2287 Ok(())
2288 }
2289
2290 pub async fn format_ranges_via_lsp(
2291 this: &WeakEntity<LspStore>,
2292 buffer_handle: &Entity<Buffer>,
2293 ranges: &[Range<Anchor>],
2294 abs_path: &Path,
2295 language_server: &Arc<LanguageServer>,
2296 settings: &LanguageSettings,
2297 cx: &mut AsyncApp,
2298 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2299 let capabilities = &language_server.capabilities();
2300 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2301 if range_formatting_provider == Some(&OneOf::Left(false)) {
2302 anyhow::bail!(
2303 "{} language server does not support range formatting",
2304 language_server.name()
2305 );
2306 }
2307
2308 let uri = file_path_to_lsp_url(abs_path)?;
2309 let text_document = lsp::TextDocumentIdentifier::new(uri);
2310
2311 let request_timeout = cx.update(|app| {
2312 ProjectSettings::get_global(app)
2313 .global_lsp_settings
2314 .get_request_timeout()
2315 });
2316 let lsp_edits = {
2317 let mut lsp_ranges = Vec::new();
2318 this.update(cx, |_this, cx| {
2319 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2320 // not have been sent to the language server. This seems like a fairly systemic
2321 // issue, though, the resolution probably is not specific to formatting.
2322 //
2323 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2324 // LSP.
2325 let snapshot = buffer_handle.read(cx).snapshot();
2326 for range in ranges {
2327 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2328 }
2329 anyhow::Ok(())
2330 })??;
2331
2332 let mut edits = None;
2333 for range in lsp_ranges {
2334 if let Some(mut edit) = language_server
2335 .request::<lsp::request::RangeFormatting>(
2336 lsp::DocumentRangeFormattingParams {
2337 text_document: text_document.clone(),
2338 range,
2339 options: lsp_command::lsp_formatting_options(settings),
2340 work_done_progress_params: Default::default(),
2341 },
2342 request_timeout,
2343 )
2344 .await
2345 .into_response()?
2346 {
2347 edits.get_or_insert_with(Vec::new).append(&mut edit);
2348 }
2349 }
2350 edits
2351 };
2352
2353 if let Some(lsp_edits) = lsp_edits {
2354 this.update(cx, |this, cx| {
2355 this.as_local_mut().unwrap().edits_from_lsp(
2356 buffer_handle,
2357 lsp_edits,
2358 language_server.server_id(),
2359 None,
2360 cx,
2361 )
2362 })?
2363 .await
2364 } else {
2365 Ok(Vec::with_capacity(0))
2366 }
2367 }
2368
2369 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2370 let capabilities = server.capabilities();
2371 let formatting = capabilities.document_formatting_provider.as_ref();
2372 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2373 || server_capabilities_support_range_formatting(&capabilities)
2374 }
2375
2376 async fn format_via_lsp(
2377 this: &WeakEntity<LspStore>,
2378 buffer: &Entity<Buffer>,
2379 abs_path: &Path,
2380 language_server: &Arc<LanguageServer>,
2381 settings: &LanguageSettings,
2382 cx: &mut AsyncApp,
2383 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2384 let logger = zlog::scoped!("lsp_format");
2385 zlog::debug!(logger => "Formatting via LSP");
2386
2387 let uri = file_path_to_lsp_url(abs_path)?;
2388 let text_document = lsp::TextDocumentIdentifier::new(uri);
2389 let capabilities = &language_server.capabilities();
2390
2391 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2392 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2393
2394 let request_timeout = cx.update(|app| {
2395 ProjectSettings::get_global(app)
2396 .global_lsp_settings
2397 .get_request_timeout()
2398 });
2399
2400 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2401 let _timer = zlog::time!(logger => "format-full");
2402 language_server
2403 .request::<lsp::request::Formatting>(
2404 lsp::DocumentFormattingParams {
2405 text_document,
2406 options: lsp_command::lsp_formatting_options(settings),
2407 work_done_progress_params: Default::default(),
2408 },
2409 request_timeout,
2410 )
2411 .await
2412 .into_response()?
2413 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2414 let _timer = zlog::time!(logger => "format-range");
2415 let buffer_start = lsp::Position::new(0, 0);
2416 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2417 language_server
2418 .request::<lsp::request::RangeFormatting>(
2419 lsp::DocumentRangeFormattingParams {
2420 text_document: text_document.clone(),
2421 range: lsp::Range::new(buffer_start, buffer_end),
2422 options: lsp_command::lsp_formatting_options(settings),
2423 work_done_progress_params: Default::default(),
2424 },
2425 request_timeout,
2426 )
2427 .await
2428 .into_response()?
2429 } else {
2430 None
2431 };
2432
2433 if let Some(lsp_edits) = lsp_edits {
2434 this.update(cx, |this, cx| {
2435 this.as_local_mut().unwrap().edits_from_lsp(
2436 buffer,
2437 lsp_edits,
2438 language_server.server_id(),
2439 None,
2440 cx,
2441 )
2442 })?
2443 .await
2444 } else {
2445 Ok(Vec::with_capacity(0))
2446 }
2447 }
2448
2449 async fn format_via_external_command(
2450 buffer: &FormattableBuffer,
2451 command: &str,
2452 arguments: Option<&[String]>,
2453 cx: &mut AsyncApp,
2454 ) -> Result<Option<Diff>> {
2455 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2456 let file = File::from_dyn(buffer.file())?;
2457 let worktree = file.worktree.read(cx);
2458 let mut worktree_path = worktree.abs_path().to_path_buf();
2459 if worktree.root_entry()?.is_file() {
2460 worktree_path.pop();
2461 }
2462 Some(worktree_path)
2463 });
2464
2465 use util::command::Stdio;
2466 let mut child = util::command::new_command(command);
2467
2468 if let Some(buffer_env) = buffer.env.as_ref() {
2469 child.envs(buffer_env);
2470 }
2471
2472 if let Some(working_dir_path) = working_dir_path {
2473 child.current_dir(working_dir_path);
2474 }
2475
2476 if let Some(arguments) = arguments {
2477 child.args(arguments.iter().map(|arg| {
2478 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2479 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2480 } else {
2481 arg.replace("{buffer_path}", "Untitled")
2482 }
2483 }));
2484 }
2485
2486 let mut child = child
2487 .stdin(Stdio::piped())
2488 .stdout(Stdio::piped())
2489 .stderr(Stdio::piped())
2490 .spawn()?;
2491
2492 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2493 let text = buffer
2494 .handle
2495 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2496 for chunk in text.chunks() {
2497 stdin.write_all(chunk.as_bytes()).await?;
2498 }
2499 stdin.flush().await?;
2500
2501 let output = child.output().await?;
2502 anyhow::ensure!(
2503 output.status.success(),
2504 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2505 output.status.code(),
2506 String::from_utf8_lossy(&output.stdout),
2507 String::from_utf8_lossy(&output.stderr),
2508 );
2509
2510 let stdout = String::from_utf8(output.stdout)?;
2511 Ok(Some(
2512 buffer
2513 .handle
2514 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2515 .await,
2516 ))
2517 }
2518
2519 async fn try_resolve_code_action(
2520 lang_server: &LanguageServer,
2521 action: &mut CodeAction,
2522 request_timeout: Duration,
2523 ) -> anyhow::Result<()> {
2524 match &mut action.lsp_action {
2525 LspAction::Action(lsp_action) => {
2526 if !action.resolved
2527 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2528 && lsp_action.data.is_some()
2529 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2530 {
2531 **lsp_action = lang_server
2532 .request::<lsp::request::CodeActionResolveRequest>(
2533 *lsp_action.clone(),
2534 request_timeout,
2535 )
2536 .await
2537 .into_response()?;
2538 }
2539 }
2540 LspAction::CodeLens(lens) => {
2541 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2542 *lens = lang_server
2543 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2544 .await
2545 .into_response()?;
2546 }
2547 }
2548 LspAction::Command(_) => {}
2549 }
2550
2551 action.resolved = true;
2552 anyhow::Ok(())
2553 }
2554
2555 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2556 let buffer = buffer_handle.read(cx);
2557
2558 let file = buffer.file().cloned();
2559
2560 let Some(file) = File::from_dyn(file.as_ref()) else {
2561 return;
2562 };
2563 if !file.is_local() {
2564 return;
2565 }
2566 let path = ProjectPath::from_file(file, cx);
2567 let worktree_id = file.worktree_id(cx);
2568 let language = buffer.language().cloned();
2569
2570 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2571 for (server_id, diagnostics) in
2572 diagnostics.get(file.path()).cloned().unwrap_or_default()
2573 {
2574 self.update_buffer_diagnostics(
2575 buffer_handle,
2576 server_id,
2577 None,
2578 None,
2579 None,
2580 Vec::new(),
2581 diagnostics,
2582 cx,
2583 )
2584 .log_err();
2585 }
2586 }
2587 let Some(language) = language else {
2588 return;
2589 };
2590 let Some(snapshot) = self
2591 .worktree_store
2592 .read(cx)
2593 .worktree_for_id(worktree_id, cx)
2594 .map(|worktree| worktree.read(cx).snapshot())
2595 else {
2596 return;
2597 };
2598 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2599
2600 for server_id in
2601 self.lsp_tree
2602 .get(path, language.name(), language.manifest(), &delegate, cx)
2603 {
2604 let server = self
2605 .language_servers
2606 .get(&server_id)
2607 .and_then(|server_state| {
2608 if let LanguageServerState::Running { server, .. } = server_state {
2609 Some(server.clone())
2610 } else {
2611 None
2612 }
2613 });
2614 let server = match server {
2615 Some(server) => server,
2616 None => continue,
2617 };
2618
2619 buffer_handle.update(cx, |buffer, cx| {
2620 buffer.set_completion_triggers(
2621 server.server_id(),
2622 server
2623 .capabilities()
2624 .completion_provider
2625 .as_ref()
2626 .and_then(|provider| {
2627 provider
2628 .trigger_characters
2629 .as_ref()
2630 .map(|characters| characters.iter().cloned().collect())
2631 })
2632 .unwrap_or_default(),
2633 cx,
2634 );
2635 });
2636 }
2637 }
2638
2639 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2640 buffer.update(cx, |buffer, cx| {
2641 let Some(language) = buffer.language() else {
2642 return;
2643 };
2644 let path = ProjectPath {
2645 worktree_id: old_file.worktree_id(cx),
2646 path: old_file.path.clone(),
2647 };
2648 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2649 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2650 buffer.set_completion_triggers(server_id, Default::default(), cx);
2651 }
2652 });
2653 }
2654
2655 fn update_buffer_diagnostics(
2656 &mut self,
2657 buffer: &Entity<Buffer>,
2658 server_id: LanguageServerId,
2659 registration_id: Option<Option<SharedString>>,
2660 result_id: Option<SharedString>,
2661 version: Option<i32>,
2662 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2663 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2664 cx: &mut Context<LspStore>,
2665 ) -> Result<()> {
2666 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2667 Ordering::Equal
2668 .then_with(|| b.is_primary.cmp(&a.is_primary))
2669 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2670 .then_with(|| a.severity.cmp(&b.severity))
2671 .then_with(|| a.message.cmp(&b.message))
2672 }
2673
2674 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2675 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2676 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2677
2678 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2679 Ordering::Equal
2680 .then_with(|| a.range.start.cmp(&b.range.start))
2681 .then_with(|| b.range.end.cmp(&a.range.end))
2682 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2683 });
2684
2685 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2686
2687 let edits_since_save = std::cell::LazyCell::new(|| {
2688 let saved_version = buffer.read(cx).saved_version();
2689 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2690 });
2691
2692 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2693
2694 for (new_diagnostic, entry) in diagnostics {
2695 let start;
2696 let end;
2697 if new_diagnostic && entry.diagnostic.is_disk_based {
2698 // Some diagnostics are based on files on disk instead of buffers'
2699 // current contents. Adjust these diagnostics' ranges to reflect
2700 // any unsaved edits.
2701 // Do not alter the reused ones though, as their coordinates were stored as anchors
2702 // and were properly adjusted on reuse.
2703 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2704 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2705 } else {
2706 start = entry.range.start;
2707 end = entry.range.end;
2708 }
2709
2710 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2711 ..snapshot.clip_point_utf16(end, Bias::Right);
2712
2713 // Expand empty ranges by one codepoint
2714 if range.start == range.end {
2715 // This will be go to the next boundary when being clipped
2716 range.end.column += 1;
2717 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2718 if range.start == range.end && range.end.column > 0 {
2719 range.start.column -= 1;
2720 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2721 }
2722 }
2723
2724 sanitized_diagnostics.push(DiagnosticEntry {
2725 range,
2726 diagnostic: entry.diagnostic,
2727 });
2728 }
2729 drop(edits_since_save);
2730
2731 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2732 buffer.update(cx, |buffer, cx| {
2733 if let Some(registration_id) = registration_id {
2734 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2735 self.buffer_pull_diagnostics_result_ids
2736 .entry(server_id)
2737 .or_default()
2738 .entry(registration_id)
2739 .or_default()
2740 .insert(abs_path, result_id);
2741 }
2742 }
2743
2744 buffer.update_diagnostics(server_id, set, cx)
2745 });
2746
2747 Ok(())
2748 }
2749
2750 fn register_language_server_for_invisible_worktree(
2751 &mut self,
2752 worktree: &Entity<Worktree>,
2753 language_server_id: LanguageServerId,
2754 cx: &mut App,
2755 ) {
2756 let worktree = worktree.read(cx);
2757 let worktree_id = worktree.id();
2758 debug_assert!(!worktree.is_visible());
2759 let Some(mut origin_seed) = self
2760 .language_server_ids
2761 .iter()
2762 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2763 else {
2764 return;
2765 };
2766 origin_seed.worktree_id = worktree_id;
2767 self.language_server_ids
2768 .entry(origin_seed)
2769 .or_insert_with(|| UnifiedLanguageServer {
2770 id: language_server_id,
2771 project_roots: Default::default(),
2772 });
2773 }
2774
2775 fn register_buffer_with_language_servers(
2776 &mut self,
2777 buffer_handle: &Entity<Buffer>,
2778 only_register_servers: HashSet<LanguageServerSelector>,
2779 cx: &mut Context<LspStore>,
2780 ) {
2781 let buffer = buffer_handle.read(cx);
2782 let buffer_id = buffer.remote_id();
2783
2784 let Some(file) = File::from_dyn(buffer.file()) else {
2785 return;
2786 };
2787 if !file.is_local() {
2788 return;
2789 }
2790
2791 let abs_path = file.abs_path(cx);
2792 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2793 return;
2794 };
2795 let initial_snapshot = buffer.text_snapshot();
2796 let worktree_id = file.worktree_id(cx);
2797
2798 let Some(language) = buffer.language().cloned() else {
2799 return;
2800 };
2801 let path: Arc<RelPath> = file
2802 .path()
2803 .parent()
2804 .map(Arc::from)
2805 .unwrap_or_else(|| file.path().clone());
2806 let Some(worktree) = self
2807 .worktree_store
2808 .read(cx)
2809 .worktree_for_id(worktree_id, cx)
2810 else {
2811 return;
2812 };
2813 let language_name = language.name();
2814 let (reused, delegate, servers) = self
2815 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2816 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2817 .unwrap_or_else(|| {
2818 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2819 let delegate: Arc<dyn ManifestDelegate> =
2820 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2821
2822 let servers = self
2823 .lsp_tree
2824 .walk(
2825 ProjectPath { worktree_id, path },
2826 language.name(),
2827 language.manifest(),
2828 &delegate,
2829 cx,
2830 )
2831 .collect::<Vec<_>>();
2832 (false, lsp_delegate, servers)
2833 });
2834 let servers_and_adapters = servers
2835 .into_iter()
2836 .filter_map(|server_node| {
2837 if reused && server_node.server_id().is_none() {
2838 return None;
2839 }
2840 if !only_register_servers.is_empty() {
2841 if let Some(server_id) = server_node.server_id()
2842 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2843 {
2844 return None;
2845 }
2846 if let Some(name) = server_node.name()
2847 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2848 {
2849 return None;
2850 }
2851 }
2852
2853 let server_id = server_node.server_id_or_init(|disposition| {
2854 let path = &disposition.path;
2855
2856 {
2857 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2858
2859 let server_id = self.get_or_insert_language_server(
2860 &worktree,
2861 delegate.clone(),
2862 disposition,
2863 &language_name,
2864 cx,
2865 );
2866
2867 if let Some(state) = self.language_servers.get(&server_id)
2868 && let Ok(uri) = uri
2869 {
2870 state.add_workspace_folder(uri);
2871 };
2872 server_id
2873 }
2874 })?;
2875 let server_state = self.language_servers.get(&server_id)?;
2876 if let LanguageServerState::Running {
2877 server, adapter, ..
2878 } = server_state
2879 {
2880 Some((server.clone(), adapter.clone()))
2881 } else {
2882 None
2883 }
2884 })
2885 .collect::<Vec<_>>();
2886 for (server, adapter) in servers_and_adapters {
2887 buffer_handle.update(cx, |buffer, cx| {
2888 buffer.set_completion_triggers(
2889 server.server_id(),
2890 server
2891 .capabilities()
2892 .completion_provider
2893 .as_ref()
2894 .and_then(|provider| {
2895 provider
2896 .trigger_characters
2897 .as_ref()
2898 .map(|characters| characters.iter().cloned().collect())
2899 })
2900 .unwrap_or_default(),
2901 cx,
2902 );
2903 });
2904
2905 let snapshot = LspBufferSnapshot {
2906 version: 0,
2907 snapshot: initial_snapshot.clone(),
2908 };
2909
2910 let mut registered = false;
2911 self.buffer_snapshots
2912 .entry(buffer_id)
2913 .or_default()
2914 .entry(server.server_id())
2915 .or_insert_with(|| {
2916 registered = true;
2917 server.register_buffer(
2918 uri.clone(),
2919 adapter.language_id(&language.name()),
2920 0,
2921 initial_snapshot.text(),
2922 );
2923
2924 vec![snapshot]
2925 });
2926
2927 self.buffers_opened_in_servers
2928 .entry(buffer_id)
2929 .or_default()
2930 .insert(server.server_id());
2931 if registered {
2932 cx.emit(LspStoreEvent::LanguageServerUpdate {
2933 language_server_id: server.server_id(),
2934 name: None,
2935 message: proto::update_language_server::Variant::RegisteredForBuffer(
2936 proto::RegisteredForBuffer {
2937 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2938 buffer_id: buffer_id.to_proto(),
2939 },
2940 ),
2941 });
2942 }
2943 }
2944 }
2945
2946 fn reuse_existing_language_server<'lang_name>(
2947 &self,
2948 server_tree: &LanguageServerTree,
2949 worktree: &Entity<Worktree>,
2950 language_name: &'lang_name LanguageName,
2951 cx: &mut App,
2952 ) -> Option<(
2953 Arc<LocalLspAdapterDelegate>,
2954 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2955 )> {
2956 if worktree.read(cx).is_visible() {
2957 return None;
2958 }
2959
2960 let worktree_store = self.worktree_store.read(cx);
2961 let servers = server_tree
2962 .instances
2963 .iter()
2964 .filter(|(worktree_id, _)| {
2965 worktree_store
2966 .worktree_for_id(**worktree_id, cx)
2967 .is_some_and(|worktree| worktree.read(cx).is_visible())
2968 })
2969 .flat_map(|(worktree_id, servers)| {
2970 servers
2971 .roots
2972 .iter()
2973 .flat_map(|(_, language_servers)| language_servers)
2974 .map(move |(_, (server_node, server_languages))| {
2975 (worktree_id, server_node, server_languages)
2976 })
2977 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2978 .map(|(worktree_id, server_node, _)| {
2979 (
2980 *worktree_id,
2981 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2982 )
2983 })
2984 })
2985 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2986 acc.entry(worktree_id)
2987 .or_insert_with(Vec::new)
2988 .push(server_node);
2989 acc
2990 })
2991 .into_values()
2992 .max_by_key(|servers| servers.len())?;
2993
2994 let worktree_id = worktree.read(cx).id();
2995 let apply = move |tree: &mut LanguageServerTree| {
2996 for server_node in &servers {
2997 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2998 }
2999 servers
3000 };
3001
3002 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
3003 Some((delegate, apply))
3004 }
3005
3006 pub(crate) fn unregister_old_buffer_from_language_servers(
3007 &mut self,
3008 buffer: &Entity<Buffer>,
3009 old_file: &File,
3010 cx: &mut App,
3011 ) {
3012 let old_path = match old_file.as_local() {
3013 Some(local) => local.abs_path(cx),
3014 None => return,
3015 };
3016
3017 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
3018 debug_panic!("{old_path:?} is not parseable as an URI");
3019 return;
3020 };
3021 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
3022 }
3023
3024 pub(crate) fn unregister_buffer_from_language_servers(
3025 &mut self,
3026 buffer: &Entity<Buffer>,
3027 file_url: &lsp::Uri,
3028 cx: &mut App,
3029 ) {
3030 buffer.update(cx, |buffer, cx| {
3031 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
3032
3033 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
3034 if snapshots
3035 .as_mut()
3036 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
3037 {
3038 language_server.unregister_buffer(file_url.clone());
3039 }
3040 }
3041 });
3042 }
3043
3044 fn buffer_snapshot_for_lsp_version(
3045 &mut self,
3046 buffer: &Entity<Buffer>,
3047 server_id: LanguageServerId,
3048 version: Option<i32>,
3049 cx: &App,
3050 ) -> Result<TextBufferSnapshot> {
3051 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
3052
3053 if let Some(version) = version {
3054 let buffer_id = buffer.read(cx).remote_id();
3055 let snapshots = if let Some(snapshots) = self
3056 .buffer_snapshots
3057 .get_mut(&buffer_id)
3058 .and_then(|m| m.get_mut(&server_id))
3059 {
3060 snapshots
3061 } else if version == 0 {
3062 // Some language servers report version 0 even if the buffer hasn't been opened yet.
3063 // We detect this case and treat it as if the version was `None`.
3064 return Ok(buffer.read(cx).text_snapshot());
3065 } else {
3066 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
3067 };
3068
3069 let found_snapshot = snapshots
3070 .binary_search_by_key(&version, |e| e.version)
3071 .map(|ix| snapshots[ix].snapshot.clone())
3072 .map_err(|_| {
3073 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3074 })?;
3075
3076 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3077 Ok(found_snapshot)
3078 } else {
3079 Ok((buffer.read(cx)).text_snapshot())
3080 }
3081 }
3082
3083 async fn get_server_code_actions_from_action_kinds(
3084 lsp_store: &WeakEntity<LspStore>,
3085 language_server_id: LanguageServerId,
3086 code_action_kinds: Vec<lsp::CodeActionKind>,
3087 buffer: &Entity<Buffer>,
3088 cx: &mut AsyncApp,
3089 ) -> Result<Vec<CodeAction>> {
3090 let actions = lsp_store
3091 .update(cx, move |this, cx| {
3092 let request = GetCodeActions {
3093 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3094 kinds: Some(code_action_kinds),
3095 };
3096 let server = LanguageServerToQuery::Other(language_server_id);
3097 this.request_lsp(buffer.clone(), server, request, cx)
3098 })?
3099 .await?;
3100 Ok(actions)
3101 }
3102
3103 pub async fn execute_code_actions_on_server(
3104 lsp_store: &WeakEntity<LspStore>,
3105 language_server: &Arc<LanguageServer>,
3106 actions: Vec<CodeAction>,
3107 push_to_history: bool,
3108 project_transaction: &mut ProjectTransaction,
3109 cx: &mut AsyncApp,
3110 ) -> anyhow::Result<()> {
3111 let request_timeout = cx.update(|app| {
3112 ProjectSettings::get_global(app)
3113 .global_lsp_settings
3114 .get_request_timeout()
3115 });
3116
3117 for mut action in actions {
3118 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3119 .await
3120 .context("resolving a formatting code action")?;
3121
3122 if let Some(edit) = action.lsp_action.edit() {
3123 if edit.changes.is_none() && edit.document_changes.is_none() {
3124 continue;
3125 }
3126
3127 let new = Self::deserialize_workspace_edit(
3128 lsp_store.upgrade().context("project dropped")?,
3129 edit.clone(),
3130 push_to_history,
3131 language_server.clone(),
3132 cx,
3133 )
3134 .await?;
3135 project_transaction.0.extend(new.0);
3136 }
3137
3138 let Some(command) = action.lsp_action.command() else {
3139 continue;
3140 };
3141
3142 let server_capabilities = language_server.capabilities();
3143 let available_commands = server_capabilities
3144 .execute_command_provider
3145 .as_ref()
3146 .map(|options| options.commands.as_slice())
3147 .unwrap_or_default();
3148 if !available_commands.contains(&command.command) {
3149 log::warn!(
3150 "Cannot execute a command {} not listed in the language server capabilities",
3151 command.command
3152 );
3153 continue;
3154 }
3155
3156 lsp_store.update(cx, |lsp_store, _| {
3157 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3158 mode.last_workspace_edits_by_language_server
3159 .remove(&language_server.server_id());
3160 }
3161 })?;
3162
3163 language_server
3164 .request::<lsp::request::ExecuteCommand>(
3165 lsp::ExecuteCommandParams {
3166 command: command.command.clone(),
3167 arguments: command.arguments.clone().unwrap_or_default(),
3168 ..Default::default()
3169 },
3170 request_timeout,
3171 )
3172 .await
3173 .into_response()
3174 .context("execute command")?;
3175
3176 lsp_store.update(cx, |this, _| {
3177 if let LspStoreMode::Local(mode) = &mut this.mode {
3178 project_transaction.0.extend(
3179 mode.last_workspace_edits_by_language_server
3180 .remove(&language_server.server_id())
3181 .unwrap_or_default()
3182 .0,
3183 )
3184 }
3185 })?;
3186 }
3187 Ok(())
3188 }
3189
3190 pub async fn deserialize_text_edits(
3191 this: Entity<LspStore>,
3192 buffer_to_edit: Entity<Buffer>,
3193 edits: Vec<lsp::TextEdit>,
3194 push_to_history: bool,
3195 _: Arc<CachedLspAdapter>,
3196 language_server: Arc<LanguageServer>,
3197 cx: &mut AsyncApp,
3198 ) -> Result<Option<Transaction>> {
3199 let edits = this
3200 .update(cx, |this, cx| {
3201 this.as_local_mut().unwrap().edits_from_lsp(
3202 &buffer_to_edit,
3203 edits,
3204 language_server.server_id(),
3205 None,
3206 cx,
3207 )
3208 })
3209 .await?;
3210
3211 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3212 buffer.finalize_last_transaction();
3213 buffer.start_transaction();
3214 for (range, text) in edits {
3215 buffer.edit([(range, text)], None, cx);
3216 }
3217
3218 if buffer.end_transaction(cx).is_some() {
3219 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3220 if !push_to_history {
3221 buffer.forget_transaction(transaction.id);
3222 }
3223 Some(transaction)
3224 } else {
3225 None
3226 }
3227 });
3228
3229 Ok(transaction)
3230 }
3231
3232 #[allow(clippy::type_complexity)]
3233 pub fn edits_from_lsp(
3234 &mut self,
3235 buffer: &Entity<Buffer>,
3236 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3237 server_id: LanguageServerId,
3238 version: Option<i32>,
3239 cx: &mut Context<LspStore>,
3240 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3241 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3242 cx.background_spawn(async move {
3243 let snapshot = snapshot?;
3244 let mut lsp_edits = lsp_edits
3245 .into_iter()
3246 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3247 .collect::<Vec<_>>();
3248
3249 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3250
3251 let mut lsp_edits = lsp_edits.into_iter().peekable();
3252 let mut edits = Vec::new();
3253 while let Some((range, mut new_text)) = lsp_edits.next() {
3254 // Clip invalid ranges provided by the language server.
3255 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3256 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3257
3258 // Combine any LSP edits that are adjacent.
3259 //
3260 // Also, combine LSP edits that are separated from each other by only
3261 // a newline. This is important because for some code actions,
3262 // Rust-analyzer rewrites the entire buffer via a series of edits that
3263 // are separated by unchanged newline characters.
3264 //
3265 // In order for the diffing logic below to work properly, any edits that
3266 // cancel each other out must be combined into one.
3267 while let Some((next_range, next_text)) = lsp_edits.peek() {
3268 if next_range.start.0 > range.end {
3269 if next_range.start.0.row > range.end.row + 1
3270 || next_range.start.0.column > 0
3271 || snapshot.clip_point_utf16(
3272 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3273 Bias::Left,
3274 ) > range.end
3275 {
3276 break;
3277 }
3278 new_text.push('\n');
3279 }
3280 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3281 new_text.push_str(next_text);
3282 lsp_edits.next();
3283 }
3284
3285 // For multiline edits, perform a diff of the old and new text so that
3286 // we can identify the changes more precisely, preserving the locations
3287 // of any anchors positioned in the unchanged regions.
3288 if range.end.row > range.start.row {
3289 let offset = range.start.to_offset(&snapshot);
3290 let old_text = snapshot.text_for_range(range).collect::<String>();
3291 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3292 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3293 (
3294 snapshot.anchor_after(offset + range.start)
3295 ..snapshot.anchor_before(offset + range.end),
3296 replacement,
3297 )
3298 }));
3299 } else if range.end == range.start {
3300 let anchor = snapshot.anchor_after(range.start);
3301 edits.push((anchor..anchor, new_text.into()));
3302 } else {
3303 let edit_start = snapshot.anchor_after(range.start);
3304 let edit_end = snapshot.anchor_before(range.end);
3305 edits.push((edit_start..edit_end, new_text.into()));
3306 }
3307 }
3308
3309 Ok(edits)
3310 })
3311 }
3312
3313 pub(crate) async fn deserialize_workspace_edit(
3314 this: Entity<LspStore>,
3315 edit: lsp::WorkspaceEdit,
3316 push_to_history: bool,
3317 language_server: Arc<LanguageServer>,
3318 cx: &mut AsyncApp,
3319 ) -> Result<ProjectTransaction> {
3320 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3321
3322 let mut operations = Vec::new();
3323 if let Some(document_changes) = edit.document_changes {
3324 match document_changes {
3325 lsp::DocumentChanges::Edits(edits) => {
3326 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3327 }
3328 lsp::DocumentChanges::Operations(ops) => operations = ops,
3329 }
3330 } else if let Some(changes) = edit.changes {
3331 operations.extend(changes.into_iter().map(|(uri, edits)| {
3332 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3333 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3334 uri,
3335 version: None,
3336 },
3337 edits: edits.into_iter().map(Edit::Plain).collect(),
3338 })
3339 }));
3340 }
3341
3342 let mut project_transaction = ProjectTransaction::default();
3343 for operation in operations {
3344 match operation {
3345 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3346 let abs_path = op
3347 .uri
3348 .to_file_path()
3349 .map_err(|()| anyhow!("can't convert URI to path"))?;
3350
3351 if let Some(parent_path) = abs_path.parent() {
3352 fs.create_dir(parent_path).await?;
3353 }
3354 if abs_path.ends_with("/") {
3355 fs.create_dir(&abs_path).await?;
3356 } else {
3357 fs.create_file(
3358 &abs_path,
3359 op.options
3360 .map(|options| fs::CreateOptions {
3361 overwrite: options.overwrite.unwrap_or(false),
3362 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3363 })
3364 .unwrap_or_default(),
3365 )
3366 .await?;
3367 }
3368 }
3369
3370 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3371 let source_abs_path = op
3372 .old_uri
3373 .to_file_path()
3374 .map_err(|()| anyhow!("can't convert URI to path"))?;
3375 let target_abs_path = op
3376 .new_uri
3377 .to_file_path()
3378 .map_err(|()| anyhow!("can't convert URI to path"))?;
3379
3380 let options = fs::RenameOptions {
3381 overwrite: op
3382 .options
3383 .as_ref()
3384 .and_then(|options| options.overwrite)
3385 .unwrap_or(false),
3386 ignore_if_exists: op
3387 .options
3388 .as_ref()
3389 .and_then(|options| options.ignore_if_exists)
3390 .unwrap_or(false),
3391 create_parents: true,
3392 };
3393
3394 fs.rename(&source_abs_path, &target_abs_path, options)
3395 .await?;
3396 }
3397
3398 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3399 let abs_path = op
3400 .uri
3401 .to_file_path()
3402 .map_err(|()| anyhow!("can't convert URI to path"))?;
3403 let options = op
3404 .options
3405 .map(|options| fs::RemoveOptions {
3406 recursive: options.recursive.unwrap_or(false),
3407 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3408 })
3409 .unwrap_or_default();
3410 if abs_path.ends_with("/") {
3411 fs.remove_dir(&abs_path, options).await?;
3412 } else {
3413 fs.remove_file(&abs_path, options).await?;
3414 }
3415 }
3416
3417 lsp::DocumentChangeOperation::Edit(op) => {
3418 let buffer_to_edit = this
3419 .update(cx, |this, cx| {
3420 this.open_local_buffer_via_lsp(
3421 op.text_document.uri.clone(),
3422 language_server.server_id(),
3423 cx,
3424 )
3425 })
3426 .await?;
3427
3428 let edits = this
3429 .update(cx, |this, cx| {
3430 let path = buffer_to_edit.read(cx).project_path(cx);
3431 let active_entry = this.active_entry;
3432 let is_active_entry = path.is_some_and(|project_path| {
3433 this.worktree_store
3434 .read(cx)
3435 .entry_for_path(&project_path, cx)
3436 .is_some_and(|entry| Some(entry.id) == active_entry)
3437 });
3438 let local = this.as_local_mut().unwrap();
3439
3440 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3441 for edit in op.edits {
3442 match edit {
3443 Edit::Plain(edit) => {
3444 if !edits.contains(&edit) {
3445 edits.push(edit)
3446 }
3447 }
3448 Edit::Annotated(edit) => {
3449 if !edits.contains(&edit.text_edit) {
3450 edits.push(edit.text_edit)
3451 }
3452 }
3453 Edit::Snippet(edit) => {
3454 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3455 else {
3456 continue;
3457 };
3458
3459 if is_active_entry {
3460 snippet_edits.push((edit.range, snippet));
3461 } else {
3462 // Since this buffer is not focused, apply a normal edit.
3463 let new_edit = TextEdit {
3464 range: edit.range,
3465 new_text: snippet.text,
3466 };
3467 if !edits.contains(&new_edit) {
3468 edits.push(new_edit);
3469 }
3470 }
3471 }
3472 }
3473 }
3474 if !snippet_edits.is_empty() {
3475 let buffer_id = buffer_to_edit.read(cx).remote_id();
3476 let version = if let Some(buffer_version) = op.text_document.version
3477 {
3478 local
3479 .buffer_snapshot_for_lsp_version(
3480 &buffer_to_edit,
3481 language_server.server_id(),
3482 Some(buffer_version),
3483 cx,
3484 )
3485 .ok()
3486 .map(|snapshot| snapshot.version)
3487 } else {
3488 Some(buffer_to_edit.read(cx).saved_version().clone())
3489 };
3490
3491 let most_recent_edit =
3492 version.and_then(|version| version.most_recent());
3493 // Check if the edit that triggered that edit has been made by this participant.
3494
3495 if let Some(most_recent_edit) = most_recent_edit {
3496 cx.emit(LspStoreEvent::SnippetEdit {
3497 buffer_id,
3498 edits: snippet_edits,
3499 most_recent_edit,
3500 });
3501 }
3502 }
3503
3504 local.edits_from_lsp(
3505 &buffer_to_edit,
3506 edits,
3507 language_server.server_id(),
3508 op.text_document.version,
3509 cx,
3510 )
3511 })
3512 .await?;
3513
3514 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3515 buffer.finalize_last_transaction();
3516 buffer.start_transaction();
3517 for (range, text) in edits {
3518 buffer.edit([(range, text)], None, cx);
3519 }
3520
3521 buffer.end_transaction(cx).and_then(|transaction_id| {
3522 if push_to_history {
3523 buffer.finalize_last_transaction();
3524 buffer.get_transaction(transaction_id).cloned()
3525 } else {
3526 buffer.forget_transaction(transaction_id)
3527 }
3528 })
3529 });
3530 if let Some(transaction) = transaction {
3531 project_transaction.0.insert(buffer_to_edit, transaction);
3532 }
3533 }
3534 }
3535 }
3536
3537 Ok(project_transaction)
3538 }
3539
3540 async fn on_lsp_workspace_edit(
3541 this: WeakEntity<LspStore>,
3542 params: lsp::ApplyWorkspaceEditParams,
3543 server_id: LanguageServerId,
3544 cx: &mut AsyncApp,
3545 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3546 let this = this.upgrade().context("project project closed")?;
3547 let language_server = this
3548 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3549 .context("language server not found")?;
3550 let transaction = Self::deserialize_workspace_edit(
3551 this.clone(),
3552 params.edit,
3553 true,
3554 language_server.clone(),
3555 cx,
3556 )
3557 .await
3558 .log_err();
3559 this.update(cx, |this, cx| {
3560 if let Some(transaction) = transaction {
3561 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3562
3563 this.as_local_mut()
3564 .unwrap()
3565 .last_workspace_edits_by_language_server
3566 .insert(server_id, transaction);
3567 }
3568 });
3569 Ok(lsp::ApplyWorkspaceEditResponse {
3570 applied: true,
3571 failed_change: None,
3572 failure_reason: None,
3573 })
3574 }
3575
3576 fn remove_worktree(
3577 &mut self,
3578 id_to_remove: WorktreeId,
3579 cx: &mut Context<LspStore>,
3580 ) -> Vec<LanguageServerId> {
3581 self.restricted_worktrees_tasks.remove(&id_to_remove);
3582 self.diagnostics.remove(&id_to_remove);
3583 self.prettier_store.update(cx, |prettier_store, cx| {
3584 prettier_store.remove_worktree(id_to_remove, cx);
3585 });
3586
3587 let mut servers_to_remove = BTreeSet::default();
3588 let mut servers_to_preserve = HashSet::default();
3589 for (seed, state) in &self.language_server_ids {
3590 if seed.worktree_id == id_to_remove {
3591 servers_to_remove.insert(state.id);
3592 } else {
3593 servers_to_preserve.insert(state.id);
3594 }
3595 }
3596 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3597 self.language_server_ids
3598 .retain(|_, state| !servers_to_remove.contains(&state.id));
3599 for server_id_to_remove in &servers_to_remove {
3600 self.language_server_watched_paths
3601 .remove(server_id_to_remove);
3602 self.language_server_paths_watched_for_rename
3603 .remove(server_id_to_remove);
3604 self.last_workspace_edits_by_language_server
3605 .remove(server_id_to_remove);
3606 self.language_servers.remove(server_id_to_remove);
3607 self.buffer_pull_diagnostics_result_ids
3608 .remove(server_id_to_remove);
3609 self.workspace_pull_diagnostics_result_ids
3610 .remove(server_id_to_remove);
3611 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3612 buffer_servers.remove(server_id_to_remove);
3613 }
3614 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3615 }
3616 servers_to_remove.into_iter().collect()
3617 }
3618
3619 fn rebuild_watched_paths_inner<'a>(
3620 &'a self,
3621 language_server_id: LanguageServerId,
3622 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3623 cx: &mut Context<LspStore>,
3624 ) -> LanguageServerWatchedPathsBuilder {
3625 let worktrees = self
3626 .worktree_store
3627 .read(cx)
3628 .worktrees()
3629 .filter_map(|worktree| {
3630 self.language_servers_for_worktree(worktree.read(cx).id())
3631 .find(|server| server.server_id() == language_server_id)
3632 .map(|_| worktree)
3633 })
3634 .collect::<Vec<_>>();
3635
3636 let mut worktree_globs = HashMap::default();
3637 let mut abs_globs = HashMap::default();
3638 log::trace!(
3639 "Processing new watcher paths for language server with id {}",
3640 language_server_id
3641 );
3642
3643 for watcher in watchers {
3644 if let Some((worktree, literal_prefix, pattern)) =
3645 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3646 {
3647 worktree.update(cx, |worktree, _| {
3648 if let Some((tree, glob)) =
3649 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3650 {
3651 tree.add_path_prefix_to_scan(literal_prefix);
3652 worktree_globs
3653 .entry(tree.id())
3654 .or_insert_with(GlobSetBuilder::new)
3655 .add(glob);
3656 }
3657 });
3658 } else {
3659 let (path, pattern) = match &watcher.glob_pattern {
3660 lsp::GlobPattern::String(s) => {
3661 let watcher_path = SanitizedPath::new(s);
3662 let path = glob_literal_prefix(watcher_path.as_path());
3663 let pattern = watcher_path
3664 .as_path()
3665 .strip_prefix(&path)
3666 .map(|p| p.to_string_lossy().into_owned())
3667 .unwrap_or_else(|e| {
3668 debug_panic!(
3669 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3670 s,
3671 path.display(),
3672 e
3673 );
3674 watcher_path.as_path().to_string_lossy().into_owned()
3675 });
3676 (path, pattern)
3677 }
3678 lsp::GlobPattern::Relative(rp) => {
3679 let Ok(mut base_uri) = match &rp.base_uri {
3680 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3681 lsp::OneOf::Right(base_uri) => base_uri,
3682 }
3683 .to_file_path() else {
3684 continue;
3685 };
3686
3687 let path = glob_literal_prefix(Path::new(&rp.pattern));
3688 let pattern = Path::new(&rp.pattern)
3689 .strip_prefix(&path)
3690 .map(|p| p.to_string_lossy().into_owned())
3691 .unwrap_or_else(|e| {
3692 debug_panic!(
3693 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3694 rp.pattern,
3695 path.display(),
3696 e
3697 );
3698 rp.pattern.clone()
3699 });
3700 base_uri.push(path);
3701 (base_uri, pattern)
3702 }
3703 };
3704
3705 if let Some(glob) = Glob::new(&pattern).log_err() {
3706 if !path
3707 .components()
3708 .any(|c| matches!(c, path::Component::Normal(_)))
3709 {
3710 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3711 // rather than adding a new watcher for `/`.
3712 for worktree in &worktrees {
3713 worktree_globs
3714 .entry(worktree.read(cx).id())
3715 .or_insert_with(GlobSetBuilder::new)
3716 .add(glob.clone());
3717 }
3718 } else {
3719 abs_globs
3720 .entry(path.into())
3721 .or_insert_with(GlobSetBuilder::new)
3722 .add(glob);
3723 }
3724 }
3725 }
3726 }
3727
3728 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3729 for (worktree_id, builder) in worktree_globs {
3730 if let Ok(globset) = builder.build() {
3731 watch_builder.watch_worktree(worktree_id, globset);
3732 }
3733 }
3734 for (abs_path, builder) in abs_globs {
3735 if let Ok(globset) = builder.build() {
3736 watch_builder.watch_abs_path(abs_path, globset);
3737 }
3738 }
3739 watch_builder
3740 }
3741
3742 fn worktree_and_path_for_file_watcher(
3743 worktrees: &[Entity<Worktree>],
3744 watcher: &FileSystemWatcher,
3745 cx: &App,
3746 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3747 worktrees.iter().find_map(|worktree| {
3748 let tree = worktree.read(cx);
3749 let worktree_root_path = tree.abs_path();
3750 let path_style = tree.path_style();
3751 match &watcher.glob_pattern {
3752 lsp::GlobPattern::String(s) => {
3753 let watcher_path = SanitizedPath::new(s);
3754 let relative = watcher_path
3755 .as_path()
3756 .strip_prefix(&worktree_root_path)
3757 .ok()?;
3758 let literal_prefix = glob_literal_prefix(relative);
3759 Some((
3760 worktree.clone(),
3761 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3762 relative.to_string_lossy().into_owned(),
3763 ))
3764 }
3765 lsp::GlobPattern::Relative(rp) => {
3766 let base_uri = match &rp.base_uri {
3767 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3768 lsp::OneOf::Right(base_uri) => base_uri,
3769 }
3770 .to_file_path()
3771 .ok()?;
3772 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3773 let mut literal_prefix = relative.to_owned();
3774 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3775 Some((
3776 worktree.clone(),
3777 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3778 rp.pattern.clone(),
3779 ))
3780 }
3781 }
3782 })
3783 }
3784
3785 fn rebuild_watched_paths(
3786 &mut self,
3787 language_server_id: LanguageServerId,
3788 cx: &mut Context<LspStore>,
3789 ) {
3790 let Some(registrations) = self
3791 .language_server_dynamic_registrations
3792 .get(&language_server_id)
3793 else {
3794 return;
3795 };
3796
3797 let watch_builder = self.rebuild_watched_paths_inner(
3798 language_server_id,
3799 registrations.did_change_watched_files.values().flatten(),
3800 cx,
3801 );
3802 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3803 self.language_server_watched_paths
3804 .insert(language_server_id, watcher);
3805
3806 cx.notify();
3807 }
3808
3809 fn on_lsp_did_change_watched_files(
3810 &mut self,
3811 language_server_id: LanguageServerId,
3812 registration_id: &str,
3813 params: DidChangeWatchedFilesRegistrationOptions,
3814 cx: &mut Context<LspStore>,
3815 ) {
3816 let registrations = self
3817 .language_server_dynamic_registrations
3818 .entry(language_server_id)
3819 .or_default();
3820
3821 registrations
3822 .did_change_watched_files
3823 .insert(registration_id.to_string(), params.watchers);
3824
3825 self.rebuild_watched_paths(language_server_id, cx);
3826 }
3827
3828 fn on_lsp_unregister_did_change_watched_files(
3829 &mut self,
3830 language_server_id: LanguageServerId,
3831 registration_id: &str,
3832 cx: &mut Context<LspStore>,
3833 ) {
3834 let registrations = self
3835 .language_server_dynamic_registrations
3836 .entry(language_server_id)
3837 .or_default();
3838
3839 if registrations
3840 .did_change_watched_files
3841 .remove(registration_id)
3842 .is_some()
3843 {
3844 log::info!(
3845 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3846 language_server_id,
3847 registration_id
3848 );
3849 } else {
3850 log::warn!(
3851 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3852 language_server_id,
3853 registration_id
3854 );
3855 }
3856
3857 self.rebuild_watched_paths(language_server_id, cx);
3858 }
3859
3860 async fn initialization_options_for_adapter(
3861 adapter: Arc<dyn LspAdapter>,
3862 delegate: &Arc<dyn LspAdapterDelegate>,
3863 cx: &mut AsyncApp,
3864 ) -> Result<Option<serde_json::Value>> {
3865 let Some(mut initialization_config) =
3866 adapter.clone().initialization_options(delegate, cx).await?
3867 else {
3868 return Ok(None);
3869 };
3870
3871 for other_adapter in delegate.registered_lsp_adapters() {
3872 if other_adapter.name() == adapter.name() {
3873 continue;
3874 }
3875 if let Ok(Some(target_config)) = other_adapter
3876 .clone()
3877 .additional_initialization_options(adapter.name(), delegate)
3878 .await
3879 {
3880 merge_json_value_into(target_config.clone(), &mut initialization_config);
3881 }
3882 }
3883
3884 Ok(Some(initialization_config))
3885 }
3886
3887 async fn workspace_configuration_for_adapter(
3888 adapter: Arc<dyn LspAdapter>,
3889 delegate: &Arc<dyn LspAdapterDelegate>,
3890 toolchain: Option<Toolchain>,
3891 requested_uri: Option<Uri>,
3892 cx: &mut AsyncApp,
3893 ) -> Result<serde_json::Value> {
3894 let mut workspace_config = adapter
3895 .clone()
3896 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3897 .await?;
3898
3899 for other_adapter in delegate.registered_lsp_adapters() {
3900 if other_adapter.name() == adapter.name() {
3901 continue;
3902 }
3903 if let Ok(Some(target_config)) = other_adapter
3904 .clone()
3905 .additional_workspace_configuration(adapter.name(), delegate, cx)
3906 .await
3907 {
3908 merge_json_value_into(target_config.clone(), &mut workspace_config);
3909 }
3910 }
3911
3912 Ok(workspace_config)
3913 }
3914
3915 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3916 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3917 Some(server.clone())
3918 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3919 Some(Arc::clone(server))
3920 } else {
3921 None
3922 }
3923 }
3924}
3925
3926fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3927 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3928 cx.emit(LspStoreEvent::LanguageServerUpdate {
3929 language_server_id: server.server_id(),
3930 name: Some(server.name()),
3931 message: proto::update_language_server::Variant::MetadataUpdated(
3932 proto::ServerMetadataUpdated {
3933 capabilities: Some(capabilities),
3934 binary: Some(proto::LanguageServerBinaryInfo {
3935 path: server.binary().path.to_string_lossy().into_owned(),
3936 arguments: server
3937 .binary()
3938 .arguments
3939 .iter()
3940 .map(|arg| arg.to_string_lossy().into_owned())
3941 .collect(),
3942 }),
3943 configuration: serde_json::to_string(server.configuration()).ok(),
3944 workspace_folders: server
3945 .workspace_folders()
3946 .iter()
3947 .map(|uri| uri.to_string())
3948 .collect(),
3949 },
3950 ),
3951 });
3952 }
3953}
3954
3955#[derive(Debug)]
3956pub struct FormattableBuffer {
3957 handle: Entity<Buffer>,
3958 abs_path: Option<PathBuf>,
3959 env: Option<HashMap<String, String>>,
3960 ranges: Option<Vec<Range<Anchor>>>,
3961}
3962
3963pub struct RemoteLspStore {
3964 upstream_client: Option<AnyProtoClient>,
3965 upstream_project_id: u64,
3966}
3967
3968pub(crate) enum LspStoreMode {
3969 Local(LocalLspStore), // ssh host and collab host
3970 Remote(RemoteLspStore), // collab guest
3971}
3972
3973impl LspStoreMode {
3974 fn is_local(&self) -> bool {
3975 matches!(self, LspStoreMode::Local(_))
3976 }
3977}
3978
3979pub struct LspStore {
3980 mode: LspStoreMode,
3981 last_formatting_failure: Option<String>,
3982 downstream_client: Option<(AnyProtoClient, u64)>,
3983 nonce: u128,
3984 buffer_store: Entity<BufferStore>,
3985 worktree_store: Entity<WorktreeStore>,
3986 pub languages: Arc<LanguageRegistry>,
3987 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3988 active_entry: Option<ProjectEntryId>,
3989 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3990 _maintain_buffer_languages: Task<()>,
3991 diagnostic_summaries:
3992 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3993 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3994 semantic_token_config: SemanticTokenConfig,
3995 lsp_data: HashMap<BufferId, BufferLspData>,
3996 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3997 next_hint_id: Arc<AtomicUsize>,
3998}
3999
4000#[derive(Debug)]
4001pub struct BufferLspData {
4002 buffer_version: Global,
4003 document_colors: Option<DocumentColorData>,
4004 code_lens: Option<CodeLensData>,
4005 semantic_tokens: Option<SemanticTokensData>,
4006 folding_ranges: Option<FoldingRangeData>,
4007 document_symbols: Option<DocumentSymbolsData>,
4008 inlay_hints: BufferInlayHints,
4009 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
4010 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
4011}
4012
4013#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4014struct LspKey {
4015 request_type: TypeId,
4016 server_queried: Option<LanguageServerId>,
4017}
4018
4019impl BufferLspData {
4020 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
4021 Self {
4022 buffer_version: buffer.read(cx).version(),
4023 document_colors: None,
4024 code_lens: None,
4025 semantic_tokens: None,
4026 folding_ranges: None,
4027 document_symbols: None,
4028 inlay_hints: BufferInlayHints::new(buffer, cx),
4029 lsp_requests: HashMap::default(),
4030 chunk_lsp_requests: HashMap::default(),
4031 }
4032 }
4033
4034 fn remove_server_data(&mut self, for_server: LanguageServerId) {
4035 if let Some(document_colors) = &mut self.document_colors {
4036 document_colors.remove_server_data(for_server);
4037 }
4038
4039 if let Some(code_lens) = &mut self.code_lens {
4040 code_lens.remove_server_data(for_server);
4041 }
4042
4043 self.inlay_hints.remove_server_data(for_server);
4044
4045 if let Some(semantic_tokens) = &mut self.semantic_tokens {
4046 semantic_tokens.remove_server_data(for_server);
4047 }
4048
4049 if let Some(folding_ranges) = &mut self.folding_ranges {
4050 folding_ranges.ranges.remove(&for_server);
4051 }
4052
4053 if let Some(document_symbols) = &mut self.document_symbols {
4054 document_symbols.remove_server_data(for_server);
4055 }
4056 }
4057
4058 #[cfg(any(test, feature = "test-support"))]
4059 pub fn inlay_hints(&self) -> &BufferInlayHints {
4060 &self.inlay_hints
4061 }
4062}
4063
4064#[derive(Debug)]
4065pub enum LspStoreEvent {
4066 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4067 LanguageServerRemoved(LanguageServerId),
4068 LanguageServerUpdate {
4069 language_server_id: LanguageServerId,
4070 name: Option<LanguageServerName>,
4071 message: proto::update_language_server::Variant,
4072 },
4073 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4074 LanguageServerPrompt(LanguageServerPromptRequest),
4075 LanguageDetected {
4076 buffer: Entity<Buffer>,
4077 new_language: Option<Arc<Language>>,
4078 },
4079 Notification(String),
4080 RefreshInlayHints {
4081 server_id: LanguageServerId,
4082 request_id: Option<usize>,
4083 },
4084 RefreshSemanticTokens {
4085 server_id: LanguageServerId,
4086 request_id: Option<usize>,
4087 },
4088 RefreshCodeLens,
4089 DiagnosticsUpdated {
4090 server_id: LanguageServerId,
4091 paths: Vec<ProjectPath>,
4092 },
4093 DiskBasedDiagnosticsStarted {
4094 language_server_id: LanguageServerId,
4095 },
4096 DiskBasedDiagnosticsFinished {
4097 language_server_id: LanguageServerId,
4098 },
4099 SnippetEdit {
4100 buffer_id: BufferId,
4101 edits: Vec<(lsp::Range, Snippet)>,
4102 most_recent_edit: clock::Lamport,
4103 },
4104 WorkspaceEditApplied(ProjectTransaction),
4105}
4106
4107#[derive(Clone, Debug, Serialize)]
4108pub struct LanguageServerStatus {
4109 pub name: LanguageServerName,
4110 pub server_version: Option<SharedString>,
4111 pub server_readable_version: Option<SharedString>,
4112 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4113 pub has_pending_diagnostic_updates: bool,
4114 pub progress_tokens: HashSet<ProgressToken>,
4115 pub worktree: Option<WorktreeId>,
4116 pub binary: Option<LanguageServerBinary>,
4117 pub configuration: Option<Value>,
4118 pub workspace_folders: BTreeSet<Uri>,
4119 pub process_id: Option<u32>,
4120}
4121
4122#[derive(Clone, Debug)]
4123struct CoreSymbol {
4124 pub language_server_name: LanguageServerName,
4125 pub source_worktree_id: WorktreeId,
4126 pub source_language_server_id: LanguageServerId,
4127 pub path: SymbolLocation,
4128 pub name: String,
4129 pub kind: lsp::SymbolKind,
4130 pub range: Range<Unclipped<PointUtf16>>,
4131 pub container_name: Option<String>,
4132}
4133
4134#[derive(Clone, Debug, PartialEq, Eq)]
4135pub enum SymbolLocation {
4136 InProject(ProjectPath),
4137 OutsideProject {
4138 abs_path: Arc<Path>,
4139 signature: [u8; 32],
4140 },
4141}
4142
4143impl SymbolLocation {
4144 fn file_name(&self) -> Option<&str> {
4145 match self {
4146 Self::InProject(path) => path.path.file_name(),
4147 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4148 }
4149 }
4150}
4151
4152impl LspStore {
4153 pub fn init(client: &AnyProtoClient) {
4154 client.add_entity_request_handler(Self::handle_lsp_query);
4155 client.add_entity_message_handler(Self::handle_lsp_query_response);
4156 client.add_entity_request_handler(Self::handle_restart_language_servers);
4157 client.add_entity_request_handler(Self::handle_stop_language_servers);
4158 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4159 client.add_entity_message_handler(Self::handle_start_language_server);
4160 client.add_entity_message_handler(Self::handle_update_language_server);
4161 client.add_entity_message_handler(Self::handle_language_server_log);
4162 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4163 client.add_entity_request_handler(Self::handle_format_buffers);
4164 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4165 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4166 client.add_entity_request_handler(Self::handle_apply_code_action);
4167 client.add_entity_request_handler(Self::handle_get_project_symbols);
4168 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4169 client.add_entity_request_handler(Self::handle_get_color_presentation);
4170 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4171 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4172 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4173 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4174 client.add_entity_request_handler(Self::handle_on_type_formatting);
4175 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4176 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4177 client.add_entity_request_handler(Self::handle_rename_project_entry);
4178 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4179 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4180 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4181 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4182 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4183 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4184 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4185
4186 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4187 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4188 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4189 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4190 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4191 client.add_entity_request_handler(
4192 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4193 );
4194 client.add_entity_request_handler(
4195 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4196 );
4197 client.add_entity_request_handler(
4198 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4199 );
4200 }
4201
4202 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4203 match &self.mode {
4204 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4205 _ => None,
4206 }
4207 }
4208
4209 pub fn as_local(&self) -> Option<&LocalLspStore> {
4210 match &self.mode {
4211 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4212 _ => None,
4213 }
4214 }
4215
4216 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4217 match &mut self.mode {
4218 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4219 _ => None,
4220 }
4221 }
4222
4223 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4224 match &self.mode {
4225 LspStoreMode::Remote(RemoteLspStore {
4226 upstream_client: Some(upstream_client),
4227 upstream_project_id,
4228 ..
4229 }) => Some((upstream_client.clone(), *upstream_project_id)),
4230
4231 LspStoreMode::Remote(RemoteLspStore {
4232 upstream_client: None,
4233 ..
4234 }) => None,
4235 LspStoreMode::Local(_) => None,
4236 }
4237 }
4238
4239 pub fn new_local(
4240 buffer_store: Entity<BufferStore>,
4241 worktree_store: Entity<WorktreeStore>,
4242 prettier_store: Entity<PrettierStore>,
4243 toolchain_store: Entity<LocalToolchainStore>,
4244 environment: Entity<ProjectEnvironment>,
4245 manifest_tree: Entity<ManifestTree>,
4246 languages: Arc<LanguageRegistry>,
4247 http_client: Arc<dyn HttpClient>,
4248 fs: Arc<dyn Fs>,
4249 cx: &mut Context<Self>,
4250 ) -> Self {
4251 let yarn = YarnPathStore::new(fs.clone(), cx);
4252 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4253 .detach();
4254 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4255 .detach();
4256 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4257 .detach();
4258 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4259 .detach();
4260 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4261 .detach();
4262 subscribe_to_binary_statuses(&languages, cx).detach();
4263
4264 let _maintain_workspace_config = {
4265 let (sender, receiver) = watch::channel();
4266 (Self::maintain_workspace_config(receiver, cx), sender)
4267 };
4268
4269 Self {
4270 mode: LspStoreMode::Local(LocalLspStore {
4271 weak: cx.weak_entity(),
4272 worktree_store: worktree_store.clone(),
4273
4274 supplementary_language_servers: Default::default(),
4275 languages: languages.clone(),
4276 language_server_ids: Default::default(),
4277 language_servers: Default::default(),
4278 last_workspace_edits_by_language_server: Default::default(),
4279 language_server_watched_paths: Default::default(),
4280 language_server_paths_watched_for_rename: Default::default(),
4281 language_server_dynamic_registrations: Default::default(),
4282 buffers_being_formatted: Default::default(),
4283 buffers_to_refresh_hash_set: HashSet::default(),
4284 buffers_to_refresh_queue: VecDeque::new(),
4285 _background_diagnostics_worker: Task::ready(()).shared(),
4286 buffer_snapshots: Default::default(),
4287 prettier_store,
4288 environment,
4289 http_client,
4290 fs,
4291 yarn,
4292 next_diagnostic_group_id: Default::default(),
4293 diagnostics: Default::default(),
4294 _subscription: cx.on_app_quit(|this, _| {
4295 this.as_local_mut()
4296 .unwrap()
4297 .shutdown_language_servers_on_quit()
4298 }),
4299 lsp_tree: LanguageServerTree::new(
4300 manifest_tree,
4301 languages.clone(),
4302 toolchain_store.clone(),
4303 ),
4304 toolchain_store,
4305 registered_buffers: HashMap::default(),
4306 buffers_opened_in_servers: HashMap::default(),
4307 buffer_pull_diagnostics_result_ids: HashMap::default(),
4308 workspace_pull_diagnostics_result_ids: HashMap::default(),
4309 restricted_worktrees_tasks: HashMap::default(),
4310 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4311 .manifest_file_names(),
4312 }),
4313 last_formatting_failure: None,
4314 downstream_client: None,
4315 buffer_store,
4316 worktree_store,
4317 languages: languages.clone(),
4318 language_server_statuses: Default::default(),
4319 nonce: StdRng::from_os_rng().random(),
4320 diagnostic_summaries: HashMap::default(),
4321 lsp_server_capabilities: HashMap::default(),
4322 semantic_token_config: SemanticTokenConfig::new(cx),
4323 lsp_data: HashMap::default(),
4324 buffer_reload_tasks: HashMap::default(),
4325 next_hint_id: Arc::default(),
4326 active_entry: None,
4327 _maintain_workspace_config,
4328 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4329 }
4330 }
4331
4332 fn send_lsp_proto_request<R: LspCommand>(
4333 &self,
4334 buffer: Entity<Buffer>,
4335 client: AnyProtoClient,
4336 upstream_project_id: u64,
4337 request: R,
4338 cx: &mut Context<LspStore>,
4339 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4340 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4341 return Task::ready(Ok(R::Response::default()));
4342 }
4343 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4344 cx.spawn(async move |this, cx| {
4345 let response = client.request(message).await?;
4346 let this = this.upgrade().context("project dropped")?;
4347 request
4348 .response_from_proto(response, this, buffer, cx.clone())
4349 .await
4350 })
4351 }
4352
4353 pub(super) fn new_remote(
4354 buffer_store: Entity<BufferStore>,
4355 worktree_store: Entity<WorktreeStore>,
4356 languages: Arc<LanguageRegistry>,
4357 upstream_client: AnyProtoClient,
4358 project_id: u64,
4359 cx: &mut Context<Self>,
4360 ) -> Self {
4361 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4362 .detach();
4363 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4364 .detach();
4365 subscribe_to_binary_statuses(&languages, cx).detach();
4366 let _maintain_workspace_config = {
4367 let (sender, receiver) = watch::channel();
4368 (Self::maintain_workspace_config(receiver, cx), sender)
4369 };
4370 Self {
4371 mode: LspStoreMode::Remote(RemoteLspStore {
4372 upstream_client: Some(upstream_client),
4373 upstream_project_id: project_id,
4374 }),
4375 downstream_client: None,
4376 last_formatting_failure: None,
4377 buffer_store,
4378 worktree_store,
4379 languages: languages.clone(),
4380 language_server_statuses: Default::default(),
4381 nonce: StdRng::from_os_rng().random(),
4382 diagnostic_summaries: HashMap::default(),
4383 lsp_server_capabilities: HashMap::default(),
4384 semantic_token_config: SemanticTokenConfig::new(cx),
4385 next_hint_id: Arc::default(),
4386 lsp_data: HashMap::default(),
4387 buffer_reload_tasks: HashMap::default(),
4388 active_entry: None,
4389
4390 _maintain_workspace_config,
4391 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4392 }
4393 }
4394
4395 fn on_buffer_store_event(
4396 &mut self,
4397 _: Entity<BufferStore>,
4398 event: &BufferStoreEvent,
4399 cx: &mut Context<Self>,
4400 ) {
4401 match event {
4402 BufferStoreEvent::BufferAdded(buffer) => {
4403 self.on_buffer_added(buffer, cx).log_err();
4404 }
4405 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4406 let buffer_id = buffer.read(cx).remote_id();
4407 if let Some(local) = self.as_local_mut()
4408 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4409 {
4410 local.reset_buffer(buffer, old_file, cx);
4411
4412 if local.registered_buffers.contains_key(&buffer_id) {
4413 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4414 }
4415 }
4416
4417 self.detect_language_for_buffer(buffer, cx);
4418 if let Some(local) = self.as_local_mut() {
4419 local.initialize_buffer(buffer, cx);
4420 if local.registered_buffers.contains_key(&buffer_id) {
4421 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4422 }
4423 }
4424 }
4425 _ => {}
4426 }
4427 }
4428
4429 fn on_worktree_store_event(
4430 &mut self,
4431 _: Entity<WorktreeStore>,
4432 event: &WorktreeStoreEvent,
4433 cx: &mut Context<Self>,
4434 ) {
4435 match event {
4436 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4437 if !worktree.read(cx).is_local() {
4438 return;
4439 }
4440 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4441 worktree::Event::UpdatedEntries(changes) => {
4442 this.update_local_worktree_language_servers(&worktree, changes, cx);
4443 }
4444 worktree::Event::UpdatedGitRepositories(_)
4445 | worktree::Event::DeletedEntry(_)
4446 | worktree::Event::Deleted
4447 | worktree::Event::UpdatedRootRepoCommonDir { .. } => {}
4448 })
4449 .detach()
4450 }
4451 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4452 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4453 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4454 }
4455 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4456 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4457 }
4458 WorktreeStoreEvent::WorktreeReleased(..)
4459 | WorktreeStoreEvent::WorktreeOrderChanged
4460 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4461 | WorktreeStoreEvent::WorktreeDeletedEntry(..)
4462 | WorktreeStoreEvent::WorktreeUpdatedRootRepoCommonDir(..) => {}
4463 }
4464 }
4465
4466 fn on_prettier_store_event(
4467 &mut self,
4468 _: Entity<PrettierStore>,
4469 event: &PrettierStoreEvent,
4470 cx: &mut Context<Self>,
4471 ) {
4472 match event {
4473 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4474 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4475 }
4476 PrettierStoreEvent::LanguageServerAdded {
4477 new_server_id,
4478 name,
4479 prettier_server,
4480 } => {
4481 self.register_supplementary_language_server(
4482 *new_server_id,
4483 name.clone(),
4484 prettier_server.clone(),
4485 cx,
4486 );
4487 }
4488 }
4489 }
4490
4491 fn on_toolchain_store_event(
4492 &mut self,
4493 _: Entity<LocalToolchainStore>,
4494 event: &ToolchainStoreEvent,
4495 _: &mut Context<Self>,
4496 ) {
4497 if let ToolchainStoreEvent::ToolchainActivated = event {
4498 self.request_workspace_config_refresh()
4499 }
4500 }
4501
4502 fn request_workspace_config_refresh(&mut self) {
4503 *self._maintain_workspace_config.1.borrow_mut() = ();
4504 }
4505
4506 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4507 self.as_local().map(|local| local.prettier_store.clone())
4508 }
4509
4510 fn on_buffer_event(
4511 &mut self,
4512 buffer: Entity<Buffer>,
4513 event: &language::BufferEvent,
4514 cx: &mut Context<Self>,
4515 ) {
4516 match event {
4517 language::BufferEvent::Edited { .. } => {
4518 self.on_buffer_edited(buffer, cx);
4519 }
4520
4521 language::BufferEvent::Saved => {
4522 self.on_buffer_saved(buffer, cx);
4523 }
4524
4525 language::BufferEvent::Reloaded => {
4526 self.on_buffer_reloaded(buffer, cx);
4527 }
4528
4529 _ => {}
4530 }
4531 }
4532
4533 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4534 buffer
4535 .read(cx)
4536 .set_language_registry(self.languages.clone());
4537
4538 cx.subscribe(buffer, |this, buffer, event, cx| {
4539 this.on_buffer_event(buffer, event, cx);
4540 })
4541 .detach();
4542
4543 self.parse_modeline(buffer, cx);
4544 self.detect_language_for_buffer(buffer, cx);
4545 if let Some(local) = self.as_local_mut() {
4546 local.initialize_buffer(buffer, cx);
4547 }
4548
4549 Ok(())
4550 }
4551
4552 pub fn refresh_background_diagnostics_for_buffers(
4553 &mut self,
4554 buffers: HashSet<BufferId>,
4555 cx: &mut Context<Self>,
4556 ) -> Shared<Task<()>> {
4557 let Some(local) = self.as_local_mut() else {
4558 return Task::ready(()).shared();
4559 };
4560 for buffer in buffers {
4561 if local.buffers_to_refresh_hash_set.insert(buffer) {
4562 local.buffers_to_refresh_queue.push_back(buffer);
4563 if local.buffers_to_refresh_queue.len() == 1 {
4564 local._background_diagnostics_worker =
4565 Self::background_diagnostics_worker(cx).shared();
4566 }
4567 }
4568 }
4569
4570 local._background_diagnostics_worker.clone()
4571 }
4572
4573 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4574 let buffer_store = self.buffer_store.clone();
4575 let local = self.as_local_mut()?;
4576 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4577 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4578 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4579 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4580 }
4581 }
4582 None
4583 }
4584
4585 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4586 cx.spawn(async move |this, cx| {
4587 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4588 task.await.log_err();
4589 }
4590 })
4591 }
4592
4593 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4594 if self.parse_modeline(&buffer, cx) {
4595 self.detect_language_for_buffer(&buffer, cx);
4596 }
4597
4598 let buffer_id = buffer.read(cx).remote_id();
4599 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4600 self.buffer_reload_tasks.insert(buffer_id, task);
4601 }
4602
4603 pub(crate) fn register_buffer_with_language_servers(
4604 &mut self,
4605 buffer: &Entity<Buffer>,
4606 only_register_servers: HashSet<LanguageServerSelector>,
4607 ignore_refcounts: bool,
4608 cx: &mut Context<Self>,
4609 ) -> OpenLspBufferHandle {
4610 let buffer_id = buffer.read(cx).remote_id();
4611 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4612 if let Some(local) = self.as_local_mut() {
4613 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4614 if !ignore_refcounts {
4615 *refcount += 1;
4616 }
4617
4618 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4619 // 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
4620 // 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
4621 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4622 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4623 return handle;
4624 };
4625 if !file.is_local() {
4626 return handle;
4627 }
4628
4629 if ignore_refcounts || *refcount == 1 {
4630 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4631 }
4632 if !ignore_refcounts {
4633 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4634 let refcount = {
4635 let local = lsp_store.as_local_mut().unwrap();
4636 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4637 debug_panic!("bad refcounting");
4638 return;
4639 };
4640
4641 *refcount -= 1;
4642 *refcount
4643 };
4644 if refcount == 0 {
4645 lsp_store.lsp_data.remove(&buffer_id);
4646 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4647 let local = lsp_store.as_local_mut().unwrap();
4648 local.registered_buffers.remove(&buffer_id);
4649
4650 local.buffers_opened_in_servers.remove(&buffer_id);
4651 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4652 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4653
4654 let buffer_abs_path = file.abs_path(cx);
4655 for (_, buffer_pull_diagnostics_result_ids) in
4656 &mut local.buffer_pull_diagnostics_result_ids
4657 {
4658 buffer_pull_diagnostics_result_ids.retain(
4659 |_, buffer_result_ids| {
4660 buffer_result_ids.remove(&buffer_abs_path);
4661 !buffer_result_ids.is_empty()
4662 },
4663 );
4664 }
4665
4666 let diagnostic_updates = local
4667 .language_servers
4668 .keys()
4669 .cloned()
4670 .map(|server_id| DocumentDiagnosticsUpdate {
4671 diagnostics: DocumentDiagnostics {
4672 document_abs_path: buffer_abs_path.clone(),
4673 version: None,
4674 diagnostics: Vec::new(),
4675 },
4676 result_id: None,
4677 registration_id: None,
4678 server_id,
4679 disk_based_sources: Cow::Borrowed(&[]),
4680 })
4681 .collect::<Vec<_>>();
4682
4683 lsp_store
4684 .merge_diagnostic_entries(
4685 diagnostic_updates,
4686 |_, diagnostic, _| {
4687 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4688 },
4689 cx,
4690 )
4691 .context("Clearing diagnostics for the closed buffer")
4692 .log_err();
4693 }
4694 }
4695 })
4696 .detach();
4697 }
4698 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4699 let buffer_id = buffer.read(cx).remote_id().to_proto();
4700 cx.background_spawn(async move {
4701 upstream_client
4702 .request(proto::RegisterBufferWithLanguageServers {
4703 project_id: upstream_project_id,
4704 buffer_id,
4705 only_servers: only_register_servers
4706 .into_iter()
4707 .map(|selector| {
4708 let selector = match selector {
4709 LanguageServerSelector::Id(language_server_id) => {
4710 proto::language_server_selector::Selector::ServerId(
4711 language_server_id.to_proto(),
4712 )
4713 }
4714 LanguageServerSelector::Name(language_server_name) => {
4715 proto::language_server_selector::Selector::Name(
4716 language_server_name.to_string(),
4717 )
4718 }
4719 };
4720 proto::LanguageServerSelector {
4721 selector: Some(selector),
4722 }
4723 })
4724 .collect(),
4725 })
4726 .await
4727 })
4728 .detach();
4729 } else {
4730 // Our remote connection got closed
4731 }
4732 handle
4733 }
4734
4735 fn maintain_buffer_languages(
4736 languages: Arc<LanguageRegistry>,
4737 cx: &mut Context<Self>,
4738 ) -> Task<()> {
4739 let mut subscription = languages.subscribe();
4740 let mut prev_reload_count = languages.reload_count();
4741 cx.spawn(async move |this, cx| {
4742 while let Some(()) = subscription.next().await {
4743 if let Some(this) = this.upgrade() {
4744 // If the language registry has been reloaded, then remove and
4745 // re-assign the languages on all open buffers.
4746 let reload_count = languages.reload_count();
4747 if reload_count > prev_reload_count {
4748 prev_reload_count = reload_count;
4749 this.update(cx, |this, cx| {
4750 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4751 for buffer in buffer_store.buffers() {
4752 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4753 {
4754 buffer.update(cx, |buffer, cx| {
4755 buffer.set_language_async(None, cx)
4756 });
4757 if let Some(local) = this.as_local_mut() {
4758 local.reset_buffer(&buffer, &f, cx);
4759
4760 if local
4761 .registered_buffers
4762 .contains_key(&buffer.read(cx).remote_id())
4763 && let Some(file_url) =
4764 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4765 {
4766 local.unregister_buffer_from_language_servers(
4767 &buffer, &file_url, cx,
4768 );
4769 }
4770 }
4771 }
4772 }
4773 });
4774 });
4775 }
4776
4777 this.update(cx, |this, cx| {
4778 let mut plain_text_buffers = Vec::new();
4779 let mut buffers_with_language = Vec::new();
4780 let mut buffers_with_unknown_injections = Vec::new();
4781 for handle in this.buffer_store.read(cx).buffers() {
4782 let buffer = handle.read(cx);
4783 if buffer.language().is_none()
4784 || buffer.language() == Some(&*language::PLAIN_TEXT)
4785 {
4786 plain_text_buffers.push(handle);
4787 } else {
4788 if buffer.contains_unknown_injections() {
4789 buffers_with_unknown_injections.push(handle.clone());
4790 }
4791 buffers_with_language.push(handle);
4792 }
4793 }
4794
4795 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4796 // and reused later in the invisible worktrees.
4797 plain_text_buffers.sort_by_key(|buffer| {
4798 Reverse(
4799 File::from_dyn(buffer.read(cx).file())
4800 .map(|file| file.worktree.read(cx).is_visible()),
4801 )
4802 });
4803
4804 for buffer in plain_text_buffers {
4805 this.detect_language_for_buffer(&buffer, cx);
4806 if let Some(local) = this.as_local_mut() {
4807 local.initialize_buffer(&buffer, cx);
4808 if local
4809 .registered_buffers
4810 .contains_key(&buffer.read(cx).remote_id())
4811 {
4812 local.register_buffer_with_language_servers(
4813 &buffer,
4814 HashSet::default(),
4815 cx,
4816 );
4817 }
4818 }
4819 }
4820
4821 // Also register buffers that already have a language with
4822 // any newly-available language servers (e.g., from extensions
4823 // that finished loading after buffers were restored).
4824 if let Some(local) = this.as_local_mut() {
4825 for buffer in buffers_with_language {
4826 if local
4827 .registered_buffers
4828 .contains_key(&buffer.read(cx).remote_id())
4829 {
4830 local.register_buffer_with_language_servers(
4831 &buffer,
4832 HashSet::default(),
4833 cx,
4834 );
4835 }
4836 }
4837 }
4838
4839 for buffer in buffers_with_unknown_injections {
4840 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4841 }
4842 });
4843 }
4844 }
4845 })
4846 }
4847
4848 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4849 let buffer = buffer_handle.read(cx);
4850 let content = buffer.as_rope();
4851
4852 let modeline_settings = {
4853 let settings_store = cx.global::<SettingsStore>();
4854 let modeline_lines = settings_store
4855 .raw_user_settings()
4856 .and_then(|s| s.content.modeline_lines)
4857 .or(settings_store.raw_default_settings().modeline_lines)
4858 .unwrap_or(5);
4859
4860 const MAX_MODELINE_BYTES: usize = 1024;
4861
4862 let first_bytes =
4863 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4864 let mut first_lines = Vec::new();
4865 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4866 for _ in 0..modeline_lines {
4867 if let Some(line) = lines.next() {
4868 first_lines.push(line.to_string());
4869 } else {
4870 break;
4871 }
4872 }
4873 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4874
4875 let last_start =
4876 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4877 let mut last_lines = Vec::new();
4878 let mut lines = content
4879 .reversed_chunks_in_range(last_start..content.len())
4880 .lines();
4881 for _ in 0..modeline_lines {
4882 if let Some(line) = lines.next() {
4883 last_lines.push(line.to_string());
4884 } else {
4885 break;
4886 }
4887 }
4888 let last_lines_ref: Vec<_> =
4889 last_lines.iter().rev().map(|line| line.as_str()).collect();
4890 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4891 };
4892
4893 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4894
4895 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4896 }
4897
4898 fn detect_language_for_buffer(
4899 &mut self,
4900 buffer_handle: &Entity<Buffer>,
4901 cx: &mut Context<Self>,
4902 ) -> Option<language::AvailableLanguage> {
4903 // If the buffer has a language, set it and start the language server if we haven't already.
4904 let buffer = buffer_handle.read(cx);
4905 let file = buffer.file()?;
4906 let content = buffer.as_rope();
4907 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4908
4909 let available_language = if let Some(ModelineSettings {
4910 mode: Some(mode_name),
4911 ..
4912 }) = modeline_settings
4913 {
4914 self.languages
4915 .available_language_for_modeline_name(mode_name)
4916 } else {
4917 self.languages.language_for_file(file, Some(content), cx)
4918 };
4919 if let Some(available_language) = &available_language {
4920 if let Some(Ok(Ok(new_language))) = self
4921 .languages
4922 .load_language(available_language)
4923 .now_or_never()
4924 {
4925 self.set_language_for_buffer(buffer_handle, new_language, cx);
4926 }
4927 } else {
4928 cx.emit(LspStoreEvent::LanguageDetected {
4929 buffer: buffer_handle.clone(),
4930 new_language: None,
4931 });
4932 }
4933
4934 available_language
4935 }
4936
4937 pub(crate) fn set_language_for_buffer(
4938 &mut self,
4939 buffer_entity: &Entity<Buffer>,
4940 new_language: Arc<Language>,
4941 cx: &mut Context<Self>,
4942 ) {
4943 let buffer = buffer_entity.read(cx);
4944 let buffer_file = buffer.file().cloned();
4945 let buffer_id = buffer.remote_id();
4946 if let Some(local_store) = self.as_local_mut()
4947 && local_store.registered_buffers.contains_key(&buffer_id)
4948 && let Some(abs_path) =
4949 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4950 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4951 {
4952 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4953 }
4954 buffer_entity.update(cx, |buffer, cx| {
4955 if buffer
4956 .language()
4957 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4958 {
4959 buffer.set_language_async(Some(new_language.clone()), cx);
4960 }
4961 });
4962
4963 let settings = LanguageSettings::resolve(
4964 Some(&buffer_entity.read(cx)),
4965 Some(&new_language.name()),
4966 cx,
4967 )
4968 .into_owned();
4969 let buffer_file = File::from_dyn(buffer_file.as_ref());
4970
4971 let worktree_id = if let Some(file) = buffer_file {
4972 let worktree = file.worktree.clone();
4973
4974 if let Some(local) = self.as_local_mut()
4975 && local.registered_buffers.contains_key(&buffer_id)
4976 {
4977 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4978 }
4979 Some(worktree.read(cx).id())
4980 } else {
4981 None
4982 };
4983
4984 if settings.prettier.allowed
4985 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4986 {
4987 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4988 if let Some(prettier_store) = prettier_store {
4989 prettier_store.update(cx, |prettier_store, cx| {
4990 prettier_store.install_default_prettier(
4991 worktree_id,
4992 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4993 cx,
4994 )
4995 })
4996 }
4997 }
4998
4999 cx.emit(LspStoreEvent::LanguageDetected {
5000 buffer: buffer_entity.clone(),
5001 new_language: Some(new_language),
5002 })
5003 }
5004
5005 pub fn buffer_store(&self) -> Entity<BufferStore> {
5006 self.buffer_store.clone()
5007 }
5008
5009 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
5010 self.active_entry = active_entry;
5011 }
5012
5013 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
5014 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
5015 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
5016 {
5017 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
5018 summaries
5019 .iter()
5020 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
5021 });
5022 if let Some(summary) = summaries.next() {
5023 client
5024 .send(proto::UpdateDiagnosticSummary {
5025 project_id: downstream_project_id,
5026 worktree_id: worktree.id().to_proto(),
5027 summary: Some(summary),
5028 more_summaries: summaries.collect(),
5029 })
5030 .log_err();
5031 }
5032 }
5033 }
5034
5035 fn is_capable_for_proto_request<R>(
5036 &self,
5037 buffer: &Entity<Buffer>,
5038 request: &R,
5039 cx: &App,
5040 ) -> bool
5041 where
5042 R: LspCommand,
5043 {
5044 self.check_if_capable_for_proto_request(
5045 buffer,
5046 |capabilities| {
5047 request.check_capabilities(AdapterServerCapabilities {
5048 server_capabilities: capabilities.clone(),
5049 code_action_kinds: None,
5050 })
5051 },
5052 cx,
5053 )
5054 }
5055
5056 fn relevant_server_ids_for_capability_check(
5057 &self,
5058 buffer: &Entity<Buffer>,
5059 cx: &App,
5060 ) -> Vec<LanguageServerId> {
5061 let buffer_id = buffer.read(cx).remote_id();
5062 if let Some(local) = self.as_local() {
5063 return local
5064 .buffers_opened_in_servers
5065 .get(&buffer_id)
5066 .into_iter()
5067 .flatten()
5068 .copied()
5069 .collect();
5070 }
5071
5072 let Some(language) = buffer.read(cx).language().cloned() else {
5073 return Vec::default();
5074 };
5075 let registered_language_servers = self
5076 .languages
5077 .lsp_adapters(&language.name())
5078 .into_iter()
5079 .map(|lsp_adapter| lsp_adapter.name())
5080 .collect::<HashSet<_>>();
5081 self.language_server_statuses
5082 .iter()
5083 .filter_map(|(server_id, server_status)| {
5084 // Include servers that are either registered for this language OR
5085 // available to be loaded (for SSH remote mode where adapters like
5086 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5087 // but only loaded on the server side)
5088 let is_relevant = registered_language_servers.contains(&server_status.name)
5089 || self.languages.is_lsp_adapter_available(&server_status.name);
5090 is_relevant.then_some(*server_id)
5091 })
5092 .collect()
5093 }
5094
5095 fn check_if_any_relevant_server_matches<F>(
5096 &self,
5097 buffer: &Entity<Buffer>,
5098 mut check: F,
5099 cx: &App,
5100 ) -> bool
5101 where
5102 F: FnMut(&LanguageServerStatus, &lsp::ServerCapabilities) -> bool,
5103 {
5104 self.relevant_server_ids_for_capability_check(buffer, cx)
5105 .into_iter()
5106 .filter_map(|server_id| {
5107 Some((
5108 self.language_server_statuses.get(&server_id)?,
5109 self.lsp_server_capabilities.get(&server_id)?,
5110 ))
5111 })
5112 .any(|(server_status, capabilities)| check(server_status, capabilities))
5113 }
5114
5115 fn check_if_capable_for_proto_request<F>(
5116 &self,
5117 buffer: &Entity<Buffer>,
5118 mut check: F,
5119 cx: &App,
5120 ) -> bool
5121 where
5122 F: FnMut(&lsp::ServerCapabilities) -> bool,
5123 {
5124 self.check_if_any_relevant_server_matches(buffer, |_, capabilities| check(capabilities), cx)
5125 }
5126
5127 pub fn supports_range_formatting(&self, buffer: &Entity<Buffer>, cx: &App) -> bool {
5128 let settings = LanguageSettings::for_buffer(buffer.read(cx), cx);
5129 settings.formatter.as_ref().iter().any(|formatter| {
5130 match formatter {
5131 Formatter::None => false,
5132 Formatter::Auto => {
5133 settings.prettier.allowed
5134 || self.check_if_capable_for_proto_request(
5135 buffer,
5136 server_capabilities_support_range_formatting,
5137 cx,
5138 )
5139 }
5140 Formatter::Prettier => true,
5141 Formatter::External { .. } => false,
5142 Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current) => {
5143 self.check_if_capable_for_proto_request(
5144 buffer,
5145 server_capabilities_support_range_formatting,
5146 cx,
5147 )
5148 }
5149 Formatter::LanguageServer(
5150 settings::LanguageServerFormatterSpecifier::Specific { name },
5151 ) => self.check_if_any_relevant_server_matches(
5152 buffer,
5153 |server_status, capabilities| {
5154 server_status.name.0.as_ref() == name
5155 && server_capabilities_support_range_formatting(capabilities)
5156 },
5157 cx,
5158 ),
5159 // `FormatSelections` should only surface when a formatter can honor the
5160 // selected ranges. Code actions can still run as part of formatting, but
5161 // they operate on the whole buffer rather than the selected text.
5162 Formatter::CodeAction(_) => false,
5163 }
5164 })
5165 }
5166
5167 fn all_capable_for_proto_request<F>(
5168 &self,
5169 buffer: &Entity<Buffer>,
5170 mut check: F,
5171 cx: &App,
5172 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
5173 where
5174 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
5175 {
5176 self.relevant_server_ids_for_capability_check(buffer, cx)
5177 .into_iter()
5178 .filter_map(|server_id| {
5179 Some((
5180 server_id,
5181 &self.language_server_statuses.get(&server_id)?.name,
5182 self.lsp_server_capabilities.get(&server_id)?,
5183 ))
5184 })
5185 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5186 .map(|(server_id, server_name, _)| (server_id, server_name.clone()))
5187 .collect()
5188 }
5189
5190 pub fn request_lsp<R>(
5191 &mut self,
5192 buffer: Entity<Buffer>,
5193 server: LanguageServerToQuery,
5194 request: R,
5195 cx: &mut Context<Self>,
5196 ) -> Task<Result<R::Response>>
5197 where
5198 R: LspCommand,
5199 <R::LspRequest as lsp::request::Request>::Result: Send,
5200 <R::LspRequest as lsp::request::Request>::Params: Send,
5201 {
5202 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5203 return self.send_lsp_proto_request(
5204 buffer,
5205 upstream_client,
5206 upstream_project_id,
5207 request,
5208 cx,
5209 );
5210 }
5211
5212 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5213 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5214 local
5215 .language_servers_for_buffer(buffer, cx)
5216 .find(|(_, server)| {
5217 request.check_capabilities(server.adapter_server_capabilities())
5218 })
5219 .map(|(_, server)| server.clone())
5220 }),
5221 LanguageServerToQuery::Other(id) => self
5222 .language_server_for_local_buffer(buffer, id, cx)
5223 .and_then(|(_, server)| {
5224 request
5225 .check_capabilities(server.adapter_server_capabilities())
5226 .then(|| Arc::clone(server))
5227 }),
5228 }) else {
5229 return Task::ready(Ok(Default::default()));
5230 };
5231
5232 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5233
5234 let Some(file) = file else {
5235 return Task::ready(Ok(Default::default()));
5236 };
5237
5238 let lsp_params = match request.to_lsp_params_or_response(
5239 &file.abs_path(cx),
5240 buffer.read(cx),
5241 &language_server,
5242 cx,
5243 ) {
5244 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5245 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5246 Err(err) => {
5247 let message = format!(
5248 "{} via {} failed: {}",
5249 request.display_name(),
5250 language_server.name(),
5251 err
5252 );
5253 // rust-analyzer likes to error with this when its still loading up
5254 if !message.ends_with("content modified") {
5255 log::warn!("{message}");
5256 }
5257 return Task::ready(Err(anyhow!(message)));
5258 }
5259 };
5260
5261 let status = request.status();
5262 let request_timeout = ProjectSettings::get_global(cx)
5263 .global_lsp_settings
5264 .get_request_timeout();
5265
5266 cx.spawn(async move |this, cx| {
5267 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5268
5269 let id = lsp_request.id();
5270 let _cleanup = if status.is_some() {
5271 cx.update(|cx| {
5272 this.update(cx, |this, cx| {
5273 this.on_lsp_work_start(
5274 language_server.server_id(),
5275 ProgressToken::Number(id),
5276 LanguageServerProgress {
5277 is_disk_based_diagnostics_progress: false,
5278 is_cancellable: false,
5279 title: None,
5280 message: status.clone(),
5281 percentage: None,
5282 last_update_at: cx.background_executor().now(),
5283 },
5284 cx,
5285 );
5286 })
5287 })
5288 .log_err();
5289
5290 Some(defer(|| {
5291 cx.update(|cx| {
5292 this.update(cx, |this, cx| {
5293 this.on_lsp_work_end(
5294 language_server.server_id(),
5295 ProgressToken::Number(id),
5296 cx,
5297 );
5298 })
5299 })
5300 .log_err();
5301 }))
5302 } else {
5303 None
5304 };
5305
5306 let result = lsp_request.await.into_response();
5307
5308 let response = result.map_err(|err| {
5309 let message = format!(
5310 "{} via {} failed: {}",
5311 request.display_name(),
5312 language_server.name(),
5313 err
5314 );
5315 // rust-analyzer likes to error with this when its still loading up
5316 if !message.ends_with("content modified") {
5317 log::warn!("{message}");
5318 }
5319 anyhow::anyhow!(message)
5320 })?;
5321
5322 request
5323 .response_from_lsp(
5324 response,
5325 this.upgrade().context("no app context")?,
5326 buffer,
5327 language_server.server_id(),
5328 cx.clone(),
5329 )
5330 .await
5331 })
5332 }
5333
5334 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5335 let mut language_formatters_to_check = Vec::new();
5336 for buffer in self.buffer_store.read(cx).buffers() {
5337 let buffer = buffer.read(cx);
5338 let settings = LanguageSettings::for_buffer(buffer, cx);
5339 if buffer.language().is_some() {
5340 let buffer_file = File::from_dyn(buffer.file());
5341 language_formatters_to_check.push((
5342 buffer_file.map(|f| f.worktree_id(cx)),
5343 settings.into_owned(),
5344 ));
5345 }
5346 }
5347
5348 self.request_workspace_config_refresh();
5349
5350 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5351 prettier_store.update(cx, |prettier_store, cx| {
5352 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5353 })
5354 }
5355
5356 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5357 .global_lsp_settings
5358 .semantic_token_rules
5359 .clone();
5360 self.semantic_token_config
5361 .update_rules(new_semantic_token_rules);
5362 // Always clear cached stylizers so that changes to language-specific
5363 // semantic token rules (e.g. from extension install/uninstall) are
5364 // picked up. Stylizers are recreated lazily, so this is cheap.
5365 self.semantic_token_config.clear_stylizers();
5366
5367 let new_global_semantic_tokens_mode =
5368 all_language_settings(None, cx).defaults.semantic_tokens;
5369 if self
5370 .semantic_token_config
5371 .update_global_mode(new_global_semantic_tokens_mode)
5372 {
5373 self.restart_all_language_servers(cx);
5374 }
5375
5376 cx.notify();
5377 }
5378
5379 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5380 let buffer_store = self.buffer_store.clone();
5381 let Some(local) = self.as_local_mut() else {
5382 return;
5383 };
5384 let mut adapters = BTreeMap::default();
5385 let get_adapter = {
5386 let languages = local.languages.clone();
5387 let environment = local.environment.clone();
5388 let weak = local.weak.clone();
5389 let worktree_store = local.worktree_store.clone();
5390 let http_client = local.http_client.clone();
5391 let fs = local.fs.clone();
5392 move |worktree_id, cx: &mut App| {
5393 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5394 Some(LocalLspAdapterDelegate::new(
5395 languages.clone(),
5396 &environment,
5397 weak.clone(),
5398 &worktree,
5399 http_client.clone(),
5400 fs.clone(),
5401 cx,
5402 ))
5403 }
5404 };
5405
5406 let mut messages_to_report = Vec::new();
5407 let (new_tree, to_stop) = {
5408 let mut rebase = local.lsp_tree.rebase();
5409 let buffers = buffer_store
5410 .read(cx)
5411 .buffers()
5412 .filter_map(|buffer| {
5413 let raw_buffer = buffer.read(cx);
5414 if !local
5415 .registered_buffers
5416 .contains_key(&raw_buffer.remote_id())
5417 {
5418 return None;
5419 }
5420 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5421 let language = raw_buffer.language().cloned()?;
5422 Some((file, language, raw_buffer.remote_id()))
5423 })
5424 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5425 for (file, language, buffer_id) in buffers {
5426 let worktree_id = file.worktree_id(cx);
5427 let Some(worktree) = local
5428 .worktree_store
5429 .read(cx)
5430 .worktree_for_id(worktree_id, cx)
5431 else {
5432 continue;
5433 };
5434
5435 if let Some((_, apply)) = local.reuse_existing_language_server(
5436 rebase.server_tree(),
5437 &worktree,
5438 &language.name(),
5439 cx,
5440 ) {
5441 (apply)(rebase.server_tree());
5442 } else if let Some(lsp_delegate) = adapters
5443 .entry(worktree_id)
5444 .or_insert_with(|| get_adapter(worktree_id, cx))
5445 .clone()
5446 {
5447 let delegate =
5448 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5449 let path = file
5450 .path()
5451 .parent()
5452 .map(Arc::from)
5453 .unwrap_or_else(|| file.path().clone());
5454 let worktree_path = ProjectPath { worktree_id, path };
5455 let abs_path = file.abs_path(cx);
5456 let nodes = rebase
5457 .walk(
5458 worktree_path,
5459 language.name(),
5460 language.manifest(),
5461 delegate.clone(),
5462 cx,
5463 )
5464 .collect::<Vec<_>>();
5465 for node in nodes {
5466 let server_id = node.server_id_or_init(|disposition| {
5467 let path = &disposition.path;
5468 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5469 let key = LanguageServerSeed {
5470 worktree_id,
5471 name: disposition.server_name.clone(),
5472 settings: LanguageServerSeedSettings {
5473 binary: disposition.settings.binary.clone(),
5474 initialization_options: disposition
5475 .settings
5476 .initialization_options
5477 .clone(),
5478 },
5479 toolchain: local.toolchain_store.read(cx).active_toolchain(
5480 path.worktree_id,
5481 &path.path,
5482 language.name(),
5483 ),
5484 };
5485 local.language_server_ids.remove(&key);
5486
5487 let server_id = local.get_or_insert_language_server(
5488 &worktree,
5489 lsp_delegate.clone(),
5490 disposition,
5491 &language.name(),
5492 cx,
5493 );
5494 if let Some(state) = local.language_servers.get(&server_id)
5495 && let Ok(uri) = uri
5496 {
5497 state.add_workspace_folder(uri);
5498 };
5499 server_id
5500 });
5501
5502 if let Some(language_server_id) = server_id {
5503 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5504 language_server_id,
5505 name: node.name(),
5506 message:
5507 proto::update_language_server::Variant::RegisteredForBuffer(
5508 proto::RegisteredForBuffer {
5509 buffer_abs_path: abs_path
5510 .to_string_lossy()
5511 .into_owned(),
5512 buffer_id: buffer_id.to_proto(),
5513 },
5514 ),
5515 });
5516 }
5517 }
5518 } else {
5519 continue;
5520 }
5521 }
5522 rebase.finish()
5523 };
5524 for message in messages_to_report {
5525 cx.emit(message);
5526 }
5527 local.lsp_tree = new_tree;
5528 for (id, _) in to_stop {
5529 self.stop_local_language_server(id, cx).detach();
5530 }
5531 }
5532
5533 pub fn apply_code_action(
5534 &self,
5535 buffer_handle: Entity<Buffer>,
5536 mut action: CodeAction,
5537 push_to_history: bool,
5538 cx: &mut Context<Self>,
5539 ) -> Task<Result<ProjectTransaction>> {
5540 if let Some((upstream_client, project_id)) = self.upstream_client() {
5541 let request = proto::ApplyCodeAction {
5542 project_id,
5543 buffer_id: buffer_handle.read(cx).remote_id().into(),
5544 action: Some(Self::serialize_code_action(&action)),
5545 };
5546 let buffer_store = self.buffer_store();
5547 cx.spawn(async move |_, cx| {
5548 let response = upstream_client
5549 .request(request)
5550 .await?
5551 .transaction
5552 .context("missing transaction")?;
5553
5554 buffer_store
5555 .update(cx, |buffer_store, cx| {
5556 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5557 })
5558 .await
5559 })
5560 } else if self.mode.is_local() {
5561 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5562 let request_timeout = ProjectSettings::get_global(cx)
5563 .global_lsp_settings
5564 .get_request_timeout();
5565 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5566 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5567 }) else {
5568 return Task::ready(Ok(ProjectTransaction::default()));
5569 };
5570
5571 cx.spawn(async move |this, cx| {
5572 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5573 .await
5574 .context("resolving a code action")?;
5575 if let Some(edit) = action.lsp_action.edit()
5576 && (edit.changes.is_some() || edit.document_changes.is_some())
5577 {
5578 return LocalLspStore::deserialize_workspace_edit(
5579 this.upgrade().context("no app present")?,
5580 edit.clone(),
5581 push_to_history,
5582 lang_server.clone(),
5583 cx,
5584 )
5585 .await;
5586 }
5587
5588 let Some(command) = action.lsp_action.command() else {
5589 return Ok(ProjectTransaction::default());
5590 };
5591
5592 let server_capabilities = lang_server.capabilities();
5593 let available_commands = server_capabilities
5594 .execute_command_provider
5595 .as_ref()
5596 .map(|options| options.commands.as_slice())
5597 .unwrap_or_default();
5598
5599 if !available_commands.contains(&command.command) {
5600 log::warn!(
5601 "Skipping executeCommand for {}, not listed in language server capabilities",
5602 command.command
5603 );
5604 return Ok(ProjectTransaction::default());
5605 }
5606
5607 let request_timeout = cx.update(|app| {
5608 ProjectSettings::get_global(app)
5609 .global_lsp_settings
5610 .get_request_timeout()
5611 });
5612
5613 this.update(cx, |this, _| {
5614 this.as_local_mut()
5615 .unwrap()
5616 .last_workspace_edits_by_language_server
5617 .remove(&lang_server.server_id());
5618 })?;
5619
5620 let _result = lang_server
5621 .request::<lsp::request::ExecuteCommand>(
5622 lsp::ExecuteCommandParams {
5623 command: command.command.clone(),
5624 arguments: command.arguments.clone().unwrap_or_default(),
5625 ..lsp::ExecuteCommandParams::default()
5626 },
5627 request_timeout,
5628 )
5629 .await
5630 .into_response()
5631 .context("execute command")?;
5632
5633 return this.update(cx, |this, _| {
5634 this.as_local_mut()
5635 .unwrap()
5636 .last_workspace_edits_by_language_server
5637 .remove(&lang_server.server_id())
5638 .unwrap_or_default()
5639 });
5640 })
5641 } else {
5642 Task::ready(Err(anyhow!("no upstream client and not local")))
5643 }
5644 }
5645
5646 pub fn apply_code_action_kind(
5647 &mut self,
5648 buffers: HashSet<Entity<Buffer>>,
5649 kind: CodeActionKind,
5650 push_to_history: bool,
5651 cx: &mut Context<Self>,
5652 ) -> Task<anyhow::Result<ProjectTransaction>> {
5653 if self.as_local().is_some() {
5654 cx.spawn(async move |lsp_store, cx| {
5655 let buffers = buffers.into_iter().collect::<Vec<_>>();
5656 let result = LocalLspStore::execute_code_action_kind_locally(
5657 lsp_store.clone(),
5658 buffers,
5659 kind,
5660 push_to_history,
5661 cx,
5662 )
5663 .await;
5664 lsp_store.update(cx, |lsp_store, _| {
5665 lsp_store.update_last_formatting_failure(&result);
5666 })?;
5667 result
5668 })
5669 } else if let Some((client, project_id)) = self.upstream_client() {
5670 let buffer_store = self.buffer_store();
5671 cx.spawn(async move |lsp_store, cx| {
5672 let result = client
5673 .request(proto::ApplyCodeActionKind {
5674 project_id,
5675 kind: kind.as_str().to_owned(),
5676 buffer_ids: buffers
5677 .iter()
5678 .map(|buffer| {
5679 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5680 })
5681 .collect(),
5682 })
5683 .await
5684 .and_then(|result| result.transaction.context("missing transaction"));
5685 lsp_store.update(cx, |lsp_store, _| {
5686 lsp_store.update_last_formatting_failure(&result);
5687 })?;
5688
5689 let transaction_response = result?;
5690 buffer_store
5691 .update(cx, |buffer_store, cx| {
5692 buffer_store.deserialize_project_transaction(
5693 transaction_response,
5694 push_to_history,
5695 cx,
5696 )
5697 })
5698 .await
5699 })
5700 } else {
5701 Task::ready(Ok(ProjectTransaction::default()))
5702 }
5703 }
5704
5705 pub fn resolved_hint(
5706 &mut self,
5707 buffer_id: BufferId,
5708 id: InlayId,
5709 cx: &mut Context<Self>,
5710 ) -> Option<ResolvedHint> {
5711 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5712
5713 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5714 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5715 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5716 let (server_id, resolve_data) = match &hint.resolve_state {
5717 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5718 ResolveState::Resolving => {
5719 return Some(ResolvedHint::Resolving(
5720 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5721 ));
5722 }
5723 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5724 };
5725
5726 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5727 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5728 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5729 id,
5730 cx.spawn(async move |lsp_store, cx| {
5731 let resolved_hint = resolve_task.await;
5732 lsp_store
5733 .update(cx, |lsp_store, _| {
5734 if let Some(old_inlay_hint) = lsp_store
5735 .lsp_data
5736 .get_mut(&buffer_id)
5737 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5738 {
5739 match resolved_hint {
5740 Ok(resolved_hint) => {
5741 *old_inlay_hint = resolved_hint;
5742 }
5743 Err(e) => {
5744 old_inlay_hint.resolve_state =
5745 ResolveState::CanResolve(server_id, resolve_data);
5746 log::error!("Inlay hint resolve failed: {e:#}");
5747 }
5748 }
5749 }
5750 })
5751 .ok();
5752 })
5753 .shared(),
5754 );
5755 debug_assert!(
5756 previous_task.is_none(),
5757 "Did not change hint's resolve state after spawning its resolve"
5758 );
5759 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5760 None
5761 }
5762
5763 pub(crate) fn linked_edits(
5764 &mut self,
5765 buffer: &Entity<Buffer>,
5766 position: Anchor,
5767 cx: &mut Context<Self>,
5768 ) -> Task<Result<Vec<Range<Anchor>>>> {
5769 let snapshot = buffer.read(cx).snapshot();
5770 let scope = snapshot.language_scope_at(position);
5771 let Some(server_id) = self
5772 .as_local()
5773 .and_then(|local| {
5774 buffer.update(cx, |buffer, cx| {
5775 local
5776 .language_servers_for_buffer(buffer, cx)
5777 .filter(|(_, server)| {
5778 LinkedEditingRange::check_server_capabilities(server.capabilities())
5779 })
5780 .filter(|(adapter, _)| {
5781 scope
5782 .as_ref()
5783 .map(|scope| scope.language_allowed(&adapter.name))
5784 .unwrap_or(true)
5785 })
5786 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5787 .next()
5788 })
5789 })
5790 .or_else(|| {
5791 self.upstream_client()
5792 .is_some()
5793 .then_some(LanguageServerToQuery::FirstCapable)
5794 })
5795 .filter(|_| {
5796 maybe!({
5797 buffer.read(cx).language_at(position)?;
5798 Some(
5799 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5800 .linked_edits,
5801 )
5802 }) == Some(true)
5803 })
5804 else {
5805 return Task::ready(Ok(Vec::new()));
5806 };
5807
5808 self.request_lsp(
5809 buffer.clone(),
5810 server_id,
5811 LinkedEditingRange { position },
5812 cx,
5813 )
5814 }
5815
5816 fn apply_on_type_formatting(
5817 &mut self,
5818 buffer: Entity<Buffer>,
5819 position: Anchor,
5820 trigger: String,
5821 cx: &mut Context<Self>,
5822 ) -> Task<Result<Option<Transaction>>> {
5823 if let Some((client, project_id)) = self.upstream_client() {
5824 if !self.check_if_capable_for_proto_request(
5825 &buffer,
5826 |capabilities| {
5827 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5828 },
5829 cx,
5830 ) {
5831 return Task::ready(Ok(None));
5832 }
5833 let request = proto::OnTypeFormatting {
5834 project_id,
5835 buffer_id: buffer.read(cx).remote_id().into(),
5836 position: Some(serialize_anchor(&position)),
5837 trigger,
5838 version: serialize_version(&buffer.read(cx).version()),
5839 };
5840 cx.background_spawn(async move {
5841 client
5842 .request(request)
5843 .await?
5844 .transaction
5845 .map(language::proto::deserialize_transaction)
5846 .transpose()
5847 })
5848 } else if let Some(local) = self.as_local_mut() {
5849 let buffer_id = buffer.read(cx).remote_id();
5850 local.buffers_being_formatted.insert(buffer_id);
5851 cx.spawn(async move |this, cx| {
5852 let _cleanup = defer({
5853 let this = this.clone();
5854 let mut cx = cx.clone();
5855 move || {
5856 this.update(&mut cx, |this, _| {
5857 if let Some(local) = this.as_local_mut() {
5858 local.buffers_being_formatted.remove(&buffer_id);
5859 }
5860 })
5861 .ok();
5862 }
5863 });
5864
5865 buffer
5866 .update(cx, |buffer, _| {
5867 buffer.wait_for_edits(Some(position.timestamp()))
5868 })
5869 .await?;
5870 this.update(cx, |this, cx| {
5871 let position = position.to_point_utf16(buffer.read(cx));
5872 this.on_type_format(buffer, position, trigger, false, cx)
5873 })?
5874 .await
5875 })
5876 } else {
5877 Task::ready(Err(anyhow!("No upstream client or local language server")))
5878 }
5879 }
5880
5881 pub fn on_type_format<T: ToPointUtf16>(
5882 &mut self,
5883 buffer: Entity<Buffer>,
5884 position: T,
5885 trigger: String,
5886 push_to_history: bool,
5887 cx: &mut Context<Self>,
5888 ) -> Task<Result<Option<Transaction>>> {
5889 let position = position.to_point_utf16(buffer.read(cx));
5890 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5891 }
5892
5893 fn on_type_format_impl(
5894 &mut self,
5895 buffer: Entity<Buffer>,
5896 position: PointUtf16,
5897 trigger: String,
5898 push_to_history: bool,
5899 cx: &mut Context<Self>,
5900 ) -> Task<Result<Option<Transaction>>> {
5901 let options = buffer.update(cx, |buffer, cx| {
5902 lsp_command::lsp_formatting_options(
5903 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5904 )
5905 });
5906
5907 cx.spawn(async move |this, cx| {
5908 if let Some(waiter) =
5909 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5910 {
5911 waiter.await?;
5912 }
5913 cx.update(|cx| {
5914 this.update(cx, |this, cx| {
5915 this.request_lsp(
5916 buffer.clone(),
5917 LanguageServerToQuery::FirstCapable,
5918 OnTypeFormatting {
5919 position,
5920 trigger,
5921 options,
5922 push_to_history,
5923 },
5924 cx,
5925 )
5926 })
5927 })?
5928 .await
5929 })
5930 }
5931
5932 pub fn definitions(
5933 &mut self,
5934 buffer: &Entity<Buffer>,
5935 position: PointUtf16,
5936 cx: &mut Context<Self>,
5937 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5938 if let Some((upstream_client, project_id)) = self.upstream_client() {
5939 let request = GetDefinitions { position };
5940 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5941 return Task::ready(Ok(None));
5942 }
5943
5944 let request_timeout = ProjectSettings::get_global(cx)
5945 .global_lsp_settings
5946 .get_request_timeout();
5947
5948 let request_task = upstream_client.request_lsp(
5949 project_id,
5950 None,
5951 request_timeout,
5952 cx.background_executor().clone(),
5953 request.to_proto(project_id, buffer.read(cx)),
5954 );
5955 let buffer = buffer.clone();
5956 cx.spawn(async move |weak_lsp_store, cx| {
5957 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5958 return Ok(None);
5959 };
5960 let Some(responses) = request_task.await? else {
5961 return Ok(None);
5962 };
5963 let actions = join_all(responses.payload.into_iter().map(|response| {
5964 GetDefinitions { position }.response_from_proto(
5965 response.response,
5966 lsp_store.clone(),
5967 buffer.clone(),
5968 cx.clone(),
5969 )
5970 }))
5971 .await;
5972
5973 Ok(Some(
5974 actions
5975 .into_iter()
5976 .collect::<Result<Vec<Vec<_>>>>()?
5977 .into_iter()
5978 .flatten()
5979 .dedup()
5980 .collect(),
5981 ))
5982 })
5983 } else {
5984 let definitions_task = self.request_multiple_lsp_locally(
5985 buffer,
5986 Some(position),
5987 GetDefinitions { position },
5988 cx,
5989 );
5990 cx.background_spawn(async move {
5991 Ok(Some(
5992 definitions_task
5993 .await
5994 .into_iter()
5995 .flat_map(|(_, definitions)| definitions)
5996 .dedup()
5997 .collect(),
5998 ))
5999 })
6000 }
6001 }
6002
6003 pub fn declarations(
6004 &mut self,
6005 buffer: &Entity<Buffer>,
6006 position: PointUtf16,
6007 cx: &mut Context<Self>,
6008 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6009 if let Some((upstream_client, project_id)) = self.upstream_client() {
6010 let request = GetDeclarations { position };
6011 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6012 return Task::ready(Ok(None));
6013 }
6014 let request_timeout = ProjectSettings::get_global(cx)
6015 .global_lsp_settings
6016 .get_request_timeout();
6017 let request_task = upstream_client.request_lsp(
6018 project_id,
6019 None,
6020 request_timeout,
6021 cx.background_executor().clone(),
6022 request.to_proto(project_id, buffer.read(cx)),
6023 );
6024 let buffer = buffer.clone();
6025 cx.spawn(async move |weak_lsp_store, cx| {
6026 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6027 return Ok(None);
6028 };
6029 let Some(responses) = request_task.await? else {
6030 return Ok(None);
6031 };
6032 let actions = join_all(responses.payload.into_iter().map(|response| {
6033 GetDeclarations { position }.response_from_proto(
6034 response.response,
6035 lsp_store.clone(),
6036 buffer.clone(),
6037 cx.clone(),
6038 )
6039 }))
6040 .await;
6041
6042 Ok(Some(
6043 actions
6044 .into_iter()
6045 .collect::<Result<Vec<Vec<_>>>>()?
6046 .into_iter()
6047 .flatten()
6048 .dedup()
6049 .collect(),
6050 ))
6051 })
6052 } else {
6053 let declarations_task = self.request_multiple_lsp_locally(
6054 buffer,
6055 Some(position),
6056 GetDeclarations { position },
6057 cx,
6058 );
6059 cx.background_spawn(async move {
6060 Ok(Some(
6061 declarations_task
6062 .await
6063 .into_iter()
6064 .flat_map(|(_, declarations)| declarations)
6065 .dedup()
6066 .collect(),
6067 ))
6068 })
6069 }
6070 }
6071
6072 pub fn type_definitions(
6073 &mut self,
6074 buffer: &Entity<Buffer>,
6075 position: PointUtf16,
6076 cx: &mut Context<Self>,
6077 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6078 if let Some((upstream_client, project_id)) = self.upstream_client() {
6079 let request = GetTypeDefinitions { position };
6080 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6081 return Task::ready(Ok(None));
6082 }
6083 let request_timeout = ProjectSettings::get_global(cx)
6084 .global_lsp_settings
6085 .get_request_timeout();
6086 let request_task = upstream_client.request_lsp(
6087 project_id,
6088 None,
6089 request_timeout,
6090 cx.background_executor().clone(),
6091 request.to_proto(project_id, buffer.read(cx)),
6092 );
6093 let buffer = buffer.clone();
6094 cx.spawn(async move |weak_lsp_store, cx| {
6095 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6096 return Ok(None);
6097 };
6098 let Some(responses) = request_task.await? else {
6099 return Ok(None);
6100 };
6101 let actions = join_all(responses.payload.into_iter().map(|response| {
6102 GetTypeDefinitions { position }.response_from_proto(
6103 response.response,
6104 lsp_store.clone(),
6105 buffer.clone(),
6106 cx.clone(),
6107 )
6108 }))
6109 .await;
6110
6111 Ok(Some(
6112 actions
6113 .into_iter()
6114 .collect::<Result<Vec<Vec<_>>>>()?
6115 .into_iter()
6116 .flatten()
6117 .dedup()
6118 .collect(),
6119 ))
6120 })
6121 } else {
6122 let type_definitions_task = self.request_multiple_lsp_locally(
6123 buffer,
6124 Some(position),
6125 GetTypeDefinitions { position },
6126 cx,
6127 );
6128 cx.background_spawn(async move {
6129 Ok(Some(
6130 type_definitions_task
6131 .await
6132 .into_iter()
6133 .flat_map(|(_, type_definitions)| type_definitions)
6134 .dedup()
6135 .collect(),
6136 ))
6137 })
6138 }
6139 }
6140
6141 pub fn implementations(
6142 &mut self,
6143 buffer: &Entity<Buffer>,
6144 position: PointUtf16,
6145 cx: &mut Context<Self>,
6146 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6147 if let Some((upstream_client, project_id)) = self.upstream_client() {
6148 let request = GetImplementations { position };
6149 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6150 return Task::ready(Ok(None));
6151 }
6152
6153 let request_timeout = ProjectSettings::get_global(cx)
6154 .global_lsp_settings
6155 .get_request_timeout();
6156 let request_task = upstream_client.request_lsp(
6157 project_id,
6158 None,
6159 request_timeout,
6160 cx.background_executor().clone(),
6161 request.to_proto(project_id, buffer.read(cx)),
6162 );
6163 let buffer = buffer.clone();
6164 cx.spawn(async move |weak_lsp_store, cx| {
6165 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6166 return Ok(None);
6167 };
6168 let Some(responses) = request_task.await? else {
6169 return Ok(None);
6170 };
6171 let actions = join_all(responses.payload.into_iter().map(|response| {
6172 GetImplementations { position }.response_from_proto(
6173 response.response,
6174 lsp_store.clone(),
6175 buffer.clone(),
6176 cx.clone(),
6177 )
6178 }))
6179 .await;
6180
6181 Ok(Some(
6182 actions
6183 .into_iter()
6184 .collect::<Result<Vec<Vec<_>>>>()?
6185 .into_iter()
6186 .flatten()
6187 .dedup()
6188 .collect(),
6189 ))
6190 })
6191 } else {
6192 let implementations_task = self.request_multiple_lsp_locally(
6193 buffer,
6194 Some(position),
6195 GetImplementations { position },
6196 cx,
6197 );
6198 cx.background_spawn(async move {
6199 Ok(Some(
6200 implementations_task
6201 .await
6202 .into_iter()
6203 .flat_map(|(_, implementations)| implementations)
6204 .dedup()
6205 .collect(),
6206 ))
6207 })
6208 }
6209 }
6210
6211 pub fn references(
6212 &mut self,
6213 buffer: &Entity<Buffer>,
6214 position: PointUtf16,
6215 cx: &mut Context<Self>,
6216 ) -> Task<Result<Option<Vec<Location>>>> {
6217 if let Some((upstream_client, project_id)) = self.upstream_client() {
6218 let request = GetReferences { position };
6219 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6220 return Task::ready(Ok(None));
6221 }
6222
6223 let request_timeout = ProjectSettings::get_global(cx)
6224 .global_lsp_settings
6225 .get_request_timeout();
6226 let request_task = upstream_client.request_lsp(
6227 project_id,
6228 None,
6229 request_timeout,
6230 cx.background_executor().clone(),
6231 request.to_proto(project_id, buffer.read(cx)),
6232 );
6233 let buffer = buffer.clone();
6234 cx.spawn(async move |weak_lsp_store, cx| {
6235 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6236 return Ok(None);
6237 };
6238 let Some(responses) = request_task.await? else {
6239 return Ok(None);
6240 };
6241
6242 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6243 GetReferences { position }.response_from_proto(
6244 lsp_response.response,
6245 lsp_store.clone(),
6246 buffer.clone(),
6247 cx.clone(),
6248 )
6249 }))
6250 .await
6251 .into_iter()
6252 .collect::<Result<Vec<Vec<_>>>>()?
6253 .into_iter()
6254 .flatten()
6255 .dedup()
6256 .collect();
6257 Ok(Some(locations))
6258 })
6259 } else {
6260 let references_task = self.request_multiple_lsp_locally(
6261 buffer,
6262 Some(position),
6263 GetReferences { position },
6264 cx,
6265 );
6266 cx.background_spawn(async move {
6267 Ok(Some(
6268 references_task
6269 .await
6270 .into_iter()
6271 .flat_map(|(_, references)| references)
6272 .dedup()
6273 .collect(),
6274 ))
6275 })
6276 }
6277 }
6278
6279 pub fn code_actions(
6280 &mut self,
6281 buffer: &Entity<Buffer>,
6282 range: Range<Anchor>,
6283 kinds: Option<Vec<CodeActionKind>>,
6284 cx: &mut Context<Self>,
6285 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6286 if let Some((upstream_client, project_id)) = self.upstream_client() {
6287 let request = GetCodeActions {
6288 range: range.clone(),
6289 kinds: kinds.clone(),
6290 };
6291 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6292 return Task::ready(Ok(None));
6293 }
6294 let request_timeout = ProjectSettings::get_global(cx)
6295 .global_lsp_settings
6296 .get_request_timeout();
6297 let request_task = upstream_client.request_lsp(
6298 project_id,
6299 None,
6300 request_timeout,
6301 cx.background_executor().clone(),
6302 request.to_proto(project_id, buffer.read(cx)),
6303 );
6304 let buffer = buffer.clone();
6305 cx.spawn(async move |weak_lsp_store, cx| {
6306 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6307 return Ok(None);
6308 };
6309 let Some(responses) = request_task.await? else {
6310 return Ok(None);
6311 };
6312 let actions = join_all(responses.payload.into_iter().map(|response| {
6313 GetCodeActions {
6314 range: range.clone(),
6315 kinds: kinds.clone(),
6316 }
6317 .response_from_proto(
6318 response.response,
6319 lsp_store.clone(),
6320 buffer.clone(),
6321 cx.clone(),
6322 )
6323 }))
6324 .await;
6325
6326 Ok(Some(
6327 actions
6328 .into_iter()
6329 .collect::<Result<Vec<Vec<_>>>>()?
6330 .into_iter()
6331 .flatten()
6332 .collect(),
6333 ))
6334 })
6335 } else {
6336 let all_actions_task = self.request_multiple_lsp_locally(
6337 buffer,
6338 Some(range.start),
6339 GetCodeActions { range, kinds },
6340 cx,
6341 );
6342 cx.background_spawn(async move {
6343 Ok(Some(
6344 all_actions_task
6345 .await
6346 .into_iter()
6347 .flat_map(|(_, actions)| actions)
6348 .collect(),
6349 ))
6350 })
6351 }
6352 }
6353
6354 #[inline(never)]
6355 pub fn completions(
6356 &self,
6357 buffer: &Entity<Buffer>,
6358 position: PointUtf16,
6359 context: CompletionContext,
6360 cx: &mut Context<Self>,
6361 ) -> Task<Result<Vec<CompletionResponse>>> {
6362 let language_registry = self.languages.clone();
6363
6364 if let Some((upstream_client, project_id)) = self.upstream_client() {
6365 let snapshot = buffer.read(cx).snapshot();
6366 let offset = position.to_offset(&snapshot);
6367 let scope = snapshot.language_scope_at(offset);
6368 let capable_lsps = self.all_capable_for_proto_request(
6369 buffer,
6370 |server_name, capabilities| {
6371 capabilities.completion_provider.is_some()
6372 && scope
6373 .as_ref()
6374 .map(|scope| scope.language_allowed(server_name))
6375 .unwrap_or(true)
6376 },
6377 cx,
6378 );
6379 if capable_lsps.is_empty() {
6380 return Task::ready(Ok(Vec::new()));
6381 }
6382
6383 let language = buffer.read(cx).language().cloned();
6384
6385 let buffer = buffer.clone();
6386
6387 cx.spawn(async move |this, cx| {
6388 let requests = join_all(
6389 capable_lsps
6390 .into_iter()
6391 .map(|(id, server_name)| {
6392 let request = GetCompletions {
6393 position,
6394 context: context.clone(),
6395 server_id: Some(id),
6396 };
6397 let buffer = buffer.clone();
6398 let language = language.clone();
6399 let lsp_adapter = language.as_ref().and_then(|language| {
6400 let adapters = language_registry.lsp_adapters(&language.name());
6401 adapters
6402 .iter()
6403 .find(|adapter| adapter.name() == server_name)
6404 .or_else(|| adapters.first())
6405 .cloned()
6406 });
6407 let upstream_client = upstream_client.clone();
6408 let response = this
6409 .update(cx, |this, cx| {
6410 this.send_lsp_proto_request(
6411 buffer,
6412 upstream_client,
6413 project_id,
6414 request,
6415 cx,
6416 )
6417 })
6418 .log_err();
6419 async move {
6420 let response = response?.await.log_err()?;
6421
6422 let completions = populate_labels_for_completions(
6423 response.completions,
6424 language,
6425 lsp_adapter,
6426 )
6427 .await;
6428
6429 Some(CompletionResponse {
6430 completions,
6431 display_options: CompletionDisplayOptions::default(),
6432 is_incomplete: response.is_incomplete,
6433 })
6434 }
6435 })
6436 .collect::<Vec<_>>(),
6437 );
6438 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6439 })
6440 } else if let Some(local) = self.as_local() {
6441 let snapshot = buffer.read(cx).snapshot();
6442 let offset = position.to_offset(&snapshot);
6443 let scope = snapshot.language_scope_at(offset);
6444 let language = snapshot.language().cloned();
6445 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6446 .completions
6447 .clone();
6448 if !completion_settings.lsp {
6449 return Task::ready(Ok(Vec::new()));
6450 }
6451
6452 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6453 local
6454 .language_servers_for_buffer(buffer, cx)
6455 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6456 .filter(|(adapter, _)| {
6457 scope
6458 .as_ref()
6459 .map(|scope| scope.language_allowed(&adapter.name))
6460 .unwrap_or(true)
6461 })
6462 .map(|(_, server)| server.server_id())
6463 .collect()
6464 });
6465
6466 let buffer = buffer.clone();
6467 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6468 let lsp_timeout = if lsp_timeout > 0 {
6469 Some(Duration::from_millis(lsp_timeout))
6470 } else {
6471 None
6472 };
6473 cx.spawn(async move |this, cx| {
6474 let mut tasks = Vec::with_capacity(server_ids.len());
6475 this.update(cx, |lsp_store, cx| {
6476 for server_id in server_ids {
6477 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6478 let lsp_timeout = lsp_timeout
6479 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6480 let mut timeout = cx.background_spawn(async move {
6481 match lsp_timeout {
6482 Some(lsp_timeout) => {
6483 lsp_timeout.await;
6484 true
6485 },
6486 None => false,
6487 }
6488 }).fuse();
6489 let mut lsp_request = lsp_store.request_lsp(
6490 buffer.clone(),
6491 LanguageServerToQuery::Other(server_id),
6492 GetCompletions {
6493 position,
6494 context: context.clone(),
6495 server_id: Some(server_id),
6496 },
6497 cx,
6498 ).fuse();
6499 let new_task = cx.background_spawn(async move {
6500 select_biased! {
6501 response = lsp_request => anyhow::Ok(Some(response?)),
6502 timeout_happened = timeout => {
6503 if timeout_happened {
6504 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6505 Ok(None)
6506 } else {
6507 let completions = lsp_request.await?;
6508 Ok(Some(completions))
6509 }
6510 },
6511 }
6512 });
6513 tasks.push((lsp_adapter, new_task));
6514 }
6515 })?;
6516
6517 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6518 let completion_response = task.await.ok()??;
6519 let completions = populate_labels_for_completions(
6520 completion_response.completions,
6521 language.clone(),
6522 lsp_adapter,
6523 )
6524 .await;
6525 Some(CompletionResponse {
6526 completions,
6527 display_options: CompletionDisplayOptions::default(),
6528 is_incomplete: completion_response.is_incomplete,
6529 })
6530 });
6531
6532 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6533
6534 Ok(responses.into_iter().flatten().collect())
6535 })
6536 } else {
6537 Task::ready(Err(anyhow!("No upstream client or local language server")))
6538 }
6539 }
6540
6541 pub fn resolve_completions(
6542 &self,
6543 buffer: Entity<Buffer>,
6544 completion_indices: Vec<usize>,
6545 completions: Rc<RefCell<Box<[Completion]>>>,
6546 cx: &mut Context<Self>,
6547 ) -> Task<Result<bool>> {
6548 let client = self.upstream_client();
6549 let buffer_id = buffer.read(cx).remote_id();
6550 let buffer_snapshot = buffer.read(cx).snapshot();
6551
6552 if !self.check_if_capable_for_proto_request(
6553 &buffer,
6554 GetCompletions::can_resolve_completions,
6555 cx,
6556 ) {
6557 return Task::ready(Ok(false));
6558 }
6559 cx.spawn(async move |lsp_store, cx| {
6560 let request_timeout = cx.update(|app| {
6561 ProjectSettings::get_global(app)
6562 .global_lsp_settings
6563 .get_request_timeout()
6564 });
6565
6566 let mut did_resolve = false;
6567 if let Some((client, project_id)) = client {
6568 for completion_index in completion_indices {
6569 let server_id = {
6570 let completion = &completions.borrow()[completion_index];
6571 completion.source.server_id()
6572 };
6573 if let Some(server_id) = server_id {
6574 if Self::resolve_completion_remote(
6575 project_id,
6576 server_id,
6577 buffer_id,
6578 completions.clone(),
6579 completion_index,
6580 client.clone(),
6581 )
6582 .await
6583 .log_err()
6584 .is_some()
6585 {
6586 did_resolve = true;
6587 }
6588 } else {
6589 resolve_word_completion(
6590 &buffer_snapshot,
6591 &mut completions.borrow_mut()[completion_index],
6592 );
6593 }
6594 }
6595 } else {
6596 for completion_index in completion_indices {
6597 let server_id = {
6598 let completion = &completions.borrow()[completion_index];
6599 completion.source.server_id()
6600 };
6601 if let Some(server_id) = server_id {
6602 let server_and_adapter = lsp_store
6603 .read_with(cx, |lsp_store, _| {
6604 let server = lsp_store.language_server_for_id(server_id)?;
6605 let adapter =
6606 lsp_store.language_server_adapter_for_id(server.server_id())?;
6607 Some((server, adapter))
6608 })
6609 .ok()
6610 .flatten();
6611 let Some((server, adapter)) = server_and_adapter else {
6612 continue;
6613 };
6614
6615 let resolved = Self::resolve_completion_local(
6616 server,
6617 completions.clone(),
6618 completion_index,
6619 request_timeout,
6620 )
6621 .await
6622 .log_err()
6623 .is_some();
6624 if resolved {
6625 Self::regenerate_completion_labels(
6626 adapter,
6627 &buffer_snapshot,
6628 completions.clone(),
6629 completion_index,
6630 )
6631 .await
6632 .log_err();
6633 did_resolve = true;
6634 }
6635 } else {
6636 resolve_word_completion(
6637 &buffer_snapshot,
6638 &mut completions.borrow_mut()[completion_index],
6639 );
6640 }
6641 }
6642 }
6643
6644 Ok(did_resolve)
6645 })
6646 }
6647
6648 async fn resolve_completion_local(
6649 server: Arc<lsp::LanguageServer>,
6650 completions: Rc<RefCell<Box<[Completion]>>>,
6651 completion_index: usize,
6652 request_timeout: Duration,
6653 ) -> Result<()> {
6654 let server_id = server.server_id();
6655 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6656 return Ok(());
6657 }
6658
6659 let request = {
6660 let completion = &completions.borrow()[completion_index];
6661 match &completion.source {
6662 CompletionSource::Lsp {
6663 lsp_completion,
6664 resolved,
6665 server_id: completion_server_id,
6666 ..
6667 } => {
6668 if *resolved {
6669 return Ok(());
6670 }
6671 anyhow::ensure!(
6672 server_id == *completion_server_id,
6673 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6674 );
6675 server.request::<lsp::request::ResolveCompletionItem>(
6676 *lsp_completion.clone(),
6677 request_timeout,
6678 )
6679 }
6680 CompletionSource::BufferWord { .. }
6681 | CompletionSource::Dap { .. }
6682 | CompletionSource::Custom => {
6683 return Ok(());
6684 }
6685 }
6686 };
6687 let resolved_completion = request
6688 .await
6689 .into_response()
6690 .context("resolve completion")?;
6691
6692 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6693 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6694
6695 let mut completions = completions.borrow_mut();
6696 let completion = &mut completions[completion_index];
6697 if let CompletionSource::Lsp {
6698 lsp_completion,
6699 resolved,
6700 server_id: completion_server_id,
6701 ..
6702 } = &mut completion.source
6703 {
6704 if *resolved {
6705 return Ok(());
6706 }
6707 anyhow::ensure!(
6708 server_id == *completion_server_id,
6709 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6710 );
6711 **lsp_completion = resolved_completion;
6712 *resolved = true;
6713 }
6714 Ok(())
6715 }
6716
6717 async fn regenerate_completion_labels(
6718 adapter: Arc<CachedLspAdapter>,
6719 snapshot: &BufferSnapshot,
6720 completions: Rc<RefCell<Box<[Completion]>>>,
6721 completion_index: usize,
6722 ) -> Result<()> {
6723 let completion_item = completions.borrow()[completion_index]
6724 .source
6725 .lsp_completion(true)
6726 .map(Cow::into_owned);
6727 if let Some(lsp_documentation) = completion_item
6728 .as_ref()
6729 .and_then(|completion_item| completion_item.documentation.clone())
6730 {
6731 let mut completions = completions.borrow_mut();
6732 let completion = &mut completions[completion_index];
6733 completion.documentation = Some(lsp_documentation.into());
6734 } else {
6735 let mut completions = completions.borrow_mut();
6736 let completion = &mut completions[completion_index];
6737 completion.documentation = Some(CompletionDocumentation::Undocumented);
6738 }
6739
6740 let mut new_label = match completion_item {
6741 Some(completion_item) => {
6742 // Some language servers always return `detail` lazily via resolve, regardless of
6743 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6744 // See: https://github.com/yioneko/vtsls/issues/213
6745 let language = snapshot.language();
6746 match language {
6747 Some(language) => {
6748 adapter
6749 .labels_for_completions(
6750 std::slice::from_ref(&completion_item),
6751 language,
6752 )
6753 .await?
6754 }
6755 None => Vec::new(),
6756 }
6757 .pop()
6758 .flatten()
6759 .unwrap_or_else(|| {
6760 CodeLabel::fallback_for_completion(
6761 &completion_item,
6762 language.map(|language| language.as_ref()),
6763 )
6764 })
6765 }
6766 None => CodeLabel::plain(
6767 completions.borrow()[completion_index].new_text.clone(),
6768 None,
6769 ),
6770 };
6771 ensure_uniform_list_compatible_label(&mut new_label);
6772
6773 let mut completions = completions.borrow_mut();
6774 let completion = &mut completions[completion_index];
6775 if completion.label.filter_text() == new_label.filter_text() {
6776 completion.label = new_label;
6777 } else {
6778 log::error!(
6779 "Resolved completion changed display label from {} to {}. \
6780 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6781 completion.label.text(),
6782 new_label.text(),
6783 completion.label.filter_text(),
6784 new_label.filter_text()
6785 );
6786 }
6787
6788 Ok(())
6789 }
6790
6791 async fn resolve_completion_remote(
6792 project_id: u64,
6793 server_id: LanguageServerId,
6794 buffer_id: BufferId,
6795 completions: Rc<RefCell<Box<[Completion]>>>,
6796 completion_index: usize,
6797 client: AnyProtoClient,
6798 ) -> Result<()> {
6799 let lsp_completion = {
6800 let completion = &completions.borrow()[completion_index];
6801 match &completion.source {
6802 CompletionSource::Lsp {
6803 lsp_completion,
6804 resolved,
6805 server_id: completion_server_id,
6806 ..
6807 } => {
6808 anyhow::ensure!(
6809 server_id == *completion_server_id,
6810 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6811 );
6812 if *resolved {
6813 return Ok(());
6814 }
6815 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6816 }
6817 CompletionSource::Custom
6818 | CompletionSource::Dap { .. }
6819 | CompletionSource::BufferWord { .. } => {
6820 return Ok(());
6821 }
6822 }
6823 };
6824 let request = proto::ResolveCompletionDocumentation {
6825 project_id,
6826 language_server_id: server_id.0 as u64,
6827 lsp_completion,
6828 buffer_id: buffer_id.into(),
6829 };
6830
6831 let response = client
6832 .request(request)
6833 .await
6834 .context("completion documentation resolve proto request")?;
6835 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6836
6837 let documentation = if response.documentation.is_empty() {
6838 CompletionDocumentation::Undocumented
6839 } else if response.documentation_is_markdown {
6840 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6841 } else if response.documentation.lines().count() <= 1 {
6842 CompletionDocumentation::SingleLine(response.documentation.into())
6843 } else {
6844 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6845 };
6846
6847 let mut completions = completions.borrow_mut();
6848 let completion = &mut completions[completion_index];
6849 completion.documentation = Some(documentation);
6850 if let CompletionSource::Lsp {
6851 insert_range,
6852 lsp_completion,
6853 resolved,
6854 server_id: completion_server_id,
6855 lsp_defaults: _,
6856 } = &mut completion.source
6857 {
6858 let completion_insert_range = response
6859 .old_insert_start
6860 .and_then(deserialize_anchor)
6861 .zip(response.old_insert_end.and_then(deserialize_anchor));
6862 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6863
6864 if *resolved {
6865 return Ok(());
6866 }
6867 anyhow::ensure!(
6868 server_id == *completion_server_id,
6869 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6870 );
6871 **lsp_completion = resolved_lsp_completion;
6872 *resolved = true;
6873 }
6874
6875 let replace_range = response
6876 .old_replace_start
6877 .and_then(deserialize_anchor)
6878 .zip(response.old_replace_end.and_then(deserialize_anchor));
6879 if let Some((old_replace_start, old_replace_end)) = replace_range
6880 && !response.new_text.is_empty()
6881 {
6882 completion.new_text = response.new_text;
6883 completion.replace_range = old_replace_start..old_replace_end;
6884 }
6885
6886 Ok(())
6887 }
6888
6889 pub fn apply_additional_edits_for_completion(
6890 &self,
6891 buffer_handle: Entity<Buffer>,
6892 completions: Rc<RefCell<Box<[Completion]>>>,
6893 completion_index: usize,
6894 push_to_history: bool,
6895 all_commit_ranges: Vec<Range<language::Anchor>>,
6896 cx: &mut Context<Self>,
6897 ) -> Task<Result<Option<Transaction>>> {
6898 if let Some((client, project_id)) = self.upstream_client() {
6899 let buffer = buffer_handle.read(cx);
6900 let buffer_id = buffer.remote_id();
6901 cx.spawn(async move |_, cx| {
6902 let request = {
6903 let completion = completions.borrow()[completion_index].clone();
6904 proto::ApplyCompletionAdditionalEdits {
6905 project_id,
6906 buffer_id: buffer_id.into(),
6907 completion: Some(Self::serialize_completion(&CoreCompletion {
6908 replace_range: completion.replace_range,
6909 new_text: completion.new_text,
6910 source: completion.source,
6911 })),
6912 all_commit_ranges: all_commit_ranges
6913 .iter()
6914 .cloned()
6915 .map(language::proto::serialize_anchor_range)
6916 .collect(),
6917 }
6918 };
6919
6920 let Some(transaction) = client.request(request).await?.transaction else {
6921 return Ok(None);
6922 };
6923
6924 let transaction = language::proto::deserialize_transaction(transaction)?;
6925 buffer_handle
6926 .update(cx, |buffer, _| {
6927 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6928 })
6929 .await?;
6930 if push_to_history {
6931 buffer_handle.update(cx, |buffer, _| {
6932 buffer.push_transaction(transaction.clone(), Instant::now());
6933 buffer.finalize_last_transaction();
6934 });
6935 }
6936 Ok(Some(transaction))
6937 })
6938 } else {
6939 let request_timeout = ProjectSettings::get_global(cx)
6940 .global_lsp_settings
6941 .get_request_timeout();
6942
6943 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6944 let completion = &completions.borrow()[completion_index];
6945 let server_id = completion.source.server_id()?;
6946 Some(
6947 self.language_server_for_local_buffer(buffer, server_id, cx)?
6948 .1
6949 .clone(),
6950 )
6951 }) else {
6952 return Task::ready(Ok(None));
6953 };
6954
6955 cx.spawn(async move |this, cx| {
6956 Self::resolve_completion_local(
6957 server.clone(),
6958 completions.clone(),
6959 completion_index,
6960 request_timeout,
6961 )
6962 .await
6963 .context("resolving completion")?;
6964 let completion = completions.borrow()[completion_index].clone();
6965 let additional_text_edits = completion
6966 .source
6967 .lsp_completion(true)
6968 .as_ref()
6969 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6970 if let Some(edits) = additional_text_edits {
6971 let edits = this
6972 .update(cx, |this, cx| {
6973 this.as_local_mut().unwrap().edits_from_lsp(
6974 &buffer_handle,
6975 edits,
6976 server.server_id(),
6977 None,
6978 cx,
6979 )
6980 })?
6981 .await?;
6982
6983 buffer_handle.update(cx, |buffer, cx| {
6984 buffer.finalize_last_transaction();
6985 buffer.start_transaction();
6986
6987 for (range, text) in edits {
6988 let primary = &completion.replace_range;
6989
6990 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6991 // and the primary completion is just an insertion (empty range), then this is likely
6992 // an auto-import scenario and should not be considered overlapping
6993 // https://github.com/zed-industries/zed/issues/26136
6994 let is_file_start_auto_import = {
6995 let snapshot = buffer.snapshot();
6996 let primary_start_point = primary.start.to_point(&snapshot);
6997 let range_start_point = range.start.to_point(&snapshot);
6998
6999 let result = primary_start_point.row == 0
7000 && primary_start_point.column == 0
7001 && range_start_point.row == 0
7002 && range_start_point.column == 0;
7003
7004 result
7005 };
7006
7007 let has_overlap = if is_file_start_auto_import {
7008 false
7009 } else {
7010 all_commit_ranges.iter().any(|commit_range| {
7011 let start_within =
7012 commit_range.start.cmp(&range.start, buffer).is_le()
7013 && commit_range.end.cmp(&range.start, buffer).is_ge();
7014 let end_within =
7015 range.start.cmp(&commit_range.end, buffer).is_le()
7016 && range.end.cmp(&commit_range.end, buffer).is_ge();
7017 start_within || end_within
7018 })
7019 };
7020
7021 //Skip additional edits which overlap with the primary completion edit
7022 //https://github.com/zed-industries/zed/pull/1871
7023 if !has_overlap {
7024 buffer.edit([(range, text)], None, cx);
7025 }
7026 }
7027
7028 let transaction = if buffer.end_transaction(cx).is_some() {
7029 let transaction = buffer.finalize_last_transaction().unwrap().clone();
7030 if !push_to_history {
7031 buffer.forget_transaction(transaction.id);
7032 }
7033 Some(transaction)
7034 } else {
7035 None
7036 };
7037 Ok(transaction)
7038 })
7039 } else {
7040 Ok(None)
7041 }
7042 })
7043 }
7044 }
7045
7046 pub fn pull_diagnostics(
7047 &mut self,
7048 buffer: Entity<Buffer>,
7049 cx: &mut Context<Self>,
7050 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
7051 let buffer_id = buffer.read(cx).remote_id();
7052
7053 if let Some((client, upstream_project_id)) = self.upstream_client() {
7054 let mut suitable_capabilities = None;
7055 // Are we capable for proto request?
7056 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
7057 &buffer,
7058 |capabilities| {
7059 if let Some(caps) = &capabilities.diagnostic_provider {
7060 suitable_capabilities = Some(caps.clone());
7061 true
7062 } else {
7063 false
7064 }
7065 },
7066 cx,
7067 );
7068 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
7069 let Some(dynamic_caps) = suitable_capabilities else {
7070 return Task::ready(Ok(None));
7071 };
7072 assert!(any_server_has_diagnostics_provider);
7073
7074 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
7075 let request = GetDocumentDiagnostics {
7076 previous_result_id: None,
7077 identifier,
7078 registration_id: None,
7079 };
7080 let request_timeout = ProjectSettings::get_global(cx)
7081 .global_lsp_settings
7082 .get_request_timeout();
7083 let request_task = client.request_lsp(
7084 upstream_project_id,
7085 None,
7086 request_timeout,
7087 cx.background_executor().clone(),
7088 request.to_proto(upstream_project_id, buffer.read(cx)),
7089 );
7090 cx.background_spawn(async move {
7091 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
7092 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
7093 // Do not attempt to further process the dummy responses here.
7094 let _response = request_task.await?;
7095 Ok(None)
7096 })
7097 } else {
7098 let servers = buffer.update(cx, |buffer, cx| {
7099 self.running_language_servers_for_local_buffer(buffer, cx)
7100 .map(|(_, server)| server.clone())
7101 .collect::<Vec<_>>()
7102 });
7103
7104 let pull_diagnostics = servers
7105 .into_iter()
7106 .flat_map(|server| {
7107 let result = maybe!({
7108 let local = self.as_local()?;
7109 let server_id = server.server_id();
7110 let providers_with_identifiers = local
7111 .language_server_dynamic_registrations
7112 .get(&server_id)
7113 .into_iter()
7114 .flat_map(|registrations| registrations.diagnostics.clone())
7115 .collect::<Vec<_>>();
7116 Some(
7117 providers_with_identifiers
7118 .into_iter()
7119 .map(|(registration_id, dynamic_caps)| {
7120 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
7121 let registration_id = registration_id.map(SharedString::from);
7122 let result_id = self.result_id_for_buffer_pull(
7123 server_id,
7124 buffer_id,
7125 ®istration_id,
7126 cx,
7127 );
7128 self.request_lsp(
7129 buffer.clone(),
7130 LanguageServerToQuery::Other(server_id),
7131 GetDocumentDiagnostics {
7132 previous_result_id: result_id,
7133 registration_id,
7134 identifier,
7135 },
7136 cx,
7137 )
7138 })
7139 .collect::<Vec<_>>(),
7140 )
7141 });
7142
7143 result.unwrap_or_default()
7144 })
7145 .collect::<Vec<_>>();
7146
7147 cx.background_spawn(async move {
7148 let mut responses = Vec::new();
7149 for diagnostics in join_all(pull_diagnostics).await {
7150 responses.extend(diagnostics?);
7151 }
7152 Ok(Some(responses))
7153 })
7154 }
7155 }
7156
7157 pub fn applicable_inlay_chunks(
7158 &mut self,
7159 buffer: &Entity<Buffer>,
7160 ranges: &[Range<text::Anchor>],
7161 cx: &mut Context<Self>,
7162 ) -> Vec<Range<BufferRow>> {
7163 let buffer_snapshot = buffer.read(cx).snapshot();
7164 let ranges = ranges
7165 .iter()
7166 .map(|range| range.to_point(&buffer_snapshot))
7167 .collect::<Vec<_>>();
7168
7169 self.latest_lsp_data(buffer, cx)
7170 .inlay_hints
7171 .applicable_chunks(ranges.as_slice())
7172 .map(|chunk| chunk.row_range())
7173 .collect()
7174 }
7175
7176 pub fn invalidate_inlay_hints<'a>(
7177 &'a mut self,
7178 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7179 ) {
7180 for buffer_id in for_buffers {
7181 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7182 lsp_data.inlay_hints.clear();
7183 }
7184 }
7185 }
7186
7187 pub fn inlay_hints(
7188 &mut self,
7189 invalidate: InvalidationStrategy,
7190 buffer: Entity<Buffer>,
7191 ranges: Vec<Range<text::Anchor>>,
7192 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7193 cx: &mut Context<Self>,
7194 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7195 let next_hint_id = self.next_hint_id.clone();
7196 let lsp_data = self.latest_lsp_data(&buffer, cx);
7197 let query_version = lsp_data.buffer_version.clone();
7198 let mut lsp_refresh_requested = false;
7199 let for_server = if let InvalidationStrategy::RefreshRequested {
7200 server_id,
7201 request_id,
7202 } = invalidate
7203 {
7204 let invalidated = lsp_data
7205 .inlay_hints
7206 .invalidate_for_server_refresh(server_id, request_id);
7207 lsp_refresh_requested = invalidated;
7208 Some(server_id)
7209 } else {
7210 None
7211 };
7212 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7213 let known_chunks = known_chunks
7214 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7215 .map(|(_, known_chunks)| known_chunks)
7216 .unwrap_or_default();
7217
7218 let buffer_snapshot = buffer.read(cx).snapshot();
7219 let ranges = ranges
7220 .iter()
7221 .map(|range| range.to_point(&buffer_snapshot))
7222 .collect::<Vec<_>>();
7223
7224 let mut hint_fetch_tasks = Vec::new();
7225 let mut cached_inlay_hints = None;
7226 let mut ranges_to_query = None;
7227 let applicable_chunks = existing_inlay_hints
7228 .applicable_chunks(ranges.as_slice())
7229 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7230 .collect::<Vec<_>>();
7231 if applicable_chunks.is_empty() {
7232 return HashMap::default();
7233 }
7234
7235 for row_chunk in applicable_chunks {
7236 match (
7237 existing_inlay_hints
7238 .cached_hints(&row_chunk)
7239 .filter(|_| !lsp_refresh_requested)
7240 .cloned(),
7241 existing_inlay_hints
7242 .fetched_hints(&row_chunk)
7243 .as_ref()
7244 .filter(|_| !lsp_refresh_requested)
7245 .cloned(),
7246 ) {
7247 (None, None) => {
7248 let chunk_range = row_chunk.anchor_range();
7249 ranges_to_query
7250 .get_or_insert_with(Vec::new)
7251 .push((row_chunk, chunk_range));
7252 }
7253 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7254 (Some(cached_hints), None) => {
7255 for (server_id, cached_hints) in cached_hints {
7256 if for_server.is_none_or(|for_server| for_server == server_id) {
7257 cached_inlay_hints
7258 .get_or_insert_with(HashMap::default)
7259 .entry(row_chunk.row_range())
7260 .or_insert_with(HashMap::default)
7261 .entry(server_id)
7262 .or_insert_with(Vec::new)
7263 .extend(cached_hints);
7264 }
7265 }
7266 }
7267 (Some(cached_hints), Some(fetched_hints)) => {
7268 hint_fetch_tasks.push((row_chunk, fetched_hints));
7269 for (server_id, cached_hints) in cached_hints {
7270 if for_server.is_none_or(|for_server| for_server == server_id) {
7271 cached_inlay_hints
7272 .get_or_insert_with(HashMap::default)
7273 .entry(row_chunk.row_range())
7274 .or_insert_with(HashMap::default)
7275 .entry(server_id)
7276 .or_insert_with(Vec::new)
7277 .extend(cached_hints);
7278 }
7279 }
7280 }
7281 }
7282 }
7283
7284 if hint_fetch_tasks.is_empty()
7285 && ranges_to_query
7286 .as_ref()
7287 .is_none_or(|ranges| ranges.is_empty())
7288 && let Some(cached_inlay_hints) = cached_inlay_hints
7289 {
7290 cached_inlay_hints
7291 .into_iter()
7292 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7293 .collect()
7294 } else {
7295 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7296 // When a server refresh was requested, other servers' cached hints
7297 // are unaffected by the refresh and must be included in the result.
7298 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7299 // removes all visible hints but only adds back the requesting
7300 // server's new hints, permanently losing other servers' hints.
7301 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7302 lsp_data
7303 .inlay_hints
7304 .cached_hints(&chunk)
7305 .cloned()
7306 .unwrap_or_default()
7307 } else {
7308 HashMap::default()
7309 };
7310
7311 let next_hint_id = next_hint_id.clone();
7312 let buffer = buffer.clone();
7313 let query_version = query_version.clone();
7314 let new_inlay_hints = cx
7315 .spawn(async move |lsp_store, cx| {
7316 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7317 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7318 })?;
7319 new_fetch_task
7320 .await
7321 .and_then(|new_hints_by_server| {
7322 lsp_store.update(cx, |lsp_store, cx| {
7323 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7324 let update_cache = lsp_data.buffer_version == query_version;
7325 if new_hints_by_server.is_empty() {
7326 if update_cache {
7327 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7328 }
7329 other_servers_cached
7330 } else {
7331 let mut result = other_servers_cached;
7332 for (server_id, new_hints) in new_hints_by_server {
7333 let new_hints = new_hints
7334 .into_iter()
7335 .map(|new_hint| {
7336 (
7337 InlayId::Hint(next_hint_id.fetch_add(
7338 1,
7339 atomic::Ordering::AcqRel,
7340 )),
7341 new_hint,
7342 )
7343 })
7344 .collect::<Vec<_>>();
7345 if update_cache {
7346 lsp_data.inlay_hints.insert_new_hints(
7347 chunk,
7348 server_id,
7349 new_hints.clone(),
7350 );
7351 }
7352 result.insert(server_id, new_hints);
7353 }
7354 result
7355 }
7356 })
7357 })
7358 .map_err(Arc::new)
7359 })
7360 .shared();
7361
7362 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7363 *fetch_task = Some(new_inlay_hints.clone());
7364 hint_fetch_tasks.push((chunk, new_inlay_hints));
7365 }
7366
7367 cached_inlay_hints
7368 .unwrap_or_default()
7369 .into_iter()
7370 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7371 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7372 (
7373 chunk.row_range(),
7374 cx.spawn(async move |_, _| {
7375 hints_fetch.await.map_err(|e| {
7376 if e.error_code() != ErrorCode::Internal {
7377 anyhow!(e.error_code())
7378 } else {
7379 anyhow!("{e:#}")
7380 }
7381 })
7382 }),
7383 )
7384 }))
7385 .collect()
7386 }
7387 }
7388
7389 fn fetch_inlay_hints(
7390 &mut self,
7391 for_server: Option<LanguageServerId>,
7392 buffer: &Entity<Buffer>,
7393 range: Range<Anchor>,
7394 cx: &mut Context<Self>,
7395 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7396 let request = InlayHints {
7397 range: range.clone(),
7398 };
7399 if let Some((upstream_client, project_id)) = self.upstream_client() {
7400 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7401 return Task::ready(Ok(HashMap::default()));
7402 }
7403 let request_timeout = ProjectSettings::get_global(cx)
7404 .global_lsp_settings
7405 .get_request_timeout();
7406 let request_task = upstream_client.request_lsp(
7407 project_id,
7408 for_server.map(|id| id.to_proto()),
7409 request_timeout,
7410 cx.background_executor().clone(),
7411 request.to_proto(project_id, buffer.read(cx)),
7412 );
7413 let buffer = buffer.clone();
7414 cx.spawn(async move |weak_lsp_store, cx| {
7415 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7416 return Ok(HashMap::default());
7417 };
7418 let Some(responses) = request_task.await? else {
7419 return Ok(HashMap::default());
7420 };
7421
7422 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7423 let lsp_store = lsp_store.clone();
7424 let buffer = buffer.clone();
7425 let cx = cx.clone();
7426 let request = request.clone();
7427 async move {
7428 (
7429 LanguageServerId::from_proto(response.server_id),
7430 request
7431 .response_from_proto(response.response, lsp_store, buffer, cx)
7432 .await,
7433 )
7434 }
7435 }))
7436 .await;
7437
7438 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7439 let mut has_errors = false;
7440 let inlay_hints = inlay_hints
7441 .into_iter()
7442 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7443 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7444 Err(e) => {
7445 has_errors = true;
7446 log::error!("{e:#}");
7447 None
7448 }
7449 })
7450 .map(|(server_id, mut new_hints)| {
7451 new_hints.retain(|hint| {
7452 hint.position.is_valid(&buffer_snapshot)
7453 && range.start.is_valid(&buffer_snapshot)
7454 && range.end.is_valid(&buffer_snapshot)
7455 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7456 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7457 });
7458 (server_id, new_hints)
7459 })
7460 .collect::<HashMap<_, _>>();
7461 anyhow::ensure!(
7462 !has_errors || !inlay_hints.is_empty(),
7463 "Failed to fetch inlay hints"
7464 );
7465 Ok(inlay_hints)
7466 })
7467 } else {
7468 let inlay_hints_task = match for_server {
7469 Some(server_id) => {
7470 let server_task = self.request_lsp(
7471 buffer.clone(),
7472 LanguageServerToQuery::Other(server_id),
7473 request,
7474 cx,
7475 );
7476 cx.background_spawn(async move {
7477 let mut responses = Vec::new();
7478 match server_task.await {
7479 Ok(response) => responses.push((server_id, response)),
7480 // rust-analyzer likes to error with this when its still loading up
7481 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7482 Err(e) => log::error!(
7483 "Error handling response for inlay hints request: {e:#}"
7484 ),
7485 }
7486 responses
7487 })
7488 }
7489 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7490 };
7491 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7492 cx.background_spawn(async move {
7493 Ok(inlay_hints_task
7494 .await
7495 .into_iter()
7496 .map(|(server_id, mut new_hints)| {
7497 new_hints.retain(|hint| {
7498 hint.position.is_valid(&buffer_snapshot)
7499 && range.start.is_valid(&buffer_snapshot)
7500 && range.end.is_valid(&buffer_snapshot)
7501 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7502 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7503 });
7504 (server_id, new_hints)
7505 })
7506 .collect())
7507 })
7508 }
7509 }
7510
7511 fn diagnostic_registration_exists(
7512 &self,
7513 server_id: LanguageServerId,
7514 registration_id: &Option<SharedString>,
7515 ) -> bool {
7516 let Some(local) = self.as_local() else {
7517 return false;
7518 };
7519 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7520 else {
7521 return false;
7522 };
7523 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7524 registrations.diagnostics.contains_key(®istration_key)
7525 }
7526
7527 pub fn pull_diagnostics_for_buffer(
7528 &mut self,
7529 buffer: Entity<Buffer>,
7530 cx: &mut Context<Self>,
7531 ) -> Task<anyhow::Result<()>> {
7532 let diagnostics = self.pull_diagnostics(buffer, cx);
7533 cx.spawn(async move |lsp_store, cx| {
7534 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7535 return Ok(());
7536 };
7537 lsp_store.update(cx, |lsp_store, cx| {
7538 if lsp_store.as_local().is_none() {
7539 return;
7540 }
7541
7542 let mut unchanged_buffers = HashMap::default();
7543 let server_diagnostics_updates = diagnostics
7544 .into_iter()
7545 .filter_map(|diagnostics_set| match diagnostics_set {
7546 LspPullDiagnostics::Response {
7547 server_id,
7548 uri,
7549 diagnostics,
7550 registration_id,
7551 } => Some((server_id, uri, diagnostics, registration_id)),
7552 LspPullDiagnostics::Default => None,
7553 })
7554 .filter(|(server_id, _, _, registration_id)| {
7555 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7556 })
7557 .fold(
7558 HashMap::default(),
7559 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7560 let (result_id, diagnostics) = match diagnostics {
7561 PulledDiagnostics::Unchanged { result_id } => {
7562 unchanged_buffers
7563 .entry(new_registration_id.clone())
7564 .or_insert_with(HashSet::default)
7565 .insert(uri.clone());
7566 (Some(result_id), Vec::new())
7567 }
7568 PulledDiagnostics::Changed {
7569 result_id,
7570 diagnostics,
7571 } => (result_id, diagnostics),
7572 };
7573 let disk_based_sources = Cow::Owned(
7574 lsp_store
7575 .language_server_adapter_for_id(server_id)
7576 .as_ref()
7577 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7578 .unwrap_or(&[])
7579 .to_vec(),
7580 );
7581 acc.entry(server_id)
7582 .or_insert_with(HashMap::default)
7583 .entry(new_registration_id.clone())
7584 .or_insert_with(Vec::new)
7585 .push(DocumentDiagnosticsUpdate {
7586 server_id,
7587 diagnostics: lsp::PublishDiagnosticsParams {
7588 uri,
7589 diagnostics,
7590 version: None,
7591 },
7592 result_id: result_id.map(SharedString::new),
7593 disk_based_sources,
7594 registration_id: new_registration_id,
7595 });
7596 acc
7597 },
7598 );
7599
7600 for diagnostic_updates in server_diagnostics_updates.into_values() {
7601 for (registration_id, diagnostic_updates) in diagnostic_updates {
7602 lsp_store
7603 .merge_lsp_diagnostics(
7604 DiagnosticSourceKind::Pulled,
7605 diagnostic_updates,
7606 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7607 DiagnosticSourceKind::Pulled => {
7608 old_diagnostic.registration_id != registration_id
7609 || unchanged_buffers
7610 .get(&old_diagnostic.registration_id)
7611 .is_some_and(|unchanged_buffers| {
7612 unchanged_buffers.contains(&document_uri)
7613 })
7614 }
7615 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7616 true
7617 }
7618 },
7619 cx,
7620 )
7621 .log_err();
7622 }
7623 }
7624 })
7625 })
7626 }
7627
7628 pub fn signature_help<T: ToPointUtf16>(
7629 &mut self,
7630 buffer: &Entity<Buffer>,
7631 position: T,
7632 cx: &mut Context<Self>,
7633 ) -> Task<Option<Vec<SignatureHelp>>> {
7634 let position = position.to_point_utf16(buffer.read(cx));
7635
7636 if let Some((client, upstream_project_id)) = self.upstream_client() {
7637 let request = GetSignatureHelp { position };
7638 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7639 return Task::ready(None);
7640 }
7641 let request_timeout = ProjectSettings::get_global(cx)
7642 .global_lsp_settings
7643 .get_request_timeout();
7644 let request_task = client.request_lsp(
7645 upstream_project_id,
7646 None,
7647 request_timeout,
7648 cx.background_executor().clone(),
7649 request.to_proto(upstream_project_id, buffer.read(cx)),
7650 );
7651 let buffer = buffer.clone();
7652 cx.spawn(async move |weak_lsp_store, cx| {
7653 let lsp_store = weak_lsp_store.upgrade()?;
7654 let signatures = join_all(
7655 request_task
7656 .await
7657 .log_err()
7658 .flatten()
7659 .map(|response| response.payload)
7660 .unwrap_or_default()
7661 .into_iter()
7662 .map(|response| {
7663 let response = GetSignatureHelp { position }.response_from_proto(
7664 response.response,
7665 lsp_store.clone(),
7666 buffer.clone(),
7667 cx.clone(),
7668 );
7669 async move { response.await.log_err().flatten() }
7670 }),
7671 )
7672 .await
7673 .into_iter()
7674 .flatten()
7675 .collect();
7676 Some(signatures)
7677 })
7678 } else {
7679 let all_actions_task = self.request_multiple_lsp_locally(
7680 buffer,
7681 Some(position),
7682 GetSignatureHelp { position },
7683 cx,
7684 );
7685 cx.background_spawn(async move {
7686 Some(
7687 all_actions_task
7688 .await
7689 .into_iter()
7690 .flat_map(|(_, actions)| actions)
7691 .collect::<Vec<_>>(),
7692 )
7693 })
7694 }
7695 }
7696
7697 pub fn hover(
7698 &mut self,
7699 buffer: &Entity<Buffer>,
7700 position: PointUtf16,
7701 cx: &mut Context<Self>,
7702 ) -> Task<Option<Vec<Hover>>> {
7703 if let Some((client, upstream_project_id)) = self.upstream_client() {
7704 let request = GetHover { position };
7705 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7706 return Task::ready(None);
7707 }
7708 let request_timeout = ProjectSettings::get_global(cx)
7709 .global_lsp_settings
7710 .get_request_timeout();
7711 let request_task = client.request_lsp(
7712 upstream_project_id,
7713 None,
7714 request_timeout,
7715 cx.background_executor().clone(),
7716 request.to_proto(upstream_project_id, buffer.read(cx)),
7717 );
7718 let buffer = buffer.clone();
7719 cx.spawn(async move |weak_lsp_store, cx| {
7720 let lsp_store = weak_lsp_store.upgrade()?;
7721 let hovers = join_all(
7722 request_task
7723 .await
7724 .log_err()
7725 .flatten()
7726 .map(|response| response.payload)
7727 .unwrap_or_default()
7728 .into_iter()
7729 .map(|response| {
7730 let response = GetHover { position }.response_from_proto(
7731 response.response,
7732 lsp_store.clone(),
7733 buffer.clone(),
7734 cx.clone(),
7735 );
7736 async move {
7737 response
7738 .await
7739 .log_err()
7740 .flatten()
7741 .and_then(remove_empty_hover_blocks)
7742 }
7743 }),
7744 )
7745 .await
7746 .into_iter()
7747 .flatten()
7748 .collect();
7749 Some(hovers)
7750 })
7751 } else {
7752 let all_actions_task = self.request_multiple_lsp_locally(
7753 buffer,
7754 Some(position),
7755 GetHover { position },
7756 cx,
7757 );
7758 cx.background_spawn(async move {
7759 Some(
7760 all_actions_task
7761 .await
7762 .into_iter()
7763 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7764 .collect::<Vec<Hover>>(),
7765 )
7766 })
7767 }
7768 }
7769
7770 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7771 let language_registry = self.languages.clone();
7772
7773 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7774 let request = upstream_client.request(proto::GetProjectSymbols {
7775 project_id: *project_id,
7776 query: query.to_string(),
7777 });
7778 cx.foreground_executor().spawn(async move {
7779 let response = request.await?;
7780 let mut symbols = Vec::new();
7781 let core_symbols = response
7782 .symbols
7783 .into_iter()
7784 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7785 .collect::<Vec<_>>();
7786 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7787 .await;
7788 Ok(symbols)
7789 })
7790 } else if let Some(local) = self.as_local() {
7791 struct WorkspaceSymbolsResult {
7792 server_id: LanguageServerId,
7793 lsp_adapter: Arc<CachedLspAdapter>,
7794 worktree: WeakEntity<Worktree>,
7795 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7796 }
7797
7798 let mut requests = Vec::new();
7799 let mut requested_servers = BTreeSet::new();
7800 let request_timeout = ProjectSettings::get_global(cx)
7801 .global_lsp_settings
7802 .get_request_timeout();
7803
7804 for (seed, state) in local.language_server_ids.iter() {
7805 let Some(worktree_handle) = self
7806 .worktree_store
7807 .read(cx)
7808 .worktree_for_id(seed.worktree_id, cx)
7809 else {
7810 continue;
7811 };
7812
7813 let worktree = worktree_handle.read(cx);
7814 if !worktree.is_visible() {
7815 continue;
7816 }
7817
7818 if !requested_servers.insert(state.id) {
7819 continue;
7820 }
7821
7822 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7823 Some(LanguageServerState::Running {
7824 adapter, server, ..
7825 }) => (adapter.clone(), server),
7826
7827 _ => continue,
7828 };
7829
7830 let supports_workspace_symbol_request =
7831 match server.capabilities().workspace_symbol_provider {
7832 Some(OneOf::Left(supported)) => supported,
7833 Some(OneOf::Right(_)) => true,
7834 None => false,
7835 };
7836
7837 if !supports_workspace_symbol_request {
7838 continue;
7839 }
7840
7841 let worktree_handle = worktree_handle.clone();
7842 let server_id = server.server_id();
7843 requests.push(
7844 server
7845 .request::<lsp::request::WorkspaceSymbolRequest>(
7846 lsp::WorkspaceSymbolParams {
7847 query: query.to_string(),
7848 ..Default::default()
7849 },
7850 request_timeout,
7851 )
7852 .map(move |response| {
7853 let lsp_symbols = response
7854 .into_response()
7855 .context("workspace symbols request")
7856 .log_err()
7857 .flatten()
7858 .map(|symbol_response| match symbol_response {
7859 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7860 flat_responses
7861 .into_iter()
7862 .map(|lsp_symbol| {
7863 (
7864 lsp_symbol.name,
7865 lsp_symbol.kind,
7866 lsp_symbol.location,
7867 lsp_symbol.container_name,
7868 )
7869 })
7870 .collect::<Vec<_>>()
7871 }
7872 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7873 nested_responses
7874 .into_iter()
7875 .filter_map(|lsp_symbol| {
7876 let location = match lsp_symbol.location {
7877 OneOf::Left(location) => location,
7878 OneOf::Right(_) => {
7879 log::error!(
7880 "Unexpected: client capabilities \
7881 forbid symbol resolutions in \
7882 workspace.symbol.resolveSupport"
7883 );
7884 return None;
7885 }
7886 };
7887 Some((
7888 lsp_symbol.name,
7889 lsp_symbol.kind,
7890 location,
7891 lsp_symbol.container_name,
7892 ))
7893 })
7894 .collect::<Vec<_>>()
7895 }
7896 })
7897 .unwrap_or_default();
7898
7899 WorkspaceSymbolsResult {
7900 server_id,
7901 lsp_adapter,
7902 worktree: worktree_handle.downgrade(),
7903 lsp_symbols,
7904 }
7905 }),
7906 );
7907 }
7908
7909 cx.spawn(async move |this, cx| {
7910 let responses = futures::future::join_all(requests).await;
7911 let this = match this.upgrade() {
7912 Some(this) => this,
7913 None => return Ok(Vec::new()),
7914 };
7915
7916 let mut symbols = Vec::new();
7917 for result in responses {
7918 let core_symbols = this.update(cx, |this, cx| {
7919 result
7920 .lsp_symbols
7921 .into_iter()
7922 .filter_map(
7923 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7924 let abs_path = symbol_location.uri.to_file_path().ok()?;
7925 let source_worktree = result.worktree.upgrade()?;
7926 let source_worktree_id = source_worktree.read(cx).id();
7927
7928 let path = if let Some((tree, rel_path)) =
7929 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7930 {
7931 let worktree_id = tree.read(cx).id();
7932 SymbolLocation::InProject(ProjectPath {
7933 worktree_id,
7934 path: rel_path,
7935 })
7936 } else {
7937 SymbolLocation::OutsideProject {
7938 signature: this.symbol_signature(&abs_path),
7939 abs_path: abs_path.into(),
7940 }
7941 };
7942
7943 Some(CoreSymbol {
7944 source_language_server_id: result.server_id,
7945 language_server_name: result.lsp_adapter.name.clone(),
7946 source_worktree_id,
7947 path,
7948 kind: symbol_kind,
7949 name: collapse_newlines(&symbol_name, "↵ "),
7950 range: range_from_lsp(symbol_location.range),
7951 container_name: container_name
7952 .map(|c| collapse_newlines(&c, "↵ ")),
7953 })
7954 },
7955 )
7956 .collect::<Vec<_>>()
7957 });
7958
7959 populate_labels_for_symbols(
7960 core_symbols,
7961 &language_registry,
7962 Some(result.lsp_adapter),
7963 &mut symbols,
7964 )
7965 .await;
7966 }
7967
7968 Ok(symbols)
7969 })
7970 } else {
7971 Task::ready(Err(anyhow!("No upstream client or local language server")))
7972 }
7973 }
7974
7975 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7976 let mut summary = DiagnosticSummary::default();
7977 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7978 summary.error_count += path_summary.error_count;
7979 summary.warning_count += path_summary.warning_count;
7980 }
7981 summary
7982 }
7983
7984 /// Returns the diagnostic summary for a specific project path.
7985 pub fn diagnostic_summary_for_path(
7986 &self,
7987 project_path: &ProjectPath,
7988 _: &App,
7989 ) -> DiagnosticSummary {
7990 if let Some(summaries) = self
7991 .diagnostic_summaries
7992 .get(&project_path.worktree_id)
7993 .and_then(|map| map.get(&project_path.path))
7994 {
7995 let (error_count, warning_count) = summaries.iter().fold(
7996 (0, 0),
7997 |(error_count, warning_count), (_language_server_id, summary)| {
7998 (
7999 error_count + summary.error_count,
8000 warning_count + summary.warning_count,
8001 )
8002 },
8003 );
8004
8005 DiagnosticSummary {
8006 error_count,
8007 warning_count,
8008 }
8009 } else {
8010 DiagnosticSummary::default()
8011 }
8012 }
8013
8014 pub fn diagnostic_summaries<'a>(
8015 &'a self,
8016 include_ignored: bool,
8017 cx: &'a App,
8018 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
8019 self.worktree_store
8020 .read(cx)
8021 .visible_worktrees(cx)
8022 .filter_map(|worktree| {
8023 let worktree = worktree.read(cx);
8024 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
8025 })
8026 .flat_map(move |(worktree, summaries)| {
8027 let worktree_id = worktree.id();
8028 summaries
8029 .iter()
8030 .filter(move |(path, _)| {
8031 include_ignored
8032 || worktree
8033 .entry_for_path(path.as_ref())
8034 .is_some_and(|entry| !entry.is_ignored)
8035 })
8036 .flat_map(move |(path, summaries)| {
8037 summaries.iter().map(move |(server_id, summary)| {
8038 (
8039 ProjectPath {
8040 worktree_id,
8041 path: path.clone(),
8042 },
8043 *server_id,
8044 *summary,
8045 )
8046 })
8047 })
8048 })
8049 }
8050
8051 pub fn on_buffer_edited(
8052 &mut self,
8053 buffer: Entity<Buffer>,
8054 cx: &mut Context<Self>,
8055 ) -> Option<()> {
8056 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8057 Some(
8058 self.as_local()?
8059 .language_servers_for_buffer(buffer, cx)
8060 .map(|i| i.1.clone())
8061 .collect(),
8062 )
8063 })?;
8064
8065 let buffer = buffer.read(cx);
8066 let file = File::from_dyn(buffer.file())?;
8067 let abs_path = file.as_local()?.abs_path(cx);
8068 let uri = lsp::Uri::from_file_path(&abs_path)
8069 .ok()
8070 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8071 .log_err()?;
8072 let next_snapshot = buffer.text_snapshot();
8073 for language_server in language_servers {
8074 let language_server = language_server.clone();
8075
8076 let buffer_snapshots = self
8077 .as_local_mut()?
8078 .buffer_snapshots
8079 .get_mut(&buffer.remote_id())
8080 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8081 let previous_snapshot = buffer_snapshots.last()?;
8082
8083 let build_incremental_change = || {
8084 buffer
8085 .edits_since::<Dimensions<PointUtf16, usize>>(
8086 previous_snapshot.snapshot.version(),
8087 )
8088 .map(|edit| {
8089 let edit_start = edit.new.start.0;
8090 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8091 let new_text = next_snapshot
8092 .text_for_range(edit.new.start.1..edit.new.end.1)
8093 .collect();
8094 lsp::TextDocumentContentChangeEvent {
8095 range: Some(lsp::Range::new(
8096 point_to_lsp(edit_start),
8097 point_to_lsp(edit_end),
8098 )),
8099 range_length: None,
8100 text: new_text,
8101 }
8102 })
8103 .collect()
8104 };
8105
8106 let document_sync_kind = language_server
8107 .capabilities()
8108 .text_document_sync
8109 .as_ref()
8110 .and_then(|sync| match sync {
8111 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8112 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8113 });
8114
8115 let content_changes: Vec<_> = match document_sync_kind {
8116 Some(lsp::TextDocumentSyncKind::FULL) => {
8117 vec![lsp::TextDocumentContentChangeEvent {
8118 range: None,
8119 range_length: None,
8120 text: next_snapshot.text(),
8121 }]
8122 }
8123 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8124 _ => {
8125 #[cfg(any(test, feature = "test-support"))]
8126 {
8127 build_incremental_change()
8128 }
8129
8130 #[cfg(not(any(test, feature = "test-support")))]
8131 {
8132 continue;
8133 }
8134 }
8135 };
8136
8137 let next_version = previous_snapshot.version + 1;
8138 buffer_snapshots.push(LspBufferSnapshot {
8139 version: next_version,
8140 snapshot: next_snapshot.clone(),
8141 });
8142
8143 language_server
8144 .notify::<lsp::notification::DidChangeTextDocument>(
8145 lsp::DidChangeTextDocumentParams {
8146 text_document: lsp::VersionedTextDocumentIdentifier::new(
8147 uri.clone(),
8148 next_version,
8149 ),
8150 content_changes,
8151 },
8152 )
8153 .ok();
8154 self.pull_workspace_diagnostics(language_server.server_id());
8155 }
8156
8157 None
8158 }
8159
8160 pub fn on_buffer_saved(
8161 &mut self,
8162 buffer: Entity<Buffer>,
8163 cx: &mut Context<Self>,
8164 ) -> Option<()> {
8165 let file = File::from_dyn(buffer.read(cx).file())?;
8166 let worktree_id = file.worktree_id(cx);
8167 let abs_path = file.as_local()?.abs_path(cx);
8168 let text_document = lsp::TextDocumentIdentifier {
8169 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8170 };
8171 let local = self.as_local()?;
8172
8173 for server in local.language_servers_for_worktree(worktree_id) {
8174 if let Some(include_text) = include_text(server.as_ref()) {
8175 let text = if include_text {
8176 Some(buffer.read(cx).text())
8177 } else {
8178 None
8179 };
8180 server
8181 .notify::<lsp::notification::DidSaveTextDocument>(
8182 lsp::DidSaveTextDocumentParams {
8183 text_document: text_document.clone(),
8184 text,
8185 },
8186 )
8187 .ok();
8188 }
8189 }
8190
8191 let language_servers = buffer.update(cx, |buffer, cx| {
8192 local.language_server_ids_for_buffer(buffer, cx)
8193 });
8194 for language_server_id in language_servers {
8195 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8196 }
8197
8198 None
8199 }
8200
8201 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8202 maybe!(async move {
8203 let mut refreshed_servers = HashSet::default();
8204 let servers = lsp_store
8205 .update(cx, |lsp_store, cx| {
8206 let local = lsp_store.as_local()?;
8207
8208 let servers = local
8209 .language_server_ids
8210 .iter()
8211 .filter_map(|(seed, state)| {
8212 let worktree = lsp_store
8213 .worktree_store
8214 .read(cx)
8215 .worktree_for_id(seed.worktree_id, cx);
8216 let delegate: Arc<dyn LspAdapterDelegate> =
8217 worktree.map(|worktree| {
8218 LocalLspAdapterDelegate::new(
8219 local.languages.clone(),
8220 &local.environment,
8221 cx.weak_entity(),
8222 &worktree,
8223 local.http_client.clone(),
8224 local.fs.clone(),
8225 cx,
8226 )
8227 })?;
8228 let server_id = state.id;
8229
8230 let states = local.language_servers.get(&server_id)?;
8231
8232 match states {
8233 LanguageServerState::Starting { .. } => None,
8234 LanguageServerState::Running {
8235 adapter, server, ..
8236 } => {
8237 let adapter = adapter.clone();
8238 let server = server.clone();
8239 refreshed_servers.insert(server.name());
8240 let toolchain = seed.toolchain.clone();
8241 Some(cx.spawn(async move |_, cx| {
8242 let settings =
8243 LocalLspStore::workspace_configuration_for_adapter(
8244 adapter.adapter.clone(),
8245 &delegate,
8246 toolchain,
8247 None,
8248 cx,
8249 )
8250 .await
8251 .ok()?;
8252 server
8253 .notify::<lsp::notification::DidChangeConfiguration>(
8254 lsp::DidChangeConfigurationParams { settings },
8255 )
8256 .ok()?;
8257 Some(())
8258 }))
8259 }
8260 }
8261 })
8262 .collect::<Vec<_>>();
8263
8264 Some(servers)
8265 })
8266 .ok()
8267 .flatten()?;
8268
8269 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8270 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8271 // to stop and unregister its language server wrapper.
8272 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8273 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8274 let _: Vec<Option<()>> = join_all(servers).await;
8275
8276 Some(())
8277 })
8278 .await;
8279 }
8280
8281 fn maintain_workspace_config(
8282 external_refresh_requests: watch::Receiver<()>,
8283 cx: &mut Context<Self>,
8284 ) -> Task<Result<()>> {
8285 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8286 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8287
8288 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8289 *settings_changed_tx.borrow_mut() = ();
8290 });
8291
8292 let mut joint_future =
8293 futures::stream::select(settings_changed_rx, external_refresh_requests);
8294 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8295 // - 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).
8296 // - 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.
8297 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8298 // - 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,
8299 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8300 cx.spawn(async move |this, cx| {
8301 while let Some(()) = joint_future.next().await {
8302 this.update(cx, |this, cx| {
8303 this.refresh_server_tree(cx);
8304 })
8305 .ok();
8306
8307 Self::refresh_workspace_configurations(&this, cx).await;
8308 }
8309
8310 drop(settings_observation);
8311 anyhow::Ok(())
8312 })
8313 }
8314
8315 pub fn running_language_servers_for_local_buffer<'a>(
8316 &'a self,
8317 buffer: &Buffer,
8318 cx: &mut App,
8319 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8320 let local = self.as_local();
8321 let language_server_ids = local
8322 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8323 .unwrap_or_default();
8324
8325 language_server_ids
8326 .into_iter()
8327 .filter_map(
8328 move |server_id| match local?.language_servers.get(&server_id)? {
8329 LanguageServerState::Running {
8330 adapter, server, ..
8331 } => Some((adapter, server)),
8332 _ => None,
8333 },
8334 )
8335 }
8336
8337 pub fn language_servers_for_local_buffer(
8338 &self,
8339 buffer: &Buffer,
8340 cx: &mut App,
8341 ) -> Vec<LanguageServerId> {
8342 let local = self.as_local();
8343 local
8344 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8345 .unwrap_or_default()
8346 }
8347
8348 pub fn language_server_for_local_buffer<'a>(
8349 &'a self,
8350 buffer: &'a Buffer,
8351 server_id: LanguageServerId,
8352 cx: &'a mut App,
8353 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8354 self.as_local()?
8355 .language_servers_for_buffer(buffer, cx)
8356 .find(|(_, s)| s.server_id() == server_id)
8357 }
8358
8359 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8360 self.diagnostic_summaries.remove(&id_to_remove);
8361 if let Some(local) = self.as_local_mut() {
8362 let to_remove = local.remove_worktree(id_to_remove, cx);
8363 for server in to_remove {
8364 self.language_server_statuses.remove(&server);
8365 }
8366 }
8367 }
8368
8369 fn invalidate_diagnostic_summaries_for_removed_entries(
8370 &mut self,
8371 worktree_id: WorktreeId,
8372 changes: &UpdatedEntriesSet,
8373 cx: &mut Context<Self>,
8374 ) {
8375 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8376 return;
8377 };
8378
8379 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8380 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8381 let downstream = self.downstream_client.clone();
8382
8383 for (path, _, _) in changes
8384 .iter()
8385 .filter(|(_, _, change)| *change == PathChange::Removed)
8386 {
8387 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8388 for (server_id, _) in &summaries_by_server_id {
8389 cleared_server_ids.insert(*server_id);
8390 if let Some((client, project_id)) = &downstream {
8391 client
8392 .send(proto::UpdateDiagnosticSummary {
8393 project_id: *project_id,
8394 worktree_id: worktree_id.to_proto(),
8395 summary: Some(proto::DiagnosticSummary {
8396 path: path.as_ref().to_proto(),
8397 language_server_id: server_id.0 as u64,
8398 error_count: 0,
8399 warning_count: 0,
8400 }),
8401 more_summaries: Vec::new(),
8402 })
8403 .ok();
8404 }
8405 }
8406 cleared_paths.push(ProjectPath {
8407 worktree_id,
8408 path: path.clone(),
8409 });
8410 }
8411 }
8412
8413 if !cleared_paths.is_empty() {
8414 for server_id in cleared_server_ids {
8415 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8416 server_id,
8417 paths: cleared_paths.clone(),
8418 });
8419 }
8420 }
8421 }
8422
8423 pub fn shared(
8424 &mut self,
8425 project_id: u64,
8426 downstream_client: AnyProtoClient,
8427 _: &mut Context<Self>,
8428 ) {
8429 self.downstream_client = Some((downstream_client.clone(), project_id));
8430
8431 for (server_id, status) in &self.language_server_statuses {
8432 if let Some(server) = self.language_server_for_id(*server_id) {
8433 downstream_client
8434 .send(proto::StartLanguageServer {
8435 project_id,
8436 server: Some(proto::LanguageServer {
8437 id: server_id.to_proto(),
8438 name: status.name.to_string(),
8439 worktree_id: status.worktree.map(|id| id.to_proto()),
8440 }),
8441 capabilities: serde_json::to_string(&server.capabilities())
8442 .expect("serializing server LSP capabilities"),
8443 })
8444 .log_err();
8445 }
8446 }
8447 }
8448
8449 pub fn disconnected_from_host(&mut self) {
8450 self.downstream_client.take();
8451 }
8452
8453 pub fn disconnected_from_ssh_remote(&mut self) {
8454 if let LspStoreMode::Remote(RemoteLspStore {
8455 upstream_client, ..
8456 }) = &mut self.mode
8457 {
8458 upstream_client.take();
8459 }
8460 }
8461
8462 pub(crate) fn set_language_server_statuses_from_proto(
8463 &mut self,
8464 project: WeakEntity<Project>,
8465 language_servers: Vec<proto::LanguageServer>,
8466 server_capabilities: Vec<String>,
8467 cx: &mut Context<Self>,
8468 ) {
8469 let lsp_logs = cx
8470 .try_global::<GlobalLogStore>()
8471 .map(|lsp_store| lsp_store.0.clone());
8472
8473 self.language_server_statuses = language_servers
8474 .into_iter()
8475 .zip(server_capabilities)
8476 .map(|(server, server_capabilities)| {
8477 let server_id = LanguageServerId(server.id as usize);
8478 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8479 self.lsp_server_capabilities
8480 .insert(server_id, server_capabilities);
8481 }
8482
8483 let name = LanguageServerName::from_proto(server.name);
8484 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8485
8486 if let Some(lsp_logs) = &lsp_logs {
8487 lsp_logs.update(cx, |lsp_logs, cx| {
8488 lsp_logs.add_language_server(
8489 // Only remote clients get their language servers set from proto
8490 LanguageServerKind::Remote {
8491 project: project.clone(),
8492 },
8493 server_id,
8494 Some(name.clone()),
8495 worktree,
8496 None,
8497 cx,
8498 );
8499 });
8500 }
8501
8502 (
8503 server_id,
8504 LanguageServerStatus {
8505 name,
8506 server_version: None,
8507 server_readable_version: None,
8508 pending_work: Default::default(),
8509 has_pending_diagnostic_updates: false,
8510 progress_tokens: Default::default(),
8511 worktree,
8512 binary: None,
8513 configuration: None,
8514 workspace_folders: BTreeSet::new(),
8515 process_id: None,
8516 },
8517 )
8518 })
8519 .collect();
8520 }
8521
8522 #[cfg(feature = "test-support")]
8523 pub fn update_diagnostic_entries(
8524 &mut self,
8525 server_id: LanguageServerId,
8526 abs_path: PathBuf,
8527 result_id: Option<SharedString>,
8528 version: Option<i32>,
8529 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8530 cx: &mut Context<Self>,
8531 ) -> anyhow::Result<()> {
8532 self.merge_diagnostic_entries(
8533 vec![DocumentDiagnosticsUpdate {
8534 diagnostics: DocumentDiagnostics {
8535 diagnostics,
8536 document_abs_path: abs_path,
8537 version,
8538 },
8539 result_id,
8540 server_id,
8541 disk_based_sources: Cow::Borrowed(&[]),
8542 registration_id: None,
8543 }],
8544 |_, _, _| false,
8545 cx,
8546 )?;
8547 Ok(())
8548 }
8549
8550 pub fn merge_diagnostic_entries<'a>(
8551 &mut self,
8552 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8553 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8554 cx: &mut Context<Self>,
8555 ) -> anyhow::Result<()> {
8556 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8557 let mut updated_diagnostics_paths = HashMap::default();
8558 for mut update in diagnostic_updates {
8559 let abs_path = &update.diagnostics.document_abs_path;
8560 let server_id = update.server_id;
8561 let Some((worktree, relative_path)) =
8562 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8563 else {
8564 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8565 return Ok(());
8566 };
8567
8568 let worktree_id = worktree.read(cx).id();
8569 let project_path = ProjectPath {
8570 worktree_id,
8571 path: relative_path,
8572 };
8573
8574 let document_uri = lsp::Uri::from_file_path(abs_path)
8575 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8576 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8577 let snapshot = buffer_handle.read(cx).snapshot();
8578 let buffer = buffer_handle.read(cx);
8579 let reused_diagnostics = buffer
8580 .buffer_diagnostics(Some(server_id))
8581 .iter()
8582 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8583 .map(|v| {
8584 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8585 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8586 DiagnosticEntry {
8587 range: start..end,
8588 diagnostic: v.diagnostic.clone(),
8589 }
8590 })
8591 .collect::<Vec<_>>();
8592
8593 self.as_local_mut()
8594 .context("cannot merge diagnostics on a remote LspStore")?
8595 .update_buffer_diagnostics(
8596 &buffer_handle,
8597 server_id,
8598 Some(update.registration_id),
8599 update.result_id,
8600 update.diagnostics.version,
8601 update.diagnostics.diagnostics.clone(),
8602 reused_diagnostics.clone(),
8603 cx,
8604 )?;
8605
8606 update.diagnostics.diagnostics.extend(reused_diagnostics);
8607 } else if let Some(local) = self.as_local() {
8608 let reused_diagnostics = local
8609 .diagnostics
8610 .get(&worktree_id)
8611 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8612 .and_then(|diagnostics_by_server_id| {
8613 diagnostics_by_server_id
8614 .binary_search_by_key(&server_id, |e| e.0)
8615 .ok()
8616 .map(|ix| &diagnostics_by_server_id[ix].1)
8617 })
8618 .into_iter()
8619 .flatten()
8620 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8621
8622 update
8623 .diagnostics
8624 .diagnostics
8625 .extend(reused_diagnostics.cloned());
8626 }
8627
8628 let updated = worktree.update(cx, |worktree, cx| {
8629 self.update_worktree_diagnostics(
8630 worktree.id(),
8631 server_id,
8632 project_path.path.clone(),
8633 update.diagnostics.diagnostics,
8634 cx,
8635 )
8636 })?;
8637 match updated {
8638 ControlFlow::Continue(new_summary) => {
8639 if let Some((project_id, new_summary)) = new_summary {
8640 match &mut diagnostics_summary {
8641 Some(diagnostics_summary) => {
8642 diagnostics_summary
8643 .more_summaries
8644 .push(proto::DiagnosticSummary {
8645 path: project_path.path.as_ref().to_proto(),
8646 language_server_id: server_id.0 as u64,
8647 error_count: new_summary.error_count,
8648 warning_count: new_summary.warning_count,
8649 })
8650 }
8651 None => {
8652 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8653 project_id,
8654 worktree_id: worktree_id.to_proto(),
8655 summary: Some(proto::DiagnosticSummary {
8656 path: project_path.path.as_ref().to_proto(),
8657 language_server_id: server_id.0 as u64,
8658 error_count: new_summary.error_count,
8659 warning_count: new_summary.warning_count,
8660 }),
8661 more_summaries: Vec::new(),
8662 })
8663 }
8664 }
8665 }
8666 updated_diagnostics_paths
8667 .entry(server_id)
8668 .or_insert_with(Vec::new)
8669 .push(project_path);
8670 }
8671 ControlFlow::Break(()) => {}
8672 }
8673 }
8674
8675 if let Some((diagnostics_summary, (downstream_client, _))) =
8676 diagnostics_summary.zip(self.downstream_client.as_ref())
8677 {
8678 downstream_client.send(diagnostics_summary).log_err();
8679 }
8680 for (server_id, paths) in updated_diagnostics_paths {
8681 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8682 }
8683 Ok(())
8684 }
8685
8686 fn update_worktree_diagnostics(
8687 &mut self,
8688 worktree_id: WorktreeId,
8689 server_id: LanguageServerId,
8690 path_in_worktree: Arc<RelPath>,
8691 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8692 _: &mut Context<Worktree>,
8693 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8694 let local = match &mut self.mode {
8695 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8696 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8697 };
8698
8699 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8700 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8701 let summaries_by_server_id = summaries_for_tree
8702 .entry(path_in_worktree.clone())
8703 .or_default();
8704
8705 let old_summary = summaries_by_server_id
8706 .remove(&server_id)
8707 .unwrap_or_default();
8708
8709 let new_summary = DiagnosticSummary::new(&diagnostics);
8710 if diagnostics.is_empty() {
8711 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8712 {
8713 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8714 diagnostics_by_server_id.remove(ix);
8715 }
8716 if diagnostics_by_server_id.is_empty() {
8717 diagnostics_for_tree.remove(&path_in_worktree);
8718 }
8719 }
8720 } else {
8721 summaries_by_server_id.insert(server_id, new_summary);
8722 let diagnostics_by_server_id = diagnostics_for_tree
8723 .entry(path_in_worktree.clone())
8724 .or_default();
8725 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8726 Ok(ix) => {
8727 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8728 }
8729 Err(ix) => {
8730 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8731 }
8732 }
8733 }
8734
8735 if !old_summary.is_empty() || !new_summary.is_empty() {
8736 if let Some((_, project_id)) = &self.downstream_client {
8737 Ok(ControlFlow::Continue(Some((
8738 *project_id,
8739 proto::DiagnosticSummary {
8740 path: path_in_worktree.to_proto(),
8741 language_server_id: server_id.0 as u64,
8742 error_count: new_summary.error_count as u32,
8743 warning_count: new_summary.warning_count as u32,
8744 },
8745 ))))
8746 } else {
8747 Ok(ControlFlow::Continue(None))
8748 }
8749 } else {
8750 Ok(ControlFlow::Break(()))
8751 }
8752 }
8753
8754 pub fn open_buffer_for_symbol(
8755 &mut self,
8756 symbol: &Symbol,
8757 cx: &mut Context<Self>,
8758 ) -> Task<Result<Entity<Buffer>>> {
8759 if let Some((client, project_id)) = self.upstream_client() {
8760 let request = client.request(proto::OpenBufferForSymbol {
8761 project_id,
8762 symbol: Some(Self::serialize_symbol(symbol)),
8763 });
8764 cx.spawn(async move |this, cx| {
8765 let response = request.await?;
8766 let buffer_id = BufferId::new(response.buffer_id)?;
8767 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8768 .await
8769 })
8770 } else if let Some(local) = self.as_local() {
8771 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8772 seed.worktree_id == symbol.source_worktree_id
8773 && state.id == symbol.source_language_server_id
8774 && symbol.language_server_name == seed.name
8775 });
8776 if !is_valid {
8777 return Task::ready(Err(anyhow!(
8778 "language server for worktree and language not found"
8779 )));
8780 };
8781
8782 let symbol_abs_path = match &symbol.path {
8783 SymbolLocation::InProject(project_path) => self
8784 .worktree_store
8785 .read(cx)
8786 .absolutize(&project_path, cx)
8787 .context("no such worktree"),
8788 SymbolLocation::OutsideProject {
8789 abs_path,
8790 signature: _,
8791 } => Ok(abs_path.to_path_buf()),
8792 };
8793 let symbol_abs_path = match symbol_abs_path {
8794 Ok(abs_path) => abs_path,
8795 Err(err) => return Task::ready(Err(err)),
8796 };
8797 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8798 uri
8799 } else {
8800 return Task::ready(Err(anyhow!("invalid symbol path")));
8801 };
8802
8803 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8804 } else {
8805 Task::ready(Err(anyhow!("no upstream client or local store")))
8806 }
8807 }
8808
8809 pub(crate) fn open_local_buffer_via_lsp(
8810 &mut self,
8811 abs_path: lsp::Uri,
8812 language_server_id: LanguageServerId,
8813 cx: &mut Context<Self>,
8814 ) -> Task<Result<Entity<Buffer>>> {
8815 let path_style = self.worktree_store.read(cx).path_style();
8816 cx.spawn(async move |lsp_store, cx| {
8817 // Escape percent-encoded string.
8818 let current_scheme = abs_path.scheme().to_owned();
8819 // Uri is immutable, so we can't modify the scheme
8820
8821 let abs_path = abs_path
8822 .to_file_path_ext(path_style)
8823 .map_err(|()| anyhow!("can't convert URI to path"))?;
8824 let p = abs_path.clone();
8825 let yarn_worktree = lsp_store
8826 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8827 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8828 cx.spawn(async move |this, cx| {
8829 let t = this
8830 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8831 .ok()?;
8832 t.await
8833 })
8834 }),
8835 None => Task::ready(None),
8836 })?
8837 .await;
8838 let (worktree_root_target, known_relative_path) =
8839 if let Some((zip_root, relative_path)) = yarn_worktree {
8840 (zip_root, Some(relative_path))
8841 } else {
8842 (Arc::<Path>::from(abs_path.as_path()), None)
8843 };
8844 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8845 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8846 worktree_store.find_worktree(&worktree_root_target, cx)
8847 })
8848 })?;
8849 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8850 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8851 (result.0, relative_path, None)
8852 } else {
8853 let worktree = lsp_store
8854 .update(cx, |lsp_store, cx| {
8855 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8856 worktree_store.create_worktree(&worktree_root_target, false, cx)
8857 })
8858 })?
8859 .await?;
8860 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8861 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8862 lsp_store
8863 .update(cx, |lsp_store, cx| {
8864 if let Some(local) = lsp_store.as_local_mut() {
8865 local.register_language_server_for_invisible_worktree(
8866 &worktree,
8867 language_server_id,
8868 cx,
8869 )
8870 }
8871 match lsp_store.language_server_statuses.get(&language_server_id) {
8872 Some(status) => status.worktree,
8873 None => None,
8874 }
8875 })
8876 .ok()
8877 .flatten()
8878 .zip(Some(worktree_root.clone()))
8879 } else {
8880 None
8881 };
8882 let relative_path = if let Some(known_path) = known_relative_path {
8883 known_path
8884 } else {
8885 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8886 .into_arc()
8887 };
8888 (worktree, relative_path, source_ws)
8889 };
8890 let project_path = ProjectPath {
8891 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8892 path: relative_path,
8893 };
8894 let buffer = lsp_store
8895 .update(cx, |lsp_store, cx| {
8896 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8897 buffer_store.open_buffer(project_path, cx)
8898 })
8899 })?
8900 .await?;
8901 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8902 if let Some((source_ws, worktree_root)) = source_ws {
8903 buffer.update(cx, |buffer, cx| {
8904 let settings = WorktreeSettings::get(
8905 Some(
8906 (&ProjectPath {
8907 worktree_id: source_ws,
8908 path: Arc::from(RelPath::empty()),
8909 })
8910 .into(),
8911 ),
8912 cx,
8913 );
8914 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8915 if is_read_only {
8916 buffer.set_capability(Capability::ReadOnly, cx);
8917 }
8918 });
8919 }
8920 Ok(buffer)
8921 })
8922 }
8923
8924 fn local_lsp_servers_for_buffer(
8925 &self,
8926 buffer: &Entity<Buffer>,
8927 cx: &mut Context<Self>,
8928 ) -> Vec<LanguageServerId> {
8929 let Some(local) = self.as_local() else {
8930 return Vec::new();
8931 };
8932
8933 let snapshot = buffer.read(cx).snapshot();
8934
8935 buffer.update(cx, |buffer, cx| {
8936 local
8937 .language_servers_for_buffer(buffer, cx)
8938 .map(|(_, server)| server.server_id())
8939 .filter(|server_id| {
8940 self.as_local().is_none_or(|local| {
8941 local
8942 .buffers_opened_in_servers
8943 .get(&snapshot.remote_id())
8944 .is_some_and(|servers| servers.contains(server_id))
8945 })
8946 })
8947 .collect()
8948 })
8949 }
8950
8951 fn request_multiple_lsp_locally<P, R>(
8952 &mut self,
8953 buffer: &Entity<Buffer>,
8954 position: Option<P>,
8955 request: R,
8956 cx: &mut Context<Self>,
8957 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8958 where
8959 P: ToOffset,
8960 R: LspCommand + Clone,
8961 <R::LspRequest as lsp::request::Request>::Result: Send,
8962 <R::LspRequest as lsp::request::Request>::Params: Send,
8963 {
8964 let Some(local) = self.as_local() else {
8965 return Task::ready(Vec::new());
8966 };
8967
8968 let snapshot = buffer.read(cx).snapshot();
8969 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8970
8971 let server_ids = buffer.update(cx, |buffer, cx| {
8972 local
8973 .language_servers_for_buffer(buffer, cx)
8974 .filter(|(adapter, _)| {
8975 scope
8976 .as_ref()
8977 .map(|scope| scope.language_allowed(&adapter.name))
8978 .unwrap_or(true)
8979 })
8980 .map(|(_, server)| server.server_id())
8981 .filter(|server_id| {
8982 self.as_local().is_none_or(|local| {
8983 local
8984 .buffers_opened_in_servers
8985 .get(&snapshot.remote_id())
8986 .is_some_and(|servers| servers.contains(server_id))
8987 })
8988 })
8989 .collect::<Vec<_>>()
8990 });
8991
8992 let mut response_results = server_ids
8993 .into_iter()
8994 .map(|server_id| {
8995 let task = self.request_lsp(
8996 buffer.clone(),
8997 LanguageServerToQuery::Other(server_id),
8998 request.clone(),
8999 cx,
9000 );
9001 async move { (server_id, task.await) }
9002 })
9003 .collect::<FuturesUnordered<_>>();
9004
9005 cx.background_spawn(async move {
9006 let mut responses = Vec::with_capacity(response_results.len());
9007 while let Some((server_id, response_result)) = response_results.next().await {
9008 match response_result {
9009 Ok(response) => responses.push((server_id, response)),
9010 // rust-analyzer likes to error with this when its still loading up
9011 Err(e) if format!("{e:#}").ends_with("content modified") => (),
9012 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
9013 }
9014 }
9015 responses
9016 })
9017 }
9018
9019 async fn handle_lsp_get_completions(
9020 this: Entity<Self>,
9021 envelope: TypedEnvelope<proto::GetCompletions>,
9022 mut cx: AsyncApp,
9023 ) -> Result<proto::GetCompletionsResponse> {
9024 let sender_id = envelope.original_sender_id().unwrap_or_default();
9025
9026 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
9027 let buffer_handle = this.update(&mut cx, |this, cx| {
9028 this.buffer_store.read(cx).get_existing(buffer_id)
9029 })?;
9030 let request = GetCompletions::from_proto(
9031 envelope.payload,
9032 this.clone(),
9033 buffer_handle.clone(),
9034 cx.clone(),
9035 )
9036 .await?;
9037
9038 let server_to_query = match request.server_id {
9039 Some(server_id) => LanguageServerToQuery::Other(server_id),
9040 None => LanguageServerToQuery::FirstCapable,
9041 };
9042
9043 let response = this
9044 .update(&mut cx, |this, cx| {
9045 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
9046 })
9047 .await?;
9048 this.update(&mut cx, |this, cx| {
9049 Ok(GetCompletions::response_to_proto(
9050 response,
9051 this,
9052 sender_id,
9053 &buffer_handle.read(cx).version(),
9054 cx,
9055 ))
9056 })
9057 }
9058
9059 async fn handle_lsp_command<T: LspCommand>(
9060 this: Entity<Self>,
9061 envelope: TypedEnvelope<T::ProtoRequest>,
9062 mut cx: AsyncApp,
9063 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
9064 where
9065 <T::LspRequest as lsp::request::Request>::Params: Send,
9066 <T::LspRequest as lsp::request::Request>::Result: Send,
9067 {
9068 let sender_id = envelope.original_sender_id().unwrap_or_default();
9069 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
9070 let buffer_handle = this.update(&mut cx, |this, cx| {
9071 this.buffer_store.read(cx).get_existing(buffer_id)
9072 })?;
9073 let request = T::from_proto(
9074 envelope.payload,
9075 this.clone(),
9076 buffer_handle.clone(),
9077 cx.clone(),
9078 )
9079 .await?;
9080 let response = this
9081 .update(&mut cx, |this, cx| {
9082 this.request_lsp(
9083 buffer_handle.clone(),
9084 LanguageServerToQuery::FirstCapable,
9085 request,
9086 cx,
9087 )
9088 })
9089 .await?;
9090 this.update(&mut cx, |this, cx| {
9091 Ok(T::response_to_proto(
9092 response,
9093 this,
9094 sender_id,
9095 &buffer_handle.read(cx).version(),
9096 cx,
9097 ))
9098 })
9099 }
9100
9101 async fn handle_lsp_query(
9102 lsp_store: Entity<Self>,
9103 envelope: TypedEnvelope<proto::LspQuery>,
9104 mut cx: AsyncApp,
9105 ) -> Result<proto::Ack> {
9106 use proto::lsp_query::Request;
9107 let sender_id = envelope.original_sender_id().unwrap_or_default();
9108 let lsp_query = envelope.payload;
9109 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
9110 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
9111 match lsp_query.request.context("invalid LSP query request")? {
9112 Request::GetReferences(get_references) => {
9113 let position = get_references.position.clone().and_then(deserialize_anchor);
9114 Self::query_lsp_locally::<GetReferences>(
9115 lsp_store,
9116 server_id,
9117 sender_id,
9118 lsp_request_id,
9119 get_references,
9120 position,
9121 &mut cx,
9122 )
9123 .await?;
9124 }
9125 Request::GetDocumentColor(get_document_color) => {
9126 Self::query_lsp_locally::<GetDocumentColor>(
9127 lsp_store,
9128 server_id,
9129 sender_id,
9130 lsp_request_id,
9131 get_document_color,
9132 None,
9133 &mut cx,
9134 )
9135 .await?;
9136 }
9137 Request::GetFoldingRanges(get_folding_ranges) => {
9138 Self::query_lsp_locally::<GetFoldingRanges>(
9139 lsp_store,
9140 server_id,
9141 sender_id,
9142 lsp_request_id,
9143 get_folding_ranges,
9144 None,
9145 &mut cx,
9146 )
9147 .await?;
9148 }
9149 Request::GetDocumentSymbols(get_document_symbols) => {
9150 Self::query_lsp_locally::<GetDocumentSymbols>(
9151 lsp_store,
9152 server_id,
9153 sender_id,
9154 lsp_request_id,
9155 get_document_symbols,
9156 None,
9157 &mut cx,
9158 )
9159 .await?;
9160 }
9161 Request::GetHover(get_hover) => {
9162 let position = get_hover.position.clone().and_then(deserialize_anchor);
9163 Self::query_lsp_locally::<GetHover>(
9164 lsp_store,
9165 server_id,
9166 sender_id,
9167 lsp_request_id,
9168 get_hover,
9169 position,
9170 &mut cx,
9171 )
9172 .await?;
9173 }
9174 Request::GetCodeActions(get_code_actions) => {
9175 Self::query_lsp_locally::<GetCodeActions>(
9176 lsp_store,
9177 server_id,
9178 sender_id,
9179 lsp_request_id,
9180 get_code_actions,
9181 None,
9182 &mut cx,
9183 )
9184 .await?;
9185 }
9186 Request::GetSignatureHelp(get_signature_help) => {
9187 let position = get_signature_help
9188 .position
9189 .clone()
9190 .and_then(deserialize_anchor);
9191 Self::query_lsp_locally::<GetSignatureHelp>(
9192 lsp_store,
9193 server_id,
9194 sender_id,
9195 lsp_request_id,
9196 get_signature_help,
9197 position,
9198 &mut cx,
9199 )
9200 .await?;
9201 }
9202 Request::GetCodeLens(get_code_lens) => {
9203 Self::query_lsp_locally::<GetCodeLens>(
9204 lsp_store,
9205 server_id,
9206 sender_id,
9207 lsp_request_id,
9208 get_code_lens,
9209 None,
9210 &mut cx,
9211 )
9212 .await?;
9213 }
9214 Request::GetDefinition(get_definition) => {
9215 let position = get_definition.position.clone().and_then(deserialize_anchor);
9216 Self::query_lsp_locally::<GetDefinitions>(
9217 lsp_store,
9218 server_id,
9219 sender_id,
9220 lsp_request_id,
9221 get_definition,
9222 position,
9223 &mut cx,
9224 )
9225 .await?;
9226 }
9227 Request::GetDeclaration(get_declaration) => {
9228 let position = get_declaration
9229 .position
9230 .clone()
9231 .and_then(deserialize_anchor);
9232 Self::query_lsp_locally::<GetDeclarations>(
9233 lsp_store,
9234 server_id,
9235 sender_id,
9236 lsp_request_id,
9237 get_declaration,
9238 position,
9239 &mut cx,
9240 )
9241 .await?;
9242 }
9243 Request::GetTypeDefinition(get_type_definition) => {
9244 let position = get_type_definition
9245 .position
9246 .clone()
9247 .and_then(deserialize_anchor);
9248 Self::query_lsp_locally::<GetTypeDefinitions>(
9249 lsp_store,
9250 server_id,
9251 sender_id,
9252 lsp_request_id,
9253 get_type_definition,
9254 position,
9255 &mut cx,
9256 )
9257 .await?;
9258 }
9259 Request::GetImplementation(get_implementation) => {
9260 let position = get_implementation
9261 .position
9262 .clone()
9263 .and_then(deserialize_anchor);
9264 Self::query_lsp_locally::<GetImplementations>(
9265 lsp_store,
9266 server_id,
9267 sender_id,
9268 lsp_request_id,
9269 get_implementation,
9270 position,
9271 &mut cx,
9272 )
9273 .await?;
9274 }
9275 Request::InlayHints(inlay_hints) => {
9276 let query_start = inlay_hints
9277 .start
9278 .clone()
9279 .and_then(deserialize_anchor)
9280 .context("invalid inlay hints range start")?;
9281 let query_end = inlay_hints
9282 .end
9283 .clone()
9284 .and_then(deserialize_anchor)
9285 .context("invalid inlay hints range end")?;
9286 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9287 &lsp_store,
9288 server_id,
9289 lsp_request_id,
9290 &inlay_hints,
9291 query_start..query_end,
9292 &mut cx,
9293 )
9294 .await
9295 .context("preparing inlay hints request")?;
9296 Self::query_lsp_locally::<InlayHints>(
9297 lsp_store,
9298 server_id,
9299 sender_id,
9300 lsp_request_id,
9301 inlay_hints,
9302 None,
9303 &mut cx,
9304 )
9305 .await
9306 .context("querying for inlay hints")?
9307 }
9308 //////////////////////////////
9309 // Below are LSP queries that need to fetch more data,
9310 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9311 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9312 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9313 &lsp_store,
9314 &get_document_diagnostics,
9315 &mut cx,
9316 )
9317 .await?;
9318 lsp_store.update(&mut cx, |lsp_store, cx| {
9319 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9320 let key = LspKey {
9321 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9322 server_queried: server_id,
9323 };
9324 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9325 ) {
9326 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9327 lsp_requests.clear();
9328 };
9329 }
9330
9331 lsp_data.lsp_requests.entry(key).or_default().insert(
9332 lsp_request_id,
9333 cx.spawn(async move |lsp_store, cx| {
9334 let diagnostics_pull = lsp_store
9335 .update(cx, |lsp_store, cx| {
9336 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9337 })
9338 .ok();
9339 if let Some(diagnostics_pull) = diagnostics_pull {
9340 match diagnostics_pull.await {
9341 Ok(()) => {}
9342 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9343 };
9344 }
9345 }),
9346 );
9347 });
9348 }
9349 Request::SemanticTokens(semantic_tokens) => {
9350 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9351 &lsp_store,
9352 &semantic_tokens,
9353 &mut cx,
9354 )
9355 .await?;
9356 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9357 lsp_store.update(&mut cx, |lsp_store, cx| {
9358 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9359 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9360 let key = LspKey {
9361 request_type: TypeId::of::<SemanticTokensFull>(),
9362 server_queried: server_id,
9363 };
9364 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9365 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9366 lsp_requests.clear();
9367 };
9368 }
9369
9370 lsp_data.lsp_requests.entry(key).or_default().insert(
9371 lsp_request_id,
9372 cx.spawn(async move |lsp_store, cx| {
9373 let tokens_fetch = lsp_store
9374 .update(cx, |lsp_store, cx| {
9375 lsp_store
9376 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9377 })
9378 .ok();
9379 if let Some(tokens_fetch) = tokens_fetch {
9380 let new_tokens = tokens_fetch.await;
9381 if let Some(new_tokens) = new_tokens {
9382 lsp_store
9383 .update(cx, |lsp_store, cx| {
9384 let response = new_tokens
9385 .into_iter()
9386 .map(|(server_id, response)| {
9387 (
9388 server_id.to_proto(),
9389 SemanticTokensFull::response_to_proto(
9390 response,
9391 lsp_store,
9392 sender_id,
9393 &buffer_version,
9394 cx,
9395 ),
9396 )
9397 })
9398 .collect::<HashMap<_, _>>();
9399 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9400 project_id,
9401 lsp_request_id,
9402 response,
9403 ) {
9404 Ok(()) => {}
9405 Err(e) => {
9406 log::error!(
9407 "Failed to send semantic tokens LSP response: {e:#}",
9408 )
9409 }
9410 }
9411 })
9412 .ok();
9413 }
9414 }
9415 }),
9416 );
9417 }
9418 });
9419 }
9420 }
9421 Ok(proto::Ack {})
9422 }
9423
9424 async fn handle_lsp_query_response(
9425 lsp_store: Entity<Self>,
9426 envelope: TypedEnvelope<proto::LspQueryResponse>,
9427 cx: AsyncApp,
9428 ) -> Result<()> {
9429 lsp_store.read_with(&cx, |lsp_store, _| {
9430 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9431 upstream_client.handle_lsp_response(envelope.clone());
9432 }
9433 });
9434 Ok(())
9435 }
9436
9437 async fn handle_apply_code_action(
9438 this: Entity<Self>,
9439 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9440 mut cx: AsyncApp,
9441 ) -> Result<proto::ApplyCodeActionResponse> {
9442 let sender_id = envelope.original_sender_id().unwrap_or_default();
9443 let action =
9444 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9445 let apply_code_action = this.update(&mut cx, |this, cx| {
9446 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9447 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9448 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9449 })?;
9450
9451 let project_transaction = apply_code_action.await?;
9452 let project_transaction = this.update(&mut cx, |this, cx| {
9453 this.buffer_store.update(cx, |buffer_store, cx| {
9454 buffer_store.serialize_project_transaction_for_peer(
9455 project_transaction,
9456 sender_id,
9457 cx,
9458 )
9459 })
9460 });
9461 Ok(proto::ApplyCodeActionResponse {
9462 transaction: Some(project_transaction),
9463 })
9464 }
9465
9466 async fn handle_register_buffer_with_language_servers(
9467 this: Entity<Self>,
9468 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9469 mut cx: AsyncApp,
9470 ) -> Result<proto::Ack> {
9471 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9472 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9473 this.update(&mut cx, |this, cx| {
9474 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9475 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9476 project_id: upstream_project_id,
9477 buffer_id: buffer_id.to_proto(),
9478 only_servers: envelope.payload.only_servers,
9479 });
9480 }
9481
9482 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9483 anyhow::bail!("buffer is not open");
9484 };
9485
9486 let handle = this.register_buffer_with_language_servers(
9487 &buffer,
9488 envelope
9489 .payload
9490 .only_servers
9491 .into_iter()
9492 .filter_map(|selector| {
9493 Some(match selector.selector? {
9494 proto::language_server_selector::Selector::ServerId(server_id) => {
9495 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9496 }
9497 proto::language_server_selector::Selector::Name(name) => {
9498 LanguageServerSelector::Name(LanguageServerName(
9499 SharedString::from(name),
9500 ))
9501 }
9502 })
9503 })
9504 .collect(),
9505 false,
9506 cx,
9507 );
9508 // Pull diagnostics for the buffer even if it was already registered.
9509 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9510 // but it's unclear if we need it.
9511 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9512 .detach();
9513 this.buffer_store().update(cx, |buffer_store, _| {
9514 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9515 });
9516
9517 Ok(())
9518 })?;
9519 Ok(proto::Ack {})
9520 }
9521
9522 async fn handle_rename_project_entry(
9523 this: Entity<Self>,
9524 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9525 mut cx: AsyncApp,
9526 ) -> Result<proto::ProjectEntryResponse> {
9527 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9528 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9529 let new_path =
9530 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9531
9532 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9533 .update(&mut cx, |this, cx| {
9534 let (worktree, entry) = this
9535 .worktree_store
9536 .read(cx)
9537 .worktree_and_entry_for_id(entry_id, cx)?;
9538 let new_worktree = this
9539 .worktree_store
9540 .read(cx)
9541 .worktree_for_id(new_worktree_id, cx)?;
9542 Some((
9543 this.worktree_store.clone(),
9544 worktree,
9545 new_worktree,
9546 entry.clone(),
9547 ))
9548 })
9549 .context("worktree not found")?;
9550 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9551 (worktree.absolutize(&old_entry.path), worktree.id())
9552 });
9553 let new_abs_path =
9554 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9555
9556 let _transaction = Self::will_rename_entry(
9557 this.downgrade(),
9558 old_worktree_id,
9559 &old_abs_path,
9560 &new_abs_path,
9561 old_entry.is_dir(),
9562 cx.clone(),
9563 )
9564 .await;
9565 let response = WorktreeStore::handle_rename_project_entry(
9566 worktree_store,
9567 envelope.payload,
9568 cx.clone(),
9569 )
9570 .await;
9571 this.read_with(&cx, |this, _| {
9572 this.did_rename_entry(
9573 old_worktree_id,
9574 &old_abs_path,
9575 &new_abs_path,
9576 old_entry.is_dir(),
9577 );
9578 });
9579 response
9580 }
9581
9582 async fn handle_update_diagnostic_summary(
9583 this: Entity<Self>,
9584 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9585 mut cx: AsyncApp,
9586 ) -> Result<()> {
9587 this.update(&mut cx, |lsp_store, cx| {
9588 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9589 let mut updated_diagnostics_paths = HashMap::default();
9590 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9591 for message_summary in envelope
9592 .payload
9593 .summary
9594 .into_iter()
9595 .chain(envelope.payload.more_summaries)
9596 {
9597 let project_path = ProjectPath {
9598 worktree_id,
9599 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9600 };
9601 let path = project_path.path.clone();
9602 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9603 let summary = DiagnosticSummary {
9604 error_count: message_summary.error_count as usize,
9605 warning_count: message_summary.warning_count as usize,
9606 };
9607
9608 if summary.is_empty() {
9609 if let Some(worktree_summaries) =
9610 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9611 && let Some(summaries) = worktree_summaries.get_mut(&path)
9612 {
9613 summaries.remove(&server_id);
9614 if summaries.is_empty() {
9615 worktree_summaries.remove(&path);
9616 }
9617 }
9618 } else {
9619 lsp_store
9620 .diagnostic_summaries
9621 .entry(worktree_id)
9622 .or_default()
9623 .entry(path)
9624 .or_default()
9625 .insert(server_id, summary);
9626 }
9627
9628 if let Some((_, project_id)) = &lsp_store.downstream_client {
9629 match &mut diagnostics_summary {
9630 Some(diagnostics_summary) => {
9631 diagnostics_summary
9632 .more_summaries
9633 .push(proto::DiagnosticSummary {
9634 path: project_path.path.as_ref().to_proto(),
9635 language_server_id: server_id.0 as u64,
9636 error_count: summary.error_count as u32,
9637 warning_count: summary.warning_count as u32,
9638 })
9639 }
9640 None => {
9641 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9642 project_id: *project_id,
9643 worktree_id: worktree_id.to_proto(),
9644 summary: Some(proto::DiagnosticSummary {
9645 path: project_path.path.as_ref().to_proto(),
9646 language_server_id: server_id.0 as u64,
9647 error_count: summary.error_count as u32,
9648 warning_count: summary.warning_count as u32,
9649 }),
9650 more_summaries: Vec::new(),
9651 })
9652 }
9653 }
9654 }
9655 updated_diagnostics_paths
9656 .entry(server_id)
9657 .or_insert_with(Vec::new)
9658 .push(project_path);
9659 }
9660
9661 if let Some((diagnostics_summary, (downstream_client, _))) =
9662 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9663 {
9664 downstream_client.send(diagnostics_summary).log_err();
9665 }
9666 for (server_id, paths) in updated_diagnostics_paths {
9667 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9668 }
9669 Ok(())
9670 })
9671 }
9672
9673 async fn handle_start_language_server(
9674 lsp_store: Entity<Self>,
9675 envelope: TypedEnvelope<proto::StartLanguageServer>,
9676 mut cx: AsyncApp,
9677 ) -> Result<()> {
9678 let server = envelope.payload.server.context("invalid server")?;
9679 let server_capabilities =
9680 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9681 .with_context(|| {
9682 format!(
9683 "incorrect server capabilities {}",
9684 envelope.payload.capabilities
9685 )
9686 })?;
9687 lsp_store.update(&mut cx, |lsp_store, cx| {
9688 let server_id = LanguageServerId(server.id as usize);
9689 let server_name = LanguageServerName::from_proto(server.name.clone());
9690 lsp_store
9691 .lsp_server_capabilities
9692 .insert(server_id, server_capabilities);
9693 lsp_store.language_server_statuses.insert(
9694 server_id,
9695 LanguageServerStatus {
9696 name: server_name.clone(),
9697 server_version: None,
9698 server_readable_version: None,
9699 pending_work: Default::default(),
9700 has_pending_diagnostic_updates: false,
9701 progress_tokens: Default::default(),
9702 worktree: server.worktree_id.map(WorktreeId::from_proto),
9703 binary: None,
9704 configuration: None,
9705 workspace_folders: BTreeSet::new(),
9706 process_id: None,
9707 },
9708 );
9709 cx.emit(LspStoreEvent::LanguageServerAdded(
9710 server_id,
9711 server_name,
9712 server.worktree_id.map(WorktreeId::from_proto),
9713 ));
9714 cx.notify();
9715 });
9716 Ok(())
9717 }
9718
9719 async fn handle_update_language_server(
9720 lsp_store: Entity<Self>,
9721 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9722 mut cx: AsyncApp,
9723 ) -> Result<()> {
9724 lsp_store.update(&mut cx, |lsp_store, cx| {
9725 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9726
9727 match envelope.payload.variant.context("invalid variant")? {
9728 proto::update_language_server::Variant::WorkStart(payload) => {
9729 lsp_store.on_lsp_work_start(
9730 language_server_id,
9731 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9732 .context("invalid progress token value")?,
9733 LanguageServerProgress {
9734 title: payload.title,
9735 is_disk_based_diagnostics_progress: false,
9736 is_cancellable: payload.is_cancellable.unwrap_or(false),
9737 message: payload.message,
9738 percentage: payload.percentage.map(|p| p as usize),
9739 last_update_at: cx.background_executor().now(),
9740 },
9741 cx,
9742 );
9743 }
9744 proto::update_language_server::Variant::WorkProgress(payload) => {
9745 lsp_store.on_lsp_work_progress(
9746 language_server_id,
9747 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9748 .context("invalid progress token value")?,
9749 LanguageServerProgress {
9750 title: None,
9751 is_disk_based_diagnostics_progress: false,
9752 is_cancellable: payload.is_cancellable.unwrap_or(false),
9753 message: payload.message,
9754 percentage: payload.percentage.map(|p| p as usize),
9755 last_update_at: cx.background_executor().now(),
9756 },
9757 cx,
9758 );
9759 }
9760
9761 proto::update_language_server::Variant::WorkEnd(payload) => {
9762 lsp_store.on_lsp_work_end(
9763 language_server_id,
9764 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9765 .context("invalid progress token value")?,
9766 cx,
9767 );
9768 }
9769
9770 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9771 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9772 }
9773
9774 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9775 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9776 }
9777
9778 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9779 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9780 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9781 cx.emit(LspStoreEvent::LanguageServerUpdate {
9782 language_server_id,
9783 name: envelope
9784 .payload
9785 .server_name
9786 .map(SharedString::new)
9787 .map(LanguageServerName),
9788 message: non_lsp,
9789 });
9790 }
9791 }
9792
9793 Ok(())
9794 })
9795 }
9796
9797 async fn handle_language_server_log(
9798 this: Entity<Self>,
9799 envelope: TypedEnvelope<proto::LanguageServerLog>,
9800 mut cx: AsyncApp,
9801 ) -> Result<()> {
9802 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9803 let log_type = envelope
9804 .payload
9805 .log_type
9806 .map(LanguageServerLogType::from_proto)
9807 .context("invalid language server log type")?;
9808
9809 let message = envelope.payload.message;
9810
9811 this.update(&mut cx, |_, cx| {
9812 cx.emit(LspStoreEvent::LanguageServerLog(
9813 language_server_id,
9814 log_type,
9815 message,
9816 ));
9817 });
9818 Ok(())
9819 }
9820
9821 async fn handle_lsp_ext_cancel_flycheck(
9822 lsp_store: Entity<Self>,
9823 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9824 cx: AsyncApp,
9825 ) -> Result<proto::Ack> {
9826 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9827 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9828 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9829 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9830 } else {
9831 None
9832 }
9833 });
9834 if let Some(task) = task {
9835 task.context("handling lsp ext cancel flycheck")?;
9836 }
9837
9838 Ok(proto::Ack {})
9839 }
9840
9841 async fn handle_lsp_ext_run_flycheck(
9842 lsp_store: Entity<Self>,
9843 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9844 mut cx: AsyncApp,
9845 ) -> Result<proto::Ack> {
9846 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9847 lsp_store.update(&mut cx, |lsp_store, cx| {
9848 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9849 let text_document = if envelope.payload.current_file_only {
9850 let buffer_id = envelope
9851 .payload
9852 .buffer_id
9853 .map(|id| BufferId::new(id))
9854 .transpose()?;
9855 buffer_id
9856 .and_then(|buffer_id| {
9857 lsp_store
9858 .buffer_store()
9859 .read(cx)
9860 .get(buffer_id)
9861 .and_then(|buffer| {
9862 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9863 })
9864 .map(|path| make_text_document_identifier(&path))
9865 })
9866 .transpose()?
9867 } else {
9868 None
9869 };
9870 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9871 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9872 )?;
9873 }
9874 anyhow::Ok(())
9875 })?;
9876
9877 Ok(proto::Ack {})
9878 }
9879
9880 async fn handle_lsp_ext_clear_flycheck(
9881 lsp_store: Entity<Self>,
9882 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9883 cx: AsyncApp,
9884 ) -> Result<proto::Ack> {
9885 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9886 lsp_store.read_with(&cx, |lsp_store, _| {
9887 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9888 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9889 } else {
9890 None
9891 }
9892 });
9893
9894 Ok(proto::Ack {})
9895 }
9896
9897 pub fn disk_based_diagnostics_started(
9898 &mut self,
9899 language_server_id: LanguageServerId,
9900 cx: &mut Context<Self>,
9901 ) {
9902 if let Some(language_server_status) =
9903 self.language_server_statuses.get_mut(&language_server_id)
9904 {
9905 language_server_status.has_pending_diagnostic_updates = true;
9906 }
9907
9908 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9909 cx.emit(LspStoreEvent::LanguageServerUpdate {
9910 language_server_id,
9911 name: self
9912 .language_server_adapter_for_id(language_server_id)
9913 .map(|adapter| adapter.name()),
9914 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9915 Default::default(),
9916 ),
9917 })
9918 }
9919
9920 pub fn disk_based_diagnostics_finished(
9921 &mut self,
9922 language_server_id: LanguageServerId,
9923 cx: &mut Context<Self>,
9924 ) {
9925 if let Some(language_server_status) =
9926 self.language_server_statuses.get_mut(&language_server_id)
9927 {
9928 language_server_status.has_pending_diagnostic_updates = false;
9929 }
9930
9931 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9932 cx.emit(LspStoreEvent::LanguageServerUpdate {
9933 language_server_id,
9934 name: self
9935 .language_server_adapter_for_id(language_server_id)
9936 .map(|adapter| adapter.name()),
9937 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9938 Default::default(),
9939 ),
9940 })
9941 }
9942
9943 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9944 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9945 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9946 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9947 // the language server might take some time to publish diagnostics.
9948 fn simulate_disk_based_diagnostics_events_if_needed(
9949 &mut self,
9950 language_server_id: LanguageServerId,
9951 cx: &mut Context<Self>,
9952 ) {
9953 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9954
9955 let Some(LanguageServerState::Running {
9956 simulate_disk_based_diagnostics_completion,
9957 adapter,
9958 ..
9959 }) = self
9960 .as_local_mut()
9961 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9962 else {
9963 return;
9964 };
9965
9966 if adapter.disk_based_diagnostics_progress_token.is_some() {
9967 return;
9968 }
9969
9970 let prev_task =
9971 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9972 cx.background_executor()
9973 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9974 .await;
9975
9976 this.update(cx, |this, cx| {
9977 this.disk_based_diagnostics_finished(language_server_id, cx);
9978
9979 if let Some(LanguageServerState::Running {
9980 simulate_disk_based_diagnostics_completion,
9981 ..
9982 }) = this.as_local_mut().and_then(|local_store| {
9983 local_store.language_servers.get_mut(&language_server_id)
9984 }) {
9985 *simulate_disk_based_diagnostics_completion = None;
9986 }
9987 })
9988 .ok();
9989 }));
9990
9991 if prev_task.is_none() {
9992 self.disk_based_diagnostics_started(language_server_id, cx);
9993 }
9994 }
9995
9996 pub fn language_server_statuses(
9997 &self,
9998 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9999 self.language_server_statuses
10000 .iter()
10001 .map(|(key, value)| (*key, value))
10002 }
10003
10004 pub(super) fn did_rename_entry(
10005 &self,
10006 worktree_id: WorktreeId,
10007 old_path: &Path,
10008 new_path: &Path,
10009 is_dir: bool,
10010 ) {
10011 maybe!({
10012 let local_store = self.as_local()?;
10013
10014 let old_uri = lsp::Uri::from_file_path(old_path)
10015 .ok()
10016 .map(|uri| uri.to_string())?;
10017 let new_uri = lsp::Uri::from_file_path(new_path)
10018 .ok()
10019 .map(|uri| uri.to_string())?;
10020
10021 for language_server in local_store.language_servers_for_worktree(worktree_id) {
10022 let Some(filter) = local_store
10023 .language_server_paths_watched_for_rename
10024 .get(&language_server.server_id())
10025 else {
10026 continue;
10027 };
10028
10029 if filter.should_send_did_rename(&old_uri, is_dir) {
10030 language_server
10031 .notify::<DidRenameFiles>(RenameFilesParams {
10032 files: vec![FileRename {
10033 old_uri: old_uri.clone(),
10034 new_uri: new_uri.clone(),
10035 }],
10036 })
10037 .ok();
10038 }
10039 }
10040 Some(())
10041 });
10042 }
10043
10044 pub(super) fn will_rename_entry(
10045 this: WeakEntity<Self>,
10046 worktree_id: WorktreeId,
10047 old_path: &Path,
10048 new_path: &Path,
10049 is_dir: bool,
10050 cx: AsyncApp,
10051 ) -> Task<ProjectTransaction> {
10052 let old_uri = lsp::Uri::from_file_path(old_path)
10053 .ok()
10054 .map(|uri| uri.to_string());
10055 let new_uri = lsp::Uri::from_file_path(new_path)
10056 .ok()
10057 .map(|uri| uri.to_string());
10058 cx.spawn(async move |cx| {
10059 let mut tasks = vec![];
10060 this.update(cx, |this, cx| {
10061 let local_store = this.as_local()?;
10062 let old_uri = old_uri?;
10063 let new_uri = new_uri?;
10064 for language_server in local_store.language_servers_for_worktree(worktree_id) {
10065 let Some(filter) = local_store
10066 .language_server_paths_watched_for_rename
10067 .get(&language_server.server_id())
10068 else {
10069 continue;
10070 };
10071
10072 if !filter.should_send_will_rename(&old_uri, is_dir) {
10073 continue;
10074 }
10075 let request_timeout = ProjectSettings::get_global(cx)
10076 .global_lsp_settings
10077 .get_request_timeout();
10078
10079 let apply_edit = cx.spawn({
10080 let old_uri = old_uri.clone();
10081 let new_uri = new_uri.clone();
10082 let language_server = language_server.clone();
10083 async move |this, cx| {
10084 let edit = language_server
10085 .request::<WillRenameFiles>(
10086 RenameFilesParams {
10087 files: vec![FileRename { old_uri, new_uri }],
10088 },
10089 request_timeout,
10090 )
10091 .await
10092 .into_response()
10093 .context("will rename files")
10094 .log_err()
10095 .flatten()?;
10096
10097 LocalLspStore::deserialize_workspace_edit(
10098 this.upgrade()?,
10099 edit,
10100 false,
10101 language_server.clone(),
10102 cx,
10103 )
10104 .await
10105 .ok()
10106 }
10107 });
10108 tasks.push(apply_edit);
10109 }
10110 Some(())
10111 })
10112 .ok()
10113 .flatten();
10114 let mut merged_transaction = ProjectTransaction::default();
10115 for task in tasks {
10116 // Await on tasks sequentially so that the order of application of edits is deterministic
10117 // (at least with regards to the order of registration of language servers)
10118 if let Some(transaction) = task.await {
10119 for (buffer, buffer_transaction) in transaction.0 {
10120 merged_transaction.0.insert(buffer, buffer_transaction);
10121 }
10122 }
10123 }
10124 merged_transaction
10125 })
10126 }
10127
10128 fn lsp_notify_abs_paths_changed(
10129 &mut self,
10130 server_id: LanguageServerId,
10131 changes: Vec<PathEvent>,
10132 ) {
10133 maybe!({
10134 let server = self.language_server_for_id(server_id)?;
10135 let changes = changes
10136 .into_iter()
10137 .filter_map(|event| {
10138 let typ = match event.kind? {
10139 PathEventKind::Created => lsp::FileChangeType::CREATED,
10140 PathEventKind::Removed => lsp::FileChangeType::DELETED,
10141 PathEventKind::Changed | PathEventKind::Rescan => {
10142 lsp::FileChangeType::CHANGED
10143 }
10144 };
10145 Some(lsp::FileEvent {
10146 uri: file_path_to_lsp_url(&event.path).log_err()?,
10147 typ,
10148 })
10149 })
10150 .collect::<Vec<_>>();
10151 if !changes.is_empty() {
10152 server
10153 .notify::<lsp::notification::DidChangeWatchedFiles>(
10154 lsp::DidChangeWatchedFilesParams { changes },
10155 )
10156 .ok();
10157 }
10158 Some(())
10159 });
10160 }
10161
10162 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10163 self.as_local()?.language_server_for_id(id)
10164 }
10165
10166 fn on_lsp_progress(
10167 &mut self,
10168 progress_params: lsp::ProgressParams,
10169 language_server_id: LanguageServerId,
10170 disk_based_diagnostics_progress_token: Option<String>,
10171 cx: &mut Context<Self>,
10172 ) {
10173 match progress_params.value {
10174 lsp::ProgressParamsValue::WorkDone(progress) => {
10175 self.handle_work_done_progress(
10176 progress,
10177 language_server_id,
10178 disk_based_diagnostics_progress_token,
10179 ProgressToken::from_lsp(progress_params.token),
10180 cx,
10181 );
10182 }
10183 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10184 let registration_id = match progress_params.token {
10185 lsp::NumberOrString::Number(_) => None,
10186 lsp::NumberOrString::String(token) => token
10187 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10188 .map(|(_, id)| id.to_owned()),
10189 };
10190 if let Some(LanguageServerState::Running {
10191 workspace_diagnostics_refresh_tasks,
10192 ..
10193 }) = self
10194 .as_local_mut()
10195 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10196 && let Some(workspace_diagnostics) =
10197 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10198 {
10199 workspace_diagnostics.progress_tx.try_send(()).ok();
10200 self.apply_workspace_diagnostic_report(
10201 language_server_id,
10202 report,
10203 registration_id.map(SharedString::from),
10204 cx,
10205 )
10206 }
10207 }
10208 }
10209 }
10210
10211 fn handle_work_done_progress(
10212 &mut self,
10213 progress: lsp::WorkDoneProgress,
10214 language_server_id: LanguageServerId,
10215 disk_based_diagnostics_progress_token: Option<String>,
10216 token: ProgressToken,
10217 cx: &mut Context<Self>,
10218 ) {
10219 let language_server_status =
10220 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10221 status
10222 } else {
10223 return;
10224 };
10225
10226 if !language_server_status.progress_tokens.contains(&token) {
10227 return;
10228 }
10229
10230 let is_disk_based_diagnostics_progress =
10231 if let (Some(disk_based_token), ProgressToken::String(token)) =
10232 (&disk_based_diagnostics_progress_token, &token)
10233 {
10234 token.starts_with(disk_based_token)
10235 } else {
10236 false
10237 };
10238
10239 match progress {
10240 lsp::WorkDoneProgress::Begin(report) => {
10241 if is_disk_based_diagnostics_progress {
10242 self.disk_based_diagnostics_started(language_server_id, cx);
10243 }
10244 self.on_lsp_work_start(
10245 language_server_id,
10246 token.clone(),
10247 LanguageServerProgress {
10248 title: Some(report.title),
10249 is_disk_based_diagnostics_progress,
10250 is_cancellable: report.cancellable.unwrap_or(false),
10251 message: report.message.clone(),
10252 percentage: report.percentage.map(|p| p as usize),
10253 last_update_at: cx.background_executor().now(),
10254 },
10255 cx,
10256 );
10257 }
10258 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10259 language_server_id,
10260 token,
10261 LanguageServerProgress {
10262 title: None,
10263 is_disk_based_diagnostics_progress,
10264 is_cancellable: report.cancellable.unwrap_or(false),
10265 message: report.message,
10266 percentage: report.percentage.map(|p| p as usize),
10267 last_update_at: cx.background_executor().now(),
10268 },
10269 cx,
10270 ),
10271 lsp::WorkDoneProgress::End(_) => {
10272 language_server_status.progress_tokens.remove(&token);
10273 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10274 if is_disk_based_diagnostics_progress {
10275 self.disk_based_diagnostics_finished(language_server_id, cx);
10276 }
10277 }
10278 }
10279 }
10280
10281 fn on_lsp_work_start(
10282 &mut self,
10283 language_server_id: LanguageServerId,
10284 token: ProgressToken,
10285 progress: LanguageServerProgress,
10286 cx: &mut Context<Self>,
10287 ) {
10288 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10289 status.pending_work.insert(token.clone(), progress.clone());
10290 cx.notify();
10291 }
10292 cx.emit(LspStoreEvent::LanguageServerUpdate {
10293 language_server_id,
10294 name: self
10295 .language_server_adapter_for_id(language_server_id)
10296 .map(|adapter| adapter.name()),
10297 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10298 token: Some(token.to_proto()),
10299 title: progress.title,
10300 message: progress.message,
10301 percentage: progress.percentage.map(|p| p as u32),
10302 is_cancellable: Some(progress.is_cancellable),
10303 }),
10304 })
10305 }
10306
10307 fn on_lsp_work_progress(
10308 &mut self,
10309 language_server_id: LanguageServerId,
10310 token: ProgressToken,
10311 progress: LanguageServerProgress,
10312 cx: &mut Context<Self>,
10313 ) {
10314 let mut did_update = false;
10315 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10316 match status.pending_work.entry(token.clone()) {
10317 btree_map::Entry::Vacant(entry) => {
10318 entry.insert(progress.clone());
10319 did_update = true;
10320 }
10321 btree_map::Entry::Occupied(mut entry) => {
10322 let entry = entry.get_mut();
10323 if (progress.last_update_at - entry.last_update_at)
10324 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10325 {
10326 entry.last_update_at = progress.last_update_at;
10327 if progress.message.is_some() {
10328 entry.message = progress.message.clone();
10329 }
10330 if progress.percentage.is_some() {
10331 entry.percentage = progress.percentage;
10332 }
10333 if progress.is_cancellable != entry.is_cancellable {
10334 entry.is_cancellable = progress.is_cancellable;
10335 }
10336 did_update = true;
10337 }
10338 }
10339 }
10340 }
10341
10342 if did_update {
10343 cx.emit(LspStoreEvent::LanguageServerUpdate {
10344 language_server_id,
10345 name: self
10346 .language_server_adapter_for_id(language_server_id)
10347 .map(|adapter| adapter.name()),
10348 message: proto::update_language_server::Variant::WorkProgress(
10349 proto::LspWorkProgress {
10350 token: Some(token.to_proto()),
10351 message: progress.message,
10352 percentage: progress.percentage.map(|p| p as u32),
10353 is_cancellable: Some(progress.is_cancellable),
10354 },
10355 ),
10356 })
10357 }
10358 }
10359
10360 fn on_lsp_work_end(
10361 &mut self,
10362 language_server_id: LanguageServerId,
10363 token: ProgressToken,
10364 cx: &mut Context<Self>,
10365 ) {
10366 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10367 if let Some(work) = status.pending_work.remove(&token)
10368 && !work.is_disk_based_diagnostics_progress
10369 {
10370 cx.emit(LspStoreEvent::RefreshInlayHints {
10371 server_id: language_server_id,
10372 request_id: None,
10373 });
10374 }
10375 cx.notify();
10376 }
10377
10378 cx.emit(LspStoreEvent::LanguageServerUpdate {
10379 language_server_id,
10380 name: self
10381 .language_server_adapter_for_id(language_server_id)
10382 .map(|adapter| adapter.name()),
10383 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10384 token: Some(token.to_proto()),
10385 }),
10386 })
10387 }
10388
10389 pub async fn handle_resolve_completion_documentation(
10390 this: Entity<Self>,
10391 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10392 mut cx: AsyncApp,
10393 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10394 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10395
10396 let completion = this
10397 .read_with(&cx, |this, cx| {
10398 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10399 let server = this
10400 .language_server_for_id(id)
10401 .with_context(|| format!("No language server {id}"))?;
10402
10403 let request_timeout = ProjectSettings::get_global(cx)
10404 .global_lsp_settings
10405 .get_request_timeout();
10406
10407 anyhow::Ok(cx.background_spawn(async move {
10408 let can_resolve = server
10409 .capabilities()
10410 .completion_provider
10411 .as_ref()
10412 .and_then(|options| options.resolve_provider)
10413 .unwrap_or(false);
10414 if can_resolve {
10415 server
10416 .request::<lsp::request::ResolveCompletionItem>(
10417 lsp_completion,
10418 request_timeout,
10419 )
10420 .await
10421 .into_response()
10422 .context("resolve completion item")
10423 } else {
10424 anyhow::Ok(lsp_completion)
10425 }
10426 }))
10427 })?
10428 .await?;
10429
10430 let mut documentation_is_markdown = false;
10431 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10432 let documentation = match completion.documentation {
10433 Some(lsp::Documentation::String(text)) => text,
10434
10435 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10436 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10437 value
10438 }
10439
10440 _ => String::new(),
10441 };
10442
10443 // If we have a new buffer_id, that means we're talking to a new client
10444 // and want to check for new text_edits in the completion too.
10445 let mut old_replace_start = None;
10446 let mut old_replace_end = None;
10447 let mut old_insert_start = None;
10448 let mut old_insert_end = None;
10449 let mut new_text = String::default();
10450 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10451 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10452 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10453 anyhow::Ok(buffer.read(cx).snapshot())
10454 })?;
10455
10456 if let Some(text_edit) = completion.text_edit.as_ref() {
10457 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10458
10459 if let Some(mut edit) = edit {
10460 LineEnding::normalize(&mut edit.new_text);
10461
10462 new_text = edit.new_text;
10463 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10464 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10465 if let Some(insert_range) = edit.insert_range {
10466 old_insert_start = Some(serialize_anchor(&insert_range.start));
10467 old_insert_end = Some(serialize_anchor(&insert_range.end));
10468 }
10469 }
10470 }
10471 }
10472
10473 Ok(proto::ResolveCompletionDocumentationResponse {
10474 documentation,
10475 documentation_is_markdown,
10476 old_replace_start,
10477 old_replace_end,
10478 new_text,
10479 lsp_completion,
10480 old_insert_start,
10481 old_insert_end,
10482 })
10483 }
10484
10485 async fn handle_on_type_formatting(
10486 this: Entity<Self>,
10487 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10488 mut cx: AsyncApp,
10489 ) -> Result<proto::OnTypeFormattingResponse> {
10490 let on_type_formatting = this.update(&mut cx, |this, cx| {
10491 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10492 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10493 let position = envelope
10494 .payload
10495 .position
10496 .and_then(deserialize_anchor)
10497 .context("invalid position")?;
10498 anyhow::Ok(this.apply_on_type_formatting(
10499 buffer,
10500 position,
10501 envelope.payload.trigger.clone(),
10502 cx,
10503 ))
10504 })?;
10505
10506 let transaction = on_type_formatting
10507 .await?
10508 .as_ref()
10509 .map(language::proto::serialize_transaction);
10510 Ok(proto::OnTypeFormattingResponse { transaction })
10511 }
10512
10513 async fn handle_pull_workspace_diagnostics(
10514 lsp_store: Entity<Self>,
10515 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10516 mut cx: AsyncApp,
10517 ) -> Result<proto::Ack> {
10518 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10519 lsp_store.update(&mut cx, |lsp_store, _| {
10520 lsp_store.pull_workspace_diagnostics(server_id);
10521 });
10522 Ok(proto::Ack {})
10523 }
10524
10525 async fn handle_open_buffer_for_symbol(
10526 this: Entity<Self>,
10527 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10528 mut cx: AsyncApp,
10529 ) -> Result<proto::OpenBufferForSymbolResponse> {
10530 let peer_id = envelope.original_sender_id().unwrap_or_default();
10531 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10532 let symbol = Self::deserialize_symbol(symbol)?;
10533 this.read_with(&cx, |this, _| {
10534 if let SymbolLocation::OutsideProject {
10535 abs_path,
10536 signature,
10537 } = &symbol.path
10538 {
10539 let new_signature = this.symbol_signature(&abs_path);
10540 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10541 }
10542 Ok(())
10543 })?;
10544 let buffer = this
10545 .update(&mut cx, |this, cx| {
10546 this.open_buffer_for_symbol(
10547 &Symbol {
10548 language_server_name: symbol.language_server_name,
10549 source_worktree_id: symbol.source_worktree_id,
10550 source_language_server_id: symbol.source_language_server_id,
10551 path: symbol.path,
10552 name: symbol.name,
10553 kind: symbol.kind,
10554 range: symbol.range,
10555 label: CodeLabel::default(),
10556 container_name: symbol.container_name,
10557 },
10558 cx,
10559 )
10560 })
10561 .await?;
10562
10563 this.update(&mut cx, |this, cx| {
10564 let is_private = buffer
10565 .read(cx)
10566 .file()
10567 .map(|f| f.is_private())
10568 .unwrap_or_default();
10569 if is_private {
10570 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10571 } else {
10572 this.buffer_store
10573 .update(cx, |buffer_store, cx| {
10574 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10575 })
10576 .detach_and_log_err(cx);
10577 let buffer_id = buffer.read(cx).remote_id().to_proto();
10578 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10579 }
10580 })
10581 }
10582
10583 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10584 let mut hasher = Sha256::new();
10585 hasher.update(abs_path.to_string_lossy().as_bytes());
10586 hasher.update(self.nonce.to_be_bytes());
10587 hasher.finalize().as_slice().try_into().unwrap()
10588 }
10589
10590 pub async fn handle_get_project_symbols(
10591 this: Entity<Self>,
10592 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10593 mut cx: AsyncApp,
10594 ) -> Result<proto::GetProjectSymbolsResponse> {
10595 let symbols = this
10596 .update(&mut cx, |this, cx| {
10597 this.symbols(&envelope.payload.query, cx)
10598 })
10599 .await?;
10600
10601 Ok(proto::GetProjectSymbolsResponse {
10602 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10603 })
10604 }
10605
10606 pub async fn handle_restart_language_servers(
10607 this: Entity<Self>,
10608 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10609 mut cx: AsyncApp,
10610 ) -> Result<proto::Ack> {
10611 this.update(&mut cx, |lsp_store, cx| {
10612 let buffers =
10613 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10614 lsp_store.restart_language_servers_for_buffers(
10615 buffers,
10616 envelope
10617 .payload
10618 .only_servers
10619 .into_iter()
10620 .filter_map(|selector| {
10621 Some(match selector.selector? {
10622 proto::language_server_selector::Selector::ServerId(server_id) => {
10623 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10624 }
10625 proto::language_server_selector::Selector::Name(name) => {
10626 LanguageServerSelector::Name(LanguageServerName(
10627 SharedString::from(name),
10628 ))
10629 }
10630 })
10631 })
10632 .collect(),
10633 cx,
10634 );
10635 });
10636
10637 Ok(proto::Ack {})
10638 }
10639
10640 pub async fn handle_stop_language_servers(
10641 lsp_store: Entity<Self>,
10642 envelope: TypedEnvelope<proto::StopLanguageServers>,
10643 mut cx: AsyncApp,
10644 ) -> Result<proto::Ack> {
10645 lsp_store.update(&mut cx, |lsp_store, cx| {
10646 if envelope.payload.all
10647 && envelope.payload.also_servers.is_empty()
10648 && envelope.payload.buffer_ids.is_empty()
10649 {
10650 lsp_store.stop_all_language_servers(cx);
10651 } else {
10652 let buffers =
10653 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10654 lsp_store
10655 .stop_language_servers_for_buffers(
10656 buffers,
10657 envelope
10658 .payload
10659 .also_servers
10660 .into_iter()
10661 .filter_map(|selector| {
10662 Some(match selector.selector? {
10663 proto::language_server_selector::Selector::ServerId(
10664 server_id,
10665 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10666 server_id,
10667 )),
10668 proto::language_server_selector::Selector::Name(name) => {
10669 LanguageServerSelector::Name(LanguageServerName(
10670 SharedString::from(name),
10671 ))
10672 }
10673 })
10674 })
10675 .collect(),
10676 cx,
10677 )
10678 .detach_and_log_err(cx);
10679 }
10680 });
10681
10682 Ok(proto::Ack {})
10683 }
10684
10685 pub async fn handle_cancel_language_server_work(
10686 lsp_store: Entity<Self>,
10687 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10688 mut cx: AsyncApp,
10689 ) -> Result<proto::Ack> {
10690 lsp_store.update(&mut cx, |lsp_store, cx| {
10691 if let Some(work) = envelope.payload.work {
10692 match work {
10693 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10694 let buffers =
10695 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10696 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10697 }
10698 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10699 let server_id = LanguageServerId::from_proto(work.language_server_id);
10700 let token = work
10701 .token
10702 .map(|token| {
10703 ProgressToken::from_proto(token)
10704 .context("invalid work progress token")
10705 })
10706 .transpose()?;
10707 lsp_store.cancel_language_server_work(server_id, token, cx);
10708 }
10709 }
10710 }
10711 anyhow::Ok(())
10712 })?;
10713
10714 Ok(proto::Ack {})
10715 }
10716
10717 fn buffer_ids_to_buffers(
10718 &mut self,
10719 buffer_ids: impl Iterator<Item = u64>,
10720 cx: &mut Context<Self>,
10721 ) -> Vec<Entity<Buffer>> {
10722 buffer_ids
10723 .into_iter()
10724 .flat_map(|buffer_id| {
10725 self.buffer_store
10726 .read(cx)
10727 .get(BufferId::new(buffer_id).log_err()?)
10728 })
10729 .collect::<Vec<_>>()
10730 }
10731
10732 async fn handle_apply_additional_edits_for_completion(
10733 this: Entity<Self>,
10734 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10735 mut cx: AsyncApp,
10736 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10737 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10738 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10739 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10740 let completion = Self::deserialize_completion(
10741 envelope.payload.completion.context("invalid completion")?,
10742 )?;
10743 let all_commit_ranges = envelope
10744 .payload
10745 .all_commit_ranges
10746 .into_iter()
10747 .map(language::proto::deserialize_anchor_range)
10748 .collect::<Result<Vec<_>, _>>()?;
10749 anyhow::Ok((buffer, completion, all_commit_ranges))
10750 })?;
10751
10752 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10753 this.apply_additional_edits_for_completion(
10754 buffer,
10755 Rc::new(RefCell::new(Box::new([Completion {
10756 replace_range: completion.replace_range,
10757 new_text: completion.new_text,
10758 source: completion.source,
10759 documentation: None,
10760 label: CodeLabel::default(),
10761 match_start: None,
10762 snippet_deduplication_key: None,
10763 insert_text_mode: None,
10764 icon_path: None,
10765 confirm: None,
10766 }]))),
10767 0,
10768 false,
10769 all_commit_ranges,
10770 cx,
10771 )
10772 });
10773
10774 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10775 transaction: apply_additional_edits
10776 .await?
10777 .as_ref()
10778 .map(language::proto::serialize_transaction),
10779 })
10780 }
10781
10782 pub fn last_formatting_failure(&self) -> Option<&str> {
10783 self.last_formatting_failure.as_deref()
10784 }
10785
10786 pub fn reset_last_formatting_failure(&mut self) {
10787 self.last_formatting_failure = None;
10788 }
10789
10790 pub fn environment_for_buffer(
10791 &self,
10792 buffer: &Entity<Buffer>,
10793 cx: &mut Context<Self>,
10794 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10795 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10796 environment.update(cx, |env, cx| {
10797 env.buffer_environment(buffer, &self.worktree_store, cx)
10798 })
10799 } else {
10800 Task::ready(None).shared()
10801 }
10802 }
10803
10804 pub fn format(
10805 &mut self,
10806 buffers: HashSet<Entity<Buffer>>,
10807 target: LspFormatTarget,
10808 push_to_history: bool,
10809 trigger: FormatTrigger,
10810 cx: &mut Context<Self>,
10811 ) -> Task<anyhow::Result<ProjectTransaction>> {
10812 let logger = zlog::scoped!("format");
10813 if self.as_local().is_some() {
10814 zlog::trace!(logger => "Formatting locally");
10815 let logger = zlog::scoped!(logger => "local");
10816 let buffers = buffers
10817 .into_iter()
10818 .map(|buffer_handle| {
10819 let buffer = buffer_handle.read(cx);
10820 let buffer_abs_path = File::from_dyn(buffer.file())
10821 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10822
10823 (buffer_handle, buffer_abs_path, buffer.remote_id())
10824 })
10825 .collect::<Vec<_>>();
10826
10827 cx.spawn(async move |lsp_store, cx| {
10828 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10829
10830 for (handle, abs_path, id) in buffers {
10831 let env = lsp_store
10832 .update(cx, |lsp_store, cx| {
10833 lsp_store.environment_for_buffer(&handle, cx)
10834 })?
10835 .await;
10836
10837 let ranges = match &target {
10838 LspFormatTarget::Buffers => None,
10839 LspFormatTarget::Ranges(ranges) => {
10840 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10841 }
10842 };
10843
10844 formattable_buffers.push(FormattableBuffer {
10845 handle,
10846 abs_path,
10847 env,
10848 ranges,
10849 });
10850 }
10851 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10852
10853 let format_timer = zlog::time!(logger => "Formatting buffers");
10854 let result = LocalLspStore::format_locally(
10855 lsp_store.clone(),
10856 formattable_buffers,
10857 push_to_history,
10858 trigger,
10859 logger,
10860 cx,
10861 )
10862 .await;
10863 format_timer.end();
10864
10865 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10866
10867 lsp_store.update(cx, |lsp_store, _| {
10868 lsp_store.update_last_formatting_failure(&result);
10869 })?;
10870
10871 result
10872 })
10873 } else if let Some((client, project_id)) = self.upstream_client() {
10874 zlog::trace!(logger => "Formatting remotely");
10875 let logger = zlog::scoped!(logger => "remote");
10876
10877 let buffer_ranges = match &target {
10878 LspFormatTarget::Buffers => Vec::new(),
10879 LspFormatTarget::Ranges(ranges) => ranges
10880 .iter()
10881 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10882 buffer_id: buffer_id.to_proto(),
10883 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10884 })
10885 .collect(),
10886 };
10887
10888 let buffer_store = self.buffer_store();
10889 cx.spawn(async move |lsp_store, cx| {
10890 zlog::trace!(logger => "Sending remote format request");
10891 let request_timer = zlog::time!(logger => "remote format request");
10892 let result = client
10893 .request(proto::FormatBuffers {
10894 project_id,
10895 trigger: trigger as i32,
10896 buffer_ids: buffers
10897 .iter()
10898 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10899 .collect(),
10900 buffer_ranges,
10901 })
10902 .await
10903 .and_then(|result| result.transaction.context("missing transaction"));
10904 request_timer.end();
10905
10906 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10907
10908 lsp_store.update(cx, |lsp_store, _| {
10909 lsp_store.update_last_formatting_failure(&result);
10910 })?;
10911
10912 let transaction_response = result?;
10913 let _timer = zlog::time!(logger => "deserializing project transaction");
10914 buffer_store
10915 .update(cx, |buffer_store, cx| {
10916 buffer_store.deserialize_project_transaction(
10917 transaction_response,
10918 push_to_history,
10919 cx,
10920 )
10921 })
10922 .await
10923 })
10924 } else {
10925 zlog::trace!(logger => "Not formatting");
10926 Task::ready(Ok(ProjectTransaction::default()))
10927 }
10928 }
10929
10930 async fn handle_format_buffers(
10931 this: Entity<Self>,
10932 envelope: TypedEnvelope<proto::FormatBuffers>,
10933 mut cx: AsyncApp,
10934 ) -> Result<proto::FormatBuffersResponse> {
10935 let sender_id = envelope.original_sender_id().unwrap_or_default();
10936 let format = this.update(&mut cx, |this, cx| {
10937 let mut buffers = HashSet::default();
10938 for buffer_id in &envelope.payload.buffer_ids {
10939 let buffer_id = BufferId::new(*buffer_id)?;
10940 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10941 }
10942
10943 let target = if envelope.payload.buffer_ranges.is_empty() {
10944 LspFormatTarget::Buffers
10945 } else {
10946 let mut ranges_map = BTreeMap::new();
10947 for buffer_range in &envelope.payload.buffer_ranges {
10948 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10949 let ranges: Result<Vec<_>> = buffer_range
10950 .ranges
10951 .iter()
10952 .map(|range| {
10953 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10954 })
10955 .collect();
10956 ranges_map.insert(buffer_id, ranges?);
10957 }
10958 LspFormatTarget::Ranges(ranges_map)
10959 };
10960
10961 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10962 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10963 })?;
10964
10965 let project_transaction = format.await?;
10966 let project_transaction = this.update(&mut cx, |this, cx| {
10967 this.buffer_store.update(cx, |buffer_store, cx| {
10968 buffer_store.serialize_project_transaction_for_peer(
10969 project_transaction,
10970 sender_id,
10971 cx,
10972 )
10973 })
10974 });
10975 Ok(proto::FormatBuffersResponse {
10976 transaction: Some(project_transaction),
10977 })
10978 }
10979
10980 async fn handle_apply_code_action_kind(
10981 this: Entity<Self>,
10982 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10983 mut cx: AsyncApp,
10984 ) -> Result<proto::ApplyCodeActionKindResponse> {
10985 let sender_id = envelope.original_sender_id().unwrap_or_default();
10986 let format = this.update(&mut cx, |this, cx| {
10987 let mut buffers = HashSet::default();
10988 for buffer_id in &envelope.payload.buffer_ids {
10989 let buffer_id = BufferId::new(*buffer_id)?;
10990 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10991 }
10992 let kind = match envelope.payload.kind.as_str() {
10993 "" => CodeActionKind::EMPTY,
10994 "quickfix" => CodeActionKind::QUICKFIX,
10995 "refactor" => CodeActionKind::REFACTOR,
10996 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10997 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10998 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10999 "source" => CodeActionKind::SOURCE,
11000 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
11001 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
11002 _ => anyhow::bail!(
11003 "Invalid code action kind {}",
11004 envelope.payload.kind.as_str()
11005 ),
11006 };
11007 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
11008 })?;
11009
11010 let project_transaction = format.await?;
11011 let project_transaction = this.update(&mut cx, |this, cx| {
11012 this.buffer_store.update(cx, |buffer_store, cx| {
11013 buffer_store.serialize_project_transaction_for_peer(
11014 project_transaction,
11015 sender_id,
11016 cx,
11017 )
11018 })
11019 });
11020 Ok(proto::ApplyCodeActionKindResponse {
11021 transaction: Some(project_transaction),
11022 })
11023 }
11024
11025 async fn shutdown_language_server(
11026 server_state: Option<LanguageServerState>,
11027 name: LanguageServerName,
11028 cx: &mut AsyncApp,
11029 ) {
11030 let server = match server_state {
11031 Some(LanguageServerState::Starting { startup, .. }) => {
11032 let mut timer = cx
11033 .background_executor()
11034 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
11035 .fuse();
11036
11037 select! {
11038 server = startup.fuse() => server,
11039 () = timer => {
11040 log::info!("timeout waiting for language server {name} to finish launching before stopping");
11041 None
11042 },
11043 }
11044 }
11045
11046 Some(LanguageServerState::Running { server, .. }) => Some(server),
11047
11048 None => None,
11049 };
11050
11051 let Some(server) = server else { return };
11052 if let Some(shutdown) = server.shutdown() {
11053 shutdown.await;
11054 }
11055 }
11056
11057 // Returns a list of all of the worktrees which no longer have a language server and the root path
11058 // for the stopped server
11059 fn stop_local_language_server(
11060 &mut self,
11061 server_id: LanguageServerId,
11062 cx: &mut Context<Self>,
11063 ) -> Task<()> {
11064 let local = match &mut self.mode {
11065 LspStoreMode::Local(local) => local,
11066 _ => {
11067 return Task::ready(());
11068 }
11069 };
11070
11071 // Remove this server ID from all entries in the given worktree.
11072 local
11073 .language_server_ids
11074 .retain(|_, state| state.id != server_id);
11075 self.buffer_store.update(cx, |buffer_store, cx| {
11076 for buffer in buffer_store.buffers() {
11077 buffer.update(cx, |buffer, cx| {
11078 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
11079 buffer.set_completion_triggers(server_id, Default::default(), cx);
11080 });
11081 }
11082 });
11083
11084 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
11085 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
11086 summaries.retain(|path, summaries_by_server_id| {
11087 if summaries_by_server_id.remove(&server_id).is_some() {
11088 if let Some((client, project_id)) = self.downstream_client.clone() {
11089 client
11090 .send(proto::UpdateDiagnosticSummary {
11091 project_id,
11092 worktree_id: worktree_id.to_proto(),
11093 summary: Some(proto::DiagnosticSummary {
11094 path: path.as_ref().to_proto(),
11095 language_server_id: server_id.0 as u64,
11096 error_count: 0,
11097 warning_count: 0,
11098 }),
11099 more_summaries: Vec::new(),
11100 })
11101 .log_err();
11102 }
11103 cleared_paths.push(ProjectPath {
11104 worktree_id: *worktree_id,
11105 path: path.clone(),
11106 });
11107 !summaries_by_server_id.is_empty()
11108 } else {
11109 true
11110 }
11111 });
11112 }
11113 if !cleared_paths.is_empty() {
11114 cx.emit(LspStoreEvent::DiagnosticsUpdated {
11115 server_id,
11116 paths: cleared_paths,
11117 });
11118 }
11119
11120 let local = self.as_local_mut().unwrap();
11121 for diagnostics in local.diagnostics.values_mut() {
11122 diagnostics.retain(|_, diagnostics_by_server_id| {
11123 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11124 diagnostics_by_server_id.remove(ix);
11125 !diagnostics_by_server_id.is_empty()
11126 } else {
11127 true
11128 }
11129 });
11130 }
11131 local.language_server_watched_paths.remove(&server_id);
11132
11133 let server_state = local.language_servers.remove(&server_id);
11134 self.cleanup_lsp_data(server_id);
11135 let name = self
11136 .language_server_statuses
11137 .remove(&server_id)
11138 .map(|status| status.name)
11139 .or_else(|| {
11140 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11141 Some(adapter.name())
11142 } else {
11143 None
11144 }
11145 });
11146
11147 if let Some(name) = name {
11148 log::info!("stopping language server {name}");
11149 self.languages
11150 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11151 cx.notify();
11152
11153 return cx.spawn(async move |lsp_store, cx| {
11154 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11155 lsp_store
11156 .update(cx, |lsp_store, cx| {
11157 lsp_store
11158 .languages
11159 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11160 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11161 cx.notify();
11162 })
11163 .ok();
11164 });
11165 }
11166
11167 if server_state.is_some() {
11168 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11169 }
11170 Task::ready(())
11171 }
11172
11173 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11174 self.shutdown_all_language_servers(cx).detach();
11175 }
11176
11177 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11178 if let Some((client, project_id)) = self.upstream_client() {
11179 let request = client.request(proto::StopLanguageServers {
11180 project_id,
11181 buffer_ids: Vec::new(),
11182 also_servers: Vec::new(),
11183 all: true,
11184 });
11185 cx.background_spawn(async move {
11186 request.await.ok();
11187 })
11188 } else {
11189 let Some(local) = self.as_local_mut() else {
11190 return Task::ready(());
11191 };
11192 let language_servers_to_stop = local
11193 .language_server_ids
11194 .values()
11195 .map(|state| state.id)
11196 .collect();
11197 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11198 let tasks = language_servers_to_stop
11199 .into_iter()
11200 .map(|server| self.stop_local_language_server(server, cx))
11201 .collect::<Vec<_>>();
11202 cx.background_spawn(async move {
11203 futures::future::join_all(tasks).await;
11204 })
11205 }
11206 }
11207
11208 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11209 let buffers = self.buffer_store.read(cx).buffers().collect();
11210 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11211 }
11212
11213 pub fn restart_language_servers_for_buffers(
11214 &mut self,
11215 buffers: Vec<Entity<Buffer>>,
11216 only_restart_servers: HashSet<LanguageServerSelector>,
11217 cx: &mut Context<Self>,
11218 ) {
11219 if let Some((client, project_id)) = self.upstream_client() {
11220 let request = client.request(proto::RestartLanguageServers {
11221 project_id,
11222 buffer_ids: buffers
11223 .into_iter()
11224 .map(|b| b.read(cx).remote_id().to_proto())
11225 .collect(),
11226 only_servers: only_restart_servers
11227 .into_iter()
11228 .map(|selector| {
11229 let selector = match selector {
11230 LanguageServerSelector::Id(language_server_id) => {
11231 proto::language_server_selector::Selector::ServerId(
11232 language_server_id.to_proto(),
11233 )
11234 }
11235 LanguageServerSelector::Name(language_server_name) => {
11236 proto::language_server_selector::Selector::Name(
11237 language_server_name.to_string(),
11238 )
11239 }
11240 };
11241 proto::LanguageServerSelector {
11242 selector: Some(selector),
11243 }
11244 })
11245 .collect(),
11246 all: false,
11247 });
11248 cx.background_spawn(request).detach_and_log_err(cx);
11249 } else {
11250 let stop_task = if only_restart_servers.is_empty() {
11251 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11252 } else {
11253 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11254 };
11255 cx.spawn(async move |lsp_store, cx| {
11256 stop_task.await;
11257 lsp_store.update(cx, |lsp_store, cx| {
11258 for buffer in buffers {
11259 lsp_store.register_buffer_with_language_servers(
11260 &buffer,
11261 only_restart_servers.clone(),
11262 true,
11263 cx,
11264 );
11265 }
11266 })
11267 })
11268 .detach();
11269 }
11270 }
11271
11272 pub fn stop_language_servers_for_buffers(
11273 &mut self,
11274 buffers: Vec<Entity<Buffer>>,
11275 also_stop_servers: HashSet<LanguageServerSelector>,
11276 cx: &mut Context<Self>,
11277 ) -> Task<Result<()>> {
11278 if let Some((client, project_id)) = self.upstream_client() {
11279 let request = client.request(proto::StopLanguageServers {
11280 project_id,
11281 buffer_ids: buffers
11282 .into_iter()
11283 .map(|b| b.read(cx).remote_id().to_proto())
11284 .collect(),
11285 also_servers: also_stop_servers
11286 .into_iter()
11287 .map(|selector| {
11288 let selector = match selector {
11289 LanguageServerSelector::Id(language_server_id) => {
11290 proto::language_server_selector::Selector::ServerId(
11291 language_server_id.to_proto(),
11292 )
11293 }
11294 LanguageServerSelector::Name(language_server_name) => {
11295 proto::language_server_selector::Selector::Name(
11296 language_server_name.to_string(),
11297 )
11298 }
11299 };
11300 proto::LanguageServerSelector {
11301 selector: Some(selector),
11302 }
11303 })
11304 .collect(),
11305 all: false,
11306 });
11307 cx.background_spawn(async move {
11308 let _ = request.await?;
11309 Ok(())
11310 })
11311 } else {
11312 let task =
11313 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11314 cx.background_spawn(async move {
11315 task.await;
11316 Ok(())
11317 })
11318 }
11319 }
11320
11321 fn stop_local_language_servers_for_buffers(
11322 &mut self,
11323 buffers: &[Entity<Buffer>],
11324 also_stop_servers: HashSet<LanguageServerSelector>,
11325 cx: &mut Context<Self>,
11326 ) -> Task<()> {
11327 let Some(local) = self.as_local_mut() else {
11328 return Task::ready(());
11329 };
11330 let mut language_server_names_to_stop = BTreeSet::default();
11331 let mut language_servers_to_stop = also_stop_servers
11332 .into_iter()
11333 .flat_map(|selector| match selector {
11334 LanguageServerSelector::Id(id) => Some(id),
11335 LanguageServerSelector::Name(name) => {
11336 language_server_names_to_stop.insert(name);
11337 None
11338 }
11339 })
11340 .collect::<BTreeSet<_>>();
11341
11342 let mut covered_worktrees = HashSet::default();
11343 for buffer in buffers {
11344 buffer.update(cx, |buffer, cx| {
11345 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11346 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11347 && covered_worktrees.insert(worktree_id)
11348 {
11349 language_server_names_to_stop.retain(|name| {
11350 let old_ids_count = language_servers_to_stop.len();
11351 let all_language_servers_with_this_name = local
11352 .language_server_ids
11353 .iter()
11354 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11355 language_servers_to_stop.extend(all_language_servers_with_this_name);
11356 old_ids_count == language_servers_to_stop.len()
11357 });
11358 }
11359 });
11360 }
11361 for name in language_server_names_to_stop {
11362 language_servers_to_stop.extend(
11363 local
11364 .language_server_ids
11365 .iter()
11366 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11367 );
11368 }
11369
11370 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11371 let tasks = language_servers_to_stop
11372 .into_iter()
11373 .map(|server| self.stop_local_language_server(server, cx))
11374 .collect::<Vec<_>>();
11375
11376 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11377 }
11378
11379 #[cfg(any(test, feature = "test-support"))]
11380 pub fn update_diagnostics(
11381 &mut self,
11382 server_id: LanguageServerId,
11383 diagnostics: lsp::PublishDiagnosticsParams,
11384 result_id: Option<SharedString>,
11385 source_kind: DiagnosticSourceKind,
11386 disk_based_sources: &[String],
11387 cx: &mut Context<Self>,
11388 ) -> Result<()> {
11389 self.merge_lsp_diagnostics(
11390 source_kind,
11391 vec![DocumentDiagnosticsUpdate {
11392 diagnostics,
11393 result_id,
11394 server_id,
11395 disk_based_sources: Cow::Borrowed(disk_based_sources),
11396 registration_id: None,
11397 }],
11398 |_, _, _| false,
11399 cx,
11400 )
11401 }
11402
11403 pub fn merge_lsp_diagnostics(
11404 &mut self,
11405 source_kind: DiagnosticSourceKind,
11406 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11407 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11408 cx: &mut Context<Self>,
11409 ) -> Result<()> {
11410 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11411 let updates = lsp_diagnostics
11412 .into_iter()
11413 .filter_map(|update| {
11414 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11415 Some(DocumentDiagnosticsUpdate {
11416 diagnostics: self.lsp_to_document_diagnostics(
11417 abs_path,
11418 source_kind,
11419 update.server_id,
11420 update.diagnostics,
11421 &update.disk_based_sources,
11422 update.registration_id.clone(),
11423 ),
11424 result_id: update.result_id,
11425 server_id: update.server_id,
11426 disk_based_sources: update.disk_based_sources,
11427 registration_id: update.registration_id,
11428 })
11429 })
11430 .collect();
11431 self.merge_diagnostic_entries(updates, merge, cx)?;
11432 Ok(())
11433 }
11434
11435 fn lsp_to_document_diagnostics(
11436 &mut self,
11437 document_abs_path: PathBuf,
11438 source_kind: DiagnosticSourceKind,
11439 server_id: LanguageServerId,
11440 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11441 disk_based_sources: &[String],
11442 registration_id: Option<SharedString>,
11443 ) -> DocumentDiagnostics {
11444 let mut diagnostics = Vec::default();
11445 let mut primary_diagnostic_group_ids = HashMap::default();
11446 let mut sources_by_group_id = HashMap::default();
11447 let mut supporting_diagnostics = HashMap::default();
11448
11449 let adapter = self.language_server_adapter_for_id(server_id);
11450
11451 // Ensure that primary diagnostics are always the most severe
11452 lsp_diagnostics
11453 .diagnostics
11454 .sort_by_key(|item| item.severity);
11455
11456 for diagnostic in &lsp_diagnostics.diagnostics {
11457 let source = diagnostic.source.as_ref();
11458 let range = range_from_lsp(diagnostic.range);
11459 let is_supporting = diagnostic
11460 .related_information
11461 .as_ref()
11462 .is_some_and(|infos| {
11463 infos.iter().any(|info| {
11464 primary_diagnostic_group_ids.contains_key(&(
11465 source,
11466 diagnostic.code.clone(),
11467 range_from_lsp(info.location.range),
11468 ))
11469 })
11470 });
11471
11472 let is_unnecessary = diagnostic
11473 .tags
11474 .as_ref()
11475 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11476
11477 let underline = self
11478 .language_server_adapter_for_id(server_id)
11479 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11480
11481 if is_supporting {
11482 supporting_diagnostics.insert(
11483 (source, diagnostic.code.clone(), range),
11484 (diagnostic.severity, is_unnecessary),
11485 );
11486 } else {
11487 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11488 let is_disk_based =
11489 source.is_some_and(|source| disk_based_sources.contains(source));
11490
11491 sources_by_group_id.insert(group_id, source);
11492 primary_diagnostic_group_ids
11493 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11494
11495 diagnostics.push(DiagnosticEntry {
11496 range,
11497 diagnostic: Diagnostic {
11498 source: diagnostic.source.clone(),
11499 source_kind,
11500 code: diagnostic.code.clone(),
11501 code_description: diagnostic
11502 .code_description
11503 .as_ref()
11504 .and_then(|d| d.href.clone()),
11505 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11506 markdown: adapter.as_ref().and_then(|adapter| {
11507 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11508 }),
11509 message: diagnostic.message.trim().to_string(),
11510 group_id,
11511 is_primary: true,
11512 is_disk_based,
11513 is_unnecessary,
11514 underline,
11515 data: diagnostic.data.clone(),
11516 registration_id: registration_id.clone(),
11517 },
11518 });
11519 if let Some(infos) = &diagnostic.related_information {
11520 for info in infos {
11521 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11522 let range = range_from_lsp(info.location.range);
11523 diagnostics.push(DiagnosticEntry {
11524 range,
11525 diagnostic: Diagnostic {
11526 source: diagnostic.source.clone(),
11527 source_kind,
11528 code: diagnostic.code.clone(),
11529 code_description: diagnostic
11530 .code_description
11531 .as_ref()
11532 .and_then(|d| d.href.clone()),
11533 severity: DiagnosticSeverity::INFORMATION,
11534 markdown: adapter.as_ref().and_then(|adapter| {
11535 adapter.diagnostic_message_to_markdown(&info.message)
11536 }),
11537 message: info.message.trim().to_string(),
11538 group_id,
11539 is_primary: false,
11540 is_disk_based,
11541 is_unnecessary: false,
11542 underline,
11543 data: diagnostic.data.clone(),
11544 registration_id: registration_id.clone(),
11545 },
11546 });
11547 }
11548 }
11549 }
11550 }
11551 }
11552
11553 for entry in &mut diagnostics {
11554 let diagnostic = &mut entry.diagnostic;
11555 if !diagnostic.is_primary {
11556 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11557 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11558 source,
11559 diagnostic.code.clone(),
11560 entry.range.clone(),
11561 )) {
11562 if let Some(severity) = severity {
11563 diagnostic.severity = severity;
11564 }
11565 diagnostic.is_unnecessary = is_unnecessary;
11566 }
11567 }
11568 }
11569
11570 DocumentDiagnostics {
11571 diagnostics,
11572 document_abs_path,
11573 version: lsp_diagnostics.version,
11574 }
11575 }
11576
11577 fn insert_newly_running_language_server(
11578 &mut self,
11579 adapter: Arc<CachedLspAdapter>,
11580 language_server: Arc<LanguageServer>,
11581 server_id: LanguageServerId,
11582 key: LanguageServerSeed,
11583 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11584 cx: &mut Context<Self>,
11585 ) {
11586 let Some(local) = self.as_local_mut() else {
11587 return;
11588 };
11589 // If the language server for this key doesn't match the server id, don't store the
11590 // server. Which will cause it to be dropped, killing the process
11591 if local
11592 .language_server_ids
11593 .get(&key)
11594 .map(|state| state.id != server_id)
11595 .unwrap_or(false)
11596 {
11597 return;
11598 }
11599
11600 // Update language_servers collection with Running variant of LanguageServerState
11601 // indicating that the server is up and running and ready
11602 let workspace_folders = workspace_folders.lock().clone();
11603 language_server.set_workspace_folders(workspace_folders);
11604
11605 let workspace_diagnostics_refresh_tasks = language_server
11606 .capabilities()
11607 .diagnostic_provider
11608 .and_then(|provider| {
11609 local
11610 .language_server_dynamic_registrations
11611 .entry(server_id)
11612 .or_default()
11613 .diagnostics
11614 .entry(None)
11615 .or_insert(provider.clone());
11616 let workspace_refresher =
11617 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11618
11619 Some((None, workspace_refresher))
11620 })
11621 .into_iter()
11622 .collect();
11623 local.language_servers.insert(
11624 server_id,
11625 LanguageServerState::Running {
11626 workspace_diagnostics_refresh_tasks,
11627 adapter: adapter.clone(),
11628 server: language_server.clone(),
11629 simulate_disk_based_diagnostics_completion: None,
11630 },
11631 );
11632 local
11633 .languages
11634 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11635 if let Some(file_ops_caps) = language_server
11636 .capabilities()
11637 .workspace
11638 .as_ref()
11639 .and_then(|ws| ws.file_operations.as_ref())
11640 {
11641 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11642 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11643 if did_rename_caps.or(will_rename_caps).is_some() {
11644 let watcher = RenamePathsWatchedForServer::default()
11645 .with_did_rename_patterns(did_rename_caps)
11646 .with_will_rename_patterns(will_rename_caps);
11647 local
11648 .language_server_paths_watched_for_rename
11649 .insert(server_id, watcher);
11650 }
11651 }
11652
11653 self.language_server_statuses.insert(
11654 server_id,
11655 LanguageServerStatus {
11656 name: language_server.name(),
11657 server_version: language_server.version(),
11658 server_readable_version: language_server.readable_version(),
11659 pending_work: Default::default(),
11660 has_pending_diagnostic_updates: false,
11661 progress_tokens: Default::default(),
11662 worktree: Some(key.worktree_id),
11663 binary: Some(language_server.binary().clone()),
11664 configuration: Some(language_server.configuration().clone()),
11665 workspace_folders: language_server.workspace_folders(),
11666 process_id: language_server.process_id(),
11667 },
11668 );
11669
11670 cx.emit(LspStoreEvent::LanguageServerAdded(
11671 server_id,
11672 language_server.name(),
11673 Some(key.worktree_id),
11674 ));
11675
11676 let server_capabilities = language_server.capabilities();
11677 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11678 downstream_client
11679 .send(proto::StartLanguageServer {
11680 project_id: *project_id,
11681 server: Some(proto::LanguageServer {
11682 id: server_id.to_proto(),
11683 name: language_server.name().to_string(),
11684 worktree_id: Some(key.worktree_id.to_proto()),
11685 }),
11686 capabilities: serde_json::to_string(&server_capabilities)
11687 .expect("serializing server LSP capabilities"),
11688 })
11689 .log_err();
11690 }
11691 self.lsp_server_capabilities
11692 .insert(server_id, server_capabilities);
11693
11694 // Tell the language server about every open buffer in the worktree that matches the language.
11695 // Also check for buffers in worktrees that reused this server
11696 let mut worktrees_using_server = vec![key.worktree_id];
11697 if let Some(local) = self.as_local() {
11698 // Find all worktrees that have this server in their language server tree
11699 for (worktree_id, servers) in &local.lsp_tree.instances {
11700 if *worktree_id != key.worktree_id {
11701 for server_map in servers.roots.values() {
11702 if server_map
11703 .values()
11704 .any(|(node, _)| node.id() == Some(server_id))
11705 {
11706 worktrees_using_server.push(*worktree_id);
11707 }
11708 }
11709 }
11710 }
11711 }
11712
11713 let mut buffer_paths_registered = Vec::new();
11714 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11715 let mut lsp_adapters = HashMap::default();
11716 for buffer_handle in buffer_store.buffers() {
11717 let buffer = buffer_handle.read(cx);
11718 let file = match File::from_dyn(buffer.file()) {
11719 Some(file) => file,
11720 None => continue,
11721 };
11722 let language = match buffer.language() {
11723 Some(language) => language,
11724 None => continue,
11725 };
11726
11727 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11728 || !lsp_adapters
11729 .entry(language.name())
11730 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11731 .iter()
11732 .any(|a| a.name == key.name)
11733 {
11734 continue;
11735 }
11736 // didOpen
11737 let file = match file.as_local() {
11738 Some(file) => file,
11739 None => continue,
11740 };
11741
11742 let local = self.as_local_mut().unwrap();
11743
11744 let buffer_id = buffer.remote_id();
11745 if local.registered_buffers.contains_key(&buffer_id) {
11746 let abs_path = file.abs_path(cx);
11747 let uri = match lsp::Uri::from_file_path(&abs_path) {
11748 Ok(uri) => uri,
11749 Err(()) => {
11750 log::error!("failed to convert path to URI: {:?}", abs_path);
11751 continue;
11752 }
11753 };
11754
11755 let versions = local
11756 .buffer_snapshots
11757 .entry(buffer_id)
11758 .or_default()
11759 .entry(server_id)
11760 .and_modify(|_| {
11761 assert!(
11762 false,
11763 "There should not be an existing snapshot for a newly inserted buffer"
11764 )
11765 })
11766 .or_insert_with(|| {
11767 vec![LspBufferSnapshot {
11768 version: 0,
11769 snapshot: buffer.text_snapshot(),
11770 }]
11771 });
11772
11773 let snapshot = versions.last().unwrap();
11774 let version = snapshot.version;
11775 let initial_snapshot = &snapshot.snapshot;
11776 language_server.register_buffer(
11777 uri,
11778 adapter.language_id(&language.name()),
11779 version,
11780 initial_snapshot.text(),
11781 );
11782 buffer_paths_registered.push((buffer_id, abs_path));
11783 local
11784 .buffers_opened_in_servers
11785 .entry(buffer_id)
11786 .or_default()
11787 .insert(server_id);
11788 }
11789 buffer_handle.update(cx, |buffer, cx| {
11790 buffer.set_completion_triggers(
11791 server_id,
11792 language_server
11793 .capabilities()
11794 .completion_provider
11795 .as_ref()
11796 .and_then(|provider| {
11797 provider
11798 .trigger_characters
11799 .as_ref()
11800 .map(|characters| characters.iter().cloned().collect())
11801 })
11802 .unwrap_or_default(),
11803 cx,
11804 )
11805 });
11806 }
11807 });
11808
11809 for (buffer_id, abs_path) in buffer_paths_registered {
11810 cx.emit(LspStoreEvent::LanguageServerUpdate {
11811 language_server_id: server_id,
11812 name: Some(adapter.name()),
11813 message: proto::update_language_server::Variant::RegisteredForBuffer(
11814 proto::RegisteredForBuffer {
11815 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11816 buffer_id: buffer_id.to_proto(),
11817 },
11818 ),
11819 });
11820 }
11821
11822 cx.notify();
11823 }
11824
11825 pub fn language_servers_running_disk_based_diagnostics(
11826 &self,
11827 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11828 self.language_server_statuses
11829 .iter()
11830 .filter_map(|(id, status)| {
11831 if status.has_pending_diagnostic_updates {
11832 Some(*id)
11833 } else {
11834 None
11835 }
11836 })
11837 }
11838
11839 pub(crate) fn cancel_language_server_work_for_buffers(
11840 &mut self,
11841 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11842 cx: &mut Context<Self>,
11843 ) {
11844 if let Some((client, project_id)) = self.upstream_client() {
11845 let request = client.request(proto::CancelLanguageServerWork {
11846 project_id,
11847 work: Some(proto::cancel_language_server_work::Work::Buffers(
11848 proto::cancel_language_server_work::Buffers {
11849 buffer_ids: buffers
11850 .into_iter()
11851 .map(|b| b.read(cx).remote_id().to_proto())
11852 .collect(),
11853 },
11854 )),
11855 });
11856 cx.background_spawn(request).detach_and_log_err(cx);
11857 } else if let Some(local) = self.as_local() {
11858 let servers = buffers
11859 .into_iter()
11860 .flat_map(|buffer| {
11861 buffer.update(cx, |buffer, cx| {
11862 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11863 })
11864 })
11865 .collect::<HashSet<_>>();
11866 for server_id in servers {
11867 self.cancel_language_server_work(server_id, None, cx);
11868 }
11869 }
11870 }
11871
11872 pub(crate) fn cancel_language_server_work(
11873 &mut self,
11874 server_id: LanguageServerId,
11875 token_to_cancel: Option<ProgressToken>,
11876 cx: &mut Context<Self>,
11877 ) {
11878 if let Some(local) = self.as_local() {
11879 let status = self.language_server_statuses.get(&server_id);
11880 let server = local.language_servers.get(&server_id);
11881 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11882 {
11883 for (token, progress) in &status.pending_work {
11884 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11885 && token != token_to_cancel
11886 {
11887 continue;
11888 }
11889 if progress.is_cancellable {
11890 server
11891 .notify::<lsp::notification::WorkDoneProgressCancel>(
11892 WorkDoneProgressCancelParams {
11893 token: token.to_lsp(),
11894 },
11895 )
11896 .ok();
11897 }
11898 }
11899 }
11900 } else if let Some((client, project_id)) = self.upstream_client() {
11901 let request = client.request(proto::CancelLanguageServerWork {
11902 project_id,
11903 work: Some(
11904 proto::cancel_language_server_work::Work::LanguageServerWork(
11905 proto::cancel_language_server_work::LanguageServerWork {
11906 language_server_id: server_id.to_proto(),
11907 token: token_to_cancel.map(|token| token.to_proto()),
11908 },
11909 ),
11910 ),
11911 });
11912 cx.background_spawn(request).detach_and_log_err(cx);
11913 }
11914 }
11915
11916 fn register_supplementary_language_server(
11917 &mut self,
11918 id: LanguageServerId,
11919 name: LanguageServerName,
11920 server: Arc<LanguageServer>,
11921 cx: &mut Context<Self>,
11922 ) {
11923 if let Some(local) = self.as_local_mut() {
11924 local
11925 .supplementary_language_servers
11926 .insert(id, (name.clone(), server));
11927 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11928 }
11929 }
11930
11931 fn unregister_supplementary_language_server(
11932 &mut self,
11933 id: LanguageServerId,
11934 cx: &mut Context<Self>,
11935 ) {
11936 if let Some(local) = self.as_local_mut() {
11937 local.supplementary_language_servers.remove(&id);
11938 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11939 }
11940 }
11941
11942 pub(crate) fn supplementary_language_servers(
11943 &self,
11944 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11945 self.as_local().into_iter().flat_map(|local| {
11946 local
11947 .supplementary_language_servers
11948 .iter()
11949 .map(|(id, (name, _))| (*id, name.clone()))
11950 })
11951 }
11952
11953 pub fn language_server_adapter_for_id(
11954 &self,
11955 id: LanguageServerId,
11956 ) -> Option<Arc<CachedLspAdapter>> {
11957 if let Some(local) = self.as_local()
11958 && let Some(LanguageServerState::Running { adapter, .. }) =
11959 local.language_servers.get(&id)
11960 {
11961 return Some(adapter.clone());
11962 }
11963 // In remote (SSH/collab) mode there are no local `language_servers`, but
11964 // `language_server_statuses` is kept in sync with the upstream and carries each
11965 // server's registered name, which is enough to look the adapter up in the registry.
11966 let name = &self.language_server_statuses.get(&id)?.name;
11967 self.languages.adapter_for_name(name)
11968 }
11969
11970 pub(super) fn update_local_worktree_language_servers(
11971 &mut self,
11972 worktree_handle: &Entity<Worktree>,
11973 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11974 cx: &mut Context<Self>,
11975 ) {
11976 if changes.is_empty() {
11977 return;
11978 }
11979
11980 let Some(local) = self.as_local() else { return };
11981
11982 local.prettier_store.update(cx, |prettier_store, cx| {
11983 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11984 });
11985
11986 let worktree_id = worktree_handle.read(cx).id();
11987 let mut language_server_ids = local
11988 .language_server_ids
11989 .iter()
11990 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11991 .collect::<Vec<_>>();
11992 language_server_ids.sort();
11993 language_server_ids.dedup();
11994
11995 // let abs_path = worktree_handle.read(cx).abs_path();
11996 for server_id in &language_server_ids {
11997 if let Some(LanguageServerState::Running { server, .. }) =
11998 local.language_servers.get(server_id)
11999 && let Some(watched_paths) = local
12000 .language_server_watched_paths
12001 .get(server_id)
12002 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
12003 {
12004 let params = lsp::DidChangeWatchedFilesParams {
12005 changes: changes
12006 .iter()
12007 .filter_map(|(path, _, change)| {
12008 if !watched_paths.is_match(path.as_std_path()) {
12009 return None;
12010 }
12011 let typ = match change {
12012 PathChange::Loaded => return None,
12013 PathChange::Added => lsp::FileChangeType::CREATED,
12014 PathChange::Removed => lsp::FileChangeType::DELETED,
12015 PathChange::Updated => lsp::FileChangeType::CHANGED,
12016 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
12017 };
12018 let uri = lsp::Uri::from_file_path(
12019 worktree_handle.read(cx).absolutize(&path),
12020 )
12021 .ok()?;
12022 Some(lsp::FileEvent { uri, typ })
12023 })
12024 .collect(),
12025 };
12026 if !params.changes.is_empty() {
12027 server
12028 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
12029 .ok();
12030 }
12031 }
12032 }
12033 for (path, _, _) in changes {
12034 if let Some(file_name) = path.file_name()
12035 && local.watched_manifest_filenames.contains(file_name)
12036 {
12037 self.request_workspace_config_refresh();
12038 break;
12039 }
12040 }
12041 }
12042
12043 pub fn wait_for_remote_buffer(
12044 &mut self,
12045 id: BufferId,
12046 cx: &mut Context<Self>,
12047 ) -> Task<Result<Entity<Buffer>>> {
12048 self.buffer_store.update(cx, |buffer_store, cx| {
12049 buffer_store.wait_for_remote_buffer(id, cx)
12050 })
12051 }
12052
12053 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
12054 let mut result = proto::Symbol {
12055 language_server_name: symbol.language_server_name.0.to_string(),
12056 source_worktree_id: symbol.source_worktree_id.to_proto(),
12057 language_server_id: symbol.source_language_server_id.to_proto(),
12058 name: symbol.name.clone(),
12059 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
12060 start: Some(proto::PointUtf16 {
12061 row: symbol.range.start.0.row,
12062 column: symbol.range.start.0.column,
12063 }),
12064 end: Some(proto::PointUtf16 {
12065 row: symbol.range.end.0.row,
12066 column: symbol.range.end.0.column,
12067 }),
12068 worktree_id: Default::default(),
12069 path: Default::default(),
12070 signature: Default::default(),
12071 container_name: symbol.container_name.clone(),
12072 };
12073 match &symbol.path {
12074 SymbolLocation::InProject(path) => {
12075 result.worktree_id = path.worktree_id.to_proto();
12076 result.path = path.path.to_proto();
12077 }
12078 SymbolLocation::OutsideProject {
12079 abs_path,
12080 signature,
12081 } => {
12082 result.path = abs_path.to_string_lossy().into_owned();
12083 result.signature = signature.to_vec();
12084 }
12085 }
12086 result
12087 }
12088
12089 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
12090 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
12091 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
12092 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
12093
12094 let path = if serialized_symbol.signature.is_empty() {
12095 SymbolLocation::InProject(ProjectPath {
12096 worktree_id,
12097 path: RelPath::from_proto(&serialized_symbol.path)
12098 .context("invalid symbol path")?,
12099 })
12100 } else {
12101 SymbolLocation::OutsideProject {
12102 abs_path: Path::new(&serialized_symbol.path).into(),
12103 signature: serialized_symbol
12104 .signature
12105 .try_into()
12106 .map_err(|_| anyhow!("invalid signature"))?,
12107 }
12108 };
12109
12110 let start = serialized_symbol.start.context("invalid start")?;
12111 let end = serialized_symbol.end.context("invalid end")?;
12112 Ok(CoreSymbol {
12113 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
12114 source_worktree_id,
12115 source_language_server_id: LanguageServerId::from_proto(
12116 serialized_symbol.language_server_id,
12117 ),
12118 path,
12119 name: serialized_symbol.name,
12120 range: Unclipped(PointUtf16::new(start.row, start.column))
12121 ..Unclipped(PointUtf16::new(end.row, end.column)),
12122 kind,
12123 container_name: serialized_symbol.container_name,
12124 })
12125 }
12126
12127 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12128 let mut serialized_completion = proto::Completion {
12129 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12130 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12131 new_text: completion.new_text.clone(),
12132 ..proto::Completion::default()
12133 };
12134 match &completion.source {
12135 CompletionSource::Lsp {
12136 insert_range,
12137 server_id,
12138 lsp_completion,
12139 lsp_defaults,
12140 resolved,
12141 } => {
12142 let (old_insert_start, old_insert_end) = insert_range
12143 .as_ref()
12144 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12145 .unzip();
12146
12147 serialized_completion.old_insert_start = old_insert_start;
12148 serialized_completion.old_insert_end = old_insert_end;
12149 serialized_completion.source = proto::completion::Source::Lsp as i32;
12150 serialized_completion.server_id = server_id.0 as u64;
12151 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12152 serialized_completion.lsp_defaults = lsp_defaults
12153 .as_deref()
12154 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12155 serialized_completion.resolved = *resolved;
12156 }
12157 CompletionSource::BufferWord {
12158 word_range,
12159 resolved,
12160 } => {
12161 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12162 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12163 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12164 serialized_completion.resolved = *resolved;
12165 }
12166 CompletionSource::Custom => {
12167 serialized_completion.source = proto::completion::Source::Custom as i32;
12168 serialized_completion.resolved = true;
12169 }
12170 CompletionSource::Dap { sort_text } => {
12171 serialized_completion.source = proto::completion::Source::Dap as i32;
12172 serialized_completion.sort_text = Some(sort_text.clone());
12173 }
12174 }
12175
12176 serialized_completion
12177 }
12178
12179 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12180 let old_replace_start = completion
12181 .old_replace_start
12182 .and_then(deserialize_anchor)
12183 .context("invalid old start")?;
12184 let old_replace_end = completion
12185 .old_replace_end
12186 .and_then(deserialize_anchor)
12187 .context("invalid old end")?;
12188 let insert_range = {
12189 match completion.old_insert_start.zip(completion.old_insert_end) {
12190 Some((start, end)) => {
12191 let start = deserialize_anchor(start).context("invalid insert old start")?;
12192 let end = deserialize_anchor(end).context("invalid insert old end")?;
12193 Some(start..end)
12194 }
12195 None => None,
12196 }
12197 };
12198 Ok(CoreCompletion {
12199 replace_range: old_replace_start..old_replace_end,
12200 new_text: completion.new_text,
12201 source: match proto::completion::Source::from_i32(completion.source) {
12202 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12203 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12204 insert_range,
12205 server_id: LanguageServerId::from_proto(completion.server_id),
12206 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12207 lsp_defaults: completion
12208 .lsp_defaults
12209 .as_deref()
12210 .map(serde_json::from_slice)
12211 .transpose()?,
12212 resolved: completion.resolved,
12213 },
12214 Some(proto::completion::Source::BufferWord) => {
12215 let word_range = completion
12216 .buffer_word_start
12217 .and_then(deserialize_anchor)
12218 .context("invalid buffer word start")?
12219 ..completion
12220 .buffer_word_end
12221 .and_then(deserialize_anchor)
12222 .context("invalid buffer word end")?;
12223 CompletionSource::BufferWord {
12224 word_range,
12225 resolved: completion.resolved,
12226 }
12227 }
12228 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12229 sort_text: completion
12230 .sort_text
12231 .context("expected sort text to exist")?,
12232 },
12233 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12234 },
12235 })
12236 }
12237
12238 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12239 let (kind, lsp_action) = match &action.lsp_action {
12240 LspAction::Action(code_action) => (
12241 proto::code_action::Kind::Action as i32,
12242 serde_json::to_vec(code_action).unwrap(),
12243 ),
12244 LspAction::Command(command) => (
12245 proto::code_action::Kind::Command as i32,
12246 serde_json::to_vec(command).unwrap(),
12247 ),
12248 LspAction::CodeLens(code_lens) => (
12249 proto::code_action::Kind::CodeLens as i32,
12250 serde_json::to_vec(code_lens).unwrap(),
12251 ),
12252 };
12253
12254 proto::CodeAction {
12255 server_id: action.server_id.0 as u64,
12256 start: Some(serialize_anchor(&action.range.start)),
12257 end: Some(serialize_anchor(&action.range.end)),
12258 lsp_action,
12259 kind,
12260 resolved: action.resolved,
12261 }
12262 }
12263
12264 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12265 let start = action
12266 .start
12267 .and_then(deserialize_anchor)
12268 .context("invalid start")?;
12269 let end = action
12270 .end
12271 .and_then(deserialize_anchor)
12272 .context("invalid end")?;
12273 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12274 Some(proto::code_action::Kind::Action) => {
12275 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12276 }
12277 Some(proto::code_action::Kind::Command) => {
12278 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12279 }
12280 Some(proto::code_action::Kind::CodeLens) => {
12281 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12282 }
12283 None => anyhow::bail!("Unknown action kind {}", action.kind),
12284 };
12285 Ok(CodeAction {
12286 server_id: LanguageServerId(action.server_id as usize),
12287 range: start..end,
12288 resolved: action.resolved,
12289 lsp_action,
12290 })
12291 }
12292
12293 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12294 match &formatting_result {
12295 Ok(_) => self.last_formatting_failure = None,
12296 Err(error) => {
12297 let error_string = format!("{error:#}");
12298 log::error!("Formatting failed: {error_string}");
12299 self.last_formatting_failure
12300 .replace(error_string.lines().join(" "));
12301 }
12302 }
12303 }
12304
12305 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12306 self.lsp_server_capabilities.remove(&for_server);
12307 self.semantic_token_config.remove_server_data(for_server);
12308 for lsp_data in self.lsp_data.values_mut() {
12309 lsp_data.remove_server_data(for_server);
12310 }
12311 if let Some(local) = self.as_local_mut() {
12312 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12313 local
12314 .workspace_pull_diagnostics_result_ids
12315 .remove(&for_server);
12316 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12317 buffer_servers.remove(&for_server);
12318 }
12319 }
12320 }
12321
12322 pub fn result_id_for_buffer_pull(
12323 &self,
12324 server_id: LanguageServerId,
12325 buffer_id: BufferId,
12326 registration_id: &Option<SharedString>,
12327 cx: &App,
12328 ) -> Option<SharedString> {
12329 let abs_path = self
12330 .buffer_store
12331 .read(cx)
12332 .get(buffer_id)
12333 .and_then(|b| File::from_dyn(b.read(cx).file()))
12334 .map(|f| f.abs_path(cx))?;
12335 self.as_local()?
12336 .buffer_pull_diagnostics_result_ids
12337 .get(&server_id)?
12338 .get(registration_id)?
12339 .get(&abs_path)?
12340 .clone()
12341 }
12342
12343 /// Gets all result_ids for a workspace diagnostics pull request.
12344 /// 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.
12345 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12346 pub fn result_ids_for_workspace_refresh(
12347 &self,
12348 server_id: LanguageServerId,
12349 registration_id: &Option<SharedString>,
12350 ) -> HashMap<PathBuf, SharedString> {
12351 let Some(local) = self.as_local() else {
12352 return HashMap::default();
12353 };
12354 local
12355 .workspace_pull_diagnostics_result_ids
12356 .get(&server_id)
12357 .into_iter()
12358 .filter_map(|diagnostics| diagnostics.get(registration_id))
12359 .flatten()
12360 .filter_map(|(abs_path, result_id)| {
12361 let result_id = local
12362 .buffer_pull_diagnostics_result_ids
12363 .get(&server_id)
12364 .and_then(|buffer_ids_result_ids| {
12365 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12366 })
12367 .cloned()
12368 .flatten()
12369 .or_else(|| result_id.clone())?;
12370 Some((abs_path.clone(), result_id))
12371 })
12372 .collect()
12373 }
12374
12375 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12376 if let Some(LanguageServerState::Running {
12377 workspace_diagnostics_refresh_tasks,
12378 ..
12379 }) = self
12380 .as_local_mut()
12381 .and_then(|local| local.language_servers.get_mut(&server_id))
12382 {
12383 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12384 diagnostics.refresh_tx.try_send(()).ok();
12385 }
12386 }
12387 }
12388
12389 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12390 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12391 /// which requires refreshing both workspace and document diagnostics.
12392 pub fn pull_document_diagnostics_for_server(
12393 &mut self,
12394 server_id: LanguageServerId,
12395 source_buffer_id: Option<BufferId>,
12396 cx: &mut Context<Self>,
12397 ) -> Shared<Task<()>> {
12398 let Some(local) = self.as_local_mut() else {
12399 return Task::ready(()).shared();
12400 };
12401 let mut buffers_to_refresh = HashSet::default();
12402 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12403 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12404 buffers_to_refresh.insert(*buffer_id);
12405 }
12406 }
12407
12408 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12409 }
12410
12411 pub fn pull_document_diagnostics_for_buffer_edit(
12412 &mut self,
12413 buffer_id: BufferId,
12414 cx: &mut Context<Self>,
12415 ) {
12416 let Some(local) = self.as_local_mut() else {
12417 return;
12418 };
12419 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12420 else {
12421 return;
12422 };
12423 for server_id in languages_servers {
12424 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12425 }
12426 }
12427
12428 fn apply_workspace_diagnostic_report(
12429 &mut self,
12430 server_id: LanguageServerId,
12431 report: lsp::WorkspaceDiagnosticReportResult,
12432 registration_id: Option<SharedString>,
12433 cx: &mut Context<Self>,
12434 ) {
12435 let mut workspace_diagnostics =
12436 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12437 report,
12438 server_id,
12439 registration_id,
12440 );
12441 workspace_diagnostics.retain(|d| match &d.diagnostics {
12442 LspPullDiagnostics::Response {
12443 server_id,
12444 registration_id,
12445 ..
12446 } => self.diagnostic_registration_exists(*server_id, registration_id),
12447 LspPullDiagnostics::Default => false,
12448 });
12449 let mut unchanged_buffers = HashMap::default();
12450 let workspace_diagnostics_updates = workspace_diagnostics
12451 .into_iter()
12452 .filter_map(
12453 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12454 LspPullDiagnostics::Response {
12455 server_id,
12456 uri,
12457 diagnostics,
12458 registration_id,
12459 } => Some((
12460 server_id,
12461 uri,
12462 diagnostics,
12463 workspace_diagnostics.version,
12464 registration_id,
12465 )),
12466 LspPullDiagnostics::Default => None,
12467 },
12468 )
12469 .fold(
12470 HashMap::default(),
12471 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12472 let (result_id, diagnostics) = match diagnostics {
12473 PulledDiagnostics::Unchanged { result_id } => {
12474 unchanged_buffers
12475 .entry(new_registration_id.clone())
12476 .or_insert_with(HashSet::default)
12477 .insert(uri.clone());
12478 (Some(result_id), Vec::new())
12479 }
12480 PulledDiagnostics::Changed {
12481 result_id,
12482 diagnostics,
12483 } => (result_id, diagnostics),
12484 };
12485 let disk_based_sources = Cow::Owned(
12486 self.language_server_adapter_for_id(server_id)
12487 .as_ref()
12488 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12489 .unwrap_or(&[])
12490 .to_vec(),
12491 );
12492
12493 let Some(abs_path) = uri.to_file_path().ok() else {
12494 return acc;
12495 };
12496 let Some((worktree, relative_path)) =
12497 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12498 else {
12499 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12500 return acc;
12501 };
12502 let worktree_id = worktree.read(cx).id();
12503 let project_path = ProjectPath {
12504 worktree_id,
12505 path: relative_path,
12506 };
12507 if let Some(local_lsp_store) = self.as_local_mut() {
12508 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12509 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12510 }
12511 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12512 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12513 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12514 acc.entry(server_id)
12515 .or_insert_with(HashMap::default)
12516 .entry(new_registration_id.clone())
12517 .or_insert_with(Vec::new)
12518 .push(DocumentDiagnosticsUpdate {
12519 server_id,
12520 diagnostics: lsp::PublishDiagnosticsParams {
12521 uri,
12522 diagnostics,
12523 version,
12524 },
12525 result_id: result_id.map(SharedString::new),
12526 disk_based_sources,
12527 registration_id: new_registration_id,
12528 });
12529 }
12530 acc
12531 },
12532 );
12533
12534 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12535 for (registration_id, diagnostic_updates) in diagnostic_updates {
12536 self.merge_lsp_diagnostics(
12537 DiagnosticSourceKind::Pulled,
12538 diagnostic_updates,
12539 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12540 DiagnosticSourceKind::Pulled => {
12541 old_diagnostic.registration_id != registration_id
12542 || unchanged_buffers
12543 .get(&old_diagnostic.registration_id)
12544 .is_some_and(|unchanged_buffers| {
12545 unchanged_buffers.contains(&document_uri)
12546 })
12547 }
12548 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12549 },
12550 cx,
12551 )
12552 .log_err();
12553 }
12554 }
12555 }
12556
12557 fn register_server_capabilities(
12558 &mut self,
12559 server_id: LanguageServerId,
12560 params: lsp::RegistrationParams,
12561 cx: &mut Context<Self>,
12562 ) -> anyhow::Result<()> {
12563 let server = self
12564 .language_server_for_id(server_id)
12565 .with_context(|| format!("no server {server_id} found"))?;
12566 for reg in params.registrations {
12567 match reg.method.as_str() {
12568 "workspace/didChangeWatchedFiles" => {
12569 if let Some(options) = reg.register_options {
12570 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12571 let caps = serde_json::from_value(options)?;
12572 local_lsp_store
12573 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12574 true
12575 } else {
12576 false
12577 };
12578 if notify {
12579 notify_server_capabilities_updated(&server, cx);
12580 }
12581 }
12582 }
12583 "workspace/didChangeConfiguration" => {
12584 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12585 }
12586 "workspace/didChangeWorkspaceFolders" => {
12587 // In this case register options is an empty object, we can ignore it
12588 let caps = lsp::WorkspaceFoldersServerCapabilities {
12589 supported: Some(true),
12590 change_notifications: Some(OneOf::Right(reg.id)),
12591 };
12592 server.update_capabilities(|capabilities| {
12593 capabilities
12594 .workspace
12595 .get_or_insert_default()
12596 .workspace_folders = Some(caps);
12597 });
12598 notify_server_capabilities_updated(&server, cx);
12599 }
12600 "workspace/symbol" => {
12601 let options = parse_register_capabilities(reg)?;
12602 server.update_capabilities(|capabilities| {
12603 capabilities.workspace_symbol_provider = Some(options);
12604 });
12605 notify_server_capabilities_updated(&server, cx);
12606 }
12607 "workspace/fileOperations" => {
12608 if let Some(options) = reg.register_options {
12609 let caps = serde_json::from_value(options)?;
12610 server.update_capabilities(|capabilities| {
12611 capabilities
12612 .workspace
12613 .get_or_insert_default()
12614 .file_operations = Some(caps);
12615 });
12616 notify_server_capabilities_updated(&server, cx);
12617 }
12618 }
12619 "workspace/executeCommand" => {
12620 if let Some(options) = reg.register_options {
12621 let options = serde_json::from_value(options)?;
12622 server.update_capabilities(|capabilities| {
12623 capabilities.execute_command_provider = Some(options);
12624 });
12625 notify_server_capabilities_updated(&server, cx);
12626 }
12627 }
12628 "textDocument/rangeFormatting" => {
12629 let options = parse_register_capabilities(reg)?;
12630 server.update_capabilities(|capabilities| {
12631 capabilities.document_range_formatting_provider = Some(options);
12632 });
12633 notify_server_capabilities_updated(&server, cx);
12634 }
12635 "textDocument/onTypeFormatting" => {
12636 if let Some(options) = reg
12637 .register_options
12638 .map(serde_json::from_value)
12639 .transpose()?
12640 {
12641 server.update_capabilities(|capabilities| {
12642 capabilities.document_on_type_formatting_provider = Some(options);
12643 });
12644 notify_server_capabilities_updated(&server, cx);
12645 }
12646 }
12647 "textDocument/formatting" => {
12648 let options = parse_register_capabilities(reg)?;
12649 server.update_capabilities(|capabilities| {
12650 capabilities.document_formatting_provider = Some(options);
12651 });
12652 notify_server_capabilities_updated(&server, cx);
12653 }
12654 "textDocument/rename" => {
12655 let options = parse_register_capabilities(reg)?;
12656 server.update_capabilities(|capabilities| {
12657 capabilities.rename_provider = Some(options);
12658 });
12659 notify_server_capabilities_updated(&server, cx);
12660 }
12661 "textDocument/inlayHint" => {
12662 let options = parse_register_capabilities(reg)?;
12663 server.update_capabilities(|capabilities| {
12664 capabilities.inlay_hint_provider = Some(options);
12665 });
12666 notify_server_capabilities_updated(&server, cx);
12667 }
12668 "textDocument/documentSymbol" => {
12669 let options = parse_register_capabilities(reg)?;
12670 server.update_capabilities(|capabilities| {
12671 capabilities.document_symbol_provider = Some(options);
12672 });
12673 notify_server_capabilities_updated(&server, cx);
12674 }
12675 "textDocument/codeAction" => {
12676 let options = parse_register_capabilities(reg)?;
12677 let provider = match options {
12678 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12679 OneOf::Right(caps) => caps,
12680 };
12681 server.update_capabilities(|capabilities| {
12682 capabilities.code_action_provider = Some(provider);
12683 });
12684 notify_server_capabilities_updated(&server, cx);
12685 }
12686 "textDocument/definition" => {
12687 let options = parse_register_capabilities(reg)?;
12688 server.update_capabilities(|capabilities| {
12689 capabilities.definition_provider = Some(options);
12690 });
12691 notify_server_capabilities_updated(&server, cx);
12692 }
12693 "textDocument/completion" => {
12694 if let Some(caps) = reg
12695 .register_options
12696 .map(serde_json::from_value::<CompletionOptions>)
12697 .transpose()?
12698 {
12699 server.update_capabilities(|capabilities| {
12700 capabilities.completion_provider = Some(caps.clone());
12701 });
12702
12703 if let Some(local) = self.as_local() {
12704 let mut buffers_with_language_server = Vec::new();
12705 for handle in self.buffer_store.read(cx).buffers() {
12706 let buffer_id = handle.read(cx).remote_id();
12707 if local
12708 .buffers_opened_in_servers
12709 .get(&buffer_id)
12710 .filter(|s| s.contains(&server_id))
12711 .is_some()
12712 {
12713 buffers_with_language_server.push(handle);
12714 }
12715 }
12716 let triggers = caps
12717 .trigger_characters
12718 .unwrap_or_default()
12719 .into_iter()
12720 .collect::<BTreeSet<_>>();
12721 for handle in buffers_with_language_server {
12722 let triggers = triggers.clone();
12723 let _ = handle.update(cx, move |buffer, cx| {
12724 buffer.set_completion_triggers(server_id, triggers, cx);
12725 });
12726 }
12727 }
12728 notify_server_capabilities_updated(&server, cx);
12729 }
12730 }
12731 "textDocument/hover" => {
12732 let options = parse_register_capabilities(reg)?;
12733 let provider = match options {
12734 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12735 OneOf::Right(caps) => caps,
12736 };
12737 server.update_capabilities(|capabilities| {
12738 capabilities.hover_provider = Some(provider);
12739 });
12740 notify_server_capabilities_updated(&server, cx);
12741 }
12742 "textDocument/signatureHelp" => {
12743 if let Some(caps) = reg
12744 .register_options
12745 .map(serde_json::from_value)
12746 .transpose()?
12747 {
12748 server.update_capabilities(|capabilities| {
12749 capabilities.signature_help_provider = Some(caps);
12750 });
12751 notify_server_capabilities_updated(&server, cx);
12752 }
12753 }
12754 "textDocument/didChange" => {
12755 if let Some(sync_kind) = reg
12756 .register_options
12757 .and_then(|opts| opts.get("syncKind").cloned())
12758 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12759 .transpose()?
12760 {
12761 server.update_capabilities(|capabilities| {
12762 let mut sync_options =
12763 Self::take_text_document_sync_options(capabilities);
12764 sync_options.change = Some(sync_kind);
12765 capabilities.text_document_sync =
12766 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12767 });
12768 notify_server_capabilities_updated(&server, cx);
12769 }
12770 }
12771 "textDocument/didSave" => {
12772 if let Some(include_text) = reg
12773 .register_options
12774 .map(|opts| {
12775 let transpose = opts
12776 .get("includeText")
12777 .cloned()
12778 .map(serde_json::from_value::<Option<bool>>)
12779 .transpose();
12780 match transpose {
12781 Ok(value) => Ok(value.flatten()),
12782 Err(e) => Err(e),
12783 }
12784 })
12785 .transpose()?
12786 {
12787 server.update_capabilities(|capabilities| {
12788 let mut sync_options =
12789 Self::take_text_document_sync_options(capabilities);
12790 sync_options.save =
12791 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12792 include_text,
12793 }));
12794 capabilities.text_document_sync =
12795 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12796 });
12797 notify_server_capabilities_updated(&server, cx);
12798 }
12799 }
12800 "textDocument/codeLens" => {
12801 if let Some(caps) = reg
12802 .register_options
12803 .map(serde_json::from_value)
12804 .transpose()?
12805 {
12806 server.update_capabilities(|capabilities| {
12807 capabilities.code_lens_provider = Some(caps);
12808 });
12809 notify_server_capabilities_updated(&server, cx);
12810 }
12811 }
12812 "textDocument/diagnostic" => {
12813 if let Some(caps) = reg
12814 .register_options
12815 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12816 .transpose()?
12817 {
12818 let local = self
12819 .as_local_mut()
12820 .context("Expected LSP Store to be local")?;
12821 let state = local
12822 .language_servers
12823 .get_mut(&server_id)
12824 .context("Could not obtain Language Servers state")?;
12825 local
12826 .language_server_dynamic_registrations
12827 .entry(server_id)
12828 .or_default()
12829 .diagnostics
12830 .insert(Some(reg.id.clone()), caps.clone());
12831
12832 let supports_workspace_diagnostics =
12833 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12834 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12835 diagnostic_options.workspace_diagnostics
12836 }
12837 DiagnosticServerCapabilities::RegistrationOptions(
12838 diagnostic_registration_options,
12839 ) => {
12840 diagnostic_registration_options
12841 .diagnostic_options
12842 .workspace_diagnostics
12843 }
12844 };
12845
12846 if supports_workspace_diagnostics(&caps) {
12847 if let LanguageServerState::Running {
12848 workspace_diagnostics_refresh_tasks,
12849 ..
12850 } = state
12851 && let Some(task) = lsp_workspace_diagnostics_refresh(
12852 Some(reg.id.clone()),
12853 caps.clone(),
12854 server.clone(),
12855 cx,
12856 )
12857 {
12858 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12859 }
12860 }
12861
12862 server.update_capabilities(|capabilities| {
12863 capabilities.diagnostic_provider = Some(caps);
12864 });
12865
12866 notify_server_capabilities_updated(&server, cx);
12867
12868 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12869 }
12870 }
12871 "textDocument/documentColor" => {
12872 let options = parse_register_capabilities(reg)?;
12873 let provider = match options {
12874 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12875 OneOf::Right(caps) => caps,
12876 };
12877 server.update_capabilities(|capabilities| {
12878 capabilities.color_provider = Some(provider);
12879 });
12880 notify_server_capabilities_updated(&server, cx);
12881 }
12882 "textDocument/foldingRange" => {
12883 let options = parse_register_capabilities(reg)?;
12884 let provider = match options {
12885 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12886 OneOf::Right(caps) => caps,
12887 };
12888 server.update_capabilities(|capabilities| {
12889 capabilities.folding_range_provider = Some(provider);
12890 });
12891 notify_server_capabilities_updated(&server, cx);
12892 }
12893 _ => log::warn!("unhandled capability registration: {reg:?}"),
12894 }
12895 }
12896
12897 Ok(())
12898 }
12899
12900 fn unregister_server_capabilities(
12901 &mut self,
12902 server_id: LanguageServerId,
12903 params: lsp::UnregistrationParams,
12904 cx: &mut Context<Self>,
12905 ) -> anyhow::Result<()> {
12906 let server = self
12907 .language_server_for_id(server_id)
12908 .with_context(|| format!("no server {server_id} found"))?;
12909 for unreg in params.unregisterations.iter() {
12910 match unreg.method.as_str() {
12911 "workspace/didChangeWatchedFiles" => {
12912 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12913 local_lsp_store
12914 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12915 true
12916 } else {
12917 false
12918 };
12919 if notify {
12920 notify_server_capabilities_updated(&server, cx);
12921 }
12922 }
12923 "workspace/didChangeConfiguration" => {
12924 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12925 }
12926 "workspace/didChangeWorkspaceFolders" => {
12927 server.update_capabilities(|capabilities| {
12928 capabilities
12929 .workspace
12930 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12931 workspace_folders: None,
12932 file_operations: None,
12933 })
12934 .workspace_folders = None;
12935 });
12936 notify_server_capabilities_updated(&server, cx);
12937 }
12938 "workspace/symbol" => {
12939 server.update_capabilities(|capabilities| {
12940 capabilities.workspace_symbol_provider = None
12941 });
12942 notify_server_capabilities_updated(&server, cx);
12943 }
12944 "workspace/fileOperations" => {
12945 server.update_capabilities(|capabilities| {
12946 capabilities
12947 .workspace
12948 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12949 workspace_folders: None,
12950 file_operations: None,
12951 })
12952 .file_operations = None;
12953 });
12954 notify_server_capabilities_updated(&server, cx);
12955 }
12956 "workspace/executeCommand" => {
12957 server.update_capabilities(|capabilities| {
12958 capabilities.execute_command_provider = None;
12959 });
12960 notify_server_capabilities_updated(&server, cx);
12961 }
12962 "textDocument/rangeFormatting" => {
12963 server.update_capabilities(|capabilities| {
12964 capabilities.document_range_formatting_provider = None
12965 });
12966 notify_server_capabilities_updated(&server, cx);
12967 }
12968 "textDocument/onTypeFormatting" => {
12969 server.update_capabilities(|capabilities| {
12970 capabilities.document_on_type_formatting_provider = None;
12971 });
12972 notify_server_capabilities_updated(&server, cx);
12973 }
12974 "textDocument/formatting" => {
12975 server.update_capabilities(|capabilities| {
12976 capabilities.document_formatting_provider = None;
12977 });
12978 notify_server_capabilities_updated(&server, cx);
12979 }
12980 "textDocument/rename" => {
12981 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12982 notify_server_capabilities_updated(&server, cx);
12983 }
12984 "textDocument/codeAction" => {
12985 server.update_capabilities(|capabilities| {
12986 capabilities.code_action_provider = None;
12987 });
12988 notify_server_capabilities_updated(&server, cx);
12989 }
12990 "textDocument/definition" => {
12991 server.update_capabilities(|capabilities| {
12992 capabilities.definition_provider = None;
12993 });
12994 notify_server_capabilities_updated(&server, cx);
12995 }
12996 "textDocument/completion" => {
12997 server.update_capabilities(|capabilities| {
12998 capabilities.completion_provider = None;
12999 });
13000 notify_server_capabilities_updated(&server, cx);
13001 }
13002 "textDocument/hover" => {
13003 server.update_capabilities(|capabilities| {
13004 capabilities.hover_provider = None;
13005 });
13006 notify_server_capabilities_updated(&server, cx);
13007 }
13008 "textDocument/signatureHelp" => {
13009 server.update_capabilities(|capabilities| {
13010 capabilities.signature_help_provider = None;
13011 });
13012 notify_server_capabilities_updated(&server, cx);
13013 }
13014 "textDocument/didChange" => {
13015 server.update_capabilities(|capabilities| {
13016 let mut sync_options = Self::take_text_document_sync_options(capabilities);
13017 sync_options.change = None;
13018 capabilities.text_document_sync =
13019 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
13020 });
13021 notify_server_capabilities_updated(&server, cx);
13022 }
13023 "textDocument/didSave" => {
13024 server.update_capabilities(|capabilities| {
13025 let mut sync_options = Self::take_text_document_sync_options(capabilities);
13026 sync_options.save = None;
13027 capabilities.text_document_sync =
13028 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
13029 });
13030 notify_server_capabilities_updated(&server, cx);
13031 }
13032 "textDocument/codeLens" => {
13033 server.update_capabilities(|capabilities| {
13034 capabilities.code_lens_provider = None;
13035 });
13036 notify_server_capabilities_updated(&server, cx);
13037 }
13038 "textDocument/diagnostic" => {
13039 let local = self
13040 .as_local_mut()
13041 .context("Expected LSP Store to be local")?;
13042
13043 let state = local
13044 .language_servers
13045 .get_mut(&server_id)
13046 .context("Could not obtain Language Servers state")?;
13047 let registrations = local
13048 .language_server_dynamic_registrations
13049 .get_mut(&server_id)
13050 .with_context(|| {
13051 format!("Expected dynamic registration to exist for server {server_id}")
13052 })?;
13053 registrations.diagnostics
13054 .remove(&Some(unreg.id.clone()))
13055 .with_context(|| format!(
13056 "Attempted to unregister non-existent diagnostic registration with ID {}",
13057 unreg.id)
13058 )?;
13059 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
13060
13061 if let LanguageServerState::Running {
13062 workspace_diagnostics_refresh_tasks,
13063 ..
13064 } = state
13065 {
13066 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
13067 }
13068
13069 self.clear_unregistered_diagnostics(
13070 server_id,
13071 SharedString::from(unreg.id.clone()),
13072 cx,
13073 )?;
13074
13075 if removed_last_diagnostic_provider {
13076 server.update_capabilities(|capabilities| {
13077 debug_assert!(capabilities.diagnostic_provider.is_some());
13078 capabilities.diagnostic_provider = None;
13079 });
13080 }
13081
13082 notify_server_capabilities_updated(&server, cx);
13083 }
13084 "textDocument/documentColor" => {
13085 server.update_capabilities(|capabilities| {
13086 capabilities.color_provider = None;
13087 });
13088 notify_server_capabilities_updated(&server, cx);
13089 }
13090 "textDocument/foldingRange" => {
13091 server.update_capabilities(|capabilities| {
13092 capabilities.folding_range_provider = None;
13093 });
13094 notify_server_capabilities_updated(&server, cx);
13095 }
13096 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
13097 }
13098 }
13099
13100 Ok(())
13101 }
13102
13103 fn clear_unregistered_diagnostics(
13104 &mut self,
13105 server_id: LanguageServerId,
13106 cleared_registration_id: SharedString,
13107 cx: &mut Context<Self>,
13108 ) -> anyhow::Result<()> {
13109 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
13110
13111 self.buffer_store.update(cx, |buffer_store, cx| {
13112 for buffer_handle in buffer_store.buffers() {
13113 let buffer = buffer_handle.read(cx);
13114 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
13115 let Some(abs_path) = abs_path else {
13116 continue;
13117 };
13118 affected_abs_paths.insert(abs_path);
13119 }
13120 });
13121
13122 let local = self.as_local().context("Expected LSP Store to be local")?;
13123 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13124 let Some(worktree) = self
13125 .worktree_store
13126 .read(cx)
13127 .worktree_for_id(*worktree_id, cx)
13128 else {
13129 continue;
13130 };
13131
13132 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13133 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13134 let has_matching_registration =
13135 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13136 entry.diagnostic.registration_id.as_ref()
13137 == Some(&cleared_registration_id)
13138 });
13139 if has_matching_registration {
13140 let abs_path = worktree.read(cx).absolutize(rel_path);
13141 affected_abs_paths.insert(abs_path);
13142 }
13143 }
13144 }
13145 }
13146
13147 if affected_abs_paths.is_empty() {
13148 return Ok(());
13149 }
13150
13151 // Send a fake diagnostic update which clears the state for the registration ID
13152 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13153 affected_abs_paths
13154 .into_iter()
13155 .map(|abs_path| DocumentDiagnosticsUpdate {
13156 diagnostics: DocumentDiagnostics {
13157 diagnostics: Vec::new(),
13158 document_abs_path: abs_path,
13159 version: None,
13160 },
13161 result_id: None,
13162 registration_id: Some(cleared_registration_id.clone()),
13163 server_id,
13164 disk_based_sources: Cow::Borrowed(&[]),
13165 })
13166 .collect();
13167
13168 let merge_registration_id = cleared_registration_id.clone();
13169 self.merge_diagnostic_entries(
13170 clears,
13171 move |_, diagnostic, _| {
13172 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13173 diagnostic.registration_id != Some(merge_registration_id.clone())
13174 } else {
13175 true
13176 }
13177 },
13178 cx,
13179 )?;
13180
13181 Ok(())
13182 }
13183
13184 async fn deduplicate_range_based_lsp_requests<T>(
13185 lsp_store: &Entity<Self>,
13186 server_id: Option<LanguageServerId>,
13187 lsp_request_id: LspRequestId,
13188 proto_request: &T::ProtoRequest,
13189 range: Range<Anchor>,
13190 cx: &mut AsyncApp,
13191 ) -> Result<()>
13192 where
13193 T: LspCommand,
13194 T::ProtoRequest: proto::LspRequestMessage,
13195 {
13196 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13197 let version = deserialize_version(proto_request.buffer_version());
13198 let buffer = lsp_store.update(cx, |this, cx| {
13199 this.buffer_store.read(cx).get_existing(buffer_id)
13200 })?;
13201 buffer
13202 .update(cx, |buffer, _| buffer.wait_for_version(version))
13203 .await?;
13204 lsp_store.update(cx, |lsp_store, cx| {
13205 let buffer_snapshot = buffer.read(cx).snapshot();
13206 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13207 let chunks_queried_for = lsp_data
13208 .inlay_hints
13209 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13210 .collect::<Vec<_>>();
13211 match chunks_queried_for.as_slice() {
13212 &[chunk] => {
13213 let key = LspKey {
13214 request_type: TypeId::of::<T>(),
13215 server_queried: server_id,
13216 };
13217 let previous_request = lsp_data
13218 .chunk_lsp_requests
13219 .entry(key)
13220 .or_default()
13221 .insert(chunk, lsp_request_id);
13222 if let Some((previous_request, running_requests)) =
13223 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13224 {
13225 running_requests.remove(&previous_request);
13226 }
13227 }
13228 _ambiguous_chunks => {
13229 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13230 // there, a buffer version-based check will be performed and outdated requests discarded.
13231 }
13232 }
13233 anyhow::Ok(())
13234 })?;
13235
13236 Ok(())
13237 }
13238
13239 async fn query_lsp_locally<T>(
13240 lsp_store: Entity<Self>,
13241 for_server_id: Option<LanguageServerId>,
13242 sender_id: proto::PeerId,
13243 lsp_request_id: LspRequestId,
13244 proto_request: T::ProtoRequest,
13245 position: Option<Anchor>,
13246 cx: &mut AsyncApp,
13247 ) -> Result<()>
13248 where
13249 T: LspCommand + Clone,
13250 T::ProtoRequest: proto::LspRequestMessage,
13251 <T::ProtoRequest as proto::RequestMessage>::Response:
13252 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13253 {
13254 let (buffer_version, buffer) =
13255 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13256 let request =
13257 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13258 let key = LspKey {
13259 request_type: TypeId::of::<T>(),
13260 server_queried: for_server_id,
13261 };
13262 lsp_store.update(cx, |lsp_store, cx| {
13263 let request_task = match for_server_id {
13264 Some(server_id) => {
13265 let server_task = lsp_store.request_lsp(
13266 buffer.clone(),
13267 LanguageServerToQuery::Other(server_id),
13268 request.clone(),
13269 cx,
13270 );
13271 cx.background_spawn(async move {
13272 let mut responses = Vec::new();
13273 match server_task.await {
13274 Ok(response) => responses.push((server_id, response)),
13275 // rust-analyzer likes to error with this when its still loading up
13276 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13277 Err(e) => log::error!(
13278 "Error handling response for request {request:?}: {e:#}"
13279 ),
13280 }
13281 responses
13282 })
13283 }
13284 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13285 };
13286 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13287 if T::ProtoRequest::stop_previous_requests() {
13288 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13289 lsp_requests.clear();
13290 }
13291 }
13292 lsp_data.lsp_requests.entry(key).or_default().insert(
13293 lsp_request_id,
13294 cx.spawn(async move |lsp_store, cx| {
13295 let response = request_task.await;
13296 lsp_store
13297 .update(cx, |lsp_store, cx| {
13298 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13299 {
13300 let response = response
13301 .into_iter()
13302 .map(|(server_id, response)| {
13303 (
13304 server_id.to_proto(),
13305 T::response_to_proto(
13306 response,
13307 lsp_store,
13308 sender_id,
13309 &buffer_version,
13310 cx,
13311 )
13312 .into(),
13313 )
13314 })
13315 .collect::<HashMap<_, _>>();
13316 match client.send_lsp_response::<T::ProtoRequest>(
13317 project_id,
13318 lsp_request_id,
13319 response,
13320 ) {
13321 Ok(()) => {}
13322 Err(e) => {
13323 log::error!("Failed to send LSP response: {e:#}",)
13324 }
13325 }
13326 }
13327 })
13328 .ok();
13329 }),
13330 );
13331 });
13332 Ok(())
13333 }
13334
13335 async fn wait_for_buffer_version<T>(
13336 lsp_store: &Entity<Self>,
13337 proto_request: &T::ProtoRequest,
13338 cx: &mut AsyncApp,
13339 ) -> Result<(Global, Entity<Buffer>)>
13340 where
13341 T: LspCommand,
13342 T::ProtoRequest: proto::LspRequestMessage,
13343 {
13344 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13345 let version = deserialize_version(proto_request.buffer_version());
13346 let buffer = lsp_store.update(cx, |this, cx| {
13347 this.buffer_store.read(cx).get_existing(buffer_id)
13348 })?;
13349 buffer
13350 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13351 .await?;
13352 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13353 Ok((buffer_version, buffer))
13354 }
13355
13356 fn take_text_document_sync_options(
13357 capabilities: &mut lsp::ServerCapabilities,
13358 ) -> lsp::TextDocumentSyncOptions {
13359 match capabilities.text_document_sync.take() {
13360 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13361 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13362 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13363 sync_options.change = Some(sync_kind);
13364 sync_options
13365 }
13366 None => lsp::TextDocumentSyncOptions::default(),
13367 }
13368 }
13369
13370 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13371 self.downstream_client.clone()
13372 }
13373
13374 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13375 self.worktree_store.clone()
13376 }
13377
13378 /// Gets what's stored in the LSP data for the given buffer.
13379 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13380 self.lsp_data.get_mut(&buffer_id)
13381 }
13382
13383 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13384 /// new [`BufferLspData`] will be created to replace the previous state.
13385 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13386 let (buffer_id, buffer_version) =
13387 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13388 let lsp_data = self
13389 .lsp_data
13390 .entry(buffer_id)
13391 .or_insert_with(|| BufferLspData::new(buffer, cx));
13392 if buffer_version.changed_since(&lsp_data.buffer_version) {
13393 // To send delta requests for semantic tokens, the previous tokens
13394 // need to be kept between buffer changes.
13395 let semantic_tokens = lsp_data.semantic_tokens.take();
13396 *lsp_data = BufferLspData::new(buffer, cx);
13397 lsp_data.semantic_tokens = semantic_tokens;
13398 }
13399 lsp_data
13400 }
13401}
13402
13403// Registration with registerOptions as null, should fallback to true.
13404// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13405fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13406 reg: lsp::Registration,
13407) -> Result<OneOf<bool, T>> {
13408 Ok(match reg.register_options {
13409 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13410 None => OneOf::Left(true),
13411 })
13412}
13413
13414fn server_capabilities_support_range_formatting(capabilities: &lsp::ServerCapabilities) -> bool {
13415 matches!(
13416 capabilities.document_range_formatting_provider.as_ref(),
13417 Some(provider) if *provider != OneOf::Left(false)
13418 )
13419}
13420
13421fn subscribe_to_binary_statuses(
13422 languages: &Arc<LanguageRegistry>,
13423 cx: &mut Context<'_, LspStore>,
13424) -> Task<()> {
13425 let mut server_statuses = languages.language_server_binary_statuses();
13426 cx.spawn(async move |lsp_store, cx| {
13427 while let Some((server_name, binary_status)) = server_statuses.next().await {
13428 if lsp_store
13429 .update(cx, |_, cx| {
13430 let mut message = None;
13431 let binary_status = match binary_status {
13432 BinaryStatus::None => proto::ServerBinaryStatus::None,
13433 BinaryStatus::CheckingForUpdate => {
13434 proto::ServerBinaryStatus::CheckingForUpdate
13435 }
13436 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13437 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13438 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13439 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13440 BinaryStatus::Failed { error } => {
13441 message = Some(error);
13442 proto::ServerBinaryStatus::Failed
13443 }
13444 };
13445 cx.emit(LspStoreEvent::LanguageServerUpdate {
13446 // Binary updates are about the binary that might not have any language server id at that point.
13447 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13448 language_server_id: LanguageServerId(0),
13449 name: Some(server_name),
13450 message: proto::update_language_server::Variant::StatusUpdate(
13451 proto::StatusUpdate {
13452 message,
13453 status: Some(proto::status_update::Status::Binary(
13454 binary_status as i32,
13455 )),
13456 },
13457 ),
13458 });
13459 })
13460 .is_err()
13461 {
13462 break;
13463 }
13464 }
13465 })
13466}
13467
13468fn lsp_workspace_diagnostics_refresh(
13469 registration_id: Option<String>,
13470 options: DiagnosticServerCapabilities,
13471 server: Arc<LanguageServer>,
13472 cx: &mut Context<'_, LspStore>,
13473) -> Option<WorkspaceRefreshTask> {
13474 let identifier = workspace_diagnostic_identifier(&options)?;
13475 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13476
13477 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13478 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13479 refresh_tx.try_send(()).ok();
13480
13481 let request_timeout = ProjectSettings::get_global(cx)
13482 .global_lsp_settings
13483 .get_request_timeout();
13484
13485 // 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.
13486 // This allows users to increase the duration if need be
13487 let timeout = if request_timeout != Duration::ZERO {
13488 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13489 } else {
13490 request_timeout
13491 };
13492
13493 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13494 let mut attempts = 0;
13495 let max_attempts = 50;
13496 let mut requests = 0;
13497
13498 loop {
13499 let Some(()) = refresh_rx.recv().await else {
13500 return;
13501 };
13502
13503 'request: loop {
13504 requests += 1;
13505 if attempts > max_attempts {
13506 log::error!(
13507 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13508 );
13509 return;
13510 }
13511 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13512 cx.background_executor()
13513 .timer(Duration::from_millis(backoff_millis))
13514 .await;
13515 attempts += 1;
13516
13517 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13518 lsp_store
13519 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13520 .into_iter()
13521 .filter_map(|(abs_path, result_id)| {
13522 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13523 Some(lsp::PreviousResultId {
13524 uri,
13525 value: result_id.to_string(),
13526 })
13527 })
13528 .collect()
13529 }) else {
13530 return;
13531 };
13532
13533 let token = if let Some(registration_id) = ®istration_id {
13534 format!(
13535 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13536 server.server_id(),
13537 )
13538 } else {
13539 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13540 };
13541
13542 progress_rx.try_recv().ok();
13543 let timer = server.request_timer(timeout).fuse();
13544 let progress = pin!(progress_rx.recv().fuse());
13545 let response_result = server
13546 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13547 lsp::WorkspaceDiagnosticParams {
13548 previous_result_ids,
13549 identifier: identifier.clone(),
13550 work_done_progress_params: Default::default(),
13551 partial_result_params: lsp::PartialResultParams {
13552 partial_result_token: Some(lsp::ProgressToken::String(token)),
13553 },
13554 },
13555 select(timer, progress).then(|either| match either {
13556 Either::Left((message, ..)) => ready(message).left_future(),
13557 Either::Right(..) => pending::<String>().right_future(),
13558 }),
13559 )
13560 .await;
13561
13562 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13563 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13564 match response_result {
13565 ConnectionResult::Timeout => {
13566 log::error!("Timeout during workspace diagnostics pull");
13567 continue 'request;
13568 }
13569 ConnectionResult::ConnectionReset => {
13570 log::error!("Server closed a workspace diagnostics pull request");
13571 continue 'request;
13572 }
13573 ConnectionResult::Result(Err(e)) => {
13574 log::error!("Error during workspace diagnostics pull: {e:#}");
13575 break 'request;
13576 }
13577 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13578 attempts = 0;
13579 if lsp_store
13580 .update(cx, |lsp_store, cx| {
13581 lsp_store.apply_workspace_diagnostic_report(
13582 server.server_id(),
13583 pulled_diagnostics,
13584 registration_id_shared.clone(),
13585 cx,
13586 )
13587 })
13588 .is_err()
13589 {
13590 return;
13591 }
13592 break 'request;
13593 }
13594 }
13595 }
13596 }
13597 });
13598
13599 Some(WorkspaceRefreshTask {
13600 refresh_tx,
13601 progress_tx,
13602 task: workspace_query_language_server,
13603 })
13604}
13605
13606fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13607 match &options {
13608 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13609 .identifier
13610 .as_deref()
13611 .map(SharedString::new),
13612 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13613 let diagnostic_options = ®istration_options.diagnostic_options;
13614 diagnostic_options
13615 .identifier
13616 .as_deref()
13617 .map(SharedString::new)
13618 }
13619 }
13620}
13621
13622fn workspace_diagnostic_identifier(
13623 options: &DiagnosticServerCapabilities,
13624) -> Option<Option<String>> {
13625 match &options {
13626 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13627 if !diagnostic_options.workspace_diagnostics {
13628 return None;
13629 }
13630 Some(diagnostic_options.identifier.clone())
13631 }
13632 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13633 let diagnostic_options = ®istration_options.diagnostic_options;
13634 if !diagnostic_options.workspace_diagnostics {
13635 return None;
13636 }
13637 Some(diagnostic_options.identifier.clone())
13638 }
13639 }
13640}
13641
13642fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13643 let CompletionSource::BufferWord {
13644 word_range,
13645 resolved,
13646 } = &mut completion.source
13647 else {
13648 return;
13649 };
13650 if *resolved {
13651 return;
13652 }
13653
13654 if completion.new_text
13655 != snapshot
13656 .text_for_range(word_range.clone())
13657 .collect::<String>()
13658 {
13659 return;
13660 }
13661
13662 let mut offset = 0;
13663 for chunk in snapshot.chunks(
13664 word_range.clone(),
13665 LanguageAwareStyling {
13666 tree_sitter: true,
13667 diagnostics: true,
13668 },
13669 ) {
13670 let end_offset = offset + chunk.text.len();
13671 if let Some(highlight_id) = chunk.syntax_highlight_id {
13672 completion
13673 .label
13674 .runs
13675 .push((offset..end_offset, highlight_id));
13676 }
13677 offset = end_offset;
13678 }
13679 *resolved = true;
13680}
13681
13682impl EventEmitter<LspStoreEvent> for LspStore {}
13683
13684fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13685 hover
13686 .contents
13687 .retain(|hover_block| !hover_block.text.trim().is_empty());
13688 if hover.contents.is_empty() {
13689 None
13690 } else {
13691 Some(hover)
13692 }
13693}
13694
13695async fn populate_labels_for_completions(
13696 new_completions: Vec<CoreCompletion>,
13697 language: Option<Arc<Language>>,
13698 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13699) -> Vec<Completion> {
13700 let lsp_completions = new_completions
13701 .iter()
13702 .filter_map(|new_completion| {
13703 new_completion
13704 .source
13705 .lsp_completion(true)
13706 .map(|lsp_completion| lsp_completion.into_owned())
13707 })
13708 .collect::<Vec<_>>();
13709
13710 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13711 lsp_adapter
13712 .labels_for_completions(&lsp_completions, language)
13713 .await
13714 .log_err()
13715 .unwrap_or_default()
13716 } else {
13717 Vec::new()
13718 }
13719 .into_iter()
13720 .fuse();
13721
13722 let mut completions = Vec::new();
13723 for completion in new_completions {
13724 match completion.source.lsp_completion(true) {
13725 Some(lsp_completion) => {
13726 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13727
13728 let mut label = labels.next().flatten().unwrap_or_else(|| {
13729 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13730 });
13731 ensure_uniform_list_compatible_label(&mut label);
13732 completions.push(Completion {
13733 label,
13734 documentation,
13735 replace_range: completion.replace_range,
13736 new_text: completion.new_text,
13737 insert_text_mode: lsp_completion.insert_text_mode,
13738 source: completion.source,
13739 icon_path: None,
13740 confirm: None,
13741 match_start: None,
13742 snippet_deduplication_key: None,
13743 });
13744 }
13745 None => {
13746 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13747 ensure_uniform_list_compatible_label(&mut label);
13748 completions.push(Completion {
13749 label,
13750 documentation: None,
13751 replace_range: completion.replace_range,
13752 new_text: completion.new_text,
13753 source: completion.source,
13754 insert_text_mode: None,
13755 icon_path: None,
13756 confirm: None,
13757 match_start: None,
13758 snippet_deduplication_key: None,
13759 });
13760 }
13761 }
13762 }
13763 completions
13764}
13765
13766#[derive(Debug)]
13767pub enum LanguageServerToQuery {
13768 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13769 FirstCapable,
13770 /// Query a specific language server.
13771 Other(LanguageServerId),
13772}
13773
13774#[derive(Default)]
13775struct RenamePathsWatchedForServer {
13776 did_rename: Vec<RenameActionPredicate>,
13777 will_rename: Vec<RenameActionPredicate>,
13778}
13779
13780impl RenamePathsWatchedForServer {
13781 fn with_did_rename_patterns(
13782 mut self,
13783 did_rename: Option<&FileOperationRegistrationOptions>,
13784 ) -> Self {
13785 if let Some(did_rename) = did_rename {
13786 self.did_rename = did_rename
13787 .filters
13788 .iter()
13789 .filter_map(|filter| filter.try_into().log_err())
13790 .collect();
13791 }
13792 self
13793 }
13794 fn with_will_rename_patterns(
13795 mut self,
13796 will_rename: Option<&FileOperationRegistrationOptions>,
13797 ) -> Self {
13798 if let Some(will_rename) = will_rename {
13799 self.will_rename = will_rename
13800 .filters
13801 .iter()
13802 .filter_map(|filter| filter.try_into().log_err())
13803 .collect();
13804 }
13805 self
13806 }
13807
13808 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13809 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13810 }
13811 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13812 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13813 }
13814}
13815
13816impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13817 type Error = globset::Error;
13818 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13819 Ok(Self {
13820 kind: ops.pattern.matches.clone(),
13821 glob: GlobBuilder::new(&ops.pattern.glob)
13822 .case_insensitive(
13823 ops.pattern
13824 .options
13825 .as_ref()
13826 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13827 )
13828 .build()?
13829 .compile_matcher(),
13830 })
13831 }
13832}
13833struct RenameActionPredicate {
13834 glob: GlobMatcher,
13835 kind: Option<FileOperationPatternKind>,
13836}
13837
13838impl RenameActionPredicate {
13839 // Returns true if language server should be notified
13840 fn eval(&self, path: &str, is_dir: bool) -> bool {
13841 self.kind.as_ref().is_none_or(|kind| {
13842 let expected_kind = if is_dir {
13843 FileOperationPatternKind::Folder
13844 } else {
13845 FileOperationPatternKind::File
13846 };
13847 kind == &expected_kind
13848 }) && self.glob.is_match(path)
13849 }
13850}
13851
13852#[derive(Default)]
13853struct LanguageServerWatchedPaths {
13854 worktree_paths: HashMap<WorktreeId, GlobSet>,
13855 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13856}
13857
13858#[derive(Default)]
13859struct LanguageServerWatchedPathsBuilder {
13860 worktree_paths: HashMap<WorktreeId, GlobSet>,
13861 abs_paths: HashMap<Arc<Path>, GlobSet>,
13862}
13863
13864impl LanguageServerWatchedPathsBuilder {
13865 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13866 self.worktree_paths.insert(worktree_id, glob_set);
13867 }
13868 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13869 self.abs_paths.insert(path, glob_set);
13870 }
13871 fn build(
13872 self,
13873 fs: Arc<dyn Fs>,
13874 language_server_id: LanguageServerId,
13875 cx: &mut Context<LspStore>,
13876 ) -> LanguageServerWatchedPaths {
13877 let lsp_store = cx.weak_entity();
13878
13879 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13880 let abs_paths = self
13881 .abs_paths
13882 .into_iter()
13883 .map(|(abs_path, globset)| {
13884 let task = cx.spawn({
13885 let abs_path = abs_path.clone();
13886 let fs = fs.clone();
13887
13888 let lsp_store = lsp_store.clone();
13889 async move |_, cx| {
13890 maybe!(async move {
13891 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13892 while let Some(update) = push_updates.0.next().await {
13893 let action = lsp_store
13894 .update(cx, |this, _| {
13895 let Some(local) = this.as_local() else {
13896 return ControlFlow::Break(());
13897 };
13898 let Some(watcher) = local
13899 .language_server_watched_paths
13900 .get(&language_server_id)
13901 else {
13902 return ControlFlow::Break(());
13903 };
13904 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13905 "Watched abs path is not registered with a watcher",
13906 );
13907 let matching_entries = update
13908 .into_iter()
13909 .filter(|event| globs.is_match(&event.path))
13910 .collect::<Vec<_>>();
13911 this.lsp_notify_abs_paths_changed(
13912 language_server_id,
13913 matching_entries,
13914 );
13915 ControlFlow::Continue(())
13916 })
13917 .ok()?;
13918
13919 if action.is_break() {
13920 break;
13921 }
13922 }
13923 Some(())
13924 })
13925 .await;
13926 }
13927 });
13928 (abs_path, (globset, task))
13929 })
13930 .collect();
13931 LanguageServerWatchedPaths {
13932 worktree_paths: self.worktree_paths,
13933 abs_paths,
13934 }
13935 }
13936}
13937
13938struct LspBufferSnapshot {
13939 version: i32,
13940 snapshot: TextBufferSnapshot,
13941}
13942
13943/// A prompt requested by LSP server.
13944#[derive(Clone, Debug)]
13945pub struct LanguageServerPromptRequest {
13946 pub id: usize,
13947 pub level: PromptLevel,
13948 pub message: String,
13949 pub actions: Vec<MessageActionItem>,
13950 pub lsp_name: String,
13951 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13952}
13953
13954impl LanguageServerPromptRequest {
13955 pub fn new(
13956 level: PromptLevel,
13957 message: String,
13958 actions: Vec<MessageActionItem>,
13959 lsp_name: String,
13960 response_channel: smol::channel::Sender<MessageActionItem>,
13961 ) -> Self {
13962 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13963 LanguageServerPromptRequest {
13964 id,
13965 level,
13966 message,
13967 actions,
13968 lsp_name,
13969 response_channel,
13970 }
13971 }
13972 pub async fn respond(self, index: usize) -> Option<()> {
13973 if let Some(response) = self.actions.into_iter().nth(index) {
13974 self.response_channel.send(response).await.ok()
13975 } else {
13976 None
13977 }
13978 }
13979
13980 #[cfg(any(test, feature = "test-support"))]
13981 pub fn test(
13982 level: PromptLevel,
13983 message: String,
13984 actions: Vec<MessageActionItem>,
13985 lsp_name: String,
13986 ) -> Self {
13987 let (tx, _rx) = smol::channel::unbounded();
13988 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13989 }
13990}
13991impl PartialEq for LanguageServerPromptRequest {
13992 fn eq(&self, other: &Self) -> bool {
13993 self.message == other.message && self.actions == other.actions
13994 }
13995}
13996
13997#[derive(Clone, Debug, PartialEq)]
13998pub enum LanguageServerLogType {
13999 Log(MessageType),
14000 Trace { verbose_info: Option<String> },
14001 Rpc { received: bool },
14002}
14003
14004impl LanguageServerLogType {
14005 pub fn to_proto(&self) -> proto::language_server_log::LogType {
14006 match self {
14007 Self::Log(log_type) => {
14008 use proto::log_message::LogLevel;
14009 let level = match *log_type {
14010 MessageType::ERROR => LogLevel::Error,
14011 MessageType::WARNING => LogLevel::Warning,
14012 MessageType::INFO => LogLevel::Info,
14013 MessageType::LOG => LogLevel::Log,
14014 other => {
14015 log::warn!("Unknown lsp log message type: {other:?}");
14016 LogLevel::Log
14017 }
14018 };
14019 proto::language_server_log::LogType::Log(proto::LogMessage {
14020 level: level as i32,
14021 })
14022 }
14023 Self::Trace { verbose_info } => {
14024 proto::language_server_log::LogType::Trace(proto::TraceMessage {
14025 verbose_info: verbose_info.to_owned(),
14026 })
14027 }
14028 Self::Rpc { received } => {
14029 let kind = if *received {
14030 proto::rpc_message::Kind::Received
14031 } else {
14032 proto::rpc_message::Kind::Sent
14033 };
14034 let kind = kind as i32;
14035 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
14036 }
14037 }
14038 }
14039
14040 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
14041 use proto::log_message::LogLevel;
14042 use proto::rpc_message;
14043 match log_type {
14044 proto::language_server_log::LogType::Log(message_type) => Self::Log(
14045 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
14046 LogLevel::Error => MessageType::ERROR,
14047 LogLevel::Warning => MessageType::WARNING,
14048 LogLevel::Info => MessageType::INFO,
14049 LogLevel::Log => MessageType::LOG,
14050 },
14051 ),
14052 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
14053 verbose_info: trace_message.verbose_info,
14054 },
14055 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
14056 received: match rpc_message::Kind::from_i32(message.kind)
14057 .unwrap_or(rpc_message::Kind::Received)
14058 {
14059 rpc_message::Kind::Received => true,
14060 rpc_message::Kind::Sent => false,
14061 },
14062 },
14063 }
14064 }
14065}
14066
14067pub struct WorkspaceRefreshTask {
14068 refresh_tx: mpsc::Sender<()>,
14069 progress_tx: mpsc::Sender<()>,
14070 #[allow(dead_code)]
14071 task: Task<()>,
14072}
14073
14074pub enum LanguageServerState {
14075 Starting {
14076 startup: Task<Option<Arc<LanguageServer>>>,
14077 /// List of language servers that will be added to the workspace once it's initialization completes.
14078 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
14079 },
14080
14081 Running {
14082 adapter: Arc<CachedLspAdapter>,
14083 server: Arc<LanguageServer>,
14084 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
14085 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
14086 },
14087}
14088
14089impl LanguageServerState {
14090 fn add_workspace_folder(&self, uri: Uri) {
14091 match self {
14092 LanguageServerState::Starting {
14093 pending_workspace_folders,
14094 ..
14095 } => {
14096 pending_workspace_folders.lock().insert(uri);
14097 }
14098 LanguageServerState::Running { server, .. } => {
14099 server.add_workspace_folder(uri);
14100 }
14101 }
14102 }
14103 fn _remove_workspace_folder(&self, uri: Uri) {
14104 match self {
14105 LanguageServerState::Starting {
14106 pending_workspace_folders,
14107 ..
14108 } => {
14109 pending_workspace_folders.lock().remove(&uri);
14110 }
14111 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
14112 }
14113 }
14114}
14115
14116impl std::fmt::Debug for LanguageServerState {
14117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14118 match self {
14119 LanguageServerState::Starting { .. } => {
14120 f.debug_struct("LanguageServerState::Starting").finish()
14121 }
14122 LanguageServerState::Running { .. } => {
14123 f.debug_struct("LanguageServerState::Running").finish()
14124 }
14125 }
14126 }
14127}
14128
14129#[derive(Clone, Debug, Serialize)]
14130pub struct LanguageServerProgress {
14131 pub is_disk_based_diagnostics_progress: bool,
14132 pub is_cancellable: bool,
14133 pub title: Option<String>,
14134 pub message: Option<String>,
14135 pub percentage: Option<usize>,
14136 #[serde(skip_serializing)]
14137 pub last_update_at: Instant,
14138}
14139
14140#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14141pub struct DiagnosticSummary {
14142 pub error_count: usize,
14143 pub warning_count: usize,
14144}
14145
14146impl DiagnosticSummary {
14147 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14148 let mut this = Self {
14149 error_count: 0,
14150 warning_count: 0,
14151 };
14152
14153 for entry in diagnostics {
14154 if entry.diagnostic.is_primary {
14155 match entry.diagnostic.severity {
14156 DiagnosticSeverity::ERROR => this.error_count += 1,
14157 DiagnosticSeverity::WARNING => this.warning_count += 1,
14158 _ => {}
14159 }
14160 }
14161 }
14162
14163 this
14164 }
14165
14166 pub fn is_empty(&self) -> bool {
14167 self.error_count == 0 && self.warning_count == 0
14168 }
14169
14170 pub fn to_proto(
14171 self,
14172 language_server_id: LanguageServerId,
14173 path: &RelPath,
14174 ) -> proto::DiagnosticSummary {
14175 proto::DiagnosticSummary {
14176 path: path.to_proto(),
14177 language_server_id: language_server_id.0 as u64,
14178 error_count: self.error_count as u32,
14179 warning_count: self.warning_count as u32,
14180 }
14181 }
14182}
14183
14184#[derive(Clone, Debug)]
14185pub enum CompletionDocumentation {
14186 /// There is no documentation for this completion.
14187 Undocumented,
14188 /// A single line of documentation.
14189 SingleLine(SharedString),
14190 /// Multiple lines of plain text documentation.
14191 MultiLinePlainText(SharedString),
14192 /// Markdown documentation.
14193 MultiLineMarkdown(SharedString),
14194 /// Both single line and multiple lines of plain text documentation.
14195 SingleLineAndMultiLinePlainText {
14196 single_line: SharedString,
14197 plain_text: Option<SharedString>,
14198 },
14199}
14200
14201impl CompletionDocumentation {
14202 #[cfg(any(test, feature = "test-support"))]
14203 pub fn text(&self) -> SharedString {
14204 match self {
14205 CompletionDocumentation::Undocumented => "".into(),
14206 CompletionDocumentation::SingleLine(s) => s.clone(),
14207 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14208 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14209 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14210 single_line.clone()
14211 }
14212 }
14213 }
14214}
14215
14216impl From<lsp::Documentation> for CompletionDocumentation {
14217 fn from(docs: lsp::Documentation) -> Self {
14218 match docs {
14219 lsp::Documentation::String(text) => {
14220 if text.lines().count() <= 1 {
14221 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14222 } else {
14223 CompletionDocumentation::MultiLinePlainText(text.into())
14224 }
14225 }
14226
14227 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14228 lsp::MarkupKind::PlainText => {
14229 if value.lines().count() <= 1 {
14230 CompletionDocumentation::SingleLine(value.into())
14231 } else {
14232 CompletionDocumentation::MultiLinePlainText(value.into())
14233 }
14234 }
14235
14236 lsp::MarkupKind::Markdown => {
14237 CompletionDocumentation::MultiLineMarkdown(value.into())
14238 }
14239 },
14240 }
14241 }
14242}
14243
14244pub enum ResolvedHint {
14245 Resolved(InlayHint),
14246 Resolving(Shared<Task<()>>),
14247}
14248
14249pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14250 glob.components()
14251 .take_while(|component| match component {
14252 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14253 _ => true,
14254 })
14255 .collect()
14256}
14257
14258pub struct SshLspAdapter {
14259 name: LanguageServerName,
14260 binary: LanguageServerBinary,
14261 initialization_options: Option<String>,
14262 code_action_kinds: Option<Vec<CodeActionKind>>,
14263}
14264
14265impl SshLspAdapter {
14266 pub fn new(
14267 name: LanguageServerName,
14268 binary: LanguageServerBinary,
14269 initialization_options: Option<String>,
14270 code_action_kinds: Option<String>,
14271 ) -> Self {
14272 Self {
14273 name,
14274 binary,
14275 initialization_options,
14276 code_action_kinds: code_action_kinds
14277 .as_ref()
14278 .and_then(|c| serde_json::from_str(c).ok()),
14279 }
14280 }
14281}
14282
14283impl LspInstaller for SshLspAdapter {
14284 type BinaryVersion = ();
14285 async fn check_if_user_installed(
14286 &self,
14287 _: &dyn LspAdapterDelegate,
14288 _: Option<Toolchain>,
14289 _: &AsyncApp,
14290 ) -> Option<LanguageServerBinary> {
14291 Some(self.binary.clone())
14292 }
14293
14294 async fn cached_server_binary(
14295 &self,
14296 _: PathBuf,
14297 _: &dyn LspAdapterDelegate,
14298 ) -> Option<LanguageServerBinary> {
14299 None
14300 }
14301
14302 async fn fetch_latest_server_version(
14303 &self,
14304 _: &dyn LspAdapterDelegate,
14305 _: bool,
14306 _: &mut AsyncApp,
14307 ) -> Result<()> {
14308 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14309 }
14310
14311 async fn fetch_server_binary(
14312 &self,
14313 _: (),
14314 _: PathBuf,
14315 _: &dyn LspAdapterDelegate,
14316 ) -> Result<LanguageServerBinary> {
14317 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14318 }
14319}
14320
14321#[async_trait(?Send)]
14322impl LspAdapter for SshLspAdapter {
14323 fn name(&self) -> LanguageServerName {
14324 self.name.clone()
14325 }
14326
14327 async fn initialization_options(
14328 self: Arc<Self>,
14329 _: &Arc<dyn LspAdapterDelegate>,
14330 _: &mut AsyncApp,
14331 ) -> Result<Option<serde_json::Value>> {
14332 let Some(options) = &self.initialization_options else {
14333 return Ok(None);
14334 };
14335 let result = serde_json::from_str(options)?;
14336 Ok(result)
14337 }
14338
14339 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14340 self.code_action_kinds.clone()
14341 }
14342}
14343
14344pub fn language_server_settings<'a>(
14345 delegate: &'a dyn LspAdapterDelegate,
14346 language: &LanguageServerName,
14347 cx: &'a App,
14348) -> Option<&'a LspSettings> {
14349 language_server_settings_for(
14350 SettingsLocation {
14351 worktree_id: delegate.worktree_id(),
14352 path: RelPath::empty(),
14353 },
14354 language,
14355 cx,
14356 )
14357}
14358
14359pub fn language_server_settings_for<'a>(
14360 location: SettingsLocation<'a>,
14361 language: &LanguageServerName,
14362 cx: &'a App,
14363) -> Option<&'a LspSettings> {
14364 ProjectSettings::get(Some(location), cx).lsp.get(language)
14365}
14366
14367pub struct LocalLspAdapterDelegate {
14368 lsp_store: WeakEntity<LspStore>,
14369 worktree: worktree::Snapshot,
14370 fs: Arc<dyn Fs>,
14371 http_client: Arc<dyn HttpClient>,
14372 language_registry: Arc<LanguageRegistry>,
14373 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14374}
14375
14376impl LocalLspAdapterDelegate {
14377 pub fn new(
14378 language_registry: Arc<LanguageRegistry>,
14379 environment: &Entity<ProjectEnvironment>,
14380 lsp_store: WeakEntity<LspStore>,
14381 worktree: &Entity<Worktree>,
14382 http_client: Arc<dyn HttpClient>,
14383 fs: Arc<dyn Fs>,
14384 cx: &mut App,
14385 ) -> Arc<Self> {
14386 let load_shell_env_task =
14387 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14388
14389 Arc::new(Self {
14390 lsp_store,
14391 worktree: worktree.read(cx).snapshot(),
14392 fs,
14393 http_client,
14394 language_registry,
14395 load_shell_env_task,
14396 })
14397 }
14398
14399 pub fn from_local_lsp(
14400 local: &LocalLspStore,
14401 worktree: &Entity<Worktree>,
14402 cx: &mut App,
14403 ) -> Arc<Self> {
14404 Self::new(
14405 local.languages.clone(),
14406 &local.environment,
14407 local.weak.clone(),
14408 worktree,
14409 local.http_client.clone(),
14410 local.fs.clone(),
14411 cx,
14412 )
14413 }
14414}
14415
14416#[async_trait]
14417impl LspAdapterDelegate for LocalLspAdapterDelegate {
14418 fn show_notification(&self, message: &str, cx: &mut App) {
14419 self.lsp_store
14420 .update(cx, |_, cx| {
14421 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14422 })
14423 .ok();
14424 }
14425
14426 fn http_client(&self) -> Arc<dyn HttpClient> {
14427 self.http_client.clone()
14428 }
14429
14430 fn worktree_id(&self) -> WorktreeId {
14431 self.worktree.id()
14432 }
14433
14434 fn worktree_root_path(&self) -> &Path {
14435 self.worktree.abs_path().as_ref()
14436 }
14437
14438 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14439 self.worktree.resolve_relative_path(path)
14440 }
14441
14442 async fn shell_env(&self) -> HashMap<String, String> {
14443 let task = self.load_shell_env_task.clone();
14444 task.await.unwrap_or_default()
14445 }
14446
14447 async fn npm_package_installed_version(
14448 &self,
14449 package_name: &str,
14450 ) -> Result<Option<(PathBuf, Version)>> {
14451 let local_package_directory = self.worktree_root_path();
14452 let node_modules_directory = local_package_directory.join("node_modules");
14453
14454 if let Some(version) =
14455 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14456 {
14457 return Ok(Some((node_modules_directory, version)));
14458 }
14459 let Some(npm) = self.which("npm".as_ref()).await else {
14460 log::warn!(
14461 "Failed to find npm executable for {:?}",
14462 local_package_directory
14463 );
14464 return Ok(None);
14465 };
14466
14467 let env = self.shell_env().await;
14468 let output = util::command::new_command(&npm)
14469 .args(["root", "-g"])
14470 .envs(env)
14471 .current_dir(local_package_directory)
14472 .output()
14473 .await?;
14474 let global_node_modules =
14475 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14476
14477 if let Some(version) =
14478 read_package_installed_version(global_node_modules.clone(), package_name).await?
14479 {
14480 return Ok(Some((global_node_modules, version)));
14481 }
14482 return Ok(None);
14483 }
14484
14485 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14486 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14487 if self.fs.is_file(&worktree_abs_path).await {
14488 worktree_abs_path.pop();
14489 }
14490
14491 let env = self.shell_env().await;
14492
14493 let shell_path = env.get("PATH").cloned();
14494
14495 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14496 }
14497
14498 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14499 let mut working_dir = self.worktree_root_path().to_path_buf();
14500 if self.fs.is_file(&working_dir).await {
14501 working_dir.pop();
14502 }
14503 let output = util::command::new_command(&command.path)
14504 .args(command.arguments)
14505 .envs(command.env.clone().unwrap_or_default())
14506 .current_dir(working_dir)
14507 .output()
14508 .await?;
14509
14510 anyhow::ensure!(
14511 output.status.success(),
14512 "{}, stdout: {:?}, stderr: {:?}",
14513 output.status,
14514 String::from_utf8_lossy(&output.stdout),
14515 String::from_utf8_lossy(&output.stderr)
14516 );
14517 Ok(())
14518 }
14519
14520 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14521 self.language_registry
14522 .update_lsp_binary_status(server_name, status);
14523 }
14524
14525 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14526 self.language_registry
14527 .all_lsp_adapters()
14528 .into_iter()
14529 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14530 .collect()
14531 }
14532
14533 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14534 let dir = self.language_registry.language_server_download_dir(name)?;
14535
14536 if !dir.exists() {
14537 smol::fs::create_dir_all(&dir)
14538 .await
14539 .context("failed to create container directory")
14540 .log_err()?;
14541 }
14542
14543 Some(dir)
14544 }
14545
14546 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14547 let entry = self
14548 .worktree
14549 .entry_for_path(path)
14550 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14551 let abs_path = self.worktree.absolutize(&entry.path);
14552 self.fs.load(&abs_path).await
14553 }
14554}
14555
14556async fn populate_labels_for_symbols(
14557 symbols: Vec<CoreSymbol>,
14558 language_registry: &Arc<LanguageRegistry>,
14559 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14560 output: &mut Vec<Symbol>,
14561) {
14562 #[allow(clippy::mutable_key_type)]
14563 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14564
14565 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14566 for symbol in symbols {
14567 let Some(file_name) = symbol.path.file_name() else {
14568 continue;
14569 };
14570 let language = language_registry
14571 .load_language_for_file_path(Path::new(file_name))
14572 .await
14573 .ok()
14574 .or_else(|| {
14575 unknown_paths.insert(file_name.into());
14576 None
14577 });
14578 symbols_by_language
14579 .entry(language)
14580 .or_default()
14581 .push(symbol);
14582 }
14583
14584 for unknown_path in unknown_paths {
14585 log::info!("no language found for symbol in file {unknown_path:?}");
14586 }
14587
14588 let mut label_params = Vec::new();
14589 for (language, mut symbols) in symbols_by_language {
14590 label_params.clear();
14591 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14592 name: mem::take(&mut symbol.name),
14593 kind: symbol.kind,
14594 container_name: symbol.container_name.take(),
14595 }));
14596
14597 let mut labels = Vec::new();
14598 if let Some(language) = language {
14599 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14600 language_registry
14601 .lsp_adapters(&language.name())
14602 .first()
14603 .cloned()
14604 });
14605 if let Some(lsp_adapter) = lsp_adapter {
14606 labels = lsp_adapter
14607 .labels_for_symbols(&label_params, &language)
14608 .await
14609 .log_err()
14610 .unwrap_or_default();
14611 }
14612 }
14613
14614 for (
14615 (
14616 symbol,
14617 language::Symbol {
14618 name,
14619 container_name,
14620 ..
14621 },
14622 ),
14623 label,
14624 ) in symbols
14625 .into_iter()
14626 .zip(label_params.drain(..))
14627 .zip(labels.into_iter().chain(iter::repeat(None)))
14628 {
14629 output.push(Symbol {
14630 language_server_name: symbol.language_server_name,
14631 source_worktree_id: symbol.source_worktree_id,
14632 source_language_server_id: symbol.source_language_server_id,
14633 path: symbol.path,
14634 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14635 name,
14636 kind: symbol.kind,
14637 range: symbol.range,
14638 container_name,
14639 });
14640 }
14641 }
14642}
14643
14644pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14645 text.lines()
14646 .map(|line| line.trim())
14647 .filter(|line| !line.is_empty())
14648 .join(separator)
14649}
14650
14651fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14652 match server.capabilities().text_document_sync.as_ref()? {
14653 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14654 // Server wants didSave but didn't specify includeText.
14655 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14656 // Server doesn't want didSave at all.
14657 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14658 // Server provided SaveOptions.
14659 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14660 Some(save_options.include_text.unwrap_or(false))
14661 }
14662 },
14663 // We do not have any save info. Kind affects didChange only.
14664 lsp::TextDocumentSyncCapability::Kind(_) => None,
14665 }
14666}
14667
14668/// Completion items are displayed in a `UniformList`.
14669/// Usually, those items are single-line strings, but in LSP responses,
14670/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14671/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14672/// 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,
14673/// breaking the completions menu presentation.
14674///
14675/// 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.
14676pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14677 let mut new_text = String::with_capacity(label.text.len());
14678 let mut offset_map = vec![0; label.text.len() + 1];
14679 let mut last_char_was_space = false;
14680 let mut new_idx = 0;
14681 let chars = label.text.char_indices().fuse();
14682 let mut newlines_removed = false;
14683
14684 for (idx, c) in chars {
14685 offset_map[idx] = new_idx;
14686
14687 match c {
14688 '\n' if last_char_was_space => {
14689 newlines_removed = true;
14690 }
14691 '\t' | ' ' if last_char_was_space => {}
14692 '\n' if !last_char_was_space => {
14693 new_text.push(' ');
14694 new_idx += 1;
14695 last_char_was_space = true;
14696 newlines_removed = true;
14697 }
14698 ' ' | '\t' => {
14699 new_text.push(' ');
14700 new_idx += 1;
14701 last_char_was_space = true;
14702 }
14703 _ => {
14704 new_text.push(c);
14705 new_idx += c.len_utf8();
14706 last_char_was_space = false;
14707 }
14708 }
14709 }
14710 offset_map[label.text.len()] = new_idx;
14711
14712 // Only modify the label if newlines were removed.
14713 if !newlines_removed {
14714 return;
14715 }
14716
14717 let last_index = new_idx;
14718 let mut run_ranges_errors = Vec::new();
14719 label.runs.retain_mut(|(range, _)| {
14720 match offset_map.get(range.start) {
14721 Some(&start) => range.start = start,
14722 None => {
14723 run_ranges_errors.push(range.clone());
14724 return false;
14725 }
14726 }
14727
14728 match offset_map.get(range.end) {
14729 Some(&end) => range.end = end,
14730 None => {
14731 run_ranges_errors.push(range.clone());
14732 range.end = last_index;
14733 }
14734 }
14735 true
14736 });
14737 if !run_ranges_errors.is_empty() {
14738 log::error!(
14739 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14740 label.text
14741 );
14742 }
14743
14744 let mut wrong_filter_range = None;
14745 if label.filter_range == (0..label.text.len()) {
14746 label.filter_range = 0..new_text.len();
14747 } else {
14748 let mut original_filter_range = Some(label.filter_range.clone());
14749 match offset_map.get(label.filter_range.start) {
14750 Some(&start) => label.filter_range.start = start,
14751 None => {
14752 wrong_filter_range = original_filter_range.take();
14753 label.filter_range.start = last_index;
14754 }
14755 }
14756
14757 match offset_map.get(label.filter_range.end) {
14758 Some(&end) => label.filter_range.end = end,
14759 None => {
14760 wrong_filter_range = original_filter_range.take();
14761 label.filter_range.end = last_index;
14762 }
14763 }
14764 }
14765 if let Some(wrong_filter_range) = wrong_filter_range {
14766 log::error!(
14767 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14768 label.text
14769 );
14770 }
14771
14772 label.text = new_text;
14773}
14774
14775/// Apply edits to the buffer that will become part of the formatting transaction.
14776/// Fails if the buffer has been edited since the start of that transaction.
14777fn extend_formatting_transaction(
14778 buffer: &FormattableBuffer,
14779 formatting_transaction_id: text::TransactionId,
14780 cx: &mut AsyncApp,
14781 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14782) -> anyhow::Result<()> {
14783 buffer.handle.update(cx, |buffer, cx| {
14784 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14785 if last_transaction_id != Some(formatting_transaction_id) {
14786 anyhow::bail!("Buffer edited while formatting. Aborting")
14787 }
14788 buffer.start_transaction();
14789 operation(buffer, cx);
14790 if let Some(transaction_id) = buffer.end_transaction(cx) {
14791 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14792 }
14793 Ok(())
14794 })
14795}