1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
77 Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 language_settings,
81 },
82 point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153pub use semantic_tokens::{
154 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
155};
156
157pub use worktree::{
158 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
159 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
160};
161
162const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
163pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
164const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
165const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
166static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
167
168#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
169pub enum ProgressToken {
170 Number(i32),
171 String(SharedString),
172}
173
174impl std::fmt::Display for ProgressToken {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Number(number) => write!(f, "{number}"),
178 Self::String(string) => write!(f, "{string}"),
179 }
180 }
181}
182
183impl ProgressToken {
184 fn from_lsp(value: lsp::NumberOrString) -> Self {
185 match value {
186 lsp::NumberOrString::Number(number) => Self::Number(number),
187 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
188 }
189 }
190
191 fn to_lsp(&self) -> lsp::NumberOrString {
192 match self {
193 Self::Number(number) => lsp::NumberOrString::Number(*number),
194 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
195 }
196 }
197
198 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
199 Some(match value.value? {
200 proto::progress_token::Value::Number(number) => Self::Number(number),
201 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
202 })
203 }
204
205 fn to_proto(&self) -> proto::ProgressToken {
206 proto::ProgressToken {
207 value: Some(match self {
208 Self::Number(number) => proto::progress_token::Value::Number(*number),
209 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
210 }),
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum FormatTrigger {
217 Save,
218 Manual,
219}
220
221pub enum LspFormatTarget {
222 Buffers,
223 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
228
229struct OpenLspBuffer(Entity<Buffer>);
230
231impl FormatTrigger {
232 fn from_proto(value: i32) -> FormatTrigger {
233 match value {
234 0 => FormatTrigger::Save,
235 1 => FormatTrigger::Manual,
236 _ => FormatTrigger::Save,
237 }
238 }
239}
240
241#[derive(Clone)]
242struct UnifiedLanguageServer {
243 id: LanguageServerId,
244 project_roots: HashSet<Arc<RelPath>>,
245}
246
247/// Settings that affect language server identity.
248///
249/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
250/// updated via `workspace/didChangeConfiguration` without restarting the server.
251#[derive(Clone, Debug, Hash, PartialEq, Eq)]
252struct LanguageServerSeedSettings {
253 binary: Option<BinarySettings>,
254 initialization_options: Option<serde_json::Value>,
255}
256
257#[derive(Clone, Debug, Hash, PartialEq, Eq)]
258struct LanguageServerSeed {
259 worktree_id: WorktreeId,
260 name: LanguageServerName,
261 toolchain: Option<Toolchain>,
262 settings: LanguageServerSeedSettings,
263}
264
265#[derive(Debug)]
266pub struct DocumentDiagnosticsUpdate<'a, D> {
267 pub diagnostics: D,
268 pub result_id: Option<SharedString>,
269 pub registration_id: Option<SharedString>,
270 pub server_id: LanguageServerId,
271 pub disk_based_sources: Cow<'a, [String]>,
272}
273
274pub struct DocumentDiagnostics {
275 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 document_abs_path: PathBuf,
277 version: Option<i32>,
278}
279
280#[derive(Default, Debug)]
281struct DynamicRegistrations {
282 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
283 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
284}
285
286pub struct LocalLspStore {
287 weak: WeakEntity<LspStore>,
288 pub worktree_store: Entity<WorktreeStore>,
289 toolchain_store: Entity<LocalToolchainStore>,
290 http_client: Arc<dyn HttpClient>,
291 environment: Entity<ProjectEnvironment>,
292 fs: Arc<dyn Fs>,
293 languages: Arc<LanguageRegistry>,
294 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
295 yarn: Entity<YarnPathStore>,
296 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
297 buffers_being_formatted: HashSet<BufferId>,
298 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
299 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
300 watched_manifest_filenames: HashSet<ManifestName>,
301 language_server_paths_watched_for_rename:
302 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
303 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
304 supplementary_language_servers:
305 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
306 prettier_store: Entity<PrettierStore>,
307 next_diagnostic_group_id: usize,
308 diagnostics: HashMap<
309 WorktreeId,
310 HashMap<
311 Arc<RelPath>,
312 Vec<(
313 LanguageServerId,
314 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
315 )>,
316 >,
317 >,
318 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
319 _subscription: gpui::Subscription,
320 lsp_tree: LanguageServerTree,
321 registered_buffers: HashMap<BufferId, usize>,
322 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
323 buffer_pull_diagnostics_result_ids: HashMap<
324 LanguageServerId,
325 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
326 >,
327 workspace_pull_diagnostics_result_ids: HashMap<
328 LanguageServerId,
329 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
330 >,
331 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
332
333 buffers_to_refresh_hash_set: HashSet<BufferId>,
334 buffers_to_refresh_queue: VecDeque<BufferId>,
335 _background_diagnostics_worker: Shared<Task<()>>,
336}
337
338impl LocalLspStore {
339 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
340 pub fn running_language_server_for_id(
341 &self,
342 id: LanguageServerId,
343 ) -> Option<&Arc<LanguageServer>> {
344 let language_server_state = self.language_servers.get(&id)?;
345
346 match language_server_state {
347 LanguageServerState::Running { server, .. } => Some(server),
348 LanguageServerState::Starting { .. } => None,
349 }
350 }
351
352 fn get_or_insert_language_server(
353 &mut self,
354 worktree_handle: &Entity<Worktree>,
355 delegate: Arc<LocalLspAdapterDelegate>,
356 disposition: &Arc<LaunchDisposition>,
357 language_name: &LanguageName,
358 cx: &mut App,
359 ) -> LanguageServerId {
360 let key = LanguageServerSeed {
361 worktree_id: worktree_handle.read(cx).id(),
362 name: disposition.server_name.clone(),
363 settings: LanguageServerSeedSettings {
364 binary: disposition.settings.binary.clone(),
365 initialization_options: disposition.settings.initialization_options.clone(),
366 },
367 toolchain: disposition.toolchain.clone(),
368 };
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 state.id
372 } else {
373 let adapter = self
374 .languages
375 .lsp_adapters(language_name)
376 .into_iter()
377 .find(|adapter| adapter.name() == disposition.server_name)
378 .expect("To find LSP adapter");
379 let new_language_server_id = self.start_language_server(
380 worktree_handle,
381 delegate,
382 adapter,
383 disposition.settings.clone(),
384 key.clone(),
385 language_name.clone(),
386 cx,
387 );
388 if let Some(state) = self.language_server_ids.get_mut(&key) {
389 state.project_roots.insert(disposition.path.path.clone());
390 } else {
391 debug_assert!(
392 false,
393 "Expected `start_language_server` to ensure that `key` exists in a map"
394 );
395 }
396 new_language_server_id
397 }
398 }
399
400 fn start_language_server(
401 &mut self,
402 worktree_handle: &Entity<Worktree>,
403 delegate: Arc<LocalLspAdapterDelegate>,
404 adapter: Arc<CachedLspAdapter>,
405 settings: Arc<LspSettings>,
406 key: LanguageServerSeed,
407 language_name: LanguageName,
408 cx: &mut App,
409 ) -> LanguageServerId {
410 let worktree = worktree_handle.read(cx);
411
412 let worktree_id = worktree.id();
413 let worktree_abs_path = worktree.abs_path();
414 let toolchain = key.toolchain.clone();
415 let override_options = settings.initialization_options.clone();
416
417 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
418
419 let server_id = self.languages.next_language_server_id();
420 log::trace!(
421 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
422 adapter.name.0
423 );
424
425 let wait_until_worktree_trust =
426 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
427 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
428 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
429 });
430 if can_trust {
431 self.restricted_worktrees_tasks.remove(&worktree_id);
432 None
433 } else {
434 match self.restricted_worktrees_tasks.entry(worktree_id) {
435 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
436 hash_map::Entry::Vacant(v) => {
437 let (mut tx, rx) = watch::channel::<bool>();
438 let lsp_store = self.weak.clone();
439 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
440 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
441 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
442 tx.blocking_send(true).ok();
443 lsp_store
444 .update(cx, |lsp_store, _| {
445 if let Some(local_lsp_store) =
446 lsp_store.as_local_mut()
447 {
448 local_lsp_store
449 .restricted_worktrees_tasks
450 .remove(&worktree_id);
451 }
452 })
453 .ok();
454 }
455 }
456 });
457 v.insert((subscription, rx.clone()));
458 Some(rx)
459 }
460 }
461 }
462 });
463 let update_binary_status = wait_until_worktree_trust.is_none();
464
465 let binary = self.get_language_server_binary(
466 worktree_abs_path.clone(),
467 adapter.clone(),
468 settings,
469 toolchain.clone(),
470 delegate.clone(),
471 true,
472 wait_until_worktree_trust,
473 cx,
474 );
475 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
476
477 let pending_server = cx.spawn({
478 let adapter = adapter.clone();
479 let server_name = adapter.name.clone();
480 let stderr_capture = stderr_capture.clone();
481 #[cfg(any(test, feature = "test-support"))]
482 let lsp_store = self.weak.clone();
483 let pending_workspace_folders = pending_workspace_folders.clone();
484 async move |cx| {
485 let binary = binary.await?;
486 #[cfg(any(test, feature = "test-support"))]
487 if let Some(server) = lsp_store
488 .update(&mut cx.clone(), |this, cx| {
489 this.languages.create_fake_language_server(
490 server_id,
491 &server_name,
492 binary.clone(),
493 &mut cx.to_async(),
494 )
495 })
496 .ok()
497 .flatten()
498 {
499 return Ok(server);
500 }
501
502 let code_action_kinds = adapter.code_action_kinds();
503 lsp::LanguageServer::new(
504 stderr_capture,
505 server_id,
506 server_name,
507 binary,
508 &worktree_abs_path,
509 code_action_kinds,
510 Some(pending_workspace_folders),
511 cx,
512 )
513 }
514 });
515
516 let startup = {
517 let server_name = adapter.name.0.clone();
518 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
519 let key = key.clone();
520 let adapter = adapter.clone();
521 let lsp_store = self.weak.clone();
522 let pending_workspace_folders = pending_workspace_folders.clone();
523 let pull_diagnostics = ProjectSettings::get_global(cx)
524 .diagnostics
525 .lsp_pull_diagnostics
526 .enabled;
527 let settings_location = SettingsLocation {
528 worktree_id,
529 path: RelPath::empty(),
530 };
531 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
532 .language(Some(settings_location), Some(&language_name), cx)
533 .semantic_tokens
534 .use_tree_sitter();
535 cx.spawn(async move |cx| {
536 let result = async {
537 let language_server = pending_server.await?;
538
539 let workspace_config = Self::workspace_configuration_for_adapter(
540 adapter.adapter.clone(),
541 &delegate,
542 toolchain,
543 None,
544 cx,
545 )
546 .await?;
547
548 let mut initialization_options = Self::initialization_options_for_adapter(
549 adapter.adapter.clone(),
550 &delegate,
551 cx,
552 )
553 .await?;
554
555 match (&mut initialization_options, override_options) {
556 (Some(initialization_options), Some(override_options)) => {
557 merge_json_value_into(override_options, initialization_options);
558 }
559 (None, override_options) => initialization_options = override_options,
560 _ => {}
561 }
562
563 let initialization_params = cx.update(|cx| {
564 let mut params = language_server.default_initialize_params(
565 pull_diagnostics,
566 augments_syntax_tokens,
567 cx,
568 );
569 params.initialization_options = initialization_options;
570 adapter.adapter.prepare_initialize_params(params, cx)
571 })?;
572
573 Self::setup_lsp_messages(
574 lsp_store.clone(),
575 &language_server,
576 delegate.clone(),
577 adapter.clone(),
578 );
579
580 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
581 settings: workspace_config,
582 };
583 let language_server = cx
584 .update(|cx| {
585 let request_timeout = ProjectSettings::get_global(cx)
586 .global_lsp_settings
587 .get_request_timeout();
588
589 language_server.initialize(
590 initialization_params,
591 Arc::new(did_change_configuration_params.clone()),
592 request_timeout,
593 cx,
594 )
595 })
596 .await
597 .inspect_err(|_| {
598 if let Some(lsp_store) = lsp_store.upgrade() {
599 lsp_store.update(cx, |lsp_store, cx| {
600 lsp_store.cleanup_lsp_data(server_id);
601 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
602 });
603 }
604 })?;
605
606 language_server.notify::<lsp::notification::DidChangeConfiguration>(
607 did_change_configuration_params,
608 )?;
609
610 anyhow::Ok(language_server)
611 }
612 .await;
613
614 match result {
615 Ok(server) => {
616 lsp_store
617 .update(cx, |lsp_store, cx| {
618 lsp_store.insert_newly_running_language_server(
619 adapter,
620 server.clone(),
621 server_id,
622 key,
623 pending_workspace_folders,
624 cx,
625 );
626 })
627 .ok();
628 stderr_capture.lock().take();
629 Some(server)
630 }
631
632 Err(err) => {
633 let log = stderr_capture.lock().take().unwrap_or_default();
634 delegate.update_status(
635 adapter.name(),
636 BinaryStatus::Failed {
637 error: if log.is_empty() {
638 format!("{err:#}")
639 } else {
640 format!("{err:#}\n-- stderr --\n{log}")
641 },
642 },
643 );
644 log::error!(
645 "Failed to start language server {server_name:?}: {}",
646 redact_command(&format!("{err:?}"))
647 );
648 if !log.is_empty() {
649 log::error!("server stderr: {}", redact_command(&log));
650 }
651 None
652 }
653 }
654 })
655 };
656 let state = LanguageServerState::Starting {
657 startup,
658 pending_workspace_folders,
659 };
660
661 if update_binary_status {
662 self.languages
663 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
664 }
665
666 self.language_servers.insert(server_id, state);
667 self.language_server_ids
668 .entry(key)
669 .or_insert(UnifiedLanguageServer {
670 id: server_id,
671 project_roots: Default::default(),
672 });
673 server_id
674 }
675
676 fn get_language_server_binary(
677 &self,
678 worktree_abs_path: Arc<Path>,
679 adapter: Arc<CachedLspAdapter>,
680 settings: Arc<LspSettings>,
681 toolchain: Option<Toolchain>,
682 delegate: Arc<dyn LspAdapterDelegate>,
683 allow_binary_download: bool,
684 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
685 cx: &mut App,
686 ) -> Task<Result<LanguageServerBinary>> {
687 if let Some(settings) = &settings.binary
688 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
689 {
690 let settings = settings.clone();
691 let languages = self.languages.clone();
692 return cx.background_spawn(async move {
693 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
694 let already_trusted = *wait_until_worktree_trust.borrow();
695 if !already_trusted {
696 log::info!(
697 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
698 adapter.name(),
699 );
700 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
701 if worktree_trusted {
702 break;
703 }
704 }
705 log::info!(
706 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
707 adapter.name(),
708 );
709 }
710 languages
711 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
712 }
713 let mut env = delegate.shell_env().await;
714 env.extend(settings.env.unwrap_or_default());
715
716 Ok(LanguageServerBinary {
717 path: delegate.resolve_relative_path(path),
718 env: Some(env),
719 arguments: settings
720 .arguments
721 .unwrap_or_default()
722 .iter()
723 .map(Into::into)
724 .collect(),
725 })
726 });
727 }
728 let lsp_binary_options = LanguageServerBinaryOptions {
729 allow_path_lookup: !settings
730 .binary
731 .as_ref()
732 .and_then(|b| b.ignore_system_version)
733 .unwrap_or_default(),
734 allow_binary_download,
735 pre_release: settings
736 .fetch
737 .as_ref()
738 .and_then(|f| f.pre_release)
739 .unwrap_or(false),
740 };
741
742 cx.spawn(async move |cx| {
743 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
744 let already_trusted = *wait_until_worktree_trust.borrow();
745 if !already_trusted {
746 log::info!(
747 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
748 adapter.name(),
749 );
750 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
751 if worktree_trusted {
752 break;
753 }
754 }
755 log::info!(
756 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
757 adapter.name(),
758 );
759 }
760 }
761
762 let (existing_binary, maybe_download_binary) = adapter
763 .clone()
764 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
765 .await
766 .await;
767
768 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
769
770 let mut binary = match (existing_binary, maybe_download_binary) {
771 (binary, None) => binary?,
772 (Err(_), Some(downloader)) => downloader.await?,
773 (Ok(existing_binary), Some(downloader)) => {
774 let mut download_timeout = cx
775 .background_executor()
776 .timer(SERVER_DOWNLOAD_TIMEOUT)
777 .fuse();
778 let mut downloader = downloader.fuse();
779 futures::select! {
780 _ = download_timeout => {
781 // Return existing binary and kick the existing work to the background.
782 cx.spawn(async move |_| downloader.await).detach();
783 Ok(existing_binary)
784 },
785 downloaded_or_existing_binary = downloader => {
786 // If download fails, this results in the existing binary.
787 downloaded_or_existing_binary
788 }
789 }?
790 }
791 };
792 let mut shell_env = delegate.shell_env().await;
793
794 shell_env.extend(binary.env.unwrap_or_default());
795
796 if let Some(settings) = settings.binary.as_ref() {
797 if let Some(arguments) = &settings.arguments {
798 binary.arguments = arguments.iter().map(Into::into).collect();
799 }
800 if let Some(env) = &settings.env {
801 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
802 }
803 }
804
805 binary.env = Some(shell_env);
806 Ok(binary)
807 })
808 }
809
810 fn setup_lsp_messages(
811 lsp_store: WeakEntity<LspStore>,
812 language_server: &LanguageServer,
813 delegate: Arc<dyn LspAdapterDelegate>,
814 adapter: Arc<CachedLspAdapter>,
815 ) {
816 let name = language_server.name();
817 let server_id = language_server.server_id();
818 language_server
819 .on_notification::<lsp::notification::PublishDiagnostics, _>({
820 let adapter = adapter.clone();
821 let this = lsp_store.clone();
822 move |mut params, cx| {
823 let adapter = adapter.clone();
824 if let Some(this) = this.upgrade() {
825 this.update(cx, |this, cx| {
826 {
827 let buffer = params
828 .uri
829 .to_file_path()
830 .map(|file_path| this.get_buffer(&file_path, cx))
831 .ok()
832 .flatten();
833 adapter.process_diagnostics(&mut params, server_id, buffer);
834 }
835
836 this.merge_lsp_diagnostics(
837 DiagnosticSourceKind::Pushed,
838 vec![DocumentDiagnosticsUpdate {
839 server_id,
840 diagnostics: params,
841 result_id: None,
842 disk_based_sources: Cow::Borrowed(
843 &adapter.disk_based_diagnostic_sources,
844 ),
845 registration_id: None,
846 }],
847 |_, diagnostic, cx| match diagnostic.source_kind {
848 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
849 adapter.retain_old_diagnostic(diagnostic, cx)
850 }
851 DiagnosticSourceKind::Pulled => true,
852 },
853 cx,
854 )
855 .log_err();
856 });
857 }
858 }
859 })
860 .detach();
861 language_server
862 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
863 let adapter = adapter.adapter.clone();
864 let delegate = delegate.clone();
865 let this = lsp_store.clone();
866 move |params, cx| {
867 let adapter = adapter.clone();
868 let delegate = delegate.clone();
869 let this = this.clone();
870 let mut cx = cx.clone();
871 async move {
872 let toolchain_for_id = this
873 .update(&mut cx, |this, _| {
874 this.as_local()?.language_server_ids.iter().find_map(
875 |(seed, value)| {
876 (value.id == server_id).then(|| seed.toolchain.clone())
877 },
878 )
879 })?
880 .context("Expected the LSP store to be in a local mode")?;
881
882 let mut scope_uri_to_workspace_config = BTreeMap::new();
883 for item in ¶ms.items {
884 let scope_uri = item.scope_uri.clone();
885 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
886 scope_uri_to_workspace_config.entry(scope_uri.clone())
887 else {
888 // We've already queried workspace configuration of this URI.
889 continue;
890 };
891 let workspace_config = Self::workspace_configuration_for_adapter(
892 adapter.clone(),
893 &delegate,
894 toolchain_for_id.clone(),
895 scope_uri,
896 &mut cx,
897 )
898 .await?;
899 new_scope_uri.insert(workspace_config);
900 }
901
902 Ok(params
903 .items
904 .into_iter()
905 .filter_map(|item| {
906 let workspace_config =
907 scope_uri_to_workspace_config.get(&item.scope_uri)?;
908 if let Some(section) = &item.section {
909 Some(
910 workspace_config
911 .get(section)
912 .cloned()
913 .unwrap_or(serde_json::Value::Null),
914 )
915 } else {
916 Some(workspace_config.clone())
917 }
918 })
919 .collect())
920 }
921 }
922 })
923 .detach();
924
925 language_server
926 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
927 let this = lsp_store.clone();
928 move |_, cx| {
929 let this = this.clone();
930 let cx = cx.clone();
931 async move {
932 let Some(server) =
933 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
934 else {
935 return Ok(None);
936 };
937 let root = server.workspace_folders();
938 Ok(Some(
939 root.into_iter()
940 .map(|uri| WorkspaceFolder {
941 uri,
942 name: Default::default(),
943 })
944 .collect(),
945 ))
946 }
947 }
948 })
949 .detach();
950 // Even though we don't have handling for these requests, respond to them to
951 // avoid stalling any language server like `gopls` which waits for a response
952 // to these requests when initializing.
953 language_server
954 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
955 let this = lsp_store.clone();
956 move |params, cx| {
957 let this = this.clone();
958 let mut cx = cx.clone();
959 async move {
960 this.update(&mut cx, |this, _| {
961 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
962 {
963 status
964 .progress_tokens
965 .insert(ProgressToken::from_lsp(params.token));
966 }
967 })?;
968
969 Ok(())
970 }
971 }
972 })
973 .detach();
974
975 language_server
976 .on_request::<lsp::request::RegisterCapability, _, _>({
977 let lsp_store = lsp_store.clone();
978 move |params, cx| {
979 let lsp_store = lsp_store.clone();
980 let mut cx = cx.clone();
981 async move {
982 lsp_store
983 .update(&mut cx, |lsp_store, cx| {
984 if lsp_store.as_local().is_some() {
985 match lsp_store
986 .register_server_capabilities(server_id, params, cx)
987 {
988 Ok(()) => {}
989 Err(e) => {
990 log::error!(
991 "Failed to register server capabilities: {e:#}"
992 );
993 }
994 };
995 }
996 })
997 .ok();
998 Ok(())
999 }
1000 }
1001 })
1002 .detach();
1003
1004 language_server
1005 .on_request::<lsp::request::UnregisterCapability, _, _>({
1006 let lsp_store = lsp_store.clone();
1007 move |params, cx| {
1008 let lsp_store = lsp_store.clone();
1009 let mut cx = cx.clone();
1010 async move {
1011 lsp_store
1012 .update(&mut cx, |lsp_store, cx| {
1013 if lsp_store.as_local().is_some() {
1014 match lsp_store
1015 .unregister_server_capabilities(server_id, params, cx)
1016 {
1017 Ok(()) => {}
1018 Err(e) => {
1019 log::error!(
1020 "Failed to unregister server capabilities: {e:#}"
1021 );
1022 }
1023 }
1024 }
1025 })
1026 .ok();
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1035 let this = lsp_store.clone();
1036 move |params, cx| {
1037 let mut cx = cx.clone();
1038 let this = this.clone();
1039 async move {
1040 LocalLspStore::on_lsp_workspace_edit(
1041 this.clone(),
1042 params,
1043 server_id,
1044 &mut cx,
1045 )
1046 .await
1047 }
1048 }
1049 })
1050 .detach();
1051
1052 language_server
1053 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1054 let lsp_store = lsp_store.clone();
1055 let request_id = Arc::new(AtomicUsize::new(0));
1056 move |(), cx| {
1057 let lsp_store = lsp_store.clone();
1058 let request_id = request_id.clone();
1059 let mut cx = cx.clone();
1060 async move {
1061 lsp_store
1062 .update(&mut cx, |lsp_store, cx| {
1063 let request_id =
1064 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1065 cx.emit(LspStoreEvent::RefreshInlayHints {
1066 server_id,
1067 request_id,
1068 });
1069 lsp_store
1070 .downstream_client
1071 .as_ref()
1072 .map(|(client, project_id)| {
1073 client.send(proto::RefreshInlayHints {
1074 project_id: *project_id,
1075 server_id: server_id.to_proto(),
1076 request_id: request_id.map(|id| id as u64),
1077 })
1078 })
1079 })?
1080 .transpose()?;
1081 Ok(())
1082 }
1083 }
1084 })
1085 .detach();
1086
1087 language_server
1088 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1089 let this = lsp_store.clone();
1090 move |(), cx| {
1091 let this = this.clone();
1092 let mut cx = cx.clone();
1093 async move {
1094 this.update(&mut cx, |this, cx| {
1095 cx.emit(LspStoreEvent::RefreshCodeLens);
1096 this.downstream_client.as_ref().map(|(client, project_id)| {
1097 client.send(proto::RefreshCodeLens {
1098 project_id: *project_id,
1099 })
1100 })
1101 })?
1102 .transpose()?;
1103 Ok(())
1104 }
1105 }
1106 })
1107 .detach();
1108
1109 language_server
1110 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1111 let lsp_store = lsp_store.clone();
1112 let request_id = Arc::new(AtomicUsize::new(0));
1113 move |(), cx| {
1114 let lsp_store = lsp_store.clone();
1115 let request_id = request_id.clone();
1116 let mut cx = cx.clone();
1117 async move {
1118 lsp_store
1119 .update(&mut cx, |lsp_store, cx| {
1120 let request_id =
1121 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1122 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1123 server_id,
1124 request_id,
1125 });
1126 lsp_store
1127 .downstream_client
1128 .as_ref()
1129 .map(|(client, project_id)| {
1130 client.send(proto::RefreshSemanticTokens {
1131 project_id: *project_id,
1132 server_id: server_id.to_proto(),
1133 request_id: request_id.map(|id| id as u64),
1134 })
1135 })
1136 })?
1137 .transpose()?;
1138 Ok(())
1139 }
1140 }
1141 })
1142 .detach();
1143
1144 language_server
1145 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1146 let this = lsp_store.clone();
1147 move |(), cx| {
1148 let this = this.clone();
1149 let mut cx = cx.clone();
1150 async move {
1151 this.update(&mut cx, |lsp_store, cx| {
1152 lsp_store.pull_workspace_diagnostics(server_id);
1153 lsp_store
1154 .downstream_client
1155 .as_ref()
1156 .map(|(client, project_id)| {
1157 client.send(proto::PullWorkspaceDiagnostics {
1158 project_id: *project_id,
1159 server_id: server_id.to_proto(),
1160 })
1161 })
1162 .transpose()?;
1163 anyhow::Ok(
1164 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1165 )
1166 })??
1167 .await;
1168 Ok(())
1169 }
1170 }
1171 })
1172 .detach();
1173
1174 language_server
1175 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1176 let this = lsp_store.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 move |params, cx| {
1180 let this = this.clone();
1181 let name = name.to_string();
1182 let adapter = adapter.clone();
1183 let mut cx = cx.clone();
1184 async move {
1185 let actions = params.actions.unwrap_or_default();
1186 let message = params.message.clone();
1187 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1188 let level = match params.typ {
1189 lsp::MessageType::ERROR => PromptLevel::Critical,
1190 lsp::MessageType::WARNING => PromptLevel::Warning,
1191 _ => PromptLevel::Info,
1192 };
1193 let request = LanguageServerPromptRequest::new(
1194 level,
1195 params.message,
1196 actions,
1197 name.clone(),
1198 tx,
1199 );
1200
1201 let did_update = this
1202 .update(&mut cx, |_, cx| {
1203 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1204 })
1205 .is_ok();
1206 if did_update {
1207 let response = rx.recv().await.ok();
1208 if let Some(ref selected_action) = response {
1209 let context = language::PromptResponseContext {
1210 message,
1211 selected_action: selected_action.clone(),
1212 };
1213 adapter.process_prompt_response(&context, &mut cx)
1214 }
1215
1216 Ok(response)
1217 } else {
1218 Ok(None)
1219 }
1220 }
1221 }
1222 })
1223 .detach();
1224 language_server
1225 .on_notification::<lsp::notification::ShowMessage, _>({
1226 let this = lsp_store.clone();
1227 let name = name.to_string();
1228 move |params, cx| {
1229 let this = this.clone();
1230 let name = name.to_string();
1231 let mut cx = cx.clone();
1232
1233 let (tx, _) = smol::channel::bounded(1);
1234 let level = match params.typ {
1235 lsp::MessageType::ERROR => PromptLevel::Critical,
1236 lsp::MessageType::WARNING => PromptLevel::Warning,
1237 _ => PromptLevel::Info,
1238 };
1239 let request =
1240 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1241
1242 let _ = this.update(&mut cx, |_, cx| {
1243 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1244 });
1245 }
1246 })
1247 .detach();
1248
1249 let disk_based_diagnostics_progress_token =
1250 adapter.disk_based_diagnostics_progress_token.clone();
1251
1252 language_server
1253 .on_notification::<lsp::notification::Progress, _>({
1254 let this = lsp_store.clone();
1255 move |params, cx| {
1256 if let Some(this) = this.upgrade() {
1257 this.update(cx, |this, cx| {
1258 this.on_lsp_progress(
1259 params,
1260 server_id,
1261 disk_based_diagnostics_progress_token.clone(),
1262 cx,
1263 );
1264 });
1265 }
1266 }
1267 })
1268 .detach();
1269
1270 language_server
1271 .on_notification::<lsp::notification::LogMessage, _>({
1272 let this = lsp_store.clone();
1273 move |params, cx| {
1274 if let Some(this) = this.upgrade() {
1275 this.update(cx, |_, cx| {
1276 cx.emit(LspStoreEvent::LanguageServerLog(
1277 server_id,
1278 LanguageServerLogType::Log(params.typ),
1279 params.message,
1280 ));
1281 });
1282 }
1283 }
1284 })
1285 .detach();
1286
1287 language_server
1288 .on_notification::<lsp::notification::LogTrace, _>({
1289 let this = lsp_store.clone();
1290 move |params, cx| {
1291 let mut cx = cx.clone();
1292 if let Some(this) = this.upgrade() {
1293 this.update(&mut cx, |_, cx| {
1294 cx.emit(LspStoreEvent::LanguageServerLog(
1295 server_id,
1296 LanguageServerLogType::Trace {
1297 verbose_info: params.verbose,
1298 },
1299 params.message,
1300 ));
1301 });
1302 }
1303 }
1304 })
1305 .detach();
1306
1307 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1309 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1310 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1311 }
1312
1313 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1314 let shutdown_futures = self
1315 .language_servers
1316 .drain()
1317 .map(|(_, server_state)| Self::shutdown_server(server_state))
1318 .collect::<Vec<_>>();
1319
1320 async move {
1321 join_all(shutdown_futures).await;
1322 }
1323 }
1324
1325 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1326 match server_state {
1327 LanguageServerState::Running { server, .. } => {
1328 if let Some(shutdown) = server.shutdown() {
1329 shutdown.await;
1330 }
1331 }
1332 LanguageServerState::Starting { startup, .. } => {
1333 if let Some(server) = startup.await
1334 && let Some(shutdown) = server.shutdown()
1335 {
1336 shutdown.await;
1337 }
1338 }
1339 }
1340 Ok(())
1341 }
1342
1343 fn language_servers_for_worktree(
1344 &self,
1345 worktree_id: WorktreeId,
1346 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1347 self.language_server_ids
1348 .iter()
1349 .filter_map(move |(seed, state)| {
1350 if seed.worktree_id != worktree_id {
1351 return None;
1352 }
1353
1354 if let Some(LanguageServerState::Running { server, .. }) =
1355 self.language_servers.get(&state.id)
1356 {
1357 Some(server)
1358 } else {
1359 None
1360 }
1361 })
1362 }
1363
1364 fn language_server_ids_for_project_path(
1365 &self,
1366 project_path: ProjectPath,
1367 language: &Language,
1368 cx: &mut App,
1369 ) -> Vec<LanguageServerId> {
1370 let Some(worktree) = self
1371 .worktree_store
1372 .read(cx)
1373 .worktree_for_id(project_path.worktree_id, cx)
1374 else {
1375 return Vec::new();
1376 };
1377 let delegate: Arc<dyn ManifestDelegate> =
1378 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1379
1380 self.lsp_tree
1381 .get(
1382 project_path,
1383 language.name(),
1384 language.manifest(),
1385 &delegate,
1386 cx,
1387 )
1388 .collect::<Vec<_>>()
1389 }
1390
1391 fn language_server_ids_for_buffer(
1392 &self,
1393 buffer: &Buffer,
1394 cx: &mut App,
1395 ) -> Vec<LanguageServerId> {
1396 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1397 let worktree_id = file.worktree_id(cx);
1398
1399 let path: Arc<RelPath> = file
1400 .path()
1401 .parent()
1402 .map(Arc::from)
1403 .unwrap_or_else(|| file.path().clone());
1404 let worktree_path = ProjectPath { worktree_id, path };
1405 self.language_server_ids_for_project_path(worktree_path, language, cx)
1406 } else {
1407 Vec::new()
1408 }
1409 }
1410
1411 fn language_servers_for_buffer<'a>(
1412 &'a self,
1413 buffer: &'a Buffer,
1414 cx: &'a mut App,
1415 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1416 self.language_server_ids_for_buffer(buffer, cx)
1417 .into_iter()
1418 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1419 LanguageServerState::Running {
1420 adapter, server, ..
1421 } => Some((adapter, server)),
1422 _ => None,
1423 })
1424 }
1425
1426 async fn execute_code_action_kind_locally(
1427 lsp_store: WeakEntity<LspStore>,
1428 mut buffers: Vec<Entity<Buffer>>,
1429 kind: CodeActionKind,
1430 push_to_history: bool,
1431 cx: &mut AsyncApp,
1432 ) -> anyhow::Result<ProjectTransaction> {
1433 // Do not allow multiple concurrent code actions requests for the
1434 // same buffer.
1435 lsp_store.update(cx, |this, cx| {
1436 let this = this.as_local_mut().unwrap();
1437 buffers.retain(|buffer| {
1438 this.buffers_being_formatted
1439 .insert(buffer.read(cx).remote_id())
1440 });
1441 })?;
1442 let _cleanup = defer({
1443 let this = lsp_store.clone();
1444 let mut cx = cx.clone();
1445 let buffers = &buffers;
1446 move || {
1447 this.update(&mut cx, |this, cx| {
1448 let this = this.as_local_mut().unwrap();
1449 for buffer in buffers {
1450 this.buffers_being_formatted
1451 .remove(&buffer.read(cx).remote_id());
1452 }
1453 })
1454 .ok();
1455 }
1456 });
1457 let mut project_transaction = ProjectTransaction::default();
1458
1459 for buffer in &buffers {
1460 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1461 buffer.update(cx, |buffer, cx| {
1462 lsp_store
1463 .as_local()
1464 .unwrap()
1465 .language_servers_for_buffer(buffer, cx)
1466 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1467 .collect::<Vec<_>>()
1468 })
1469 })?;
1470 for (_, language_server) in adapters_and_servers.iter() {
1471 let actions = Self::get_server_code_actions_from_action_kinds(
1472 &lsp_store,
1473 language_server.server_id(),
1474 vec![kind.clone()],
1475 buffer,
1476 cx,
1477 )
1478 .await?;
1479 Self::execute_code_actions_on_server(
1480 &lsp_store,
1481 language_server,
1482 actions,
1483 push_to_history,
1484 &mut project_transaction,
1485 cx,
1486 )
1487 .await?;
1488 }
1489 }
1490 Ok(project_transaction)
1491 }
1492
1493 async fn format_locally(
1494 lsp_store: WeakEntity<LspStore>,
1495 mut buffers: Vec<FormattableBuffer>,
1496 push_to_history: bool,
1497 trigger: FormatTrigger,
1498 logger: zlog::Logger,
1499 cx: &mut AsyncApp,
1500 ) -> anyhow::Result<ProjectTransaction> {
1501 // Do not allow multiple concurrent formatting requests for the
1502 // same buffer.
1503 lsp_store.update(cx, |this, cx| {
1504 let this = this.as_local_mut().unwrap();
1505 buffers.retain(|buffer| {
1506 this.buffers_being_formatted
1507 .insert(buffer.handle.read(cx).remote_id())
1508 });
1509 })?;
1510
1511 let _cleanup = defer({
1512 let this = lsp_store.clone();
1513 let mut cx = cx.clone();
1514 let buffers = &buffers;
1515 move || {
1516 this.update(&mut cx, |this, cx| {
1517 let this = this.as_local_mut().unwrap();
1518 for buffer in buffers {
1519 this.buffers_being_formatted
1520 .remove(&buffer.handle.read(cx).remote_id());
1521 }
1522 })
1523 .ok();
1524 }
1525 });
1526
1527 let mut project_transaction = ProjectTransaction::default();
1528
1529 for buffer in &buffers {
1530 zlog::debug!(
1531 logger =>
1532 "formatting buffer '{:?}'",
1533 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1534 );
1535 // Create an empty transaction to hold all of the formatting edits.
1536 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1537 // ensure no transactions created while formatting are
1538 // grouped with the previous transaction in the history
1539 // based on the transaction group interval
1540 buffer.finalize_last_transaction();
1541 buffer
1542 .start_transaction()
1543 .context("transaction already open")?;
1544 buffer.end_transaction(cx);
1545 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1546 buffer.finalize_last_transaction();
1547 anyhow::Ok(transaction_id)
1548 })?;
1549
1550 let result = Self::format_buffer_locally(
1551 lsp_store.clone(),
1552 buffer,
1553 formatting_transaction_id,
1554 trigger,
1555 logger,
1556 cx,
1557 )
1558 .await;
1559
1560 buffer.handle.update(cx, |buffer, cx| {
1561 let Some(formatting_transaction) =
1562 buffer.get_transaction(formatting_transaction_id).cloned()
1563 else {
1564 zlog::warn!(logger => "no formatting transaction");
1565 return;
1566 };
1567 if formatting_transaction.edit_ids.is_empty() {
1568 zlog::debug!(logger => "no changes made while formatting");
1569 buffer.forget_transaction(formatting_transaction_id);
1570 return;
1571 }
1572 if !push_to_history {
1573 zlog::trace!(logger => "forgetting format transaction");
1574 buffer.forget_transaction(formatting_transaction.id);
1575 }
1576 project_transaction
1577 .0
1578 .insert(cx.entity(), formatting_transaction);
1579 });
1580
1581 result?;
1582 }
1583
1584 Ok(project_transaction)
1585 }
1586
1587 async fn format_buffer_locally(
1588 lsp_store: WeakEntity<LspStore>,
1589 buffer: &FormattableBuffer,
1590 formatting_transaction_id: clock::Lamport,
1591 trigger: FormatTrigger,
1592 logger: zlog::Logger,
1593 cx: &mut AsyncApp,
1594 ) -> Result<()> {
1595 let (adapters_and_servers, settings, request_timeout) =
1596 lsp_store.update(cx, |lsp_store, cx| {
1597 buffer.handle.update(cx, |buffer, cx| {
1598 let adapters_and_servers = lsp_store
1599 .as_local()
1600 .unwrap()
1601 .language_servers_for_buffer(buffer, cx)
1602 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1603 .collect::<Vec<_>>();
1604 let settings =
1605 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1606 .into_owned();
1607 let request_timeout = ProjectSettings::get_global(cx)
1608 .global_lsp_settings
1609 .get_request_timeout();
1610 (adapters_and_servers, settings, request_timeout)
1611 })
1612 })?;
1613
1614 /// Apply edits to the buffer that will become part of the formatting transaction.
1615 /// Fails if the buffer has been edited since the start of that transaction.
1616 fn extend_formatting_transaction(
1617 buffer: &FormattableBuffer,
1618 formatting_transaction_id: text::TransactionId,
1619 cx: &mut AsyncApp,
1620 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1621 ) -> anyhow::Result<()> {
1622 buffer.handle.update(cx, |buffer, cx| {
1623 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1624 if last_transaction_id != Some(formatting_transaction_id) {
1625 anyhow::bail!("Buffer edited while formatting. Aborting")
1626 }
1627 buffer.start_transaction();
1628 operation(buffer, cx);
1629 if let Some(transaction_id) = buffer.end_transaction(cx) {
1630 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1631 }
1632 Ok(())
1633 })
1634 }
1635
1636 // handle whitespace formatting
1637 if settings.remove_trailing_whitespace_on_save {
1638 zlog::trace!(logger => "removing trailing whitespace");
1639 let diff = buffer
1640 .handle
1641 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1642 .await;
1643 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1644 buffer.apply_diff(diff, cx);
1645 })?;
1646 }
1647
1648 if settings.ensure_final_newline_on_save {
1649 zlog::trace!(logger => "ensuring final newline");
1650 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1651 buffer.ensure_final_newline(cx);
1652 })?;
1653 }
1654
1655 // Formatter for `code_actions_on_format` that runs before
1656 // the rest of the formatters
1657 let mut code_actions_on_format_formatters = None;
1658 let should_run_code_actions_on_format = !matches!(
1659 (trigger, &settings.format_on_save),
1660 (FormatTrigger::Save, &FormatOnSave::Off)
1661 );
1662 if should_run_code_actions_on_format {
1663 let have_code_actions_to_run_on_format = settings
1664 .code_actions_on_format
1665 .values()
1666 .any(|enabled| *enabled);
1667 if have_code_actions_to_run_on_format {
1668 zlog::trace!(logger => "going to run code actions on format");
1669 code_actions_on_format_formatters = Some(
1670 settings
1671 .code_actions_on_format
1672 .iter()
1673 .filter_map(|(action, enabled)| enabled.then_some(action))
1674 .cloned()
1675 .map(Formatter::CodeAction)
1676 .collect::<Vec<_>>(),
1677 );
1678 }
1679 }
1680
1681 let formatters = match (trigger, &settings.format_on_save) {
1682 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1683 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1684 settings.formatter.as_ref()
1685 }
1686 };
1687
1688 let formatters = code_actions_on_format_formatters
1689 .iter()
1690 .flatten()
1691 .chain(formatters);
1692
1693 for formatter in formatters {
1694 let formatter = if formatter == &Formatter::Auto {
1695 if settings.prettier.allowed {
1696 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1697 &Formatter::Prettier
1698 } else {
1699 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1700 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1701 }
1702 } else {
1703 formatter
1704 };
1705 match formatter {
1706 Formatter::None => {
1707 zlog::trace!(logger => "skipping formatter 'none'");
1708 continue;
1709 }
1710 Formatter::Auto => unreachable!("Auto resolved above"),
1711 Formatter::Prettier => {
1712 let logger = zlog::scoped!(logger => "prettier");
1713 zlog::trace!(logger => "formatting");
1714 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1715
1716 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1717 lsp_store.prettier_store().unwrap().downgrade()
1718 })?;
1719 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1720 .await
1721 .transpose()?;
1722 let Some(diff) = diff else {
1723 zlog::trace!(logger => "No changes");
1724 continue;
1725 };
1726
1727 extend_formatting_transaction(
1728 buffer,
1729 formatting_transaction_id,
1730 cx,
1731 |buffer, cx| {
1732 buffer.apply_diff(diff, cx);
1733 },
1734 )?;
1735 }
1736 Formatter::External { command, arguments } => {
1737 let logger = zlog::scoped!(logger => "command");
1738 zlog::trace!(logger => "formatting");
1739 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1740
1741 let diff = Self::format_via_external_command(
1742 buffer,
1743 &command,
1744 arguments.as_deref(),
1745 cx,
1746 )
1747 .await
1748 .with_context(|| {
1749 format!("Failed to format buffer via external command: {}", command)
1750 })?;
1751 let Some(diff) = diff else {
1752 zlog::trace!(logger => "No changes");
1753 continue;
1754 };
1755
1756 extend_formatting_transaction(
1757 buffer,
1758 formatting_transaction_id,
1759 cx,
1760 |buffer, cx| {
1761 buffer.apply_diff(diff, cx);
1762 },
1763 )?;
1764 }
1765 Formatter::LanguageServer(specifier) => {
1766 let logger = zlog::scoped!(logger => "language-server");
1767 zlog::trace!(logger => "formatting");
1768 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1769
1770 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1771 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1772 continue;
1773 };
1774
1775 let language_server = match specifier {
1776 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1777 adapters_and_servers.iter().find_map(|(adapter, server)| {
1778 if adapter.name.0.as_ref() == name {
1779 Some(server.clone())
1780 } else {
1781 None
1782 }
1783 })
1784 }
1785 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1786 .iter()
1787 .find(|(_, server)| Self::server_supports_formatting(server))
1788 .map(|(_, server)| server.clone()),
1789 };
1790
1791 let Some(language_server) = language_server else {
1792 log::debug!(
1793 "No language server found to format buffer '{:?}'. Skipping",
1794 buffer_path_abs.as_path().to_string_lossy()
1795 );
1796 continue;
1797 };
1798
1799 zlog::trace!(
1800 logger =>
1801 "Formatting buffer '{:?}' using language server '{:?}'",
1802 buffer_path_abs.as_path().to_string_lossy(),
1803 language_server.name()
1804 );
1805
1806 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1807 zlog::trace!(logger => "formatting ranges");
1808 Self::format_ranges_via_lsp(
1809 &lsp_store,
1810 &buffer.handle,
1811 ranges,
1812 buffer_path_abs,
1813 &language_server,
1814 &settings,
1815 cx,
1816 )
1817 .await
1818 .context("Failed to format ranges via language server")?
1819 } else {
1820 zlog::trace!(logger => "formatting full");
1821 Self::format_via_lsp(
1822 &lsp_store,
1823 &buffer.handle,
1824 buffer_path_abs,
1825 &language_server,
1826 &settings,
1827 cx,
1828 )
1829 .await
1830 .context("failed to format via language server")?
1831 };
1832
1833 if edits.is_empty() {
1834 zlog::trace!(logger => "No changes");
1835 continue;
1836 }
1837 extend_formatting_transaction(
1838 buffer,
1839 formatting_transaction_id,
1840 cx,
1841 |buffer, cx| {
1842 buffer.edit(edits, None, cx);
1843 },
1844 )?;
1845 }
1846 Formatter::CodeAction(code_action_name) => {
1847 let logger = zlog::scoped!(logger => "code-actions");
1848 zlog::trace!(logger => "formatting");
1849 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1850
1851 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1852 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1853 continue;
1854 };
1855
1856 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1857 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1858
1859 let mut actions_and_servers = Vec::new();
1860
1861 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1862 let actions_result = Self::get_server_code_actions_from_action_kinds(
1863 &lsp_store,
1864 language_server.server_id(),
1865 vec![code_action_kind.clone()],
1866 &buffer.handle,
1867 cx,
1868 )
1869 .await
1870 .with_context(|| {
1871 format!(
1872 "Failed to resolve code action {:?} with language server {}",
1873 code_action_kind,
1874 language_server.name()
1875 )
1876 });
1877 let Ok(actions) = actions_result else {
1878 // note: it may be better to set result to the error and break formatters here
1879 // but for now we try to execute the actions that we can resolve and skip the rest
1880 zlog::error!(
1881 logger =>
1882 "Failed to resolve code action {:?} with language server {}",
1883 code_action_kind,
1884 language_server.name()
1885 );
1886 continue;
1887 };
1888 for action in actions {
1889 actions_and_servers.push((action, index));
1890 }
1891 }
1892
1893 if actions_and_servers.is_empty() {
1894 zlog::warn!(logger => "No code actions were resolved, continuing");
1895 continue;
1896 }
1897
1898 'actions: for (mut action, server_index) in actions_and_servers {
1899 let server = &adapters_and_servers[server_index].1;
1900
1901 let describe_code_action = |action: &CodeAction| {
1902 format!(
1903 "code action '{}' with title \"{}\" on server {}",
1904 action
1905 .lsp_action
1906 .action_kind()
1907 .unwrap_or("unknown".into())
1908 .as_str(),
1909 action.lsp_action.title(),
1910 server.name(),
1911 )
1912 };
1913
1914 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1915
1916 if let Err(err) =
1917 Self::try_resolve_code_action(server, &mut action, request_timeout)
1918 .await
1919 {
1920 zlog::error!(
1921 logger =>
1922 "Failed to resolve {}. Error: {}",
1923 describe_code_action(&action),
1924 err
1925 );
1926 continue;
1927 }
1928
1929 if let Some(edit) = action.lsp_action.edit().cloned() {
1930 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1931 // but filters out and logs warnings for code actions that require unreasonably
1932 // difficult handling on our part, such as:
1933 // - applying edits that call commands
1934 // which can result in arbitrary workspace edits being sent from the server that
1935 // have no way of being tied back to the command that initiated them (i.e. we
1936 // can't know which edits are part of the format request, or if the server is done sending
1937 // actions in response to the command)
1938 // - actions that create/delete/modify/rename files other than the one we are formatting
1939 // as we then would need to handle such changes correctly in the local history as well
1940 // as the remote history through the ProjectTransaction
1941 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1942 // Supporting these actions is not impossible, but not supported as of yet.
1943 if edit.changes.is_none() && edit.document_changes.is_none() {
1944 zlog::trace!(
1945 logger =>
1946 "No changes for code action. Skipping {}",
1947 describe_code_action(&action),
1948 );
1949 continue;
1950 }
1951
1952 let mut operations = Vec::new();
1953 if let Some(document_changes) = edit.document_changes {
1954 match document_changes {
1955 lsp::DocumentChanges::Edits(edits) => operations.extend(
1956 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1957 ),
1958 lsp::DocumentChanges::Operations(ops) => operations = ops,
1959 }
1960 } else if let Some(changes) = edit.changes {
1961 operations.extend(changes.into_iter().map(|(uri, edits)| {
1962 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1963 text_document:
1964 lsp::OptionalVersionedTextDocumentIdentifier {
1965 uri,
1966 version: None,
1967 },
1968 edits: edits.into_iter().map(Edit::Plain).collect(),
1969 })
1970 }));
1971 }
1972
1973 let mut edits = Vec::with_capacity(operations.len());
1974
1975 if operations.is_empty() {
1976 zlog::trace!(
1977 logger =>
1978 "No changes for code action. Skipping {}",
1979 describe_code_action(&action),
1980 );
1981 continue;
1982 }
1983 for operation in operations {
1984 let op = match operation {
1985 lsp::DocumentChangeOperation::Edit(op) => op,
1986 lsp::DocumentChangeOperation::Op(_) => {
1987 zlog::warn!(
1988 logger =>
1989 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1990 describe_code_action(&action),
1991 );
1992 continue 'actions;
1993 }
1994 };
1995 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1996 zlog::warn!(
1997 logger =>
1998 "Failed to convert URI '{:?}' to file path. Skipping {}",
1999 &op.text_document.uri,
2000 describe_code_action(&action),
2001 );
2002 continue 'actions;
2003 };
2004 if &file_path != buffer_path_abs {
2005 zlog::warn!(
2006 logger =>
2007 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2008 file_path,
2009 buffer_path_abs,
2010 describe_code_action(&action),
2011 );
2012 continue 'actions;
2013 }
2014
2015 let mut lsp_edits = Vec::new();
2016 for edit in op.edits {
2017 match edit {
2018 Edit::Plain(edit) => {
2019 if !lsp_edits.contains(&edit) {
2020 lsp_edits.push(edit);
2021 }
2022 }
2023 Edit::Annotated(edit) => {
2024 if !lsp_edits.contains(&edit.text_edit) {
2025 lsp_edits.push(edit.text_edit);
2026 }
2027 }
2028 Edit::Snippet(_) => {
2029 zlog::warn!(
2030 logger =>
2031 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2032 describe_code_action(&action),
2033 );
2034 continue 'actions;
2035 }
2036 }
2037 }
2038 let edits_result = lsp_store
2039 .update(cx, |lsp_store, cx| {
2040 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2041 &buffer.handle,
2042 lsp_edits,
2043 server.server_id(),
2044 op.text_document.version,
2045 cx,
2046 )
2047 })?
2048 .await;
2049 let Ok(resolved_edits) = edits_result else {
2050 zlog::warn!(
2051 logger =>
2052 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2053 buffer_path_abs.as_path(),
2054 describe_code_action(&action),
2055 );
2056 continue 'actions;
2057 };
2058 edits.extend(resolved_edits);
2059 }
2060
2061 if edits.is_empty() {
2062 zlog::warn!(logger => "No edits resolved from LSP");
2063 continue;
2064 }
2065
2066 extend_formatting_transaction(
2067 buffer,
2068 formatting_transaction_id,
2069 cx,
2070 |buffer, cx| {
2071 zlog::info!(
2072 "Applying edits {edits:?}. Content: {:?}",
2073 buffer.text()
2074 );
2075 buffer.edit(edits, None, cx);
2076 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2077 },
2078 )?;
2079 }
2080
2081 // bail early if command is invalid
2082 let Some(command) = action.lsp_action.command() else {
2083 continue;
2084 };
2085
2086 zlog::warn!(
2087 logger =>
2088 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2089 &command.command,
2090 );
2091
2092 let server_capabilities = server.capabilities();
2093 let available_commands = server_capabilities
2094 .execute_command_provider
2095 .as_ref()
2096 .map(|options| options.commands.as_slice())
2097 .unwrap_or_default();
2098 if !available_commands.contains(&command.command) {
2099 zlog::warn!(
2100 logger =>
2101 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2102 command.command,
2103 server.name(),
2104 );
2105 continue;
2106 }
2107
2108 // noop so we just ensure buffer hasn't been edited since resolving code actions
2109 extend_formatting_transaction(
2110 buffer,
2111 formatting_transaction_id,
2112 cx,
2113 |_, _| {},
2114 )?;
2115 zlog::info!(logger => "Executing command {}", &command.command);
2116
2117 lsp_store.update(cx, |this, _| {
2118 this.as_local_mut()
2119 .unwrap()
2120 .last_workspace_edits_by_language_server
2121 .remove(&server.server_id());
2122 })?;
2123
2124 let execute_command_result = server
2125 .request::<lsp::request::ExecuteCommand>(
2126 lsp::ExecuteCommandParams {
2127 command: command.command.clone(),
2128 arguments: command.arguments.clone().unwrap_or_default(),
2129 ..Default::default()
2130 },
2131 request_timeout,
2132 )
2133 .await
2134 .into_response();
2135
2136 if execute_command_result.is_err() {
2137 zlog::error!(
2138 logger =>
2139 "Failed to execute command '{}' as part of {}",
2140 &command.command,
2141 describe_code_action(&action),
2142 );
2143 continue 'actions;
2144 }
2145
2146 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2147 this.as_local_mut()
2148 .unwrap()
2149 .last_workspace_edits_by_language_server
2150 .remove(&server.server_id())
2151 .unwrap_or_default()
2152 })?;
2153
2154 if let Some(transaction) =
2155 project_transaction_command.0.remove(&buffer.handle)
2156 {
2157 zlog::trace!(
2158 logger =>
2159 "Successfully captured {} edits that resulted from command {}",
2160 transaction.edit_ids.len(),
2161 &command.command,
2162 );
2163 let transaction_id_project_transaction = transaction.id;
2164 buffer.handle.update(cx, |buffer, _| {
2165 // it may have been removed from history if push_to_history was
2166 // false in deserialize_workspace_edit. If so push it so we
2167 // can merge it with the format transaction
2168 // and pop the combined transaction off the history stack
2169 // later if push_to_history is false
2170 if buffer.get_transaction(transaction.id).is_none() {
2171 buffer.push_transaction(transaction, Instant::now());
2172 }
2173 buffer.merge_transactions(
2174 transaction_id_project_transaction,
2175 formatting_transaction_id,
2176 );
2177 });
2178 }
2179
2180 if project_transaction_command.0.is_empty() {
2181 continue;
2182 }
2183
2184 let mut extra_buffers = String::new();
2185 for buffer in project_transaction_command.0.keys() {
2186 buffer.read_with(cx, |b, cx| {
2187 let Some(path) = b.project_path(cx) else {
2188 return;
2189 };
2190
2191 if !extra_buffers.is_empty() {
2192 extra_buffers.push_str(", ");
2193 }
2194 extra_buffers.push_str(path.path.as_unix_str());
2195 });
2196 }
2197 zlog::warn!(
2198 logger =>
2199 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2200 &command.command,
2201 extra_buffers,
2202 );
2203 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2204 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2205 // add it so it's included, and merge it into the format transaction when its created later
2206 }
2207 }
2208 }
2209 }
2210
2211 Ok(())
2212 }
2213
2214 pub async fn format_ranges_via_lsp(
2215 this: &WeakEntity<LspStore>,
2216 buffer_handle: &Entity<Buffer>,
2217 ranges: &[Range<Anchor>],
2218 abs_path: &Path,
2219 language_server: &Arc<LanguageServer>,
2220 settings: &LanguageSettings,
2221 cx: &mut AsyncApp,
2222 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2223 let capabilities = &language_server.capabilities();
2224 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2225 if range_formatting_provider == Some(&OneOf::Left(false)) {
2226 anyhow::bail!(
2227 "{} language server does not support range formatting",
2228 language_server.name()
2229 );
2230 }
2231
2232 let uri = file_path_to_lsp_url(abs_path)?;
2233 let text_document = lsp::TextDocumentIdentifier::new(uri);
2234
2235 let request_timeout = cx.update(|app| {
2236 ProjectSettings::get_global(app)
2237 .global_lsp_settings
2238 .get_request_timeout()
2239 });
2240 let lsp_edits = {
2241 let mut lsp_ranges = Vec::new();
2242 this.update(cx, |_this, cx| {
2243 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2244 // not have been sent to the language server. This seems like a fairly systemic
2245 // issue, though, the resolution probably is not specific to formatting.
2246 //
2247 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2248 // LSP.
2249 let snapshot = buffer_handle.read(cx).snapshot();
2250 for range in ranges {
2251 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2252 }
2253 anyhow::Ok(())
2254 })??;
2255
2256 let mut edits = None;
2257 for range in lsp_ranges {
2258 if let Some(mut edit) = language_server
2259 .request::<lsp::request::RangeFormatting>(
2260 lsp::DocumentRangeFormattingParams {
2261 text_document: text_document.clone(),
2262 range,
2263 options: lsp_command::lsp_formatting_options(settings),
2264 work_done_progress_params: Default::default(),
2265 },
2266 request_timeout,
2267 )
2268 .await
2269 .into_response()?
2270 {
2271 edits.get_or_insert_with(Vec::new).append(&mut edit);
2272 }
2273 }
2274 edits
2275 };
2276
2277 if let Some(lsp_edits) = lsp_edits {
2278 this.update(cx, |this, cx| {
2279 this.as_local_mut().unwrap().edits_from_lsp(
2280 buffer_handle,
2281 lsp_edits,
2282 language_server.server_id(),
2283 None,
2284 cx,
2285 )
2286 })?
2287 .await
2288 } else {
2289 Ok(Vec::with_capacity(0))
2290 }
2291 }
2292
2293 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2294 let capabilities = server.capabilities();
2295 let formatting = capabilities.document_formatting_provider.as_ref();
2296 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2297 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2298 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2299 }
2300
2301 async fn format_via_lsp(
2302 this: &WeakEntity<LspStore>,
2303 buffer: &Entity<Buffer>,
2304 abs_path: &Path,
2305 language_server: &Arc<LanguageServer>,
2306 settings: &LanguageSettings,
2307 cx: &mut AsyncApp,
2308 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2309 let logger = zlog::scoped!("lsp_format");
2310 zlog::debug!(logger => "Formatting via LSP");
2311
2312 let uri = file_path_to_lsp_url(abs_path)?;
2313 let text_document = lsp::TextDocumentIdentifier::new(uri);
2314 let capabilities = &language_server.capabilities();
2315
2316 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2317 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2318
2319 let request_timeout = cx.update(|app| {
2320 ProjectSettings::get_global(app)
2321 .global_lsp_settings
2322 .get_request_timeout()
2323 });
2324
2325 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2326 let _timer = zlog::time!(logger => "format-full");
2327 language_server
2328 .request::<lsp::request::Formatting>(
2329 lsp::DocumentFormattingParams {
2330 text_document,
2331 options: lsp_command::lsp_formatting_options(settings),
2332 work_done_progress_params: Default::default(),
2333 },
2334 request_timeout,
2335 )
2336 .await
2337 .into_response()?
2338 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2339 let _timer = zlog::time!(logger => "format-range");
2340 let buffer_start = lsp::Position::new(0, 0);
2341 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2342 language_server
2343 .request::<lsp::request::RangeFormatting>(
2344 lsp::DocumentRangeFormattingParams {
2345 text_document: text_document.clone(),
2346 range: lsp::Range::new(buffer_start, buffer_end),
2347 options: lsp_command::lsp_formatting_options(settings),
2348 work_done_progress_params: Default::default(),
2349 },
2350 request_timeout,
2351 )
2352 .await
2353 .into_response()?
2354 } else {
2355 None
2356 };
2357
2358 if let Some(lsp_edits) = lsp_edits {
2359 this.update(cx, |this, cx| {
2360 this.as_local_mut().unwrap().edits_from_lsp(
2361 buffer,
2362 lsp_edits,
2363 language_server.server_id(),
2364 None,
2365 cx,
2366 )
2367 })?
2368 .await
2369 } else {
2370 Ok(Vec::with_capacity(0))
2371 }
2372 }
2373
2374 async fn format_via_external_command(
2375 buffer: &FormattableBuffer,
2376 command: &str,
2377 arguments: Option<&[String]>,
2378 cx: &mut AsyncApp,
2379 ) -> Result<Option<Diff>> {
2380 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2381 let file = File::from_dyn(buffer.file())?;
2382 let worktree = file.worktree.read(cx);
2383 let mut worktree_path = worktree.abs_path().to_path_buf();
2384 if worktree.root_entry()?.is_file() {
2385 worktree_path.pop();
2386 }
2387 Some(worktree_path)
2388 });
2389
2390 use util::command::Stdio;
2391 let mut child = util::command::new_command(command);
2392
2393 if let Some(buffer_env) = buffer.env.as_ref() {
2394 child.envs(buffer_env);
2395 }
2396
2397 if let Some(working_dir_path) = working_dir_path {
2398 child.current_dir(working_dir_path);
2399 }
2400
2401 if let Some(arguments) = arguments {
2402 child.args(arguments.iter().map(|arg| {
2403 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2404 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2405 } else {
2406 arg.replace("{buffer_path}", "Untitled")
2407 }
2408 }));
2409 }
2410
2411 let mut child = child
2412 .stdin(Stdio::piped())
2413 .stdout(Stdio::piped())
2414 .stderr(Stdio::piped())
2415 .spawn()?;
2416
2417 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2418 let text = buffer
2419 .handle
2420 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2421 for chunk in text.chunks() {
2422 stdin.write_all(chunk.as_bytes()).await?;
2423 }
2424 stdin.flush().await?;
2425
2426 let output = child.output().await?;
2427 anyhow::ensure!(
2428 output.status.success(),
2429 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2430 output.status.code(),
2431 String::from_utf8_lossy(&output.stdout),
2432 String::from_utf8_lossy(&output.stderr),
2433 );
2434
2435 let stdout = String::from_utf8(output.stdout)?;
2436 Ok(Some(
2437 buffer
2438 .handle
2439 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2440 .await,
2441 ))
2442 }
2443
2444 async fn try_resolve_code_action(
2445 lang_server: &LanguageServer,
2446 action: &mut CodeAction,
2447 request_timeout: Duration,
2448 ) -> anyhow::Result<()> {
2449 match &mut action.lsp_action {
2450 LspAction::Action(lsp_action) => {
2451 if !action.resolved
2452 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2453 && lsp_action.data.is_some()
2454 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2455 {
2456 **lsp_action = lang_server
2457 .request::<lsp::request::CodeActionResolveRequest>(
2458 *lsp_action.clone(),
2459 request_timeout,
2460 )
2461 .await
2462 .into_response()?;
2463 }
2464 }
2465 LspAction::CodeLens(lens) => {
2466 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2467 *lens = lang_server
2468 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2469 .await
2470 .into_response()?;
2471 }
2472 }
2473 LspAction::Command(_) => {}
2474 }
2475
2476 action.resolved = true;
2477 anyhow::Ok(())
2478 }
2479
2480 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2481 let buffer = buffer_handle.read(cx);
2482
2483 let file = buffer.file().cloned();
2484
2485 let Some(file) = File::from_dyn(file.as_ref()) else {
2486 return;
2487 };
2488 if !file.is_local() {
2489 return;
2490 }
2491 let path = ProjectPath::from_file(file, cx);
2492 let worktree_id = file.worktree_id(cx);
2493 let language = buffer.language().cloned();
2494
2495 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2496 for (server_id, diagnostics) in
2497 diagnostics.get(file.path()).cloned().unwrap_or_default()
2498 {
2499 self.update_buffer_diagnostics(
2500 buffer_handle,
2501 server_id,
2502 None,
2503 None,
2504 None,
2505 Vec::new(),
2506 diagnostics,
2507 cx,
2508 )
2509 .log_err();
2510 }
2511 }
2512 let Some(language) = language else {
2513 return;
2514 };
2515 let Some(snapshot) = self
2516 .worktree_store
2517 .read(cx)
2518 .worktree_for_id(worktree_id, cx)
2519 .map(|worktree| worktree.read(cx).snapshot())
2520 else {
2521 return;
2522 };
2523 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2524
2525 for server_id in
2526 self.lsp_tree
2527 .get(path, language.name(), language.manifest(), &delegate, cx)
2528 {
2529 let server = self
2530 .language_servers
2531 .get(&server_id)
2532 .and_then(|server_state| {
2533 if let LanguageServerState::Running { server, .. } = server_state {
2534 Some(server.clone())
2535 } else {
2536 None
2537 }
2538 });
2539 let server = match server {
2540 Some(server) => server,
2541 None => continue,
2542 };
2543
2544 buffer_handle.update(cx, |buffer, cx| {
2545 buffer.set_completion_triggers(
2546 server.server_id(),
2547 server
2548 .capabilities()
2549 .completion_provider
2550 .as_ref()
2551 .and_then(|provider| {
2552 provider
2553 .trigger_characters
2554 .as_ref()
2555 .map(|characters| characters.iter().cloned().collect())
2556 })
2557 .unwrap_or_default(),
2558 cx,
2559 );
2560 });
2561 }
2562 }
2563
2564 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2565 buffer.update(cx, |buffer, cx| {
2566 let Some(language) = buffer.language() else {
2567 return;
2568 };
2569 let path = ProjectPath {
2570 worktree_id: old_file.worktree_id(cx),
2571 path: old_file.path.clone(),
2572 };
2573 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2574 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2575 buffer.set_completion_triggers(server_id, Default::default(), cx);
2576 }
2577 });
2578 }
2579
2580 fn update_buffer_diagnostics(
2581 &mut self,
2582 buffer: &Entity<Buffer>,
2583 server_id: LanguageServerId,
2584 registration_id: Option<Option<SharedString>>,
2585 result_id: Option<SharedString>,
2586 version: Option<i32>,
2587 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2588 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2589 cx: &mut Context<LspStore>,
2590 ) -> Result<()> {
2591 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2592 Ordering::Equal
2593 .then_with(|| b.is_primary.cmp(&a.is_primary))
2594 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2595 .then_with(|| a.severity.cmp(&b.severity))
2596 .then_with(|| a.message.cmp(&b.message))
2597 }
2598
2599 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2600 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2601 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2602
2603 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2604 Ordering::Equal
2605 .then_with(|| a.range.start.cmp(&b.range.start))
2606 .then_with(|| b.range.end.cmp(&a.range.end))
2607 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2608 });
2609
2610 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2611
2612 let edits_since_save = std::cell::LazyCell::new(|| {
2613 let saved_version = buffer.read(cx).saved_version();
2614 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2615 });
2616
2617 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2618
2619 for (new_diagnostic, entry) in diagnostics {
2620 let start;
2621 let end;
2622 if new_diagnostic && entry.diagnostic.is_disk_based {
2623 // Some diagnostics are based on files on disk instead of buffers'
2624 // current contents. Adjust these diagnostics' ranges to reflect
2625 // any unsaved edits.
2626 // Do not alter the reused ones though, as their coordinates were stored as anchors
2627 // and were properly adjusted on reuse.
2628 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2629 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2630 } else {
2631 start = entry.range.start;
2632 end = entry.range.end;
2633 }
2634
2635 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2636 ..snapshot.clip_point_utf16(end, Bias::Right);
2637
2638 // Expand empty ranges by one codepoint
2639 if range.start == range.end {
2640 // This will be go to the next boundary when being clipped
2641 range.end.column += 1;
2642 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2643 if range.start == range.end && range.end.column > 0 {
2644 range.start.column -= 1;
2645 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2646 }
2647 }
2648
2649 sanitized_diagnostics.push(DiagnosticEntry {
2650 range,
2651 diagnostic: entry.diagnostic,
2652 });
2653 }
2654 drop(edits_since_save);
2655
2656 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2657 buffer.update(cx, |buffer, cx| {
2658 if let Some(registration_id) = registration_id {
2659 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2660 self.buffer_pull_diagnostics_result_ids
2661 .entry(server_id)
2662 .or_default()
2663 .entry(registration_id)
2664 .or_default()
2665 .insert(abs_path, result_id);
2666 }
2667 }
2668
2669 buffer.update_diagnostics(server_id, set, cx)
2670 });
2671
2672 Ok(())
2673 }
2674
2675 fn register_language_server_for_invisible_worktree(
2676 &mut self,
2677 worktree: &Entity<Worktree>,
2678 language_server_id: LanguageServerId,
2679 cx: &mut App,
2680 ) {
2681 let worktree = worktree.read(cx);
2682 let worktree_id = worktree.id();
2683 debug_assert!(!worktree.is_visible());
2684 let Some(mut origin_seed) = self
2685 .language_server_ids
2686 .iter()
2687 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2688 else {
2689 return;
2690 };
2691 origin_seed.worktree_id = worktree_id;
2692 self.language_server_ids
2693 .entry(origin_seed)
2694 .or_insert_with(|| UnifiedLanguageServer {
2695 id: language_server_id,
2696 project_roots: Default::default(),
2697 });
2698 }
2699
2700 fn register_buffer_with_language_servers(
2701 &mut self,
2702 buffer_handle: &Entity<Buffer>,
2703 only_register_servers: HashSet<LanguageServerSelector>,
2704 cx: &mut Context<LspStore>,
2705 ) {
2706 let buffer = buffer_handle.read(cx);
2707 let buffer_id = buffer.remote_id();
2708
2709 let Some(file) = File::from_dyn(buffer.file()) else {
2710 return;
2711 };
2712 if !file.is_local() {
2713 return;
2714 }
2715
2716 let abs_path = file.abs_path(cx);
2717 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2718 return;
2719 };
2720 let initial_snapshot = buffer.text_snapshot();
2721 let worktree_id = file.worktree_id(cx);
2722
2723 let Some(language) = buffer.language().cloned() else {
2724 return;
2725 };
2726 let path: Arc<RelPath> = file
2727 .path()
2728 .parent()
2729 .map(Arc::from)
2730 .unwrap_or_else(|| file.path().clone());
2731 let Some(worktree) = self
2732 .worktree_store
2733 .read(cx)
2734 .worktree_for_id(worktree_id, cx)
2735 else {
2736 return;
2737 };
2738 let language_name = language.name();
2739 let (reused, delegate, servers) = self
2740 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2741 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2742 .unwrap_or_else(|| {
2743 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2744 let delegate: Arc<dyn ManifestDelegate> =
2745 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2746
2747 let servers = self
2748 .lsp_tree
2749 .walk(
2750 ProjectPath { worktree_id, path },
2751 language.name(),
2752 language.manifest(),
2753 &delegate,
2754 cx,
2755 )
2756 .collect::<Vec<_>>();
2757 (false, lsp_delegate, servers)
2758 });
2759 let servers_and_adapters = servers
2760 .into_iter()
2761 .filter_map(|server_node| {
2762 if reused && server_node.server_id().is_none() {
2763 return None;
2764 }
2765 if !only_register_servers.is_empty() {
2766 if let Some(server_id) = server_node.server_id()
2767 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2768 {
2769 return None;
2770 }
2771 if let Some(name) = server_node.name()
2772 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2773 {
2774 return None;
2775 }
2776 }
2777
2778 let server_id = server_node.server_id_or_init(|disposition| {
2779 let path = &disposition.path;
2780
2781 {
2782 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2783
2784 let server_id = self.get_or_insert_language_server(
2785 &worktree,
2786 delegate.clone(),
2787 disposition,
2788 &language_name,
2789 cx,
2790 );
2791
2792 if let Some(state) = self.language_servers.get(&server_id)
2793 && let Ok(uri) = uri
2794 {
2795 state.add_workspace_folder(uri);
2796 };
2797 server_id
2798 }
2799 })?;
2800 let server_state = self.language_servers.get(&server_id)?;
2801 if let LanguageServerState::Running {
2802 server, adapter, ..
2803 } = server_state
2804 {
2805 Some((server.clone(), adapter.clone()))
2806 } else {
2807 None
2808 }
2809 })
2810 .collect::<Vec<_>>();
2811 for (server, adapter) in servers_and_adapters {
2812 buffer_handle.update(cx, |buffer, cx| {
2813 buffer.set_completion_triggers(
2814 server.server_id(),
2815 server
2816 .capabilities()
2817 .completion_provider
2818 .as_ref()
2819 .and_then(|provider| {
2820 provider
2821 .trigger_characters
2822 .as_ref()
2823 .map(|characters| characters.iter().cloned().collect())
2824 })
2825 .unwrap_or_default(),
2826 cx,
2827 );
2828 });
2829
2830 let snapshot = LspBufferSnapshot {
2831 version: 0,
2832 snapshot: initial_snapshot.clone(),
2833 };
2834
2835 let mut registered = false;
2836 self.buffer_snapshots
2837 .entry(buffer_id)
2838 .or_default()
2839 .entry(server.server_id())
2840 .or_insert_with(|| {
2841 registered = true;
2842 server.register_buffer(
2843 uri.clone(),
2844 adapter.language_id(&language.name()),
2845 0,
2846 initial_snapshot.text(),
2847 );
2848
2849 vec![snapshot]
2850 });
2851
2852 self.buffers_opened_in_servers
2853 .entry(buffer_id)
2854 .or_default()
2855 .insert(server.server_id());
2856 if registered {
2857 cx.emit(LspStoreEvent::LanguageServerUpdate {
2858 language_server_id: server.server_id(),
2859 name: None,
2860 message: proto::update_language_server::Variant::RegisteredForBuffer(
2861 proto::RegisteredForBuffer {
2862 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2863 buffer_id: buffer_id.to_proto(),
2864 },
2865 ),
2866 });
2867 }
2868 }
2869 }
2870
2871 fn reuse_existing_language_server<'lang_name>(
2872 &self,
2873 server_tree: &LanguageServerTree,
2874 worktree: &Entity<Worktree>,
2875 language_name: &'lang_name LanguageName,
2876 cx: &mut App,
2877 ) -> Option<(
2878 Arc<LocalLspAdapterDelegate>,
2879 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2880 )> {
2881 if worktree.read(cx).is_visible() {
2882 return None;
2883 }
2884
2885 let worktree_store = self.worktree_store.read(cx);
2886 let servers = server_tree
2887 .instances
2888 .iter()
2889 .filter(|(worktree_id, _)| {
2890 worktree_store
2891 .worktree_for_id(**worktree_id, cx)
2892 .is_some_and(|worktree| worktree.read(cx).is_visible())
2893 })
2894 .flat_map(|(worktree_id, servers)| {
2895 servers
2896 .roots
2897 .iter()
2898 .flat_map(|(_, language_servers)| language_servers)
2899 .map(move |(_, (server_node, server_languages))| {
2900 (worktree_id, server_node, server_languages)
2901 })
2902 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2903 .map(|(worktree_id, server_node, _)| {
2904 (
2905 *worktree_id,
2906 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2907 )
2908 })
2909 })
2910 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2911 acc.entry(worktree_id)
2912 .or_insert_with(Vec::new)
2913 .push(server_node);
2914 acc
2915 })
2916 .into_values()
2917 .max_by_key(|servers| servers.len())?;
2918
2919 let worktree_id = worktree.read(cx).id();
2920 let apply = move |tree: &mut LanguageServerTree| {
2921 for server_node in &servers {
2922 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2923 }
2924 servers
2925 };
2926
2927 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2928 Some((delegate, apply))
2929 }
2930
2931 pub(crate) fn unregister_old_buffer_from_language_servers(
2932 &mut self,
2933 buffer: &Entity<Buffer>,
2934 old_file: &File,
2935 cx: &mut App,
2936 ) {
2937 let old_path = match old_file.as_local() {
2938 Some(local) => local.abs_path(cx),
2939 None => return,
2940 };
2941
2942 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2943 debug_panic!("{old_path:?} is not parseable as an URI");
2944 return;
2945 };
2946 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2947 }
2948
2949 pub(crate) fn unregister_buffer_from_language_servers(
2950 &mut self,
2951 buffer: &Entity<Buffer>,
2952 file_url: &lsp::Uri,
2953 cx: &mut App,
2954 ) {
2955 buffer.update(cx, |buffer, cx| {
2956 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2957
2958 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2959 if snapshots
2960 .as_mut()
2961 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2962 {
2963 language_server.unregister_buffer(file_url.clone());
2964 }
2965 }
2966 });
2967 }
2968
2969 fn buffer_snapshot_for_lsp_version(
2970 &mut self,
2971 buffer: &Entity<Buffer>,
2972 server_id: LanguageServerId,
2973 version: Option<i32>,
2974 cx: &App,
2975 ) -> Result<TextBufferSnapshot> {
2976 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2977
2978 if let Some(version) = version {
2979 let buffer_id = buffer.read(cx).remote_id();
2980 let snapshots = if let Some(snapshots) = self
2981 .buffer_snapshots
2982 .get_mut(&buffer_id)
2983 .and_then(|m| m.get_mut(&server_id))
2984 {
2985 snapshots
2986 } else if version == 0 {
2987 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2988 // We detect this case and treat it as if the version was `None`.
2989 return Ok(buffer.read(cx).text_snapshot());
2990 } else {
2991 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2992 };
2993
2994 let found_snapshot = snapshots
2995 .binary_search_by_key(&version, |e| e.version)
2996 .map(|ix| snapshots[ix].snapshot.clone())
2997 .map_err(|_| {
2998 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2999 })?;
3000
3001 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3002 Ok(found_snapshot)
3003 } else {
3004 Ok((buffer.read(cx)).text_snapshot())
3005 }
3006 }
3007
3008 async fn get_server_code_actions_from_action_kinds(
3009 lsp_store: &WeakEntity<LspStore>,
3010 language_server_id: LanguageServerId,
3011 code_action_kinds: Vec<lsp::CodeActionKind>,
3012 buffer: &Entity<Buffer>,
3013 cx: &mut AsyncApp,
3014 ) -> Result<Vec<CodeAction>> {
3015 let actions = lsp_store
3016 .update(cx, move |this, cx| {
3017 let request = GetCodeActions {
3018 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3019 kinds: Some(code_action_kinds),
3020 };
3021 let server = LanguageServerToQuery::Other(language_server_id);
3022 this.request_lsp(buffer.clone(), server, request, cx)
3023 })?
3024 .await?;
3025 Ok(actions)
3026 }
3027
3028 pub async fn execute_code_actions_on_server(
3029 lsp_store: &WeakEntity<LspStore>,
3030 language_server: &Arc<LanguageServer>,
3031 actions: Vec<CodeAction>,
3032 push_to_history: bool,
3033 project_transaction: &mut ProjectTransaction,
3034 cx: &mut AsyncApp,
3035 ) -> anyhow::Result<()> {
3036 let request_timeout = cx.update(|app| {
3037 ProjectSettings::get_global(app)
3038 .global_lsp_settings
3039 .get_request_timeout()
3040 });
3041
3042 for mut action in actions {
3043 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3044 .await
3045 .context("resolving a formatting code action")?;
3046
3047 if let Some(edit) = action.lsp_action.edit() {
3048 if edit.changes.is_none() && edit.document_changes.is_none() {
3049 continue;
3050 }
3051
3052 let new = Self::deserialize_workspace_edit(
3053 lsp_store.upgrade().context("project dropped")?,
3054 edit.clone(),
3055 push_to_history,
3056 language_server.clone(),
3057 cx,
3058 )
3059 .await?;
3060 project_transaction.0.extend(new.0);
3061 }
3062
3063 let Some(command) = action.lsp_action.command() else {
3064 continue;
3065 };
3066
3067 let server_capabilities = language_server.capabilities();
3068 let available_commands = server_capabilities
3069 .execute_command_provider
3070 .as_ref()
3071 .map(|options| options.commands.as_slice())
3072 .unwrap_or_default();
3073 if !available_commands.contains(&command.command) {
3074 log::warn!(
3075 "Cannot execute a command {} not listed in the language server capabilities",
3076 command.command
3077 );
3078 continue;
3079 }
3080
3081 lsp_store.update(cx, |lsp_store, _| {
3082 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3083 mode.last_workspace_edits_by_language_server
3084 .remove(&language_server.server_id());
3085 }
3086 })?;
3087
3088 language_server
3089 .request::<lsp::request::ExecuteCommand>(
3090 lsp::ExecuteCommandParams {
3091 command: command.command.clone(),
3092 arguments: command.arguments.clone().unwrap_or_default(),
3093 ..Default::default()
3094 },
3095 request_timeout,
3096 )
3097 .await
3098 .into_response()
3099 .context("execute command")?;
3100
3101 lsp_store.update(cx, |this, _| {
3102 if let LspStoreMode::Local(mode) = &mut this.mode {
3103 project_transaction.0.extend(
3104 mode.last_workspace_edits_by_language_server
3105 .remove(&language_server.server_id())
3106 .unwrap_or_default()
3107 .0,
3108 )
3109 }
3110 })?;
3111 }
3112 Ok(())
3113 }
3114
3115 pub async fn deserialize_text_edits(
3116 this: Entity<LspStore>,
3117 buffer_to_edit: Entity<Buffer>,
3118 edits: Vec<lsp::TextEdit>,
3119 push_to_history: bool,
3120 _: Arc<CachedLspAdapter>,
3121 language_server: Arc<LanguageServer>,
3122 cx: &mut AsyncApp,
3123 ) -> Result<Option<Transaction>> {
3124 let edits = this
3125 .update(cx, |this, cx| {
3126 this.as_local_mut().unwrap().edits_from_lsp(
3127 &buffer_to_edit,
3128 edits,
3129 language_server.server_id(),
3130 None,
3131 cx,
3132 )
3133 })
3134 .await?;
3135
3136 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3137 buffer.finalize_last_transaction();
3138 buffer.start_transaction();
3139 for (range, text) in edits {
3140 buffer.edit([(range, text)], None, cx);
3141 }
3142
3143 if buffer.end_transaction(cx).is_some() {
3144 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3145 if !push_to_history {
3146 buffer.forget_transaction(transaction.id);
3147 }
3148 Some(transaction)
3149 } else {
3150 None
3151 }
3152 });
3153
3154 Ok(transaction)
3155 }
3156
3157 #[allow(clippy::type_complexity)]
3158 pub fn edits_from_lsp(
3159 &mut self,
3160 buffer: &Entity<Buffer>,
3161 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3162 server_id: LanguageServerId,
3163 version: Option<i32>,
3164 cx: &mut Context<LspStore>,
3165 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3166 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3167 cx.background_spawn(async move {
3168 let snapshot = snapshot?;
3169 let mut lsp_edits = lsp_edits
3170 .into_iter()
3171 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3172 .collect::<Vec<_>>();
3173
3174 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3175
3176 let mut lsp_edits = lsp_edits.into_iter().peekable();
3177 let mut edits = Vec::new();
3178 while let Some((range, mut new_text)) = lsp_edits.next() {
3179 // Clip invalid ranges provided by the language server.
3180 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3181 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3182
3183 // Combine any LSP edits that are adjacent.
3184 //
3185 // Also, combine LSP edits that are separated from each other by only
3186 // a newline. This is important because for some code actions,
3187 // Rust-analyzer rewrites the entire buffer via a series of edits that
3188 // are separated by unchanged newline characters.
3189 //
3190 // In order for the diffing logic below to work properly, any edits that
3191 // cancel each other out must be combined into one.
3192 while let Some((next_range, next_text)) = lsp_edits.peek() {
3193 if next_range.start.0 > range.end {
3194 if next_range.start.0.row > range.end.row + 1
3195 || next_range.start.0.column > 0
3196 || snapshot.clip_point_utf16(
3197 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3198 Bias::Left,
3199 ) > range.end
3200 {
3201 break;
3202 }
3203 new_text.push('\n');
3204 }
3205 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3206 new_text.push_str(next_text);
3207 lsp_edits.next();
3208 }
3209
3210 // For multiline edits, perform a diff of the old and new text so that
3211 // we can identify the changes more precisely, preserving the locations
3212 // of any anchors positioned in the unchanged regions.
3213 if range.end.row > range.start.row {
3214 let offset = range.start.to_offset(&snapshot);
3215 let old_text = snapshot.text_for_range(range).collect::<String>();
3216 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3217 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3218 (
3219 snapshot.anchor_after(offset + range.start)
3220 ..snapshot.anchor_before(offset + range.end),
3221 replacement,
3222 )
3223 }));
3224 } else if range.end == range.start {
3225 let anchor = snapshot.anchor_after(range.start);
3226 edits.push((anchor..anchor, new_text.into()));
3227 } else {
3228 let edit_start = snapshot.anchor_after(range.start);
3229 let edit_end = snapshot.anchor_before(range.end);
3230 edits.push((edit_start..edit_end, new_text.into()));
3231 }
3232 }
3233
3234 Ok(edits)
3235 })
3236 }
3237
3238 pub(crate) async fn deserialize_workspace_edit(
3239 this: Entity<LspStore>,
3240 edit: lsp::WorkspaceEdit,
3241 push_to_history: bool,
3242 language_server: Arc<LanguageServer>,
3243 cx: &mut AsyncApp,
3244 ) -> Result<ProjectTransaction> {
3245 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3246
3247 let mut operations = Vec::new();
3248 if let Some(document_changes) = edit.document_changes {
3249 match document_changes {
3250 lsp::DocumentChanges::Edits(edits) => {
3251 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3252 }
3253 lsp::DocumentChanges::Operations(ops) => operations = ops,
3254 }
3255 } else if let Some(changes) = edit.changes {
3256 operations.extend(changes.into_iter().map(|(uri, edits)| {
3257 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3258 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3259 uri,
3260 version: None,
3261 },
3262 edits: edits.into_iter().map(Edit::Plain).collect(),
3263 })
3264 }));
3265 }
3266
3267 let mut project_transaction = ProjectTransaction::default();
3268 for operation in operations {
3269 match operation {
3270 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3271 let abs_path = op
3272 .uri
3273 .to_file_path()
3274 .map_err(|()| anyhow!("can't convert URI to path"))?;
3275
3276 if let Some(parent_path) = abs_path.parent() {
3277 fs.create_dir(parent_path).await?;
3278 }
3279 if abs_path.ends_with("/") {
3280 fs.create_dir(&abs_path).await?;
3281 } else {
3282 fs.create_file(
3283 &abs_path,
3284 op.options
3285 .map(|options| fs::CreateOptions {
3286 overwrite: options.overwrite.unwrap_or(false),
3287 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3288 })
3289 .unwrap_or_default(),
3290 )
3291 .await?;
3292 }
3293 }
3294
3295 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3296 let source_abs_path = op
3297 .old_uri
3298 .to_file_path()
3299 .map_err(|()| anyhow!("can't convert URI to path"))?;
3300 let target_abs_path = op
3301 .new_uri
3302 .to_file_path()
3303 .map_err(|()| anyhow!("can't convert URI to path"))?;
3304
3305 let options = fs::RenameOptions {
3306 overwrite: op
3307 .options
3308 .as_ref()
3309 .and_then(|options| options.overwrite)
3310 .unwrap_or(false),
3311 ignore_if_exists: op
3312 .options
3313 .as_ref()
3314 .and_then(|options| options.ignore_if_exists)
3315 .unwrap_or(false),
3316 create_parents: true,
3317 };
3318
3319 fs.rename(&source_abs_path, &target_abs_path, options)
3320 .await?;
3321 }
3322
3323 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3324 let abs_path = op
3325 .uri
3326 .to_file_path()
3327 .map_err(|()| anyhow!("can't convert URI to path"))?;
3328 let options = op
3329 .options
3330 .map(|options| fs::RemoveOptions {
3331 recursive: options.recursive.unwrap_or(false),
3332 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3333 })
3334 .unwrap_or_default();
3335 if abs_path.ends_with("/") {
3336 fs.remove_dir(&abs_path, options).await?;
3337 } else {
3338 fs.remove_file(&abs_path, options).await?;
3339 }
3340 }
3341
3342 lsp::DocumentChangeOperation::Edit(op) => {
3343 let buffer_to_edit = this
3344 .update(cx, |this, cx| {
3345 this.open_local_buffer_via_lsp(
3346 op.text_document.uri.clone(),
3347 language_server.server_id(),
3348 cx,
3349 )
3350 })
3351 .await?;
3352
3353 let edits = this
3354 .update(cx, |this, cx| {
3355 let path = buffer_to_edit.read(cx).project_path(cx);
3356 let active_entry = this.active_entry;
3357 let is_active_entry = path.is_some_and(|project_path| {
3358 this.worktree_store
3359 .read(cx)
3360 .entry_for_path(&project_path, cx)
3361 .is_some_and(|entry| Some(entry.id) == active_entry)
3362 });
3363 let local = this.as_local_mut().unwrap();
3364
3365 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3366 for edit in op.edits {
3367 match edit {
3368 Edit::Plain(edit) => {
3369 if !edits.contains(&edit) {
3370 edits.push(edit)
3371 }
3372 }
3373 Edit::Annotated(edit) => {
3374 if !edits.contains(&edit.text_edit) {
3375 edits.push(edit.text_edit)
3376 }
3377 }
3378 Edit::Snippet(edit) => {
3379 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3380 else {
3381 continue;
3382 };
3383
3384 if is_active_entry {
3385 snippet_edits.push((edit.range, snippet));
3386 } else {
3387 // Since this buffer is not focused, apply a normal edit.
3388 let new_edit = TextEdit {
3389 range: edit.range,
3390 new_text: snippet.text,
3391 };
3392 if !edits.contains(&new_edit) {
3393 edits.push(new_edit);
3394 }
3395 }
3396 }
3397 }
3398 }
3399 if !snippet_edits.is_empty() {
3400 let buffer_id = buffer_to_edit.read(cx).remote_id();
3401 let version = if let Some(buffer_version) = op.text_document.version
3402 {
3403 local
3404 .buffer_snapshot_for_lsp_version(
3405 &buffer_to_edit,
3406 language_server.server_id(),
3407 Some(buffer_version),
3408 cx,
3409 )
3410 .ok()
3411 .map(|snapshot| snapshot.version)
3412 } else {
3413 Some(buffer_to_edit.read(cx).saved_version().clone())
3414 };
3415
3416 let most_recent_edit =
3417 version.and_then(|version| version.most_recent());
3418 // Check if the edit that triggered that edit has been made by this participant.
3419
3420 if let Some(most_recent_edit) = most_recent_edit {
3421 cx.emit(LspStoreEvent::SnippetEdit {
3422 buffer_id,
3423 edits: snippet_edits,
3424 most_recent_edit,
3425 });
3426 }
3427 }
3428
3429 local.edits_from_lsp(
3430 &buffer_to_edit,
3431 edits,
3432 language_server.server_id(),
3433 op.text_document.version,
3434 cx,
3435 )
3436 })
3437 .await?;
3438
3439 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3440 buffer.finalize_last_transaction();
3441 buffer.start_transaction();
3442 for (range, text) in edits {
3443 buffer.edit([(range, text)], None, cx);
3444 }
3445
3446 buffer.end_transaction(cx).and_then(|transaction_id| {
3447 if push_to_history {
3448 buffer.finalize_last_transaction();
3449 buffer.get_transaction(transaction_id).cloned()
3450 } else {
3451 buffer.forget_transaction(transaction_id)
3452 }
3453 })
3454 });
3455 if let Some(transaction) = transaction {
3456 project_transaction.0.insert(buffer_to_edit, transaction);
3457 }
3458 }
3459 }
3460 }
3461
3462 Ok(project_transaction)
3463 }
3464
3465 async fn on_lsp_workspace_edit(
3466 this: WeakEntity<LspStore>,
3467 params: lsp::ApplyWorkspaceEditParams,
3468 server_id: LanguageServerId,
3469 cx: &mut AsyncApp,
3470 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3471 let this = this.upgrade().context("project project closed")?;
3472 let language_server = this
3473 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3474 .context("language server not found")?;
3475 let transaction = Self::deserialize_workspace_edit(
3476 this.clone(),
3477 params.edit,
3478 true,
3479 language_server.clone(),
3480 cx,
3481 )
3482 .await
3483 .log_err();
3484 this.update(cx, |this, cx| {
3485 if let Some(transaction) = transaction {
3486 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3487
3488 this.as_local_mut()
3489 .unwrap()
3490 .last_workspace_edits_by_language_server
3491 .insert(server_id, transaction);
3492 }
3493 });
3494 Ok(lsp::ApplyWorkspaceEditResponse {
3495 applied: true,
3496 failed_change: None,
3497 failure_reason: None,
3498 })
3499 }
3500
3501 fn remove_worktree(
3502 &mut self,
3503 id_to_remove: WorktreeId,
3504 cx: &mut Context<LspStore>,
3505 ) -> Vec<LanguageServerId> {
3506 self.restricted_worktrees_tasks.remove(&id_to_remove);
3507 self.diagnostics.remove(&id_to_remove);
3508 self.prettier_store.update(cx, |prettier_store, cx| {
3509 prettier_store.remove_worktree(id_to_remove, cx);
3510 });
3511
3512 let mut servers_to_remove = BTreeSet::default();
3513 let mut servers_to_preserve = HashSet::default();
3514 for (seed, state) in &self.language_server_ids {
3515 if seed.worktree_id == id_to_remove {
3516 servers_to_remove.insert(state.id);
3517 } else {
3518 servers_to_preserve.insert(state.id);
3519 }
3520 }
3521 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3522 self.language_server_ids
3523 .retain(|_, state| !servers_to_remove.contains(&state.id));
3524 for server_id_to_remove in &servers_to_remove {
3525 self.language_server_watched_paths
3526 .remove(server_id_to_remove);
3527 self.language_server_paths_watched_for_rename
3528 .remove(server_id_to_remove);
3529 self.last_workspace_edits_by_language_server
3530 .remove(server_id_to_remove);
3531 self.language_servers.remove(server_id_to_remove);
3532 self.buffer_pull_diagnostics_result_ids
3533 .remove(server_id_to_remove);
3534 self.workspace_pull_diagnostics_result_ids
3535 .remove(server_id_to_remove);
3536 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3537 buffer_servers.remove(server_id_to_remove);
3538 }
3539 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3540 }
3541 servers_to_remove.into_iter().collect()
3542 }
3543
3544 fn rebuild_watched_paths_inner<'a>(
3545 &'a self,
3546 language_server_id: LanguageServerId,
3547 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3548 cx: &mut Context<LspStore>,
3549 ) -> LanguageServerWatchedPathsBuilder {
3550 let worktrees = self
3551 .worktree_store
3552 .read(cx)
3553 .worktrees()
3554 .filter_map(|worktree| {
3555 self.language_servers_for_worktree(worktree.read(cx).id())
3556 .find(|server| server.server_id() == language_server_id)
3557 .map(|_| worktree)
3558 })
3559 .collect::<Vec<_>>();
3560
3561 let mut worktree_globs = HashMap::default();
3562 let mut abs_globs = HashMap::default();
3563 log::trace!(
3564 "Processing new watcher paths for language server with id {}",
3565 language_server_id
3566 );
3567
3568 for watcher in watchers {
3569 if let Some((worktree, literal_prefix, pattern)) =
3570 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3571 {
3572 worktree.update(cx, |worktree, _| {
3573 if let Some((tree, glob)) =
3574 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3575 {
3576 tree.add_path_prefix_to_scan(literal_prefix);
3577 worktree_globs
3578 .entry(tree.id())
3579 .or_insert_with(GlobSetBuilder::new)
3580 .add(glob);
3581 }
3582 });
3583 } else {
3584 let (path, pattern) = match &watcher.glob_pattern {
3585 lsp::GlobPattern::String(s) => {
3586 let watcher_path = SanitizedPath::new(s);
3587 let path = glob_literal_prefix(watcher_path.as_path());
3588 let pattern = watcher_path
3589 .as_path()
3590 .strip_prefix(&path)
3591 .map(|p| p.to_string_lossy().into_owned())
3592 .unwrap_or_else(|e| {
3593 debug_panic!(
3594 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3595 s,
3596 path.display(),
3597 e
3598 );
3599 watcher_path.as_path().to_string_lossy().into_owned()
3600 });
3601 (path, pattern)
3602 }
3603 lsp::GlobPattern::Relative(rp) => {
3604 let Ok(mut base_uri) = match &rp.base_uri {
3605 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3606 lsp::OneOf::Right(base_uri) => base_uri,
3607 }
3608 .to_file_path() else {
3609 continue;
3610 };
3611
3612 let path = glob_literal_prefix(Path::new(&rp.pattern));
3613 let pattern = Path::new(&rp.pattern)
3614 .strip_prefix(&path)
3615 .map(|p| p.to_string_lossy().into_owned())
3616 .unwrap_or_else(|e| {
3617 debug_panic!(
3618 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3619 rp.pattern,
3620 path.display(),
3621 e
3622 );
3623 rp.pattern.clone()
3624 });
3625 base_uri.push(path);
3626 (base_uri, pattern)
3627 }
3628 };
3629
3630 if let Some(glob) = Glob::new(&pattern).log_err() {
3631 if !path
3632 .components()
3633 .any(|c| matches!(c, path::Component::Normal(_)))
3634 {
3635 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3636 // rather than adding a new watcher for `/`.
3637 for worktree in &worktrees {
3638 worktree_globs
3639 .entry(worktree.read(cx).id())
3640 .or_insert_with(GlobSetBuilder::new)
3641 .add(glob.clone());
3642 }
3643 } else {
3644 abs_globs
3645 .entry(path.into())
3646 .or_insert_with(GlobSetBuilder::new)
3647 .add(glob);
3648 }
3649 }
3650 }
3651 }
3652
3653 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3654 for (worktree_id, builder) in worktree_globs {
3655 if let Ok(globset) = builder.build() {
3656 watch_builder.watch_worktree(worktree_id, globset);
3657 }
3658 }
3659 for (abs_path, builder) in abs_globs {
3660 if let Ok(globset) = builder.build() {
3661 watch_builder.watch_abs_path(abs_path, globset);
3662 }
3663 }
3664 watch_builder
3665 }
3666
3667 fn worktree_and_path_for_file_watcher(
3668 worktrees: &[Entity<Worktree>],
3669 watcher: &FileSystemWatcher,
3670 cx: &App,
3671 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3672 worktrees.iter().find_map(|worktree| {
3673 let tree = worktree.read(cx);
3674 let worktree_root_path = tree.abs_path();
3675 let path_style = tree.path_style();
3676 match &watcher.glob_pattern {
3677 lsp::GlobPattern::String(s) => {
3678 let watcher_path = SanitizedPath::new(s);
3679 let relative = watcher_path
3680 .as_path()
3681 .strip_prefix(&worktree_root_path)
3682 .ok()?;
3683 let literal_prefix = glob_literal_prefix(relative);
3684 Some((
3685 worktree.clone(),
3686 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3687 relative.to_string_lossy().into_owned(),
3688 ))
3689 }
3690 lsp::GlobPattern::Relative(rp) => {
3691 let base_uri = match &rp.base_uri {
3692 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3693 lsp::OneOf::Right(base_uri) => base_uri,
3694 }
3695 .to_file_path()
3696 .ok()?;
3697 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3698 let mut literal_prefix = relative.to_owned();
3699 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3700 Some((
3701 worktree.clone(),
3702 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3703 rp.pattern.clone(),
3704 ))
3705 }
3706 }
3707 })
3708 }
3709
3710 fn rebuild_watched_paths(
3711 &mut self,
3712 language_server_id: LanguageServerId,
3713 cx: &mut Context<LspStore>,
3714 ) {
3715 let Some(registrations) = self
3716 .language_server_dynamic_registrations
3717 .get(&language_server_id)
3718 else {
3719 return;
3720 };
3721
3722 let watch_builder = self.rebuild_watched_paths_inner(
3723 language_server_id,
3724 registrations.did_change_watched_files.values().flatten(),
3725 cx,
3726 );
3727 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3728 self.language_server_watched_paths
3729 .insert(language_server_id, watcher);
3730
3731 cx.notify();
3732 }
3733
3734 fn on_lsp_did_change_watched_files(
3735 &mut self,
3736 language_server_id: LanguageServerId,
3737 registration_id: &str,
3738 params: DidChangeWatchedFilesRegistrationOptions,
3739 cx: &mut Context<LspStore>,
3740 ) {
3741 let registrations = self
3742 .language_server_dynamic_registrations
3743 .entry(language_server_id)
3744 .or_default();
3745
3746 registrations
3747 .did_change_watched_files
3748 .insert(registration_id.to_string(), params.watchers);
3749
3750 self.rebuild_watched_paths(language_server_id, cx);
3751 }
3752
3753 fn on_lsp_unregister_did_change_watched_files(
3754 &mut self,
3755 language_server_id: LanguageServerId,
3756 registration_id: &str,
3757 cx: &mut Context<LspStore>,
3758 ) {
3759 let registrations = self
3760 .language_server_dynamic_registrations
3761 .entry(language_server_id)
3762 .or_default();
3763
3764 if registrations
3765 .did_change_watched_files
3766 .remove(registration_id)
3767 .is_some()
3768 {
3769 log::info!(
3770 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3771 language_server_id,
3772 registration_id
3773 );
3774 } else {
3775 log::warn!(
3776 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3777 language_server_id,
3778 registration_id
3779 );
3780 }
3781
3782 self.rebuild_watched_paths(language_server_id, cx);
3783 }
3784
3785 async fn initialization_options_for_adapter(
3786 adapter: Arc<dyn LspAdapter>,
3787 delegate: &Arc<dyn LspAdapterDelegate>,
3788 cx: &mut AsyncApp,
3789 ) -> Result<Option<serde_json::Value>> {
3790 let Some(mut initialization_config) =
3791 adapter.clone().initialization_options(delegate, cx).await?
3792 else {
3793 return Ok(None);
3794 };
3795
3796 for other_adapter in delegate.registered_lsp_adapters() {
3797 if other_adapter.name() == adapter.name() {
3798 continue;
3799 }
3800 if let Ok(Some(target_config)) = other_adapter
3801 .clone()
3802 .additional_initialization_options(adapter.name(), delegate)
3803 .await
3804 {
3805 merge_json_value_into(target_config.clone(), &mut initialization_config);
3806 }
3807 }
3808
3809 Ok(Some(initialization_config))
3810 }
3811
3812 async fn workspace_configuration_for_adapter(
3813 adapter: Arc<dyn LspAdapter>,
3814 delegate: &Arc<dyn LspAdapterDelegate>,
3815 toolchain: Option<Toolchain>,
3816 requested_uri: Option<Uri>,
3817 cx: &mut AsyncApp,
3818 ) -> Result<serde_json::Value> {
3819 let mut workspace_config = adapter
3820 .clone()
3821 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3822 .await?;
3823
3824 for other_adapter in delegate.registered_lsp_adapters() {
3825 if other_adapter.name() == adapter.name() {
3826 continue;
3827 }
3828 if let Ok(Some(target_config)) = other_adapter
3829 .clone()
3830 .additional_workspace_configuration(adapter.name(), delegate, cx)
3831 .await
3832 {
3833 merge_json_value_into(target_config.clone(), &mut workspace_config);
3834 }
3835 }
3836
3837 Ok(workspace_config)
3838 }
3839
3840 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3841 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3842 Some(server.clone())
3843 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3844 Some(Arc::clone(server))
3845 } else {
3846 None
3847 }
3848 }
3849}
3850
3851fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3852 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3853 cx.emit(LspStoreEvent::LanguageServerUpdate {
3854 language_server_id: server.server_id(),
3855 name: Some(server.name()),
3856 message: proto::update_language_server::Variant::MetadataUpdated(
3857 proto::ServerMetadataUpdated {
3858 capabilities: Some(capabilities),
3859 binary: Some(proto::LanguageServerBinaryInfo {
3860 path: server.binary().path.to_string_lossy().into_owned(),
3861 arguments: server
3862 .binary()
3863 .arguments
3864 .iter()
3865 .map(|arg| arg.to_string_lossy().into_owned())
3866 .collect(),
3867 }),
3868 configuration: serde_json::to_string(server.configuration()).ok(),
3869 workspace_folders: server
3870 .workspace_folders()
3871 .iter()
3872 .map(|uri| uri.to_string())
3873 .collect(),
3874 },
3875 ),
3876 });
3877 }
3878}
3879
3880#[derive(Debug)]
3881pub struct FormattableBuffer {
3882 handle: Entity<Buffer>,
3883 abs_path: Option<PathBuf>,
3884 env: Option<HashMap<String, String>>,
3885 ranges: Option<Vec<Range<Anchor>>>,
3886}
3887
3888pub struct RemoteLspStore {
3889 upstream_client: Option<AnyProtoClient>,
3890 upstream_project_id: u64,
3891}
3892
3893pub(crate) enum LspStoreMode {
3894 Local(LocalLspStore), // ssh host and collab host
3895 Remote(RemoteLspStore), // collab guest
3896}
3897
3898impl LspStoreMode {
3899 fn is_local(&self) -> bool {
3900 matches!(self, LspStoreMode::Local(_))
3901 }
3902}
3903
3904pub struct LspStore {
3905 mode: LspStoreMode,
3906 last_formatting_failure: Option<String>,
3907 downstream_client: Option<(AnyProtoClient, u64)>,
3908 nonce: u128,
3909 buffer_store: Entity<BufferStore>,
3910 worktree_store: Entity<WorktreeStore>,
3911 pub languages: Arc<LanguageRegistry>,
3912 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3913 active_entry: Option<ProjectEntryId>,
3914 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3915 _maintain_buffer_languages: Task<()>,
3916 diagnostic_summaries:
3917 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3918 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3919 semantic_token_config: SemanticTokenConfig,
3920 lsp_data: HashMap<BufferId, BufferLspData>,
3921 next_hint_id: Arc<AtomicUsize>,
3922}
3923
3924#[derive(Debug)]
3925pub struct BufferLspData {
3926 buffer_version: Global,
3927 document_colors: Option<DocumentColorData>,
3928 code_lens: Option<CodeLensData>,
3929 semantic_tokens: Option<SemanticTokensData>,
3930 folding_ranges: Option<FoldingRangeData>,
3931 document_symbols: Option<DocumentSymbolsData>,
3932 inlay_hints: BufferInlayHints,
3933 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3934 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3935}
3936
3937#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3938struct LspKey {
3939 request_type: TypeId,
3940 server_queried: Option<LanguageServerId>,
3941}
3942
3943impl BufferLspData {
3944 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3945 Self {
3946 buffer_version: buffer.read(cx).version(),
3947 document_colors: None,
3948 code_lens: None,
3949 semantic_tokens: None,
3950 folding_ranges: None,
3951 document_symbols: None,
3952 inlay_hints: BufferInlayHints::new(buffer, cx),
3953 lsp_requests: HashMap::default(),
3954 chunk_lsp_requests: HashMap::default(),
3955 }
3956 }
3957
3958 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3959 if let Some(document_colors) = &mut self.document_colors {
3960 document_colors.remove_server_data(for_server);
3961 }
3962
3963 if let Some(code_lens) = &mut self.code_lens {
3964 code_lens.remove_server_data(for_server);
3965 }
3966
3967 self.inlay_hints.remove_server_data(for_server);
3968
3969 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3970 semantic_tokens.remove_server_data(for_server);
3971 }
3972
3973 if let Some(folding_ranges) = &mut self.folding_ranges {
3974 folding_ranges.ranges.remove(&for_server);
3975 }
3976
3977 if let Some(document_symbols) = &mut self.document_symbols {
3978 document_symbols.remove_server_data(for_server);
3979 }
3980 }
3981
3982 #[cfg(any(test, feature = "test-support"))]
3983 pub fn inlay_hints(&self) -> &BufferInlayHints {
3984 &self.inlay_hints
3985 }
3986}
3987
3988#[derive(Debug)]
3989pub enum LspStoreEvent {
3990 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3991 LanguageServerRemoved(LanguageServerId),
3992 LanguageServerUpdate {
3993 language_server_id: LanguageServerId,
3994 name: Option<LanguageServerName>,
3995 message: proto::update_language_server::Variant,
3996 },
3997 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3998 LanguageServerPrompt(LanguageServerPromptRequest),
3999 LanguageDetected {
4000 buffer: Entity<Buffer>,
4001 new_language: Option<Arc<Language>>,
4002 },
4003 Notification(String),
4004 RefreshInlayHints {
4005 server_id: LanguageServerId,
4006 request_id: Option<usize>,
4007 },
4008 RefreshSemanticTokens {
4009 server_id: LanguageServerId,
4010 request_id: Option<usize>,
4011 },
4012 RefreshCodeLens,
4013 DiagnosticsUpdated {
4014 server_id: LanguageServerId,
4015 paths: Vec<ProjectPath>,
4016 },
4017 DiskBasedDiagnosticsStarted {
4018 language_server_id: LanguageServerId,
4019 },
4020 DiskBasedDiagnosticsFinished {
4021 language_server_id: LanguageServerId,
4022 },
4023 SnippetEdit {
4024 buffer_id: BufferId,
4025 edits: Vec<(lsp::Range, Snippet)>,
4026 most_recent_edit: clock::Lamport,
4027 },
4028 WorkspaceEditApplied(ProjectTransaction),
4029}
4030
4031#[derive(Clone, Debug, Serialize)]
4032pub struct LanguageServerStatus {
4033 pub name: LanguageServerName,
4034 pub server_version: Option<SharedString>,
4035 pub server_readable_version: Option<SharedString>,
4036 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4037 pub has_pending_diagnostic_updates: bool,
4038 pub progress_tokens: HashSet<ProgressToken>,
4039 pub worktree: Option<WorktreeId>,
4040 pub binary: Option<LanguageServerBinary>,
4041 pub configuration: Option<Value>,
4042 pub workspace_folders: BTreeSet<Uri>,
4043 pub process_id: Option<u32>,
4044}
4045
4046#[derive(Clone, Debug)]
4047struct CoreSymbol {
4048 pub language_server_name: LanguageServerName,
4049 pub source_worktree_id: WorktreeId,
4050 pub source_language_server_id: LanguageServerId,
4051 pub path: SymbolLocation,
4052 pub name: String,
4053 pub kind: lsp::SymbolKind,
4054 pub range: Range<Unclipped<PointUtf16>>,
4055 pub container_name: Option<String>,
4056}
4057
4058#[derive(Clone, Debug, PartialEq, Eq)]
4059pub enum SymbolLocation {
4060 InProject(ProjectPath),
4061 OutsideProject {
4062 abs_path: Arc<Path>,
4063 signature: [u8; 32],
4064 },
4065}
4066
4067impl SymbolLocation {
4068 fn file_name(&self) -> Option<&str> {
4069 match self {
4070 Self::InProject(path) => path.path.file_name(),
4071 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4072 }
4073 }
4074}
4075
4076impl LspStore {
4077 pub fn init(client: &AnyProtoClient) {
4078 client.add_entity_request_handler(Self::handle_lsp_query);
4079 client.add_entity_message_handler(Self::handle_lsp_query_response);
4080 client.add_entity_request_handler(Self::handle_restart_language_servers);
4081 client.add_entity_request_handler(Self::handle_stop_language_servers);
4082 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4083 client.add_entity_message_handler(Self::handle_start_language_server);
4084 client.add_entity_message_handler(Self::handle_update_language_server);
4085 client.add_entity_message_handler(Self::handle_language_server_log);
4086 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4087 client.add_entity_request_handler(Self::handle_format_buffers);
4088 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4089 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4090 client.add_entity_request_handler(Self::handle_apply_code_action);
4091 client.add_entity_request_handler(Self::handle_get_project_symbols);
4092 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4093 client.add_entity_request_handler(Self::handle_get_color_presentation);
4094 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4095 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4096 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4097 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4098 client.add_entity_request_handler(Self::handle_on_type_formatting);
4099 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4100 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4101 client.add_entity_request_handler(Self::handle_rename_project_entry);
4102 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4103 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4104 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4105 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4106 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4107 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4108 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4109
4110 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4111 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4112 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4113 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4114 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4115 client.add_entity_request_handler(
4116 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4117 );
4118 client.add_entity_request_handler(
4119 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4120 );
4121 client.add_entity_request_handler(
4122 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4123 );
4124 }
4125
4126 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4127 match &self.mode {
4128 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4129 _ => None,
4130 }
4131 }
4132
4133 pub fn as_local(&self) -> Option<&LocalLspStore> {
4134 match &self.mode {
4135 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4136 _ => None,
4137 }
4138 }
4139
4140 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4141 match &mut self.mode {
4142 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4143 _ => None,
4144 }
4145 }
4146
4147 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4148 match &self.mode {
4149 LspStoreMode::Remote(RemoteLspStore {
4150 upstream_client: Some(upstream_client),
4151 upstream_project_id,
4152 ..
4153 }) => Some((upstream_client.clone(), *upstream_project_id)),
4154
4155 LspStoreMode::Remote(RemoteLspStore {
4156 upstream_client: None,
4157 ..
4158 }) => None,
4159 LspStoreMode::Local(_) => None,
4160 }
4161 }
4162
4163 pub fn new_local(
4164 buffer_store: Entity<BufferStore>,
4165 worktree_store: Entity<WorktreeStore>,
4166 prettier_store: Entity<PrettierStore>,
4167 toolchain_store: Entity<LocalToolchainStore>,
4168 environment: Entity<ProjectEnvironment>,
4169 manifest_tree: Entity<ManifestTree>,
4170 languages: Arc<LanguageRegistry>,
4171 http_client: Arc<dyn HttpClient>,
4172 fs: Arc<dyn Fs>,
4173 cx: &mut Context<Self>,
4174 ) -> Self {
4175 let yarn = YarnPathStore::new(fs.clone(), cx);
4176 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4177 .detach();
4178 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4179 .detach();
4180 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4181 .detach();
4182 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4183 .detach();
4184 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4185 .detach();
4186 subscribe_to_binary_statuses(&languages, cx).detach();
4187
4188 let _maintain_workspace_config = {
4189 let (sender, receiver) = watch::channel();
4190 (Self::maintain_workspace_config(receiver, cx), sender)
4191 };
4192
4193 Self {
4194 mode: LspStoreMode::Local(LocalLspStore {
4195 weak: cx.weak_entity(),
4196 worktree_store: worktree_store.clone(),
4197
4198 supplementary_language_servers: Default::default(),
4199 languages: languages.clone(),
4200 language_server_ids: Default::default(),
4201 language_servers: Default::default(),
4202 last_workspace_edits_by_language_server: Default::default(),
4203 language_server_watched_paths: Default::default(),
4204 language_server_paths_watched_for_rename: Default::default(),
4205 language_server_dynamic_registrations: Default::default(),
4206 buffers_being_formatted: Default::default(),
4207 buffers_to_refresh_hash_set: HashSet::default(),
4208 buffers_to_refresh_queue: VecDeque::new(),
4209 _background_diagnostics_worker: Task::ready(()).shared(),
4210 buffer_snapshots: Default::default(),
4211 prettier_store,
4212 environment,
4213 http_client,
4214 fs,
4215 yarn,
4216 next_diagnostic_group_id: Default::default(),
4217 diagnostics: Default::default(),
4218 _subscription: cx.on_app_quit(|this, _| {
4219 this.as_local_mut()
4220 .unwrap()
4221 .shutdown_language_servers_on_quit()
4222 }),
4223 lsp_tree: LanguageServerTree::new(
4224 manifest_tree,
4225 languages.clone(),
4226 toolchain_store.clone(),
4227 ),
4228 toolchain_store,
4229 registered_buffers: HashMap::default(),
4230 buffers_opened_in_servers: HashMap::default(),
4231 buffer_pull_diagnostics_result_ids: HashMap::default(),
4232 workspace_pull_diagnostics_result_ids: HashMap::default(),
4233 restricted_worktrees_tasks: HashMap::default(),
4234 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4235 .manifest_file_names(),
4236 }),
4237 last_formatting_failure: None,
4238 downstream_client: None,
4239 buffer_store,
4240 worktree_store,
4241 languages: languages.clone(),
4242 language_server_statuses: Default::default(),
4243 nonce: StdRng::from_os_rng().random(),
4244 diagnostic_summaries: HashMap::default(),
4245 lsp_server_capabilities: HashMap::default(),
4246 semantic_token_config: SemanticTokenConfig::new(cx),
4247 lsp_data: HashMap::default(),
4248 next_hint_id: Arc::default(),
4249 active_entry: None,
4250 _maintain_workspace_config,
4251 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4252 }
4253 }
4254
4255 fn send_lsp_proto_request<R: LspCommand>(
4256 &self,
4257 buffer: Entity<Buffer>,
4258 client: AnyProtoClient,
4259 upstream_project_id: u64,
4260 request: R,
4261 cx: &mut Context<LspStore>,
4262 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4263 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4264 return Task::ready(Ok(R::Response::default()));
4265 }
4266 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4267 cx.spawn(async move |this, cx| {
4268 let response = client.request(message).await?;
4269 let this = this.upgrade().context("project dropped")?;
4270 request
4271 .response_from_proto(response, this, buffer, cx.clone())
4272 .await
4273 })
4274 }
4275
4276 pub(super) fn new_remote(
4277 buffer_store: Entity<BufferStore>,
4278 worktree_store: Entity<WorktreeStore>,
4279 languages: Arc<LanguageRegistry>,
4280 upstream_client: AnyProtoClient,
4281 project_id: u64,
4282 cx: &mut Context<Self>,
4283 ) -> Self {
4284 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4285 .detach();
4286 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4287 .detach();
4288 subscribe_to_binary_statuses(&languages, cx).detach();
4289 let _maintain_workspace_config = {
4290 let (sender, receiver) = watch::channel();
4291 (Self::maintain_workspace_config(receiver, cx), sender)
4292 };
4293 Self {
4294 mode: LspStoreMode::Remote(RemoteLspStore {
4295 upstream_client: Some(upstream_client),
4296 upstream_project_id: project_id,
4297 }),
4298 downstream_client: None,
4299 last_formatting_failure: None,
4300 buffer_store,
4301 worktree_store,
4302 languages: languages.clone(),
4303 language_server_statuses: Default::default(),
4304 nonce: StdRng::from_os_rng().random(),
4305 diagnostic_summaries: HashMap::default(),
4306 lsp_server_capabilities: HashMap::default(),
4307 semantic_token_config: SemanticTokenConfig::new(cx),
4308 next_hint_id: Arc::default(),
4309 lsp_data: HashMap::default(),
4310 active_entry: None,
4311
4312 _maintain_workspace_config,
4313 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4314 }
4315 }
4316
4317 fn on_buffer_store_event(
4318 &mut self,
4319 _: Entity<BufferStore>,
4320 event: &BufferStoreEvent,
4321 cx: &mut Context<Self>,
4322 ) {
4323 match event {
4324 BufferStoreEvent::BufferAdded(buffer) => {
4325 self.on_buffer_added(buffer, cx).log_err();
4326 }
4327 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4328 let buffer_id = buffer.read(cx).remote_id();
4329 if let Some(local) = self.as_local_mut()
4330 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4331 {
4332 local.reset_buffer(buffer, old_file, cx);
4333
4334 if local.registered_buffers.contains_key(&buffer_id) {
4335 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4336 }
4337 }
4338
4339 self.detect_language_for_buffer(buffer, cx);
4340 if let Some(local) = self.as_local_mut() {
4341 local.initialize_buffer(buffer, cx);
4342 if local.registered_buffers.contains_key(&buffer_id) {
4343 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4344 }
4345 }
4346 }
4347 _ => {}
4348 }
4349 }
4350
4351 fn on_worktree_store_event(
4352 &mut self,
4353 _: Entity<WorktreeStore>,
4354 event: &WorktreeStoreEvent,
4355 cx: &mut Context<Self>,
4356 ) {
4357 match event {
4358 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4359 if !worktree.read(cx).is_local() {
4360 return;
4361 }
4362 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4363 worktree::Event::UpdatedEntries(changes) => {
4364 this.update_local_worktree_language_servers(&worktree, changes, cx);
4365 }
4366 worktree::Event::UpdatedGitRepositories(_)
4367 | worktree::Event::DeletedEntry(_) => {}
4368 })
4369 .detach()
4370 }
4371 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4372 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4373 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4374 }
4375 WorktreeStoreEvent::WorktreeReleased(..)
4376 | WorktreeStoreEvent::WorktreeOrderChanged
4377 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4378 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4379 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4380 }
4381 }
4382
4383 fn on_prettier_store_event(
4384 &mut self,
4385 _: Entity<PrettierStore>,
4386 event: &PrettierStoreEvent,
4387 cx: &mut Context<Self>,
4388 ) {
4389 match event {
4390 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4391 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4392 }
4393 PrettierStoreEvent::LanguageServerAdded {
4394 new_server_id,
4395 name,
4396 prettier_server,
4397 } => {
4398 self.register_supplementary_language_server(
4399 *new_server_id,
4400 name.clone(),
4401 prettier_server.clone(),
4402 cx,
4403 );
4404 }
4405 }
4406 }
4407
4408 fn on_toolchain_store_event(
4409 &mut self,
4410 _: Entity<LocalToolchainStore>,
4411 event: &ToolchainStoreEvent,
4412 _: &mut Context<Self>,
4413 ) {
4414 if let ToolchainStoreEvent::ToolchainActivated = event {
4415 self.request_workspace_config_refresh()
4416 }
4417 }
4418
4419 fn request_workspace_config_refresh(&mut self) {
4420 *self._maintain_workspace_config.1.borrow_mut() = ();
4421 }
4422
4423 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4424 self.as_local().map(|local| local.prettier_store.clone())
4425 }
4426
4427 fn on_buffer_event(
4428 &mut self,
4429 buffer: Entity<Buffer>,
4430 event: &language::BufferEvent,
4431 cx: &mut Context<Self>,
4432 ) {
4433 match event {
4434 language::BufferEvent::Edited { .. } => {
4435 self.on_buffer_edited(buffer, cx);
4436 }
4437
4438 language::BufferEvent::Saved => {
4439 self.on_buffer_saved(buffer, cx);
4440 }
4441
4442 _ => {}
4443 }
4444 }
4445
4446 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4447 buffer
4448 .read(cx)
4449 .set_language_registry(self.languages.clone());
4450
4451 cx.subscribe(buffer, |this, buffer, event, cx| {
4452 this.on_buffer_event(buffer, event, cx);
4453 })
4454 .detach();
4455
4456 self.detect_language_for_buffer(buffer, cx);
4457 if let Some(local) = self.as_local_mut() {
4458 local.initialize_buffer(buffer, cx);
4459 }
4460
4461 Ok(())
4462 }
4463
4464 pub fn refresh_background_diagnostics_for_buffers(
4465 &mut self,
4466 buffers: HashSet<BufferId>,
4467 cx: &mut Context<Self>,
4468 ) -> Shared<Task<()>> {
4469 let Some(local) = self.as_local_mut() else {
4470 return Task::ready(()).shared();
4471 };
4472 for buffer in buffers {
4473 if local.buffers_to_refresh_hash_set.insert(buffer) {
4474 local.buffers_to_refresh_queue.push_back(buffer);
4475 if local.buffers_to_refresh_queue.len() == 1 {
4476 local._background_diagnostics_worker =
4477 Self::background_diagnostics_worker(cx).shared();
4478 }
4479 }
4480 }
4481
4482 local._background_diagnostics_worker.clone()
4483 }
4484
4485 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4486 let buffer_store = self.buffer_store.clone();
4487 let local = self.as_local_mut()?;
4488 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4489 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4490 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4491 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4492 }
4493 }
4494 None
4495 }
4496
4497 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4498 cx.spawn(async move |this, cx| {
4499 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4500 task.await.log_err();
4501 }
4502 })
4503 }
4504
4505 pub(crate) fn register_buffer_with_language_servers(
4506 &mut self,
4507 buffer: &Entity<Buffer>,
4508 only_register_servers: HashSet<LanguageServerSelector>,
4509 ignore_refcounts: bool,
4510 cx: &mut Context<Self>,
4511 ) -> OpenLspBufferHandle {
4512 let buffer_id = buffer.read(cx).remote_id();
4513 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4514 if let Some(local) = self.as_local_mut() {
4515 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4516 if !ignore_refcounts {
4517 *refcount += 1;
4518 }
4519
4520 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4521 // 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
4522 // 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
4523 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4524 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4525 return handle;
4526 };
4527 if !file.is_local() {
4528 return handle;
4529 }
4530
4531 if ignore_refcounts || *refcount == 1 {
4532 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4533 }
4534 if !ignore_refcounts {
4535 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4536 let refcount = {
4537 let local = lsp_store.as_local_mut().unwrap();
4538 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4539 debug_panic!("bad refcounting");
4540 return;
4541 };
4542
4543 *refcount -= 1;
4544 *refcount
4545 };
4546 if refcount == 0 {
4547 lsp_store.lsp_data.remove(&buffer_id);
4548 let local = lsp_store.as_local_mut().unwrap();
4549 local.registered_buffers.remove(&buffer_id);
4550
4551 local.buffers_opened_in_servers.remove(&buffer_id);
4552 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4553 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4554
4555 let buffer_abs_path = file.abs_path(cx);
4556 for (_, buffer_pull_diagnostics_result_ids) in
4557 &mut local.buffer_pull_diagnostics_result_ids
4558 {
4559 buffer_pull_diagnostics_result_ids.retain(
4560 |_, buffer_result_ids| {
4561 buffer_result_ids.remove(&buffer_abs_path);
4562 !buffer_result_ids.is_empty()
4563 },
4564 );
4565 }
4566
4567 let diagnostic_updates = local
4568 .language_servers
4569 .keys()
4570 .cloned()
4571 .map(|server_id| DocumentDiagnosticsUpdate {
4572 diagnostics: DocumentDiagnostics {
4573 document_abs_path: buffer_abs_path.clone(),
4574 version: None,
4575 diagnostics: Vec::new(),
4576 },
4577 result_id: None,
4578 registration_id: None,
4579 server_id,
4580 disk_based_sources: Cow::Borrowed(&[]),
4581 })
4582 .collect::<Vec<_>>();
4583
4584 lsp_store
4585 .merge_diagnostic_entries(
4586 diagnostic_updates,
4587 |_, diagnostic, _| {
4588 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4589 },
4590 cx,
4591 )
4592 .context("Clearing diagnostics for the closed buffer")
4593 .log_err();
4594 }
4595 }
4596 })
4597 .detach();
4598 }
4599 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4600 let buffer_id = buffer.read(cx).remote_id().to_proto();
4601 cx.background_spawn(async move {
4602 upstream_client
4603 .request(proto::RegisterBufferWithLanguageServers {
4604 project_id: upstream_project_id,
4605 buffer_id,
4606 only_servers: only_register_servers
4607 .into_iter()
4608 .map(|selector| {
4609 let selector = match selector {
4610 LanguageServerSelector::Id(language_server_id) => {
4611 proto::language_server_selector::Selector::ServerId(
4612 language_server_id.to_proto(),
4613 )
4614 }
4615 LanguageServerSelector::Name(language_server_name) => {
4616 proto::language_server_selector::Selector::Name(
4617 language_server_name.to_string(),
4618 )
4619 }
4620 };
4621 proto::LanguageServerSelector {
4622 selector: Some(selector),
4623 }
4624 })
4625 .collect(),
4626 })
4627 .await
4628 })
4629 .detach();
4630 } else {
4631 // Our remote connection got closed
4632 }
4633 handle
4634 }
4635
4636 fn maintain_buffer_languages(
4637 languages: Arc<LanguageRegistry>,
4638 cx: &mut Context<Self>,
4639 ) -> Task<()> {
4640 let mut subscription = languages.subscribe();
4641 let mut prev_reload_count = languages.reload_count();
4642 cx.spawn(async move |this, cx| {
4643 while let Some(()) = subscription.next().await {
4644 if let Some(this) = this.upgrade() {
4645 // If the language registry has been reloaded, then remove and
4646 // re-assign the languages on all open buffers.
4647 let reload_count = languages.reload_count();
4648 if reload_count > prev_reload_count {
4649 prev_reload_count = reload_count;
4650 this.update(cx, |this, cx| {
4651 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4652 for buffer in buffer_store.buffers() {
4653 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4654 {
4655 buffer.update(cx, |buffer, cx| {
4656 buffer.set_language_async(None, cx)
4657 });
4658 if let Some(local) = this.as_local_mut() {
4659 local.reset_buffer(&buffer, &f, cx);
4660
4661 if local
4662 .registered_buffers
4663 .contains_key(&buffer.read(cx).remote_id())
4664 && let Some(file_url) =
4665 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4666 {
4667 local.unregister_buffer_from_language_servers(
4668 &buffer, &file_url, cx,
4669 );
4670 }
4671 }
4672 }
4673 }
4674 });
4675 });
4676 }
4677
4678 this.update(cx, |this, cx| {
4679 let mut plain_text_buffers = Vec::new();
4680 let mut buffers_with_unknown_injections = Vec::new();
4681 for handle in this.buffer_store.read(cx).buffers() {
4682 let buffer = handle.read(cx);
4683 if buffer.language().is_none()
4684 || buffer.language() == Some(&*language::PLAIN_TEXT)
4685 {
4686 plain_text_buffers.push(handle);
4687 } else if buffer.contains_unknown_injections() {
4688 buffers_with_unknown_injections.push(handle);
4689 }
4690 }
4691
4692 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4693 // and reused later in the invisible worktrees.
4694 plain_text_buffers.sort_by_key(|buffer| {
4695 Reverse(
4696 File::from_dyn(buffer.read(cx).file())
4697 .map(|file| file.worktree.read(cx).is_visible()),
4698 )
4699 });
4700
4701 for buffer in plain_text_buffers {
4702 this.detect_language_for_buffer(&buffer, cx);
4703 if let Some(local) = this.as_local_mut() {
4704 local.initialize_buffer(&buffer, cx);
4705 if local
4706 .registered_buffers
4707 .contains_key(&buffer.read(cx).remote_id())
4708 {
4709 local.register_buffer_with_language_servers(
4710 &buffer,
4711 HashSet::default(),
4712 cx,
4713 );
4714 }
4715 }
4716 }
4717
4718 for buffer in buffers_with_unknown_injections {
4719 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4720 }
4721 });
4722 }
4723 }
4724 })
4725 }
4726
4727 fn detect_language_for_buffer(
4728 &mut self,
4729 buffer_handle: &Entity<Buffer>,
4730 cx: &mut Context<Self>,
4731 ) -> Option<language::AvailableLanguage> {
4732 // If the buffer has a language, set it and start the language server if we haven't already.
4733 let buffer = buffer_handle.read(cx);
4734 let file = buffer.file()?;
4735
4736 let content = buffer.as_rope();
4737 let available_language = self.languages.language_for_file(file, Some(content), cx);
4738 if let Some(available_language) = &available_language {
4739 if let Some(Ok(Ok(new_language))) = self
4740 .languages
4741 .load_language(available_language)
4742 .now_or_never()
4743 {
4744 self.set_language_for_buffer(buffer_handle, new_language, cx);
4745 }
4746 } else {
4747 cx.emit(LspStoreEvent::LanguageDetected {
4748 buffer: buffer_handle.clone(),
4749 new_language: None,
4750 });
4751 }
4752
4753 available_language
4754 }
4755
4756 pub(crate) fn set_language_for_buffer(
4757 &mut self,
4758 buffer_entity: &Entity<Buffer>,
4759 new_language: Arc<Language>,
4760 cx: &mut Context<Self>,
4761 ) {
4762 let buffer = buffer_entity.read(cx);
4763 let buffer_file = buffer.file().cloned();
4764 let buffer_id = buffer.remote_id();
4765 if let Some(local_store) = self.as_local_mut()
4766 && local_store.registered_buffers.contains_key(&buffer_id)
4767 && let Some(abs_path) =
4768 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4769 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4770 {
4771 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4772 }
4773 buffer_entity.update(cx, |buffer, cx| {
4774 if buffer
4775 .language()
4776 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4777 {
4778 buffer.set_language_async(Some(new_language.clone()), cx);
4779 }
4780 });
4781
4782 let settings =
4783 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4784 let buffer_file = File::from_dyn(buffer_file.as_ref());
4785
4786 let worktree_id = if let Some(file) = buffer_file {
4787 let worktree = file.worktree.clone();
4788
4789 if let Some(local) = self.as_local_mut()
4790 && local.registered_buffers.contains_key(&buffer_id)
4791 {
4792 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4793 }
4794 Some(worktree.read(cx).id())
4795 } else {
4796 None
4797 };
4798
4799 if settings.prettier.allowed
4800 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4801 {
4802 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4803 if let Some(prettier_store) = prettier_store {
4804 prettier_store.update(cx, |prettier_store, cx| {
4805 prettier_store.install_default_prettier(
4806 worktree_id,
4807 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4808 cx,
4809 )
4810 })
4811 }
4812 }
4813
4814 cx.emit(LspStoreEvent::LanguageDetected {
4815 buffer: buffer_entity.clone(),
4816 new_language: Some(new_language),
4817 })
4818 }
4819
4820 pub fn buffer_store(&self) -> Entity<BufferStore> {
4821 self.buffer_store.clone()
4822 }
4823
4824 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4825 self.active_entry = active_entry;
4826 }
4827
4828 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4829 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4830 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4831 {
4832 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4833 summaries
4834 .iter()
4835 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4836 });
4837 if let Some(summary) = summaries.next() {
4838 client
4839 .send(proto::UpdateDiagnosticSummary {
4840 project_id: downstream_project_id,
4841 worktree_id: worktree.id().to_proto(),
4842 summary: Some(summary),
4843 more_summaries: summaries.collect(),
4844 })
4845 .log_err();
4846 }
4847 }
4848 }
4849
4850 fn is_capable_for_proto_request<R>(
4851 &self,
4852 buffer: &Entity<Buffer>,
4853 request: &R,
4854 cx: &App,
4855 ) -> bool
4856 where
4857 R: LspCommand,
4858 {
4859 self.check_if_capable_for_proto_request(
4860 buffer,
4861 |capabilities| {
4862 request.check_capabilities(AdapterServerCapabilities {
4863 server_capabilities: capabilities.clone(),
4864 code_action_kinds: None,
4865 })
4866 },
4867 cx,
4868 )
4869 }
4870
4871 fn check_if_capable_for_proto_request<F>(
4872 &self,
4873 buffer: &Entity<Buffer>,
4874 check: F,
4875 cx: &App,
4876 ) -> bool
4877 where
4878 F: FnMut(&lsp::ServerCapabilities) -> bool,
4879 {
4880 let Some(language) = buffer.read(cx).language().cloned() else {
4881 return false;
4882 };
4883 let registered_language_servers = self
4884 .languages
4885 .lsp_adapters(&language.name())
4886 .into_iter()
4887 .map(|lsp_adapter| lsp_adapter.name())
4888 .collect::<HashSet<_>>();
4889 self.language_server_statuses
4890 .iter()
4891 .filter_map(|(server_id, server_status)| {
4892 // Include servers that are either registered for this language OR
4893 // available to be loaded (for SSH remote mode where adapters like
4894 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4895 // but only loaded on the server side)
4896 let is_relevant = registered_language_servers.contains(&server_status.name)
4897 || self.languages.is_lsp_adapter_available(&server_status.name);
4898 is_relevant.then_some(server_id)
4899 })
4900 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4901 .any(check)
4902 }
4903
4904 fn all_capable_for_proto_request<F>(
4905 &self,
4906 buffer: &Entity<Buffer>,
4907 mut check: F,
4908 cx: &App,
4909 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4910 where
4911 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4912 {
4913 let Some(language) = buffer.read(cx).language().cloned() else {
4914 return Vec::default();
4915 };
4916 let registered_language_servers = self
4917 .languages
4918 .lsp_adapters(&language.name())
4919 .into_iter()
4920 .map(|lsp_adapter| lsp_adapter.name())
4921 .collect::<HashSet<_>>();
4922 self.language_server_statuses
4923 .iter()
4924 .filter_map(|(server_id, server_status)| {
4925 // Include servers that are either registered for this language OR
4926 // available to be loaded (for SSH remote mode where adapters like
4927 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4928 // but only loaded on the server side)
4929 let is_relevant = registered_language_servers.contains(&server_status.name)
4930 || self.languages.is_lsp_adapter_available(&server_status.name);
4931 is_relevant.then_some((server_id, &server_status.name))
4932 })
4933 .filter_map(|(server_id, server_name)| {
4934 self.lsp_server_capabilities
4935 .get(server_id)
4936 .map(|c| (server_id, server_name, c))
4937 })
4938 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4939 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
4940 .collect()
4941 }
4942
4943 pub fn request_lsp<R>(
4944 &mut self,
4945 buffer: Entity<Buffer>,
4946 server: LanguageServerToQuery,
4947 request: R,
4948 cx: &mut Context<Self>,
4949 ) -> Task<Result<R::Response>>
4950 where
4951 R: LspCommand,
4952 <R::LspRequest as lsp::request::Request>::Result: Send,
4953 <R::LspRequest as lsp::request::Request>::Params: Send,
4954 {
4955 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4956 return self.send_lsp_proto_request(
4957 buffer,
4958 upstream_client,
4959 upstream_project_id,
4960 request,
4961 cx,
4962 );
4963 }
4964
4965 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4966 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4967 local
4968 .language_servers_for_buffer(buffer, cx)
4969 .find(|(_, server)| {
4970 request.check_capabilities(server.adapter_server_capabilities())
4971 })
4972 .map(|(_, server)| server.clone())
4973 }),
4974 LanguageServerToQuery::Other(id) => self
4975 .language_server_for_local_buffer(buffer, id, cx)
4976 .and_then(|(_, server)| {
4977 request
4978 .check_capabilities(server.adapter_server_capabilities())
4979 .then(|| Arc::clone(server))
4980 }),
4981 }) else {
4982 return Task::ready(Ok(Default::default()));
4983 };
4984
4985 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4986
4987 let Some(file) = file else {
4988 return Task::ready(Ok(Default::default()));
4989 };
4990
4991 let lsp_params = match request.to_lsp_params_or_response(
4992 &file.abs_path(cx),
4993 buffer.read(cx),
4994 &language_server,
4995 cx,
4996 ) {
4997 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4998 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4999 Err(err) => {
5000 let message = format!(
5001 "{} via {} failed: {}",
5002 request.display_name(),
5003 language_server.name(),
5004 err
5005 );
5006 // rust-analyzer likes to error with this when its still loading up
5007 if !message.ends_with("content modified") {
5008 log::warn!("{message}");
5009 }
5010 return Task::ready(Err(anyhow!(message)));
5011 }
5012 };
5013
5014 let status = request.status();
5015 let request_timeout = ProjectSettings::get_global(cx)
5016 .global_lsp_settings
5017 .get_request_timeout();
5018
5019 cx.spawn(async move |this, cx| {
5020 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5021
5022 let id = lsp_request.id();
5023 let _cleanup = if status.is_some() {
5024 cx.update(|cx| {
5025 this.update(cx, |this, cx| {
5026 this.on_lsp_work_start(
5027 language_server.server_id(),
5028 ProgressToken::Number(id),
5029 LanguageServerProgress {
5030 is_disk_based_diagnostics_progress: false,
5031 is_cancellable: false,
5032 title: None,
5033 message: status.clone(),
5034 percentage: None,
5035 last_update_at: cx.background_executor().now(),
5036 },
5037 cx,
5038 );
5039 })
5040 })
5041 .log_err();
5042
5043 Some(defer(|| {
5044 cx.update(|cx| {
5045 this.update(cx, |this, cx| {
5046 this.on_lsp_work_end(
5047 language_server.server_id(),
5048 ProgressToken::Number(id),
5049 cx,
5050 );
5051 })
5052 })
5053 .log_err();
5054 }))
5055 } else {
5056 None
5057 };
5058
5059 let result = lsp_request.await.into_response();
5060
5061 let response = result.map_err(|err| {
5062 let message = format!(
5063 "{} via {} failed: {}",
5064 request.display_name(),
5065 language_server.name(),
5066 err
5067 );
5068 // rust-analyzer likes to error with this when its still loading up
5069 if !message.ends_with("content modified") {
5070 log::warn!("{message}");
5071 }
5072 anyhow::anyhow!(message)
5073 })?;
5074
5075 request
5076 .response_from_lsp(
5077 response,
5078 this.upgrade().context("no app context")?,
5079 buffer,
5080 language_server.server_id(),
5081 cx.clone(),
5082 )
5083 .await
5084 })
5085 }
5086
5087 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5088 let mut language_formatters_to_check = Vec::new();
5089 for buffer in self.buffer_store.read(cx).buffers() {
5090 let buffer = buffer.read(cx);
5091 let buffer_file = File::from_dyn(buffer.file());
5092 let buffer_language = buffer.language();
5093 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5094 if buffer_language.is_some() {
5095 language_formatters_to_check.push((
5096 buffer_file.map(|f| f.worktree_id(cx)),
5097 settings.into_owned(),
5098 ));
5099 }
5100 }
5101
5102 self.request_workspace_config_refresh();
5103
5104 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5105 prettier_store.update(cx, |prettier_store, cx| {
5106 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5107 })
5108 }
5109
5110 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5111 .global_lsp_settings
5112 .semantic_token_rules
5113 .clone();
5114 self.semantic_token_config
5115 .update_rules(new_semantic_token_rules);
5116 // Always clear cached stylizers so that changes to language-specific
5117 // semantic token rules (e.g. from extension install/uninstall) are
5118 // picked up. Stylizers are recreated lazily, so this is cheap.
5119 self.semantic_token_config.clear_stylizers();
5120
5121 let new_global_semantic_tokens_mode =
5122 all_language_settings(None, cx).defaults.semantic_tokens;
5123 if self
5124 .semantic_token_config
5125 .update_global_mode(new_global_semantic_tokens_mode)
5126 {
5127 self.restart_all_language_servers(cx);
5128 }
5129
5130 cx.notify();
5131 }
5132
5133 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5134 let buffer_store = self.buffer_store.clone();
5135 let Some(local) = self.as_local_mut() else {
5136 return;
5137 };
5138 let mut adapters = BTreeMap::default();
5139 let get_adapter = {
5140 let languages = local.languages.clone();
5141 let environment = local.environment.clone();
5142 let weak = local.weak.clone();
5143 let worktree_store = local.worktree_store.clone();
5144 let http_client = local.http_client.clone();
5145 let fs = local.fs.clone();
5146 move |worktree_id, cx: &mut App| {
5147 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5148 Some(LocalLspAdapterDelegate::new(
5149 languages.clone(),
5150 &environment,
5151 weak.clone(),
5152 &worktree,
5153 http_client.clone(),
5154 fs.clone(),
5155 cx,
5156 ))
5157 }
5158 };
5159
5160 let mut messages_to_report = Vec::new();
5161 let (new_tree, to_stop) = {
5162 let mut rebase = local.lsp_tree.rebase();
5163 let buffers = buffer_store
5164 .read(cx)
5165 .buffers()
5166 .filter_map(|buffer| {
5167 let raw_buffer = buffer.read(cx);
5168 if !local
5169 .registered_buffers
5170 .contains_key(&raw_buffer.remote_id())
5171 {
5172 return None;
5173 }
5174 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5175 let language = raw_buffer.language().cloned()?;
5176 Some((file, language, raw_buffer.remote_id()))
5177 })
5178 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5179 for (file, language, buffer_id) in buffers {
5180 let worktree_id = file.worktree_id(cx);
5181 let Some(worktree) = local
5182 .worktree_store
5183 .read(cx)
5184 .worktree_for_id(worktree_id, cx)
5185 else {
5186 continue;
5187 };
5188
5189 if let Some((_, apply)) = local.reuse_existing_language_server(
5190 rebase.server_tree(),
5191 &worktree,
5192 &language.name(),
5193 cx,
5194 ) {
5195 (apply)(rebase.server_tree());
5196 } else if let Some(lsp_delegate) = adapters
5197 .entry(worktree_id)
5198 .or_insert_with(|| get_adapter(worktree_id, cx))
5199 .clone()
5200 {
5201 let delegate =
5202 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5203 let path = file
5204 .path()
5205 .parent()
5206 .map(Arc::from)
5207 .unwrap_or_else(|| file.path().clone());
5208 let worktree_path = ProjectPath { worktree_id, path };
5209 let abs_path = file.abs_path(cx);
5210 let nodes = rebase
5211 .walk(
5212 worktree_path,
5213 language.name(),
5214 language.manifest(),
5215 delegate.clone(),
5216 cx,
5217 )
5218 .collect::<Vec<_>>();
5219 for node in nodes {
5220 let server_id = node.server_id_or_init(|disposition| {
5221 let path = &disposition.path;
5222 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5223 let key = LanguageServerSeed {
5224 worktree_id,
5225 name: disposition.server_name.clone(),
5226 settings: LanguageServerSeedSettings {
5227 binary: disposition.settings.binary.clone(),
5228 initialization_options: disposition
5229 .settings
5230 .initialization_options
5231 .clone(),
5232 },
5233 toolchain: local.toolchain_store.read(cx).active_toolchain(
5234 path.worktree_id,
5235 &path.path,
5236 language.name(),
5237 ),
5238 };
5239 local.language_server_ids.remove(&key);
5240
5241 let server_id = local.get_or_insert_language_server(
5242 &worktree,
5243 lsp_delegate.clone(),
5244 disposition,
5245 &language.name(),
5246 cx,
5247 );
5248 if let Some(state) = local.language_servers.get(&server_id)
5249 && let Ok(uri) = uri
5250 {
5251 state.add_workspace_folder(uri);
5252 };
5253 server_id
5254 });
5255
5256 if let Some(language_server_id) = server_id {
5257 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5258 language_server_id,
5259 name: node.name(),
5260 message:
5261 proto::update_language_server::Variant::RegisteredForBuffer(
5262 proto::RegisteredForBuffer {
5263 buffer_abs_path: abs_path
5264 .to_string_lossy()
5265 .into_owned(),
5266 buffer_id: buffer_id.to_proto(),
5267 },
5268 ),
5269 });
5270 }
5271 }
5272 } else {
5273 continue;
5274 }
5275 }
5276 rebase.finish()
5277 };
5278 for message in messages_to_report {
5279 cx.emit(message);
5280 }
5281 local.lsp_tree = new_tree;
5282 for (id, _) in to_stop {
5283 self.stop_local_language_server(id, cx).detach();
5284 }
5285 }
5286
5287 pub fn apply_code_action(
5288 &self,
5289 buffer_handle: Entity<Buffer>,
5290 mut action: CodeAction,
5291 push_to_history: bool,
5292 cx: &mut Context<Self>,
5293 ) -> Task<Result<ProjectTransaction>> {
5294 if let Some((upstream_client, project_id)) = self.upstream_client() {
5295 let request = proto::ApplyCodeAction {
5296 project_id,
5297 buffer_id: buffer_handle.read(cx).remote_id().into(),
5298 action: Some(Self::serialize_code_action(&action)),
5299 };
5300 let buffer_store = self.buffer_store();
5301 cx.spawn(async move |_, cx| {
5302 let response = upstream_client
5303 .request(request)
5304 .await?
5305 .transaction
5306 .context("missing transaction")?;
5307
5308 buffer_store
5309 .update(cx, |buffer_store, cx| {
5310 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5311 })
5312 .await
5313 })
5314 } else if self.mode.is_local() {
5315 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5316 let request_timeout = ProjectSettings::get_global(cx)
5317 .global_lsp_settings
5318 .get_request_timeout();
5319 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5320 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5321 }) else {
5322 return Task::ready(Ok(ProjectTransaction::default()));
5323 };
5324
5325 cx.spawn(async move |this, cx| {
5326 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5327 .await
5328 .context("resolving a code action")?;
5329 if let Some(edit) = action.lsp_action.edit()
5330 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5331 return LocalLspStore::deserialize_workspace_edit(
5332 this.upgrade().context("no app present")?,
5333 edit.clone(),
5334 push_to_history,
5335
5336 lang_server.clone(),
5337 cx,
5338 )
5339 .await;
5340 }
5341
5342 let Some(command) = action.lsp_action.command() else {
5343 return Ok(ProjectTransaction::default())
5344 };
5345
5346 let server_capabilities = lang_server.capabilities();
5347 let available_commands = server_capabilities
5348 .execute_command_provider
5349 .as_ref()
5350 .map(|options| options.commands.as_slice())
5351 .unwrap_or_default();
5352
5353 if !available_commands.contains(&command.command) {
5354 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5355 return Ok(ProjectTransaction::default())
5356 }
5357
5358 let request_timeout = cx.update(|app|
5359 ProjectSettings::get_global(app)
5360 .global_lsp_settings
5361 .get_request_timeout()
5362 );
5363
5364 this.update(cx, |this, _| {
5365 this.as_local_mut()
5366 .unwrap()
5367 .last_workspace_edits_by_language_server
5368 .remove(&lang_server.server_id());
5369 })?;
5370
5371 let _result = lang_server
5372 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5373 command: command.command.clone(),
5374 arguments: command.arguments.clone().unwrap_or_default(),
5375 ..lsp::ExecuteCommandParams::default()
5376 }, request_timeout)
5377 .await.into_response()
5378 .context("execute command")?;
5379
5380 return this.update(cx, |this, _| {
5381 this.as_local_mut()
5382 .unwrap()
5383 .last_workspace_edits_by_language_server
5384 .remove(&lang_server.server_id())
5385 .unwrap_or_default()
5386 });
5387 })
5388 } else {
5389 Task::ready(Err(anyhow!("no upstream client and not local")))
5390 }
5391 }
5392
5393 pub fn apply_code_action_kind(
5394 &mut self,
5395 buffers: HashSet<Entity<Buffer>>,
5396 kind: CodeActionKind,
5397 push_to_history: bool,
5398 cx: &mut Context<Self>,
5399 ) -> Task<anyhow::Result<ProjectTransaction>> {
5400 if self.as_local().is_some() {
5401 cx.spawn(async move |lsp_store, cx| {
5402 let buffers = buffers.into_iter().collect::<Vec<_>>();
5403 let result = LocalLspStore::execute_code_action_kind_locally(
5404 lsp_store.clone(),
5405 buffers,
5406 kind,
5407 push_to_history,
5408 cx,
5409 )
5410 .await;
5411 lsp_store.update(cx, |lsp_store, _| {
5412 lsp_store.update_last_formatting_failure(&result);
5413 })?;
5414 result
5415 })
5416 } else if let Some((client, project_id)) = self.upstream_client() {
5417 let buffer_store = self.buffer_store();
5418 cx.spawn(async move |lsp_store, cx| {
5419 let result = client
5420 .request(proto::ApplyCodeActionKind {
5421 project_id,
5422 kind: kind.as_str().to_owned(),
5423 buffer_ids: buffers
5424 .iter()
5425 .map(|buffer| {
5426 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5427 })
5428 .collect(),
5429 })
5430 .await
5431 .and_then(|result| result.transaction.context("missing transaction"));
5432 lsp_store.update(cx, |lsp_store, _| {
5433 lsp_store.update_last_formatting_failure(&result);
5434 })?;
5435
5436 let transaction_response = result?;
5437 buffer_store
5438 .update(cx, |buffer_store, cx| {
5439 buffer_store.deserialize_project_transaction(
5440 transaction_response,
5441 push_to_history,
5442 cx,
5443 )
5444 })
5445 .await
5446 })
5447 } else {
5448 Task::ready(Ok(ProjectTransaction::default()))
5449 }
5450 }
5451
5452 pub fn resolved_hint(
5453 &mut self,
5454 buffer_id: BufferId,
5455 id: InlayId,
5456 cx: &mut Context<Self>,
5457 ) -> Option<ResolvedHint> {
5458 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5459
5460 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5461 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5462 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5463 let (server_id, resolve_data) = match &hint.resolve_state {
5464 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5465 ResolveState::Resolving => {
5466 return Some(ResolvedHint::Resolving(
5467 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5468 ));
5469 }
5470 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5471 };
5472
5473 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5474 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5475 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5476 id,
5477 cx.spawn(async move |lsp_store, cx| {
5478 let resolved_hint = resolve_task.await;
5479 lsp_store
5480 .update(cx, |lsp_store, _| {
5481 if let Some(old_inlay_hint) = lsp_store
5482 .lsp_data
5483 .get_mut(&buffer_id)
5484 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5485 {
5486 match resolved_hint {
5487 Ok(resolved_hint) => {
5488 *old_inlay_hint = resolved_hint;
5489 }
5490 Err(e) => {
5491 old_inlay_hint.resolve_state =
5492 ResolveState::CanResolve(server_id, resolve_data);
5493 log::error!("Inlay hint resolve failed: {e:#}");
5494 }
5495 }
5496 }
5497 })
5498 .ok();
5499 })
5500 .shared(),
5501 );
5502 debug_assert!(
5503 previous_task.is_none(),
5504 "Did not change hint's resolve state after spawning its resolve"
5505 );
5506 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5507 None
5508 }
5509
5510 pub(crate) fn linked_edits(
5511 &mut self,
5512 buffer: &Entity<Buffer>,
5513 position: Anchor,
5514 cx: &mut Context<Self>,
5515 ) -> Task<Result<Vec<Range<Anchor>>>> {
5516 let snapshot = buffer.read(cx).snapshot();
5517 let scope = snapshot.language_scope_at(position);
5518 let Some(server_id) = self
5519 .as_local()
5520 .and_then(|local| {
5521 buffer.update(cx, |buffer, cx| {
5522 local
5523 .language_servers_for_buffer(buffer, cx)
5524 .filter(|(_, server)| {
5525 LinkedEditingRange::check_server_capabilities(server.capabilities())
5526 })
5527 .filter(|(adapter, _)| {
5528 scope
5529 .as_ref()
5530 .map(|scope| scope.language_allowed(&adapter.name))
5531 .unwrap_or(true)
5532 })
5533 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5534 .next()
5535 })
5536 })
5537 .or_else(|| {
5538 self.upstream_client()
5539 .is_some()
5540 .then_some(LanguageServerToQuery::FirstCapable)
5541 })
5542 .filter(|_| {
5543 maybe!({
5544 let language = buffer.read(cx).language_at(position)?;
5545 Some(
5546 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5547 .linked_edits,
5548 )
5549 }) == Some(true)
5550 })
5551 else {
5552 return Task::ready(Ok(Vec::new()));
5553 };
5554
5555 self.request_lsp(
5556 buffer.clone(),
5557 server_id,
5558 LinkedEditingRange { position },
5559 cx,
5560 )
5561 }
5562
5563 fn apply_on_type_formatting(
5564 &mut self,
5565 buffer: Entity<Buffer>,
5566 position: Anchor,
5567 trigger: String,
5568 cx: &mut Context<Self>,
5569 ) -> Task<Result<Option<Transaction>>> {
5570 if let Some((client, project_id)) = self.upstream_client() {
5571 if !self.check_if_capable_for_proto_request(
5572 &buffer,
5573 |capabilities| {
5574 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5575 },
5576 cx,
5577 ) {
5578 return Task::ready(Ok(None));
5579 }
5580 let request = proto::OnTypeFormatting {
5581 project_id,
5582 buffer_id: buffer.read(cx).remote_id().into(),
5583 position: Some(serialize_anchor(&position)),
5584 trigger,
5585 version: serialize_version(&buffer.read(cx).version()),
5586 };
5587 cx.background_spawn(async move {
5588 client
5589 .request(request)
5590 .await?
5591 .transaction
5592 .map(language::proto::deserialize_transaction)
5593 .transpose()
5594 })
5595 } else if let Some(local) = self.as_local_mut() {
5596 let buffer_id = buffer.read(cx).remote_id();
5597 local.buffers_being_formatted.insert(buffer_id);
5598 cx.spawn(async move |this, cx| {
5599 let _cleanup = defer({
5600 let this = this.clone();
5601 let mut cx = cx.clone();
5602 move || {
5603 this.update(&mut cx, |this, _| {
5604 if let Some(local) = this.as_local_mut() {
5605 local.buffers_being_formatted.remove(&buffer_id);
5606 }
5607 })
5608 .ok();
5609 }
5610 });
5611
5612 buffer
5613 .update(cx, |buffer, _| {
5614 buffer.wait_for_edits(Some(position.timestamp()))
5615 })
5616 .await?;
5617 this.update(cx, |this, cx| {
5618 let position = position.to_point_utf16(buffer.read(cx));
5619 this.on_type_format(buffer, position, trigger, false, cx)
5620 })?
5621 .await
5622 })
5623 } else {
5624 Task::ready(Err(anyhow!("No upstream client or local language server")))
5625 }
5626 }
5627
5628 pub fn on_type_format<T: ToPointUtf16>(
5629 &mut self,
5630 buffer: Entity<Buffer>,
5631 position: T,
5632 trigger: String,
5633 push_to_history: bool,
5634 cx: &mut Context<Self>,
5635 ) -> Task<Result<Option<Transaction>>> {
5636 let position = position.to_point_utf16(buffer.read(cx));
5637 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5638 }
5639
5640 fn on_type_format_impl(
5641 &mut self,
5642 buffer: Entity<Buffer>,
5643 position: PointUtf16,
5644 trigger: String,
5645 push_to_history: bool,
5646 cx: &mut Context<Self>,
5647 ) -> Task<Result<Option<Transaction>>> {
5648 let options = buffer.update(cx, |buffer, cx| {
5649 lsp_command::lsp_formatting_options(
5650 language_settings(
5651 buffer.language_at(position).map(|l| l.name()),
5652 buffer.file(),
5653 cx,
5654 )
5655 .as_ref(),
5656 )
5657 });
5658
5659 cx.spawn(async move |this, cx| {
5660 if let Some(waiter) =
5661 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5662 {
5663 waiter.await?;
5664 }
5665 cx.update(|cx| {
5666 this.update(cx, |this, cx| {
5667 this.request_lsp(
5668 buffer.clone(),
5669 LanguageServerToQuery::FirstCapable,
5670 OnTypeFormatting {
5671 position,
5672 trigger,
5673 options,
5674 push_to_history,
5675 },
5676 cx,
5677 )
5678 })
5679 })?
5680 .await
5681 })
5682 }
5683
5684 pub fn definitions(
5685 &mut self,
5686 buffer: &Entity<Buffer>,
5687 position: PointUtf16,
5688 cx: &mut Context<Self>,
5689 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5690 if let Some((upstream_client, project_id)) = self.upstream_client() {
5691 let request = GetDefinitions { position };
5692 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5693 return Task::ready(Ok(None));
5694 }
5695
5696 let request_timeout = ProjectSettings::get_global(cx)
5697 .global_lsp_settings
5698 .get_request_timeout();
5699
5700 let request_task = upstream_client.request_lsp(
5701 project_id,
5702 None,
5703 request_timeout,
5704 cx.background_executor().clone(),
5705 request.to_proto(project_id, buffer.read(cx)),
5706 );
5707 let buffer = buffer.clone();
5708 cx.spawn(async move |weak_lsp_store, cx| {
5709 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5710 return Ok(None);
5711 };
5712 let Some(responses) = request_task.await? else {
5713 return Ok(None);
5714 };
5715 let actions = join_all(responses.payload.into_iter().map(|response| {
5716 GetDefinitions { position }.response_from_proto(
5717 response.response,
5718 lsp_store.clone(),
5719 buffer.clone(),
5720 cx.clone(),
5721 )
5722 }))
5723 .await;
5724
5725 Ok(Some(
5726 actions
5727 .into_iter()
5728 .collect::<Result<Vec<Vec<_>>>>()?
5729 .into_iter()
5730 .flatten()
5731 .dedup()
5732 .collect(),
5733 ))
5734 })
5735 } else {
5736 let definitions_task = self.request_multiple_lsp_locally(
5737 buffer,
5738 Some(position),
5739 GetDefinitions { position },
5740 cx,
5741 );
5742 cx.background_spawn(async move {
5743 Ok(Some(
5744 definitions_task
5745 .await
5746 .into_iter()
5747 .flat_map(|(_, definitions)| definitions)
5748 .dedup()
5749 .collect(),
5750 ))
5751 })
5752 }
5753 }
5754
5755 pub fn declarations(
5756 &mut self,
5757 buffer: &Entity<Buffer>,
5758 position: PointUtf16,
5759 cx: &mut Context<Self>,
5760 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5761 if let Some((upstream_client, project_id)) = self.upstream_client() {
5762 let request = GetDeclarations { position };
5763 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5764 return Task::ready(Ok(None));
5765 }
5766 let request_timeout = ProjectSettings::get_global(cx)
5767 .global_lsp_settings
5768 .get_request_timeout();
5769 let request_task = upstream_client.request_lsp(
5770 project_id,
5771 None,
5772 request_timeout,
5773 cx.background_executor().clone(),
5774 request.to_proto(project_id, buffer.read(cx)),
5775 );
5776 let buffer = buffer.clone();
5777 cx.spawn(async move |weak_lsp_store, cx| {
5778 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5779 return Ok(None);
5780 };
5781 let Some(responses) = request_task.await? else {
5782 return Ok(None);
5783 };
5784 let actions = join_all(responses.payload.into_iter().map(|response| {
5785 GetDeclarations { position }.response_from_proto(
5786 response.response,
5787 lsp_store.clone(),
5788 buffer.clone(),
5789 cx.clone(),
5790 )
5791 }))
5792 .await;
5793
5794 Ok(Some(
5795 actions
5796 .into_iter()
5797 .collect::<Result<Vec<Vec<_>>>>()?
5798 .into_iter()
5799 .flatten()
5800 .dedup()
5801 .collect(),
5802 ))
5803 })
5804 } else {
5805 let declarations_task = self.request_multiple_lsp_locally(
5806 buffer,
5807 Some(position),
5808 GetDeclarations { position },
5809 cx,
5810 );
5811 cx.background_spawn(async move {
5812 Ok(Some(
5813 declarations_task
5814 .await
5815 .into_iter()
5816 .flat_map(|(_, declarations)| declarations)
5817 .dedup()
5818 .collect(),
5819 ))
5820 })
5821 }
5822 }
5823
5824 pub fn type_definitions(
5825 &mut self,
5826 buffer: &Entity<Buffer>,
5827 position: PointUtf16,
5828 cx: &mut Context<Self>,
5829 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5830 if let Some((upstream_client, project_id)) = self.upstream_client() {
5831 let request = GetTypeDefinitions { position };
5832 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5833 return Task::ready(Ok(None));
5834 }
5835 let request_timeout = ProjectSettings::get_global(cx)
5836 .global_lsp_settings
5837 .get_request_timeout();
5838 let request_task = upstream_client.request_lsp(
5839 project_id,
5840 None,
5841 request_timeout,
5842 cx.background_executor().clone(),
5843 request.to_proto(project_id, buffer.read(cx)),
5844 );
5845 let buffer = buffer.clone();
5846 cx.spawn(async move |weak_lsp_store, cx| {
5847 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5848 return Ok(None);
5849 };
5850 let Some(responses) = request_task.await? else {
5851 return Ok(None);
5852 };
5853 let actions = join_all(responses.payload.into_iter().map(|response| {
5854 GetTypeDefinitions { position }.response_from_proto(
5855 response.response,
5856 lsp_store.clone(),
5857 buffer.clone(),
5858 cx.clone(),
5859 )
5860 }))
5861 .await;
5862
5863 Ok(Some(
5864 actions
5865 .into_iter()
5866 .collect::<Result<Vec<Vec<_>>>>()?
5867 .into_iter()
5868 .flatten()
5869 .dedup()
5870 .collect(),
5871 ))
5872 })
5873 } else {
5874 let type_definitions_task = self.request_multiple_lsp_locally(
5875 buffer,
5876 Some(position),
5877 GetTypeDefinitions { position },
5878 cx,
5879 );
5880 cx.background_spawn(async move {
5881 Ok(Some(
5882 type_definitions_task
5883 .await
5884 .into_iter()
5885 .flat_map(|(_, type_definitions)| type_definitions)
5886 .dedup()
5887 .collect(),
5888 ))
5889 })
5890 }
5891 }
5892
5893 pub fn implementations(
5894 &mut self,
5895 buffer: &Entity<Buffer>,
5896 position: PointUtf16,
5897 cx: &mut Context<Self>,
5898 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5899 if let Some((upstream_client, project_id)) = self.upstream_client() {
5900 let request = GetImplementations { position };
5901 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5902 return Task::ready(Ok(None));
5903 }
5904
5905 let request_timeout = ProjectSettings::get_global(cx)
5906 .global_lsp_settings
5907 .get_request_timeout();
5908 let request_task = upstream_client.request_lsp(
5909 project_id,
5910 None,
5911 request_timeout,
5912 cx.background_executor().clone(),
5913 request.to_proto(project_id, buffer.read(cx)),
5914 );
5915 let buffer = buffer.clone();
5916 cx.spawn(async move |weak_lsp_store, cx| {
5917 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5918 return Ok(None);
5919 };
5920 let Some(responses) = request_task.await? else {
5921 return Ok(None);
5922 };
5923 let actions = join_all(responses.payload.into_iter().map(|response| {
5924 GetImplementations { position }.response_from_proto(
5925 response.response,
5926 lsp_store.clone(),
5927 buffer.clone(),
5928 cx.clone(),
5929 )
5930 }))
5931 .await;
5932
5933 Ok(Some(
5934 actions
5935 .into_iter()
5936 .collect::<Result<Vec<Vec<_>>>>()?
5937 .into_iter()
5938 .flatten()
5939 .dedup()
5940 .collect(),
5941 ))
5942 })
5943 } else {
5944 let implementations_task = self.request_multiple_lsp_locally(
5945 buffer,
5946 Some(position),
5947 GetImplementations { position },
5948 cx,
5949 );
5950 cx.background_spawn(async move {
5951 Ok(Some(
5952 implementations_task
5953 .await
5954 .into_iter()
5955 .flat_map(|(_, implementations)| implementations)
5956 .dedup()
5957 .collect(),
5958 ))
5959 })
5960 }
5961 }
5962
5963 pub fn references(
5964 &mut self,
5965 buffer: &Entity<Buffer>,
5966 position: PointUtf16,
5967 cx: &mut Context<Self>,
5968 ) -> Task<Result<Option<Vec<Location>>>> {
5969 if let Some((upstream_client, project_id)) = self.upstream_client() {
5970 let request = GetReferences { position };
5971 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5972 return Task::ready(Ok(None));
5973 }
5974
5975 let request_timeout = ProjectSettings::get_global(cx)
5976 .global_lsp_settings
5977 .get_request_timeout();
5978 let request_task = upstream_client.request_lsp(
5979 project_id,
5980 None,
5981 request_timeout,
5982 cx.background_executor().clone(),
5983 request.to_proto(project_id, buffer.read(cx)),
5984 );
5985 let buffer = buffer.clone();
5986 cx.spawn(async move |weak_lsp_store, cx| {
5987 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5988 return Ok(None);
5989 };
5990 let Some(responses) = request_task.await? else {
5991 return Ok(None);
5992 };
5993
5994 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5995 GetReferences { position }.response_from_proto(
5996 lsp_response.response,
5997 lsp_store.clone(),
5998 buffer.clone(),
5999 cx.clone(),
6000 )
6001 }))
6002 .await
6003 .into_iter()
6004 .collect::<Result<Vec<Vec<_>>>>()?
6005 .into_iter()
6006 .flatten()
6007 .dedup()
6008 .collect();
6009 Ok(Some(locations))
6010 })
6011 } else {
6012 let references_task = self.request_multiple_lsp_locally(
6013 buffer,
6014 Some(position),
6015 GetReferences { position },
6016 cx,
6017 );
6018 cx.background_spawn(async move {
6019 Ok(Some(
6020 references_task
6021 .await
6022 .into_iter()
6023 .flat_map(|(_, references)| references)
6024 .dedup()
6025 .collect(),
6026 ))
6027 })
6028 }
6029 }
6030
6031 pub fn code_actions(
6032 &mut self,
6033 buffer: &Entity<Buffer>,
6034 range: Range<Anchor>,
6035 kinds: Option<Vec<CodeActionKind>>,
6036 cx: &mut Context<Self>,
6037 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6038 if let Some((upstream_client, project_id)) = self.upstream_client() {
6039 let request = GetCodeActions {
6040 range: range.clone(),
6041 kinds: kinds.clone(),
6042 };
6043 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6044 return Task::ready(Ok(None));
6045 }
6046 let request_timeout = ProjectSettings::get_global(cx)
6047 .global_lsp_settings
6048 .get_request_timeout();
6049 let request_task = upstream_client.request_lsp(
6050 project_id,
6051 None,
6052 request_timeout,
6053 cx.background_executor().clone(),
6054 request.to_proto(project_id, buffer.read(cx)),
6055 );
6056 let buffer = buffer.clone();
6057 cx.spawn(async move |weak_lsp_store, cx| {
6058 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6059 return Ok(None);
6060 };
6061 let Some(responses) = request_task.await? else {
6062 return Ok(None);
6063 };
6064 let actions = join_all(responses.payload.into_iter().map(|response| {
6065 GetCodeActions {
6066 range: range.clone(),
6067 kinds: kinds.clone(),
6068 }
6069 .response_from_proto(
6070 response.response,
6071 lsp_store.clone(),
6072 buffer.clone(),
6073 cx.clone(),
6074 )
6075 }))
6076 .await;
6077
6078 Ok(Some(
6079 actions
6080 .into_iter()
6081 .collect::<Result<Vec<Vec<_>>>>()?
6082 .into_iter()
6083 .flatten()
6084 .collect(),
6085 ))
6086 })
6087 } else {
6088 let all_actions_task = self.request_multiple_lsp_locally(
6089 buffer,
6090 Some(range.start),
6091 GetCodeActions { range, kinds },
6092 cx,
6093 );
6094 cx.background_spawn(async move {
6095 Ok(Some(
6096 all_actions_task
6097 .await
6098 .into_iter()
6099 .flat_map(|(_, actions)| actions)
6100 .collect(),
6101 ))
6102 })
6103 }
6104 }
6105
6106 #[inline(never)]
6107 pub fn completions(
6108 &self,
6109 buffer: &Entity<Buffer>,
6110 position: PointUtf16,
6111 context: CompletionContext,
6112 cx: &mut Context<Self>,
6113 ) -> Task<Result<Vec<CompletionResponse>>> {
6114 let language_registry = self.languages.clone();
6115
6116 if let Some((upstream_client, project_id)) = self.upstream_client() {
6117 let snapshot = buffer.read(cx).snapshot();
6118 let offset = position.to_offset(&snapshot);
6119 let scope = snapshot.language_scope_at(offset);
6120 let capable_lsps = self.all_capable_for_proto_request(
6121 buffer,
6122 |server_name, capabilities| {
6123 capabilities.completion_provider.is_some()
6124 && scope
6125 .as_ref()
6126 .map(|scope| scope.language_allowed(server_name))
6127 .unwrap_or(true)
6128 },
6129 cx,
6130 );
6131 if capable_lsps.is_empty() {
6132 return Task::ready(Ok(Vec::new()));
6133 }
6134
6135 let language = buffer.read(cx).language().cloned();
6136
6137 let buffer = buffer.clone();
6138
6139 cx.spawn(async move |this, cx| {
6140 let requests = join_all(
6141 capable_lsps
6142 .into_iter()
6143 .map(|(id, server_name)| {
6144 let request = GetCompletions {
6145 position,
6146 context: context.clone(),
6147 server_id: Some(id),
6148 };
6149 let buffer = buffer.clone();
6150 let language = language.clone();
6151 let lsp_adapter = language.as_ref().and_then(|language| {
6152 let adapters = language_registry.lsp_adapters(&language.name());
6153 adapters
6154 .iter()
6155 .find(|adapter| adapter.name() == server_name)
6156 .or_else(|| adapters.first())
6157 .cloned()
6158 });
6159 let upstream_client = upstream_client.clone();
6160 let response = this
6161 .update(cx, |this, cx| {
6162 this.send_lsp_proto_request(
6163 buffer,
6164 upstream_client,
6165 project_id,
6166 request,
6167 cx,
6168 )
6169 })
6170 .log_err();
6171 async move {
6172 let response = response?.await.log_err()?;
6173
6174 let completions = populate_labels_for_completions(
6175 response.completions,
6176 language,
6177 lsp_adapter,
6178 )
6179 .await;
6180
6181 Some(CompletionResponse {
6182 completions,
6183 display_options: CompletionDisplayOptions::default(),
6184 is_incomplete: response.is_incomplete,
6185 })
6186 }
6187 })
6188 .collect::<Vec<_>>(),
6189 );
6190 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6191 })
6192 } else if let Some(local) = self.as_local() {
6193 let snapshot = buffer.read(cx).snapshot();
6194 let offset = position.to_offset(&snapshot);
6195 let scope = snapshot.language_scope_at(offset);
6196 let language = snapshot.language().cloned();
6197 let completion_settings = language_settings(
6198 language.as_ref().map(|language| language.name()),
6199 buffer.read(cx).file(),
6200 cx,
6201 )
6202 .completions
6203 .clone();
6204 if !completion_settings.lsp {
6205 return Task::ready(Ok(Vec::new()));
6206 }
6207
6208 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6209 local
6210 .language_servers_for_buffer(buffer, cx)
6211 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6212 .filter(|(adapter, _)| {
6213 scope
6214 .as_ref()
6215 .map(|scope| scope.language_allowed(&adapter.name))
6216 .unwrap_or(true)
6217 })
6218 .map(|(_, server)| server.server_id())
6219 .collect()
6220 });
6221
6222 let buffer = buffer.clone();
6223 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6224 let lsp_timeout = if lsp_timeout > 0 {
6225 Some(Duration::from_millis(lsp_timeout))
6226 } else {
6227 None
6228 };
6229 cx.spawn(async move |this, cx| {
6230 let mut tasks = Vec::with_capacity(server_ids.len());
6231 this.update(cx, |lsp_store, cx| {
6232 for server_id in server_ids {
6233 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6234 let lsp_timeout = lsp_timeout
6235 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6236 let mut timeout = cx.background_spawn(async move {
6237 match lsp_timeout {
6238 Some(lsp_timeout) => {
6239 lsp_timeout.await;
6240 true
6241 },
6242 None => false,
6243 }
6244 }).fuse();
6245 let mut lsp_request = lsp_store.request_lsp(
6246 buffer.clone(),
6247 LanguageServerToQuery::Other(server_id),
6248 GetCompletions {
6249 position,
6250 context: context.clone(),
6251 server_id: Some(server_id),
6252 },
6253 cx,
6254 ).fuse();
6255 let new_task = cx.background_spawn(async move {
6256 select_biased! {
6257 response = lsp_request => anyhow::Ok(Some(response?)),
6258 timeout_happened = timeout => {
6259 if timeout_happened {
6260 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6261 Ok(None)
6262 } else {
6263 let completions = lsp_request.await?;
6264 Ok(Some(completions))
6265 }
6266 },
6267 }
6268 });
6269 tasks.push((lsp_adapter, new_task));
6270 }
6271 })?;
6272
6273 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6274 let completion_response = task.await.ok()??;
6275 let completions = populate_labels_for_completions(
6276 completion_response.completions,
6277 language.clone(),
6278 lsp_adapter,
6279 )
6280 .await;
6281 Some(CompletionResponse {
6282 completions,
6283 display_options: CompletionDisplayOptions::default(),
6284 is_incomplete: completion_response.is_incomplete,
6285 })
6286 });
6287
6288 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6289
6290 Ok(responses.into_iter().flatten().collect())
6291 })
6292 } else {
6293 Task::ready(Err(anyhow!("No upstream client or local language server")))
6294 }
6295 }
6296
6297 pub fn resolve_completions(
6298 &self,
6299 buffer: Entity<Buffer>,
6300 completion_indices: Vec<usize>,
6301 completions: Rc<RefCell<Box<[Completion]>>>,
6302 cx: &mut Context<Self>,
6303 ) -> Task<Result<bool>> {
6304 let client = self.upstream_client();
6305 let buffer_id = buffer.read(cx).remote_id();
6306 let buffer_snapshot = buffer.read(cx).snapshot();
6307
6308 if !self.check_if_capable_for_proto_request(
6309 &buffer,
6310 GetCompletions::can_resolve_completions,
6311 cx,
6312 ) {
6313 return Task::ready(Ok(false));
6314 }
6315 cx.spawn(async move |lsp_store, cx| {
6316 let request_timeout = cx.update(|app| {
6317 ProjectSettings::get_global(app)
6318 .global_lsp_settings
6319 .get_request_timeout()
6320 });
6321
6322 let mut did_resolve = false;
6323 if let Some((client, project_id)) = client {
6324 for completion_index in completion_indices {
6325 let server_id = {
6326 let completion = &completions.borrow()[completion_index];
6327 completion.source.server_id()
6328 };
6329 if let Some(server_id) = server_id {
6330 if Self::resolve_completion_remote(
6331 project_id,
6332 server_id,
6333 buffer_id,
6334 completions.clone(),
6335 completion_index,
6336 client.clone(),
6337 )
6338 .await
6339 .log_err()
6340 .is_some()
6341 {
6342 did_resolve = true;
6343 }
6344 } else {
6345 resolve_word_completion(
6346 &buffer_snapshot,
6347 &mut completions.borrow_mut()[completion_index],
6348 );
6349 }
6350 }
6351 } else {
6352 for completion_index in completion_indices {
6353 let server_id = {
6354 let completion = &completions.borrow()[completion_index];
6355 completion.source.server_id()
6356 };
6357 if let Some(server_id) = server_id {
6358 let server_and_adapter = lsp_store
6359 .read_with(cx, |lsp_store, _| {
6360 let server = lsp_store.language_server_for_id(server_id)?;
6361 let adapter =
6362 lsp_store.language_server_adapter_for_id(server.server_id())?;
6363 Some((server, adapter))
6364 })
6365 .ok()
6366 .flatten();
6367 let Some((server, adapter)) = server_and_adapter else {
6368 continue;
6369 };
6370
6371 let resolved = Self::resolve_completion_local(
6372 server,
6373 completions.clone(),
6374 completion_index,
6375 request_timeout,
6376 )
6377 .await
6378 .log_err()
6379 .is_some();
6380 if resolved {
6381 Self::regenerate_completion_labels(
6382 adapter,
6383 &buffer_snapshot,
6384 completions.clone(),
6385 completion_index,
6386 )
6387 .await
6388 .log_err();
6389 did_resolve = true;
6390 }
6391 } else {
6392 resolve_word_completion(
6393 &buffer_snapshot,
6394 &mut completions.borrow_mut()[completion_index],
6395 );
6396 }
6397 }
6398 }
6399
6400 Ok(did_resolve)
6401 })
6402 }
6403
6404 async fn resolve_completion_local(
6405 server: Arc<lsp::LanguageServer>,
6406 completions: Rc<RefCell<Box<[Completion]>>>,
6407 completion_index: usize,
6408 request_timeout: Duration,
6409 ) -> Result<()> {
6410 let server_id = server.server_id();
6411 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6412 return Ok(());
6413 }
6414
6415 let request = {
6416 let completion = &completions.borrow()[completion_index];
6417 match &completion.source {
6418 CompletionSource::Lsp {
6419 lsp_completion,
6420 resolved,
6421 server_id: completion_server_id,
6422 ..
6423 } => {
6424 if *resolved {
6425 return Ok(());
6426 }
6427 anyhow::ensure!(
6428 server_id == *completion_server_id,
6429 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6430 );
6431 server.request::<lsp::request::ResolveCompletionItem>(
6432 *lsp_completion.clone(),
6433 request_timeout,
6434 )
6435 }
6436 CompletionSource::BufferWord { .. }
6437 | CompletionSource::Dap { .. }
6438 | CompletionSource::Custom => {
6439 return Ok(());
6440 }
6441 }
6442 };
6443 let resolved_completion = request
6444 .await
6445 .into_response()
6446 .context("resolve completion")?;
6447
6448 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6449 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6450
6451 let mut completions = completions.borrow_mut();
6452 let completion = &mut completions[completion_index];
6453 if let CompletionSource::Lsp {
6454 lsp_completion,
6455 resolved,
6456 server_id: completion_server_id,
6457 ..
6458 } = &mut completion.source
6459 {
6460 if *resolved {
6461 return Ok(());
6462 }
6463 anyhow::ensure!(
6464 server_id == *completion_server_id,
6465 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6466 );
6467 **lsp_completion = resolved_completion;
6468 *resolved = true;
6469 }
6470 Ok(())
6471 }
6472
6473 async fn regenerate_completion_labels(
6474 adapter: Arc<CachedLspAdapter>,
6475 snapshot: &BufferSnapshot,
6476 completions: Rc<RefCell<Box<[Completion]>>>,
6477 completion_index: usize,
6478 ) -> Result<()> {
6479 let completion_item = completions.borrow()[completion_index]
6480 .source
6481 .lsp_completion(true)
6482 .map(Cow::into_owned);
6483 if let Some(lsp_documentation) = completion_item
6484 .as_ref()
6485 .and_then(|completion_item| completion_item.documentation.clone())
6486 {
6487 let mut completions = completions.borrow_mut();
6488 let completion = &mut completions[completion_index];
6489 completion.documentation = Some(lsp_documentation.into());
6490 } else {
6491 let mut completions = completions.borrow_mut();
6492 let completion = &mut completions[completion_index];
6493 completion.documentation = Some(CompletionDocumentation::Undocumented);
6494 }
6495
6496 let mut new_label = match completion_item {
6497 Some(completion_item) => {
6498 // Some language servers always return `detail` lazily via resolve, regardless of
6499 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6500 // See: https://github.com/yioneko/vtsls/issues/213
6501 let language = snapshot.language();
6502 match language {
6503 Some(language) => {
6504 adapter
6505 .labels_for_completions(
6506 std::slice::from_ref(&completion_item),
6507 language,
6508 )
6509 .await?
6510 }
6511 None => Vec::new(),
6512 }
6513 .pop()
6514 .flatten()
6515 .unwrap_or_else(|| {
6516 CodeLabel::fallback_for_completion(
6517 &completion_item,
6518 language.map(|language| language.as_ref()),
6519 )
6520 })
6521 }
6522 None => CodeLabel::plain(
6523 completions.borrow()[completion_index].new_text.clone(),
6524 None,
6525 ),
6526 };
6527 ensure_uniform_list_compatible_label(&mut new_label);
6528
6529 let mut completions = completions.borrow_mut();
6530 let completion = &mut completions[completion_index];
6531 if completion.label.filter_text() == new_label.filter_text() {
6532 completion.label = new_label;
6533 } else {
6534 log::error!(
6535 "Resolved completion changed display label from {} to {}. \
6536 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6537 completion.label.text(),
6538 new_label.text(),
6539 completion.label.filter_text(),
6540 new_label.filter_text()
6541 );
6542 }
6543
6544 Ok(())
6545 }
6546
6547 async fn resolve_completion_remote(
6548 project_id: u64,
6549 server_id: LanguageServerId,
6550 buffer_id: BufferId,
6551 completions: Rc<RefCell<Box<[Completion]>>>,
6552 completion_index: usize,
6553 client: AnyProtoClient,
6554 ) -> Result<()> {
6555 let lsp_completion = {
6556 let completion = &completions.borrow()[completion_index];
6557 match &completion.source {
6558 CompletionSource::Lsp {
6559 lsp_completion,
6560 resolved,
6561 server_id: completion_server_id,
6562 ..
6563 } => {
6564 anyhow::ensure!(
6565 server_id == *completion_server_id,
6566 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6567 );
6568 if *resolved {
6569 return Ok(());
6570 }
6571 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6572 }
6573 CompletionSource::Custom
6574 | CompletionSource::Dap { .. }
6575 | CompletionSource::BufferWord { .. } => {
6576 return Ok(());
6577 }
6578 }
6579 };
6580 let request = proto::ResolveCompletionDocumentation {
6581 project_id,
6582 language_server_id: server_id.0 as u64,
6583 lsp_completion,
6584 buffer_id: buffer_id.into(),
6585 };
6586
6587 let response = client
6588 .request(request)
6589 .await
6590 .context("completion documentation resolve proto request")?;
6591 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6592
6593 let documentation = if response.documentation.is_empty() {
6594 CompletionDocumentation::Undocumented
6595 } else if response.documentation_is_markdown {
6596 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6597 } else if response.documentation.lines().count() <= 1 {
6598 CompletionDocumentation::SingleLine(response.documentation.into())
6599 } else {
6600 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6601 };
6602
6603 let mut completions = completions.borrow_mut();
6604 let completion = &mut completions[completion_index];
6605 completion.documentation = Some(documentation);
6606 if let CompletionSource::Lsp {
6607 insert_range,
6608 lsp_completion,
6609 resolved,
6610 server_id: completion_server_id,
6611 lsp_defaults: _,
6612 } = &mut completion.source
6613 {
6614 let completion_insert_range = response
6615 .old_insert_start
6616 .and_then(deserialize_anchor)
6617 .zip(response.old_insert_end.and_then(deserialize_anchor));
6618 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6619
6620 if *resolved {
6621 return Ok(());
6622 }
6623 anyhow::ensure!(
6624 server_id == *completion_server_id,
6625 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6626 );
6627 **lsp_completion = resolved_lsp_completion;
6628 *resolved = true;
6629 }
6630
6631 let replace_range = response
6632 .old_replace_start
6633 .and_then(deserialize_anchor)
6634 .zip(response.old_replace_end.and_then(deserialize_anchor));
6635 if let Some((old_replace_start, old_replace_end)) = replace_range
6636 && !response.new_text.is_empty()
6637 {
6638 completion.new_text = response.new_text;
6639 completion.replace_range = old_replace_start..old_replace_end;
6640 }
6641
6642 Ok(())
6643 }
6644
6645 pub fn apply_additional_edits_for_completion(
6646 &self,
6647 buffer_handle: Entity<Buffer>,
6648 completions: Rc<RefCell<Box<[Completion]>>>,
6649 completion_index: usize,
6650 push_to_history: bool,
6651 all_commit_ranges: Vec<Range<language::Anchor>>,
6652 cx: &mut Context<Self>,
6653 ) -> Task<Result<Option<Transaction>>> {
6654 if let Some((client, project_id)) = self.upstream_client() {
6655 let buffer = buffer_handle.read(cx);
6656 let buffer_id = buffer.remote_id();
6657 cx.spawn(async move |_, cx| {
6658 let request = {
6659 let completion = completions.borrow()[completion_index].clone();
6660 proto::ApplyCompletionAdditionalEdits {
6661 project_id,
6662 buffer_id: buffer_id.into(),
6663 completion: Some(Self::serialize_completion(&CoreCompletion {
6664 replace_range: completion.replace_range,
6665 new_text: completion.new_text,
6666 source: completion.source,
6667 })),
6668 all_commit_ranges: all_commit_ranges
6669 .iter()
6670 .cloned()
6671 .map(language::proto::serialize_anchor_range)
6672 .collect(),
6673 }
6674 };
6675
6676 let Some(transaction) = client.request(request).await?.transaction else {
6677 return Ok(None);
6678 };
6679
6680 let transaction = language::proto::deserialize_transaction(transaction)?;
6681 buffer_handle
6682 .update(cx, |buffer, _| {
6683 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6684 })
6685 .await?;
6686 if push_to_history {
6687 buffer_handle.update(cx, |buffer, _| {
6688 buffer.push_transaction(transaction.clone(), Instant::now());
6689 buffer.finalize_last_transaction();
6690 });
6691 }
6692 Ok(Some(transaction))
6693 })
6694 } else {
6695 let request_timeout = ProjectSettings::get_global(cx)
6696 .global_lsp_settings
6697 .get_request_timeout();
6698
6699 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6700 let completion = &completions.borrow()[completion_index];
6701 let server_id = completion.source.server_id()?;
6702 Some(
6703 self.language_server_for_local_buffer(buffer, server_id, cx)?
6704 .1
6705 .clone(),
6706 )
6707 }) else {
6708 return Task::ready(Ok(None));
6709 };
6710
6711 cx.spawn(async move |this, cx| {
6712 Self::resolve_completion_local(
6713 server.clone(),
6714 completions.clone(),
6715 completion_index,
6716 request_timeout,
6717 )
6718 .await
6719 .context("resolving completion")?;
6720 let completion = completions.borrow()[completion_index].clone();
6721 let additional_text_edits = completion
6722 .source
6723 .lsp_completion(true)
6724 .as_ref()
6725 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6726 if let Some(edits) = additional_text_edits {
6727 let edits = this
6728 .update(cx, |this, cx| {
6729 this.as_local_mut().unwrap().edits_from_lsp(
6730 &buffer_handle,
6731 edits,
6732 server.server_id(),
6733 None,
6734 cx,
6735 )
6736 })?
6737 .await?;
6738
6739 buffer_handle.update(cx, |buffer, cx| {
6740 buffer.finalize_last_transaction();
6741 buffer.start_transaction();
6742
6743 for (range, text) in edits {
6744 let primary = &completion.replace_range;
6745
6746 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6747 // and the primary completion is just an insertion (empty range), then this is likely
6748 // an auto-import scenario and should not be considered overlapping
6749 // https://github.com/zed-industries/zed/issues/26136
6750 let is_file_start_auto_import = {
6751 let snapshot = buffer.snapshot();
6752 let primary_start_point = primary.start.to_point(&snapshot);
6753 let range_start_point = range.start.to_point(&snapshot);
6754
6755 let result = primary_start_point.row == 0
6756 && primary_start_point.column == 0
6757 && range_start_point.row == 0
6758 && range_start_point.column == 0;
6759
6760 result
6761 };
6762
6763 let has_overlap = if is_file_start_auto_import {
6764 false
6765 } else {
6766 all_commit_ranges.iter().any(|commit_range| {
6767 let start_within =
6768 commit_range.start.cmp(&range.start, buffer).is_le()
6769 && commit_range.end.cmp(&range.start, buffer).is_ge();
6770 let end_within =
6771 range.start.cmp(&commit_range.end, buffer).is_le()
6772 && range.end.cmp(&commit_range.end, buffer).is_ge();
6773 start_within || end_within
6774 })
6775 };
6776
6777 //Skip additional edits which overlap with the primary completion edit
6778 //https://github.com/zed-industries/zed/pull/1871
6779 if !has_overlap {
6780 buffer.edit([(range, text)], None, cx);
6781 }
6782 }
6783
6784 let transaction = if buffer.end_transaction(cx).is_some() {
6785 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6786 if !push_to_history {
6787 buffer.forget_transaction(transaction.id);
6788 }
6789 Some(transaction)
6790 } else {
6791 None
6792 };
6793 Ok(transaction)
6794 })
6795 } else {
6796 Ok(None)
6797 }
6798 })
6799 }
6800 }
6801
6802 pub fn pull_diagnostics(
6803 &mut self,
6804 buffer: Entity<Buffer>,
6805 cx: &mut Context<Self>,
6806 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6807 let buffer_id = buffer.read(cx).remote_id();
6808
6809 if let Some((client, upstream_project_id)) = self.upstream_client() {
6810 let mut suitable_capabilities = None;
6811 // Are we capable for proto request?
6812 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6813 &buffer,
6814 |capabilities| {
6815 if let Some(caps) = &capabilities.diagnostic_provider {
6816 suitable_capabilities = Some(caps.clone());
6817 true
6818 } else {
6819 false
6820 }
6821 },
6822 cx,
6823 );
6824 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6825 let Some(dynamic_caps) = suitable_capabilities else {
6826 return Task::ready(Ok(None));
6827 };
6828 assert!(any_server_has_diagnostics_provider);
6829
6830 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6831 let request = GetDocumentDiagnostics {
6832 previous_result_id: None,
6833 identifier,
6834 registration_id: None,
6835 };
6836 let request_timeout = ProjectSettings::get_global(cx)
6837 .global_lsp_settings
6838 .get_request_timeout();
6839 let request_task = client.request_lsp(
6840 upstream_project_id,
6841 None,
6842 request_timeout,
6843 cx.background_executor().clone(),
6844 request.to_proto(upstream_project_id, buffer.read(cx)),
6845 );
6846 cx.background_spawn(async move {
6847 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6848 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6849 // Do not attempt to further process the dummy responses here.
6850 let _response = request_task.await?;
6851 Ok(None)
6852 })
6853 } else {
6854 let servers = buffer.update(cx, |buffer, cx| {
6855 self.running_language_servers_for_local_buffer(buffer, cx)
6856 .map(|(_, server)| server.clone())
6857 .collect::<Vec<_>>()
6858 });
6859
6860 let pull_diagnostics = servers
6861 .into_iter()
6862 .flat_map(|server| {
6863 let result = maybe!({
6864 let local = self.as_local()?;
6865 let server_id = server.server_id();
6866 let providers_with_identifiers = local
6867 .language_server_dynamic_registrations
6868 .get(&server_id)
6869 .into_iter()
6870 .flat_map(|registrations| registrations.diagnostics.clone())
6871 .collect::<Vec<_>>();
6872 Some(
6873 providers_with_identifiers
6874 .into_iter()
6875 .map(|(registration_id, dynamic_caps)| {
6876 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6877 let registration_id = registration_id.map(SharedString::from);
6878 let result_id = self.result_id_for_buffer_pull(
6879 server_id,
6880 buffer_id,
6881 ®istration_id,
6882 cx,
6883 );
6884 self.request_lsp(
6885 buffer.clone(),
6886 LanguageServerToQuery::Other(server_id),
6887 GetDocumentDiagnostics {
6888 previous_result_id: result_id,
6889 registration_id,
6890 identifier,
6891 },
6892 cx,
6893 )
6894 })
6895 .collect::<Vec<_>>(),
6896 )
6897 });
6898
6899 result.unwrap_or_default()
6900 })
6901 .collect::<Vec<_>>();
6902
6903 cx.background_spawn(async move {
6904 let mut responses = Vec::new();
6905 for diagnostics in join_all(pull_diagnostics).await {
6906 responses.extend(diagnostics?);
6907 }
6908 Ok(Some(responses))
6909 })
6910 }
6911 }
6912
6913 pub fn applicable_inlay_chunks(
6914 &mut self,
6915 buffer: &Entity<Buffer>,
6916 ranges: &[Range<text::Anchor>],
6917 cx: &mut Context<Self>,
6918 ) -> Vec<Range<BufferRow>> {
6919 let buffer_snapshot = buffer.read(cx).snapshot();
6920 let ranges = ranges
6921 .iter()
6922 .map(|range| range.to_point(&buffer_snapshot))
6923 .collect::<Vec<_>>();
6924
6925 self.latest_lsp_data(buffer, cx)
6926 .inlay_hints
6927 .applicable_chunks(ranges.as_slice())
6928 .map(|chunk| chunk.row_range())
6929 .collect()
6930 }
6931
6932 pub fn invalidate_inlay_hints<'a>(
6933 &'a mut self,
6934 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6935 ) {
6936 for buffer_id in for_buffers {
6937 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6938 lsp_data.inlay_hints.clear();
6939 }
6940 }
6941 }
6942
6943 pub fn inlay_hints(
6944 &mut self,
6945 invalidate: InvalidationStrategy,
6946 buffer: Entity<Buffer>,
6947 ranges: Vec<Range<text::Anchor>>,
6948 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6949 cx: &mut Context<Self>,
6950 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6951 let next_hint_id = self.next_hint_id.clone();
6952 let lsp_data = self.latest_lsp_data(&buffer, cx);
6953 let query_version = lsp_data.buffer_version.clone();
6954 let mut lsp_refresh_requested = false;
6955 let for_server = if let InvalidationStrategy::RefreshRequested {
6956 server_id,
6957 request_id,
6958 } = invalidate
6959 {
6960 let invalidated = lsp_data
6961 .inlay_hints
6962 .invalidate_for_server_refresh(server_id, request_id);
6963 lsp_refresh_requested = invalidated;
6964 Some(server_id)
6965 } else {
6966 None
6967 };
6968 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6969 let known_chunks = known_chunks
6970 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6971 .map(|(_, known_chunks)| known_chunks)
6972 .unwrap_or_default();
6973
6974 let buffer_snapshot = buffer.read(cx).snapshot();
6975 let ranges = ranges
6976 .iter()
6977 .map(|range| range.to_point(&buffer_snapshot))
6978 .collect::<Vec<_>>();
6979
6980 let mut hint_fetch_tasks = Vec::new();
6981 let mut cached_inlay_hints = None;
6982 let mut ranges_to_query = None;
6983 let applicable_chunks = existing_inlay_hints
6984 .applicable_chunks(ranges.as_slice())
6985 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6986 .collect::<Vec<_>>();
6987 if applicable_chunks.is_empty() {
6988 return HashMap::default();
6989 }
6990
6991 for row_chunk in applicable_chunks {
6992 match (
6993 existing_inlay_hints
6994 .cached_hints(&row_chunk)
6995 .filter(|_| !lsp_refresh_requested)
6996 .cloned(),
6997 existing_inlay_hints
6998 .fetched_hints(&row_chunk)
6999 .as_ref()
7000 .filter(|_| !lsp_refresh_requested)
7001 .cloned(),
7002 ) {
7003 (None, None) => {
7004 let chunk_range = row_chunk.anchor_range();
7005 ranges_to_query
7006 .get_or_insert_with(Vec::new)
7007 .push((row_chunk, chunk_range));
7008 }
7009 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7010 (Some(cached_hints), None) => {
7011 for (server_id, cached_hints) in cached_hints {
7012 if for_server.is_none_or(|for_server| for_server == server_id) {
7013 cached_inlay_hints
7014 .get_or_insert_with(HashMap::default)
7015 .entry(row_chunk.row_range())
7016 .or_insert_with(HashMap::default)
7017 .entry(server_id)
7018 .or_insert_with(Vec::new)
7019 .extend(cached_hints);
7020 }
7021 }
7022 }
7023 (Some(cached_hints), Some(fetched_hints)) => {
7024 hint_fetch_tasks.push((row_chunk, fetched_hints));
7025 for (server_id, cached_hints) in cached_hints {
7026 if for_server.is_none_or(|for_server| for_server == server_id) {
7027 cached_inlay_hints
7028 .get_or_insert_with(HashMap::default)
7029 .entry(row_chunk.row_range())
7030 .or_insert_with(HashMap::default)
7031 .entry(server_id)
7032 .or_insert_with(Vec::new)
7033 .extend(cached_hints);
7034 }
7035 }
7036 }
7037 }
7038 }
7039
7040 if hint_fetch_tasks.is_empty()
7041 && ranges_to_query
7042 .as_ref()
7043 .is_none_or(|ranges| ranges.is_empty())
7044 && let Some(cached_inlay_hints) = cached_inlay_hints
7045 {
7046 cached_inlay_hints
7047 .into_iter()
7048 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7049 .collect()
7050 } else {
7051 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7052 // When a server refresh was requested, other servers' cached hints
7053 // are unaffected by the refresh and must be included in the result.
7054 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7055 // removes all visible hints but only adds back the requesting
7056 // server's new hints, permanently losing other servers' hints.
7057 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7058 lsp_data
7059 .inlay_hints
7060 .cached_hints(&chunk)
7061 .cloned()
7062 .unwrap_or_default()
7063 } else {
7064 HashMap::default()
7065 };
7066
7067 let next_hint_id = next_hint_id.clone();
7068 let buffer = buffer.clone();
7069 let query_version = query_version.clone();
7070 let new_inlay_hints = cx
7071 .spawn(async move |lsp_store, cx| {
7072 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7073 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7074 })?;
7075 new_fetch_task
7076 .await
7077 .and_then(|new_hints_by_server| {
7078 lsp_store.update(cx, |lsp_store, cx| {
7079 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7080 let update_cache = lsp_data.buffer_version == query_version;
7081 if new_hints_by_server.is_empty() {
7082 if update_cache {
7083 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7084 }
7085 other_servers_cached
7086 } else {
7087 let mut result = other_servers_cached;
7088 for (server_id, new_hints) in new_hints_by_server {
7089 let new_hints = new_hints
7090 .into_iter()
7091 .map(|new_hint| {
7092 (
7093 InlayId::Hint(next_hint_id.fetch_add(
7094 1,
7095 atomic::Ordering::AcqRel,
7096 )),
7097 new_hint,
7098 )
7099 })
7100 .collect::<Vec<_>>();
7101 if update_cache {
7102 lsp_data.inlay_hints.insert_new_hints(
7103 chunk,
7104 server_id,
7105 new_hints.clone(),
7106 );
7107 }
7108 result.insert(server_id, new_hints);
7109 }
7110 result
7111 }
7112 })
7113 })
7114 .map_err(Arc::new)
7115 })
7116 .shared();
7117
7118 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7119 *fetch_task = Some(new_inlay_hints.clone());
7120 hint_fetch_tasks.push((chunk, new_inlay_hints));
7121 }
7122
7123 cached_inlay_hints
7124 .unwrap_or_default()
7125 .into_iter()
7126 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7127 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7128 (
7129 chunk.row_range(),
7130 cx.spawn(async move |_, _| {
7131 hints_fetch.await.map_err(|e| {
7132 if e.error_code() != ErrorCode::Internal {
7133 anyhow!(e.error_code())
7134 } else {
7135 anyhow!("{e:#}")
7136 }
7137 })
7138 }),
7139 )
7140 }))
7141 .collect()
7142 }
7143 }
7144
7145 fn fetch_inlay_hints(
7146 &mut self,
7147 for_server: Option<LanguageServerId>,
7148 buffer: &Entity<Buffer>,
7149 range: Range<Anchor>,
7150 cx: &mut Context<Self>,
7151 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7152 let request = InlayHints {
7153 range: range.clone(),
7154 };
7155 if let Some((upstream_client, project_id)) = self.upstream_client() {
7156 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7157 return Task::ready(Ok(HashMap::default()));
7158 }
7159 let request_timeout = ProjectSettings::get_global(cx)
7160 .global_lsp_settings
7161 .get_request_timeout();
7162 let request_task = upstream_client.request_lsp(
7163 project_id,
7164 for_server.map(|id| id.to_proto()),
7165 request_timeout,
7166 cx.background_executor().clone(),
7167 request.to_proto(project_id, buffer.read(cx)),
7168 );
7169 let buffer = buffer.clone();
7170 cx.spawn(async move |weak_lsp_store, cx| {
7171 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7172 return Ok(HashMap::default());
7173 };
7174 let Some(responses) = request_task.await? else {
7175 return Ok(HashMap::default());
7176 };
7177
7178 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7179 let lsp_store = lsp_store.clone();
7180 let buffer = buffer.clone();
7181 let cx = cx.clone();
7182 let request = request.clone();
7183 async move {
7184 (
7185 LanguageServerId::from_proto(response.server_id),
7186 request
7187 .response_from_proto(response.response, lsp_store, buffer, cx)
7188 .await,
7189 )
7190 }
7191 }))
7192 .await;
7193
7194 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7195 let mut has_errors = false;
7196 let inlay_hints = inlay_hints
7197 .into_iter()
7198 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7199 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7200 Err(e) => {
7201 has_errors = true;
7202 log::error!("{e:#}");
7203 None
7204 }
7205 })
7206 .map(|(server_id, mut new_hints)| {
7207 new_hints.retain(|hint| {
7208 hint.position.is_valid(&buffer_snapshot)
7209 && range.start.is_valid(&buffer_snapshot)
7210 && range.end.is_valid(&buffer_snapshot)
7211 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7212 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7213 });
7214 (server_id, new_hints)
7215 })
7216 .collect::<HashMap<_, _>>();
7217 anyhow::ensure!(
7218 !has_errors || !inlay_hints.is_empty(),
7219 "Failed to fetch inlay hints"
7220 );
7221 Ok(inlay_hints)
7222 })
7223 } else {
7224 let inlay_hints_task = match for_server {
7225 Some(server_id) => {
7226 let server_task = self.request_lsp(
7227 buffer.clone(),
7228 LanguageServerToQuery::Other(server_id),
7229 request,
7230 cx,
7231 );
7232 cx.background_spawn(async move {
7233 let mut responses = Vec::new();
7234 match server_task.await {
7235 Ok(response) => responses.push((server_id, response)),
7236 // rust-analyzer likes to error with this when its still loading up
7237 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7238 Err(e) => log::error!(
7239 "Error handling response for inlay hints request: {e:#}"
7240 ),
7241 }
7242 responses
7243 })
7244 }
7245 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7246 };
7247 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7248 cx.background_spawn(async move {
7249 Ok(inlay_hints_task
7250 .await
7251 .into_iter()
7252 .map(|(server_id, mut new_hints)| {
7253 new_hints.retain(|hint| {
7254 hint.position.is_valid(&buffer_snapshot)
7255 && range.start.is_valid(&buffer_snapshot)
7256 && range.end.is_valid(&buffer_snapshot)
7257 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7258 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7259 });
7260 (server_id, new_hints)
7261 })
7262 .collect())
7263 })
7264 }
7265 }
7266
7267 fn diagnostic_registration_exists(
7268 &self,
7269 server_id: LanguageServerId,
7270 registration_id: &Option<SharedString>,
7271 ) -> bool {
7272 let Some(local) = self.as_local() else {
7273 return false;
7274 };
7275 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7276 else {
7277 return false;
7278 };
7279 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7280 registrations.diagnostics.contains_key(®istration_key)
7281 }
7282
7283 pub fn pull_diagnostics_for_buffer(
7284 &mut self,
7285 buffer: Entity<Buffer>,
7286 cx: &mut Context<Self>,
7287 ) -> Task<anyhow::Result<()>> {
7288 let diagnostics = self.pull_diagnostics(buffer, cx);
7289 cx.spawn(async move |lsp_store, cx| {
7290 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7291 return Ok(());
7292 };
7293 lsp_store.update(cx, |lsp_store, cx| {
7294 if lsp_store.as_local().is_none() {
7295 return;
7296 }
7297
7298 let mut unchanged_buffers = HashMap::default();
7299 let server_diagnostics_updates = diagnostics
7300 .into_iter()
7301 .filter_map(|diagnostics_set| match diagnostics_set {
7302 LspPullDiagnostics::Response {
7303 server_id,
7304 uri,
7305 diagnostics,
7306 registration_id,
7307 } => Some((server_id, uri, diagnostics, registration_id)),
7308 LspPullDiagnostics::Default => None,
7309 })
7310 .filter(|(server_id, _, _, registration_id)| {
7311 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7312 })
7313 .fold(
7314 HashMap::default(),
7315 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7316 let (result_id, diagnostics) = match diagnostics {
7317 PulledDiagnostics::Unchanged { result_id } => {
7318 unchanged_buffers
7319 .entry(new_registration_id.clone())
7320 .or_insert_with(HashSet::default)
7321 .insert(uri.clone());
7322 (Some(result_id), Vec::new())
7323 }
7324 PulledDiagnostics::Changed {
7325 result_id,
7326 diagnostics,
7327 } => (result_id, diagnostics),
7328 };
7329 let disk_based_sources = Cow::Owned(
7330 lsp_store
7331 .language_server_adapter_for_id(server_id)
7332 .as_ref()
7333 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7334 .unwrap_or(&[])
7335 .to_vec(),
7336 );
7337 acc.entry(server_id)
7338 .or_insert_with(HashMap::default)
7339 .entry(new_registration_id.clone())
7340 .or_insert_with(Vec::new)
7341 .push(DocumentDiagnosticsUpdate {
7342 server_id,
7343 diagnostics: lsp::PublishDiagnosticsParams {
7344 uri,
7345 diagnostics,
7346 version: None,
7347 },
7348 result_id: result_id.map(SharedString::new),
7349 disk_based_sources,
7350 registration_id: new_registration_id,
7351 });
7352 acc
7353 },
7354 );
7355
7356 for diagnostic_updates in server_diagnostics_updates.into_values() {
7357 for (registration_id, diagnostic_updates) in diagnostic_updates {
7358 lsp_store
7359 .merge_lsp_diagnostics(
7360 DiagnosticSourceKind::Pulled,
7361 diagnostic_updates,
7362 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7363 DiagnosticSourceKind::Pulled => {
7364 old_diagnostic.registration_id != registration_id
7365 || unchanged_buffers
7366 .get(&old_diagnostic.registration_id)
7367 .is_some_and(|unchanged_buffers| {
7368 unchanged_buffers.contains(&document_uri)
7369 })
7370 }
7371 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7372 true
7373 }
7374 },
7375 cx,
7376 )
7377 .log_err();
7378 }
7379 }
7380 })
7381 })
7382 }
7383
7384 pub fn signature_help<T: ToPointUtf16>(
7385 &mut self,
7386 buffer: &Entity<Buffer>,
7387 position: T,
7388 cx: &mut Context<Self>,
7389 ) -> Task<Option<Vec<SignatureHelp>>> {
7390 let position = position.to_point_utf16(buffer.read(cx));
7391
7392 if let Some((client, upstream_project_id)) = self.upstream_client() {
7393 let request = GetSignatureHelp { position };
7394 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7395 return Task::ready(None);
7396 }
7397 let request_timeout = ProjectSettings::get_global(cx)
7398 .global_lsp_settings
7399 .get_request_timeout();
7400 let request_task = client.request_lsp(
7401 upstream_project_id,
7402 None,
7403 request_timeout,
7404 cx.background_executor().clone(),
7405 request.to_proto(upstream_project_id, buffer.read(cx)),
7406 );
7407 let buffer = buffer.clone();
7408 cx.spawn(async move |weak_lsp_store, cx| {
7409 let lsp_store = weak_lsp_store.upgrade()?;
7410 let signatures = join_all(
7411 request_task
7412 .await
7413 .log_err()
7414 .flatten()
7415 .map(|response| response.payload)
7416 .unwrap_or_default()
7417 .into_iter()
7418 .map(|response| {
7419 let response = GetSignatureHelp { position }.response_from_proto(
7420 response.response,
7421 lsp_store.clone(),
7422 buffer.clone(),
7423 cx.clone(),
7424 );
7425 async move { response.await.log_err().flatten() }
7426 }),
7427 )
7428 .await
7429 .into_iter()
7430 .flatten()
7431 .collect();
7432 Some(signatures)
7433 })
7434 } else {
7435 let all_actions_task = self.request_multiple_lsp_locally(
7436 buffer,
7437 Some(position),
7438 GetSignatureHelp { position },
7439 cx,
7440 );
7441 cx.background_spawn(async move {
7442 Some(
7443 all_actions_task
7444 .await
7445 .into_iter()
7446 .flat_map(|(_, actions)| actions)
7447 .collect::<Vec<_>>(),
7448 )
7449 })
7450 }
7451 }
7452
7453 pub fn hover(
7454 &mut self,
7455 buffer: &Entity<Buffer>,
7456 position: PointUtf16,
7457 cx: &mut Context<Self>,
7458 ) -> Task<Option<Vec<Hover>>> {
7459 if let Some((client, upstream_project_id)) = self.upstream_client() {
7460 let request = GetHover { position };
7461 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7462 return Task::ready(None);
7463 }
7464 let request_timeout = ProjectSettings::get_global(cx)
7465 .global_lsp_settings
7466 .get_request_timeout();
7467 let request_task = client.request_lsp(
7468 upstream_project_id,
7469 None,
7470 request_timeout,
7471 cx.background_executor().clone(),
7472 request.to_proto(upstream_project_id, buffer.read(cx)),
7473 );
7474 let buffer = buffer.clone();
7475 cx.spawn(async move |weak_lsp_store, cx| {
7476 let lsp_store = weak_lsp_store.upgrade()?;
7477 let hovers = join_all(
7478 request_task
7479 .await
7480 .log_err()
7481 .flatten()
7482 .map(|response| response.payload)
7483 .unwrap_or_default()
7484 .into_iter()
7485 .map(|response| {
7486 let response = GetHover { position }.response_from_proto(
7487 response.response,
7488 lsp_store.clone(),
7489 buffer.clone(),
7490 cx.clone(),
7491 );
7492 async move {
7493 response
7494 .await
7495 .log_err()
7496 .flatten()
7497 .and_then(remove_empty_hover_blocks)
7498 }
7499 }),
7500 )
7501 .await
7502 .into_iter()
7503 .flatten()
7504 .collect();
7505 Some(hovers)
7506 })
7507 } else {
7508 let all_actions_task = self.request_multiple_lsp_locally(
7509 buffer,
7510 Some(position),
7511 GetHover { position },
7512 cx,
7513 );
7514 cx.background_spawn(async move {
7515 Some(
7516 all_actions_task
7517 .await
7518 .into_iter()
7519 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7520 .collect::<Vec<Hover>>(),
7521 )
7522 })
7523 }
7524 }
7525
7526 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7527 let language_registry = self.languages.clone();
7528
7529 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7530 let request = upstream_client.request(proto::GetProjectSymbols {
7531 project_id: *project_id,
7532 query: query.to_string(),
7533 });
7534 cx.foreground_executor().spawn(async move {
7535 let response = request.await?;
7536 let mut symbols = Vec::new();
7537 let core_symbols = response
7538 .symbols
7539 .into_iter()
7540 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7541 .collect::<Vec<_>>();
7542 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7543 .await;
7544 Ok(symbols)
7545 })
7546 } else if let Some(local) = self.as_local() {
7547 struct WorkspaceSymbolsResult {
7548 server_id: LanguageServerId,
7549 lsp_adapter: Arc<CachedLspAdapter>,
7550 worktree: WeakEntity<Worktree>,
7551 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7552 }
7553
7554 let mut requests = Vec::new();
7555 let mut requested_servers = BTreeSet::new();
7556 let request_timeout = ProjectSettings::get_global(cx)
7557 .global_lsp_settings
7558 .get_request_timeout();
7559
7560 for (seed, state) in local.language_server_ids.iter() {
7561 let Some(worktree_handle) = self
7562 .worktree_store
7563 .read(cx)
7564 .worktree_for_id(seed.worktree_id, cx)
7565 else {
7566 continue;
7567 };
7568
7569 let worktree = worktree_handle.read(cx);
7570 if !worktree.is_visible() {
7571 continue;
7572 }
7573
7574 if !requested_servers.insert(state.id) {
7575 continue;
7576 }
7577
7578 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7579 Some(LanguageServerState::Running {
7580 adapter, server, ..
7581 }) => (adapter.clone(), server),
7582
7583 _ => continue,
7584 };
7585
7586 let supports_workspace_symbol_request =
7587 match server.capabilities().workspace_symbol_provider {
7588 Some(OneOf::Left(supported)) => supported,
7589 Some(OneOf::Right(_)) => true,
7590 None => false,
7591 };
7592
7593 if !supports_workspace_symbol_request {
7594 continue;
7595 }
7596
7597 let worktree_handle = worktree_handle.clone();
7598 let server_id = server.server_id();
7599 requests.push(
7600 server
7601 .request::<lsp::request::WorkspaceSymbolRequest>(
7602 lsp::WorkspaceSymbolParams {
7603 query: query.to_string(),
7604 ..Default::default()
7605 },
7606 request_timeout,
7607 )
7608 .map(move |response| {
7609 let lsp_symbols = response
7610 .into_response()
7611 .context("workspace symbols request")
7612 .log_err()
7613 .flatten()
7614 .map(|symbol_response| match symbol_response {
7615 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7616 flat_responses
7617 .into_iter()
7618 .map(|lsp_symbol| {
7619 (
7620 lsp_symbol.name,
7621 lsp_symbol.kind,
7622 lsp_symbol.location,
7623 lsp_symbol.container_name,
7624 )
7625 })
7626 .collect::<Vec<_>>()
7627 }
7628 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7629 nested_responses
7630 .into_iter()
7631 .filter_map(|lsp_symbol| {
7632 let location = match lsp_symbol.location {
7633 OneOf::Left(location) => location,
7634 OneOf::Right(_) => {
7635 log::error!(
7636 "Unexpected: client capabilities \
7637 forbid symbol resolutions in \
7638 workspace.symbol.resolveSupport"
7639 );
7640 return None;
7641 }
7642 };
7643 Some((
7644 lsp_symbol.name,
7645 lsp_symbol.kind,
7646 location,
7647 lsp_symbol.container_name,
7648 ))
7649 })
7650 .collect::<Vec<_>>()
7651 }
7652 })
7653 .unwrap_or_default();
7654
7655 WorkspaceSymbolsResult {
7656 server_id,
7657 lsp_adapter,
7658 worktree: worktree_handle.downgrade(),
7659 lsp_symbols,
7660 }
7661 }),
7662 );
7663 }
7664
7665 cx.spawn(async move |this, cx| {
7666 let responses = futures::future::join_all(requests).await;
7667 let this = match this.upgrade() {
7668 Some(this) => this,
7669 None => return Ok(Vec::new()),
7670 };
7671
7672 let mut symbols = Vec::new();
7673 for result in responses {
7674 let core_symbols = this.update(cx, |this, cx| {
7675 result
7676 .lsp_symbols
7677 .into_iter()
7678 .filter_map(
7679 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7680 let abs_path = symbol_location.uri.to_file_path().ok()?;
7681 let source_worktree = result.worktree.upgrade()?;
7682 let source_worktree_id = source_worktree.read(cx).id();
7683
7684 let path = if let Some((tree, rel_path)) =
7685 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7686 {
7687 let worktree_id = tree.read(cx).id();
7688 SymbolLocation::InProject(ProjectPath {
7689 worktree_id,
7690 path: rel_path,
7691 })
7692 } else {
7693 SymbolLocation::OutsideProject {
7694 signature: this.symbol_signature(&abs_path),
7695 abs_path: abs_path.into(),
7696 }
7697 };
7698
7699 Some(CoreSymbol {
7700 source_language_server_id: result.server_id,
7701 language_server_name: result.lsp_adapter.name.clone(),
7702 source_worktree_id,
7703 path,
7704 kind: symbol_kind,
7705 name: collapse_newlines(&symbol_name, "↵ "),
7706 range: range_from_lsp(symbol_location.range),
7707 container_name: container_name
7708 .map(|c| collapse_newlines(&c, "↵ ")),
7709 })
7710 },
7711 )
7712 .collect::<Vec<_>>()
7713 });
7714
7715 populate_labels_for_symbols(
7716 core_symbols,
7717 &language_registry,
7718 Some(result.lsp_adapter),
7719 &mut symbols,
7720 )
7721 .await;
7722 }
7723
7724 Ok(symbols)
7725 })
7726 } else {
7727 Task::ready(Err(anyhow!("No upstream client or local language server")))
7728 }
7729 }
7730
7731 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7732 let mut summary = DiagnosticSummary::default();
7733 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7734 summary.error_count += path_summary.error_count;
7735 summary.warning_count += path_summary.warning_count;
7736 }
7737 summary
7738 }
7739
7740 /// Returns the diagnostic summary for a specific project path.
7741 pub fn diagnostic_summary_for_path(
7742 &self,
7743 project_path: &ProjectPath,
7744 _: &App,
7745 ) -> DiagnosticSummary {
7746 if let Some(summaries) = self
7747 .diagnostic_summaries
7748 .get(&project_path.worktree_id)
7749 .and_then(|map| map.get(&project_path.path))
7750 {
7751 let (error_count, warning_count) = summaries.iter().fold(
7752 (0, 0),
7753 |(error_count, warning_count), (_language_server_id, summary)| {
7754 (
7755 error_count + summary.error_count,
7756 warning_count + summary.warning_count,
7757 )
7758 },
7759 );
7760
7761 DiagnosticSummary {
7762 error_count,
7763 warning_count,
7764 }
7765 } else {
7766 DiagnosticSummary::default()
7767 }
7768 }
7769
7770 pub fn diagnostic_summaries<'a>(
7771 &'a self,
7772 include_ignored: bool,
7773 cx: &'a App,
7774 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7775 self.worktree_store
7776 .read(cx)
7777 .visible_worktrees(cx)
7778 .filter_map(|worktree| {
7779 let worktree = worktree.read(cx);
7780 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7781 })
7782 .flat_map(move |(worktree, summaries)| {
7783 let worktree_id = worktree.id();
7784 summaries
7785 .iter()
7786 .filter(move |(path, _)| {
7787 include_ignored
7788 || worktree
7789 .entry_for_path(path.as_ref())
7790 .is_some_and(|entry| !entry.is_ignored)
7791 })
7792 .flat_map(move |(path, summaries)| {
7793 summaries.iter().map(move |(server_id, summary)| {
7794 (
7795 ProjectPath {
7796 worktree_id,
7797 path: path.clone(),
7798 },
7799 *server_id,
7800 *summary,
7801 )
7802 })
7803 })
7804 })
7805 }
7806
7807 pub fn on_buffer_edited(
7808 &mut self,
7809 buffer: Entity<Buffer>,
7810 cx: &mut Context<Self>,
7811 ) -> Option<()> {
7812 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7813 Some(
7814 self.as_local()?
7815 .language_servers_for_buffer(buffer, cx)
7816 .map(|i| i.1.clone())
7817 .collect(),
7818 )
7819 })?;
7820
7821 let buffer = buffer.read(cx);
7822 let file = File::from_dyn(buffer.file())?;
7823 let abs_path = file.as_local()?.abs_path(cx);
7824 let uri = lsp::Uri::from_file_path(&abs_path)
7825 .ok()
7826 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7827 .log_err()?;
7828 let next_snapshot = buffer.text_snapshot();
7829 for language_server in language_servers {
7830 let language_server = language_server.clone();
7831
7832 let buffer_snapshots = self
7833 .as_local_mut()?
7834 .buffer_snapshots
7835 .get_mut(&buffer.remote_id())
7836 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7837 let previous_snapshot = buffer_snapshots.last()?;
7838
7839 let build_incremental_change = || {
7840 buffer
7841 .edits_since::<Dimensions<PointUtf16, usize>>(
7842 previous_snapshot.snapshot.version(),
7843 )
7844 .map(|edit| {
7845 let edit_start = edit.new.start.0;
7846 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7847 let new_text = next_snapshot
7848 .text_for_range(edit.new.start.1..edit.new.end.1)
7849 .collect();
7850 lsp::TextDocumentContentChangeEvent {
7851 range: Some(lsp::Range::new(
7852 point_to_lsp(edit_start),
7853 point_to_lsp(edit_end),
7854 )),
7855 range_length: None,
7856 text: new_text,
7857 }
7858 })
7859 .collect()
7860 };
7861
7862 let document_sync_kind = language_server
7863 .capabilities()
7864 .text_document_sync
7865 .as_ref()
7866 .and_then(|sync| match sync {
7867 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7868 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7869 });
7870
7871 let content_changes: Vec<_> = match document_sync_kind {
7872 Some(lsp::TextDocumentSyncKind::FULL) => {
7873 vec![lsp::TextDocumentContentChangeEvent {
7874 range: None,
7875 range_length: None,
7876 text: next_snapshot.text(),
7877 }]
7878 }
7879 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7880 _ => {
7881 #[cfg(any(test, feature = "test-support"))]
7882 {
7883 build_incremental_change()
7884 }
7885
7886 #[cfg(not(any(test, feature = "test-support")))]
7887 {
7888 continue;
7889 }
7890 }
7891 };
7892
7893 let next_version = previous_snapshot.version + 1;
7894 buffer_snapshots.push(LspBufferSnapshot {
7895 version: next_version,
7896 snapshot: next_snapshot.clone(),
7897 });
7898
7899 language_server
7900 .notify::<lsp::notification::DidChangeTextDocument>(
7901 lsp::DidChangeTextDocumentParams {
7902 text_document: lsp::VersionedTextDocumentIdentifier::new(
7903 uri.clone(),
7904 next_version,
7905 ),
7906 content_changes,
7907 },
7908 )
7909 .ok();
7910 self.pull_workspace_diagnostics(language_server.server_id());
7911 }
7912
7913 None
7914 }
7915
7916 pub fn on_buffer_saved(
7917 &mut self,
7918 buffer: Entity<Buffer>,
7919 cx: &mut Context<Self>,
7920 ) -> Option<()> {
7921 let file = File::from_dyn(buffer.read(cx).file())?;
7922 let worktree_id = file.worktree_id(cx);
7923 let abs_path = file.as_local()?.abs_path(cx);
7924 let text_document = lsp::TextDocumentIdentifier {
7925 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7926 };
7927 let local = self.as_local()?;
7928
7929 for server in local.language_servers_for_worktree(worktree_id) {
7930 if let Some(include_text) = include_text(server.as_ref()) {
7931 let text = if include_text {
7932 Some(buffer.read(cx).text())
7933 } else {
7934 None
7935 };
7936 server
7937 .notify::<lsp::notification::DidSaveTextDocument>(
7938 lsp::DidSaveTextDocumentParams {
7939 text_document: text_document.clone(),
7940 text,
7941 },
7942 )
7943 .ok();
7944 }
7945 }
7946
7947 let language_servers = buffer.update(cx, |buffer, cx| {
7948 local.language_server_ids_for_buffer(buffer, cx)
7949 });
7950 for language_server_id in language_servers {
7951 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7952 }
7953
7954 None
7955 }
7956
7957 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7958 maybe!(async move {
7959 let mut refreshed_servers = HashSet::default();
7960 let servers = lsp_store
7961 .update(cx, |lsp_store, cx| {
7962 let local = lsp_store.as_local()?;
7963
7964 let servers = local
7965 .language_server_ids
7966 .iter()
7967 .filter_map(|(seed, state)| {
7968 let worktree = lsp_store
7969 .worktree_store
7970 .read(cx)
7971 .worktree_for_id(seed.worktree_id, cx);
7972 let delegate: Arc<dyn LspAdapterDelegate> =
7973 worktree.map(|worktree| {
7974 LocalLspAdapterDelegate::new(
7975 local.languages.clone(),
7976 &local.environment,
7977 cx.weak_entity(),
7978 &worktree,
7979 local.http_client.clone(),
7980 local.fs.clone(),
7981 cx,
7982 )
7983 })?;
7984 let server_id = state.id;
7985
7986 let states = local.language_servers.get(&server_id)?;
7987
7988 match states {
7989 LanguageServerState::Starting { .. } => None,
7990 LanguageServerState::Running {
7991 adapter, server, ..
7992 } => {
7993 let adapter = adapter.clone();
7994 let server = server.clone();
7995 refreshed_servers.insert(server.name());
7996 let toolchain = seed.toolchain.clone();
7997 Some(cx.spawn(async move |_, cx| {
7998 let settings =
7999 LocalLspStore::workspace_configuration_for_adapter(
8000 adapter.adapter.clone(),
8001 &delegate,
8002 toolchain,
8003 None,
8004 cx,
8005 )
8006 .await
8007 .ok()?;
8008 server
8009 .notify::<lsp::notification::DidChangeConfiguration>(
8010 lsp::DidChangeConfigurationParams { settings },
8011 )
8012 .ok()?;
8013 Some(())
8014 }))
8015 }
8016 }
8017 })
8018 .collect::<Vec<_>>();
8019
8020 Some(servers)
8021 })
8022 .ok()
8023 .flatten()?;
8024
8025 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8026 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8027 // to stop and unregister its language server wrapper.
8028 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8029 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8030 let _: Vec<Option<()>> = join_all(servers).await;
8031
8032 Some(())
8033 })
8034 .await;
8035 }
8036
8037 fn maintain_workspace_config(
8038 external_refresh_requests: watch::Receiver<()>,
8039 cx: &mut Context<Self>,
8040 ) -> Task<Result<()>> {
8041 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8042 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8043
8044 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8045 *settings_changed_tx.borrow_mut() = ();
8046 });
8047
8048 let mut joint_future =
8049 futures::stream::select(settings_changed_rx, external_refresh_requests);
8050 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8051 // - 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).
8052 // - 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.
8053 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8054 // - 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,
8055 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8056 cx.spawn(async move |this, cx| {
8057 while let Some(()) = joint_future.next().await {
8058 this.update(cx, |this, cx| {
8059 this.refresh_server_tree(cx);
8060 })
8061 .ok();
8062
8063 Self::refresh_workspace_configurations(&this, cx).await;
8064 }
8065
8066 drop(settings_observation);
8067 anyhow::Ok(())
8068 })
8069 }
8070
8071 pub fn running_language_servers_for_local_buffer<'a>(
8072 &'a self,
8073 buffer: &Buffer,
8074 cx: &mut App,
8075 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8076 let local = self.as_local();
8077 let language_server_ids = local
8078 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8079 .unwrap_or_default();
8080
8081 language_server_ids
8082 .into_iter()
8083 .filter_map(
8084 move |server_id| match local?.language_servers.get(&server_id)? {
8085 LanguageServerState::Running {
8086 adapter, server, ..
8087 } => Some((adapter, server)),
8088 _ => None,
8089 },
8090 )
8091 }
8092
8093 pub fn language_servers_for_local_buffer(
8094 &self,
8095 buffer: &Buffer,
8096 cx: &mut App,
8097 ) -> Vec<LanguageServerId> {
8098 let local = self.as_local();
8099 local
8100 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8101 .unwrap_or_default()
8102 }
8103
8104 pub fn language_server_for_local_buffer<'a>(
8105 &'a self,
8106 buffer: &'a Buffer,
8107 server_id: LanguageServerId,
8108 cx: &'a mut App,
8109 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8110 self.as_local()?
8111 .language_servers_for_buffer(buffer, cx)
8112 .find(|(_, s)| s.server_id() == server_id)
8113 }
8114
8115 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8116 self.diagnostic_summaries.remove(&id_to_remove);
8117 if let Some(local) = self.as_local_mut() {
8118 let to_remove = local.remove_worktree(id_to_remove, cx);
8119 for server in to_remove {
8120 self.language_server_statuses.remove(&server);
8121 }
8122 }
8123 }
8124
8125 pub fn shared(
8126 &mut self,
8127 project_id: u64,
8128 downstream_client: AnyProtoClient,
8129 _: &mut Context<Self>,
8130 ) {
8131 self.downstream_client = Some((downstream_client.clone(), project_id));
8132
8133 for (server_id, status) in &self.language_server_statuses {
8134 if let Some(server) = self.language_server_for_id(*server_id) {
8135 downstream_client
8136 .send(proto::StartLanguageServer {
8137 project_id,
8138 server: Some(proto::LanguageServer {
8139 id: server_id.to_proto(),
8140 name: status.name.to_string(),
8141 worktree_id: status.worktree.map(|id| id.to_proto()),
8142 }),
8143 capabilities: serde_json::to_string(&server.capabilities())
8144 .expect("serializing server LSP capabilities"),
8145 })
8146 .log_err();
8147 }
8148 }
8149 }
8150
8151 pub fn disconnected_from_host(&mut self) {
8152 self.downstream_client.take();
8153 }
8154
8155 pub fn disconnected_from_ssh_remote(&mut self) {
8156 if let LspStoreMode::Remote(RemoteLspStore {
8157 upstream_client, ..
8158 }) = &mut self.mode
8159 {
8160 upstream_client.take();
8161 }
8162 }
8163
8164 pub(crate) fn set_language_server_statuses_from_proto(
8165 &mut self,
8166 project: WeakEntity<Project>,
8167 language_servers: Vec<proto::LanguageServer>,
8168 server_capabilities: Vec<String>,
8169 cx: &mut Context<Self>,
8170 ) {
8171 let lsp_logs = cx
8172 .try_global::<GlobalLogStore>()
8173 .map(|lsp_store| lsp_store.0.clone());
8174
8175 self.language_server_statuses = language_servers
8176 .into_iter()
8177 .zip(server_capabilities)
8178 .map(|(server, server_capabilities)| {
8179 let server_id = LanguageServerId(server.id as usize);
8180 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8181 self.lsp_server_capabilities
8182 .insert(server_id, server_capabilities);
8183 }
8184
8185 let name = LanguageServerName::from_proto(server.name);
8186 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8187
8188 if let Some(lsp_logs) = &lsp_logs {
8189 lsp_logs.update(cx, |lsp_logs, cx| {
8190 lsp_logs.add_language_server(
8191 // Only remote clients get their language servers set from proto
8192 LanguageServerKind::Remote {
8193 project: project.clone(),
8194 },
8195 server_id,
8196 Some(name.clone()),
8197 worktree,
8198 None,
8199 cx,
8200 );
8201 });
8202 }
8203
8204 (
8205 server_id,
8206 LanguageServerStatus {
8207 name,
8208 server_version: None,
8209 server_readable_version: None,
8210 pending_work: Default::default(),
8211 has_pending_diagnostic_updates: false,
8212 progress_tokens: Default::default(),
8213 worktree,
8214 binary: None,
8215 configuration: None,
8216 workspace_folders: BTreeSet::new(),
8217 process_id: None,
8218 },
8219 )
8220 })
8221 .collect();
8222 }
8223
8224 #[cfg(feature = "test-support")]
8225 pub fn update_diagnostic_entries(
8226 &mut self,
8227 server_id: LanguageServerId,
8228 abs_path: PathBuf,
8229 result_id: Option<SharedString>,
8230 version: Option<i32>,
8231 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8232 cx: &mut Context<Self>,
8233 ) -> anyhow::Result<()> {
8234 self.merge_diagnostic_entries(
8235 vec![DocumentDiagnosticsUpdate {
8236 diagnostics: DocumentDiagnostics {
8237 diagnostics,
8238 document_abs_path: abs_path,
8239 version,
8240 },
8241 result_id,
8242 server_id,
8243 disk_based_sources: Cow::Borrowed(&[]),
8244 registration_id: None,
8245 }],
8246 |_, _, _| false,
8247 cx,
8248 )?;
8249 Ok(())
8250 }
8251
8252 pub fn merge_diagnostic_entries<'a>(
8253 &mut self,
8254 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8255 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8256 cx: &mut Context<Self>,
8257 ) -> anyhow::Result<()> {
8258 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8259 let mut updated_diagnostics_paths = HashMap::default();
8260 for mut update in diagnostic_updates {
8261 let abs_path = &update.diagnostics.document_abs_path;
8262 let server_id = update.server_id;
8263 let Some((worktree, relative_path)) =
8264 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8265 else {
8266 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8267 return Ok(());
8268 };
8269
8270 let worktree_id = worktree.read(cx).id();
8271 let project_path = ProjectPath {
8272 worktree_id,
8273 path: relative_path,
8274 };
8275
8276 let document_uri = lsp::Uri::from_file_path(abs_path)
8277 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8278 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8279 let snapshot = buffer_handle.read(cx).snapshot();
8280 let buffer = buffer_handle.read(cx);
8281 let reused_diagnostics = buffer
8282 .buffer_diagnostics(Some(server_id))
8283 .iter()
8284 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8285 .map(|v| {
8286 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8287 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8288 DiagnosticEntry {
8289 range: start..end,
8290 diagnostic: v.diagnostic.clone(),
8291 }
8292 })
8293 .collect::<Vec<_>>();
8294
8295 self.as_local_mut()
8296 .context("cannot merge diagnostics on a remote LspStore")?
8297 .update_buffer_diagnostics(
8298 &buffer_handle,
8299 server_id,
8300 Some(update.registration_id),
8301 update.result_id,
8302 update.diagnostics.version,
8303 update.diagnostics.diagnostics.clone(),
8304 reused_diagnostics.clone(),
8305 cx,
8306 )?;
8307
8308 update.diagnostics.diagnostics.extend(reused_diagnostics);
8309 } else if let Some(local) = self.as_local() {
8310 let reused_diagnostics = local
8311 .diagnostics
8312 .get(&worktree_id)
8313 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8314 .and_then(|diagnostics_by_server_id| {
8315 diagnostics_by_server_id
8316 .binary_search_by_key(&server_id, |e| e.0)
8317 .ok()
8318 .map(|ix| &diagnostics_by_server_id[ix].1)
8319 })
8320 .into_iter()
8321 .flatten()
8322 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8323
8324 update
8325 .diagnostics
8326 .diagnostics
8327 .extend(reused_diagnostics.cloned());
8328 }
8329
8330 let updated = worktree.update(cx, |worktree, cx| {
8331 self.update_worktree_diagnostics(
8332 worktree.id(),
8333 server_id,
8334 project_path.path.clone(),
8335 update.diagnostics.diagnostics,
8336 cx,
8337 )
8338 })?;
8339 match updated {
8340 ControlFlow::Continue(new_summary) => {
8341 if let Some((project_id, new_summary)) = new_summary {
8342 match &mut diagnostics_summary {
8343 Some(diagnostics_summary) => {
8344 diagnostics_summary
8345 .more_summaries
8346 .push(proto::DiagnosticSummary {
8347 path: project_path.path.as_ref().to_proto(),
8348 language_server_id: server_id.0 as u64,
8349 error_count: new_summary.error_count,
8350 warning_count: new_summary.warning_count,
8351 })
8352 }
8353 None => {
8354 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8355 project_id,
8356 worktree_id: worktree_id.to_proto(),
8357 summary: Some(proto::DiagnosticSummary {
8358 path: project_path.path.as_ref().to_proto(),
8359 language_server_id: server_id.0 as u64,
8360 error_count: new_summary.error_count,
8361 warning_count: new_summary.warning_count,
8362 }),
8363 more_summaries: Vec::new(),
8364 })
8365 }
8366 }
8367 }
8368 updated_diagnostics_paths
8369 .entry(server_id)
8370 .or_insert_with(Vec::new)
8371 .push(project_path);
8372 }
8373 ControlFlow::Break(()) => {}
8374 }
8375 }
8376
8377 if let Some((diagnostics_summary, (downstream_client, _))) =
8378 diagnostics_summary.zip(self.downstream_client.as_ref())
8379 {
8380 downstream_client.send(diagnostics_summary).log_err();
8381 }
8382 for (server_id, paths) in updated_diagnostics_paths {
8383 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8384 }
8385 Ok(())
8386 }
8387
8388 fn update_worktree_diagnostics(
8389 &mut self,
8390 worktree_id: WorktreeId,
8391 server_id: LanguageServerId,
8392 path_in_worktree: Arc<RelPath>,
8393 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8394 _: &mut Context<Worktree>,
8395 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8396 let local = match &mut self.mode {
8397 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8398 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8399 };
8400
8401 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8402 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8403 let summaries_by_server_id = summaries_for_tree
8404 .entry(path_in_worktree.clone())
8405 .or_default();
8406
8407 let old_summary = summaries_by_server_id
8408 .remove(&server_id)
8409 .unwrap_or_default();
8410
8411 let new_summary = DiagnosticSummary::new(&diagnostics);
8412 if diagnostics.is_empty() {
8413 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8414 {
8415 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8416 diagnostics_by_server_id.remove(ix);
8417 }
8418 if diagnostics_by_server_id.is_empty() {
8419 diagnostics_for_tree.remove(&path_in_worktree);
8420 }
8421 }
8422 } else {
8423 summaries_by_server_id.insert(server_id, new_summary);
8424 let diagnostics_by_server_id = diagnostics_for_tree
8425 .entry(path_in_worktree.clone())
8426 .or_default();
8427 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8428 Ok(ix) => {
8429 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8430 }
8431 Err(ix) => {
8432 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8433 }
8434 }
8435 }
8436
8437 if !old_summary.is_empty() || !new_summary.is_empty() {
8438 if let Some((_, project_id)) = &self.downstream_client {
8439 Ok(ControlFlow::Continue(Some((
8440 *project_id,
8441 proto::DiagnosticSummary {
8442 path: path_in_worktree.to_proto(),
8443 language_server_id: server_id.0 as u64,
8444 error_count: new_summary.error_count as u32,
8445 warning_count: new_summary.warning_count as u32,
8446 },
8447 ))))
8448 } else {
8449 Ok(ControlFlow::Continue(None))
8450 }
8451 } else {
8452 Ok(ControlFlow::Break(()))
8453 }
8454 }
8455
8456 pub fn open_buffer_for_symbol(
8457 &mut self,
8458 symbol: &Symbol,
8459 cx: &mut Context<Self>,
8460 ) -> Task<Result<Entity<Buffer>>> {
8461 if let Some((client, project_id)) = self.upstream_client() {
8462 let request = client.request(proto::OpenBufferForSymbol {
8463 project_id,
8464 symbol: Some(Self::serialize_symbol(symbol)),
8465 });
8466 cx.spawn(async move |this, cx| {
8467 let response = request.await?;
8468 let buffer_id = BufferId::new(response.buffer_id)?;
8469 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8470 .await
8471 })
8472 } else if let Some(local) = self.as_local() {
8473 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8474 seed.worktree_id == symbol.source_worktree_id
8475 && state.id == symbol.source_language_server_id
8476 && symbol.language_server_name == seed.name
8477 });
8478 if !is_valid {
8479 return Task::ready(Err(anyhow!(
8480 "language server for worktree and language not found"
8481 )));
8482 };
8483
8484 let symbol_abs_path = match &symbol.path {
8485 SymbolLocation::InProject(project_path) => self
8486 .worktree_store
8487 .read(cx)
8488 .absolutize(&project_path, cx)
8489 .context("no such worktree"),
8490 SymbolLocation::OutsideProject {
8491 abs_path,
8492 signature: _,
8493 } => Ok(abs_path.to_path_buf()),
8494 };
8495 let symbol_abs_path = match symbol_abs_path {
8496 Ok(abs_path) => abs_path,
8497 Err(err) => return Task::ready(Err(err)),
8498 };
8499 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8500 uri
8501 } else {
8502 return Task::ready(Err(anyhow!("invalid symbol path")));
8503 };
8504
8505 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8506 } else {
8507 Task::ready(Err(anyhow!("no upstream client or local store")))
8508 }
8509 }
8510
8511 pub(crate) fn open_local_buffer_via_lsp(
8512 &mut self,
8513 abs_path: lsp::Uri,
8514 language_server_id: LanguageServerId,
8515 cx: &mut Context<Self>,
8516 ) -> Task<Result<Entity<Buffer>>> {
8517 let path_style = self.worktree_store.read(cx).path_style();
8518 cx.spawn(async move |lsp_store, cx| {
8519 // Escape percent-encoded string.
8520 let current_scheme = abs_path.scheme().to_owned();
8521 // Uri is immutable, so we can't modify the scheme
8522
8523 let abs_path = abs_path
8524 .to_file_path_ext(path_style)
8525 .map_err(|()| anyhow!("can't convert URI to path"))?;
8526 let p = abs_path.clone();
8527 let yarn_worktree = lsp_store
8528 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8529 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8530 cx.spawn(async move |this, cx| {
8531 let t = this
8532 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8533 .ok()?;
8534 t.await
8535 })
8536 }),
8537 None => Task::ready(None),
8538 })?
8539 .await;
8540 let (worktree_root_target, known_relative_path) =
8541 if let Some((zip_root, relative_path)) = yarn_worktree {
8542 (zip_root, Some(relative_path))
8543 } else {
8544 (Arc::<Path>::from(abs_path.as_path()), None)
8545 };
8546 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8547 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8548 worktree_store.find_worktree(&worktree_root_target, cx)
8549 })
8550 })?;
8551 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8552 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8553 (result.0, relative_path, None)
8554 } else {
8555 let worktree = lsp_store
8556 .update(cx, |lsp_store, cx| {
8557 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8558 worktree_store.create_worktree(&worktree_root_target, false, cx)
8559 })
8560 })?
8561 .await?;
8562 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8563 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8564 lsp_store
8565 .update(cx, |lsp_store, cx| {
8566 if let Some(local) = lsp_store.as_local_mut() {
8567 local.register_language_server_for_invisible_worktree(
8568 &worktree,
8569 language_server_id,
8570 cx,
8571 )
8572 }
8573 match lsp_store.language_server_statuses.get(&language_server_id) {
8574 Some(status) => status.worktree,
8575 None => None,
8576 }
8577 })
8578 .ok()
8579 .flatten()
8580 .zip(Some(worktree_root.clone()))
8581 } else {
8582 None
8583 };
8584 let relative_path = if let Some(known_path) = known_relative_path {
8585 known_path
8586 } else {
8587 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8588 .into_arc()
8589 };
8590 (worktree, relative_path, source_ws)
8591 };
8592 let project_path = ProjectPath {
8593 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8594 path: relative_path,
8595 };
8596 let buffer = lsp_store
8597 .update(cx, |lsp_store, cx| {
8598 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8599 buffer_store.open_buffer(project_path, cx)
8600 })
8601 })?
8602 .await?;
8603 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8604 if let Some((source_ws, worktree_root)) = source_ws {
8605 buffer.update(cx, |buffer, cx| {
8606 let settings = WorktreeSettings::get(
8607 Some(
8608 (&ProjectPath {
8609 worktree_id: source_ws,
8610 path: Arc::from(RelPath::empty()),
8611 })
8612 .into(),
8613 ),
8614 cx,
8615 );
8616 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8617 if is_read_only {
8618 buffer.set_capability(Capability::ReadOnly, cx);
8619 }
8620 });
8621 }
8622 Ok(buffer)
8623 })
8624 }
8625
8626 fn local_lsp_servers_for_buffer(
8627 &self,
8628 buffer: &Entity<Buffer>,
8629 cx: &mut Context<Self>,
8630 ) -> Vec<LanguageServerId> {
8631 let Some(local) = self.as_local() else {
8632 return Vec::new();
8633 };
8634
8635 let snapshot = buffer.read(cx).snapshot();
8636
8637 buffer.update(cx, |buffer, cx| {
8638 local
8639 .language_servers_for_buffer(buffer, cx)
8640 .map(|(_, server)| server.server_id())
8641 .filter(|server_id| {
8642 self.as_local().is_none_or(|local| {
8643 local
8644 .buffers_opened_in_servers
8645 .get(&snapshot.remote_id())
8646 .is_some_and(|servers| servers.contains(server_id))
8647 })
8648 })
8649 .collect()
8650 })
8651 }
8652
8653 fn request_multiple_lsp_locally<P, R>(
8654 &mut self,
8655 buffer: &Entity<Buffer>,
8656 position: Option<P>,
8657 request: R,
8658 cx: &mut Context<Self>,
8659 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8660 where
8661 P: ToOffset,
8662 R: LspCommand + Clone,
8663 <R::LspRequest as lsp::request::Request>::Result: Send,
8664 <R::LspRequest as lsp::request::Request>::Params: Send,
8665 {
8666 let Some(local) = self.as_local() else {
8667 return Task::ready(Vec::new());
8668 };
8669
8670 let snapshot = buffer.read(cx).snapshot();
8671 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8672
8673 let server_ids = buffer.update(cx, |buffer, cx| {
8674 local
8675 .language_servers_for_buffer(buffer, cx)
8676 .filter(|(adapter, _)| {
8677 scope
8678 .as_ref()
8679 .map(|scope| scope.language_allowed(&adapter.name))
8680 .unwrap_or(true)
8681 })
8682 .map(|(_, server)| server.server_id())
8683 .filter(|server_id| {
8684 self.as_local().is_none_or(|local| {
8685 local
8686 .buffers_opened_in_servers
8687 .get(&snapshot.remote_id())
8688 .is_some_and(|servers| servers.contains(server_id))
8689 })
8690 })
8691 .collect::<Vec<_>>()
8692 });
8693
8694 let mut response_results = server_ids
8695 .into_iter()
8696 .map(|server_id| {
8697 let task = self.request_lsp(
8698 buffer.clone(),
8699 LanguageServerToQuery::Other(server_id),
8700 request.clone(),
8701 cx,
8702 );
8703 async move { (server_id, task.await) }
8704 })
8705 .collect::<FuturesUnordered<_>>();
8706
8707 cx.background_spawn(async move {
8708 let mut responses = Vec::with_capacity(response_results.len());
8709 while let Some((server_id, response_result)) = response_results.next().await {
8710 match response_result {
8711 Ok(response) => responses.push((server_id, response)),
8712 // rust-analyzer likes to error with this when its still loading up
8713 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8714 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8715 }
8716 }
8717 responses
8718 })
8719 }
8720
8721 async fn handle_lsp_get_completions(
8722 this: Entity<Self>,
8723 envelope: TypedEnvelope<proto::GetCompletions>,
8724 mut cx: AsyncApp,
8725 ) -> Result<proto::GetCompletionsResponse> {
8726 let sender_id = envelope.original_sender_id().unwrap_or_default();
8727
8728 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8729 let buffer_handle = this.update(&mut cx, |this, cx| {
8730 this.buffer_store.read(cx).get_existing(buffer_id)
8731 })?;
8732 let request = GetCompletions::from_proto(
8733 envelope.payload,
8734 this.clone(),
8735 buffer_handle.clone(),
8736 cx.clone(),
8737 )
8738 .await?;
8739
8740 let server_to_query = match request.server_id {
8741 Some(server_id) => LanguageServerToQuery::Other(server_id),
8742 None => LanguageServerToQuery::FirstCapable,
8743 };
8744
8745 let response = this
8746 .update(&mut cx, |this, cx| {
8747 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8748 })
8749 .await?;
8750 this.update(&mut cx, |this, cx| {
8751 Ok(GetCompletions::response_to_proto(
8752 response,
8753 this,
8754 sender_id,
8755 &buffer_handle.read(cx).version(),
8756 cx,
8757 ))
8758 })
8759 }
8760
8761 async fn handle_lsp_command<T: LspCommand>(
8762 this: Entity<Self>,
8763 envelope: TypedEnvelope<T::ProtoRequest>,
8764 mut cx: AsyncApp,
8765 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8766 where
8767 <T::LspRequest as lsp::request::Request>::Params: Send,
8768 <T::LspRequest as lsp::request::Request>::Result: Send,
8769 {
8770 let sender_id = envelope.original_sender_id().unwrap_or_default();
8771 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8772 let buffer_handle = this.update(&mut cx, |this, cx| {
8773 this.buffer_store.read(cx).get_existing(buffer_id)
8774 })?;
8775 let request = T::from_proto(
8776 envelope.payload,
8777 this.clone(),
8778 buffer_handle.clone(),
8779 cx.clone(),
8780 )
8781 .await?;
8782 let response = this
8783 .update(&mut cx, |this, cx| {
8784 this.request_lsp(
8785 buffer_handle.clone(),
8786 LanguageServerToQuery::FirstCapable,
8787 request,
8788 cx,
8789 )
8790 })
8791 .await?;
8792 this.update(&mut cx, |this, cx| {
8793 Ok(T::response_to_proto(
8794 response,
8795 this,
8796 sender_id,
8797 &buffer_handle.read(cx).version(),
8798 cx,
8799 ))
8800 })
8801 }
8802
8803 async fn handle_lsp_query(
8804 lsp_store: Entity<Self>,
8805 envelope: TypedEnvelope<proto::LspQuery>,
8806 mut cx: AsyncApp,
8807 ) -> Result<proto::Ack> {
8808 use proto::lsp_query::Request;
8809 let sender_id = envelope.original_sender_id().unwrap_or_default();
8810 let lsp_query = envelope.payload;
8811 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8812 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8813 match lsp_query.request.context("invalid LSP query request")? {
8814 Request::GetReferences(get_references) => {
8815 let position = get_references.position.clone().and_then(deserialize_anchor);
8816 Self::query_lsp_locally::<GetReferences>(
8817 lsp_store,
8818 server_id,
8819 sender_id,
8820 lsp_request_id,
8821 get_references,
8822 position,
8823 &mut cx,
8824 )
8825 .await?;
8826 }
8827 Request::GetDocumentColor(get_document_color) => {
8828 Self::query_lsp_locally::<GetDocumentColor>(
8829 lsp_store,
8830 server_id,
8831 sender_id,
8832 lsp_request_id,
8833 get_document_color,
8834 None,
8835 &mut cx,
8836 )
8837 .await?;
8838 }
8839 Request::GetFoldingRanges(get_folding_ranges) => {
8840 Self::query_lsp_locally::<GetFoldingRanges>(
8841 lsp_store,
8842 server_id,
8843 sender_id,
8844 lsp_request_id,
8845 get_folding_ranges,
8846 None,
8847 &mut cx,
8848 )
8849 .await?;
8850 }
8851 Request::GetDocumentSymbols(get_document_symbols) => {
8852 Self::query_lsp_locally::<GetDocumentSymbols>(
8853 lsp_store,
8854 server_id,
8855 sender_id,
8856 lsp_request_id,
8857 get_document_symbols,
8858 None,
8859 &mut cx,
8860 )
8861 .await?;
8862 }
8863 Request::GetHover(get_hover) => {
8864 let position = get_hover.position.clone().and_then(deserialize_anchor);
8865 Self::query_lsp_locally::<GetHover>(
8866 lsp_store,
8867 server_id,
8868 sender_id,
8869 lsp_request_id,
8870 get_hover,
8871 position,
8872 &mut cx,
8873 )
8874 .await?;
8875 }
8876 Request::GetCodeActions(get_code_actions) => {
8877 Self::query_lsp_locally::<GetCodeActions>(
8878 lsp_store,
8879 server_id,
8880 sender_id,
8881 lsp_request_id,
8882 get_code_actions,
8883 None,
8884 &mut cx,
8885 )
8886 .await?;
8887 }
8888 Request::GetSignatureHelp(get_signature_help) => {
8889 let position = get_signature_help
8890 .position
8891 .clone()
8892 .and_then(deserialize_anchor);
8893 Self::query_lsp_locally::<GetSignatureHelp>(
8894 lsp_store,
8895 server_id,
8896 sender_id,
8897 lsp_request_id,
8898 get_signature_help,
8899 position,
8900 &mut cx,
8901 )
8902 .await?;
8903 }
8904 Request::GetCodeLens(get_code_lens) => {
8905 Self::query_lsp_locally::<GetCodeLens>(
8906 lsp_store,
8907 server_id,
8908 sender_id,
8909 lsp_request_id,
8910 get_code_lens,
8911 None,
8912 &mut cx,
8913 )
8914 .await?;
8915 }
8916 Request::GetDefinition(get_definition) => {
8917 let position = get_definition.position.clone().and_then(deserialize_anchor);
8918 Self::query_lsp_locally::<GetDefinitions>(
8919 lsp_store,
8920 server_id,
8921 sender_id,
8922 lsp_request_id,
8923 get_definition,
8924 position,
8925 &mut cx,
8926 )
8927 .await?;
8928 }
8929 Request::GetDeclaration(get_declaration) => {
8930 let position = get_declaration
8931 .position
8932 .clone()
8933 .and_then(deserialize_anchor);
8934 Self::query_lsp_locally::<GetDeclarations>(
8935 lsp_store,
8936 server_id,
8937 sender_id,
8938 lsp_request_id,
8939 get_declaration,
8940 position,
8941 &mut cx,
8942 )
8943 .await?;
8944 }
8945 Request::GetTypeDefinition(get_type_definition) => {
8946 let position = get_type_definition
8947 .position
8948 .clone()
8949 .and_then(deserialize_anchor);
8950 Self::query_lsp_locally::<GetTypeDefinitions>(
8951 lsp_store,
8952 server_id,
8953 sender_id,
8954 lsp_request_id,
8955 get_type_definition,
8956 position,
8957 &mut cx,
8958 )
8959 .await?;
8960 }
8961 Request::GetImplementation(get_implementation) => {
8962 let position = get_implementation
8963 .position
8964 .clone()
8965 .and_then(deserialize_anchor);
8966 Self::query_lsp_locally::<GetImplementations>(
8967 lsp_store,
8968 server_id,
8969 sender_id,
8970 lsp_request_id,
8971 get_implementation,
8972 position,
8973 &mut cx,
8974 )
8975 .await?;
8976 }
8977 Request::InlayHints(inlay_hints) => {
8978 let query_start = inlay_hints
8979 .start
8980 .clone()
8981 .and_then(deserialize_anchor)
8982 .context("invalid inlay hints range start")?;
8983 let query_end = inlay_hints
8984 .end
8985 .clone()
8986 .and_then(deserialize_anchor)
8987 .context("invalid inlay hints range end")?;
8988 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8989 &lsp_store,
8990 server_id,
8991 lsp_request_id,
8992 &inlay_hints,
8993 query_start..query_end,
8994 &mut cx,
8995 )
8996 .await
8997 .context("preparing inlay hints request")?;
8998 Self::query_lsp_locally::<InlayHints>(
8999 lsp_store,
9000 server_id,
9001 sender_id,
9002 lsp_request_id,
9003 inlay_hints,
9004 None,
9005 &mut cx,
9006 )
9007 .await
9008 .context("querying for inlay hints")?
9009 }
9010 //////////////////////////////
9011 // Below are LSP queries that need to fetch more data,
9012 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9013 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9014 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9015 &lsp_store,
9016 &get_document_diagnostics,
9017 &mut cx,
9018 )
9019 .await?;
9020 lsp_store.update(&mut cx, |lsp_store, cx| {
9021 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9022 let key = LspKey {
9023 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9024 server_queried: server_id,
9025 };
9026 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9027 ) {
9028 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9029 lsp_requests.clear();
9030 };
9031 }
9032
9033 lsp_data.lsp_requests.entry(key).or_default().insert(
9034 lsp_request_id,
9035 cx.spawn(async move |lsp_store, cx| {
9036 let diagnostics_pull = lsp_store
9037 .update(cx, |lsp_store, cx| {
9038 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9039 })
9040 .ok();
9041 if let Some(diagnostics_pull) = diagnostics_pull {
9042 match diagnostics_pull.await {
9043 Ok(()) => {}
9044 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9045 };
9046 }
9047 }),
9048 );
9049 });
9050 }
9051 Request::SemanticTokens(semantic_tokens) => {
9052 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9053 &lsp_store,
9054 &semantic_tokens,
9055 &mut cx,
9056 )
9057 .await?;
9058 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9059 lsp_store.update(&mut cx, |lsp_store, cx| {
9060 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9061 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9062 let key = LspKey {
9063 request_type: TypeId::of::<SemanticTokensFull>(),
9064 server_queried: server_id,
9065 };
9066 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9067 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9068 lsp_requests.clear();
9069 };
9070 }
9071
9072 lsp_data.lsp_requests.entry(key).or_default().insert(
9073 lsp_request_id,
9074 cx.spawn(async move |lsp_store, cx| {
9075 let tokens_fetch = lsp_store
9076 .update(cx, |lsp_store, cx| {
9077 lsp_store
9078 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9079 })
9080 .ok();
9081 if let Some(tokens_fetch) = tokens_fetch {
9082 let new_tokens = tokens_fetch.await;
9083 if let Some(new_tokens) = new_tokens {
9084 lsp_store
9085 .update(cx, |lsp_store, cx| {
9086 let response = new_tokens
9087 .into_iter()
9088 .map(|(server_id, response)| {
9089 (
9090 server_id.to_proto(),
9091 SemanticTokensFull::response_to_proto(
9092 response,
9093 lsp_store,
9094 sender_id,
9095 &buffer_version,
9096 cx,
9097 ),
9098 )
9099 })
9100 .collect::<HashMap<_, _>>();
9101 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9102 project_id,
9103 lsp_request_id,
9104 response,
9105 ) {
9106 Ok(()) => {}
9107 Err(e) => {
9108 log::error!(
9109 "Failed to send semantic tokens LSP response: {e:#}",
9110 )
9111 }
9112 }
9113 })
9114 .ok();
9115 }
9116 }
9117 }),
9118 );
9119 }
9120 });
9121 }
9122 }
9123 Ok(proto::Ack {})
9124 }
9125
9126 async fn handle_lsp_query_response(
9127 lsp_store: Entity<Self>,
9128 envelope: TypedEnvelope<proto::LspQueryResponse>,
9129 cx: AsyncApp,
9130 ) -> Result<()> {
9131 lsp_store.read_with(&cx, |lsp_store, _| {
9132 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9133 upstream_client.handle_lsp_response(envelope.clone());
9134 }
9135 });
9136 Ok(())
9137 }
9138
9139 async fn handle_apply_code_action(
9140 this: Entity<Self>,
9141 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9142 mut cx: AsyncApp,
9143 ) -> Result<proto::ApplyCodeActionResponse> {
9144 let sender_id = envelope.original_sender_id().unwrap_or_default();
9145 let action =
9146 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9147 let apply_code_action = this.update(&mut cx, |this, cx| {
9148 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9149 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9150 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9151 })?;
9152
9153 let project_transaction = apply_code_action.await?;
9154 let project_transaction = this.update(&mut cx, |this, cx| {
9155 this.buffer_store.update(cx, |buffer_store, cx| {
9156 buffer_store.serialize_project_transaction_for_peer(
9157 project_transaction,
9158 sender_id,
9159 cx,
9160 )
9161 })
9162 });
9163 Ok(proto::ApplyCodeActionResponse {
9164 transaction: Some(project_transaction),
9165 })
9166 }
9167
9168 async fn handle_register_buffer_with_language_servers(
9169 this: Entity<Self>,
9170 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9171 mut cx: AsyncApp,
9172 ) -> Result<proto::Ack> {
9173 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9174 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9175 this.update(&mut cx, |this, cx| {
9176 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9177 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9178 project_id: upstream_project_id,
9179 buffer_id: buffer_id.to_proto(),
9180 only_servers: envelope.payload.only_servers,
9181 });
9182 }
9183
9184 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9185 anyhow::bail!("buffer is not open");
9186 };
9187
9188 let handle = this.register_buffer_with_language_servers(
9189 &buffer,
9190 envelope
9191 .payload
9192 .only_servers
9193 .into_iter()
9194 .filter_map(|selector| {
9195 Some(match selector.selector? {
9196 proto::language_server_selector::Selector::ServerId(server_id) => {
9197 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9198 }
9199 proto::language_server_selector::Selector::Name(name) => {
9200 LanguageServerSelector::Name(LanguageServerName(
9201 SharedString::from(name),
9202 ))
9203 }
9204 })
9205 })
9206 .collect(),
9207 false,
9208 cx,
9209 );
9210 // Pull diagnostics for the buffer even if it was already registered.
9211 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9212 // but it's unclear if we need it.
9213 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9214 .detach();
9215 this.buffer_store().update(cx, |buffer_store, _| {
9216 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9217 });
9218
9219 Ok(())
9220 })?;
9221 Ok(proto::Ack {})
9222 }
9223
9224 async fn handle_rename_project_entry(
9225 this: Entity<Self>,
9226 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9227 mut cx: AsyncApp,
9228 ) -> Result<proto::ProjectEntryResponse> {
9229 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9230 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9231 let new_path =
9232 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9233
9234 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9235 .update(&mut cx, |this, cx| {
9236 let (worktree, entry) = this
9237 .worktree_store
9238 .read(cx)
9239 .worktree_and_entry_for_id(entry_id, cx)?;
9240 let new_worktree = this
9241 .worktree_store
9242 .read(cx)
9243 .worktree_for_id(new_worktree_id, cx)?;
9244 Some((
9245 this.worktree_store.clone(),
9246 worktree,
9247 new_worktree,
9248 entry.clone(),
9249 ))
9250 })
9251 .context("worktree not found")?;
9252 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9253 (worktree.absolutize(&old_entry.path), worktree.id())
9254 });
9255 let new_abs_path =
9256 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9257
9258 let _transaction = Self::will_rename_entry(
9259 this.downgrade(),
9260 old_worktree_id,
9261 &old_abs_path,
9262 &new_abs_path,
9263 old_entry.is_dir(),
9264 cx.clone(),
9265 )
9266 .await;
9267 let response = WorktreeStore::handle_rename_project_entry(
9268 worktree_store,
9269 envelope.payload,
9270 cx.clone(),
9271 )
9272 .await;
9273 this.read_with(&cx, |this, _| {
9274 this.did_rename_entry(
9275 old_worktree_id,
9276 &old_abs_path,
9277 &new_abs_path,
9278 old_entry.is_dir(),
9279 );
9280 });
9281 response
9282 }
9283
9284 async fn handle_update_diagnostic_summary(
9285 this: Entity<Self>,
9286 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9287 mut cx: AsyncApp,
9288 ) -> Result<()> {
9289 this.update(&mut cx, |lsp_store, cx| {
9290 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9291 let mut updated_diagnostics_paths = HashMap::default();
9292 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9293 for message_summary in envelope
9294 .payload
9295 .summary
9296 .into_iter()
9297 .chain(envelope.payload.more_summaries)
9298 {
9299 let project_path = ProjectPath {
9300 worktree_id,
9301 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9302 };
9303 let path = project_path.path.clone();
9304 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9305 let summary = DiagnosticSummary {
9306 error_count: message_summary.error_count as usize,
9307 warning_count: message_summary.warning_count as usize,
9308 };
9309
9310 if summary.is_empty() {
9311 if let Some(worktree_summaries) =
9312 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9313 && let Some(summaries) = worktree_summaries.get_mut(&path)
9314 {
9315 summaries.remove(&server_id);
9316 if summaries.is_empty() {
9317 worktree_summaries.remove(&path);
9318 }
9319 }
9320 } else {
9321 lsp_store
9322 .diagnostic_summaries
9323 .entry(worktree_id)
9324 .or_default()
9325 .entry(path)
9326 .or_default()
9327 .insert(server_id, summary);
9328 }
9329
9330 if let Some((_, project_id)) = &lsp_store.downstream_client {
9331 match &mut diagnostics_summary {
9332 Some(diagnostics_summary) => {
9333 diagnostics_summary
9334 .more_summaries
9335 .push(proto::DiagnosticSummary {
9336 path: project_path.path.as_ref().to_proto(),
9337 language_server_id: server_id.0 as u64,
9338 error_count: summary.error_count as u32,
9339 warning_count: summary.warning_count as u32,
9340 })
9341 }
9342 None => {
9343 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9344 project_id: *project_id,
9345 worktree_id: worktree_id.to_proto(),
9346 summary: Some(proto::DiagnosticSummary {
9347 path: project_path.path.as_ref().to_proto(),
9348 language_server_id: server_id.0 as u64,
9349 error_count: summary.error_count as u32,
9350 warning_count: summary.warning_count as u32,
9351 }),
9352 more_summaries: Vec::new(),
9353 })
9354 }
9355 }
9356 }
9357 updated_diagnostics_paths
9358 .entry(server_id)
9359 .or_insert_with(Vec::new)
9360 .push(project_path);
9361 }
9362
9363 if let Some((diagnostics_summary, (downstream_client, _))) =
9364 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9365 {
9366 downstream_client.send(diagnostics_summary).log_err();
9367 }
9368 for (server_id, paths) in updated_diagnostics_paths {
9369 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9370 }
9371 Ok(())
9372 })
9373 }
9374
9375 async fn handle_start_language_server(
9376 lsp_store: Entity<Self>,
9377 envelope: TypedEnvelope<proto::StartLanguageServer>,
9378 mut cx: AsyncApp,
9379 ) -> Result<()> {
9380 let server = envelope.payload.server.context("invalid server")?;
9381 let server_capabilities =
9382 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9383 .with_context(|| {
9384 format!(
9385 "incorrect server capabilities {}",
9386 envelope.payload.capabilities
9387 )
9388 })?;
9389 lsp_store.update(&mut cx, |lsp_store, cx| {
9390 let server_id = LanguageServerId(server.id as usize);
9391 let server_name = LanguageServerName::from_proto(server.name.clone());
9392 lsp_store
9393 .lsp_server_capabilities
9394 .insert(server_id, server_capabilities);
9395 lsp_store.language_server_statuses.insert(
9396 server_id,
9397 LanguageServerStatus {
9398 name: server_name.clone(),
9399 server_version: None,
9400 server_readable_version: None,
9401 pending_work: Default::default(),
9402 has_pending_diagnostic_updates: false,
9403 progress_tokens: Default::default(),
9404 worktree: server.worktree_id.map(WorktreeId::from_proto),
9405 binary: None,
9406 configuration: None,
9407 workspace_folders: BTreeSet::new(),
9408 process_id: None,
9409 },
9410 );
9411 cx.emit(LspStoreEvent::LanguageServerAdded(
9412 server_id,
9413 server_name,
9414 server.worktree_id.map(WorktreeId::from_proto),
9415 ));
9416 cx.notify();
9417 });
9418 Ok(())
9419 }
9420
9421 async fn handle_update_language_server(
9422 lsp_store: Entity<Self>,
9423 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9424 mut cx: AsyncApp,
9425 ) -> Result<()> {
9426 lsp_store.update(&mut cx, |lsp_store, cx| {
9427 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9428
9429 match envelope.payload.variant.context("invalid variant")? {
9430 proto::update_language_server::Variant::WorkStart(payload) => {
9431 lsp_store.on_lsp_work_start(
9432 language_server_id,
9433 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9434 .context("invalid progress token value")?,
9435 LanguageServerProgress {
9436 title: payload.title,
9437 is_disk_based_diagnostics_progress: false,
9438 is_cancellable: payload.is_cancellable.unwrap_or(false),
9439 message: payload.message,
9440 percentage: payload.percentage.map(|p| p as usize),
9441 last_update_at: cx.background_executor().now(),
9442 },
9443 cx,
9444 );
9445 }
9446 proto::update_language_server::Variant::WorkProgress(payload) => {
9447 lsp_store.on_lsp_work_progress(
9448 language_server_id,
9449 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9450 .context("invalid progress token value")?,
9451 LanguageServerProgress {
9452 title: None,
9453 is_disk_based_diagnostics_progress: false,
9454 is_cancellable: payload.is_cancellable.unwrap_or(false),
9455 message: payload.message,
9456 percentage: payload.percentage.map(|p| p as usize),
9457 last_update_at: cx.background_executor().now(),
9458 },
9459 cx,
9460 );
9461 }
9462
9463 proto::update_language_server::Variant::WorkEnd(payload) => {
9464 lsp_store.on_lsp_work_end(
9465 language_server_id,
9466 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9467 .context("invalid progress token value")?,
9468 cx,
9469 );
9470 }
9471
9472 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9473 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9474 }
9475
9476 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9477 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9478 }
9479
9480 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9481 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9482 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9483 cx.emit(LspStoreEvent::LanguageServerUpdate {
9484 language_server_id,
9485 name: envelope
9486 .payload
9487 .server_name
9488 .map(SharedString::new)
9489 .map(LanguageServerName),
9490 message: non_lsp,
9491 });
9492 }
9493 }
9494
9495 Ok(())
9496 })
9497 }
9498
9499 async fn handle_language_server_log(
9500 this: Entity<Self>,
9501 envelope: TypedEnvelope<proto::LanguageServerLog>,
9502 mut cx: AsyncApp,
9503 ) -> Result<()> {
9504 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9505 let log_type = envelope
9506 .payload
9507 .log_type
9508 .map(LanguageServerLogType::from_proto)
9509 .context("invalid language server log type")?;
9510
9511 let message = envelope.payload.message;
9512
9513 this.update(&mut cx, |_, cx| {
9514 cx.emit(LspStoreEvent::LanguageServerLog(
9515 language_server_id,
9516 log_type,
9517 message,
9518 ));
9519 });
9520 Ok(())
9521 }
9522
9523 async fn handle_lsp_ext_cancel_flycheck(
9524 lsp_store: Entity<Self>,
9525 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9526 cx: AsyncApp,
9527 ) -> Result<proto::Ack> {
9528 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9529 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9530 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9531 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9532 } else {
9533 None
9534 }
9535 });
9536 if let Some(task) = task {
9537 task.context("handling lsp ext cancel flycheck")?;
9538 }
9539
9540 Ok(proto::Ack {})
9541 }
9542
9543 async fn handle_lsp_ext_run_flycheck(
9544 lsp_store: Entity<Self>,
9545 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9546 mut cx: AsyncApp,
9547 ) -> Result<proto::Ack> {
9548 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9549 lsp_store.update(&mut cx, |lsp_store, cx| {
9550 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9551 let text_document = if envelope.payload.current_file_only {
9552 let buffer_id = envelope
9553 .payload
9554 .buffer_id
9555 .map(|id| BufferId::new(id))
9556 .transpose()?;
9557 buffer_id
9558 .and_then(|buffer_id| {
9559 lsp_store
9560 .buffer_store()
9561 .read(cx)
9562 .get(buffer_id)
9563 .and_then(|buffer| {
9564 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9565 })
9566 .map(|path| make_text_document_identifier(&path))
9567 })
9568 .transpose()?
9569 } else {
9570 None
9571 };
9572 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9573 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9574 )?;
9575 }
9576 anyhow::Ok(())
9577 })?;
9578
9579 Ok(proto::Ack {})
9580 }
9581
9582 async fn handle_lsp_ext_clear_flycheck(
9583 lsp_store: Entity<Self>,
9584 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9585 cx: AsyncApp,
9586 ) -> Result<proto::Ack> {
9587 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9588 lsp_store.read_with(&cx, |lsp_store, _| {
9589 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9590 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9591 } else {
9592 None
9593 }
9594 });
9595
9596 Ok(proto::Ack {})
9597 }
9598
9599 pub fn disk_based_diagnostics_started(
9600 &mut self,
9601 language_server_id: LanguageServerId,
9602 cx: &mut Context<Self>,
9603 ) {
9604 if let Some(language_server_status) =
9605 self.language_server_statuses.get_mut(&language_server_id)
9606 {
9607 language_server_status.has_pending_diagnostic_updates = true;
9608 }
9609
9610 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9611 cx.emit(LspStoreEvent::LanguageServerUpdate {
9612 language_server_id,
9613 name: self
9614 .language_server_adapter_for_id(language_server_id)
9615 .map(|adapter| adapter.name()),
9616 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9617 Default::default(),
9618 ),
9619 })
9620 }
9621
9622 pub fn disk_based_diagnostics_finished(
9623 &mut self,
9624 language_server_id: LanguageServerId,
9625 cx: &mut Context<Self>,
9626 ) {
9627 if let Some(language_server_status) =
9628 self.language_server_statuses.get_mut(&language_server_id)
9629 {
9630 language_server_status.has_pending_diagnostic_updates = false;
9631 }
9632
9633 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9634 cx.emit(LspStoreEvent::LanguageServerUpdate {
9635 language_server_id,
9636 name: self
9637 .language_server_adapter_for_id(language_server_id)
9638 .map(|adapter| adapter.name()),
9639 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9640 Default::default(),
9641 ),
9642 })
9643 }
9644
9645 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9646 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9647 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9648 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9649 // the language server might take some time to publish diagnostics.
9650 fn simulate_disk_based_diagnostics_events_if_needed(
9651 &mut self,
9652 language_server_id: LanguageServerId,
9653 cx: &mut Context<Self>,
9654 ) {
9655 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9656
9657 let Some(LanguageServerState::Running {
9658 simulate_disk_based_diagnostics_completion,
9659 adapter,
9660 ..
9661 }) = self
9662 .as_local_mut()
9663 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9664 else {
9665 return;
9666 };
9667
9668 if adapter.disk_based_diagnostics_progress_token.is_some() {
9669 return;
9670 }
9671
9672 let prev_task =
9673 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9674 cx.background_executor()
9675 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9676 .await;
9677
9678 this.update(cx, |this, cx| {
9679 this.disk_based_diagnostics_finished(language_server_id, cx);
9680
9681 if let Some(LanguageServerState::Running {
9682 simulate_disk_based_diagnostics_completion,
9683 ..
9684 }) = this.as_local_mut().and_then(|local_store| {
9685 local_store.language_servers.get_mut(&language_server_id)
9686 }) {
9687 *simulate_disk_based_diagnostics_completion = None;
9688 }
9689 })
9690 .ok();
9691 }));
9692
9693 if prev_task.is_none() {
9694 self.disk_based_diagnostics_started(language_server_id, cx);
9695 }
9696 }
9697
9698 pub fn language_server_statuses(
9699 &self,
9700 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9701 self.language_server_statuses
9702 .iter()
9703 .map(|(key, value)| (*key, value))
9704 }
9705
9706 pub(super) fn did_rename_entry(
9707 &self,
9708 worktree_id: WorktreeId,
9709 old_path: &Path,
9710 new_path: &Path,
9711 is_dir: bool,
9712 ) {
9713 maybe!({
9714 let local_store = self.as_local()?;
9715
9716 let old_uri = lsp::Uri::from_file_path(old_path)
9717 .ok()
9718 .map(|uri| uri.to_string())?;
9719 let new_uri = lsp::Uri::from_file_path(new_path)
9720 .ok()
9721 .map(|uri| uri.to_string())?;
9722
9723 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9724 let Some(filter) = local_store
9725 .language_server_paths_watched_for_rename
9726 .get(&language_server.server_id())
9727 else {
9728 continue;
9729 };
9730
9731 if filter.should_send_did_rename(&old_uri, is_dir) {
9732 language_server
9733 .notify::<DidRenameFiles>(RenameFilesParams {
9734 files: vec![FileRename {
9735 old_uri: old_uri.clone(),
9736 new_uri: new_uri.clone(),
9737 }],
9738 })
9739 .ok();
9740 }
9741 }
9742 Some(())
9743 });
9744 }
9745
9746 pub(super) fn will_rename_entry(
9747 this: WeakEntity<Self>,
9748 worktree_id: WorktreeId,
9749 old_path: &Path,
9750 new_path: &Path,
9751 is_dir: bool,
9752 cx: AsyncApp,
9753 ) -> Task<ProjectTransaction> {
9754 let old_uri = lsp::Uri::from_file_path(old_path)
9755 .ok()
9756 .map(|uri| uri.to_string());
9757 let new_uri = lsp::Uri::from_file_path(new_path)
9758 .ok()
9759 .map(|uri| uri.to_string());
9760 cx.spawn(async move |cx| {
9761 let mut tasks = vec![];
9762 this.update(cx, |this, cx| {
9763 let local_store = this.as_local()?;
9764 let old_uri = old_uri?;
9765 let new_uri = new_uri?;
9766 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9767 let Some(filter) = local_store
9768 .language_server_paths_watched_for_rename
9769 .get(&language_server.server_id())
9770 else {
9771 continue;
9772 };
9773
9774 if !filter.should_send_will_rename(&old_uri, is_dir) {
9775 continue;
9776 }
9777 let request_timeout = ProjectSettings::get_global(cx)
9778 .global_lsp_settings
9779 .get_request_timeout();
9780
9781 let apply_edit = cx.spawn({
9782 let old_uri = old_uri.clone();
9783 let new_uri = new_uri.clone();
9784 let language_server = language_server.clone();
9785 async move |this, cx| {
9786 let edit = language_server
9787 .request::<WillRenameFiles>(
9788 RenameFilesParams {
9789 files: vec![FileRename { old_uri, new_uri }],
9790 },
9791 request_timeout,
9792 )
9793 .await
9794 .into_response()
9795 .context("will rename files")
9796 .log_err()
9797 .flatten()?;
9798
9799 LocalLspStore::deserialize_workspace_edit(
9800 this.upgrade()?,
9801 edit,
9802 false,
9803 language_server.clone(),
9804 cx,
9805 )
9806 .await
9807 .ok()
9808 }
9809 });
9810 tasks.push(apply_edit);
9811 }
9812 Some(())
9813 })
9814 .ok()
9815 .flatten();
9816 let mut merged_transaction = ProjectTransaction::default();
9817 for task in tasks {
9818 // Await on tasks sequentially so that the order of application of edits is deterministic
9819 // (at least with regards to the order of registration of language servers)
9820 if let Some(transaction) = task.await {
9821 for (buffer, buffer_transaction) in transaction.0 {
9822 merged_transaction.0.insert(buffer, buffer_transaction);
9823 }
9824 }
9825 }
9826 merged_transaction
9827 })
9828 }
9829
9830 fn lsp_notify_abs_paths_changed(
9831 &mut self,
9832 server_id: LanguageServerId,
9833 changes: Vec<PathEvent>,
9834 ) {
9835 maybe!({
9836 let server = self.language_server_for_id(server_id)?;
9837 let changes = changes
9838 .into_iter()
9839 .filter_map(|event| {
9840 let typ = match event.kind? {
9841 PathEventKind::Created => lsp::FileChangeType::CREATED,
9842 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9843 PathEventKind::Changed | PathEventKind::Rescan => {
9844 lsp::FileChangeType::CHANGED
9845 }
9846 };
9847 Some(lsp::FileEvent {
9848 uri: file_path_to_lsp_url(&event.path).log_err()?,
9849 typ,
9850 })
9851 })
9852 .collect::<Vec<_>>();
9853 if !changes.is_empty() {
9854 server
9855 .notify::<lsp::notification::DidChangeWatchedFiles>(
9856 lsp::DidChangeWatchedFilesParams { changes },
9857 )
9858 .ok();
9859 }
9860 Some(())
9861 });
9862 }
9863
9864 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9865 self.as_local()?.language_server_for_id(id)
9866 }
9867
9868 fn on_lsp_progress(
9869 &mut self,
9870 progress_params: lsp::ProgressParams,
9871 language_server_id: LanguageServerId,
9872 disk_based_diagnostics_progress_token: Option<String>,
9873 cx: &mut Context<Self>,
9874 ) {
9875 match progress_params.value {
9876 lsp::ProgressParamsValue::WorkDone(progress) => {
9877 self.handle_work_done_progress(
9878 progress,
9879 language_server_id,
9880 disk_based_diagnostics_progress_token,
9881 ProgressToken::from_lsp(progress_params.token),
9882 cx,
9883 );
9884 }
9885 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9886 let registration_id = match progress_params.token {
9887 lsp::NumberOrString::Number(_) => None,
9888 lsp::NumberOrString::String(token) => token
9889 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9890 .map(|(_, id)| id.to_owned()),
9891 };
9892 if let Some(LanguageServerState::Running {
9893 workspace_diagnostics_refresh_tasks,
9894 ..
9895 }) = self
9896 .as_local_mut()
9897 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9898 && let Some(workspace_diagnostics) =
9899 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9900 {
9901 workspace_diagnostics.progress_tx.try_send(()).ok();
9902 self.apply_workspace_diagnostic_report(
9903 language_server_id,
9904 report,
9905 registration_id.map(SharedString::from),
9906 cx,
9907 )
9908 }
9909 }
9910 }
9911 }
9912
9913 fn handle_work_done_progress(
9914 &mut self,
9915 progress: lsp::WorkDoneProgress,
9916 language_server_id: LanguageServerId,
9917 disk_based_diagnostics_progress_token: Option<String>,
9918 token: ProgressToken,
9919 cx: &mut Context<Self>,
9920 ) {
9921 let language_server_status =
9922 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9923 status
9924 } else {
9925 return;
9926 };
9927
9928 if !language_server_status.progress_tokens.contains(&token) {
9929 return;
9930 }
9931
9932 let is_disk_based_diagnostics_progress =
9933 if let (Some(disk_based_token), ProgressToken::String(token)) =
9934 (&disk_based_diagnostics_progress_token, &token)
9935 {
9936 token.starts_with(disk_based_token)
9937 } else {
9938 false
9939 };
9940
9941 match progress {
9942 lsp::WorkDoneProgress::Begin(report) => {
9943 if is_disk_based_diagnostics_progress {
9944 self.disk_based_diagnostics_started(language_server_id, cx);
9945 }
9946 self.on_lsp_work_start(
9947 language_server_id,
9948 token.clone(),
9949 LanguageServerProgress {
9950 title: Some(report.title),
9951 is_disk_based_diagnostics_progress,
9952 is_cancellable: report.cancellable.unwrap_or(false),
9953 message: report.message.clone(),
9954 percentage: report.percentage.map(|p| p as usize),
9955 last_update_at: cx.background_executor().now(),
9956 },
9957 cx,
9958 );
9959 }
9960 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9961 language_server_id,
9962 token,
9963 LanguageServerProgress {
9964 title: None,
9965 is_disk_based_diagnostics_progress,
9966 is_cancellable: report.cancellable.unwrap_or(false),
9967 message: report.message,
9968 percentage: report.percentage.map(|p| p as usize),
9969 last_update_at: cx.background_executor().now(),
9970 },
9971 cx,
9972 ),
9973 lsp::WorkDoneProgress::End(_) => {
9974 language_server_status.progress_tokens.remove(&token);
9975 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9976 if is_disk_based_diagnostics_progress {
9977 self.disk_based_diagnostics_finished(language_server_id, cx);
9978 }
9979 }
9980 }
9981 }
9982
9983 fn on_lsp_work_start(
9984 &mut self,
9985 language_server_id: LanguageServerId,
9986 token: ProgressToken,
9987 progress: LanguageServerProgress,
9988 cx: &mut Context<Self>,
9989 ) {
9990 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9991 status.pending_work.insert(token.clone(), progress.clone());
9992 cx.notify();
9993 }
9994 cx.emit(LspStoreEvent::LanguageServerUpdate {
9995 language_server_id,
9996 name: self
9997 .language_server_adapter_for_id(language_server_id)
9998 .map(|adapter| adapter.name()),
9999 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10000 token: Some(token.to_proto()),
10001 title: progress.title,
10002 message: progress.message,
10003 percentage: progress.percentage.map(|p| p as u32),
10004 is_cancellable: Some(progress.is_cancellable),
10005 }),
10006 })
10007 }
10008
10009 fn on_lsp_work_progress(
10010 &mut self,
10011 language_server_id: LanguageServerId,
10012 token: ProgressToken,
10013 progress: LanguageServerProgress,
10014 cx: &mut Context<Self>,
10015 ) {
10016 let mut did_update = false;
10017 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10018 match status.pending_work.entry(token.clone()) {
10019 btree_map::Entry::Vacant(entry) => {
10020 entry.insert(progress.clone());
10021 did_update = true;
10022 }
10023 btree_map::Entry::Occupied(mut entry) => {
10024 let entry = entry.get_mut();
10025 if (progress.last_update_at - entry.last_update_at)
10026 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10027 {
10028 entry.last_update_at = progress.last_update_at;
10029 if progress.message.is_some() {
10030 entry.message = progress.message.clone();
10031 }
10032 if progress.percentage.is_some() {
10033 entry.percentage = progress.percentage;
10034 }
10035 if progress.is_cancellable != entry.is_cancellable {
10036 entry.is_cancellable = progress.is_cancellable;
10037 }
10038 did_update = true;
10039 }
10040 }
10041 }
10042 }
10043
10044 if did_update {
10045 cx.emit(LspStoreEvent::LanguageServerUpdate {
10046 language_server_id,
10047 name: self
10048 .language_server_adapter_for_id(language_server_id)
10049 .map(|adapter| adapter.name()),
10050 message: proto::update_language_server::Variant::WorkProgress(
10051 proto::LspWorkProgress {
10052 token: Some(token.to_proto()),
10053 message: progress.message,
10054 percentage: progress.percentage.map(|p| p as u32),
10055 is_cancellable: Some(progress.is_cancellable),
10056 },
10057 ),
10058 })
10059 }
10060 }
10061
10062 fn on_lsp_work_end(
10063 &mut self,
10064 language_server_id: LanguageServerId,
10065 token: ProgressToken,
10066 cx: &mut Context<Self>,
10067 ) {
10068 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10069 if let Some(work) = status.pending_work.remove(&token)
10070 && !work.is_disk_based_diagnostics_progress
10071 {
10072 cx.emit(LspStoreEvent::RefreshInlayHints {
10073 server_id: language_server_id,
10074 request_id: None,
10075 });
10076 }
10077 cx.notify();
10078 }
10079
10080 cx.emit(LspStoreEvent::LanguageServerUpdate {
10081 language_server_id,
10082 name: self
10083 .language_server_adapter_for_id(language_server_id)
10084 .map(|adapter| adapter.name()),
10085 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10086 token: Some(token.to_proto()),
10087 }),
10088 })
10089 }
10090
10091 pub async fn handle_resolve_completion_documentation(
10092 this: Entity<Self>,
10093 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10094 mut cx: AsyncApp,
10095 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10096 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10097
10098 let completion = this
10099 .read_with(&cx, |this, cx| {
10100 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10101 let server = this
10102 .language_server_for_id(id)
10103 .with_context(|| format!("No language server {id}"))?;
10104
10105 let request_timeout = ProjectSettings::get_global(cx)
10106 .global_lsp_settings
10107 .get_request_timeout();
10108
10109 anyhow::Ok(cx.background_spawn(async move {
10110 let can_resolve = server
10111 .capabilities()
10112 .completion_provider
10113 .as_ref()
10114 .and_then(|options| options.resolve_provider)
10115 .unwrap_or(false);
10116 if can_resolve {
10117 server
10118 .request::<lsp::request::ResolveCompletionItem>(
10119 lsp_completion,
10120 request_timeout,
10121 )
10122 .await
10123 .into_response()
10124 .context("resolve completion item")
10125 } else {
10126 anyhow::Ok(lsp_completion)
10127 }
10128 }))
10129 })?
10130 .await?;
10131
10132 let mut documentation_is_markdown = false;
10133 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10134 let documentation = match completion.documentation {
10135 Some(lsp::Documentation::String(text)) => text,
10136
10137 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10138 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10139 value
10140 }
10141
10142 _ => String::new(),
10143 };
10144
10145 // If we have a new buffer_id, that means we're talking to a new client
10146 // and want to check for new text_edits in the completion too.
10147 let mut old_replace_start = None;
10148 let mut old_replace_end = None;
10149 let mut old_insert_start = None;
10150 let mut old_insert_end = None;
10151 let mut new_text = String::default();
10152 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10153 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10154 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10155 anyhow::Ok(buffer.read(cx).snapshot())
10156 })?;
10157
10158 if let Some(text_edit) = completion.text_edit.as_ref() {
10159 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10160
10161 if let Some(mut edit) = edit {
10162 LineEnding::normalize(&mut edit.new_text);
10163
10164 new_text = edit.new_text;
10165 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10166 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10167 if let Some(insert_range) = edit.insert_range {
10168 old_insert_start = Some(serialize_anchor(&insert_range.start));
10169 old_insert_end = Some(serialize_anchor(&insert_range.end));
10170 }
10171 }
10172 }
10173 }
10174
10175 Ok(proto::ResolveCompletionDocumentationResponse {
10176 documentation,
10177 documentation_is_markdown,
10178 old_replace_start,
10179 old_replace_end,
10180 new_text,
10181 lsp_completion,
10182 old_insert_start,
10183 old_insert_end,
10184 })
10185 }
10186
10187 async fn handle_on_type_formatting(
10188 this: Entity<Self>,
10189 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10190 mut cx: AsyncApp,
10191 ) -> Result<proto::OnTypeFormattingResponse> {
10192 let on_type_formatting = this.update(&mut cx, |this, cx| {
10193 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10194 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10195 let position = envelope
10196 .payload
10197 .position
10198 .and_then(deserialize_anchor)
10199 .context("invalid position")?;
10200 anyhow::Ok(this.apply_on_type_formatting(
10201 buffer,
10202 position,
10203 envelope.payload.trigger.clone(),
10204 cx,
10205 ))
10206 })?;
10207
10208 let transaction = on_type_formatting
10209 .await?
10210 .as_ref()
10211 .map(language::proto::serialize_transaction);
10212 Ok(proto::OnTypeFormattingResponse { transaction })
10213 }
10214
10215 async fn handle_pull_workspace_diagnostics(
10216 lsp_store: Entity<Self>,
10217 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10218 mut cx: AsyncApp,
10219 ) -> Result<proto::Ack> {
10220 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10221 lsp_store.update(&mut cx, |lsp_store, _| {
10222 lsp_store.pull_workspace_diagnostics(server_id);
10223 });
10224 Ok(proto::Ack {})
10225 }
10226
10227 async fn handle_open_buffer_for_symbol(
10228 this: Entity<Self>,
10229 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10230 mut cx: AsyncApp,
10231 ) -> Result<proto::OpenBufferForSymbolResponse> {
10232 let peer_id = envelope.original_sender_id().unwrap_or_default();
10233 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10234 let symbol = Self::deserialize_symbol(symbol)?;
10235 this.read_with(&cx, |this, _| {
10236 if let SymbolLocation::OutsideProject {
10237 abs_path,
10238 signature,
10239 } = &symbol.path
10240 {
10241 let new_signature = this.symbol_signature(&abs_path);
10242 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10243 }
10244 Ok(())
10245 })?;
10246 let buffer = this
10247 .update(&mut cx, |this, cx| {
10248 this.open_buffer_for_symbol(
10249 &Symbol {
10250 language_server_name: symbol.language_server_name,
10251 source_worktree_id: symbol.source_worktree_id,
10252 source_language_server_id: symbol.source_language_server_id,
10253 path: symbol.path,
10254 name: symbol.name,
10255 kind: symbol.kind,
10256 range: symbol.range,
10257 label: CodeLabel::default(),
10258 container_name: symbol.container_name,
10259 },
10260 cx,
10261 )
10262 })
10263 .await?;
10264
10265 this.update(&mut cx, |this, cx| {
10266 let is_private = buffer
10267 .read(cx)
10268 .file()
10269 .map(|f| f.is_private())
10270 .unwrap_or_default();
10271 if is_private {
10272 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10273 } else {
10274 this.buffer_store
10275 .update(cx, |buffer_store, cx| {
10276 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10277 })
10278 .detach_and_log_err(cx);
10279 let buffer_id = buffer.read(cx).remote_id().to_proto();
10280 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10281 }
10282 })
10283 }
10284
10285 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10286 let mut hasher = Sha256::new();
10287 hasher.update(abs_path.to_string_lossy().as_bytes());
10288 hasher.update(self.nonce.to_be_bytes());
10289 hasher.finalize().as_slice().try_into().unwrap()
10290 }
10291
10292 pub async fn handle_get_project_symbols(
10293 this: Entity<Self>,
10294 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10295 mut cx: AsyncApp,
10296 ) -> Result<proto::GetProjectSymbolsResponse> {
10297 let symbols = this
10298 .update(&mut cx, |this, cx| {
10299 this.symbols(&envelope.payload.query, cx)
10300 })
10301 .await?;
10302
10303 Ok(proto::GetProjectSymbolsResponse {
10304 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10305 })
10306 }
10307
10308 pub async fn handle_restart_language_servers(
10309 this: Entity<Self>,
10310 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10311 mut cx: AsyncApp,
10312 ) -> Result<proto::Ack> {
10313 this.update(&mut cx, |lsp_store, cx| {
10314 let buffers =
10315 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10316 lsp_store.restart_language_servers_for_buffers(
10317 buffers,
10318 envelope
10319 .payload
10320 .only_servers
10321 .into_iter()
10322 .filter_map(|selector| {
10323 Some(match selector.selector? {
10324 proto::language_server_selector::Selector::ServerId(server_id) => {
10325 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10326 }
10327 proto::language_server_selector::Selector::Name(name) => {
10328 LanguageServerSelector::Name(LanguageServerName(
10329 SharedString::from(name),
10330 ))
10331 }
10332 })
10333 })
10334 .collect(),
10335 cx,
10336 );
10337 });
10338
10339 Ok(proto::Ack {})
10340 }
10341
10342 pub async fn handle_stop_language_servers(
10343 lsp_store: Entity<Self>,
10344 envelope: TypedEnvelope<proto::StopLanguageServers>,
10345 mut cx: AsyncApp,
10346 ) -> Result<proto::Ack> {
10347 lsp_store.update(&mut cx, |lsp_store, cx| {
10348 if envelope.payload.all
10349 && envelope.payload.also_servers.is_empty()
10350 && envelope.payload.buffer_ids.is_empty()
10351 {
10352 lsp_store.stop_all_language_servers(cx);
10353 } else {
10354 let buffers =
10355 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10356 lsp_store
10357 .stop_language_servers_for_buffers(
10358 buffers,
10359 envelope
10360 .payload
10361 .also_servers
10362 .into_iter()
10363 .filter_map(|selector| {
10364 Some(match selector.selector? {
10365 proto::language_server_selector::Selector::ServerId(
10366 server_id,
10367 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10368 server_id,
10369 )),
10370 proto::language_server_selector::Selector::Name(name) => {
10371 LanguageServerSelector::Name(LanguageServerName(
10372 SharedString::from(name),
10373 ))
10374 }
10375 })
10376 })
10377 .collect(),
10378 cx,
10379 )
10380 .detach_and_log_err(cx);
10381 }
10382 });
10383
10384 Ok(proto::Ack {})
10385 }
10386
10387 pub async fn handle_cancel_language_server_work(
10388 lsp_store: Entity<Self>,
10389 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10390 mut cx: AsyncApp,
10391 ) -> Result<proto::Ack> {
10392 lsp_store.update(&mut cx, |lsp_store, cx| {
10393 if let Some(work) = envelope.payload.work {
10394 match work {
10395 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10396 let buffers =
10397 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10398 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10399 }
10400 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10401 let server_id = LanguageServerId::from_proto(work.language_server_id);
10402 let token = work
10403 .token
10404 .map(|token| {
10405 ProgressToken::from_proto(token)
10406 .context("invalid work progress token")
10407 })
10408 .transpose()?;
10409 lsp_store.cancel_language_server_work(server_id, token, cx);
10410 }
10411 }
10412 }
10413 anyhow::Ok(())
10414 })?;
10415
10416 Ok(proto::Ack {})
10417 }
10418
10419 fn buffer_ids_to_buffers(
10420 &mut self,
10421 buffer_ids: impl Iterator<Item = u64>,
10422 cx: &mut Context<Self>,
10423 ) -> Vec<Entity<Buffer>> {
10424 buffer_ids
10425 .into_iter()
10426 .flat_map(|buffer_id| {
10427 self.buffer_store
10428 .read(cx)
10429 .get(BufferId::new(buffer_id).log_err()?)
10430 })
10431 .collect::<Vec<_>>()
10432 }
10433
10434 async fn handle_apply_additional_edits_for_completion(
10435 this: Entity<Self>,
10436 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10437 mut cx: AsyncApp,
10438 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10439 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10440 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10441 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10442 let completion = Self::deserialize_completion(
10443 envelope.payload.completion.context("invalid completion")?,
10444 )?;
10445 let all_commit_ranges = envelope
10446 .payload
10447 .all_commit_ranges
10448 .into_iter()
10449 .map(language::proto::deserialize_anchor_range)
10450 .collect::<Result<Vec<_>, _>>()?;
10451 anyhow::Ok((buffer, completion, all_commit_ranges))
10452 })?;
10453
10454 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10455 this.apply_additional_edits_for_completion(
10456 buffer,
10457 Rc::new(RefCell::new(Box::new([Completion {
10458 replace_range: completion.replace_range,
10459 new_text: completion.new_text,
10460 source: completion.source,
10461 documentation: None,
10462 label: CodeLabel::default(),
10463 match_start: None,
10464 snippet_deduplication_key: None,
10465 insert_text_mode: None,
10466 icon_path: None,
10467 confirm: None,
10468 }]))),
10469 0,
10470 false,
10471 all_commit_ranges,
10472 cx,
10473 )
10474 });
10475
10476 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10477 transaction: apply_additional_edits
10478 .await?
10479 .as_ref()
10480 .map(language::proto::serialize_transaction),
10481 })
10482 }
10483
10484 pub fn last_formatting_failure(&self) -> Option<&str> {
10485 self.last_formatting_failure.as_deref()
10486 }
10487
10488 pub fn reset_last_formatting_failure(&mut self) {
10489 self.last_formatting_failure = None;
10490 }
10491
10492 pub fn environment_for_buffer(
10493 &self,
10494 buffer: &Entity<Buffer>,
10495 cx: &mut Context<Self>,
10496 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10497 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10498 environment.update(cx, |env, cx| {
10499 env.buffer_environment(buffer, &self.worktree_store, cx)
10500 })
10501 } else {
10502 Task::ready(None).shared()
10503 }
10504 }
10505
10506 pub fn format(
10507 &mut self,
10508 buffers: HashSet<Entity<Buffer>>,
10509 target: LspFormatTarget,
10510 push_to_history: bool,
10511 trigger: FormatTrigger,
10512 cx: &mut Context<Self>,
10513 ) -> Task<anyhow::Result<ProjectTransaction>> {
10514 let logger = zlog::scoped!("format");
10515 if self.as_local().is_some() {
10516 zlog::trace!(logger => "Formatting locally");
10517 let logger = zlog::scoped!(logger => "local");
10518 let buffers = buffers
10519 .into_iter()
10520 .map(|buffer_handle| {
10521 let buffer = buffer_handle.read(cx);
10522 let buffer_abs_path = File::from_dyn(buffer.file())
10523 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10524
10525 (buffer_handle, buffer_abs_path, buffer.remote_id())
10526 })
10527 .collect::<Vec<_>>();
10528
10529 cx.spawn(async move |lsp_store, cx| {
10530 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10531
10532 for (handle, abs_path, id) in buffers {
10533 let env = lsp_store
10534 .update(cx, |lsp_store, cx| {
10535 lsp_store.environment_for_buffer(&handle, cx)
10536 })?
10537 .await;
10538
10539 let ranges = match &target {
10540 LspFormatTarget::Buffers => None,
10541 LspFormatTarget::Ranges(ranges) => {
10542 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10543 }
10544 };
10545
10546 formattable_buffers.push(FormattableBuffer {
10547 handle,
10548 abs_path,
10549 env,
10550 ranges,
10551 });
10552 }
10553 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10554
10555 let format_timer = zlog::time!(logger => "Formatting buffers");
10556 let result = LocalLspStore::format_locally(
10557 lsp_store.clone(),
10558 formattable_buffers,
10559 push_to_history,
10560 trigger,
10561 logger,
10562 cx,
10563 )
10564 .await;
10565 format_timer.end();
10566
10567 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10568
10569 lsp_store.update(cx, |lsp_store, _| {
10570 lsp_store.update_last_formatting_failure(&result);
10571 })?;
10572
10573 result
10574 })
10575 } else if let Some((client, project_id)) = self.upstream_client() {
10576 zlog::trace!(logger => "Formatting remotely");
10577 let logger = zlog::scoped!(logger => "remote");
10578
10579 let buffer_ranges = match &target {
10580 LspFormatTarget::Buffers => Vec::new(),
10581 LspFormatTarget::Ranges(ranges) => ranges
10582 .iter()
10583 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10584 buffer_id: buffer_id.to_proto(),
10585 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10586 })
10587 .collect(),
10588 };
10589
10590 let buffer_store = self.buffer_store();
10591 cx.spawn(async move |lsp_store, cx| {
10592 zlog::trace!(logger => "Sending remote format request");
10593 let request_timer = zlog::time!(logger => "remote format request");
10594 let result = client
10595 .request(proto::FormatBuffers {
10596 project_id,
10597 trigger: trigger as i32,
10598 buffer_ids: buffers
10599 .iter()
10600 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10601 .collect(),
10602 buffer_ranges,
10603 })
10604 .await
10605 .and_then(|result| result.transaction.context("missing transaction"));
10606 request_timer.end();
10607
10608 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10609
10610 lsp_store.update(cx, |lsp_store, _| {
10611 lsp_store.update_last_formatting_failure(&result);
10612 })?;
10613
10614 let transaction_response = result?;
10615 let _timer = zlog::time!(logger => "deserializing project transaction");
10616 buffer_store
10617 .update(cx, |buffer_store, cx| {
10618 buffer_store.deserialize_project_transaction(
10619 transaction_response,
10620 push_to_history,
10621 cx,
10622 )
10623 })
10624 .await
10625 })
10626 } else {
10627 zlog::trace!(logger => "Not formatting");
10628 Task::ready(Ok(ProjectTransaction::default()))
10629 }
10630 }
10631
10632 async fn handle_format_buffers(
10633 this: Entity<Self>,
10634 envelope: TypedEnvelope<proto::FormatBuffers>,
10635 mut cx: AsyncApp,
10636 ) -> Result<proto::FormatBuffersResponse> {
10637 let sender_id = envelope.original_sender_id().unwrap_or_default();
10638 let format = this.update(&mut cx, |this, cx| {
10639 let mut buffers = HashSet::default();
10640 for buffer_id in &envelope.payload.buffer_ids {
10641 let buffer_id = BufferId::new(*buffer_id)?;
10642 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10643 }
10644
10645 let target = if envelope.payload.buffer_ranges.is_empty() {
10646 LspFormatTarget::Buffers
10647 } else {
10648 let mut ranges_map = BTreeMap::new();
10649 for buffer_range in &envelope.payload.buffer_ranges {
10650 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10651 let ranges: Result<Vec<_>> = buffer_range
10652 .ranges
10653 .iter()
10654 .map(|range| {
10655 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10656 })
10657 .collect();
10658 ranges_map.insert(buffer_id, ranges?);
10659 }
10660 LspFormatTarget::Ranges(ranges_map)
10661 };
10662
10663 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10664 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10665 })?;
10666
10667 let project_transaction = format.await?;
10668 let project_transaction = this.update(&mut cx, |this, cx| {
10669 this.buffer_store.update(cx, |buffer_store, cx| {
10670 buffer_store.serialize_project_transaction_for_peer(
10671 project_transaction,
10672 sender_id,
10673 cx,
10674 )
10675 })
10676 });
10677 Ok(proto::FormatBuffersResponse {
10678 transaction: Some(project_transaction),
10679 })
10680 }
10681
10682 async fn handle_apply_code_action_kind(
10683 this: Entity<Self>,
10684 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10685 mut cx: AsyncApp,
10686 ) -> Result<proto::ApplyCodeActionKindResponse> {
10687 let sender_id = envelope.original_sender_id().unwrap_or_default();
10688 let format = this.update(&mut cx, |this, cx| {
10689 let mut buffers = HashSet::default();
10690 for buffer_id in &envelope.payload.buffer_ids {
10691 let buffer_id = BufferId::new(*buffer_id)?;
10692 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10693 }
10694 let kind = match envelope.payload.kind.as_str() {
10695 "" => CodeActionKind::EMPTY,
10696 "quickfix" => CodeActionKind::QUICKFIX,
10697 "refactor" => CodeActionKind::REFACTOR,
10698 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10699 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10700 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10701 "source" => CodeActionKind::SOURCE,
10702 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10703 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10704 _ => anyhow::bail!(
10705 "Invalid code action kind {}",
10706 envelope.payload.kind.as_str()
10707 ),
10708 };
10709 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10710 })?;
10711
10712 let project_transaction = format.await?;
10713 let project_transaction = this.update(&mut cx, |this, cx| {
10714 this.buffer_store.update(cx, |buffer_store, cx| {
10715 buffer_store.serialize_project_transaction_for_peer(
10716 project_transaction,
10717 sender_id,
10718 cx,
10719 )
10720 })
10721 });
10722 Ok(proto::ApplyCodeActionKindResponse {
10723 transaction: Some(project_transaction),
10724 })
10725 }
10726
10727 async fn shutdown_language_server(
10728 server_state: Option<LanguageServerState>,
10729 name: LanguageServerName,
10730 cx: &mut AsyncApp,
10731 ) {
10732 let server = match server_state {
10733 Some(LanguageServerState::Starting { startup, .. }) => {
10734 let mut timer = cx
10735 .background_executor()
10736 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10737 .fuse();
10738
10739 select! {
10740 server = startup.fuse() => server,
10741 () = timer => {
10742 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10743 None
10744 },
10745 }
10746 }
10747
10748 Some(LanguageServerState::Running { server, .. }) => Some(server),
10749
10750 None => None,
10751 };
10752
10753 let Some(server) = server else { return };
10754 if let Some(shutdown) = server.shutdown() {
10755 shutdown.await;
10756 }
10757 }
10758
10759 // Returns a list of all of the worktrees which no longer have a language server and the root path
10760 // for the stopped server
10761 fn stop_local_language_server(
10762 &mut self,
10763 server_id: LanguageServerId,
10764 cx: &mut Context<Self>,
10765 ) -> Task<()> {
10766 let local = match &mut self.mode {
10767 LspStoreMode::Local(local) => local,
10768 _ => {
10769 return Task::ready(());
10770 }
10771 };
10772
10773 // Remove this server ID from all entries in the given worktree.
10774 local
10775 .language_server_ids
10776 .retain(|_, state| state.id != server_id);
10777 self.buffer_store.update(cx, |buffer_store, cx| {
10778 for buffer in buffer_store.buffers() {
10779 buffer.update(cx, |buffer, cx| {
10780 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10781 buffer.set_completion_triggers(server_id, Default::default(), cx);
10782 });
10783 }
10784 });
10785
10786 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10787 summaries.retain(|path, summaries_by_server_id| {
10788 if summaries_by_server_id.remove(&server_id).is_some() {
10789 if let Some((client, project_id)) = self.downstream_client.clone() {
10790 client
10791 .send(proto::UpdateDiagnosticSummary {
10792 project_id,
10793 worktree_id: worktree_id.to_proto(),
10794 summary: Some(proto::DiagnosticSummary {
10795 path: path.as_ref().to_proto(),
10796 language_server_id: server_id.0 as u64,
10797 error_count: 0,
10798 warning_count: 0,
10799 }),
10800 more_summaries: Vec::new(),
10801 })
10802 .log_err();
10803 }
10804 !summaries_by_server_id.is_empty()
10805 } else {
10806 true
10807 }
10808 });
10809 }
10810
10811 let local = self.as_local_mut().unwrap();
10812 for diagnostics in local.diagnostics.values_mut() {
10813 diagnostics.retain(|_, diagnostics_by_server_id| {
10814 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10815 diagnostics_by_server_id.remove(ix);
10816 !diagnostics_by_server_id.is_empty()
10817 } else {
10818 true
10819 }
10820 });
10821 }
10822 local.language_server_watched_paths.remove(&server_id);
10823
10824 let server_state = local.language_servers.remove(&server_id);
10825 self.cleanup_lsp_data(server_id);
10826 let name = self
10827 .language_server_statuses
10828 .remove(&server_id)
10829 .map(|status| status.name)
10830 .or_else(|| {
10831 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10832 Some(adapter.name())
10833 } else {
10834 None
10835 }
10836 });
10837
10838 if let Some(name) = name {
10839 log::info!("stopping language server {name}");
10840 self.languages
10841 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10842 cx.notify();
10843
10844 return cx.spawn(async move |lsp_store, cx| {
10845 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10846 lsp_store
10847 .update(cx, |lsp_store, cx| {
10848 lsp_store
10849 .languages
10850 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10851 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10852 cx.notify();
10853 })
10854 .ok();
10855 });
10856 }
10857
10858 if server_state.is_some() {
10859 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10860 }
10861 Task::ready(())
10862 }
10863
10864 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10865 self.shutdown_all_language_servers(cx).detach();
10866 }
10867
10868 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10869 if let Some((client, project_id)) = self.upstream_client() {
10870 let request = client.request(proto::StopLanguageServers {
10871 project_id,
10872 buffer_ids: Vec::new(),
10873 also_servers: Vec::new(),
10874 all: true,
10875 });
10876 cx.background_spawn(async move {
10877 request.await.ok();
10878 })
10879 } else {
10880 let Some(local) = self.as_local_mut() else {
10881 return Task::ready(());
10882 };
10883 let language_servers_to_stop = local
10884 .language_server_ids
10885 .values()
10886 .map(|state| state.id)
10887 .collect();
10888 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10889 let tasks = language_servers_to_stop
10890 .into_iter()
10891 .map(|server| self.stop_local_language_server(server, cx))
10892 .collect::<Vec<_>>();
10893 cx.background_spawn(async move {
10894 futures::future::join_all(tasks).await;
10895 })
10896 }
10897 }
10898
10899 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10900 let buffers = self.buffer_store.read(cx).buffers().collect();
10901 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10902 }
10903
10904 pub fn restart_language_servers_for_buffers(
10905 &mut self,
10906 buffers: Vec<Entity<Buffer>>,
10907 only_restart_servers: HashSet<LanguageServerSelector>,
10908 cx: &mut Context<Self>,
10909 ) {
10910 if let Some((client, project_id)) = self.upstream_client() {
10911 let request = client.request(proto::RestartLanguageServers {
10912 project_id,
10913 buffer_ids: buffers
10914 .into_iter()
10915 .map(|b| b.read(cx).remote_id().to_proto())
10916 .collect(),
10917 only_servers: only_restart_servers
10918 .into_iter()
10919 .map(|selector| {
10920 let selector = match selector {
10921 LanguageServerSelector::Id(language_server_id) => {
10922 proto::language_server_selector::Selector::ServerId(
10923 language_server_id.to_proto(),
10924 )
10925 }
10926 LanguageServerSelector::Name(language_server_name) => {
10927 proto::language_server_selector::Selector::Name(
10928 language_server_name.to_string(),
10929 )
10930 }
10931 };
10932 proto::LanguageServerSelector {
10933 selector: Some(selector),
10934 }
10935 })
10936 .collect(),
10937 all: false,
10938 });
10939 cx.background_spawn(request).detach_and_log_err(cx);
10940 } else {
10941 let stop_task = if only_restart_servers.is_empty() {
10942 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10943 } else {
10944 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10945 };
10946 cx.spawn(async move |lsp_store, cx| {
10947 stop_task.await;
10948 lsp_store.update(cx, |lsp_store, cx| {
10949 for buffer in buffers {
10950 lsp_store.register_buffer_with_language_servers(
10951 &buffer,
10952 only_restart_servers.clone(),
10953 true,
10954 cx,
10955 );
10956 }
10957 })
10958 })
10959 .detach();
10960 }
10961 }
10962
10963 pub fn stop_language_servers_for_buffers(
10964 &mut self,
10965 buffers: Vec<Entity<Buffer>>,
10966 also_stop_servers: HashSet<LanguageServerSelector>,
10967 cx: &mut Context<Self>,
10968 ) -> Task<Result<()>> {
10969 if let Some((client, project_id)) = self.upstream_client() {
10970 let request = client.request(proto::StopLanguageServers {
10971 project_id,
10972 buffer_ids: buffers
10973 .into_iter()
10974 .map(|b| b.read(cx).remote_id().to_proto())
10975 .collect(),
10976 also_servers: also_stop_servers
10977 .into_iter()
10978 .map(|selector| {
10979 let selector = match selector {
10980 LanguageServerSelector::Id(language_server_id) => {
10981 proto::language_server_selector::Selector::ServerId(
10982 language_server_id.to_proto(),
10983 )
10984 }
10985 LanguageServerSelector::Name(language_server_name) => {
10986 proto::language_server_selector::Selector::Name(
10987 language_server_name.to_string(),
10988 )
10989 }
10990 };
10991 proto::LanguageServerSelector {
10992 selector: Some(selector),
10993 }
10994 })
10995 .collect(),
10996 all: false,
10997 });
10998 cx.background_spawn(async move {
10999 let _ = request.await?;
11000 Ok(())
11001 })
11002 } else {
11003 let task =
11004 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11005 cx.background_spawn(async move {
11006 task.await;
11007 Ok(())
11008 })
11009 }
11010 }
11011
11012 fn stop_local_language_servers_for_buffers(
11013 &mut self,
11014 buffers: &[Entity<Buffer>],
11015 also_stop_servers: HashSet<LanguageServerSelector>,
11016 cx: &mut Context<Self>,
11017 ) -> Task<()> {
11018 let Some(local) = self.as_local_mut() else {
11019 return Task::ready(());
11020 };
11021 let mut language_server_names_to_stop = BTreeSet::default();
11022 let mut language_servers_to_stop = also_stop_servers
11023 .into_iter()
11024 .flat_map(|selector| match selector {
11025 LanguageServerSelector::Id(id) => Some(id),
11026 LanguageServerSelector::Name(name) => {
11027 language_server_names_to_stop.insert(name);
11028 None
11029 }
11030 })
11031 .collect::<BTreeSet<_>>();
11032
11033 let mut covered_worktrees = HashSet::default();
11034 for buffer in buffers {
11035 buffer.update(cx, |buffer, cx| {
11036 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11037 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11038 && covered_worktrees.insert(worktree_id)
11039 {
11040 language_server_names_to_stop.retain(|name| {
11041 let old_ids_count = language_servers_to_stop.len();
11042 let all_language_servers_with_this_name = local
11043 .language_server_ids
11044 .iter()
11045 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11046 language_servers_to_stop.extend(all_language_servers_with_this_name);
11047 old_ids_count == language_servers_to_stop.len()
11048 });
11049 }
11050 });
11051 }
11052 for name in language_server_names_to_stop {
11053 language_servers_to_stop.extend(
11054 local
11055 .language_server_ids
11056 .iter()
11057 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11058 );
11059 }
11060
11061 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11062 let tasks = language_servers_to_stop
11063 .into_iter()
11064 .map(|server| self.stop_local_language_server(server, cx))
11065 .collect::<Vec<_>>();
11066
11067 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11068 }
11069
11070 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11071 let (worktree, relative_path) =
11072 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11073
11074 let project_path = ProjectPath {
11075 worktree_id: worktree.read(cx).id(),
11076 path: relative_path,
11077 };
11078
11079 Some(
11080 self.buffer_store()
11081 .read(cx)
11082 .get_by_path(&project_path)?
11083 .read(cx),
11084 )
11085 }
11086
11087 #[cfg(any(test, feature = "test-support"))]
11088 pub fn update_diagnostics(
11089 &mut self,
11090 server_id: LanguageServerId,
11091 diagnostics: lsp::PublishDiagnosticsParams,
11092 result_id: Option<SharedString>,
11093 source_kind: DiagnosticSourceKind,
11094 disk_based_sources: &[String],
11095 cx: &mut Context<Self>,
11096 ) -> Result<()> {
11097 self.merge_lsp_diagnostics(
11098 source_kind,
11099 vec![DocumentDiagnosticsUpdate {
11100 diagnostics,
11101 result_id,
11102 server_id,
11103 disk_based_sources: Cow::Borrowed(disk_based_sources),
11104 registration_id: None,
11105 }],
11106 |_, _, _| false,
11107 cx,
11108 )
11109 }
11110
11111 pub fn merge_lsp_diagnostics(
11112 &mut self,
11113 source_kind: DiagnosticSourceKind,
11114 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11115 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11116 cx: &mut Context<Self>,
11117 ) -> Result<()> {
11118 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11119 let updates = lsp_diagnostics
11120 .into_iter()
11121 .filter_map(|update| {
11122 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11123 Some(DocumentDiagnosticsUpdate {
11124 diagnostics: self.lsp_to_document_diagnostics(
11125 abs_path,
11126 source_kind,
11127 update.server_id,
11128 update.diagnostics,
11129 &update.disk_based_sources,
11130 update.registration_id.clone(),
11131 ),
11132 result_id: update.result_id,
11133 server_id: update.server_id,
11134 disk_based_sources: update.disk_based_sources,
11135 registration_id: update.registration_id,
11136 })
11137 })
11138 .collect();
11139 self.merge_diagnostic_entries(updates, merge, cx)?;
11140 Ok(())
11141 }
11142
11143 fn lsp_to_document_diagnostics(
11144 &mut self,
11145 document_abs_path: PathBuf,
11146 source_kind: DiagnosticSourceKind,
11147 server_id: LanguageServerId,
11148 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11149 disk_based_sources: &[String],
11150 registration_id: Option<SharedString>,
11151 ) -> DocumentDiagnostics {
11152 let mut diagnostics = Vec::default();
11153 let mut primary_diagnostic_group_ids = HashMap::default();
11154 let mut sources_by_group_id = HashMap::default();
11155 let mut supporting_diagnostics = HashMap::default();
11156
11157 let adapter = self.language_server_adapter_for_id(server_id);
11158
11159 // Ensure that primary diagnostics are always the most severe
11160 lsp_diagnostics
11161 .diagnostics
11162 .sort_by_key(|item| item.severity);
11163
11164 for diagnostic in &lsp_diagnostics.diagnostics {
11165 let source = diagnostic.source.as_ref();
11166 let range = range_from_lsp(diagnostic.range);
11167 let is_supporting = diagnostic
11168 .related_information
11169 .as_ref()
11170 .is_some_and(|infos| {
11171 infos.iter().any(|info| {
11172 primary_diagnostic_group_ids.contains_key(&(
11173 source,
11174 diagnostic.code.clone(),
11175 range_from_lsp(info.location.range),
11176 ))
11177 })
11178 });
11179
11180 let is_unnecessary = diagnostic
11181 .tags
11182 .as_ref()
11183 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11184
11185 let underline = self
11186 .language_server_adapter_for_id(server_id)
11187 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11188
11189 if is_supporting {
11190 supporting_diagnostics.insert(
11191 (source, diagnostic.code.clone(), range),
11192 (diagnostic.severity, is_unnecessary),
11193 );
11194 } else {
11195 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11196 let is_disk_based =
11197 source.is_some_and(|source| disk_based_sources.contains(source));
11198
11199 sources_by_group_id.insert(group_id, source);
11200 primary_diagnostic_group_ids
11201 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11202
11203 diagnostics.push(DiagnosticEntry {
11204 range,
11205 diagnostic: Diagnostic {
11206 source: diagnostic.source.clone(),
11207 source_kind,
11208 code: diagnostic.code.clone(),
11209 code_description: diagnostic
11210 .code_description
11211 .as_ref()
11212 .and_then(|d| d.href.clone()),
11213 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11214 markdown: adapter.as_ref().and_then(|adapter| {
11215 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11216 }),
11217 message: diagnostic.message.trim().to_string(),
11218 group_id,
11219 is_primary: true,
11220 is_disk_based,
11221 is_unnecessary,
11222 underline,
11223 data: diagnostic.data.clone(),
11224 registration_id: registration_id.clone(),
11225 },
11226 });
11227 if let Some(infos) = &diagnostic.related_information {
11228 for info in infos {
11229 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11230 let range = range_from_lsp(info.location.range);
11231 diagnostics.push(DiagnosticEntry {
11232 range,
11233 diagnostic: Diagnostic {
11234 source: diagnostic.source.clone(),
11235 source_kind,
11236 code: diagnostic.code.clone(),
11237 code_description: diagnostic
11238 .code_description
11239 .as_ref()
11240 .and_then(|d| d.href.clone()),
11241 severity: DiagnosticSeverity::INFORMATION,
11242 markdown: adapter.as_ref().and_then(|adapter| {
11243 adapter.diagnostic_message_to_markdown(&info.message)
11244 }),
11245 message: info.message.trim().to_string(),
11246 group_id,
11247 is_primary: false,
11248 is_disk_based,
11249 is_unnecessary: false,
11250 underline,
11251 data: diagnostic.data.clone(),
11252 registration_id: registration_id.clone(),
11253 },
11254 });
11255 }
11256 }
11257 }
11258 }
11259 }
11260
11261 for entry in &mut diagnostics {
11262 let diagnostic = &mut entry.diagnostic;
11263 if !diagnostic.is_primary {
11264 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11265 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11266 source,
11267 diagnostic.code.clone(),
11268 entry.range.clone(),
11269 )) {
11270 if let Some(severity) = severity {
11271 diagnostic.severity = severity;
11272 }
11273 diagnostic.is_unnecessary = is_unnecessary;
11274 }
11275 }
11276 }
11277
11278 DocumentDiagnostics {
11279 diagnostics,
11280 document_abs_path,
11281 version: lsp_diagnostics.version,
11282 }
11283 }
11284
11285 fn insert_newly_running_language_server(
11286 &mut self,
11287 adapter: Arc<CachedLspAdapter>,
11288 language_server: Arc<LanguageServer>,
11289 server_id: LanguageServerId,
11290 key: LanguageServerSeed,
11291 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11292 cx: &mut Context<Self>,
11293 ) {
11294 let Some(local) = self.as_local_mut() else {
11295 return;
11296 };
11297 // If the language server for this key doesn't match the server id, don't store the
11298 // server. Which will cause it to be dropped, killing the process
11299 if local
11300 .language_server_ids
11301 .get(&key)
11302 .map(|state| state.id != server_id)
11303 .unwrap_or(false)
11304 {
11305 return;
11306 }
11307
11308 // Update language_servers collection with Running variant of LanguageServerState
11309 // indicating that the server is up and running and ready
11310 let workspace_folders = workspace_folders.lock().clone();
11311 language_server.set_workspace_folders(workspace_folders);
11312
11313 let workspace_diagnostics_refresh_tasks = language_server
11314 .capabilities()
11315 .diagnostic_provider
11316 .and_then(|provider| {
11317 local
11318 .language_server_dynamic_registrations
11319 .entry(server_id)
11320 .or_default()
11321 .diagnostics
11322 .entry(None)
11323 .or_insert(provider.clone());
11324 let workspace_refresher =
11325 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11326
11327 Some((None, workspace_refresher))
11328 })
11329 .into_iter()
11330 .collect();
11331 local.language_servers.insert(
11332 server_id,
11333 LanguageServerState::Running {
11334 workspace_diagnostics_refresh_tasks,
11335 adapter: adapter.clone(),
11336 server: language_server.clone(),
11337 simulate_disk_based_diagnostics_completion: None,
11338 },
11339 );
11340 local
11341 .languages
11342 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11343 if let Some(file_ops_caps) = language_server
11344 .capabilities()
11345 .workspace
11346 .as_ref()
11347 .and_then(|ws| ws.file_operations.as_ref())
11348 {
11349 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11350 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11351 if did_rename_caps.or(will_rename_caps).is_some() {
11352 let watcher = RenamePathsWatchedForServer::default()
11353 .with_did_rename_patterns(did_rename_caps)
11354 .with_will_rename_patterns(will_rename_caps);
11355 local
11356 .language_server_paths_watched_for_rename
11357 .insert(server_id, watcher);
11358 }
11359 }
11360
11361 self.language_server_statuses.insert(
11362 server_id,
11363 LanguageServerStatus {
11364 name: language_server.name(),
11365 server_version: language_server.version(),
11366 server_readable_version: language_server.readable_version(),
11367 pending_work: Default::default(),
11368 has_pending_diagnostic_updates: false,
11369 progress_tokens: Default::default(),
11370 worktree: Some(key.worktree_id),
11371 binary: Some(language_server.binary().clone()),
11372 configuration: Some(language_server.configuration().clone()),
11373 workspace_folders: language_server.workspace_folders(),
11374 process_id: language_server.process_id(),
11375 },
11376 );
11377
11378 cx.emit(LspStoreEvent::LanguageServerAdded(
11379 server_id,
11380 language_server.name(),
11381 Some(key.worktree_id),
11382 ));
11383
11384 let server_capabilities = language_server.capabilities();
11385 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11386 downstream_client
11387 .send(proto::StartLanguageServer {
11388 project_id: *project_id,
11389 server: Some(proto::LanguageServer {
11390 id: server_id.to_proto(),
11391 name: language_server.name().to_string(),
11392 worktree_id: Some(key.worktree_id.to_proto()),
11393 }),
11394 capabilities: serde_json::to_string(&server_capabilities)
11395 .expect("serializing server LSP capabilities"),
11396 })
11397 .log_err();
11398 }
11399 self.lsp_server_capabilities
11400 .insert(server_id, server_capabilities);
11401
11402 // Tell the language server about every open buffer in the worktree that matches the language.
11403 // Also check for buffers in worktrees that reused this server
11404 let mut worktrees_using_server = vec![key.worktree_id];
11405 if let Some(local) = self.as_local() {
11406 // Find all worktrees that have this server in their language server tree
11407 for (worktree_id, servers) in &local.lsp_tree.instances {
11408 if *worktree_id != key.worktree_id {
11409 for server_map in servers.roots.values() {
11410 if server_map
11411 .values()
11412 .any(|(node, _)| node.id() == Some(server_id))
11413 {
11414 worktrees_using_server.push(*worktree_id);
11415 }
11416 }
11417 }
11418 }
11419 }
11420
11421 let mut buffer_paths_registered = Vec::new();
11422 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11423 let mut lsp_adapters = HashMap::default();
11424 for buffer_handle in buffer_store.buffers() {
11425 let buffer = buffer_handle.read(cx);
11426 let file = match File::from_dyn(buffer.file()) {
11427 Some(file) => file,
11428 None => continue,
11429 };
11430 let language = match buffer.language() {
11431 Some(language) => language,
11432 None => continue,
11433 };
11434
11435 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11436 || !lsp_adapters
11437 .entry(language.name())
11438 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11439 .iter()
11440 .any(|a| a.name == key.name)
11441 {
11442 continue;
11443 }
11444 // didOpen
11445 let file = match file.as_local() {
11446 Some(file) => file,
11447 None => continue,
11448 };
11449
11450 let local = self.as_local_mut().unwrap();
11451
11452 let buffer_id = buffer.remote_id();
11453 if local.registered_buffers.contains_key(&buffer_id) {
11454 let abs_path = file.abs_path(cx);
11455 let uri = match lsp::Uri::from_file_path(&abs_path) {
11456 Ok(uri) => uri,
11457 Err(()) => {
11458 log::error!("failed to convert path to URI: {:?}", abs_path);
11459 continue;
11460 }
11461 };
11462
11463 let versions = local
11464 .buffer_snapshots
11465 .entry(buffer_id)
11466 .or_default()
11467 .entry(server_id)
11468 .and_modify(|_| {
11469 assert!(
11470 false,
11471 "There should not be an existing snapshot for a newly inserted buffer"
11472 )
11473 })
11474 .or_insert_with(|| {
11475 vec![LspBufferSnapshot {
11476 version: 0,
11477 snapshot: buffer.text_snapshot(),
11478 }]
11479 });
11480
11481 let snapshot = versions.last().unwrap();
11482 let version = snapshot.version;
11483 let initial_snapshot = &snapshot.snapshot;
11484 language_server.register_buffer(
11485 uri,
11486 adapter.language_id(&language.name()),
11487 version,
11488 initial_snapshot.text(),
11489 );
11490 buffer_paths_registered.push((buffer_id, abs_path));
11491 local
11492 .buffers_opened_in_servers
11493 .entry(buffer_id)
11494 .or_default()
11495 .insert(server_id);
11496 }
11497 buffer_handle.update(cx, |buffer, cx| {
11498 buffer.set_completion_triggers(
11499 server_id,
11500 language_server
11501 .capabilities()
11502 .completion_provider
11503 .as_ref()
11504 .and_then(|provider| {
11505 provider
11506 .trigger_characters
11507 .as_ref()
11508 .map(|characters| characters.iter().cloned().collect())
11509 })
11510 .unwrap_or_default(),
11511 cx,
11512 )
11513 });
11514 }
11515 });
11516
11517 for (buffer_id, abs_path) in buffer_paths_registered {
11518 cx.emit(LspStoreEvent::LanguageServerUpdate {
11519 language_server_id: server_id,
11520 name: Some(adapter.name()),
11521 message: proto::update_language_server::Variant::RegisteredForBuffer(
11522 proto::RegisteredForBuffer {
11523 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11524 buffer_id: buffer_id.to_proto(),
11525 },
11526 ),
11527 });
11528 }
11529
11530 cx.notify();
11531 }
11532
11533 pub fn language_servers_running_disk_based_diagnostics(
11534 &self,
11535 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11536 self.language_server_statuses
11537 .iter()
11538 .filter_map(|(id, status)| {
11539 if status.has_pending_diagnostic_updates {
11540 Some(*id)
11541 } else {
11542 None
11543 }
11544 })
11545 }
11546
11547 pub(crate) fn cancel_language_server_work_for_buffers(
11548 &mut self,
11549 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11550 cx: &mut Context<Self>,
11551 ) {
11552 if let Some((client, project_id)) = self.upstream_client() {
11553 let request = client.request(proto::CancelLanguageServerWork {
11554 project_id,
11555 work: Some(proto::cancel_language_server_work::Work::Buffers(
11556 proto::cancel_language_server_work::Buffers {
11557 buffer_ids: buffers
11558 .into_iter()
11559 .map(|b| b.read(cx).remote_id().to_proto())
11560 .collect(),
11561 },
11562 )),
11563 });
11564 cx.background_spawn(request).detach_and_log_err(cx);
11565 } else if let Some(local) = self.as_local() {
11566 let servers = buffers
11567 .into_iter()
11568 .flat_map(|buffer| {
11569 buffer.update(cx, |buffer, cx| {
11570 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11571 })
11572 })
11573 .collect::<HashSet<_>>();
11574 for server_id in servers {
11575 self.cancel_language_server_work(server_id, None, cx);
11576 }
11577 }
11578 }
11579
11580 pub(crate) fn cancel_language_server_work(
11581 &mut self,
11582 server_id: LanguageServerId,
11583 token_to_cancel: Option<ProgressToken>,
11584 cx: &mut Context<Self>,
11585 ) {
11586 if let Some(local) = self.as_local() {
11587 let status = self.language_server_statuses.get(&server_id);
11588 let server = local.language_servers.get(&server_id);
11589 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11590 {
11591 for (token, progress) in &status.pending_work {
11592 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11593 && token != token_to_cancel
11594 {
11595 continue;
11596 }
11597 if progress.is_cancellable {
11598 server
11599 .notify::<lsp::notification::WorkDoneProgressCancel>(
11600 WorkDoneProgressCancelParams {
11601 token: token.to_lsp(),
11602 },
11603 )
11604 .ok();
11605 }
11606 }
11607 }
11608 } else if let Some((client, project_id)) = self.upstream_client() {
11609 let request = client.request(proto::CancelLanguageServerWork {
11610 project_id,
11611 work: Some(
11612 proto::cancel_language_server_work::Work::LanguageServerWork(
11613 proto::cancel_language_server_work::LanguageServerWork {
11614 language_server_id: server_id.to_proto(),
11615 token: token_to_cancel.map(|token| token.to_proto()),
11616 },
11617 ),
11618 ),
11619 });
11620 cx.background_spawn(request).detach_and_log_err(cx);
11621 }
11622 }
11623
11624 fn register_supplementary_language_server(
11625 &mut self,
11626 id: LanguageServerId,
11627 name: LanguageServerName,
11628 server: Arc<LanguageServer>,
11629 cx: &mut Context<Self>,
11630 ) {
11631 if let Some(local) = self.as_local_mut() {
11632 local
11633 .supplementary_language_servers
11634 .insert(id, (name.clone(), server));
11635 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11636 }
11637 }
11638
11639 fn unregister_supplementary_language_server(
11640 &mut self,
11641 id: LanguageServerId,
11642 cx: &mut Context<Self>,
11643 ) {
11644 if let Some(local) = self.as_local_mut() {
11645 local.supplementary_language_servers.remove(&id);
11646 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11647 }
11648 }
11649
11650 pub(crate) fn supplementary_language_servers(
11651 &self,
11652 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11653 self.as_local().into_iter().flat_map(|local| {
11654 local
11655 .supplementary_language_servers
11656 .iter()
11657 .map(|(id, (name, _))| (*id, name.clone()))
11658 })
11659 }
11660
11661 pub fn language_server_adapter_for_id(
11662 &self,
11663 id: LanguageServerId,
11664 ) -> Option<Arc<CachedLspAdapter>> {
11665 self.as_local()
11666 .and_then(|local| local.language_servers.get(&id))
11667 .and_then(|language_server_state| match language_server_state {
11668 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11669 _ => None,
11670 })
11671 }
11672
11673 pub(super) fn update_local_worktree_language_servers(
11674 &mut self,
11675 worktree_handle: &Entity<Worktree>,
11676 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11677 cx: &mut Context<Self>,
11678 ) {
11679 if changes.is_empty() {
11680 return;
11681 }
11682
11683 let Some(local) = self.as_local() else { return };
11684
11685 local.prettier_store.update(cx, |prettier_store, cx| {
11686 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11687 });
11688
11689 let worktree_id = worktree_handle.read(cx).id();
11690 let mut language_server_ids = local
11691 .language_server_ids
11692 .iter()
11693 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11694 .collect::<Vec<_>>();
11695 language_server_ids.sort();
11696 language_server_ids.dedup();
11697
11698 // let abs_path = worktree_handle.read(cx).abs_path();
11699 for server_id in &language_server_ids {
11700 if let Some(LanguageServerState::Running { server, .. }) =
11701 local.language_servers.get(server_id)
11702 && let Some(watched_paths) = local
11703 .language_server_watched_paths
11704 .get(server_id)
11705 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11706 {
11707 let params = lsp::DidChangeWatchedFilesParams {
11708 changes: changes
11709 .iter()
11710 .filter_map(|(path, _, change)| {
11711 if !watched_paths.is_match(path.as_std_path()) {
11712 return None;
11713 }
11714 let typ = match change {
11715 PathChange::Loaded => return None,
11716 PathChange::Added => lsp::FileChangeType::CREATED,
11717 PathChange::Removed => lsp::FileChangeType::DELETED,
11718 PathChange::Updated => lsp::FileChangeType::CHANGED,
11719 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11720 };
11721 let uri = lsp::Uri::from_file_path(
11722 worktree_handle.read(cx).absolutize(&path),
11723 )
11724 .ok()?;
11725 Some(lsp::FileEvent { uri, typ })
11726 })
11727 .collect(),
11728 };
11729 if !params.changes.is_empty() {
11730 server
11731 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11732 .ok();
11733 }
11734 }
11735 }
11736 for (path, _, _) in changes {
11737 if let Some(file_name) = path.file_name()
11738 && local.watched_manifest_filenames.contains(file_name)
11739 {
11740 self.request_workspace_config_refresh();
11741 break;
11742 }
11743 }
11744 }
11745
11746 pub fn wait_for_remote_buffer(
11747 &mut self,
11748 id: BufferId,
11749 cx: &mut Context<Self>,
11750 ) -> Task<Result<Entity<Buffer>>> {
11751 self.buffer_store.update(cx, |buffer_store, cx| {
11752 buffer_store.wait_for_remote_buffer(id, cx)
11753 })
11754 }
11755
11756 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11757 let mut result = proto::Symbol {
11758 language_server_name: symbol.language_server_name.0.to_string(),
11759 source_worktree_id: symbol.source_worktree_id.to_proto(),
11760 language_server_id: symbol.source_language_server_id.to_proto(),
11761 name: symbol.name.clone(),
11762 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11763 start: Some(proto::PointUtf16 {
11764 row: symbol.range.start.0.row,
11765 column: symbol.range.start.0.column,
11766 }),
11767 end: Some(proto::PointUtf16 {
11768 row: symbol.range.end.0.row,
11769 column: symbol.range.end.0.column,
11770 }),
11771 worktree_id: Default::default(),
11772 path: Default::default(),
11773 signature: Default::default(),
11774 container_name: symbol.container_name.clone(),
11775 };
11776 match &symbol.path {
11777 SymbolLocation::InProject(path) => {
11778 result.worktree_id = path.worktree_id.to_proto();
11779 result.path = path.path.to_proto();
11780 }
11781 SymbolLocation::OutsideProject {
11782 abs_path,
11783 signature,
11784 } => {
11785 result.path = abs_path.to_string_lossy().into_owned();
11786 result.signature = signature.to_vec();
11787 }
11788 }
11789 result
11790 }
11791
11792 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11793 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11794 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11795 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11796
11797 let path = if serialized_symbol.signature.is_empty() {
11798 SymbolLocation::InProject(ProjectPath {
11799 worktree_id,
11800 path: RelPath::from_proto(&serialized_symbol.path)
11801 .context("invalid symbol path")?,
11802 })
11803 } else {
11804 SymbolLocation::OutsideProject {
11805 abs_path: Path::new(&serialized_symbol.path).into(),
11806 signature: serialized_symbol
11807 .signature
11808 .try_into()
11809 .map_err(|_| anyhow!("invalid signature"))?,
11810 }
11811 };
11812
11813 let start = serialized_symbol.start.context("invalid start")?;
11814 let end = serialized_symbol.end.context("invalid end")?;
11815 Ok(CoreSymbol {
11816 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11817 source_worktree_id,
11818 source_language_server_id: LanguageServerId::from_proto(
11819 serialized_symbol.language_server_id,
11820 ),
11821 path,
11822 name: serialized_symbol.name,
11823 range: Unclipped(PointUtf16::new(start.row, start.column))
11824 ..Unclipped(PointUtf16::new(end.row, end.column)),
11825 kind,
11826 container_name: serialized_symbol.container_name,
11827 })
11828 }
11829
11830 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11831 let mut serialized_completion = proto::Completion {
11832 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11833 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11834 new_text: completion.new_text.clone(),
11835 ..proto::Completion::default()
11836 };
11837 match &completion.source {
11838 CompletionSource::Lsp {
11839 insert_range,
11840 server_id,
11841 lsp_completion,
11842 lsp_defaults,
11843 resolved,
11844 } => {
11845 let (old_insert_start, old_insert_end) = insert_range
11846 .as_ref()
11847 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11848 .unzip();
11849
11850 serialized_completion.old_insert_start = old_insert_start;
11851 serialized_completion.old_insert_end = old_insert_end;
11852 serialized_completion.source = proto::completion::Source::Lsp as i32;
11853 serialized_completion.server_id = server_id.0 as u64;
11854 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11855 serialized_completion.lsp_defaults = lsp_defaults
11856 .as_deref()
11857 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11858 serialized_completion.resolved = *resolved;
11859 }
11860 CompletionSource::BufferWord {
11861 word_range,
11862 resolved,
11863 } => {
11864 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11865 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11866 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11867 serialized_completion.resolved = *resolved;
11868 }
11869 CompletionSource::Custom => {
11870 serialized_completion.source = proto::completion::Source::Custom as i32;
11871 serialized_completion.resolved = true;
11872 }
11873 CompletionSource::Dap { sort_text } => {
11874 serialized_completion.source = proto::completion::Source::Dap as i32;
11875 serialized_completion.sort_text = Some(sort_text.clone());
11876 }
11877 }
11878
11879 serialized_completion
11880 }
11881
11882 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11883 let old_replace_start = completion
11884 .old_replace_start
11885 .and_then(deserialize_anchor)
11886 .context("invalid old start")?;
11887 let old_replace_end = completion
11888 .old_replace_end
11889 .and_then(deserialize_anchor)
11890 .context("invalid old end")?;
11891 let insert_range = {
11892 match completion.old_insert_start.zip(completion.old_insert_end) {
11893 Some((start, end)) => {
11894 let start = deserialize_anchor(start).context("invalid insert old start")?;
11895 let end = deserialize_anchor(end).context("invalid insert old end")?;
11896 Some(start..end)
11897 }
11898 None => None,
11899 }
11900 };
11901 Ok(CoreCompletion {
11902 replace_range: old_replace_start..old_replace_end,
11903 new_text: completion.new_text,
11904 source: match proto::completion::Source::from_i32(completion.source) {
11905 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11906 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11907 insert_range,
11908 server_id: LanguageServerId::from_proto(completion.server_id),
11909 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11910 lsp_defaults: completion
11911 .lsp_defaults
11912 .as_deref()
11913 .map(serde_json::from_slice)
11914 .transpose()?,
11915 resolved: completion.resolved,
11916 },
11917 Some(proto::completion::Source::BufferWord) => {
11918 let word_range = completion
11919 .buffer_word_start
11920 .and_then(deserialize_anchor)
11921 .context("invalid buffer word start")?
11922 ..completion
11923 .buffer_word_end
11924 .and_then(deserialize_anchor)
11925 .context("invalid buffer word end")?;
11926 CompletionSource::BufferWord {
11927 word_range,
11928 resolved: completion.resolved,
11929 }
11930 }
11931 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11932 sort_text: completion
11933 .sort_text
11934 .context("expected sort text to exist")?,
11935 },
11936 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11937 },
11938 })
11939 }
11940
11941 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11942 let (kind, lsp_action) = match &action.lsp_action {
11943 LspAction::Action(code_action) => (
11944 proto::code_action::Kind::Action as i32,
11945 serde_json::to_vec(code_action).unwrap(),
11946 ),
11947 LspAction::Command(command) => (
11948 proto::code_action::Kind::Command as i32,
11949 serde_json::to_vec(command).unwrap(),
11950 ),
11951 LspAction::CodeLens(code_lens) => (
11952 proto::code_action::Kind::CodeLens as i32,
11953 serde_json::to_vec(code_lens).unwrap(),
11954 ),
11955 };
11956
11957 proto::CodeAction {
11958 server_id: action.server_id.0 as u64,
11959 start: Some(serialize_anchor(&action.range.start)),
11960 end: Some(serialize_anchor(&action.range.end)),
11961 lsp_action,
11962 kind,
11963 resolved: action.resolved,
11964 }
11965 }
11966
11967 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11968 let start = action
11969 .start
11970 .and_then(deserialize_anchor)
11971 .context("invalid start")?;
11972 let end = action
11973 .end
11974 .and_then(deserialize_anchor)
11975 .context("invalid end")?;
11976 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11977 Some(proto::code_action::Kind::Action) => {
11978 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11979 }
11980 Some(proto::code_action::Kind::Command) => {
11981 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11982 }
11983 Some(proto::code_action::Kind::CodeLens) => {
11984 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11985 }
11986 None => anyhow::bail!("Unknown action kind {}", action.kind),
11987 };
11988 Ok(CodeAction {
11989 server_id: LanguageServerId(action.server_id as usize),
11990 range: start..end,
11991 resolved: action.resolved,
11992 lsp_action,
11993 })
11994 }
11995
11996 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11997 match &formatting_result {
11998 Ok(_) => self.last_formatting_failure = None,
11999 Err(error) => {
12000 let error_string = format!("{error:#}");
12001 log::error!("Formatting failed: {error_string}");
12002 self.last_formatting_failure
12003 .replace(error_string.lines().join(" "));
12004 }
12005 }
12006 }
12007
12008 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12009 self.lsp_server_capabilities.remove(&for_server);
12010 self.semantic_token_config.remove_server_data(for_server);
12011 for lsp_data in self.lsp_data.values_mut() {
12012 lsp_data.remove_server_data(for_server);
12013 }
12014 if let Some(local) = self.as_local_mut() {
12015 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12016 local
12017 .workspace_pull_diagnostics_result_ids
12018 .remove(&for_server);
12019 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12020 buffer_servers.remove(&for_server);
12021 }
12022 }
12023 }
12024
12025 pub fn result_id_for_buffer_pull(
12026 &self,
12027 server_id: LanguageServerId,
12028 buffer_id: BufferId,
12029 registration_id: &Option<SharedString>,
12030 cx: &App,
12031 ) -> Option<SharedString> {
12032 let abs_path = self
12033 .buffer_store
12034 .read(cx)
12035 .get(buffer_id)
12036 .and_then(|b| File::from_dyn(b.read(cx).file()))
12037 .map(|f| f.abs_path(cx))?;
12038 self.as_local()?
12039 .buffer_pull_diagnostics_result_ids
12040 .get(&server_id)?
12041 .get(registration_id)?
12042 .get(&abs_path)?
12043 .clone()
12044 }
12045
12046 /// Gets all result_ids for a workspace diagnostics pull request.
12047 /// 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.
12048 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12049 pub fn result_ids_for_workspace_refresh(
12050 &self,
12051 server_id: LanguageServerId,
12052 registration_id: &Option<SharedString>,
12053 ) -> HashMap<PathBuf, SharedString> {
12054 let Some(local) = self.as_local() else {
12055 return HashMap::default();
12056 };
12057 local
12058 .workspace_pull_diagnostics_result_ids
12059 .get(&server_id)
12060 .into_iter()
12061 .filter_map(|diagnostics| diagnostics.get(registration_id))
12062 .flatten()
12063 .filter_map(|(abs_path, result_id)| {
12064 let result_id = local
12065 .buffer_pull_diagnostics_result_ids
12066 .get(&server_id)
12067 .and_then(|buffer_ids_result_ids| {
12068 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12069 })
12070 .cloned()
12071 .flatten()
12072 .or_else(|| result_id.clone())?;
12073 Some((abs_path.clone(), result_id))
12074 })
12075 .collect()
12076 }
12077
12078 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12079 if let Some(LanguageServerState::Running {
12080 workspace_diagnostics_refresh_tasks,
12081 ..
12082 }) = self
12083 .as_local_mut()
12084 .and_then(|local| local.language_servers.get_mut(&server_id))
12085 {
12086 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12087 diagnostics.refresh_tx.try_send(()).ok();
12088 }
12089 }
12090 }
12091
12092 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12093 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12094 /// which requires refreshing both workspace and document diagnostics.
12095 pub fn pull_document_diagnostics_for_server(
12096 &mut self,
12097 server_id: LanguageServerId,
12098 source_buffer_id: Option<BufferId>,
12099 cx: &mut Context<Self>,
12100 ) -> Shared<Task<()>> {
12101 let Some(local) = self.as_local_mut() else {
12102 return Task::ready(()).shared();
12103 };
12104 let mut buffers_to_refresh = HashSet::default();
12105 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12106 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12107 buffers_to_refresh.insert(*buffer_id);
12108 }
12109 }
12110
12111 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12112 }
12113
12114 pub fn pull_document_diagnostics_for_buffer_edit(
12115 &mut self,
12116 buffer_id: BufferId,
12117 cx: &mut Context<Self>,
12118 ) {
12119 let Some(local) = self.as_local_mut() else {
12120 return;
12121 };
12122 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12123 else {
12124 return;
12125 };
12126 for server_id in languages_servers {
12127 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12128 }
12129 }
12130
12131 fn apply_workspace_diagnostic_report(
12132 &mut self,
12133 server_id: LanguageServerId,
12134 report: lsp::WorkspaceDiagnosticReportResult,
12135 registration_id: Option<SharedString>,
12136 cx: &mut Context<Self>,
12137 ) {
12138 let mut workspace_diagnostics =
12139 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12140 report,
12141 server_id,
12142 registration_id,
12143 );
12144 workspace_diagnostics.retain(|d| match &d.diagnostics {
12145 LspPullDiagnostics::Response {
12146 server_id,
12147 registration_id,
12148 ..
12149 } => self.diagnostic_registration_exists(*server_id, registration_id),
12150 LspPullDiagnostics::Default => false,
12151 });
12152 let mut unchanged_buffers = HashMap::default();
12153 let workspace_diagnostics_updates = workspace_diagnostics
12154 .into_iter()
12155 .filter_map(
12156 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12157 LspPullDiagnostics::Response {
12158 server_id,
12159 uri,
12160 diagnostics,
12161 registration_id,
12162 } => Some((
12163 server_id,
12164 uri,
12165 diagnostics,
12166 workspace_diagnostics.version,
12167 registration_id,
12168 )),
12169 LspPullDiagnostics::Default => None,
12170 },
12171 )
12172 .fold(
12173 HashMap::default(),
12174 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12175 let (result_id, diagnostics) = match diagnostics {
12176 PulledDiagnostics::Unchanged { result_id } => {
12177 unchanged_buffers
12178 .entry(new_registration_id.clone())
12179 .or_insert_with(HashSet::default)
12180 .insert(uri.clone());
12181 (Some(result_id), Vec::new())
12182 }
12183 PulledDiagnostics::Changed {
12184 result_id,
12185 diagnostics,
12186 } => (result_id, diagnostics),
12187 };
12188 let disk_based_sources = Cow::Owned(
12189 self.language_server_adapter_for_id(server_id)
12190 .as_ref()
12191 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12192 .unwrap_or(&[])
12193 .to_vec(),
12194 );
12195
12196 let Some(abs_path) = uri.to_file_path().ok() else {
12197 return acc;
12198 };
12199 let Some((worktree, relative_path)) =
12200 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12201 else {
12202 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12203 return acc;
12204 };
12205 let worktree_id = worktree.read(cx).id();
12206 let project_path = ProjectPath {
12207 worktree_id,
12208 path: relative_path,
12209 };
12210 if let Some(local_lsp_store) = self.as_local_mut() {
12211 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12212 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12213 }
12214 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12215 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12216 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12217 acc.entry(server_id)
12218 .or_insert_with(HashMap::default)
12219 .entry(new_registration_id.clone())
12220 .or_insert_with(Vec::new)
12221 .push(DocumentDiagnosticsUpdate {
12222 server_id,
12223 diagnostics: lsp::PublishDiagnosticsParams {
12224 uri,
12225 diagnostics,
12226 version,
12227 },
12228 result_id: result_id.map(SharedString::new),
12229 disk_based_sources,
12230 registration_id: new_registration_id,
12231 });
12232 }
12233 acc
12234 },
12235 );
12236
12237 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12238 for (registration_id, diagnostic_updates) in diagnostic_updates {
12239 self.merge_lsp_diagnostics(
12240 DiagnosticSourceKind::Pulled,
12241 diagnostic_updates,
12242 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12243 DiagnosticSourceKind::Pulled => {
12244 old_diagnostic.registration_id != registration_id
12245 || unchanged_buffers
12246 .get(&old_diagnostic.registration_id)
12247 .is_some_and(|unchanged_buffers| {
12248 unchanged_buffers.contains(&document_uri)
12249 })
12250 }
12251 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12252 },
12253 cx,
12254 )
12255 .log_err();
12256 }
12257 }
12258 }
12259
12260 fn register_server_capabilities(
12261 &mut self,
12262 server_id: LanguageServerId,
12263 params: lsp::RegistrationParams,
12264 cx: &mut Context<Self>,
12265 ) -> anyhow::Result<()> {
12266 let server = self
12267 .language_server_for_id(server_id)
12268 .with_context(|| format!("no server {server_id} found"))?;
12269 for reg in params.registrations {
12270 match reg.method.as_str() {
12271 "workspace/didChangeWatchedFiles" => {
12272 if let Some(options) = reg.register_options {
12273 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12274 let caps = serde_json::from_value(options)?;
12275 local_lsp_store
12276 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12277 true
12278 } else {
12279 false
12280 };
12281 if notify {
12282 notify_server_capabilities_updated(&server, cx);
12283 }
12284 }
12285 }
12286 "workspace/didChangeConfiguration" => {
12287 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12288 }
12289 "workspace/didChangeWorkspaceFolders" => {
12290 // In this case register options is an empty object, we can ignore it
12291 let caps = lsp::WorkspaceFoldersServerCapabilities {
12292 supported: Some(true),
12293 change_notifications: Some(OneOf::Right(reg.id)),
12294 };
12295 server.update_capabilities(|capabilities| {
12296 capabilities
12297 .workspace
12298 .get_or_insert_default()
12299 .workspace_folders = Some(caps);
12300 });
12301 notify_server_capabilities_updated(&server, cx);
12302 }
12303 "workspace/symbol" => {
12304 let options = parse_register_capabilities(reg)?;
12305 server.update_capabilities(|capabilities| {
12306 capabilities.workspace_symbol_provider = Some(options);
12307 });
12308 notify_server_capabilities_updated(&server, cx);
12309 }
12310 "workspace/fileOperations" => {
12311 if let Some(options) = reg.register_options {
12312 let caps = serde_json::from_value(options)?;
12313 server.update_capabilities(|capabilities| {
12314 capabilities
12315 .workspace
12316 .get_or_insert_default()
12317 .file_operations = Some(caps);
12318 });
12319 notify_server_capabilities_updated(&server, cx);
12320 }
12321 }
12322 "workspace/executeCommand" => {
12323 if let Some(options) = reg.register_options {
12324 let options = serde_json::from_value(options)?;
12325 server.update_capabilities(|capabilities| {
12326 capabilities.execute_command_provider = Some(options);
12327 });
12328 notify_server_capabilities_updated(&server, cx);
12329 }
12330 }
12331 "textDocument/rangeFormatting" => {
12332 let options = parse_register_capabilities(reg)?;
12333 server.update_capabilities(|capabilities| {
12334 capabilities.document_range_formatting_provider = Some(options);
12335 });
12336 notify_server_capabilities_updated(&server, cx);
12337 }
12338 "textDocument/onTypeFormatting" => {
12339 if let Some(options) = reg
12340 .register_options
12341 .map(serde_json::from_value)
12342 .transpose()?
12343 {
12344 server.update_capabilities(|capabilities| {
12345 capabilities.document_on_type_formatting_provider = Some(options);
12346 });
12347 notify_server_capabilities_updated(&server, cx);
12348 }
12349 }
12350 "textDocument/formatting" => {
12351 let options = parse_register_capabilities(reg)?;
12352 server.update_capabilities(|capabilities| {
12353 capabilities.document_formatting_provider = Some(options);
12354 });
12355 notify_server_capabilities_updated(&server, cx);
12356 }
12357 "textDocument/rename" => {
12358 let options = parse_register_capabilities(reg)?;
12359 server.update_capabilities(|capabilities| {
12360 capabilities.rename_provider = Some(options);
12361 });
12362 notify_server_capabilities_updated(&server, cx);
12363 }
12364 "textDocument/inlayHint" => {
12365 let options = parse_register_capabilities(reg)?;
12366 server.update_capabilities(|capabilities| {
12367 capabilities.inlay_hint_provider = Some(options);
12368 });
12369 notify_server_capabilities_updated(&server, cx);
12370 }
12371 "textDocument/documentSymbol" => {
12372 let options = parse_register_capabilities(reg)?;
12373 server.update_capabilities(|capabilities| {
12374 capabilities.document_symbol_provider = Some(options);
12375 });
12376 notify_server_capabilities_updated(&server, cx);
12377 }
12378 "textDocument/codeAction" => {
12379 let options = parse_register_capabilities(reg)?;
12380 let provider = match options {
12381 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12382 OneOf::Right(caps) => caps,
12383 };
12384 server.update_capabilities(|capabilities| {
12385 capabilities.code_action_provider = Some(provider);
12386 });
12387 notify_server_capabilities_updated(&server, cx);
12388 }
12389 "textDocument/definition" => {
12390 let options = parse_register_capabilities(reg)?;
12391 server.update_capabilities(|capabilities| {
12392 capabilities.definition_provider = Some(options);
12393 });
12394 notify_server_capabilities_updated(&server, cx);
12395 }
12396 "textDocument/completion" => {
12397 if let Some(caps) = reg
12398 .register_options
12399 .map(serde_json::from_value::<CompletionOptions>)
12400 .transpose()?
12401 {
12402 server.update_capabilities(|capabilities| {
12403 capabilities.completion_provider = Some(caps.clone());
12404 });
12405
12406 if let Some(local) = self.as_local() {
12407 let mut buffers_with_language_server = Vec::new();
12408 for handle in self.buffer_store.read(cx).buffers() {
12409 let buffer_id = handle.read(cx).remote_id();
12410 if local
12411 .buffers_opened_in_servers
12412 .get(&buffer_id)
12413 .filter(|s| s.contains(&server_id))
12414 .is_some()
12415 {
12416 buffers_with_language_server.push(handle);
12417 }
12418 }
12419 let triggers = caps
12420 .trigger_characters
12421 .unwrap_or_default()
12422 .into_iter()
12423 .collect::<BTreeSet<_>>();
12424 for handle in buffers_with_language_server {
12425 let triggers = triggers.clone();
12426 let _ = handle.update(cx, move |buffer, cx| {
12427 buffer.set_completion_triggers(server_id, triggers, cx);
12428 });
12429 }
12430 }
12431 notify_server_capabilities_updated(&server, cx);
12432 }
12433 }
12434 "textDocument/hover" => {
12435 let options = parse_register_capabilities(reg)?;
12436 let provider = match options {
12437 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12438 OneOf::Right(caps) => caps,
12439 };
12440 server.update_capabilities(|capabilities| {
12441 capabilities.hover_provider = Some(provider);
12442 });
12443 notify_server_capabilities_updated(&server, cx);
12444 }
12445 "textDocument/signatureHelp" => {
12446 if let Some(caps) = reg
12447 .register_options
12448 .map(serde_json::from_value)
12449 .transpose()?
12450 {
12451 server.update_capabilities(|capabilities| {
12452 capabilities.signature_help_provider = Some(caps);
12453 });
12454 notify_server_capabilities_updated(&server, cx);
12455 }
12456 }
12457 "textDocument/didChange" => {
12458 if let Some(sync_kind) = reg
12459 .register_options
12460 .and_then(|opts| opts.get("syncKind").cloned())
12461 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12462 .transpose()?
12463 {
12464 server.update_capabilities(|capabilities| {
12465 let mut sync_options =
12466 Self::take_text_document_sync_options(capabilities);
12467 sync_options.change = Some(sync_kind);
12468 capabilities.text_document_sync =
12469 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12470 });
12471 notify_server_capabilities_updated(&server, cx);
12472 }
12473 }
12474 "textDocument/didSave" => {
12475 if let Some(include_text) = reg
12476 .register_options
12477 .map(|opts| {
12478 let transpose = opts
12479 .get("includeText")
12480 .cloned()
12481 .map(serde_json::from_value::<Option<bool>>)
12482 .transpose();
12483 match transpose {
12484 Ok(value) => Ok(value.flatten()),
12485 Err(e) => Err(e),
12486 }
12487 })
12488 .transpose()?
12489 {
12490 server.update_capabilities(|capabilities| {
12491 let mut sync_options =
12492 Self::take_text_document_sync_options(capabilities);
12493 sync_options.save =
12494 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12495 include_text,
12496 }));
12497 capabilities.text_document_sync =
12498 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12499 });
12500 notify_server_capabilities_updated(&server, cx);
12501 }
12502 }
12503 "textDocument/codeLens" => {
12504 if let Some(caps) = reg
12505 .register_options
12506 .map(serde_json::from_value)
12507 .transpose()?
12508 {
12509 server.update_capabilities(|capabilities| {
12510 capabilities.code_lens_provider = Some(caps);
12511 });
12512 notify_server_capabilities_updated(&server, cx);
12513 }
12514 }
12515 "textDocument/diagnostic" => {
12516 if let Some(caps) = reg
12517 .register_options
12518 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12519 .transpose()?
12520 {
12521 let local = self
12522 .as_local_mut()
12523 .context("Expected LSP Store to be local")?;
12524 let state = local
12525 .language_servers
12526 .get_mut(&server_id)
12527 .context("Could not obtain Language Servers state")?;
12528 local
12529 .language_server_dynamic_registrations
12530 .entry(server_id)
12531 .or_default()
12532 .diagnostics
12533 .insert(Some(reg.id.clone()), caps.clone());
12534
12535 let supports_workspace_diagnostics =
12536 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12537 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12538 diagnostic_options.workspace_diagnostics
12539 }
12540 DiagnosticServerCapabilities::RegistrationOptions(
12541 diagnostic_registration_options,
12542 ) => {
12543 diagnostic_registration_options
12544 .diagnostic_options
12545 .workspace_diagnostics
12546 }
12547 };
12548
12549 if supports_workspace_diagnostics(&caps) {
12550 if let LanguageServerState::Running {
12551 workspace_diagnostics_refresh_tasks,
12552 ..
12553 } = state
12554 && let Some(task) = lsp_workspace_diagnostics_refresh(
12555 Some(reg.id.clone()),
12556 caps.clone(),
12557 server.clone(),
12558 cx,
12559 )
12560 {
12561 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12562 }
12563 }
12564
12565 server.update_capabilities(|capabilities| {
12566 capabilities.diagnostic_provider = Some(caps);
12567 });
12568
12569 notify_server_capabilities_updated(&server, cx);
12570
12571 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12572 }
12573 }
12574 "textDocument/documentColor" => {
12575 let options = parse_register_capabilities(reg)?;
12576 let provider = match options {
12577 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12578 OneOf::Right(caps) => caps,
12579 };
12580 server.update_capabilities(|capabilities| {
12581 capabilities.color_provider = Some(provider);
12582 });
12583 notify_server_capabilities_updated(&server, cx);
12584 }
12585 "textDocument/foldingRange" => {
12586 let options = parse_register_capabilities(reg)?;
12587 let provider = match options {
12588 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12589 OneOf::Right(caps) => caps,
12590 };
12591 server.update_capabilities(|capabilities| {
12592 capabilities.folding_range_provider = Some(provider);
12593 });
12594 notify_server_capabilities_updated(&server, cx);
12595 }
12596 _ => log::warn!("unhandled capability registration: {reg:?}"),
12597 }
12598 }
12599
12600 Ok(())
12601 }
12602
12603 fn unregister_server_capabilities(
12604 &mut self,
12605 server_id: LanguageServerId,
12606 params: lsp::UnregistrationParams,
12607 cx: &mut Context<Self>,
12608 ) -> anyhow::Result<()> {
12609 let server = self
12610 .language_server_for_id(server_id)
12611 .with_context(|| format!("no server {server_id} found"))?;
12612 for unreg in params.unregisterations.iter() {
12613 match unreg.method.as_str() {
12614 "workspace/didChangeWatchedFiles" => {
12615 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12616 local_lsp_store
12617 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12618 true
12619 } else {
12620 false
12621 };
12622 if notify {
12623 notify_server_capabilities_updated(&server, cx);
12624 }
12625 }
12626 "workspace/didChangeConfiguration" => {
12627 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12628 }
12629 "workspace/didChangeWorkspaceFolders" => {
12630 server.update_capabilities(|capabilities| {
12631 capabilities
12632 .workspace
12633 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12634 workspace_folders: None,
12635 file_operations: None,
12636 })
12637 .workspace_folders = None;
12638 });
12639 notify_server_capabilities_updated(&server, cx);
12640 }
12641 "workspace/symbol" => {
12642 server.update_capabilities(|capabilities| {
12643 capabilities.workspace_symbol_provider = None
12644 });
12645 notify_server_capabilities_updated(&server, cx);
12646 }
12647 "workspace/fileOperations" => {
12648 server.update_capabilities(|capabilities| {
12649 capabilities
12650 .workspace
12651 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12652 workspace_folders: None,
12653 file_operations: None,
12654 })
12655 .file_operations = None;
12656 });
12657 notify_server_capabilities_updated(&server, cx);
12658 }
12659 "workspace/executeCommand" => {
12660 server.update_capabilities(|capabilities| {
12661 capabilities.execute_command_provider = None;
12662 });
12663 notify_server_capabilities_updated(&server, cx);
12664 }
12665 "textDocument/rangeFormatting" => {
12666 server.update_capabilities(|capabilities| {
12667 capabilities.document_range_formatting_provider = None
12668 });
12669 notify_server_capabilities_updated(&server, cx);
12670 }
12671 "textDocument/onTypeFormatting" => {
12672 server.update_capabilities(|capabilities| {
12673 capabilities.document_on_type_formatting_provider = None;
12674 });
12675 notify_server_capabilities_updated(&server, cx);
12676 }
12677 "textDocument/formatting" => {
12678 server.update_capabilities(|capabilities| {
12679 capabilities.document_formatting_provider = None;
12680 });
12681 notify_server_capabilities_updated(&server, cx);
12682 }
12683 "textDocument/rename" => {
12684 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12685 notify_server_capabilities_updated(&server, cx);
12686 }
12687 "textDocument/codeAction" => {
12688 server.update_capabilities(|capabilities| {
12689 capabilities.code_action_provider = None;
12690 });
12691 notify_server_capabilities_updated(&server, cx);
12692 }
12693 "textDocument/definition" => {
12694 server.update_capabilities(|capabilities| {
12695 capabilities.definition_provider = None;
12696 });
12697 notify_server_capabilities_updated(&server, cx);
12698 }
12699 "textDocument/completion" => {
12700 server.update_capabilities(|capabilities| {
12701 capabilities.completion_provider = None;
12702 });
12703 notify_server_capabilities_updated(&server, cx);
12704 }
12705 "textDocument/hover" => {
12706 server.update_capabilities(|capabilities| {
12707 capabilities.hover_provider = None;
12708 });
12709 notify_server_capabilities_updated(&server, cx);
12710 }
12711 "textDocument/signatureHelp" => {
12712 server.update_capabilities(|capabilities| {
12713 capabilities.signature_help_provider = None;
12714 });
12715 notify_server_capabilities_updated(&server, cx);
12716 }
12717 "textDocument/didChange" => {
12718 server.update_capabilities(|capabilities| {
12719 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12720 sync_options.change = None;
12721 capabilities.text_document_sync =
12722 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12723 });
12724 notify_server_capabilities_updated(&server, cx);
12725 }
12726 "textDocument/didSave" => {
12727 server.update_capabilities(|capabilities| {
12728 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12729 sync_options.save = None;
12730 capabilities.text_document_sync =
12731 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12732 });
12733 notify_server_capabilities_updated(&server, cx);
12734 }
12735 "textDocument/codeLens" => {
12736 server.update_capabilities(|capabilities| {
12737 capabilities.code_lens_provider = None;
12738 });
12739 notify_server_capabilities_updated(&server, cx);
12740 }
12741 "textDocument/diagnostic" => {
12742 let local = self
12743 .as_local_mut()
12744 .context("Expected LSP Store to be local")?;
12745
12746 let state = local
12747 .language_servers
12748 .get_mut(&server_id)
12749 .context("Could not obtain Language Servers state")?;
12750 let registrations = local
12751 .language_server_dynamic_registrations
12752 .get_mut(&server_id)
12753 .with_context(|| {
12754 format!("Expected dynamic registration to exist for server {server_id}")
12755 })?;
12756 registrations.diagnostics
12757 .remove(&Some(unreg.id.clone()))
12758 .with_context(|| format!(
12759 "Attempted to unregister non-existent diagnostic registration with ID {}",
12760 unreg.id)
12761 )?;
12762 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12763
12764 if let LanguageServerState::Running {
12765 workspace_diagnostics_refresh_tasks,
12766 ..
12767 } = state
12768 {
12769 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12770 }
12771
12772 self.clear_unregistered_diagnostics(
12773 server_id,
12774 SharedString::from(unreg.id.clone()),
12775 cx,
12776 )?;
12777
12778 if removed_last_diagnostic_provider {
12779 server.update_capabilities(|capabilities| {
12780 debug_assert!(capabilities.diagnostic_provider.is_some());
12781 capabilities.diagnostic_provider = None;
12782 });
12783 }
12784
12785 notify_server_capabilities_updated(&server, cx);
12786 }
12787 "textDocument/documentColor" => {
12788 server.update_capabilities(|capabilities| {
12789 capabilities.color_provider = None;
12790 });
12791 notify_server_capabilities_updated(&server, cx);
12792 }
12793 "textDocument/foldingRange" => {
12794 server.update_capabilities(|capabilities| {
12795 capabilities.folding_range_provider = None;
12796 });
12797 notify_server_capabilities_updated(&server, cx);
12798 }
12799 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12800 }
12801 }
12802
12803 Ok(())
12804 }
12805
12806 fn clear_unregistered_diagnostics(
12807 &mut self,
12808 server_id: LanguageServerId,
12809 cleared_registration_id: SharedString,
12810 cx: &mut Context<Self>,
12811 ) -> anyhow::Result<()> {
12812 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12813
12814 self.buffer_store.update(cx, |buffer_store, cx| {
12815 for buffer_handle in buffer_store.buffers() {
12816 let buffer = buffer_handle.read(cx);
12817 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12818 let Some(abs_path) = abs_path else {
12819 continue;
12820 };
12821 affected_abs_paths.insert(abs_path);
12822 }
12823 });
12824
12825 let local = self.as_local().context("Expected LSP Store to be local")?;
12826 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12827 let Some(worktree) = self
12828 .worktree_store
12829 .read(cx)
12830 .worktree_for_id(*worktree_id, cx)
12831 else {
12832 continue;
12833 };
12834
12835 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12836 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12837 let has_matching_registration =
12838 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12839 entry.diagnostic.registration_id.as_ref()
12840 == Some(&cleared_registration_id)
12841 });
12842 if has_matching_registration {
12843 let abs_path = worktree.read(cx).absolutize(rel_path);
12844 affected_abs_paths.insert(abs_path);
12845 }
12846 }
12847 }
12848 }
12849
12850 if affected_abs_paths.is_empty() {
12851 return Ok(());
12852 }
12853
12854 // Send a fake diagnostic update which clears the state for the registration ID
12855 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12856 affected_abs_paths
12857 .into_iter()
12858 .map(|abs_path| DocumentDiagnosticsUpdate {
12859 diagnostics: DocumentDiagnostics {
12860 diagnostics: Vec::new(),
12861 document_abs_path: abs_path,
12862 version: None,
12863 },
12864 result_id: None,
12865 registration_id: Some(cleared_registration_id.clone()),
12866 server_id,
12867 disk_based_sources: Cow::Borrowed(&[]),
12868 })
12869 .collect();
12870
12871 let merge_registration_id = cleared_registration_id.clone();
12872 self.merge_diagnostic_entries(
12873 clears,
12874 move |_, diagnostic, _| {
12875 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12876 diagnostic.registration_id != Some(merge_registration_id.clone())
12877 } else {
12878 true
12879 }
12880 },
12881 cx,
12882 )?;
12883
12884 Ok(())
12885 }
12886
12887 async fn deduplicate_range_based_lsp_requests<T>(
12888 lsp_store: &Entity<Self>,
12889 server_id: Option<LanguageServerId>,
12890 lsp_request_id: LspRequestId,
12891 proto_request: &T::ProtoRequest,
12892 range: Range<Anchor>,
12893 cx: &mut AsyncApp,
12894 ) -> Result<()>
12895 where
12896 T: LspCommand,
12897 T::ProtoRequest: proto::LspRequestMessage,
12898 {
12899 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12900 let version = deserialize_version(proto_request.buffer_version());
12901 let buffer = lsp_store.update(cx, |this, cx| {
12902 this.buffer_store.read(cx).get_existing(buffer_id)
12903 })?;
12904 buffer
12905 .update(cx, |buffer, _| buffer.wait_for_version(version))
12906 .await?;
12907 lsp_store.update(cx, |lsp_store, cx| {
12908 let buffer_snapshot = buffer.read(cx).snapshot();
12909 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12910 let chunks_queried_for = lsp_data
12911 .inlay_hints
12912 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12913 .collect::<Vec<_>>();
12914 match chunks_queried_for.as_slice() {
12915 &[chunk] => {
12916 let key = LspKey {
12917 request_type: TypeId::of::<T>(),
12918 server_queried: server_id,
12919 };
12920 let previous_request = lsp_data
12921 .chunk_lsp_requests
12922 .entry(key)
12923 .or_default()
12924 .insert(chunk, lsp_request_id);
12925 if let Some((previous_request, running_requests)) =
12926 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12927 {
12928 running_requests.remove(&previous_request);
12929 }
12930 }
12931 _ambiguous_chunks => {
12932 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12933 // there, a buffer version-based check will be performed and outdated requests discarded.
12934 }
12935 }
12936 anyhow::Ok(())
12937 })?;
12938
12939 Ok(())
12940 }
12941
12942 async fn query_lsp_locally<T>(
12943 lsp_store: Entity<Self>,
12944 for_server_id: Option<LanguageServerId>,
12945 sender_id: proto::PeerId,
12946 lsp_request_id: LspRequestId,
12947 proto_request: T::ProtoRequest,
12948 position: Option<Anchor>,
12949 cx: &mut AsyncApp,
12950 ) -> Result<()>
12951 where
12952 T: LspCommand + Clone,
12953 T::ProtoRequest: proto::LspRequestMessage,
12954 <T::ProtoRequest as proto::RequestMessage>::Response:
12955 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12956 {
12957 let (buffer_version, buffer) =
12958 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12959 let request =
12960 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12961 let key = LspKey {
12962 request_type: TypeId::of::<T>(),
12963 server_queried: for_server_id,
12964 };
12965 lsp_store.update(cx, |lsp_store, cx| {
12966 let request_task = match for_server_id {
12967 Some(server_id) => {
12968 let server_task = lsp_store.request_lsp(
12969 buffer.clone(),
12970 LanguageServerToQuery::Other(server_id),
12971 request.clone(),
12972 cx,
12973 );
12974 cx.background_spawn(async move {
12975 let mut responses = Vec::new();
12976 match server_task.await {
12977 Ok(response) => responses.push((server_id, response)),
12978 // rust-analyzer likes to error with this when its still loading up
12979 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12980 Err(e) => log::error!(
12981 "Error handling response for request {request:?}: {e:#}"
12982 ),
12983 }
12984 responses
12985 })
12986 }
12987 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12988 };
12989 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12990 if T::ProtoRequest::stop_previous_requests() {
12991 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12992 lsp_requests.clear();
12993 }
12994 }
12995 lsp_data.lsp_requests.entry(key).or_default().insert(
12996 lsp_request_id,
12997 cx.spawn(async move |lsp_store, cx| {
12998 let response = request_task.await;
12999 lsp_store
13000 .update(cx, |lsp_store, cx| {
13001 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13002 {
13003 let response = response
13004 .into_iter()
13005 .map(|(server_id, response)| {
13006 (
13007 server_id.to_proto(),
13008 T::response_to_proto(
13009 response,
13010 lsp_store,
13011 sender_id,
13012 &buffer_version,
13013 cx,
13014 )
13015 .into(),
13016 )
13017 })
13018 .collect::<HashMap<_, _>>();
13019 match client.send_lsp_response::<T::ProtoRequest>(
13020 project_id,
13021 lsp_request_id,
13022 response,
13023 ) {
13024 Ok(()) => {}
13025 Err(e) => {
13026 log::error!("Failed to send LSP response: {e:#}",)
13027 }
13028 }
13029 }
13030 })
13031 .ok();
13032 }),
13033 );
13034 });
13035 Ok(())
13036 }
13037
13038 async fn wait_for_buffer_version<T>(
13039 lsp_store: &Entity<Self>,
13040 proto_request: &T::ProtoRequest,
13041 cx: &mut AsyncApp,
13042 ) -> Result<(Global, Entity<Buffer>)>
13043 where
13044 T: LspCommand,
13045 T::ProtoRequest: proto::LspRequestMessage,
13046 {
13047 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13048 let version = deserialize_version(proto_request.buffer_version());
13049 let buffer = lsp_store.update(cx, |this, cx| {
13050 this.buffer_store.read(cx).get_existing(buffer_id)
13051 })?;
13052 buffer
13053 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13054 .await?;
13055 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13056 Ok((buffer_version, buffer))
13057 }
13058
13059 fn take_text_document_sync_options(
13060 capabilities: &mut lsp::ServerCapabilities,
13061 ) -> lsp::TextDocumentSyncOptions {
13062 match capabilities.text_document_sync.take() {
13063 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13064 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13065 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13066 sync_options.change = Some(sync_kind);
13067 sync_options
13068 }
13069 None => lsp::TextDocumentSyncOptions::default(),
13070 }
13071 }
13072
13073 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13074 self.downstream_client.clone()
13075 }
13076
13077 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13078 self.worktree_store.clone()
13079 }
13080
13081 /// Gets what's stored in the LSP data for the given buffer.
13082 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13083 self.lsp_data.get_mut(&buffer_id)
13084 }
13085
13086 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13087 /// new [`BufferLspData`] will be created to replace the previous state.
13088 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13089 let (buffer_id, buffer_version) =
13090 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13091 let lsp_data = self
13092 .lsp_data
13093 .entry(buffer_id)
13094 .or_insert_with(|| BufferLspData::new(buffer, cx));
13095 if buffer_version.changed_since(&lsp_data.buffer_version) {
13096 // To send delta requests for semantic tokens, the previous tokens
13097 // need to be kept between buffer changes.
13098 let semantic_tokens = lsp_data.semantic_tokens.take();
13099 *lsp_data = BufferLspData::new(buffer, cx);
13100 lsp_data.semantic_tokens = semantic_tokens;
13101 }
13102 lsp_data
13103 }
13104}
13105
13106// Registration with registerOptions as null, should fallback to true.
13107// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13108fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13109 reg: lsp::Registration,
13110) -> Result<OneOf<bool, T>> {
13111 Ok(match reg.register_options {
13112 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13113 None => OneOf::Left(true),
13114 })
13115}
13116
13117fn subscribe_to_binary_statuses(
13118 languages: &Arc<LanguageRegistry>,
13119 cx: &mut Context<'_, LspStore>,
13120) -> Task<()> {
13121 let mut server_statuses = languages.language_server_binary_statuses();
13122 cx.spawn(async move |lsp_store, cx| {
13123 while let Some((server_name, binary_status)) = server_statuses.next().await {
13124 if lsp_store
13125 .update(cx, |_, cx| {
13126 let mut message = None;
13127 let binary_status = match binary_status {
13128 BinaryStatus::None => proto::ServerBinaryStatus::None,
13129 BinaryStatus::CheckingForUpdate => {
13130 proto::ServerBinaryStatus::CheckingForUpdate
13131 }
13132 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13133 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13134 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13135 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13136 BinaryStatus::Failed { error } => {
13137 message = Some(error);
13138 proto::ServerBinaryStatus::Failed
13139 }
13140 };
13141 cx.emit(LspStoreEvent::LanguageServerUpdate {
13142 // Binary updates are about the binary that might not have any language server id at that point.
13143 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13144 language_server_id: LanguageServerId(0),
13145 name: Some(server_name),
13146 message: proto::update_language_server::Variant::StatusUpdate(
13147 proto::StatusUpdate {
13148 message,
13149 status: Some(proto::status_update::Status::Binary(
13150 binary_status as i32,
13151 )),
13152 },
13153 ),
13154 });
13155 })
13156 .is_err()
13157 {
13158 break;
13159 }
13160 }
13161 })
13162}
13163
13164fn lsp_workspace_diagnostics_refresh(
13165 registration_id: Option<String>,
13166 options: DiagnosticServerCapabilities,
13167 server: Arc<LanguageServer>,
13168 cx: &mut Context<'_, LspStore>,
13169) -> Option<WorkspaceRefreshTask> {
13170 let identifier = workspace_diagnostic_identifier(&options)?;
13171 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13172
13173 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13174 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13175 refresh_tx.try_send(()).ok();
13176
13177 let request_timeout = ProjectSettings::get_global(cx)
13178 .global_lsp_settings
13179 .get_request_timeout();
13180
13181 // 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.
13182 // This allows users to increase the duration if need be
13183 let timeout = if request_timeout != Duration::ZERO {
13184 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13185 } else {
13186 request_timeout
13187 };
13188
13189 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13190 let mut attempts = 0;
13191 let max_attempts = 50;
13192 let mut requests = 0;
13193
13194 loop {
13195 let Some(()) = refresh_rx.recv().await else {
13196 return;
13197 };
13198
13199 'request: loop {
13200 requests += 1;
13201 if attempts > max_attempts {
13202 log::error!(
13203 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13204 );
13205 return;
13206 }
13207 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13208 cx.background_executor()
13209 .timer(Duration::from_millis(backoff_millis))
13210 .await;
13211 attempts += 1;
13212
13213 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13214 lsp_store
13215 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13216 .into_iter()
13217 .filter_map(|(abs_path, result_id)| {
13218 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13219 Some(lsp::PreviousResultId {
13220 uri,
13221 value: result_id.to_string(),
13222 })
13223 })
13224 .collect()
13225 }) else {
13226 return;
13227 };
13228
13229 let token = if let Some(registration_id) = ®istration_id {
13230 format!(
13231 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13232 server.server_id(),
13233 )
13234 } else {
13235 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13236 };
13237
13238 progress_rx.try_recv().ok();
13239 let timer = server.request_timer(timeout).fuse();
13240 let progress = pin!(progress_rx.recv().fuse());
13241 let response_result = server
13242 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13243 lsp::WorkspaceDiagnosticParams {
13244 previous_result_ids,
13245 identifier: identifier.clone(),
13246 work_done_progress_params: Default::default(),
13247 partial_result_params: lsp::PartialResultParams {
13248 partial_result_token: Some(lsp::ProgressToken::String(token)),
13249 },
13250 },
13251 select(timer, progress).then(|either| match either {
13252 Either::Left((message, ..)) => ready(message).left_future(),
13253 Either::Right(..) => pending::<String>().right_future(),
13254 }),
13255 )
13256 .await;
13257
13258 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13259 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13260 match response_result {
13261 ConnectionResult::Timeout => {
13262 log::error!("Timeout during workspace diagnostics pull");
13263 continue 'request;
13264 }
13265 ConnectionResult::ConnectionReset => {
13266 log::error!("Server closed a workspace diagnostics pull request");
13267 continue 'request;
13268 }
13269 ConnectionResult::Result(Err(e)) => {
13270 log::error!("Error during workspace diagnostics pull: {e:#}");
13271 break 'request;
13272 }
13273 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13274 attempts = 0;
13275 if lsp_store
13276 .update(cx, |lsp_store, cx| {
13277 lsp_store.apply_workspace_diagnostic_report(
13278 server.server_id(),
13279 pulled_diagnostics,
13280 registration_id_shared.clone(),
13281 cx,
13282 )
13283 })
13284 .is_err()
13285 {
13286 return;
13287 }
13288 break 'request;
13289 }
13290 }
13291 }
13292 }
13293 });
13294
13295 Some(WorkspaceRefreshTask {
13296 refresh_tx,
13297 progress_tx,
13298 task: workspace_query_language_server,
13299 })
13300}
13301
13302fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13303 match &options {
13304 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13305 .identifier
13306 .as_deref()
13307 .map(SharedString::new),
13308 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13309 let diagnostic_options = ®istration_options.diagnostic_options;
13310 diagnostic_options
13311 .identifier
13312 .as_deref()
13313 .map(SharedString::new)
13314 }
13315 }
13316}
13317
13318fn workspace_diagnostic_identifier(
13319 options: &DiagnosticServerCapabilities,
13320) -> Option<Option<String>> {
13321 match &options {
13322 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13323 if !diagnostic_options.workspace_diagnostics {
13324 return None;
13325 }
13326 Some(diagnostic_options.identifier.clone())
13327 }
13328 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13329 let diagnostic_options = ®istration_options.diagnostic_options;
13330 if !diagnostic_options.workspace_diagnostics {
13331 return None;
13332 }
13333 Some(diagnostic_options.identifier.clone())
13334 }
13335 }
13336}
13337
13338fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13339 let CompletionSource::BufferWord {
13340 word_range,
13341 resolved,
13342 } = &mut completion.source
13343 else {
13344 return;
13345 };
13346 if *resolved {
13347 return;
13348 }
13349
13350 if completion.new_text
13351 != snapshot
13352 .text_for_range(word_range.clone())
13353 .collect::<String>()
13354 {
13355 return;
13356 }
13357
13358 let mut offset = 0;
13359 for chunk in snapshot.chunks(word_range.clone(), true) {
13360 let end_offset = offset + chunk.text.len();
13361 if let Some(highlight_id) = chunk.syntax_highlight_id {
13362 completion
13363 .label
13364 .runs
13365 .push((offset..end_offset, highlight_id));
13366 }
13367 offset = end_offset;
13368 }
13369 *resolved = true;
13370}
13371
13372impl EventEmitter<LspStoreEvent> for LspStore {}
13373
13374fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13375 hover
13376 .contents
13377 .retain(|hover_block| !hover_block.text.trim().is_empty());
13378 if hover.contents.is_empty() {
13379 None
13380 } else {
13381 Some(hover)
13382 }
13383}
13384
13385async fn populate_labels_for_completions(
13386 new_completions: Vec<CoreCompletion>,
13387 language: Option<Arc<Language>>,
13388 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13389) -> Vec<Completion> {
13390 let lsp_completions = new_completions
13391 .iter()
13392 .filter_map(|new_completion| {
13393 new_completion
13394 .source
13395 .lsp_completion(true)
13396 .map(|lsp_completion| lsp_completion.into_owned())
13397 })
13398 .collect::<Vec<_>>();
13399
13400 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13401 lsp_adapter
13402 .labels_for_completions(&lsp_completions, language)
13403 .await
13404 .log_err()
13405 .unwrap_or_default()
13406 } else {
13407 Vec::new()
13408 }
13409 .into_iter()
13410 .fuse();
13411
13412 let mut completions = Vec::new();
13413 for completion in new_completions {
13414 match completion.source.lsp_completion(true) {
13415 Some(lsp_completion) => {
13416 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13417
13418 let mut label = labels.next().flatten().unwrap_or_else(|| {
13419 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13420 });
13421 ensure_uniform_list_compatible_label(&mut label);
13422 completions.push(Completion {
13423 label,
13424 documentation,
13425 replace_range: completion.replace_range,
13426 new_text: completion.new_text,
13427 insert_text_mode: lsp_completion.insert_text_mode,
13428 source: completion.source,
13429 icon_path: None,
13430 confirm: None,
13431 match_start: None,
13432 snippet_deduplication_key: None,
13433 });
13434 }
13435 None => {
13436 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13437 ensure_uniform_list_compatible_label(&mut label);
13438 completions.push(Completion {
13439 label,
13440 documentation: None,
13441 replace_range: completion.replace_range,
13442 new_text: completion.new_text,
13443 source: completion.source,
13444 insert_text_mode: None,
13445 icon_path: None,
13446 confirm: None,
13447 match_start: None,
13448 snippet_deduplication_key: None,
13449 });
13450 }
13451 }
13452 }
13453 completions
13454}
13455
13456#[derive(Debug)]
13457pub enum LanguageServerToQuery {
13458 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13459 FirstCapable,
13460 /// Query a specific language server.
13461 Other(LanguageServerId),
13462}
13463
13464#[derive(Default)]
13465struct RenamePathsWatchedForServer {
13466 did_rename: Vec<RenameActionPredicate>,
13467 will_rename: Vec<RenameActionPredicate>,
13468}
13469
13470impl RenamePathsWatchedForServer {
13471 fn with_did_rename_patterns(
13472 mut self,
13473 did_rename: Option<&FileOperationRegistrationOptions>,
13474 ) -> Self {
13475 if let Some(did_rename) = did_rename {
13476 self.did_rename = did_rename
13477 .filters
13478 .iter()
13479 .filter_map(|filter| filter.try_into().log_err())
13480 .collect();
13481 }
13482 self
13483 }
13484 fn with_will_rename_patterns(
13485 mut self,
13486 will_rename: Option<&FileOperationRegistrationOptions>,
13487 ) -> Self {
13488 if let Some(will_rename) = will_rename {
13489 self.will_rename = will_rename
13490 .filters
13491 .iter()
13492 .filter_map(|filter| filter.try_into().log_err())
13493 .collect();
13494 }
13495 self
13496 }
13497
13498 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13499 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13500 }
13501 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13502 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13503 }
13504}
13505
13506impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13507 type Error = globset::Error;
13508 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13509 Ok(Self {
13510 kind: ops.pattern.matches.clone(),
13511 glob: GlobBuilder::new(&ops.pattern.glob)
13512 .case_insensitive(
13513 ops.pattern
13514 .options
13515 .as_ref()
13516 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13517 )
13518 .build()?
13519 .compile_matcher(),
13520 })
13521 }
13522}
13523struct RenameActionPredicate {
13524 glob: GlobMatcher,
13525 kind: Option<FileOperationPatternKind>,
13526}
13527
13528impl RenameActionPredicate {
13529 // Returns true if language server should be notified
13530 fn eval(&self, path: &str, is_dir: bool) -> bool {
13531 self.kind.as_ref().is_none_or(|kind| {
13532 let expected_kind = if is_dir {
13533 FileOperationPatternKind::Folder
13534 } else {
13535 FileOperationPatternKind::File
13536 };
13537 kind == &expected_kind
13538 }) && self.glob.is_match(path)
13539 }
13540}
13541
13542#[derive(Default)]
13543struct LanguageServerWatchedPaths {
13544 worktree_paths: HashMap<WorktreeId, GlobSet>,
13545 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13546}
13547
13548#[derive(Default)]
13549struct LanguageServerWatchedPathsBuilder {
13550 worktree_paths: HashMap<WorktreeId, GlobSet>,
13551 abs_paths: HashMap<Arc<Path>, GlobSet>,
13552}
13553
13554impl LanguageServerWatchedPathsBuilder {
13555 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13556 self.worktree_paths.insert(worktree_id, glob_set);
13557 }
13558 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13559 self.abs_paths.insert(path, glob_set);
13560 }
13561 fn build(
13562 self,
13563 fs: Arc<dyn Fs>,
13564 language_server_id: LanguageServerId,
13565 cx: &mut Context<LspStore>,
13566 ) -> LanguageServerWatchedPaths {
13567 let lsp_store = cx.weak_entity();
13568
13569 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13570 let abs_paths = self
13571 .abs_paths
13572 .into_iter()
13573 .map(|(abs_path, globset)| {
13574 let task = cx.spawn({
13575 let abs_path = abs_path.clone();
13576 let fs = fs.clone();
13577
13578 let lsp_store = lsp_store.clone();
13579 async move |_, cx| {
13580 maybe!(async move {
13581 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13582 while let Some(update) = push_updates.0.next().await {
13583 let action = lsp_store
13584 .update(cx, |this, _| {
13585 let Some(local) = this.as_local() else {
13586 return ControlFlow::Break(());
13587 };
13588 let Some(watcher) = local
13589 .language_server_watched_paths
13590 .get(&language_server_id)
13591 else {
13592 return ControlFlow::Break(());
13593 };
13594 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13595 "Watched abs path is not registered with a watcher",
13596 );
13597 let matching_entries = update
13598 .into_iter()
13599 .filter(|event| globs.is_match(&event.path))
13600 .collect::<Vec<_>>();
13601 this.lsp_notify_abs_paths_changed(
13602 language_server_id,
13603 matching_entries,
13604 );
13605 ControlFlow::Continue(())
13606 })
13607 .ok()?;
13608
13609 if action.is_break() {
13610 break;
13611 }
13612 }
13613 Some(())
13614 })
13615 .await;
13616 }
13617 });
13618 (abs_path, (globset, task))
13619 })
13620 .collect();
13621 LanguageServerWatchedPaths {
13622 worktree_paths: self.worktree_paths,
13623 abs_paths,
13624 }
13625 }
13626}
13627
13628struct LspBufferSnapshot {
13629 version: i32,
13630 snapshot: TextBufferSnapshot,
13631}
13632
13633/// A prompt requested by LSP server.
13634#[derive(Clone, Debug)]
13635pub struct LanguageServerPromptRequest {
13636 pub id: usize,
13637 pub level: PromptLevel,
13638 pub message: String,
13639 pub actions: Vec<MessageActionItem>,
13640 pub lsp_name: String,
13641 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13642}
13643
13644impl LanguageServerPromptRequest {
13645 pub fn new(
13646 level: PromptLevel,
13647 message: String,
13648 actions: Vec<MessageActionItem>,
13649 lsp_name: String,
13650 response_channel: smol::channel::Sender<MessageActionItem>,
13651 ) -> Self {
13652 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13653 LanguageServerPromptRequest {
13654 id,
13655 level,
13656 message,
13657 actions,
13658 lsp_name,
13659 response_channel,
13660 }
13661 }
13662 pub async fn respond(self, index: usize) -> Option<()> {
13663 if let Some(response) = self.actions.into_iter().nth(index) {
13664 self.response_channel.send(response).await.ok()
13665 } else {
13666 None
13667 }
13668 }
13669
13670 #[cfg(any(test, feature = "test-support"))]
13671 pub fn test(
13672 level: PromptLevel,
13673 message: String,
13674 actions: Vec<MessageActionItem>,
13675 lsp_name: String,
13676 ) -> Self {
13677 let (tx, _rx) = smol::channel::unbounded();
13678 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13679 }
13680}
13681impl PartialEq for LanguageServerPromptRequest {
13682 fn eq(&self, other: &Self) -> bool {
13683 self.message == other.message && self.actions == other.actions
13684 }
13685}
13686
13687#[derive(Clone, Debug, PartialEq)]
13688pub enum LanguageServerLogType {
13689 Log(MessageType),
13690 Trace { verbose_info: Option<String> },
13691 Rpc { received: bool },
13692}
13693
13694impl LanguageServerLogType {
13695 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13696 match self {
13697 Self::Log(log_type) => {
13698 use proto::log_message::LogLevel;
13699 let level = match *log_type {
13700 MessageType::ERROR => LogLevel::Error,
13701 MessageType::WARNING => LogLevel::Warning,
13702 MessageType::INFO => LogLevel::Info,
13703 MessageType::LOG => LogLevel::Log,
13704 other => {
13705 log::warn!("Unknown lsp log message type: {other:?}");
13706 LogLevel::Log
13707 }
13708 };
13709 proto::language_server_log::LogType::Log(proto::LogMessage {
13710 level: level as i32,
13711 })
13712 }
13713 Self::Trace { verbose_info } => {
13714 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13715 verbose_info: verbose_info.to_owned(),
13716 })
13717 }
13718 Self::Rpc { received } => {
13719 let kind = if *received {
13720 proto::rpc_message::Kind::Received
13721 } else {
13722 proto::rpc_message::Kind::Sent
13723 };
13724 let kind = kind as i32;
13725 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13726 }
13727 }
13728 }
13729
13730 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13731 use proto::log_message::LogLevel;
13732 use proto::rpc_message;
13733 match log_type {
13734 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13735 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13736 LogLevel::Error => MessageType::ERROR,
13737 LogLevel::Warning => MessageType::WARNING,
13738 LogLevel::Info => MessageType::INFO,
13739 LogLevel::Log => MessageType::LOG,
13740 },
13741 ),
13742 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13743 verbose_info: trace_message.verbose_info,
13744 },
13745 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13746 received: match rpc_message::Kind::from_i32(message.kind)
13747 .unwrap_or(rpc_message::Kind::Received)
13748 {
13749 rpc_message::Kind::Received => true,
13750 rpc_message::Kind::Sent => false,
13751 },
13752 },
13753 }
13754 }
13755}
13756
13757pub struct WorkspaceRefreshTask {
13758 refresh_tx: mpsc::Sender<()>,
13759 progress_tx: mpsc::Sender<()>,
13760 #[allow(dead_code)]
13761 task: Task<()>,
13762}
13763
13764pub enum LanguageServerState {
13765 Starting {
13766 startup: Task<Option<Arc<LanguageServer>>>,
13767 /// List of language servers that will be added to the workspace once it's initialization completes.
13768 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13769 },
13770
13771 Running {
13772 adapter: Arc<CachedLspAdapter>,
13773 server: Arc<LanguageServer>,
13774 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13775 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13776 },
13777}
13778
13779impl LanguageServerState {
13780 fn add_workspace_folder(&self, uri: Uri) {
13781 match self {
13782 LanguageServerState::Starting {
13783 pending_workspace_folders,
13784 ..
13785 } => {
13786 pending_workspace_folders.lock().insert(uri);
13787 }
13788 LanguageServerState::Running { server, .. } => {
13789 server.add_workspace_folder(uri);
13790 }
13791 }
13792 }
13793 fn _remove_workspace_folder(&self, uri: Uri) {
13794 match self {
13795 LanguageServerState::Starting {
13796 pending_workspace_folders,
13797 ..
13798 } => {
13799 pending_workspace_folders.lock().remove(&uri);
13800 }
13801 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13802 }
13803 }
13804}
13805
13806impl std::fmt::Debug for LanguageServerState {
13807 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13808 match self {
13809 LanguageServerState::Starting { .. } => {
13810 f.debug_struct("LanguageServerState::Starting").finish()
13811 }
13812 LanguageServerState::Running { .. } => {
13813 f.debug_struct("LanguageServerState::Running").finish()
13814 }
13815 }
13816 }
13817}
13818
13819#[derive(Clone, Debug, Serialize)]
13820pub struct LanguageServerProgress {
13821 pub is_disk_based_diagnostics_progress: bool,
13822 pub is_cancellable: bool,
13823 pub title: Option<String>,
13824 pub message: Option<String>,
13825 pub percentage: Option<usize>,
13826 #[serde(skip_serializing)]
13827 pub last_update_at: Instant,
13828}
13829
13830#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13831pub struct DiagnosticSummary {
13832 pub error_count: usize,
13833 pub warning_count: usize,
13834}
13835
13836impl DiagnosticSummary {
13837 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13838 let mut this = Self {
13839 error_count: 0,
13840 warning_count: 0,
13841 };
13842
13843 for entry in diagnostics {
13844 if entry.diagnostic.is_primary {
13845 match entry.diagnostic.severity {
13846 DiagnosticSeverity::ERROR => this.error_count += 1,
13847 DiagnosticSeverity::WARNING => this.warning_count += 1,
13848 _ => {}
13849 }
13850 }
13851 }
13852
13853 this
13854 }
13855
13856 pub fn is_empty(&self) -> bool {
13857 self.error_count == 0 && self.warning_count == 0
13858 }
13859
13860 pub fn to_proto(
13861 self,
13862 language_server_id: LanguageServerId,
13863 path: &RelPath,
13864 ) -> proto::DiagnosticSummary {
13865 proto::DiagnosticSummary {
13866 path: path.to_proto(),
13867 language_server_id: language_server_id.0 as u64,
13868 error_count: self.error_count as u32,
13869 warning_count: self.warning_count as u32,
13870 }
13871 }
13872}
13873
13874#[derive(Clone, Debug)]
13875pub enum CompletionDocumentation {
13876 /// There is no documentation for this completion.
13877 Undocumented,
13878 /// A single line of documentation.
13879 SingleLine(SharedString),
13880 /// Multiple lines of plain text documentation.
13881 MultiLinePlainText(SharedString),
13882 /// Markdown documentation.
13883 MultiLineMarkdown(SharedString),
13884 /// Both single line and multiple lines of plain text documentation.
13885 SingleLineAndMultiLinePlainText {
13886 single_line: SharedString,
13887 plain_text: Option<SharedString>,
13888 },
13889}
13890
13891impl CompletionDocumentation {
13892 #[cfg(any(test, feature = "test-support"))]
13893 pub fn text(&self) -> SharedString {
13894 match self {
13895 CompletionDocumentation::Undocumented => "".into(),
13896 CompletionDocumentation::SingleLine(s) => s.clone(),
13897 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13898 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13899 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13900 single_line.clone()
13901 }
13902 }
13903 }
13904}
13905
13906impl From<lsp::Documentation> for CompletionDocumentation {
13907 fn from(docs: lsp::Documentation) -> Self {
13908 match docs {
13909 lsp::Documentation::String(text) => {
13910 if text.lines().count() <= 1 {
13911 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13912 } else {
13913 CompletionDocumentation::MultiLinePlainText(text.into())
13914 }
13915 }
13916
13917 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13918 lsp::MarkupKind::PlainText => {
13919 if value.lines().count() <= 1 {
13920 CompletionDocumentation::SingleLine(value.into())
13921 } else {
13922 CompletionDocumentation::MultiLinePlainText(value.into())
13923 }
13924 }
13925
13926 lsp::MarkupKind::Markdown => {
13927 CompletionDocumentation::MultiLineMarkdown(value.into())
13928 }
13929 },
13930 }
13931 }
13932}
13933
13934pub enum ResolvedHint {
13935 Resolved(InlayHint),
13936 Resolving(Shared<Task<()>>),
13937}
13938
13939pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13940 glob.components()
13941 .take_while(|component| match component {
13942 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13943 _ => true,
13944 })
13945 .collect()
13946}
13947
13948pub struct SshLspAdapter {
13949 name: LanguageServerName,
13950 binary: LanguageServerBinary,
13951 initialization_options: Option<String>,
13952 code_action_kinds: Option<Vec<CodeActionKind>>,
13953}
13954
13955impl SshLspAdapter {
13956 pub fn new(
13957 name: LanguageServerName,
13958 binary: LanguageServerBinary,
13959 initialization_options: Option<String>,
13960 code_action_kinds: Option<String>,
13961 ) -> Self {
13962 Self {
13963 name,
13964 binary,
13965 initialization_options,
13966 code_action_kinds: code_action_kinds
13967 .as_ref()
13968 .and_then(|c| serde_json::from_str(c).ok()),
13969 }
13970 }
13971}
13972
13973impl LspInstaller for SshLspAdapter {
13974 type BinaryVersion = ();
13975 async fn check_if_user_installed(
13976 &self,
13977 _: &dyn LspAdapterDelegate,
13978 _: Option<Toolchain>,
13979 _: &AsyncApp,
13980 ) -> Option<LanguageServerBinary> {
13981 Some(self.binary.clone())
13982 }
13983
13984 async fn cached_server_binary(
13985 &self,
13986 _: PathBuf,
13987 _: &dyn LspAdapterDelegate,
13988 ) -> Option<LanguageServerBinary> {
13989 None
13990 }
13991
13992 async fn fetch_latest_server_version(
13993 &self,
13994 _: &dyn LspAdapterDelegate,
13995 _: bool,
13996 _: &mut AsyncApp,
13997 ) -> Result<()> {
13998 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13999 }
14000
14001 async fn fetch_server_binary(
14002 &self,
14003 _: (),
14004 _: PathBuf,
14005 _: &dyn LspAdapterDelegate,
14006 ) -> Result<LanguageServerBinary> {
14007 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14008 }
14009}
14010
14011#[async_trait(?Send)]
14012impl LspAdapter for SshLspAdapter {
14013 fn name(&self) -> LanguageServerName {
14014 self.name.clone()
14015 }
14016
14017 async fn initialization_options(
14018 self: Arc<Self>,
14019 _: &Arc<dyn LspAdapterDelegate>,
14020 _: &mut AsyncApp,
14021 ) -> Result<Option<serde_json::Value>> {
14022 let Some(options) = &self.initialization_options else {
14023 return Ok(None);
14024 };
14025 let result = serde_json::from_str(options)?;
14026 Ok(result)
14027 }
14028
14029 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14030 self.code_action_kinds.clone()
14031 }
14032}
14033
14034pub fn language_server_settings<'a>(
14035 delegate: &'a dyn LspAdapterDelegate,
14036 language: &LanguageServerName,
14037 cx: &'a App,
14038) -> Option<&'a LspSettings> {
14039 language_server_settings_for(
14040 SettingsLocation {
14041 worktree_id: delegate.worktree_id(),
14042 path: RelPath::empty(),
14043 },
14044 language,
14045 cx,
14046 )
14047}
14048
14049pub fn language_server_settings_for<'a>(
14050 location: SettingsLocation<'a>,
14051 language: &LanguageServerName,
14052 cx: &'a App,
14053) -> Option<&'a LspSettings> {
14054 ProjectSettings::get(Some(location), cx).lsp.get(language)
14055}
14056
14057pub struct LocalLspAdapterDelegate {
14058 lsp_store: WeakEntity<LspStore>,
14059 worktree: worktree::Snapshot,
14060 fs: Arc<dyn Fs>,
14061 http_client: Arc<dyn HttpClient>,
14062 language_registry: Arc<LanguageRegistry>,
14063 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14064}
14065
14066impl LocalLspAdapterDelegate {
14067 pub fn new(
14068 language_registry: Arc<LanguageRegistry>,
14069 environment: &Entity<ProjectEnvironment>,
14070 lsp_store: WeakEntity<LspStore>,
14071 worktree: &Entity<Worktree>,
14072 http_client: Arc<dyn HttpClient>,
14073 fs: Arc<dyn Fs>,
14074 cx: &mut App,
14075 ) -> Arc<Self> {
14076 let load_shell_env_task =
14077 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14078
14079 Arc::new(Self {
14080 lsp_store,
14081 worktree: worktree.read(cx).snapshot(),
14082 fs,
14083 http_client,
14084 language_registry,
14085 load_shell_env_task,
14086 })
14087 }
14088
14089 pub fn from_local_lsp(
14090 local: &LocalLspStore,
14091 worktree: &Entity<Worktree>,
14092 cx: &mut App,
14093 ) -> Arc<Self> {
14094 Self::new(
14095 local.languages.clone(),
14096 &local.environment,
14097 local.weak.clone(),
14098 worktree,
14099 local.http_client.clone(),
14100 local.fs.clone(),
14101 cx,
14102 )
14103 }
14104}
14105
14106#[async_trait]
14107impl LspAdapterDelegate for LocalLspAdapterDelegate {
14108 fn show_notification(&self, message: &str, cx: &mut App) {
14109 self.lsp_store
14110 .update(cx, |_, cx| {
14111 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14112 })
14113 .ok();
14114 }
14115
14116 fn http_client(&self) -> Arc<dyn HttpClient> {
14117 self.http_client.clone()
14118 }
14119
14120 fn worktree_id(&self) -> WorktreeId {
14121 self.worktree.id()
14122 }
14123
14124 fn worktree_root_path(&self) -> &Path {
14125 self.worktree.abs_path().as_ref()
14126 }
14127
14128 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14129 self.worktree.resolve_relative_path(path)
14130 }
14131
14132 async fn shell_env(&self) -> HashMap<String, String> {
14133 let task = self.load_shell_env_task.clone();
14134 task.await.unwrap_or_default()
14135 }
14136
14137 async fn npm_package_installed_version(
14138 &self,
14139 package_name: &str,
14140 ) -> Result<Option<(PathBuf, Version)>> {
14141 let local_package_directory = self.worktree_root_path();
14142 let node_modules_directory = local_package_directory.join("node_modules");
14143
14144 if let Some(version) =
14145 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14146 {
14147 return Ok(Some((node_modules_directory, version)));
14148 }
14149 let Some(npm) = self.which("npm".as_ref()).await else {
14150 log::warn!(
14151 "Failed to find npm executable for {:?}",
14152 local_package_directory
14153 );
14154 return Ok(None);
14155 };
14156
14157 let env = self.shell_env().await;
14158 let output = util::command::new_command(&npm)
14159 .args(["root", "-g"])
14160 .envs(env)
14161 .current_dir(local_package_directory)
14162 .output()
14163 .await?;
14164 let global_node_modules =
14165 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14166
14167 if let Some(version) =
14168 read_package_installed_version(global_node_modules.clone(), package_name).await?
14169 {
14170 return Ok(Some((global_node_modules, version)));
14171 }
14172 return Ok(None);
14173 }
14174
14175 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14176 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14177 if self.fs.is_file(&worktree_abs_path).await {
14178 worktree_abs_path.pop();
14179 }
14180
14181 let env = self.shell_env().await;
14182
14183 let shell_path = env.get("PATH").cloned();
14184
14185 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14186 }
14187
14188 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14189 let mut working_dir = self.worktree_root_path().to_path_buf();
14190 if self.fs.is_file(&working_dir).await {
14191 working_dir.pop();
14192 }
14193 let output = util::command::new_command(&command.path)
14194 .args(command.arguments)
14195 .envs(command.env.clone().unwrap_or_default())
14196 .current_dir(working_dir)
14197 .output()
14198 .await?;
14199
14200 anyhow::ensure!(
14201 output.status.success(),
14202 "{}, stdout: {:?}, stderr: {:?}",
14203 output.status,
14204 String::from_utf8_lossy(&output.stdout),
14205 String::from_utf8_lossy(&output.stderr)
14206 );
14207 Ok(())
14208 }
14209
14210 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14211 self.language_registry
14212 .update_lsp_binary_status(server_name, status);
14213 }
14214
14215 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14216 self.language_registry
14217 .all_lsp_adapters()
14218 .into_iter()
14219 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14220 .collect()
14221 }
14222
14223 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14224 let dir = self.language_registry.language_server_download_dir(name)?;
14225
14226 if !dir.exists() {
14227 smol::fs::create_dir_all(&dir)
14228 .await
14229 .context("failed to create container directory")
14230 .log_err()?;
14231 }
14232
14233 Some(dir)
14234 }
14235
14236 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14237 let entry = self
14238 .worktree
14239 .entry_for_path(path)
14240 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14241 let abs_path = self.worktree.absolutize(&entry.path);
14242 self.fs.load(&abs_path).await
14243 }
14244}
14245
14246async fn populate_labels_for_symbols(
14247 symbols: Vec<CoreSymbol>,
14248 language_registry: &Arc<LanguageRegistry>,
14249 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14250 output: &mut Vec<Symbol>,
14251) {
14252 #[allow(clippy::mutable_key_type)]
14253 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14254
14255 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14256 for symbol in symbols {
14257 let Some(file_name) = symbol.path.file_name() else {
14258 continue;
14259 };
14260 let language = language_registry
14261 .load_language_for_file_path(Path::new(file_name))
14262 .await
14263 .ok()
14264 .or_else(|| {
14265 unknown_paths.insert(file_name.into());
14266 None
14267 });
14268 symbols_by_language
14269 .entry(language)
14270 .or_default()
14271 .push(symbol);
14272 }
14273
14274 for unknown_path in unknown_paths {
14275 log::info!("no language found for symbol in file {unknown_path:?}");
14276 }
14277
14278 let mut label_params = Vec::new();
14279 for (language, mut symbols) in symbols_by_language {
14280 label_params.clear();
14281 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14282 name: mem::take(&mut symbol.name),
14283 kind: symbol.kind,
14284 container_name: symbol.container_name.take(),
14285 }));
14286
14287 let mut labels = Vec::new();
14288 if let Some(language) = language {
14289 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14290 language_registry
14291 .lsp_adapters(&language.name())
14292 .first()
14293 .cloned()
14294 });
14295 if let Some(lsp_adapter) = lsp_adapter {
14296 labels = lsp_adapter
14297 .labels_for_symbols(&label_params, &language)
14298 .await
14299 .log_err()
14300 .unwrap_or_default();
14301 }
14302 }
14303
14304 for (
14305 (
14306 symbol,
14307 language::Symbol {
14308 name,
14309 container_name,
14310 ..
14311 },
14312 ),
14313 label,
14314 ) in symbols
14315 .into_iter()
14316 .zip(label_params.drain(..))
14317 .zip(labels.into_iter().chain(iter::repeat(None)))
14318 {
14319 output.push(Symbol {
14320 language_server_name: symbol.language_server_name,
14321 source_worktree_id: symbol.source_worktree_id,
14322 source_language_server_id: symbol.source_language_server_id,
14323 path: symbol.path,
14324 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14325 name,
14326 kind: symbol.kind,
14327 range: symbol.range,
14328 container_name,
14329 });
14330 }
14331 }
14332}
14333
14334pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14335 text.lines()
14336 .map(|line| line.trim())
14337 .filter(|line| !line.is_empty())
14338 .join(separator)
14339}
14340
14341fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14342 match server.capabilities().text_document_sync.as_ref()? {
14343 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14344 // Server wants didSave but didn't specify includeText.
14345 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14346 // Server doesn't want didSave at all.
14347 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14348 // Server provided SaveOptions.
14349 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14350 Some(save_options.include_text.unwrap_or(false))
14351 }
14352 },
14353 // We do not have any save info. Kind affects didChange only.
14354 lsp::TextDocumentSyncCapability::Kind(_) => None,
14355 }
14356}
14357
14358/// Completion items are displayed in a `UniformList`.
14359/// Usually, those items are single-line strings, but in LSP responses,
14360/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14361/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14362/// 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,
14363/// breaking the completions menu presentation.
14364///
14365/// 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.
14366pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14367 let mut new_text = String::with_capacity(label.text.len());
14368 let mut offset_map = vec![0; label.text.len() + 1];
14369 let mut last_char_was_space = false;
14370 let mut new_idx = 0;
14371 let chars = label.text.char_indices().fuse();
14372 let mut newlines_removed = false;
14373
14374 for (idx, c) in chars {
14375 offset_map[idx] = new_idx;
14376
14377 match c {
14378 '\n' if last_char_was_space => {
14379 newlines_removed = true;
14380 }
14381 '\t' | ' ' if last_char_was_space => {}
14382 '\n' if !last_char_was_space => {
14383 new_text.push(' ');
14384 new_idx += 1;
14385 last_char_was_space = true;
14386 newlines_removed = true;
14387 }
14388 ' ' | '\t' => {
14389 new_text.push(' ');
14390 new_idx += 1;
14391 last_char_was_space = true;
14392 }
14393 _ => {
14394 new_text.push(c);
14395 new_idx += c.len_utf8();
14396 last_char_was_space = false;
14397 }
14398 }
14399 }
14400 offset_map[label.text.len()] = new_idx;
14401
14402 // Only modify the label if newlines were removed.
14403 if !newlines_removed {
14404 return;
14405 }
14406
14407 let last_index = new_idx;
14408 let mut run_ranges_errors = Vec::new();
14409 label.runs.retain_mut(|(range, _)| {
14410 match offset_map.get(range.start) {
14411 Some(&start) => range.start = start,
14412 None => {
14413 run_ranges_errors.push(range.clone());
14414 return false;
14415 }
14416 }
14417
14418 match offset_map.get(range.end) {
14419 Some(&end) => range.end = end,
14420 None => {
14421 run_ranges_errors.push(range.clone());
14422 range.end = last_index;
14423 }
14424 }
14425 true
14426 });
14427 if !run_ranges_errors.is_empty() {
14428 log::error!(
14429 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14430 label.text
14431 );
14432 }
14433
14434 let mut wrong_filter_range = None;
14435 if label.filter_range == (0..label.text.len()) {
14436 label.filter_range = 0..new_text.len();
14437 } else {
14438 let mut original_filter_range = Some(label.filter_range.clone());
14439 match offset_map.get(label.filter_range.start) {
14440 Some(&start) => label.filter_range.start = start,
14441 None => {
14442 wrong_filter_range = original_filter_range.take();
14443 label.filter_range.start = last_index;
14444 }
14445 }
14446
14447 match offset_map.get(label.filter_range.end) {
14448 Some(&end) => label.filter_range.end = end,
14449 None => {
14450 wrong_filter_range = original_filter_range.take();
14451 label.filter_range.end = last_index;
14452 }
14453 }
14454 }
14455 if let Some(wrong_filter_range) = wrong_filter_range {
14456 log::error!(
14457 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14458 label.text
14459 );
14460 }
14461
14462 label.text = new_text;
14463}