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::{Candidate, 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 )
552 .await?;
553
554 match (&mut initialization_options, override_options) {
555 (Some(initialization_options), Some(override_options)) => {
556 merge_json_value_into(override_options, initialization_options);
557 }
558 (None, override_options) => initialization_options = override_options,
559 _ => {}
560 }
561
562 let initialization_params = cx.update(|cx| {
563 let mut params = language_server.default_initialize_params(
564 pull_diagnostics,
565 augments_syntax_tokens,
566 cx,
567 );
568 params.initialization_options = initialization_options;
569 adapter.adapter.prepare_initialize_params(params, cx)
570 })?;
571
572 Self::setup_lsp_messages(
573 lsp_store.clone(),
574 &language_server,
575 delegate.clone(),
576 adapter.clone(),
577 );
578
579 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
580 settings: workspace_config,
581 };
582 let language_server = cx
583 .update(|cx| {
584 let request_timeout = ProjectSettings::get_global(cx)
585 .global_lsp_settings
586 .get_request_timeout();
587
588 language_server.initialize(
589 initialization_params,
590 Arc::new(did_change_configuration_params.clone()),
591 request_timeout,
592 cx,
593 )
594 })
595 .await
596 .inspect_err(|_| {
597 if let Some(lsp_store) = lsp_store.upgrade() {
598 lsp_store.update(cx, |lsp_store, cx| {
599 lsp_store.cleanup_lsp_data(server_id);
600 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
601 });
602 }
603 })?;
604
605 language_server.notify::<lsp::notification::DidChangeConfiguration>(
606 did_change_configuration_params,
607 )?;
608
609 anyhow::Ok(language_server)
610 }
611 .await;
612
613 match result {
614 Ok(server) => {
615 lsp_store
616 .update(cx, |lsp_store, cx| {
617 lsp_store.insert_newly_running_language_server(
618 adapter,
619 server.clone(),
620 server_id,
621 key,
622 pending_workspace_folders,
623 cx,
624 );
625 })
626 .ok();
627 stderr_capture.lock().take();
628 Some(server)
629 }
630
631 Err(err) => {
632 let log = stderr_capture.lock().take().unwrap_or_default();
633 delegate.update_status(
634 adapter.name(),
635 BinaryStatus::Failed {
636 error: if log.is_empty() {
637 format!("{err:#}")
638 } else {
639 format!("{err:#}\n-- stderr --\n{log}")
640 },
641 },
642 );
643 log::error!(
644 "Failed to start language server {server_name:?}: {}",
645 redact_command(&format!("{err:?}"))
646 );
647 if !log.is_empty() {
648 log::error!("server stderr: {}", redact_command(&log));
649 }
650 None
651 }
652 }
653 })
654 };
655 let state = LanguageServerState::Starting {
656 startup,
657 pending_workspace_folders,
658 };
659
660 if update_binary_status {
661 self.languages
662 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
663 }
664
665 self.language_servers.insert(server_id, state);
666 self.language_server_ids
667 .entry(key)
668 .or_insert(UnifiedLanguageServer {
669 id: server_id,
670 project_roots: Default::default(),
671 });
672 server_id
673 }
674
675 fn get_language_server_binary(
676 &self,
677 worktree_abs_path: Arc<Path>,
678 adapter: Arc<CachedLspAdapter>,
679 settings: Arc<LspSettings>,
680 toolchain: Option<Toolchain>,
681 delegate: Arc<dyn LspAdapterDelegate>,
682 allow_binary_download: bool,
683 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
684 cx: &mut App,
685 ) -> Task<Result<LanguageServerBinary>> {
686 if let Some(settings) = &settings.binary
687 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
688 {
689 let settings = settings.clone();
690 let languages = self.languages.clone();
691 return cx.background_spawn(async move {
692 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
693 let already_trusted = *wait_until_worktree_trust.borrow();
694 if !already_trusted {
695 log::info!(
696 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
697 adapter.name(),
698 );
699 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
700 if worktree_trusted {
701 break;
702 }
703 }
704 log::info!(
705 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
706 adapter.name(),
707 );
708 }
709 languages
710 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
711 }
712 let mut env = delegate.shell_env().await;
713 env.extend(settings.env.unwrap_or_default());
714
715 Ok(LanguageServerBinary {
716 path: delegate.resolve_relative_path(path),
717 env: Some(env),
718 arguments: settings
719 .arguments
720 .unwrap_or_default()
721 .iter()
722 .map(Into::into)
723 .collect(),
724 })
725 });
726 }
727 let lsp_binary_options = LanguageServerBinaryOptions {
728 allow_path_lookup: !settings
729 .binary
730 .as_ref()
731 .and_then(|b| b.ignore_system_version)
732 .unwrap_or_default(),
733 allow_binary_download,
734 pre_release: settings
735 .fetch
736 .as_ref()
737 .and_then(|f| f.pre_release)
738 .unwrap_or(false),
739 };
740
741 cx.spawn(async move |cx| {
742 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
743 let already_trusted = *wait_until_worktree_trust.borrow();
744 if !already_trusted {
745 log::info!(
746 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
747 adapter.name(),
748 );
749 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
750 if worktree_trusted {
751 break;
752 }
753 }
754 log::info!(
755 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
756 adapter.name(),
757 );
758 }
759 }
760
761 let (existing_binary, maybe_download_binary) = adapter
762 .clone()
763 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
764 .await
765 .await;
766
767 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
768
769 let mut binary = match (existing_binary, maybe_download_binary) {
770 (binary, None) => binary?,
771 (Err(_), Some(downloader)) => downloader.await?,
772 (Ok(existing_binary), Some(downloader)) => {
773 let mut download_timeout = cx
774 .background_executor()
775 .timer(SERVER_DOWNLOAD_TIMEOUT)
776 .fuse();
777 let mut downloader = downloader.fuse();
778 futures::select! {
779 _ = download_timeout => {
780 // Return existing binary and kick the existing work to the background.
781 cx.spawn(async move |_| downloader.await).detach();
782 Ok(existing_binary)
783 },
784 downloaded_or_existing_binary = downloader => {
785 // If download fails, this results in the existing binary.
786 downloaded_or_existing_binary
787 }
788 }?
789 }
790 };
791 let mut shell_env = delegate.shell_env().await;
792
793 shell_env.extend(binary.env.unwrap_or_default());
794
795 if let Some(settings) = settings.binary.as_ref() {
796 if let Some(arguments) = &settings.arguments {
797 binary.arguments = arguments.iter().map(Into::into).collect();
798 }
799 if let Some(env) = &settings.env {
800 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
801 }
802 }
803
804 binary.env = Some(shell_env);
805 Ok(binary)
806 })
807 }
808
809 fn setup_lsp_messages(
810 lsp_store: WeakEntity<LspStore>,
811 language_server: &LanguageServer,
812 delegate: Arc<dyn LspAdapterDelegate>,
813 adapter: Arc<CachedLspAdapter>,
814 ) {
815 let name = language_server.name();
816 let server_id = language_server.server_id();
817 language_server
818 .on_notification::<lsp::notification::PublishDiagnostics, _>({
819 let adapter = adapter.clone();
820 let this = lsp_store.clone();
821 move |mut params, cx| {
822 let adapter = adapter.clone();
823 if let Some(this) = this.upgrade() {
824 this.update(cx, |this, cx| {
825 {
826 let buffer = params
827 .uri
828 .to_file_path()
829 .map(|file_path| this.get_buffer(&file_path, cx))
830 .ok()
831 .flatten();
832 adapter.process_diagnostics(&mut params, server_id, buffer);
833 }
834
835 this.merge_lsp_diagnostics(
836 DiagnosticSourceKind::Pushed,
837 vec![DocumentDiagnosticsUpdate {
838 server_id,
839 diagnostics: params,
840 result_id: None,
841 disk_based_sources: Cow::Borrowed(
842 &adapter.disk_based_diagnostic_sources,
843 ),
844 registration_id: None,
845 }],
846 |_, diagnostic, cx| match diagnostic.source_kind {
847 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
848 adapter.retain_old_diagnostic(diagnostic, cx)
849 }
850 DiagnosticSourceKind::Pulled => true,
851 },
852 cx,
853 )
854 .log_err();
855 });
856 }
857 }
858 })
859 .detach();
860 language_server
861 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
862 let adapter = adapter.adapter.clone();
863 let delegate = delegate.clone();
864 let this = lsp_store.clone();
865 move |params, cx| {
866 let adapter = adapter.clone();
867 let delegate = delegate.clone();
868 let this = this.clone();
869 let mut cx = cx.clone();
870 async move {
871 let toolchain_for_id = this
872 .update(&mut cx, |this, _| {
873 this.as_local()?.language_server_ids.iter().find_map(
874 |(seed, value)| {
875 (value.id == server_id).then(|| seed.toolchain.clone())
876 },
877 )
878 })?
879 .context("Expected the LSP store to be in a local mode")?;
880
881 let mut scope_uri_to_workspace_config = BTreeMap::new();
882 for item in ¶ms.items {
883 let scope_uri = item.scope_uri.clone();
884 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
885 scope_uri_to_workspace_config.entry(scope_uri.clone())
886 else {
887 // We've already queried workspace configuration of this URI.
888 continue;
889 };
890 let workspace_config = Self::workspace_configuration_for_adapter(
891 adapter.clone(),
892 &delegate,
893 toolchain_for_id.clone(),
894 scope_uri,
895 &mut cx,
896 )
897 .await?;
898 new_scope_uri.insert(workspace_config);
899 }
900
901 Ok(params
902 .items
903 .into_iter()
904 .filter_map(|item| {
905 let workspace_config =
906 scope_uri_to_workspace_config.get(&item.scope_uri)?;
907 if let Some(section) = &item.section {
908 Some(
909 workspace_config
910 .get(section)
911 .cloned()
912 .unwrap_or(serde_json::Value::Null),
913 )
914 } else {
915 Some(workspace_config.clone())
916 }
917 })
918 .collect())
919 }
920 }
921 })
922 .detach();
923
924 language_server
925 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
926 let this = lsp_store.clone();
927 move |_, cx| {
928 let this = this.clone();
929 let cx = cx.clone();
930 async move {
931 let Some(server) =
932 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
933 else {
934 return Ok(None);
935 };
936 let root = server.workspace_folders();
937 Ok(Some(
938 root.into_iter()
939 .map(|uri| WorkspaceFolder {
940 uri,
941 name: Default::default(),
942 })
943 .collect(),
944 ))
945 }
946 }
947 })
948 .detach();
949 // Even though we don't have handling for these requests, respond to them to
950 // avoid stalling any language server like `gopls` which waits for a response
951 // to these requests when initializing.
952 language_server
953 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
954 let this = lsp_store.clone();
955 move |params, cx| {
956 let this = this.clone();
957 let mut cx = cx.clone();
958 async move {
959 this.update(&mut cx, |this, _| {
960 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
961 {
962 status
963 .progress_tokens
964 .insert(ProgressToken::from_lsp(params.token));
965 }
966 })?;
967
968 Ok(())
969 }
970 }
971 })
972 .detach();
973
974 language_server
975 .on_request::<lsp::request::RegisterCapability, _, _>({
976 let lsp_store = lsp_store.clone();
977 move |params, cx| {
978 let lsp_store = lsp_store.clone();
979 let mut cx = cx.clone();
980 async move {
981 lsp_store
982 .update(&mut cx, |lsp_store, cx| {
983 if lsp_store.as_local().is_some() {
984 match lsp_store
985 .register_server_capabilities(server_id, params, cx)
986 {
987 Ok(()) => {}
988 Err(e) => {
989 log::error!(
990 "Failed to register server capabilities: {e:#}"
991 );
992 }
993 };
994 }
995 })
996 .ok();
997 Ok(())
998 }
999 }
1000 })
1001 .detach();
1002
1003 language_server
1004 .on_request::<lsp::request::UnregisterCapability, _, _>({
1005 let lsp_store = lsp_store.clone();
1006 move |params, cx| {
1007 let lsp_store = lsp_store.clone();
1008 let mut cx = cx.clone();
1009 async move {
1010 lsp_store
1011 .update(&mut cx, |lsp_store, cx| {
1012 if lsp_store.as_local().is_some() {
1013 match lsp_store
1014 .unregister_server_capabilities(server_id, params, cx)
1015 {
1016 Ok(()) => {}
1017 Err(e) => {
1018 log::error!(
1019 "Failed to unregister server capabilities: {e:#}"
1020 );
1021 }
1022 }
1023 }
1024 })
1025 .ok();
1026 Ok(())
1027 }
1028 }
1029 })
1030 .detach();
1031
1032 language_server
1033 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1034 let this = lsp_store.clone();
1035 move |params, cx| {
1036 let mut cx = cx.clone();
1037 let this = this.clone();
1038 async move {
1039 LocalLspStore::on_lsp_workspace_edit(
1040 this.clone(),
1041 params,
1042 server_id,
1043 &mut cx,
1044 )
1045 .await
1046 }
1047 }
1048 })
1049 .detach();
1050
1051 language_server
1052 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1053 let lsp_store = lsp_store.clone();
1054 let request_id = Arc::new(AtomicUsize::new(0));
1055 move |(), cx| {
1056 let lsp_store = lsp_store.clone();
1057 let request_id = request_id.clone();
1058 let mut cx = cx.clone();
1059 async move {
1060 lsp_store
1061 .update(&mut cx, |lsp_store, cx| {
1062 let request_id =
1063 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1064 cx.emit(LspStoreEvent::RefreshInlayHints {
1065 server_id,
1066 request_id,
1067 });
1068 lsp_store
1069 .downstream_client
1070 .as_ref()
1071 .map(|(client, project_id)| {
1072 client.send(proto::RefreshInlayHints {
1073 project_id: *project_id,
1074 server_id: server_id.to_proto(),
1075 request_id: request_id.map(|id| id as u64),
1076 })
1077 })
1078 })?
1079 .transpose()?;
1080 Ok(())
1081 }
1082 }
1083 })
1084 .detach();
1085
1086 language_server
1087 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1088 let this = lsp_store.clone();
1089 move |(), cx| {
1090 let this = this.clone();
1091 let mut cx = cx.clone();
1092 async move {
1093 this.update(&mut cx, |this, cx| {
1094 cx.emit(LspStoreEvent::RefreshCodeLens);
1095 this.downstream_client.as_ref().map(|(client, project_id)| {
1096 client.send(proto::RefreshCodeLens {
1097 project_id: *project_id,
1098 })
1099 })
1100 })?
1101 .transpose()?;
1102 Ok(())
1103 }
1104 }
1105 })
1106 .detach();
1107
1108 language_server
1109 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1110 let lsp_store = lsp_store.clone();
1111 let request_id = Arc::new(AtomicUsize::new(0));
1112 move |(), cx| {
1113 let lsp_store = lsp_store.clone();
1114 let request_id = request_id.clone();
1115 let mut cx = cx.clone();
1116 async move {
1117 lsp_store
1118 .update(&mut cx, |lsp_store, cx| {
1119 let request_id =
1120 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1121 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1122 server_id,
1123 request_id,
1124 });
1125 lsp_store
1126 .downstream_client
1127 .as_ref()
1128 .map(|(client, project_id)| {
1129 client.send(proto::RefreshSemanticTokens {
1130 project_id: *project_id,
1131 server_id: server_id.to_proto(),
1132 request_id: request_id.map(|id| id as u64),
1133 })
1134 })
1135 })?
1136 .transpose()?;
1137 Ok(())
1138 }
1139 }
1140 })
1141 .detach();
1142
1143 language_server
1144 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1145 let this = lsp_store.clone();
1146 move |(), cx| {
1147 let this = this.clone();
1148 let mut cx = cx.clone();
1149 async move {
1150 this.update(&mut cx, |lsp_store, cx| {
1151 lsp_store.pull_workspace_diagnostics(server_id);
1152 lsp_store
1153 .downstream_client
1154 .as_ref()
1155 .map(|(client, project_id)| {
1156 client.send(proto::PullWorkspaceDiagnostics {
1157 project_id: *project_id,
1158 server_id: server_id.to_proto(),
1159 })
1160 })
1161 .transpose()?;
1162 anyhow::Ok(
1163 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1164 )
1165 })??
1166 .await;
1167 Ok(())
1168 }
1169 }
1170 })
1171 .detach();
1172
1173 language_server
1174 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1175 let this = lsp_store.clone();
1176 let name = name.to_string();
1177 let adapter = adapter.clone();
1178 move |params, cx| {
1179 let this = this.clone();
1180 let name = name.to_string();
1181 let adapter = adapter.clone();
1182 let mut cx = cx.clone();
1183 async move {
1184 let actions = params.actions.unwrap_or_default();
1185 let message = params.message.clone();
1186 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1187 let level = match params.typ {
1188 lsp::MessageType::ERROR => PromptLevel::Critical,
1189 lsp::MessageType::WARNING => PromptLevel::Warning,
1190 _ => PromptLevel::Info,
1191 };
1192 let request = LanguageServerPromptRequest::new(
1193 level,
1194 params.message,
1195 actions,
1196 name.clone(),
1197 tx,
1198 );
1199
1200 let did_update = this
1201 .update(&mut cx, |_, cx| {
1202 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1203 })
1204 .is_ok();
1205 if did_update {
1206 let response = rx.recv().await.ok();
1207 if let Some(ref selected_action) = response {
1208 let context = language::PromptResponseContext {
1209 message,
1210 selected_action: selected_action.clone(),
1211 };
1212 adapter.process_prompt_response(&context, &mut cx)
1213 }
1214
1215 Ok(response)
1216 } else {
1217 Ok(None)
1218 }
1219 }
1220 }
1221 })
1222 .detach();
1223 language_server
1224 .on_notification::<lsp::notification::ShowMessage, _>({
1225 let this = lsp_store.clone();
1226 let name = name.to_string();
1227 move |params, cx| {
1228 let this = this.clone();
1229 let name = name.to_string();
1230 let mut cx = cx.clone();
1231
1232 let (tx, _) = smol::channel::bounded(1);
1233 let level = match params.typ {
1234 lsp::MessageType::ERROR => PromptLevel::Critical,
1235 lsp::MessageType::WARNING => PromptLevel::Warning,
1236 _ => PromptLevel::Info,
1237 };
1238 let request =
1239 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1240
1241 let _ = this.update(&mut cx, |_, cx| {
1242 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1243 });
1244 }
1245 })
1246 .detach();
1247
1248 let disk_based_diagnostics_progress_token =
1249 adapter.disk_based_diagnostics_progress_token.clone();
1250
1251 language_server
1252 .on_notification::<lsp::notification::Progress, _>({
1253 let this = lsp_store.clone();
1254 move |params, cx| {
1255 if let Some(this) = this.upgrade() {
1256 this.update(cx, |this, cx| {
1257 this.on_lsp_progress(
1258 params,
1259 server_id,
1260 disk_based_diagnostics_progress_token.clone(),
1261 cx,
1262 );
1263 });
1264 }
1265 }
1266 })
1267 .detach();
1268
1269 language_server
1270 .on_notification::<lsp::notification::LogMessage, _>({
1271 let this = lsp_store.clone();
1272 move |params, cx| {
1273 if let Some(this) = this.upgrade() {
1274 this.update(cx, |_, cx| {
1275 cx.emit(LspStoreEvent::LanguageServerLog(
1276 server_id,
1277 LanguageServerLogType::Log(params.typ),
1278 params.message,
1279 ));
1280 });
1281 }
1282 }
1283 })
1284 .detach();
1285
1286 language_server
1287 .on_notification::<lsp::notification::LogTrace, _>({
1288 let this = lsp_store.clone();
1289 move |params, cx| {
1290 let mut cx = cx.clone();
1291 if let Some(this) = this.upgrade() {
1292 this.update(&mut cx, |_, cx| {
1293 cx.emit(LspStoreEvent::LanguageServerLog(
1294 server_id,
1295 LanguageServerLogType::Trace {
1296 verbose_info: params.verbose,
1297 },
1298 params.message,
1299 ));
1300 });
1301 }
1302 }
1303 })
1304 .detach();
1305
1306 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1307 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1309 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1310 }
1311
1312 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1313 let shutdown_futures = self
1314 .language_servers
1315 .drain()
1316 .map(|(_, server_state)| Self::shutdown_server(server_state))
1317 .collect::<Vec<_>>();
1318
1319 async move {
1320 join_all(shutdown_futures).await;
1321 }
1322 }
1323
1324 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1325 match server_state {
1326 LanguageServerState::Running { server, .. } => {
1327 if let Some(shutdown) = server.shutdown() {
1328 shutdown.await;
1329 }
1330 }
1331 LanguageServerState::Starting { startup, .. } => {
1332 if let Some(server) = startup.await
1333 && let Some(shutdown) = server.shutdown()
1334 {
1335 shutdown.await;
1336 }
1337 }
1338 }
1339 Ok(())
1340 }
1341
1342 fn language_servers_for_worktree(
1343 &self,
1344 worktree_id: WorktreeId,
1345 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1346 self.language_server_ids
1347 .iter()
1348 .filter_map(move |(seed, state)| {
1349 if seed.worktree_id != worktree_id {
1350 return None;
1351 }
1352
1353 if let Some(LanguageServerState::Running { server, .. }) =
1354 self.language_servers.get(&state.id)
1355 {
1356 Some(server)
1357 } else {
1358 None
1359 }
1360 })
1361 }
1362
1363 fn language_server_ids_for_project_path(
1364 &self,
1365 project_path: ProjectPath,
1366 language: &Language,
1367 cx: &mut App,
1368 ) -> Vec<LanguageServerId> {
1369 let Some(worktree) = self
1370 .worktree_store
1371 .read(cx)
1372 .worktree_for_id(project_path.worktree_id, cx)
1373 else {
1374 return Vec::new();
1375 };
1376 let delegate: Arc<dyn ManifestDelegate> =
1377 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1378
1379 self.lsp_tree
1380 .get(
1381 project_path,
1382 language.name(),
1383 language.manifest(),
1384 &delegate,
1385 cx,
1386 )
1387 .collect::<Vec<_>>()
1388 }
1389
1390 fn language_server_ids_for_buffer(
1391 &self,
1392 buffer: &Buffer,
1393 cx: &mut App,
1394 ) -> Vec<LanguageServerId> {
1395 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1396 let worktree_id = file.worktree_id(cx);
1397
1398 let path: Arc<RelPath> = file
1399 .path()
1400 .parent()
1401 .map(Arc::from)
1402 .unwrap_or_else(|| file.path().clone());
1403 let worktree_path = ProjectPath { worktree_id, path };
1404 self.language_server_ids_for_project_path(worktree_path, language, cx)
1405 } else {
1406 Vec::new()
1407 }
1408 }
1409
1410 fn language_servers_for_buffer<'a>(
1411 &'a self,
1412 buffer: &'a Buffer,
1413 cx: &'a mut App,
1414 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1415 self.language_server_ids_for_buffer(buffer, cx)
1416 .into_iter()
1417 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1418 LanguageServerState::Running {
1419 adapter, server, ..
1420 } => Some((adapter, server)),
1421 _ => None,
1422 })
1423 }
1424
1425 async fn execute_code_action_kind_locally(
1426 lsp_store: WeakEntity<LspStore>,
1427 mut buffers: Vec<Entity<Buffer>>,
1428 kind: CodeActionKind,
1429 push_to_history: bool,
1430 cx: &mut AsyncApp,
1431 ) -> anyhow::Result<ProjectTransaction> {
1432 // Do not allow multiple concurrent code actions requests for the
1433 // same buffer.
1434 lsp_store.update(cx, |this, cx| {
1435 let this = this.as_local_mut().unwrap();
1436 buffers.retain(|buffer| {
1437 this.buffers_being_formatted
1438 .insert(buffer.read(cx).remote_id())
1439 });
1440 })?;
1441 let _cleanup = defer({
1442 let this = lsp_store.clone();
1443 let mut cx = cx.clone();
1444 let buffers = &buffers;
1445 move || {
1446 this.update(&mut cx, |this, cx| {
1447 let this = this.as_local_mut().unwrap();
1448 for buffer in buffers {
1449 this.buffers_being_formatted
1450 .remove(&buffer.read(cx).remote_id());
1451 }
1452 })
1453 .ok();
1454 }
1455 });
1456 let mut project_transaction = ProjectTransaction::default();
1457
1458 for buffer in &buffers {
1459 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1460 buffer.update(cx, |buffer, cx| {
1461 lsp_store
1462 .as_local()
1463 .unwrap()
1464 .language_servers_for_buffer(buffer, cx)
1465 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1466 .collect::<Vec<_>>()
1467 })
1468 })?;
1469 for (_, language_server) in adapters_and_servers.iter() {
1470 let actions = Self::get_server_code_actions_from_action_kinds(
1471 &lsp_store,
1472 language_server.server_id(),
1473 vec![kind.clone()],
1474 buffer,
1475 cx,
1476 )
1477 .await?;
1478 Self::execute_code_actions_on_server(
1479 &lsp_store,
1480 language_server,
1481 actions,
1482 push_to_history,
1483 &mut project_transaction,
1484 cx,
1485 )
1486 .await?;
1487 }
1488 }
1489 Ok(project_transaction)
1490 }
1491
1492 async fn format_locally(
1493 lsp_store: WeakEntity<LspStore>,
1494 mut buffers: Vec<FormattableBuffer>,
1495 push_to_history: bool,
1496 trigger: FormatTrigger,
1497 logger: zlog::Logger,
1498 cx: &mut AsyncApp,
1499 ) -> anyhow::Result<ProjectTransaction> {
1500 // Do not allow multiple concurrent formatting requests for the
1501 // same buffer.
1502 lsp_store.update(cx, |this, cx| {
1503 let this = this.as_local_mut().unwrap();
1504 buffers.retain(|buffer| {
1505 this.buffers_being_formatted
1506 .insert(buffer.handle.read(cx).remote_id())
1507 });
1508 })?;
1509
1510 let _cleanup = defer({
1511 let this = lsp_store.clone();
1512 let mut cx = cx.clone();
1513 let buffers = &buffers;
1514 move || {
1515 this.update(&mut cx, |this, cx| {
1516 let this = this.as_local_mut().unwrap();
1517 for buffer in buffers {
1518 this.buffers_being_formatted
1519 .remove(&buffer.handle.read(cx).remote_id());
1520 }
1521 })
1522 .ok();
1523 }
1524 });
1525
1526 let mut project_transaction = ProjectTransaction::default();
1527
1528 for buffer in &buffers {
1529 zlog::debug!(
1530 logger =>
1531 "formatting buffer '{:?}'",
1532 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1533 );
1534 // Create an empty transaction to hold all of the formatting edits.
1535 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1536 // ensure no transactions created while formatting are
1537 // grouped with the previous transaction in the history
1538 // based on the transaction group interval
1539 buffer.finalize_last_transaction();
1540 buffer
1541 .start_transaction()
1542 .context("transaction already open")?;
1543 buffer.end_transaction(cx);
1544 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1545 buffer.finalize_last_transaction();
1546 anyhow::Ok(transaction_id)
1547 })?;
1548
1549 let result = Self::format_buffer_locally(
1550 lsp_store.clone(),
1551 buffer,
1552 formatting_transaction_id,
1553 trigger,
1554 logger,
1555 cx,
1556 )
1557 .await;
1558
1559 buffer.handle.update(cx, |buffer, cx| {
1560 let Some(formatting_transaction) =
1561 buffer.get_transaction(formatting_transaction_id).cloned()
1562 else {
1563 zlog::warn!(logger => "no formatting transaction");
1564 return;
1565 };
1566 if formatting_transaction.edit_ids.is_empty() {
1567 zlog::debug!(logger => "no changes made while formatting");
1568 buffer.forget_transaction(formatting_transaction_id);
1569 return;
1570 }
1571 if !push_to_history {
1572 zlog::trace!(logger => "forgetting format transaction");
1573 buffer.forget_transaction(formatting_transaction.id);
1574 }
1575 project_transaction
1576 .0
1577 .insert(cx.entity(), formatting_transaction);
1578 });
1579
1580 result?;
1581 }
1582
1583 Ok(project_transaction)
1584 }
1585
1586 async fn format_buffer_locally(
1587 lsp_store: WeakEntity<LspStore>,
1588 buffer: &FormattableBuffer,
1589 formatting_transaction_id: clock::Lamport,
1590 trigger: FormatTrigger,
1591 logger: zlog::Logger,
1592 cx: &mut AsyncApp,
1593 ) -> Result<()> {
1594 let (adapters_and_servers, settings, request_timeout) =
1595 lsp_store.update(cx, |lsp_store, cx| {
1596 buffer.handle.update(cx, |buffer, cx| {
1597 let adapters_and_servers = lsp_store
1598 .as_local()
1599 .unwrap()
1600 .language_servers_for_buffer(buffer, cx)
1601 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1602 .collect::<Vec<_>>();
1603 let settings =
1604 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1605 .into_owned();
1606 let request_timeout = ProjectSettings::get_global(cx)
1607 .global_lsp_settings
1608 .get_request_timeout();
1609 (adapters_and_servers, settings, request_timeout)
1610 })
1611 })?;
1612
1613 /// Apply edits to the buffer that will become part of the formatting transaction.
1614 /// Fails if the buffer has been edited since the start of that transaction.
1615 fn extend_formatting_transaction(
1616 buffer: &FormattableBuffer,
1617 formatting_transaction_id: text::TransactionId,
1618 cx: &mut AsyncApp,
1619 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1620 ) -> anyhow::Result<()> {
1621 buffer.handle.update(cx, |buffer, cx| {
1622 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1623 if last_transaction_id != Some(formatting_transaction_id) {
1624 anyhow::bail!("Buffer edited while formatting. Aborting")
1625 }
1626 buffer.start_transaction();
1627 operation(buffer, cx);
1628 if let Some(transaction_id) = buffer.end_transaction(cx) {
1629 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1630 }
1631 Ok(())
1632 })
1633 }
1634
1635 // handle whitespace formatting
1636 if settings.remove_trailing_whitespace_on_save {
1637 zlog::trace!(logger => "removing trailing whitespace");
1638 let diff = buffer
1639 .handle
1640 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1641 .await;
1642 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1643 buffer.apply_diff(diff, cx);
1644 })?;
1645 }
1646
1647 if settings.ensure_final_newline_on_save {
1648 zlog::trace!(logger => "ensuring final newline");
1649 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1650 buffer.ensure_final_newline(cx);
1651 })?;
1652 }
1653
1654 // Formatter for `code_actions_on_format` that runs before
1655 // the rest of the formatters
1656 let mut code_actions_on_format_formatters = None;
1657 let should_run_code_actions_on_format = !matches!(
1658 (trigger, &settings.format_on_save),
1659 (FormatTrigger::Save, &FormatOnSave::Off)
1660 );
1661 if should_run_code_actions_on_format {
1662 let have_code_actions_to_run_on_format = settings
1663 .code_actions_on_format
1664 .values()
1665 .any(|enabled| *enabled);
1666 if have_code_actions_to_run_on_format {
1667 zlog::trace!(logger => "going to run code actions on format");
1668 code_actions_on_format_formatters = Some(
1669 settings
1670 .code_actions_on_format
1671 .iter()
1672 .filter_map(|(action, enabled)| enabled.then_some(action))
1673 .cloned()
1674 .map(Formatter::CodeAction)
1675 .collect::<Vec<_>>(),
1676 );
1677 }
1678 }
1679
1680 let formatters = match (trigger, &settings.format_on_save) {
1681 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1682 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1683 settings.formatter.as_ref()
1684 }
1685 };
1686
1687 let formatters = code_actions_on_format_formatters
1688 .iter()
1689 .flatten()
1690 .chain(formatters);
1691
1692 for formatter in formatters {
1693 let formatter = if formatter == &Formatter::Auto {
1694 if settings.prettier.allowed {
1695 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1696 &Formatter::Prettier
1697 } else {
1698 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1699 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1700 }
1701 } else {
1702 formatter
1703 };
1704 match formatter {
1705 Formatter::Auto => unreachable!("Auto resolved above"),
1706 Formatter::Prettier => {
1707 let logger = zlog::scoped!(logger => "prettier");
1708 zlog::trace!(logger => "formatting");
1709 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1710
1711 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1712 lsp_store.prettier_store().unwrap().downgrade()
1713 })?;
1714 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1715 .await
1716 .transpose()?;
1717 let Some(diff) = diff else {
1718 zlog::trace!(logger => "No changes");
1719 continue;
1720 };
1721
1722 extend_formatting_transaction(
1723 buffer,
1724 formatting_transaction_id,
1725 cx,
1726 |buffer, cx| {
1727 buffer.apply_diff(diff, cx);
1728 },
1729 )?;
1730 }
1731 Formatter::External { command, arguments } => {
1732 let logger = zlog::scoped!(logger => "command");
1733 zlog::trace!(logger => "formatting");
1734 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1735
1736 let diff = Self::format_via_external_command(
1737 buffer,
1738 &command,
1739 arguments.as_deref(),
1740 cx,
1741 )
1742 .await
1743 .with_context(|| {
1744 format!("Failed to format buffer via external command: {}", command)
1745 })?;
1746 let Some(diff) = diff else {
1747 zlog::trace!(logger => "No changes");
1748 continue;
1749 };
1750
1751 extend_formatting_transaction(
1752 buffer,
1753 formatting_transaction_id,
1754 cx,
1755 |buffer, cx| {
1756 buffer.apply_diff(diff, cx);
1757 },
1758 )?;
1759 }
1760 Formatter::LanguageServer(specifier) => {
1761 let logger = zlog::scoped!(logger => "language-server");
1762 zlog::trace!(logger => "formatting");
1763 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1764
1765 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1766 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1767 continue;
1768 };
1769
1770 let language_server = match specifier {
1771 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1772 adapters_and_servers.iter().find_map(|(adapter, server)| {
1773 if adapter.name.0.as_ref() == name {
1774 Some(server.clone())
1775 } else {
1776 None
1777 }
1778 })
1779 }
1780 settings::LanguageServerFormatterSpecifier::Current => {
1781 adapters_and_servers.first().map(|e| e.1.clone())
1782 }
1783 };
1784
1785 let Some(language_server) = language_server else {
1786 log::debug!(
1787 "No language server found to format buffer '{:?}'. Skipping",
1788 buffer_path_abs.as_path().to_string_lossy()
1789 );
1790 continue;
1791 };
1792
1793 zlog::trace!(
1794 logger =>
1795 "Formatting buffer '{:?}' using language server '{:?}'",
1796 buffer_path_abs.as_path().to_string_lossy(),
1797 language_server.name()
1798 );
1799
1800 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1801 zlog::trace!(logger => "formatting ranges");
1802 Self::format_ranges_via_lsp(
1803 &lsp_store,
1804 &buffer.handle,
1805 ranges,
1806 buffer_path_abs,
1807 &language_server,
1808 &settings,
1809 cx,
1810 )
1811 .await
1812 .context("Failed to format ranges via language server")?
1813 } else {
1814 zlog::trace!(logger => "formatting full");
1815 Self::format_via_lsp(
1816 &lsp_store,
1817 &buffer.handle,
1818 buffer_path_abs,
1819 &language_server,
1820 &settings,
1821 cx,
1822 )
1823 .await
1824 .context("failed to format via language server")?
1825 };
1826
1827 if edits.is_empty() {
1828 zlog::trace!(logger => "No changes");
1829 continue;
1830 }
1831 extend_formatting_transaction(
1832 buffer,
1833 formatting_transaction_id,
1834 cx,
1835 |buffer, cx| {
1836 buffer.edit(edits, None, cx);
1837 },
1838 )?;
1839 }
1840 Formatter::CodeAction(code_action_name) => {
1841 let logger = zlog::scoped!(logger => "code-actions");
1842 zlog::trace!(logger => "formatting");
1843 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1844
1845 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1846 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1847 continue;
1848 };
1849
1850 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1851 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1852
1853 let mut actions_and_servers = Vec::new();
1854
1855 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1856 let actions_result = Self::get_server_code_actions_from_action_kinds(
1857 &lsp_store,
1858 language_server.server_id(),
1859 vec![code_action_kind.clone()],
1860 &buffer.handle,
1861 cx,
1862 )
1863 .await
1864 .with_context(|| {
1865 format!(
1866 "Failed to resolve code action {:?} with language server {}",
1867 code_action_kind,
1868 language_server.name()
1869 )
1870 });
1871 let Ok(actions) = actions_result else {
1872 // note: it may be better to set result to the error and break formatters here
1873 // but for now we try to execute the actions that we can resolve and skip the rest
1874 zlog::error!(
1875 logger =>
1876 "Failed to resolve code action {:?} with language server {}",
1877 code_action_kind,
1878 language_server.name()
1879 );
1880 continue;
1881 };
1882 for action in actions {
1883 actions_and_servers.push((action, index));
1884 }
1885 }
1886
1887 if actions_and_servers.is_empty() {
1888 zlog::warn!(logger => "No code actions were resolved, continuing");
1889 continue;
1890 }
1891
1892 'actions: for (mut action, server_index) in actions_and_servers {
1893 let server = &adapters_and_servers[server_index].1;
1894
1895 let describe_code_action = |action: &CodeAction| {
1896 format!(
1897 "code action '{}' with title \"{}\" on server {}",
1898 action
1899 .lsp_action
1900 .action_kind()
1901 .unwrap_or("unknown".into())
1902 .as_str(),
1903 action.lsp_action.title(),
1904 server.name(),
1905 )
1906 };
1907
1908 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1909
1910 if let Err(err) =
1911 Self::try_resolve_code_action(server, &mut action, request_timeout)
1912 .await
1913 {
1914 zlog::error!(
1915 logger =>
1916 "Failed to resolve {}. Error: {}",
1917 describe_code_action(&action),
1918 err
1919 );
1920 continue;
1921 }
1922
1923 if let Some(edit) = action.lsp_action.edit().cloned() {
1924 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1925 // but filters out and logs warnings for code actions that require unreasonably
1926 // difficult handling on our part, such as:
1927 // - applying edits that call commands
1928 // which can result in arbitrary workspace edits being sent from the server that
1929 // have no way of being tied back to the command that initiated them (i.e. we
1930 // can't know which edits are part of the format request, or if the server is done sending
1931 // actions in response to the command)
1932 // - actions that create/delete/modify/rename files other than the one we are formatting
1933 // as we then would need to handle such changes correctly in the local history as well
1934 // as the remote history through the ProjectTransaction
1935 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1936 // Supporting these actions is not impossible, but not supported as of yet.
1937 if edit.changes.is_none() && edit.document_changes.is_none() {
1938 zlog::trace!(
1939 logger =>
1940 "No changes for code action. Skipping {}",
1941 describe_code_action(&action),
1942 );
1943 continue;
1944 }
1945
1946 let mut operations = Vec::new();
1947 if let Some(document_changes) = edit.document_changes {
1948 match document_changes {
1949 lsp::DocumentChanges::Edits(edits) => operations.extend(
1950 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1951 ),
1952 lsp::DocumentChanges::Operations(ops) => operations = ops,
1953 }
1954 } else if let Some(changes) = edit.changes {
1955 operations.extend(changes.into_iter().map(|(uri, edits)| {
1956 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1957 text_document:
1958 lsp::OptionalVersionedTextDocumentIdentifier {
1959 uri,
1960 version: None,
1961 },
1962 edits: edits.into_iter().map(Edit::Plain).collect(),
1963 })
1964 }));
1965 }
1966
1967 let mut edits = Vec::with_capacity(operations.len());
1968
1969 if operations.is_empty() {
1970 zlog::trace!(
1971 logger =>
1972 "No changes for code action. Skipping {}",
1973 describe_code_action(&action),
1974 );
1975 continue;
1976 }
1977 for operation in operations {
1978 let op = match operation {
1979 lsp::DocumentChangeOperation::Edit(op) => op,
1980 lsp::DocumentChangeOperation::Op(_) => {
1981 zlog::warn!(
1982 logger =>
1983 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1984 describe_code_action(&action),
1985 );
1986 continue 'actions;
1987 }
1988 };
1989 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1990 zlog::warn!(
1991 logger =>
1992 "Failed to convert URI '{:?}' to file path. Skipping {}",
1993 &op.text_document.uri,
1994 describe_code_action(&action),
1995 );
1996 continue 'actions;
1997 };
1998 if &file_path != buffer_path_abs {
1999 zlog::warn!(
2000 logger =>
2001 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2002 file_path,
2003 buffer_path_abs,
2004 describe_code_action(&action),
2005 );
2006 continue 'actions;
2007 }
2008
2009 let mut lsp_edits = Vec::new();
2010 for edit in op.edits {
2011 match edit {
2012 Edit::Plain(edit) => {
2013 if !lsp_edits.contains(&edit) {
2014 lsp_edits.push(edit);
2015 }
2016 }
2017 Edit::Annotated(edit) => {
2018 if !lsp_edits.contains(&edit.text_edit) {
2019 lsp_edits.push(edit.text_edit);
2020 }
2021 }
2022 Edit::Snippet(_) => {
2023 zlog::warn!(
2024 logger =>
2025 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2026 describe_code_action(&action),
2027 );
2028 continue 'actions;
2029 }
2030 }
2031 }
2032 let edits_result = lsp_store
2033 .update(cx, |lsp_store, cx| {
2034 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2035 &buffer.handle,
2036 lsp_edits,
2037 server.server_id(),
2038 op.text_document.version,
2039 cx,
2040 )
2041 })?
2042 .await;
2043 let Ok(resolved_edits) = edits_result else {
2044 zlog::warn!(
2045 logger =>
2046 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2047 buffer_path_abs.as_path(),
2048 describe_code_action(&action),
2049 );
2050 continue 'actions;
2051 };
2052 edits.extend(resolved_edits);
2053 }
2054
2055 if edits.is_empty() {
2056 zlog::warn!(logger => "No edits resolved from LSP");
2057 continue;
2058 }
2059
2060 extend_formatting_transaction(
2061 buffer,
2062 formatting_transaction_id,
2063 cx,
2064 |buffer, cx| {
2065 zlog::info!(
2066 "Applying edits {edits:?}. Content: {:?}",
2067 buffer.text()
2068 );
2069 buffer.edit(edits, None, cx);
2070 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2071 },
2072 )?;
2073 }
2074
2075 // bail early if command is invalid
2076 let Some(command) = action.lsp_action.command() else {
2077 continue;
2078 };
2079
2080 zlog::warn!(
2081 logger =>
2082 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2083 &command.command,
2084 );
2085
2086 let server_capabilities = server.capabilities();
2087 let available_commands = server_capabilities
2088 .execute_command_provider
2089 .as_ref()
2090 .map(|options| options.commands.as_slice())
2091 .unwrap_or_default();
2092 if !available_commands.contains(&command.command) {
2093 zlog::warn!(
2094 logger =>
2095 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2096 command.command,
2097 server.name(),
2098 );
2099 continue;
2100 }
2101
2102 // noop so we just ensure buffer hasn't been edited since resolving code actions
2103 extend_formatting_transaction(
2104 buffer,
2105 formatting_transaction_id,
2106 cx,
2107 |_, _| {},
2108 )?;
2109 zlog::info!(logger => "Executing command {}", &command.command);
2110
2111 lsp_store.update(cx, |this, _| {
2112 this.as_local_mut()
2113 .unwrap()
2114 .last_workspace_edits_by_language_server
2115 .remove(&server.server_id());
2116 })?;
2117
2118 let execute_command_result = server
2119 .request::<lsp::request::ExecuteCommand>(
2120 lsp::ExecuteCommandParams {
2121 command: command.command.clone(),
2122 arguments: command.arguments.clone().unwrap_or_default(),
2123 ..Default::default()
2124 },
2125 request_timeout,
2126 )
2127 .await
2128 .into_response();
2129
2130 if execute_command_result.is_err() {
2131 zlog::error!(
2132 logger =>
2133 "Failed to execute command '{}' as part of {}",
2134 &command.command,
2135 describe_code_action(&action),
2136 );
2137 continue 'actions;
2138 }
2139
2140 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2141 this.as_local_mut()
2142 .unwrap()
2143 .last_workspace_edits_by_language_server
2144 .remove(&server.server_id())
2145 .unwrap_or_default()
2146 })?;
2147
2148 if let Some(transaction) =
2149 project_transaction_command.0.remove(&buffer.handle)
2150 {
2151 zlog::trace!(
2152 logger =>
2153 "Successfully captured {} edits that resulted from command {}",
2154 transaction.edit_ids.len(),
2155 &command.command,
2156 );
2157 let transaction_id_project_transaction = transaction.id;
2158 buffer.handle.update(cx, |buffer, _| {
2159 // it may have been removed from history if push_to_history was
2160 // false in deserialize_workspace_edit. If so push it so we
2161 // can merge it with the format transaction
2162 // and pop the combined transaction off the history stack
2163 // later if push_to_history is false
2164 if buffer.get_transaction(transaction.id).is_none() {
2165 buffer.push_transaction(transaction, Instant::now());
2166 }
2167 buffer.merge_transactions(
2168 transaction_id_project_transaction,
2169 formatting_transaction_id,
2170 );
2171 });
2172 }
2173
2174 if project_transaction_command.0.is_empty() {
2175 continue;
2176 }
2177
2178 let mut extra_buffers = String::new();
2179 for buffer in project_transaction_command.0.keys() {
2180 buffer.read_with(cx, |b, cx| {
2181 let Some(path) = b.project_path(cx) else {
2182 return;
2183 };
2184
2185 if !extra_buffers.is_empty() {
2186 extra_buffers.push_str(", ");
2187 }
2188 extra_buffers.push_str(path.path.as_unix_str());
2189 });
2190 }
2191 zlog::warn!(
2192 logger =>
2193 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2194 &command.command,
2195 extra_buffers,
2196 );
2197 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2198 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2199 // add it so it's included, and merge it into the format transaction when its created later
2200 }
2201 }
2202 }
2203 }
2204
2205 Ok(())
2206 }
2207
2208 pub async fn format_ranges_via_lsp(
2209 this: &WeakEntity<LspStore>,
2210 buffer_handle: &Entity<Buffer>,
2211 ranges: &[Range<Anchor>],
2212 abs_path: &Path,
2213 language_server: &Arc<LanguageServer>,
2214 settings: &LanguageSettings,
2215 cx: &mut AsyncApp,
2216 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2217 let capabilities = &language_server.capabilities();
2218 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2219 if range_formatting_provider == Some(&OneOf::Left(false)) {
2220 anyhow::bail!(
2221 "{} language server does not support range formatting",
2222 language_server.name()
2223 );
2224 }
2225
2226 let uri = file_path_to_lsp_url(abs_path)?;
2227 let text_document = lsp::TextDocumentIdentifier::new(uri);
2228
2229 let request_timeout = cx.update(|app| {
2230 ProjectSettings::get_global(app)
2231 .global_lsp_settings
2232 .get_request_timeout()
2233 });
2234 let lsp_edits = {
2235 let mut lsp_ranges = Vec::new();
2236 this.update(cx, |_this, cx| {
2237 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2238 // not have been sent to the language server. This seems like a fairly systemic
2239 // issue, though, the resolution probably is not specific to formatting.
2240 //
2241 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2242 // LSP.
2243 let snapshot = buffer_handle.read(cx).snapshot();
2244 for range in ranges {
2245 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2246 }
2247 anyhow::Ok(())
2248 })??;
2249
2250 let mut edits = None;
2251 for range in lsp_ranges {
2252 if let Some(mut edit) = language_server
2253 .request::<lsp::request::RangeFormatting>(
2254 lsp::DocumentRangeFormattingParams {
2255 text_document: text_document.clone(),
2256 range,
2257 options: lsp_command::lsp_formatting_options(settings),
2258 work_done_progress_params: Default::default(),
2259 },
2260 request_timeout,
2261 )
2262 .await
2263 .into_response()?
2264 {
2265 edits.get_or_insert_with(Vec::new).append(&mut edit);
2266 }
2267 }
2268 edits
2269 };
2270
2271 if let Some(lsp_edits) = lsp_edits {
2272 this.update(cx, |this, cx| {
2273 this.as_local_mut().unwrap().edits_from_lsp(
2274 buffer_handle,
2275 lsp_edits,
2276 language_server.server_id(),
2277 None,
2278 cx,
2279 )
2280 })?
2281 .await
2282 } else {
2283 Ok(Vec::with_capacity(0))
2284 }
2285 }
2286
2287 async fn format_via_lsp(
2288 this: &WeakEntity<LspStore>,
2289 buffer: &Entity<Buffer>,
2290 abs_path: &Path,
2291 language_server: &Arc<LanguageServer>,
2292 settings: &LanguageSettings,
2293 cx: &mut AsyncApp,
2294 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2295 let logger = zlog::scoped!("lsp_format");
2296 zlog::debug!(logger => "Formatting via LSP");
2297
2298 let uri = file_path_to_lsp_url(abs_path)?;
2299 let text_document = lsp::TextDocumentIdentifier::new(uri);
2300 let capabilities = &language_server.capabilities();
2301
2302 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2303 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2304
2305 let request_timeout = cx.update(|app| {
2306 ProjectSettings::get_global(app)
2307 .global_lsp_settings
2308 .get_request_timeout()
2309 });
2310
2311 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2312 let _timer = zlog::time!(logger => "format-full");
2313 language_server
2314 .request::<lsp::request::Formatting>(
2315 lsp::DocumentFormattingParams {
2316 text_document,
2317 options: lsp_command::lsp_formatting_options(settings),
2318 work_done_progress_params: Default::default(),
2319 },
2320 request_timeout,
2321 )
2322 .await
2323 .into_response()?
2324 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2325 let _timer = zlog::time!(logger => "format-range");
2326 let buffer_start = lsp::Position::new(0, 0);
2327 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2328 language_server
2329 .request::<lsp::request::RangeFormatting>(
2330 lsp::DocumentRangeFormattingParams {
2331 text_document: text_document.clone(),
2332 range: lsp::Range::new(buffer_start, buffer_end),
2333 options: lsp_command::lsp_formatting_options(settings),
2334 work_done_progress_params: Default::default(),
2335 },
2336 request_timeout,
2337 )
2338 .await
2339 .into_response()?
2340 } else {
2341 None
2342 };
2343
2344 if let Some(lsp_edits) = lsp_edits {
2345 this.update(cx, |this, cx| {
2346 this.as_local_mut().unwrap().edits_from_lsp(
2347 buffer,
2348 lsp_edits,
2349 language_server.server_id(),
2350 None,
2351 cx,
2352 )
2353 })?
2354 .await
2355 } else {
2356 Ok(Vec::with_capacity(0))
2357 }
2358 }
2359
2360 async fn format_via_external_command(
2361 buffer: &FormattableBuffer,
2362 command: &str,
2363 arguments: Option<&[String]>,
2364 cx: &mut AsyncApp,
2365 ) -> Result<Option<Diff>> {
2366 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2367 let file = File::from_dyn(buffer.file())?;
2368 let worktree = file.worktree.read(cx);
2369 let mut worktree_path = worktree.abs_path().to_path_buf();
2370 if worktree.root_entry()?.is_file() {
2371 worktree_path.pop();
2372 }
2373 Some(worktree_path)
2374 });
2375
2376 use util::command::Stdio;
2377 let mut child = util::command::new_command(command);
2378
2379 if let Some(buffer_env) = buffer.env.as_ref() {
2380 child.envs(buffer_env);
2381 }
2382
2383 if let Some(working_dir_path) = working_dir_path {
2384 child.current_dir(working_dir_path);
2385 }
2386
2387 if let Some(arguments) = arguments {
2388 child.args(arguments.iter().map(|arg| {
2389 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2390 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2391 } else {
2392 arg.replace("{buffer_path}", "Untitled")
2393 }
2394 }));
2395 }
2396
2397 let mut child = child
2398 .stdin(Stdio::piped())
2399 .stdout(Stdio::piped())
2400 .stderr(Stdio::piped())
2401 .spawn()?;
2402
2403 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2404 let text = buffer
2405 .handle
2406 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2407 for chunk in text.chunks() {
2408 stdin.write_all(chunk.as_bytes()).await?;
2409 }
2410 stdin.flush().await?;
2411
2412 let output = child.output().await?;
2413 anyhow::ensure!(
2414 output.status.success(),
2415 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2416 output.status.code(),
2417 String::from_utf8_lossy(&output.stdout),
2418 String::from_utf8_lossy(&output.stderr),
2419 );
2420
2421 let stdout = String::from_utf8(output.stdout)?;
2422 Ok(Some(
2423 buffer
2424 .handle
2425 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2426 .await,
2427 ))
2428 }
2429
2430 async fn try_resolve_code_action(
2431 lang_server: &LanguageServer,
2432 action: &mut CodeAction,
2433 request_timeout: Duration,
2434 ) -> anyhow::Result<()> {
2435 match &mut action.lsp_action {
2436 LspAction::Action(lsp_action) => {
2437 if !action.resolved
2438 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2439 && lsp_action.data.is_some()
2440 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2441 {
2442 **lsp_action = lang_server
2443 .request::<lsp::request::CodeActionResolveRequest>(
2444 *lsp_action.clone(),
2445 request_timeout,
2446 )
2447 .await
2448 .into_response()?;
2449 }
2450 }
2451 LspAction::CodeLens(lens) => {
2452 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2453 *lens = lang_server
2454 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2455 .await
2456 .into_response()?;
2457 }
2458 }
2459 LspAction::Command(_) => {}
2460 }
2461
2462 action.resolved = true;
2463 anyhow::Ok(())
2464 }
2465
2466 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2467 let buffer = buffer_handle.read(cx);
2468
2469 let file = buffer.file().cloned();
2470
2471 let Some(file) = File::from_dyn(file.as_ref()) else {
2472 return;
2473 };
2474 if !file.is_local() {
2475 return;
2476 }
2477 let path = ProjectPath::from_file(file, cx);
2478 let worktree_id = file.worktree_id(cx);
2479 let language = buffer.language().cloned();
2480
2481 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2482 for (server_id, diagnostics) in
2483 diagnostics.get(file.path()).cloned().unwrap_or_default()
2484 {
2485 self.update_buffer_diagnostics(
2486 buffer_handle,
2487 server_id,
2488 None,
2489 None,
2490 None,
2491 Vec::new(),
2492 diagnostics,
2493 cx,
2494 )
2495 .log_err();
2496 }
2497 }
2498 let Some(language) = language else {
2499 return;
2500 };
2501 let Some(snapshot) = self
2502 .worktree_store
2503 .read(cx)
2504 .worktree_for_id(worktree_id, cx)
2505 .map(|worktree| worktree.read(cx).snapshot())
2506 else {
2507 return;
2508 };
2509 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2510
2511 for server_id in
2512 self.lsp_tree
2513 .get(path, language.name(), language.manifest(), &delegate, cx)
2514 {
2515 let server = self
2516 .language_servers
2517 .get(&server_id)
2518 .and_then(|server_state| {
2519 if let LanguageServerState::Running { server, .. } = server_state {
2520 Some(server.clone())
2521 } else {
2522 None
2523 }
2524 });
2525 let server = match server {
2526 Some(server) => server,
2527 None => continue,
2528 };
2529
2530 buffer_handle.update(cx, |buffer, cx| {
2531 buffer.set_completion_triggers(
2532 server.server_id(),
2533 server
2534 .capabilities()
2535 .completion_provider
2536 .as_ref()
2537 .and_then(|provider| {
2538 provider
2539 .trigger_characters
2540 .as_ref()
2541 .map(|characters| characters.iter().cloned().collect())
2542 })
2543 .unwrap_or_default(),
2544 cx,
2545 );
2546 });
2547 }
2548 }
2549
2550 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2551 buffer.update(cx, |buffer, cx| {
2552 let Some(language) = buffer.language() else {
2553 return;
2554 };
2555 let path = ProjectPath {
2556 worktree_id: old_file.worktree_id(cx),
2557 path: old_file.path.clone(),
2558 };
2559 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2560 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2561 buffer.set_completion_triggers(server_id, Default::default(), cx);
2562 }
2563 });
2564 }
2565
2566 fn update_buffer_diagnostics(
2567 &mut self,
2568 buffer: &Entity<Buffer>,
2569 server_id: LanguageServerId,
2570 registration_id: Option<Option<SharedString>>,
2571 result_id: Option<SharedString>,
2572 version: Option<i32>,
2573 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2574 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2575 cx: &mut Context<LspStore>,
2576 ) -> Result<()> {
2577 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2578 Ordering::Equal
2579 .then_with(|| b.is_primary.cmp(&a.is_primary))
2580 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2581 .then_with(|| a.severity.cmp(&b.severity))
2582 .then_with(|| a.message.cmp(&b.message))
2583 }
2584
2585 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2586 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2587 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2588
2589 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2590 Ordering::Equal
2591 .then_with(|| a.range.start.cmp(&b.range.start))
2592 .then_with(|| b.range.end.cmp(&a.range.end))
2593 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2594 });
2595
2596 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2597
2598 let edits_since_save = std::cell::LazyCell::new(|| {
2599 let saved_version = buffer.read(cx).saved_version();
2600 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2601 });
2602
2603 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2604
2605 for (new_diagnostic, entry) in diagnostics {
2606 let start;
2607 let end;
2608 if new_diagnostic && entry.diagnostic.is_disk_based {
2609 // Some diagnostics are based on files on disk instead of buffers'
2610 // current contents. Adjust these diagnostics' ranges to reflect
2611 // any unsaved edits.
2612 // Do not alter the reused ones though, as their coordinates were stored as anchors
2613 // and were properly adjusted on reuse.
2614 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2615 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2616 } else {
2617 start = entry.range.start;
2618 end = entry.range.end;
2619 }
2620
2621 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2622 ..snapshot.clip_point_utf16(end, Bias::Right);
2623
2624 // Expand empty ranges by one codepoint
2625 if range.start == range.end {
2626 // This will be go to the next boundary when being clipped
2627 range.end.column += 1;
2628 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2629 if range.start == range.end && range.end.column > 0 {
2630 range.start.column -= 1;
2631 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2632 }
2633 }
2634
2635 sanitized_diagnostics.push(DiagnosticEntry {
2636 range,
2637 diagnostic: entry.diagnostic,
2638 });
2639 }
2640 drop(edits_since_save);
2641
2642 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2643 buffer.update(cx, |buffer, cx| {
2644 if let Some(registration_id) = registration_id {
2645 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2646 self.buffer_pull_diagnostics_result_ids
2647 .entry(server_id)
2648 .or_default()
2649 .entry(registration_id)
2650 .or_default()
2651 .insert(abs_path, result_id);
2652 }
2653 }
2654
2655 buffer.update_diagnostics(server_id, set, cx)
2656 });
2657
2658 Ok(())
2659 }
2660
2661 fn register_language_server_for_invisible_worktree(
2662 &mut self,
2663 worktree: &Entity<Worktree>,
2664 language_server_id: LanguageServerId,
2665 cx: &mut App,
2666 ) {
2667 let worktree = worktree.read(cx);
2668 let worktree_id = worktree.id();
2669 debug_assert!(!worktree.is_visible());
2670 let Some(mut origin_seed) = self
2671 .language_server_ids
2672 .iter()
2673 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2674 else {
2675 return;
2676 };
2677 origin_seed.worktree_id = worktree_id;
2678 self.language_server_ids
2679 .entry(origin_seed)
2680 .or_insert_with(|| UnifiedLanguageServer {
2681 id: language_server_id,
2682 project_roots: Default::default(),
2683 });
2684 }
2685
2686 fn register_buffer_with_language_servers(
2687 &mut self,
2688 buffer_handle: &Entity<Buffer>,
2689 only_register_servers: HashSet<LanguageServerSelector>,
2690 cx: &mut Context<LspStore>,
2691 ) {
2692 let buffer = buffer_handle.read(cx);
2693 let buffer_id = buffer.remote_id();
2694
2695 let Some(file) = File::from_dyn(buffer.file()) else {
2696 return;
2697 };
2698 if !file.is_local() {
2699 return;
2700 }
2701
2702 let abs_path = file.abs_path(cx);
2703 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2704 return;
2705 };
2706 let initial_snapshot = buffer.text_snapshot();
2707 let worktree_id = file.worktree_id(cx);
2708
2709 let Some(language) = buffer.language().cloned() else {
2710 return;
2711 };
2712 let path: Arc<RelPath> = file
2713 .path()
2714 .parent()
2715 .map(Arc::from)
2716 .unwrap_or_else(|| file.path().clone());
2717 let Some(worktree) = self
2718 .worktree_store
2719 .read(cx)
2720 .worktree_for_id(worktree_id, cx)
2721 else {
2722 return;
2723 };
2724 let language_name = language.name();
2725 let (reused, delegate, servers) = self
2726 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2727 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2728 .unwrap_or_else(|| {
2729 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2730 let delegate: Arc<dyn ManifestDelegate> =
2731 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2732
2733 let servers = self
2734 .lsp_tree
2735 .walk(
2736 ProjectPath { worktree_id, path },
2737 language.name(),
2738 language.manifest(),
2739 &delegate,
2740 cx,
2741 )
2742 .collect::<Vec<_>>();
2743 (false, lsp_delegate, servers)
2744 });
2745 let servers_and_adapters = servers
2746 .into_iter()
2747 .filter_map(|server_node| {
2748 if reused && server_node.server_id().is_none() {
2749 return None;
2750 }
2751 if !only_register_servers.is_empty() {
2752 if let Some(server_id) = server_node.server_id()
2753 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2754 {
2755 return None;
2756 }
2757 if let Some(name) = server_node.name()
2758 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2759 {
2760 return None;
2761 }
2762 }
2763
2764 let server_id = server_node.server_id_or_init(|disposition| {
2765 let path = &disposition.path;
2766
2767 {
2768 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2769
2770 let server_id = self.get_or_insert_language_server(
2771 &worktree,
2772 delegate.clone(),
2773 disposition,
2774 &language_name,
2775 cx,
2776 );
2777
2778 if let Some(state) = self.language_servers.get(&server_id)
2779 && let Ok(uri) = uri
2780 {
2781 state.add_workspace_folder(uri);
2782 };
2783 server_id
2784 }
2785 })?;
2786 let server_state = self.language_servers.get(&server_id)?;
2787 if let LanguageServerState::Running {
2788 server, adapter, ..
2789 } = server_state
2790 {
2791 Some((server.clone(), adapter.clone()))
2792 } else {
2793 None
2794 }
2795 })
2796 .collect::<Vec<_>>();
2797 for (server, adapter) in servers_and_adapters {
2798 buffer_handle.update(cx, |buffer, cx| {
2799 buffer.set_completion_triggers(
2800 server.server_id(),
2801 server
2802 .capabilities()
2803 .completion_provider
2804 .as_ref()
2805 .and_then(|provider| {
2806 provider
2807 .trigger_characters
2808 .as_ref()
2809 .map(|characters| characters.iter().cloned().collect())
2810 })
2811 .unwrap_or_default(),
2812 cx,
2813 );
2814 });
2815
2816 let snapshot = LspBufferSnapshot {
2817 version: 0,
2818 snapshot: initial_snapshot.clone(),
2819 };
2820
2821 let mut registered = false;
2822 self.buffer_snapshots
2823 .entry(buffer_id)
2824 .or_default()
2825 .entry(server.server_id())
2826 .or_insert_with(|| {
2827 registered = true;
2828 server.register_buffer(
2829 uri.clone(),
2830 adapter.language_id(&language.name()),
2831 0,
2832 initial_snapshot.text(),
2833 );
2834
2835 vec![snapshot]
2836 });
2837
2838 self.buffers_opened_in_servers
2839 .entry(buffer_id)
2840 .or_default()
2841 .insert(server.server_id());
2842 if registered {
2843 cx.emit(LspStoreEvent::LanguageServerUpdate {
2844 language_server_id: server.server_id(),
2845 name: None,
2846 message: proto::update_language_server::Variant::RegisteredForBuffer(
2847 proto::RegisteredForBuffer {
2848 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2849 buffer_id: buffer_id.to_proto(),
2850 },
2851 ),
2852 });
2853 }
2854 }
2855 }
2856
2857 fn reuse_existing_language_server<'lang_name>(
2858 &self,
2859 server_tree: &LanguageServerTree,
2860 worktree: &Entity<Worktree>,
2861 language_name: &'lang_name LanguageName,
2862 cx: &mut App,
2863 ) -> Option<(
2864 Arc<LocalLspAdapterDelegate>,
2865 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2866 )> {
2867 if worktree.read(cx).is_visible() {
2868 return None;
2869 }
2870
2871 let worktree_store = self.worktree_store.read(cx);
2872 let servers = server_tree
2873 .instances
2874 .iter()
2875 .filter(|(worktree_id, _)| {
2876 worktree_store
2877 .worktree_for_id(**worktree_id, cx)
2878 .is_some_and(|worktree| worktree.read(cx).is_visible())
2879 })
2880 .flat_map(|(worktree_id, servers)| {
2881 servers
2882 .roots
2883 .iter()
2884 .flat_map(|(_, language_servers)| language_servers)
2885 .map(move |(_, (server_node, server_languages))| {
2886 (worktree_id, server_node, server_languages)
2887 })
2888 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2889 .map(|(worktree_id, server_node, _)| {
2890 (
2891 *worktree_id,
2892 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2893 )
2894 })
2895 })
2896 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2897 acc.entry(worktree_id)
2898 .or_insert_with(Vec::new)
2899 .push(server_node);
2900 acc
2901 })
2902 .into_values()
2903 .max_by_key(|servers| servers.len())?;
2904
2905 let worktree_id = worktree.read(cx).id();
2906 let apply = move |tree: &mut LanguageServerTree| {
2907 for server_node in &servers {
2908 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2909 }
2910 servers
2911 };
2912
2913 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2914 Some((delegate, apply))
2915 }
2916
2917 pub(crate) fn unregister_old_buffer_from_language_servers(
2918 &mut self,
2919 buffer: &Entity<Buffer>,
2920 old_file: &File,
2921 cx: &mut App,
2922 ) {
2923 let old_path = match old_file.as_local() {
2924 Some(local) => local.abs_path(cx),
2925 None => return,
2926 };
2927
2928 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2929 debug_panic!("{old_path:?} is not parseable as an URI");
2930 return;
2931 };
2932 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2933 }
2934
2935 pub(crate) fn unregister_buffer_from_language_servers(
2936 &mut self,
2937 buffer: &Entity<Buffer>,
2938 file_url: &lsp::Uri,
2939 cx: &mut App,
2940 ) {
2941 buffer.update(cx, |buffer, cx| {
2942 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2943
2944 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2945 if snapshots
2946 .as_mut()
2947 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2948 {
2949 language_server.unregister_buffer(file_url.clone());
2950 }
2951 }
2952 });
2953 }
2954
2955 fn buffer_snapshot_for_lsp_version(
2956 &mut self,
2957 buffer: &Entity<Buffer>,
2958 server_id: LanguageServerId,
2959 version: Option<i32>,
2960 cx: &App,
2961 ) -> Result<TextBufferSnapshot> {
2962 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2963
2964 if let Some(version) = version {
2965 let buffer_id = buffer.read(cx).remote_id();
2966 let snapshots = if let Some(snapshots) = self
2967 .buffer_snapshots
2968 .get_mut(&buffer_id)
2969 .and_then(|m| m.get_mut(&server_id))
2970 {
2971 snapshots
2972 } else if version == 0 {
2973 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2974 // We detect this case and treat it as if the version was `None`.
2975 return Ok(buffer.read(cx).text_snapshot());
2976 } else {
2977 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2978 };
2979
2980 let found_snapshot = snapshots
2981 .binary_search_by_key(&version, |e| e.version)
2982 .map(|ix| snapshots[ix].snapshot.clone())
2983 .map_err(|_| {
2984 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2985 })?;
2986
2987 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2988 Ok(found_snapshot)
2989 } else {
2990 Ok((buffer.read(cx)).text_snapshot())
2991 }
2992 }
2993
2994 async fn get_server_code_actions_from_action_kinds(
2995 lsp_store: &WeakEntity<LspStore>,
2996 language_server_id: LanguageServerId,
2997 code_action_kinds: Vec<lsp::CodeActionKind>,
2998 buffer: &Entity<Buffer>,
2999 cx: &mut AsyncApp,
3000 ) -> Result<Vec<CodeAction>> {
3001 let actions = lsp_store
3002 .update(cx, move |this, cx| {
3003 let request = GetCodeActions {
3004 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3005 kinds: Some(code_action_kinds),
3006 };
3007 let server = LanguageServerToQuery::Other(language_server_id);
3008 this.request_lsp(buffer.clone(), server, request, cx)
3009 })?
3010 .await?;
3011 Ok(actions)
3012 }
3013
3014 pub async fn execute_code_actions_on_server(
3015 lsp_store: &WeakEntity<LspStore>,
3016 language_server: &Arc<LanguageServer>,
3017 actions: Vec<CodeAction>,
3018 push_to_history: bool,
3019 project_transaction: &mut ProjectTransaction,
3020 cx: &mut AsyncApp,
3021 ) -> anyhow::Result<()> {
3022 let request_timeout = cx.update(|app| {
3023 ProjectSettings::get_global(app)
3024 .global_lsp_settings
3025 .get_request_timeout()
3026 });
3027
3028 for mut action in actions {
3029 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3030 .await
3031 .context("resolving a formatting code action")?;
3032
3033 if let Some(edit) = action.lsp_action.edit() {
3034 if edit.changes.is_none() && edit.document_changes.is_none() {
3035 continue;
3036 }
3037
3038 let new = Self::deserialize_workspace_edit(
3039 lsp_store.upgrade().context("project dropped")?,
3040 edit.clone(),
3041 push_to_history,
3042 language_server.clone(),
3043 cx,
3044 )
3045 .await?;
3046 project_transaction.0.extend(new.0);
3047 }
3048
3049 let Some(command) = action.lsp_action.command() else {
3050 continue;
3051 };
3052
3053 let server_capabilities = language_server.capabilities();
3054 let available_commands = server_capabilities
3055 .execute_command_provider
3056 .as_ref()
3057 .map(|options| options.commands.as_slice())
3058 .unwrap_or_default();
3059 if !available_commands.contains(&command.command) {
3060 log::warn!(
3061 "Cannot execute a command {} not listed in the language server capabilities",
3062 command.command
3063 );
3064 continue;
3065 }
3066
3067 lsp_store.update(cx, |lsp_store, _| {
3068 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3069 mode.last_workspace_edits_by_language_server
3070 .remove(&language_server.server_id());
3071 }
3072 })?;
3073
3074 language_server
3075 .request::<lsp::request::ExecuteCommand>(
3076 lsp::ExecuteCommandParams {
3077 command: command.command.clone(),
3078 arguments: command.arguments.clone().unwrap_or_default(),
3079 ..Default::default()
3080 },
3081 request_timeout,
3082 )
3083 .await
3084 .into_response()
3085 .context("execute command")?;
3086
3087 lsp_store.update(cx, |this, _| {
3088 if let LspStoreMode::Local(mode) = &mut this.mode {
3089 project_transaction.0.extend(
3090 mode.last_workspace_edits_by_language_server
3091 .remove(&language_server.server_id())
3092 .unwrap_or_default()
3093 .0,
3094 )
3095 }
3096 })?;
3097 }
3098 Ok(())
3099 }
3100
3101 pub async fn deserialize_text_edits(
3102 this: Entity<LspStore>,
3103 buffer_to_edit: Entity<Buffer>,
3104 edits: Vec<lsp::TextEdit>,
3105 push_to_history: bool,
3106 _: Arc<CachedLspAdapter>,
3107 language_server: Arc<LanguageServer>,
3108 cx: &mut AsyncApp,
3109 ) -> Result<Option<Transaction>> {
3110 let edits = this
3111 .update(cx, |this, cx| {
3112 this.as_local_mut().unwrap().edits_from_lsp(
3113 &buffer_to_edit,
3114 edits,
3115 language_server.server_id(),
3116 None,
3117 cx,
3118 )
3119 })
3120 .await?;
3121
3122 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3123 buffer.finalize_last_transaction();
3124 buffer.start_transaction();
3125 for (range, text) in edits {
3126 buffer.edit([(range, text)], None, cx);
3127 }
3128
3129 if buffer.end_transaction(cx).is_some() {
3130 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3131 if !push_to_history {
3132 buffer.forget_transaction(transaction.id);
3133 }
3134 Some(transaction)
3135 } else {
3136 None
3137 }
3138 });
3139
3140 Ok(transaction)
3141 }
3142
3143 #[allow(clippy::type_complexity)]
3144 pub fn edits_from_lsp(
3145 &mut self,
3146 buffer: &Entity<Buffer>,
3147 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3148 server_id: LanguageServerId,
3149 version: Option<i32>,
3150 cx: &mut Context<LspStore>,
3151 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3152 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3153 cx.background_spawn(async move {
3154 let snapshot = snapshot?;
3155 let mut lsp_edits = lsp_edits
3156 .into_iter()
3157 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3158 .collect::<Vec<_>>();
3159
3160 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3161
3162 let mut lsp_edits = lsp_edits.into_iter().peekable();
3163 let mut edits = Vec::new();
3164 while let Some((range, mut new_text)) = lsp_edits.next() {
3165 // Clip invalid ranges provided by the language server.
3166 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3167 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3168
3169 // Combine any LSP edits that are adjacent.
3170 //
3171 // Also, combine LSP edits that are separated from each other by only
3172 // a newline. This is important because for some code actions,
3173 // Rust-analyzer rewrites the entire buffer via a series of edits that
3174 // are separated by unchanged newline characters.
3175 //
3176 // In order for the diffing logic below to work properly, any edits that
3177 // cancel each other out must be combined into one.
3178 while let Some((next_range, next_text)) = lsp_edits.peek() {
3179 if next_range.start.0 > range.end {
3180 if next_range.start.0.row > range.end.row + 1
3181 || next_range.start.0.column > 0
3182 || snapshot.clip_point_utf16(
3183 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3184 Bias::Left,
3185 ) > range.end
3186 {
3187 break;
3188 }
3189 new_text.push('\n');
3190 }
3191 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3192 new_text.push_str(next_text);
3193 lsp_edits.next();
3194 }
3195
3196 // For multiline edits, perform a diff of the old and new text so that
3197 // we can identify the changes more precisely, preserving the locations
3198 // of any anchors positioned in the unchanged regions.
3199 if range.end.row > range.start.row {
3200 let offset = range.start.to_offset(&snapshot);
3201 let old_text = snapshot.text_for_range(range).collect::<String>();
3202 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3203 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3204 (
3205 snapshot.anchor_after(offset + range.start)
3206 ..snapshot.anchor_before(offset + range.end),
3207 replacement,
3208 )
3209 }));
3210 } else if range.end == range.start {
3211 let anchor = snapshot.anchor_after(range.start);
3212 edits.push((anchor..anchor, new_text.into()));
3213 } else {
3214 let edit_start = snapshot.anchor_after(range.start);
3215 let edit_end = snapshot.anchor_before(range.end);
3216 edits.push((edit_start..edit_end, new_text.into()));
3217 }
3218 }
3219
3220 Ok(edits)
3221 })
3222 }
3223
3224 pub(crate) async fn deserialize_workspace_edit(
3225 this: Entity<LspStore>,
3226 edit: lsp::WorkspaceEdit,
3227 push_to_history: bool,
3228 language_server: Arc<LanguageServer>,
3229 cx: &mut AsyncApp,
3230 ) -> Result<ProjectTransaction> {
3231 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3232
3233 let mut operations = Vec::new();
3234 if let Some(document_changes) = edit.document_changes {
3235 match document_changes {
3236 lsp::DocumentChanges::Edits(edits) => {
3237 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3238 }
3239 lsp::DocumentChanges::Operations(ops) => operations = ops,
3240 }
3241 } else if let Some(changes) = edit.changes {
3242 operations.extend(changes.into_iter().map(|(uri, edits)| {
3243 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3244 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3245 uri,
3246 version: None,
3247 },
3248 edits: edits.into_iter().map(Edit::Plain).collect(),
3249 })
3250 }));
3251 }
3252
3253 let mut project_transaction = ProjectTransaction::default();
3254 for operation in operations {
3255 match operation {
3256 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3257 let abs_path = op
3258 .uri
3259 .to_file_path()
3260 .map_err(|()| anyhow!("can't convert URI to path"))?;
3261
3262 if let Some(parent_path) = abs_path.parent() {
3263 fs.create_dir(parent_path).await?;
3264 }
3265 if abs_path.ends_with("/") {
3266 fs.create_dir(&abs_path).await?;
3267 } else {
3268 fs.create_file(
3269 &abs_path,
3270 op.options
3271 .map(|options| fs::CreateOptions {
3272 overwrite: options.overwrite.unwrap_or(false),
3273 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3274 })
3275 .unwrap_or_default(),
3276 )
3277 .await?;
3278 }
3279 }
3280
3281 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3282 let source_abs_path = op
3283 .old_uri
3284 .to_file_path()
3285 .map_err(|()| anyhow!("can't convert URI to path"))?;
3286 let target_abs_path = op
3287 .new_uri
3288 .to_file_path()
3289 .map_err(|()| anyhow!("can't convert URI to path"))?;
3290
3291 let options = fs::RenameOptions {
3292 overwrite: op
3293 .options
3294 .as_ref()
3295 .and_then(|options| options.overwrite)
3296 .unwrap_or(false),
3297 ignore_if_exists: op
3298 .options
3299 .as_ref()
3300 .and_then(|options| options.ignore_if_exists)
3301 .unwrap_or(false),
3302 create_parents: true,
3303 };
3304
3305 fs.rename(&source_abs_path, &target_abs_path, options)
3306 .await?;
3307 }
3308
3309 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3310 let abs_path = op
3311 .uri
3312 .to_file_path()
3313 .map_err(|()| anyhow!("can't convert URI to path"))?;
3314 let options = op
3315 .options
3316 .map(|options| fs::RemoveOptions {
3317 recursive: options.recursive.unwrap_or(false),
3318 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3319 })
3320 .unwrap_or_default();
3321 if abs_path.ends_with("/") {
3322 fs.remove_dir(&abs_path, options).await?;
3323 } else {
3324 fs.remove_file(&abs_path, options).await?;
3325 }
3326 }
3327
3328 lsp::DocumentChangeOperation::Edit(op) => {
3329 let buffer_to_edit = this
3330 .update(cx, |this, cx| {
3331 this.open_local_buffer_via_lsp(
3332 op.text_document.uri.clone(),
3333 language_server.server_id(),
3334 cx,
3335 )
3336 })
3337 .await?;
3338
3339 let edits = this
3340 .update(cx, |this, cx| {
3341 let path = buffer_to_edit.read(cx).project_path(cx);
3342 let active_entry = this.active_entry;
3343 let is_active_entry = path.is_some_and(|project_path| {
3344 this.worktree_store
3345 .read(cx)
3346 .entry_for_path(&project_path, cx)
3347 .is_some_and(|entry| Some(entry.id) == active_entry)
3348 });
3349 let local = this.as_local_mut().unwrap();
3350
3351 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3352 for edit in op.edits {
3353 match edit {
3354 Edit::Plain(edit) => {
3355 if !edits.contains(&edit) {
3356 edits.push(edit)
3357 }
3358 }
3359 Edit::Annotated(edit) => {
3360 if !edits.contains(&edit.text_edit) {
3361 edits.push(edit.text_edit)
3362 }
3363 }
3364 Edit::Snippet(edit) => {
3365 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3366 else {
3367 continue;
3368 };
3369
3370 if is_active_entry {
3371 snippet_edits.push((edit.range, snippet));
3372 } else {
3373 // Since this buffer is not focused, apply a normal edit.
3374 let new_edit = TextEdit {
3375 range: edit.range,
3376 new_text: snippet.text,
3377 };
3378 if !edits.contains(&new_edit) {
3379 edits.push(new_edit);
3380 }
3381 }
3382 }
3383 }
3384 }
3385 if !snippet_edits.is_empty() {
3386 let buffer_id = buffer_to_edit.read(cx).remote_id();
3387 let version = if let Some(buffer_version) = op.text_document.version
3388 {
3389 local
3390 .buffer_snapshot_for_lsp_version(
3391 &buffer_to_edit,
3392 language_server.server_id(),
3393 Some(buffer_version),
3394 cx,
3395 )
3396 .ok()
3397 .map(|snapshot| snapshot.version)
3398 } else {
3399 Some(buffer_to_edit.read(cx).saved_version().clone())
3400 };
3401
3402 let most_recent_edit =
3403 version.and_then(|version| version.most_recent());
3404 // Check if the edit that triggered that edit has been made by this participant.
3405
3406 if let Some(most_recent_edit) = most_recent_edit {
3407 cx.emit(LspStoreEvent::SnippetEdit {
3408 buffer_id,
3409 edits: snippet_edits,
3410 most_recent_edit,
3411 });
3412 }
3413 }
3414
3415 local.edits_from_lsp(
3416 &buffer_to_edit,
3417 edits,
3418 language_server.server_id(),
3419 op.text_document.version,
3420 cx,
3421 )
3422 })
3423 .await?;
3424
3425 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3426 buffer.finalize_last_transaction();
3427 buffer.start_transaction();
3428 for (range, text) in edits {
3429 buffer.edit([(range, text)], None, cx);
3430 }
3431
3432 buffer.end_transaction(cx).and_then(|transaction_id| {
3433 if push_to_history {
3434 buffer.finalize_last_transaction();
3435 buffer.get_transaction(transaction_id).cloned()
3436 } else {
3437 buffer.forget_transaction(transaction_id)
3438 }
3439 })
3440 });
3441 if let Some(transaction) = transaction {
3442 project_transaction.0.insert(buffer_to_edit, transaction);
3443 }
3444 }
3445 }
3446 }
3447
3448 Ok(project_transaction)
3449 }
3450
3451 async fn on_lsp_workspace_edit(
3452 this: WeakEntity<LspStore>,
3453 params: lsp::ApplyWorkspaceEditParams,
3454 server_id: LanguageServerId,
3455 cx: &mut AsyncApp,
3456 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3457 let this = this.upgrade().context("project project closed")?;
3458 let language_server = this
3459 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3460 .context("language server not found")?;
3461 let transaction = Self::deserialize_workspace_edit(
3462 this.clone(),
3463 params.edit,
3464 true,
3465 language_server.clone(),
3466 cx,
3467 )
3468 .await
3469 .log_err();
3470 this.update(cx, |this, cx| {
3471 if let Some(transaction) = transaction {
3472 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3473
3474 this.as_local_mut()
3475 .unwrap()
3476 .last_workspace_edits_by_language_server
3477 .insert(server_id, transaction);
3478 }
3479 });
3480 Ok(lsp::ApplyWorkspaceEditResponse {
3481 applied: true,
3482 failed_change: None,
3483 failure_reason: None,
3484 })
3485 }
3486
3487 fn remove_worktree(
3488 &mut self,
3489 id_to_remove: WorktreeId,
3490 cx: &mut Context<LspStore>,
3491 ) -> Vec<LanguageServerId> {
3492 self.restricted_worktrees_tasks.remove(&id_to_remove);
3493 self.diagnostics.remove(&id_to_remove);
3494 self.prettier_store.update(cx, |prettier_store, cx| {
3495 prettier_store.remove_worktree(id_to_remove, cx);
3496 });
3497
3498 let mut servers_to_remove = BTreeSet::default();
3499 let mut servers_to_preserve = HashSet::default();
3500 for (seed, state) in &self.language_server_ids {
3501 if seed.worktree_id == id_to_remove {
3502 servers_to_remove.insert(state.id);
3503 } else {
3504 servers_to_preserve.insert(state.id);
3505 }
3506 }
3507 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3508 self.language_server_ids
3509 .retain(|_, state| !servers_to_remove.contains(&state.id));
3510 for server_id_to_remove in &servers_to_remove {
3511 self.language_server_watched_paths
3512 .remove(server_id_to_remove);
3513 self.language_server_paths_watched_for_rename
3514 .remove(server_id_to_remove);
3515 self.last_workspace_edits_by_language_server
3516 .remove(server_id_to_remove);
3517 self.language_servers.remove(server_id_to_remove);
3518 self.buffer_pull_diagnostics_result_ids
3519 .remove(server_id_to_remove);
3520 self.workspace_pull_diagnostics_result_ids
3521 .remove(server_id_to_remove);
3522 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3523 buffer_servers.remove(server_id_to_remove);
3524 }
3525 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3526 }
3527 servers_to_remove.into_iter().collect()
3528 }
3529
3530 fn build_watched_paths_registration(
3531 &self,
3532 language_server_id: LanguageServerId,
3533 watchers: &[FileSystemWatcher],
3534 cx: &mut Context<LspStore>,
3535 ) -> WatchedPathsRegistration {
3536 let worktrees = self
3537 .worktree_store
3538 .read(cx)
3539 .worktrees()
3540 .filter_map(|worktree| {
3541 self.language_servers_for_worktree(worktree.read(cx).id())
3542 .find(|server| server.server_id() == language_server_id)
3543 .map(|_| worktree)
3544 })
3545 .collect::<Vec<_>>();
3546
3547 let mut worktree_globs = HashMap::default();
3548 let mut abs_globs = HashMap::default();
3549 log::trace!(
3550 "Processing new watcher paths for language server with id {}",
3551 language_server_id
3552 );
3553
3554 for watcher in watchers {
3555 if let Some((worktree, literal_prefix, pattern)) =
3556 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3557 {
3558 worktree.update(cx, |worktree, _| {
3559 if let Some((tree, glob)) =
3560 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3561 {
3562 tree.add_path_prefix_to_scan(literal_prefix);
3563 worktree_globs
3564 .entry(tree.id())
3565 .or_insert_with(GlobSetBuilder::new)
3566 .add(glob);
3567 }
3568 });
3569 } else {
3570 let (path, pattern) = match &watcher.glob_pattern {
3571 lsp::GlobPattern::String(s) => {
3572 let watcher_path = SanitizedPath::new(s);
3573 let path = glob_literal_prefix(watcher_path.as_path());
3574 let pattern = watcher_path
3575 .as_path()
3576 .strip_prefix(&path)
3577 .map(|p| p.to_string_lossy().into_owned())
3578 .unwrap_or_else(|e| {
3579 debug_panic!(
3580 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3581 s,
3582 path.display(),
3583 e
3584 );
3585 watcher_path.as_path().to_string_lossy().into_owned()
3586 });
3587 (path, pattern)
3588 }
3589 lsp::GlobPattern::Relative(rp) => {
3590 let Ok(mut base_uri) = match &rp.base_uri {
3591 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3592 lsp::OneOf::Right(base_uri) => base_uri,
3593 }
3594 .to_file_path() else {
3595 continue;
3596 };
3597
3598 let path = glob_literal_prefix(Path::new(&rp.pattern));
3599 let pattern = Path::new(&rp.pattern)
3600 .strip_prefix(&path)
3601 .map(|p| p.to_string_lossy().into_owned())
3602 .unwrap_or_else(|e| {
3603 debug_panic!(
3604 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3605 rp.pattern,
3606 path.display(),
3607 e
3608 );
3609 rp.pattern.clone()
3610 });
3611 base_uri.push(path);
3612 (base_uri, pattern)
3613 }
3614 };
3615
3616 if let Some(glob) = Glob::new(&pattern).log_err() {
3617 if !path
3618 .components()
3619 .any(|c| matches!(c, path::Component::Normal(_)))
3620 {
3621 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3622 // rather than adding a new watcher for `/`.
3623 for worktree in &worktrees {
3624 worktree_globs
3625 .entry(worktree.read(cx).id())
3626 .or_insert_with(GlobSetBuilder::new)
3627 .add(glob.clone());
3628 }
3629 } else {
3630 abs_globs
3631 .entry(path.into())
3632 .or_insert_with(GlobSetBuilder::new)
3633 .add(glob);
3634 }
3635 }
3636 }
3637 }
3638
3639 let worktree_globs = worktree_globs
3640 .into_iter()
3641 .filter_map(|(worktree_id, builder)| builder.build().ok().map(|gs| (worktree_id, gs)))
3642 .collect();
3643
3644 let lsp_store = self.weak.clone();
3645 let fs = self.fs.clone();
3646 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
3647
3648 let abs_path_watchers = abs_globs
3649 .into_iter()
3650 .filter_map(|(abs_path, builder): (Arc<Path>, _)| {
3651 let globset = builder.build().ok()?;
3652 let task = cx.spawn({
3653 let fs = fs.clone();
3654 let lsp_store = lsp_store.clone();
3655 async move |_, cx| {
3656 maybe!(async move {
3657 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
3658 while let Some(update) = push_updates.0.next().await {
3659 let matching_entries: Vec<_> = update
3660 .into_iter()
3661 .filter(|event| globset.is_match(&event.path))
3662 .collect();
3663 if matching_entries.is_empty() {
3664 continue;
3665 }
3666 lsp_store
3667 .update(cx, |this, _| {
3668 this.lsp_notify_abs_paths_changed(
3669 language_server_id,
3670 matching_entries,
3671 );
3672 })
3673 .ok()?;
3674 }
3675 Some(())
3676 })
3677 .await;
3678 }
3679 });
3680 Some(task)
3681 })
3682 .collect();
3683
3684 WatchedPathsRegistration {
3685 worktree_globs,
3686 _abs_path_watchers: abs_path_watchers,
3687 }
3688 }
3689
3690 fn worktree_and_path_for_file_watcher(
3691 worktrees: &[Entity<Worktree>],
3692 watcher: &FileSystemWatcher,
3693 cx: &App,
3694 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3695 worktrees.iter().find_map(|worktree| {
3696 let tree = worktree.read(cx);
3697 let worktree_root_path = tree.abs_path();
3698 let path_style = tree.path_style();
3699 match &watcher.glob_pattern {
3700 lsp::GlobPattern::String(s) => {
3701 let watcher_path = SanitizedPath::new(s);
3702 let relative = watcher_path
3703 .as_path()
3704 .strip_prefix(&worktree_root_path)
3705 .ok()?;
3706 let literal_prefix = glob_literal_prefix(relative);
3707 Some((
3708 worktree.clone(),
3709 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3710 relative.to_string_lossy().into_owned(),
3711 ))
3712 }
3713 lsp::GlobPattern::Relative(rp) => {
3714 let base_uri = match &rp.base_uri {
3715 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3716 lsp::OneOf::Right(base_uri) => base_uri,
3717 }
3718 .to_file_path()
3719 .ok()?;
3720 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3721 let mut literal_prefix = relative.to_owned();
3722 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3723 Some((
3724 worktree.clone(),
3725 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3726 rp.pattern.clone(),
3727 ))
3728 }
3729 }
3730 })
3731 }
3732
3733 fn on_lsp_did_change_watched_files(
3734 &mut self,
3735 language_server_id: LanguageServerId,
3736 registration_id: &str,
3737 params: DidChangeWatchedFilesRegistrationOptions,
3738 cx: &mut Context<LspStore>,
3739 ) {
3740 let registration =
3741 self.build_watched_paths_registration(language_server_id, ¶ms.watchers, cx);
3742
3743 self.language_server_dynamic_registrations
3744 .entry(language_server_id)
3745 .or_default()
3746 .did_change_watched_files
3747 .insert(registration_id.to_string(), params.watchers);
3748
3749 self.language_server_watched_paths
3750 .entry(language_server_id)
3751 .or_default()
3752 .registrations
3753 .insert(registration_id.to_string(), registration);
3754
3755 cx.notify();
3756 }
3757
3758 fn on_lsp_unregister_did_change_watched_files(
3759 &mut self,
3760 language_server_id: LanguageServerId,
3761 registration_id: &str,
3762 cx: &mut Context<LspStore>,
3763 ) {
3764 let registrations = self
3765 .language_server_dynamic_registrations
3766 .entry(language_server_id)
3767 .or_default();
3768
3769 if registrations
3770 .did_change_watched_files
3771 .remove(registration_id)
3772 .is_some()
3773 {
3774 log::info!(
3775 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3776 language_server_id,
3777 registration_id
3778 );
3779 } else {
3780 log::warn!(
3781 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3782 language_server_id,
3783 registration_id
3784 );
3785 }
3786
3787 if let Some(watched_paths) = self
3788 .language_server_watched_paths
3789 .get_mut(&language_server_id)
3790 {
3791 watched_paths.registrations.remove(registration_id);
3792 }
3793
3794 cx.notify();
3795 }
3796
3797 async fn initialization_options_for_adapter(
3798 adapter: Arc<dyn LspAdapter>,
3799 delegate: &Arc<dyn LspAdapterDelegate>,
3800 ) -> Result<Option<serde_json::Value>> {
3801 let Some(mut initialization_config) =
3802 adapter.clone().initialization_options(delegate).await?
3803 else {
3804 return Ok(None);
3805 };
3806
3807 for other_adapter in delegate.registered_lsp_adapters() {
3808 if other_adapter.name() == adapter.name() {
3809 continue;
3810 }
3811 if let Ok(Some(target_config)) = other_adapter
3812 .clone()
3813 .additional_initialization_options(adapter.name(), delegate)
3814 .await
3815 {
3816 merge_json_value_into(target_config.clone(), &mut initialization_config);
3817 }
3818 }
3819
3820 Ok(Some(initialization_config))
3821 }
3822
3823 async fn workspace_configuration_for_adapter(
3824 adapter: Arc<dyn LspAdapter>,
3825 delegate: &Arc<dyn LspAdapterDelegate>,
3826 toolchain: Option<Toolchain>,
3827 requested_uri: Option<Uri>,
3828 cx: &mut AsyncApp,
3829 ) -> Result<serde_json::Value> {
3830 let mut workspace_config = adapter
3831 .clone()
3832 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3833 .await?;
3834
3835 for other_adapter in delegate.registered_lsp_adapters() {
3836 if other_adapter.name() == adapter.name() {
3837 continue;
3838 }
3839 if let Ok(Some(target_config)) = other_adapter
3840 .clone()
3841 .additional_workspace_configuration(adapter.name(), delegate, cx)
3842 .await
3843 {
3844 merge_json_value_into(target_config.clone(), &mut workspace_config);
3845 }
3846 }
3847
3848 Ok(workspace_config)
3849 }
3850
3851 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3852 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3853 Some(server.clone())
3854 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3855 Some(Arc::clone(server))
3856 } else {
3857 None
3858 }
3859 }
3860}
3861
3862fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3863 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3864 cx.emit(LspStoreEvent::LanguageServerUpdate {
3865 language_server_id: server.server_id(),
3866 name: Some(server.name()),
3867 message: proto::update_language_server::Variant::MetadataUpdated(
3868 proto::ServerMetadataUpdated {
3869 capabilities: Some(capabilities),
3870 binary: Some(proto::LanguageServerBinaryInfo {
3871 path: server.binary().path.to_string_lossy().into_owned(),
3872 arguments: server
3873 .binary()
3874 .arguments
3875 .iter()
3876 .map(|arg| arg.to_string_lossy().into_owned())
3877 .collect(),
3878 }),
3879 configuration: serde_json::to_string(server.configuration()).ok(),
3880 workspace_folders: server
3881 .workspace_folders()
3882 .iter()
3883 .map(|uri| uri.to_string())
3884 .collect(),
3885 },
3886 ),
3887 });
3888 }
3889}
3890
3891#[derive(Debug)]
3892pub struct FormattableBuffer {
3893 handle: Entity<Buffer>,
3894 abs_path: Option<PathBuf>,
3895 env: Option<HashMap<String, String>>,
3896 ranges: Option<Vec<Range<Anchor>>>,
3897}
3898
3899pub struct RemoteLspStore {
3900 upstream_client: Option<AnyProtoClient>,
3901 upstream_project_id: u64,
3902}
3903
3904pub(crate) enum LspStoreMode {
3905 Local(LocalLspStore), // ssh host and collab host
3906 Remote(RemoteLspStore), // collab guest
3907}
3908
3909impl LspStoreMode {
3910 fn is_local(&self) -> bool {
3911 matches!(self, LspStoreMode::Local(_))
3912 }
3913}
3914
3915pub struct LspStore {
3916 mode: LspStoreMode,
3917 last_formatting_failure: Option<String>,
3918 downstream_client: Option<(AnyProtoClient, u64)>,
3919 nonce: u128,
3920 buffer_store: Entity<BufferStore>,
3921 worktree_store: Entity<WorktreeStore>,
3922 pub languages: Arc<LanguageRegistry>,
3923 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3924 active_entry: Option<ProjectEntryId>,
3925 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3926 _maintain_buffer_languages: Task<()>,
3927 diagnostic_summaries:
3928 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3929 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3930 semantic_token_config: SemanticTokenConfig,
3931 lsp_data: HashMap<BufferId, BufferLspData>,
3932 next_hint_id: Arc<AtomicUsize>,
3933}
3934
3935#[derive(Debug)]
3936pub struct BufferLspData {
3937 buffer_version: Global,
3938 document_colors: Option<DocumentColorData>,
3939 code_lens: Option<CodeLensData>,
3940 semantic_tokens: Option<SemanticTokensData>,
3941 folding_ranges: Option<FoldingRangeData>,
3942 document_symbols: Option<DocumentSymbolsData>,
3943 inlay_hints: BufferInlayHints,
3944 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3945 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3946}
3947
3948#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3949struct LspKey {
3950 request_type: TypeId,
3951 server_queried: Option<LanguageServerId>,
3952}
3953
3954impl BufferLspData {
3955 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3956 Self {
3957 buffer_version: buffer.read(cx).version(),
3958 document_colors: None,
3959 code_lens: None,
3960 semantic_tokens: None,
3961 folding_ranges: None,
3962 document_symbols: None,
3963 inlay_hints: BufferInlayHints::new(buffer, cx),
3964 lsp_requests: HashMap::default(),
3965 chunk_lsp_requests: HashMap::default(),
3966 }
3967 }
3968
3969 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3970 if let Some(document_colors) = &mut self.document_colors {
3971 document_colors.remove_server_data(for_server);
3972 }
3973
3974 if let Some(code_lens) = &mut self.code_lens {
3975 code_lens.remove_server_data(for_server);
3976 }
3977
3978 self.inlay_hints.remove_server_data(for_server);
3979
3980 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3981 semantic_tokens.raw_tokens.servers.remove(&for_server);
3982 semantic_tokens
3983 .latest_invalidation_requests
3984 .remove(&for_server);
3985 }
3986
3987 if let Some(folding_ranges) = &mut self.folding_ranges {
3988 folding_ranges.ranges.remove(&for_server);
3989 }
3990
3991 if let Some(document_symbols) = &mut self.document_symbols {
3992 document_symbols.remove_server_data(for_server);
3993 }
3994 }
3995
3996 #[cfg(any(test, feature = "test-support"))]
3997 pub fn inlay_hints(&self) -> &BufferInlayHints {
3998 &self.inlay_hints
3999 }
4000}
4001
4002#[derive(Debug)]
4003pub enum LspStoreEvent {
4004 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4005 LanguageServerRemoved(LanguageServerId),
4006 LanguageServerUpdate {
4007 language_server_id: LanguageServerId,
4008 name: Option<LanguageServerName>,
4009 message: proto::update_language_server::Variant,
4010 },
4011 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4012 LanguageServerPrompt(LanguageServerPromptRequest),
4013 LanguageDetected {
4014 buffer: Entity<Buffer>,
4015 new_language: Option<Arc<Language>>,
4016 },
4017 Notification(String),
4018 RefreshInlayHints {
4019 server_id: LanguageServerId,
4020 request_id: Option<usize>,
4021 },
4022 RefreshSemanticTokens {
4023 server_id: LanguageServerId,
4024 request_id: Option<usize>,
4025 },
4026 RefreshCodeLens,
4027 DiagnosticsUpdated {
4028 server_id: LanguageServerId,
4029 paths: Vec<ProjectPath>,
4030 },
4031 DiskBasedDiagnosticsStarted {
4032 language_server_id: LanguageServerId,
4033 },
4034 DiskBasedDiagnosticsFinished {
4035 language_server_id: LanguageServerId,
4036 },
4037 SnippetEdit {
4038 buffer_id: BufferId,
4039 edits: Vec<(lsp::Range, Snippet)>,
4040 most_recent_edit: clock::Lamport,
4041 },
4042 WorkspaceEditApplied(ProjectTransaction),
4043}
4044
4045#[derive(Clone, Debug, Serialize)]
4046pub struct LanguageServerStatus {
4047 pub name: LanguageServerName,
4048 pub server_version: Option<SharedString>,
4049 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4050 pub has_pending_diagnostic_updates: bool,
4051 pub progress_tokens: HashSet<ProgressToken>,
4052 pub worktree: Option<WorktreeId>,
4053 pub binary: Option<LanguageServerBinary>,
4054 pub configuration: Option<Value>,
4055 pub workspace_folders: BTreeSet<Uri>,
4056 pub process_id: Option<u32>,
4057}
4058
4059#[derive(Clone, Debug)]
4060struct CoreSymbol {
4061 pub language_server_name: LanguageServerName,
4062 pub source_worktree_id: WorktreeId,
4063 pub source_language_server_id: LanguageServerId,
4064 pub path: SymbolLocation,
4065 pub name: String,
4066 pub kind: lsp::SymbolKind,
4067 pub range: Range<Unclipped<PointUtf16>>,
4068 pub container_name: Option<String>,
4069}
4070
4071#[derive(Clone, Debug, PartialEq, Eq)]
4072pub enum SymbolLocation {
4073 InProject(ProjectPath),
4074 OutsideProject {
4075 abs_path: Arc<Path>,
4076 signature: [u8; 32],
4077 },
4078}
4079
4080impl SymbolLocation {
4081 fn file_name(&self) -> Option<&str> {
4082 match self {
4083 Self::InProject(path) => path.path.file_name(),
4084 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4085 }
4086 }
4087}
4088
4089impl LspStore {
4090 pub fn init(client: &AnyProtoClient) {
4091 client.add_entity_request_handler(Self::handle_lsp_query);
4092 client.add_entity_message_handler(Self::handle_lsp_query_response);
4093 client.add_entity_request_handler(Self::handle_restart_language_servers);
4094 client.add_entity_request_handler(Self::handle_stop_language_servers);
4095 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4096 client.add_entity_message_handler(Self::handle_start_language_server);
4097 client.add_entity_message_handler(Self::handle_update_language_server);
4098 client.add_entity_message_handler(Self::handle_language_server_log);
4099 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4100 client.add_entity_request_handler(Self::handle_format_buffers);
4101 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4102 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4103 client.add_entity_request_handler(Self::handle_apply_code_action);
4104 client.add_entity_request_handler(Self::handle_get_project_symbols);
4105 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4106 client.add_entity_request_handler(Self::handle_get_color_presentation);
4107 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4108 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4109 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4110 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4111 client.add_entity_request_handler(Self::handle_on_type_formatting);
4112 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4113 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4114 client.add_entity_request_handler(Self::handle_rename_project_entry);
4115 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4116 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4117 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4118 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4119 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4120 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4121 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4122
4123 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4124 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4125 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4126 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4127 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4128 client.add_entity_request_handler(
4129 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4130 );
4131 client.add_entity_request_handler(
4132 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4133 );
4134 client.add_entity_request_handler(
4135 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4136 );
4137 }
4138
4139 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4140 match &self.mode {
4141 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4142 _ => None,
4143 }
4144 }
4145
4146 pub fn as_local(&self) -> Option<&LocalLspStore> {
4147 match &self.mode {
4148 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4149 _ => None,
4150 }
4151 }
4152
4153 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4154 match &mut self.mode {
4155 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4156 _ => None,
4157 }
4158 }
4159
4160 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4161 match &self.mode {
4162 LspStoreMode::Remote(RemoteLspStore {
4163 upstream_client: Some(upstream_client),
4164 upstream_project_id,
4165 ..
4166 }) => Some((upstream_client.clone(), *upstream_project_id)),
4167
4168 LspStoreMode::Remote(RemoteLspStore {
4169 upstream_client: None,
4170 ..
4171 }) => None,
4172 LspStoreMode::Local(_) => None,
4173 }
4174 }
4175
4176 pub fn new_local(
4177 buffer_store: Entity<BufferStore>,
4178 worktree_store: Entity<WorktreeStore>,
4179 prettier_store: Entity<PrettierStore>,
4180 toolchain_store: Entity<LocalToolchainStore>,
4181 environment: Entity<ProjectEnvironment>,
4182 manifest_tree: Entity<ManifestTree>,
4183 languages: Arc<LanguageRegistry>,
4184 http_client: Arc<dyn HttpClient>,
4185 fs: Arc<dyn Fs>,
4186 cx: &mut Context<Self>,
4187 ) -> Self {
4188 let yarn = YarnPathStore::new(fs.clone(), cx);
4189 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4190 .detach();
4191 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4192 .detach();
4193 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4194 .detach();
4195 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4196 .detach();
4197 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4198 .detach();
4199 subscribe_to_binary_statuses(&languages, cx).detach();
4200
4201 let _maintain_workspace_config = {
4202 let (sender, receiver) = watch::channel();
4203 (Self::maintain_workspace_config(receiver, cx), sender)
4204 };
4205
4206 Self {
4207 mode: LspStoreMode::Local(LocalLspStore {
4208 weak: cx.weak_entity(),
4209 worktree_store: worktree_store.clone(),
4210
4211 supplementary_language_servers: Default::default(),
4212 languages: languages.clone(),
4213 language_server_ids: Default::default(),
4214 language_servers: Default::default(),
4215 last_workspace_edits_by_language_server: Default::default(),
4216 language_server_watched_paths: Default::default(),
4217 language_server_paths_watched_for_rename: Default::default(),
4218 language_server_dynamic_registrations: Default::default(),
4219 buffers_being_formatted: Default::default(),
4220 buffers_to_refresh_hash_set: HashSet::default(),
4221 buffers_to_refresh_queue: VecDeque::new(),
4222 _background_diagnostics_worker: Task::ready(()).shared(),
4223 buffer_snapshots: Default::default(),
4224 prettier_store,
4225 environment,
4226 http_client,
4227 fs,
4228 yarn,
4229 next_diagnostic_group_id: Default::default(),
4230 diagnostics: Default::default(),
4231 _subscription: cx.on_app_quit(|this, _| {
4232 this.as_local_mut()
4233 .unwrap()
4234 .shutdown_language_servers_on_quit()
4235 }),
4236 lsp_tree: LanguageServerTree::new(
4237 manifest_tree,
4238 languages.clone(),
4239 toolchain_store.clone(),
4240 ),
4241 toolchain_store,
4242 registered_buffers: HashMap::default(),
4243 buffers_opened_in_servers: HashMap::default(),
4244 buffer_pull_diagnostics_result_ids: HashMap::default(),
4245 workspace_pull_diagnostics_result_ids: HashMap::default(),
4246 restricted_worktrees_tasks: HashMap::default(),
4247 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4248 .manifest_file_names(),
4249 }),
4250 last_formatting_failure: None,
4251 downstream_client: None,
4252 buffer_store,
4253 worktree_store,
4254 languages: languages.clone(),
4255 language_server_statuses: Default::default(),
4256 nonce: StdRng::from_os_rng().random(),
4257 diagnostic_summaries: HashMap::default(),
4258 lsp_server_capabilities: HashMap::default(),
4259 semantic_token_config: SemanticTokenConfig::new(cx),
4260 lsp_data: HashMap::default(),
4261 next_hint_id: Arc::default(),
4262 active_entry: None,
4263 _maintain_workspace_config,
4264 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4265 }
4266 }
4267
4268 fn send_lsp_proto_request<R: LspCommand>(
4269 &self,
4270 buffer: Entity<Buffer>,
4271 client: AnyProtoClient,
4272 upstream_project_id: u64,
4273 request: R,
4274 cx: &mut Context<LspStore>,
4275 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4276 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4277 return Task::ready(Ok(R::Response::default()));
4278 }
4279 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4280 cx.spawn(async move |this, cx| {
4281 let response = client.request(message).await?;
4282 let this = this.upgrade().context("project dropped")?;
4283 request
4284 .response_from_proto(response, this, buffer, cx.clone())
4285 .await
4286 })
4287 }
4288
4289 pub(super) fn new_remote(
4290 buffer_store: Entity<BufferStore>,
4291 worktree_store: Entity<WorktreeStore>,
4292 languages: Arc<LanguageRegistry>,
4293 upstream_client: AnyProtoClient,
4294 project_id: u64,
4295 cx: &mut Context<Self>,
4296 ) -> Self {
4297 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4298 .detach();
4299 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4300 .detach();
4301 subscribe_to_binary_statuses(&languages, cx).detach();
4302 let _maintain_workspace_config = {
4303 let (sender, receiver) = watch::channel();
4304 (Self::maintain_workspace_config(receiver, cx), sender)
4305 };
4306 Self {
4307 mode: LspStoreMode::Remote(RemoteLspStore {
4308 upstream_client: Some(upstream_client),
4309 upstream_project_id: project_id,
4310 }),
4311 downstream_client: None,
4312 last_formatting_failure: None,
4313 buffer_store,
4314 worktree_store,
4315 languages: languages.clone(),
4316 language_server_statuses: Default::default(),
4317 nonce: StdRng::from_os_rng().random(),
4318 diagnostic_summaries: HashMap::default(),
4319 lsp_server_capabilities: HashMap::default(),
4320 semantic_token_config: SemanticTokenConfig::new(cx),
4321 next_hint_id: Arc::default(),
4322 lsp_data: HashMap::default(),
4323 active_entry: None,
4324
4325 _maintain_workspace_config,
4326 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4327 }
4328 }
4329
4330 fn on_buffer_store_event(
4331 &mut self,
4332 _: Entity<BufferStore>,
4333 event: &BufferStoreEvent,
4334 cx: &mut Context<Self>,
4335 ) {
4336 match event {
4337 BufferStoreEvent::BufferAdded(buffer) => {
4338 self.on_buffer_added(buffer, cx).log_err();
4339 }
4340 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4341 let buffer_id = buffer.read(cx).remote_id();
4342 if let Some(local) = self.as_local_mut()
4343 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4344 {
4345 local.reset_buffer(buffer, old_file, cx);
4346
4347 if local.registered_buffers.contains_key(&buffer_id) {
4348 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4349 }
4350 }
4351
4352 self.detect_language_for_buffer(buffer, cx);
4353 if let Some(local) = self.as_local_mut() {
4354 local.initialize_buffer(buffer, cx);
4355 if local.registered_buffers.contains_key(&buffer_id) {
4356 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4357 }
4358 }
4359 }
4360 _ => {}
4361 }
4362 }
4363
4364 fn on_worktree_store_event(
4365 &mut self,
4366 _: Entity<WorktreeStore>,
4367 event: &WorktreeStoreEvent,
4368 cx: &mut Context<Self>,
4369 ) {
4370 match event {
4371 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4372 if !worktree.read(cx).is_local() {
4373 return;
4374 }
4375 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4376 worktree::Event::UpdatedEntries(changes) => {
4377 this.update_local_worktree_language_servers(&worktree, changes, cx);
4378 }
4379 worktree::Event::UpdatedGitRepositories(_)
4380 | worktree::Event::DeletedEntry(_) => {}
4381 })
4382 .detach()
4383 }
4384 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4385 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4386 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4387 }
4388 WorktreeStoreEvent::WorktreeReleased(..)
4389 | WorktreeStoreEvent::WorktreeOrderChanged
4390 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4391 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4392 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4393 }
4394 }
4395
4396 fn on_prettier_store_event(
4397 &mut self,
4398 _: Entity<PrettierStore>,
4399 event: &PrettierStoreEvent,
4400 cx: &mut Context<Self>,
4401 ) {
4402 match event {
4403 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4404 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4405 }
4406 PrettierStoreEvent::LanguageServerAdded {
4407 new_server_id,
4408 name,
4409 prettier_server,
4410 } => {
4411 self.register_supplementary_language_server(
4412 *new_server_id,
4413 name.clone(),
4414 prettier_server.clone(),
4415 cx,
4416 );
4417 }
4418 }
4419 }
4420
4421 fn on_toolchain_store_event(
4422 &mut self,
4423 _: Entity<LocalToolchainStore>,
4424 event: &ToolchainStoreEvent,
4425 _: &mut Context<Self>,
4426 ) {
4427 if let ToolchainStoreEvent::ToolchainActivated = event {
4428 self.request_workspace_config_refresh()
4429 }
4430 }
4431
4432 fn request_workspace_config_refresh(&mut self) {
4433 *self._maintain_workspace_config.1.borrow_mut() = ();
4434 }
4435
4436 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4437 self.as_local().map(|local| local.prettier_store.clone())
4438 }
4439
4440 fn on_buffer_event(
4441 &mut self,
4442 buffer: Entity<Buffer>,
4443 event: &language::BufferEvent,
4444 cx: &mut Context<Self>,
4445 ) {
4446 match event {
4447 language::BufferEvent::Edited => {
4448 self.on_buffer_edited(buffer, cx);
4449 }
4450
4451 language::BufferEvent::Saved => {
4452 self.on_buffer_saved(buffer, cx);
4453 }
4454
4455 _ => {}
4456 }
4457 }
4458
4459 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4460 buffer
4461 .read(cx)
4462 .set_language_registry(self.languages.clone());
4463
4464 cx.subscribe(buffer, |this, buffer, event, cx| {
4465 this.on_buffer_event(buffer, event, cx);
4466 })
4467 .detach();
4468
4469 self.detect_language_for_buffer(buffer, cx);
4470 if let Some(local) = self.as_local_mut() {
4471 local.initialize_buffer(buffer, cx);
4472 }
4473
4474 Ok(())
4475 }
4476
4477 pub fn refresh_background_diagnostics_for_buffers(
4478 &mut self,
4479 buffers: HashSet<BufferId>,
4480 cx: &mut Context<Self>,
4481 ) -> Shared<Task<()>> {
4482 let Some(local) = self.as_local_mut() else {
4483 return Task::ready(()).shared();
4484 };
4485 for buffer in buffers {
4486 if local.buffers_to_refresh_hash_set.insert(buffer) {
4487 local.buffers_to_refresh_queue.push_back(buffer);
4488 if local.buffers_to_refresh_queue.len() == 1 {
4489 local._background_diagnostics_worker =
4490 Self::background_diagnostics_worker(cx).shared();
4491 }
4492 }
4493 }
4494
4495 local._background_diagnostics_worker.clone()
4496 }
4497
4498 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4499 let buffer_store = self.buffer_store.clone();
4500 let local = self.as_local_mut()?;
4501 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4502 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4503 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4504 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4505 }
4506 }
4507 None
4508 }
4509
4510 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4511 cx.spawn(async move |this, cx| {
4512 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4513 task.await.log_err();
4514 }
4515 })
4516 }
4517
4518 pub(crate) fn register_buffer_with_language_servers(
4519 &mut self,
4520 buffer: &Entity<Buffer>,
4521 only_register_servers: HashSet<LanguageServerSelector>,
4522 ignore_refcounts: bool,
4523 cx: &mut Context<Self>,
4524 ) -> OpenLspBufferHandle {
4525 let buffer_id = buffer.read(cx).remote_id();
4526 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4527 if let Some(local) = self.as_local_mut() {
4528 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4529 if !ignore_refcounts {
4530 *refcount += 1;
4531 }
4532
4533 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4534 // 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
4535 // 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
4536 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4537 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4538 return handle;
4539 };
4540 if !file.is_local() {
4541 return handle;
4542 }
4543
4544 if ignore_refcounts || *refcount == 1 {
4545 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4546 }
4547 if !ignore_refcounts {
4548 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4549 let refcount = {
4550 let local = lsp_store.as_local_mut().unwrap();
4551 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4552 debug_panic!("bad refcounting");
4553 return;
4554 };
4555
4556 *refcount -= 1;
4557 *refcount
4558 };
4559 if refcount == 0 {
4560 lsp_store.lsp_data.remove(&buffer_id);
4561 let local = lsp_store.as_local_mut().unwrap();
4562 local.registered_buffers.remove(&buffer_id);
4563
4564 local.buffers_opened_in_servers.remove(&buffer_id);
4565 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4566 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4567
4568 let buffer_abs_path = file.abs_path(cx);
4569 for (_, buffer_pull_diagnostics_result_ids) in
4570 &mut local.buffer_pull_diagnostics_result_ids
4571 {
4572 buffer_pull_diagnostics_result_ids.retain(
4573 |_, buffer_result_ids| {
4574 buffer_result_ids.remove(&buffer_abs_path);
4575 !buffer_result_ids.is_empty()
4576 },
4577 );
4578 }
4579
4580 let diagnostic_updates = local
4581 .language_servers
4582 .keys()
4583 .cloned()
4584 .map(|server_id| DocumentDiagnosticsUpdate {
4585 diagnostics: DocumentDiagnostics {
4586 document_abs_path: buffer_abs_path.clone(),
4587 version: None,
4588 diagnostics: Vec::new(),
4589 },
4590 result_id: None,
4591 registration_id: None,
4592 server_id,
4593 disk_based_sources: Cow::Borrowed(&[]),
4594 })
4595 .collect::<Vec<_>>();
4596
4597 lsp_store
4598 .merge_diagnostic_entries(
4599 diagnostic_updates,
4600 |_, diagnostic, _| {
4601 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4602 },
4603 cx,
4604 )
4605 .context("Clearing diagnostics for the closed buffer")
4606 .log_err();
4607 }
4608 }
4609 })
4610 .detach();
4611 }
4612 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4613 let buffer_id = buffer.read(cx).remote_id().to_proto();
4614 cx.background_spawn(async move {
4615 upstream_client
4616 .request(proto::RegisterBufferWithLanguageServers {
4617 project_id: upstream_project_id,
4618 buffer_id,
4619 only_servers: only_register_servers
4620 .into_iter()
4621 .map(|selector| {
4622 let selector = match selector {
4623 LanguageServerSelector::Id(language_server_id) => {
4624 proto::language_server_selector::Selector::ServerId(
4625 language_server_id.to_proto(),
4626 )
4627 }
4628 LanguageServerSelector::Name(language_server_name) => {
4629 proto::language_server_selector::Selector::Name(
4630 language_server_name.to_string(),
4631 )
4632 }
4633 };
4634 proto::LanguageServerSelector {
4635 selector: Some(selector),
4636 }
4637 })
4638 .collect(),
4639 })
4640 .await
4641 })
4642 .detach();
4643 } else {
4644 // Our remote connection got closed
4645 }
4646 handle
4647 }
4648
4649 fn maintain_buffer_languages(
4650 languages: Arc<LanguageRegistry>,
4651 cx: &mut Context<Self>,
4652 ) -> Task<()> {
4653 let mut subscription = languages.subscribe();
4654 let mut prev_reload_count = languages.reload_count();
4655 cx.spawn(async move |this, cx| {
4656 while let Some(()) = subscription.next().await {
4657 if let Some(this) = this.upgrade() {
4658 // If the language registry has been reloaded, then remove and
4659 // re-assign the languages on all open buffers.
4660 let reload_count = languages.reload_count();
4661 if reload_count > prev_reload_count {
4662 prev_reload_count = reload_count;
4663 this.update(cx, |this, cx| {
4664 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4665 for buffer in buffer_store.buffers() {
4666 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4667 {
4668 buffer.update(cx, |buffer, cx| {
4669 buffer.set_language_async(None, cx)
4670 });
4671 if let Some(local) = this.as_local_mut() {
4672 local.reset_buffer(&buffer, &f, cx);
4673
4674 if local
4675 .registered_buffers
4676 .contains_key(&buffer.read(cx).remote_id())
4677 && let Some(file_url) =
4678 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4679 {
4680 local.unregister_buffer_from_language_servers(
4681 &buffer, &file_url, cx,
4682 );
4683 }
4684 }
4685 }
4686 }
4687 });
4688 });
4689 }
4690
4691 this.update(cx, |this, cx| {
4692 let mut plain_text_buffers = Vec::new();
4693 let mut buffers_with_unknown_injections = Vec::new();
4694 for handle in this.buffer_store.read(cx).buffers() {
4695 let buffer = handle.read(cx);
4696 if buffer.language().is_none()
4697 || buffer.language() == Some(&*language::PLAIN_TEXT)
4698 {
4699 plain_text_buffers.push(handle);
4700 } else if buffer.contains_unknown_injections() {
4701 buffers_with_unknown_injections.push(handle);
4702 }
4703 }
4704
4705 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4706 // and reused later in the invisible worktrees.
4707 plain_text_buffers.sort_by_key(|buffer| {
4708 Reverse(
4709 File::from_dyn(buffer.read(cx).file())
4710 .map(|file| file.worktree.read(cx).is_visible()),
4711 )
4712 });
4713
4714 for buffer in plain_text_buffers {
4715 this.detect_language_for_buffer(&buffer, cx);
4716 if let Some(local) = this.as_local_mut() {
4717 local.initialize_buffer(&buffer, cx);
4718 if local
4719 .registered_buffers
4720 .contains_key(&buffer.read(cx).remote_id())
4721 {
4722 local.register_buffer_with_language_servers(
4723 &buffer,
4724 HashSet::default(),
4725 cx,
4726 );
4727 }
4728 }
4729 }
4730
4731 for buffer in buffers_with_unknown_injections {
4732 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4733 }
4734 });
4735 }
4736 }
4737 })
4738 }
4739
4740 fn detect_language_for_buffer(
4741 &mut self,
4742 buffer_handle: &Entity<Buffer>,
4743 cx: &mut Context<Self>,
4744 ) -> Option<language::AvailableLanguage> {
4745 // If the buffer has a language, set it and start the language server if we haven't already.
4746 let buffer = buffer_handle.read(cx);
4747 let file = buffer.file()?;
4748
4749 let content = buffer.as_rope();
4750 let available_language = self.languages.language_for_file(file, Some(content), cx);
4751 if let Some(available_language) = &available_language {
4752 if let Some(Ok(Ok(new_language))) = self
4753 .languages
4754 .load_language(available_language)
4755 .now_or_never()
4756 {
4757 self.set_language_for_buffer(buffer_handle, new_language, cx);
4758 }
4759 } else {
4760 cx.emit(LspStoreEvent::LanguageDetected {
4761 buffer: buffer_handle.clone(),
4762 new_language: None,
4763 });
4764 }
4765
4766 available_language
4767 }
4768
4769 pub(crate) fn set_language_for_buffer(
4770 &mut self,
4771 buffer_entity: &Entity<Buffer>,
4772 new_language: Arc<Language>,
4773 cx: &mut Context<Self>,
4774 ) {
4775 let buffer = buffer_entity.read(cx);
4776 let buffer_file = buffer.file().cloned();
4777 let buffer_id = buffer.remote_id();
4778 if let Some(local_store) = self.as_local_mut()
4779 && local_store.registered_buffers.contains_key(&buffer_id)
4780 && let Some(abs_path) =
4781 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4782 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4783 {
4784 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4785 }
4786 buffer_entity.update(cx, |buffer, cx| {
4787 if buffer
4788 .language()
4789 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4790 {
4791 buffer.set_language_async(Some(new_language.clone()), cx);
4792 }
4793 });
4794
4795 let settings =
4796 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4797 let buffer_file = File::from_dyn(buffer_file.as_ref());
4798
4799 let worktree_id = if let Some(file) = buffer_file {
4800 let worktree = file.worktree.clone();
4801
4802 if let Some(local) = self.as_local_mut()
4803 && local.registered_buffers.contains_key(&buffer_id)
4804 {
4805 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4806 }
4807 Some(worktree.read(cx).id())
4808 } else {
4809 None
4810 };
4811
4812 if settings.prettier.allowed
4813 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4814 {
4815 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4816 if let Some(prettier_store) = prettier_store {
4817 prettier_store.update(cx, |prettier_store, cx| {
4818 prettier_store.install_default_prettier(
4819 worktree_id,
4820 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4821 cx,
4822 )
4823 })
4824 }
4825 }
4826
4827 cx.emit(LspStoreEvent::LanguageDetected {
4828 buffer: buffer_entity.clone(),
4829 new_language: Some(new_language),
4830 })
4831 }
4832
4833 pub fn buffer_store(&self) -> Entity<BufferStore> {
4834 self.buffer_store.clone()
4835 }
4836
4837 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4838 self.active_entry = active_entry;
4839 }
4840
4841 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4842 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4843 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4844 {
4845 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4846 summaries
4847 .iter()
4848 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4849 });
4850 if let Some(summary) = summaries.next() {
4851 client
4852 .send(proto::UpdateDiagnosticSummary {
4853 project_id: downstream_project_id,
4854 worktree_id: worktree.id().to_proto(),
4855 summary: Some(summary),
4856 more_summaries: summaries.collect(),
4857 })
4858 .log_err();
4859 }
4860 }
4861 }
4862
4863 fn is_capable_for_proto_request<R>(
4864 &self,
4865 buffer: &Entity<Buffer>,
4866 request: &R,
4867 cx: &App,
4868 ) -> bool
4869 where
4870 R: LspCommand,
4871 {
4872 self.check_if_capable_for_proto_request(
4873 buffer,
4874 |capabilities| {
4875 request.check_capabilities(AdapterServerCapabilities {
4876 server_capabilities: capabilities.clone(),
4877 code_action_kinds: None,
4878 })
4879 },
4880 cx,
4881 )
4882 }
4883
4884 fn check_if_capable_for_proto_request<F>(
4885 &self,
4886 buffer: &Entity<Buffer>,
4887 check: F,
4888 cx: &App,
4889 ) -> bool
4890 where
4891 F: FnMut(&lsp::ServerCapabilities) -> bool,
4892 {
4893 let Some(language) = buffer.read(cx).language().cloned() else {
4894 return false;
4895 };
4896 let registered_language_servers = self
4897 .languages
4898 .lsp_adapters(&language.name())
4899 .into_iter()
4900 .map(|lsp_adapter| lsp_adapter.name())
4901 .collect::<HashSet<_>>();
4902 self.language_server_statuses
4903 .iter()
4904 .filter_map(|(server_id, server_status)| {
4905 // Include servers that are either registered for this language OR
4906 // available to be loaded (for SSH remote mode where adapters like
4907 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4908 // but only loaded on the server side)
4909 let is_relevant = registered_language_servers.contains(&server_status.name)
4910 || self.languages.is_lsp_adapter_available(&server_status.name);
4911 is_relevant.then_some(server_id)
4912 })
4913 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4914 .any(check)
4915 }
4916
4917 fn all_capable_for_proto_request<F>(
4918 &self,
4919 buffer: &Entity<Buffer>,
4920 mut check: F,
4921 cx: &App,
4922 ) -> Vec<lsp::LanguageServerId>
4923 where
4924 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4925 {
4926 let Some(language) = buffer.read(cx).language().cloned() else {
4927 return Vec::default();
4928 };
4929 let registered_language_servers = self
4930 .languages
4931 .lsp_adapters(&language.name())
4932 .into_iter()
4933 .map(|lsp_adapter| lsp_adapter.name())
4934 .collect::<HashSet<_>>();
4935 self.language_server_statuses
4936 .iter()
4937 .filter_map(|(server_id, server_status)| {
4938 // Include servers that are either registered for this language OR
4939 // available to be loaded (for SSH remote mode where adapters like
4940 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4941 // but only loaded on the server side)
4942 let is_relevant = registered_language_servers.contains(&server_status.name)
4943 || self.languages.is_lsp_adapter_available(&server_status.name);
4944 is_relevant.then_some((server_id, &server_status.name))
4945 })
4946 .filter_map(|(server_id, server_name)| {
4947 self.lsp_server_capabilities
4948 .get(server_id)
4949 .map(|c| (server_id, server_name, c))
4950 })
4951 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4952 .map(|(server_id, _, _)| *server_id)
4953 .collect()
4954 }
4955
4956 pub fn request_lsp<R>(
4957 &mut self,
4958 buffer: Entity<Buffer>,
4959 server: LanguageServerToQuery,
4960 request: R,
4961 cx: &mut Context<Self>,
4962 ) -> Task<Result<R::Response>>
4963 where
4964 R: LspCommand,
4965 <R::LspRequest as lsp::request::Request>::Result: Send,
4966 <R::LspRequest as lsp::request::Request>::Params: Send,
4967 {
4968 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4969 return self.send_lsp_proto_request(
4970 buffer,
4971 upstream_client,
4972 upstream_project_id,
4973 request,
4974 cx,
4975 );
4976 }
4977
4978 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4979 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4980 local
4981 .language_servers_for_buffer(buffer, cx)
4982 .find(|(_, server)| {
4983 request.check_capabilities(server.adapter_server_capabilities())
4984 })
4985 .map(|(_, server)| server.clone())
4986 }),
4987 LanguageServerToQuery::Other(id) => self
4988 .language_server_for_local_buffer(buffer, id, cx)
4989 .and_then(|(_, server)| {
4990 request
4991 .check_capabilities(server.adapter_server_capabilities())
4992 .then(|| Arc::clone(server))
4993 }),
4994 }) else {
4995 return Task::ready(Ok(Default::default()));
4996 };
4997
4998 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4999
5000 let Some(file) = file else {
5001 return Task::ready(Ok(Default::default()));
5002 };
5003
5004 let lsp_params = match request.to_lsp_params_or_response(
5005 &file.abs_path(cx),
5006 buffer.read(cx),
5007 &language_server,
5008 cx,
5009 ) {
5010 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5011 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5012 Err(err) => {
5013 let message = format!(
5014 "{} via {} failed: {}",
5015 request.display_name(),
5016 language_server.name(),
5017 err
5018 );
5019 // rust-analyzer likes to error with this when its still loading up
5020 if !message.ends_with("content modified") {
5021 log::warn!("{message}");
5022 }
5023 return Task::ready(Err(anyhow!(message)));
5024 }
5025 };
5026
5027 let status = request.status();
5028 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
5029 return Task::ready(Ok(Default::default()));
5030 }
5031
5032 let request_timeout = ProjectSettings::get_global(cx)
5033 .global_lsp_settings
5034 .get_request_timeout();
5035
5036 cx.spawn(async move |this, cx| {
5037 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5038
5039 let id = lsp_request.id();
5040 let _cleanup = if status.is_some() {
5041 cx.update(|cx| {
5042 this.update(cx, |this, cx| {
5043 this.on_lsp_work_start(
5044 language_server.server_id(),
5045 ProgressToken::Number(id),
5046 LanguageServerProgress {
5047 is_disk_based_diagnostics_progress: false,
5048 is_cancellable: false,
5049 title: None,
5050 message: status.clone(),
5051 percentage: None,
5052 last_update_at: cx.background_executor().now(),
5053 },
5054 cx,
5055 );
5056 })
5057 })
5058 .log_err();
5059
5060 Some(defer(|| {
5061 cx.update(|cx| {
5062 this.update(cx, |this, cx| {
5063 this.on_lsp_work_end(
5064 language_server.server_id(),
5065 ProgressToken::Number(id),
5066 cx,
5067 );
5068 })
5069 })
5070 .log_err();
5071 }))
5072 } else {
5073 None
5074 };
5075
5076 let result = lsp_request.await.into_response();
5077
5078 let response = result.map_err(|err| {
5079 let message = format!(
5080 "{} via {} failed: {}",
5081 request.display_name(),
5082 language_server.name(),
5083 err
5084 );
5085 // rust-analyzer likes to error with this when its still loading up
5086 if !message.ends_with("content modified") {
5087 log::warn!("{message}");
5088 }
5089 anyhow::anyhow!(message)
5090 })?;
5091
5092 request
5093 .response_from_lsp(
5094 response,
5095 this.upgrade().context("no app context")?,
5096 buffer,
5097 language_server.server_id(),
5098 cx.clone(),
5099 )
5100 .await
5101 })
5102 }
5103
5104 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5105 let mut language_formatters_to_check = Vec::new();
5106 for buffer in self.buffer_store.read(cx).buffers() {
5107 let buffer = buffer.read(cx);
5108 let buffer_file = File::from_dyn(buffer.file());
5109 let buffer_language = buffer.language();
5110 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5111 if buffer_language.is_some() {
5112 language_formatters_to_check.push((
5113 buffer_file.map(|f| f.worktree_id(cx)),
5114 settings.into_owned(),
5115 ));
5116 }
5117 }
5118
5119 self.request_workspace_config_refresh();
5120
5121 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5122 prettier_store.update(cx, |prettier_store, cx| {
5123 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5124 })
5125 }
5126
5127 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5128 .global_lsp_settings
5129 .semantic_token_rules
5130 .clone();
5131 self.semantic_token_config
5132 .update_rules(new_semantic_token_rules);
5133
5134 let new_global_semantic_tokens_mode =
5135 all_language_settings(None, cx).defaults.semantic_tokens;
5136 if self
5137 .semantic_token_config
5138 .update_global_mode(new_global_semantic_tokens_mode)
5139 {
5140 self.restart_all_language_servers(cx);
5141 }
5142
5143 cx.notify();
5144 }
5145
5146 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5147 let buffer_store = self.buffer_store.clone();
5148 let Some(local) = self.as_local_mut() else {
5149 return;
5150 };
5151 let mut adapters = BTreeMap::default();
5152 let get_adapter = {
5153 let languages = local.languages.clone();
5154 let environment = local.environment.clone();
5155 let weak = local.weak.clone();
5156 let worktree_store = local.worktree_store.clone();
5157 let http_client = local.http_client.clone();
5158 let fs = local.fs.clone();
5159 move |worktree_id, cx: &mut App| {
5160 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5161 Some(LocalLspAdapterDelegate::new(
5162 languages.clone(),
5163 &environment,
5164 weak.clone(),
5165 &worktree,
5166 http_client.clone(),
5167 fs.clone(),
5168 cx,
5169 ))
5170 }
5171 };
5172
5173 let mut messages_to_report = Vec::new();
5174 let (new_tree, to_stop) = {
5175 let mut rebase = local.lsp_tree.rebase();
5176 let buffers = buffer_store
5177 .read(cx)
5178 .buffers()
5179 .filter_map(|buffer| {
5180 let raw_buffer = buffer.read(cx);
5181 if !local
5182 .registered_buffers
5183 .contains_key(&raw_buffer.remote_id())
5184 {
5185 return None;
5186 }
5187 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5188 let language = raw_buffer.language().cloned()?;
5189 Some((file, language, raw_buffer.remote_id()))
5190 })
5191 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5192 for (file, language, buffer_id) in buffers {
5193 let worktree_id = file.worktree_id(cx);
5194 let Some(worktree) = local
5195 .worktree_store
5196 .read(cx)
5197 .worktree_for_id(worktree_id, cx)
5198 else {
5199 continue;
5200 };
5201
5202 if let Some((_, apply)) = local.reuse_existing_language_server(
5203 rebase.server_tree(),
5204 &worktree,
5205 &language.name(),
5206 cx,
5207 ) {
5208 (apply)(rebase.server_tree());
5209 } else if let Some(lsp_delegate) = adapters
5210 .entry(worktree_id)
5211 .or_insert_with(|| get_adapter(worktree_id, cx))
5212 .clone()
5213 {
5214 let delegate =
5215 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5216 let path = file
5217 .path()
5218 .parent()
5219 .map(Arc::from)
5220 .unwrap_or_else(|| file.path().clone());
5221 let worktree_path = ProjectPath { worktree_id, path };
5222 let abs_path = file.abs_path(cx);
5223 let nodes = rebase
5224 .walk(
5225 worktree_path,
5226 language.name(),
5227 language.manifest(),
5228 delegate.clone(),
5229 cx,
5230 )
5231 .collect::<Vec<_>>();
5232 for node in nodes {
5233 let server_id = node.server_id_or_init(|disposition| {
5234 let path = &disposition.path;
5235 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5236 let key = LanguageServerSeed {
5237 worktree_id,
5238 name: disposition.server_name.clone(),
5239 settings: LanguageServerSeedSettings {
5240 binary: disposition.settings.binary.clone(),
5241 initialization_options: disposition
5242 .settings
5243 .initialization_options
5244 .clone(),
5245 },
5246 toolchain: local.toolchain_store.read(cx).active_toolchain(
5247 path.worktree_id,
5248 &path.path,
5249 language.name(),
5250 ),
5251 };
5252 local.language_server_ids.remove(&key);
5253
5254 let server_id = local.get_or_insert_language_server(
5255 &worktree,
5256 lsp_delegate.clone(),
5257 disposition,
5258 &language.name(),
5259 cx,
5260 );
5261 if let Some(state) = local.language_servers.get(&server_id)
5262 && let Ok(uri) = uri
5263 {
5264 state.add_workspace_folder(uri);
5265 };
5266 server_id
5267 });
5268
5269 if let Some(language_server_id) = server_id {
5270 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5271 language_server_id,
5272 name: node.name(),
5273 message:
5274 proto::update_language_server::Variant::RegisteredForBuffer(
5275 proto::RegisteredForBuffer {
5276 buffer_abs_path: abs_path
5277 .to_string_lossy()
5278 .into_owned(),
5279 buffer_id: buffer_id.to_proto(),
5280 },
5281 ),
5282 });
5283 }
5284 }
5285 } else {
5286 continue;
5287 }
5288 }
5289 rebase.finish()
5290 };
5291 for message in messages_to_report {
5292 cx.emit(message);
5293 }
5294 local.lsp_tree = new_tree;
5295 for (id, _) in to_stop {
5296 self.stop_local_language_server(id, cx).detach();
5297 }
5298 }
5299
5300 pub fn apply_code_action(
5301 &self,
5302 buffer_handle: Entity<Buffer>,
5303 mut action: CodeAction,
5304 push_to_history: bool,
5305 cx: &mut Context<Self>,
5306 ) -> Task<Result<ProjectTransaction>> {
5307 if let Some((upstream_client, project_id)) = self.upstream_client() {
5308 let request = proto::ApplyCodeAction {
5309 project_id,
5310 buffer_id: buffer_handle.read(cx).remote_id().into(),
5311 action: Some(Self::serialize_code_action(&action)),
5312 };
5313 let buffer_store = self.buffer_store();
5314 cx.spawn(async move |_, cx| {
5315 let response = upstream_client
5316 .request(request)
5317 .await?
5318 .transaction
5319 .context("missing transaction")?;
5320
5321 buffer_store
5322 .update(cx, |buffer_store, cx| {
5323 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5324 })
5325 .await
5326 })
5327 } else if self.mode.is_local() {
5328 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5329 let request_timeout = ProjectSettings::get_global(cx)
5330 .global_lsp_settings
5331 .get_request_timeout();
5332 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5333 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5334 }) else {
5335 return Task::ready(Ok(ProjectTransaction::default()));
5336 };
5337
5338 cx.spawn(async move |this, cx| {
5339 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5340 .await
5341 .context("resolving a code action")?;
5342 if let Some(edit) = action.lsp_action.edit()
5343 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5344 return LocalLspStore::deserialize_workspace_edit(
5345 this.upgrade().context("no app present")?,
5346 edit.clone(),
5347 push_to_history,
5348
5349 lang_server.clone(),
5350 cx,
5351 )
5352 .await;
5353 }
5354
5355 let Some(command) = action.lsp_action.command() else {
5356 return Ok(ProjectTransaction::default())
5357 };
5358
5359 let server_capabilities = lang_server.capabilities();
5360 let available_commands = server_capabilities
5361 .execute_command_provider
5362 .as_ref()
5363 .map(|options| options.commands.as_slice())
5364 .unwrap_or_default();
5365
5366 if !available_commands.contains(&command.command) {
5367 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5368 return Ok(ProjectTransaction::default())
5369 }
5370
5371 let request_timeout = cx.update(|app|
5372 ProjectSettings::get_global(app)
5373 .global_lsp_settings
5374 .get_request_timeout()
5375 );
5376
5377 this.update(cx, |this, _| {
5378 this.as_local_mut()
5379 .unwrap()
5380 .last_workspace_edits_by_language_server
5381 .remove(&lang_server.server_id());
5382 })?;
5383
5384 let _result = lang_server
5385 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5386 command: command.command.clone(),
5387 arguments: command.arguments.clone().unwrap_or_default(),
5388 ..lsp::ExecuteCommandParams::default()
5389 }, request_timeout)
5390 .await.into_response()
5391 .context("execute command")?;
5392
5393 return this.update(cx, |this, _| {
5394 this.as_local_mut()
5395 .unwrap()
5396 .last_workspace_edits_by_language_server
5397 .remove(&lang_server.server_id())
5398 .unwrap_or_default()
5399 });
5400 })
5401 } else {
5402 Task::ready(Err(anyhow!("no upstream client and not local")))
5403 }
5404 }
5405
5406 pub fn apply_code_action_kind(
5407 &mut self,
5408 buffers: HashSet<Entity<Buffer>>,
5409 kind: CodeActionKind,
5410 push_to_history: bool,
5411 cx: &mut Context<Self>,
5412 ) -> Task<anyhow::Result<ProjectTransaction>> {
5413 if self.as_local().is_some() {
5414 cx.spawn(async move |lsp_store, cx| {
5415 let buffers = buffers.into_iter().collect::<Vec<_>>();
5416 let result = LocalLspStore::execute_code_action_kind_locally(
5417 lsp_store.clone(),
5418 buffers,
5419 kind,
5420 push_to_history,
5421 cx,
5422 )
5423 .await;
5424 lsp_store.update(cx, |lsp_store, _| {
5425 lsp_store.update_last_formatting_failure(&result);
5426 })?;
5427 result
5428 })
5429 } else if let Some((client, project_id)) = self.upstream_client() {
5430 let buffer_store = self.buffer_store();
5431 cx.spawn(async move |lsp_store, cx| {
5432 let result = client
5433 .request(proto::ApplyCodeActionKind {
5434 project_id,
5435 kind: kind.as_str().to_owned(),
5436 buffer_ids: buffers
5437 .iter()
5438 .map(|buffer| {
5439 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5440 })
5441 .collect(),
5442 })
5443 .await
5444 .and_then(|result| result.transaction.context("missing transaction"));
5445 lsp_store.update(cx, |lsp_store, _| {
5446 lsp_store.update_last_formatting_failure(&result);
5447 })?;
5448
5449 let transaction_response = result?;
5450 buffer_store
5451 .update(cx, |buffer_store, cx| {
5452 buffer_store.deserialize_project_transaction(
5453 transaction_response,
5454 push_to_history,
5455 cx,
5456 )
5457 })
5458 .await
5459 })
5460 } else {
5461 Task::ready(Ok(ProjectTransaction::default()))
5462 }
5463 }
5464
5465 pub fn resolved_hint(
5466 &mut self,
5467 buffer_id: BufferId,
5468 id: InlayId,
5469 cx: &mut Context<Self>,
5470 ) -> Option<ResolvedHint> {
5471 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5472
5473 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5474 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5475 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5476 let (server_id, resolve_data) = match &hint.resolve_state {
5477 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5478 ResolveState::Resolving => {
5479 return Some(ResolvedHint::Resolving(
5480 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5481 ));
5482 }
5483 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5484 };
5485
5486 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5487 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5488 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5489 id,
5490 cx.spawn(async move |lsp_store, cx| {
5491 let resolved_hint = resolve_task.await;
5492 lsp_store
5493 .update(cx, |lsp_store, _| {
5494 if let Some(old_inlay_hint) = lsp_store
5495 .lsp_data
5496 .get_mut(&buffer_id)
5497 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5498 {
5499 match resolved_hint {
5500 Ok(resolved_hint) => {
5501 *old_inlay_hint = resolved_hint;
5502 }
5503 Err(e) => {
5504 old_inlay_hint.resolve_state =
5505 ResolveState::CanResolve(server_id, resolve_data);
5506 log::error!("Inlay hint resolve failed: {e:#}");
5507 }
5508 }
5509 }
5510 })
5511 .ok();
5512 })
5513 .shared(),
5514 );
5515 debug_assert!(
5516 previous_task.is_none(),
5517 "Did not change hint's resolve state after spawning its resolve"
5518 );
5519 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5520 None
5521 }
5522
5523 pub(crate) fn linked_edits(
5524 &mut self,
5525 buffer: &Entity<Buffer>,
5526 position: Anchor,
5527 cx: &mut Context<Self>,
5528 ) -> Task<Result<Vec<Range<Anchor>>>> {
5529 let snapshot = buffer.read(cx).snapshot();
5530 let scope = snapshot.language_scope_at(position);
5531 let Some(server_id) = self
5532 .as_local()
5533 .and_then(|local| {
5534 buffer.update(cx, |buffer, cx| {
5535 local
5536 .language_servers_for_buffer(buffer, cx)
5537 .filter(|(_, server)| {
5538 LinkedEditingRange::check_server_capabilities(server.capabilities())
5539 })
5540 .filter(|(adapter, _)| {
5541 scope
5542 .as_ref()
5543 .map(|scope| scope.language_allowed(&adapter.name))
5544 .unwrap_or(true)
5545 })
5546 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5547 .next()
5548 })
5549 })
5550 .or_else(|| {
5551 self.upstream_client()
5552 .is_some()
5553 .then_some(LanguageServerToQuery::FirstCapable)
5554 })
5555 .filter(|_| {
5556 maybe!({
5557 let language = buffer.read(cx).language_at(position)?;
5558 Some(
5559 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5560 .linked_edits,
5561 )
5562 }) == Some(true)
5563 })
5564 else {
5565 return Task::ready(Ok(Vec::new()));
5566 };
5567
5568 self.request_lsp(
5569 buffer.clone(),
5570 server_id,
5571 LinkedEditingRange { position },
5572 cx,
5573 )
5574 }
5575
5576 fn apply_on_type_formatting(
5577 &mut self,
5578 buffer: Entity<Buffer>,
5579 position: Anchor,
5580 trigger: String,
5581 cx: &mut Context<Self>,
5582 ) -> Task<Result<Option<Transaction>>> {
5583 if let Some((client, project_id)) = self.upstream_client() {
5584 if !self.check_if_capable_for_proto_request(
5585 &buffer,
5586 |capabilities| {
5587 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5588 },
5589 cx,
5590 ) {
5591 return Task::ready(Ok(None));
5592 }
5593 let request = proto::OnTypeFormatting {
5594 project_id,
5595 buffer_id: buffer.read(cx).remote_id().into(),
5596 position: Some(serialize_anchor(&position)),
5597 trigger,
5598 version: serialize_version(&buffer.read(cx).version()),
5599 };
5600 cx.background_spawn(async move {
5601 client
5602 .request(request)
5603 .await?
5604 .transaction
5605 .map(language::proto::deserialize_transaction)
5606 .transpose()
5607 })
5608 } else if let Some(local) = self.as_local_mut() {
5609 let buffer_id = buffer.read(cx).remote_id();
5610 local.buffers_being_formatted.insert(buffer_id);
5611 cx.spawn(async move |this, cx| {
5612 let _cleanup = defer({
5613 let this = this.clone();
5614 let mut cx = cx.clone();
5615 move || {
5616 this.update(&mut cx, |this, _| {
5617 if let Some(local) = this.as_local_mut() {
5618 local.buffers_being_formatted.remove(&buffer_id);
5619 }
5620 })
5621 .ok();
5622 }
5623 });
5624
5625 buffer
5626 .update(cx, |buffer, _| {
5627 buffer.wait_for_edits(Some(position.timestamp()))
5628 })
5629 .await?;
5630 this.update(cx, |this, cx| {
5631 let position = position.to_point_utf16(buffer.read(cx));
5632 this.on_type_format(buffer, position, trigger, false, cx)
5633 })?
5634 .await
5635 })
5636 } else {
5637 Task::ready(Err(anyhow!("No upstream client or local language server")))
5638 }
5639 }
5640
5641 pub fn on_type_format<T: ToPointUtf16>(
5642 &mut self,
5643 buffer: Entity<Buffer>,
5644 position: T,
5645 trigger: String,
5646 push_to_history: bool,
5647 cx: &mut Context<Self>,
5648 ) -> Task<Result<Option<Transaction>>> {
5649 let position = position.to_point_utf16(buffer.read(cx));
5650 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5651 }
5652
5653 fn on_type_format_impl(
5654 &mut self,
5655 buffer: Entity<Buffer>,
5656 position: PointUtf16,
5657 trigger: String,
5658 push_to_history: bool,
5659 cx: &mut Context<Self>,
5660 ) -> Task<Result<Option<Transaction>>> {
5661 let options = buffer.update(cx, |buffer, cx| {
5662 lsp_command::lsp_formatting_options(
5663 language_settings(
5664 buffer.language_at(position).map(|l| l.name()),
5665 buffer.file(),
5666 cx,
5667 )
5668 .as_ref(),
5669 )
5670 });
5671
5672 cx.spawn(async move |this, cx| {
5673 if let Some(waiter) =
5674 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5675 {
5676 waiter.await?;
5677 }
5678 cx.update(|cx| {
5679 this.update(cx, |this, cx| {
5680 this.request_lsp(
5681 buffer.clone(),
5682 LanguageServerToQuery::FirstCapable,
5683 OnTypeFormatting {
5684 position,
5685 trigger,
5686 options,
5687 push_to_history,
5688 },
5689 cx,
5690 )
5691 })
5692 })?
5693 .await
5694 })
5695 }
5696
5697 pub fn definitions(
5698 &mut self,
5699 buffer: &Entity<Buffer>,
5700 position: PointUtf16,
5701 cx: &mut Context<Self>,
5702 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5703 if let Some((upstream_client, project_id)) = self.upstream_client() {
5704 let request = GetDefinitions { position };
5705 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5706 return Task::ready(Ok(None));
5707 }
5708
5709 let request_timeout = ProjectSettings::get_global(cx)
5710 .global_lsp_settings
5711 .get_request_timeout();
5712
5713 let request_task = upstream_client.request_lsp(
5714 project_id,
5715 None,
5716 request_timeout,
5717 cx.background_executor().clone(),
5718 request.to_proto(project_id, buffer.read(cx)),
5719 );
5720 let buffer = buffer.clone();
5721 cx.spawn(async move |weak_lsp_store, cx| {
5722 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5723 return Ok(None);
5724 };
5725 let Some(responses) = request_task.await? else {
5726 return Ok(None);
5727 };
5728 let actions = join_all(responses.payload.into_iter().map(|response| {
5729 GetDefinitions { position }.response_from_proto(
5730 response.response,
5731 lsp_store.clone(),
5732 buffer.clone(),
5733 cx.clone(),
5734 )
5735 }))
5736 .await;
5737
5738 Ok(Some(
5739 actions
5740 .into_iter()
5741 .collect::<Result<Vec<Vec<_>>>>()?
5742 .into_iter()
5743 .flatten()
5744 .dedup()
5745 .collect(),
5746 ))
5747 })
5748 } else {
5749 let definitions_task = self.request_multiple_lsp_locally(
5750 buffer,
5751 Some(position),
5752 GetDefinitions { position },
5753 cx,
5754 );
5755 cx.background_spawn(async move {
5756 Ok(Some(
5757 definitions_task
5758 .await
5759 .into_iter()
5760 .flat_map(|(_, definitions)| definitions)
5761 .dedup()
5762 .collect(),
5763 ))
5764 })
5765 }
5766 }
5767
5768 pub fn declarations(
5769 &mut self,
5770 buffer: &Entity<Buffer>,
5771 position: PointUtf16,
5772 cx: &mut Context<Self>,
5773 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5774 if let Some((upstream_client, project_id)) = self.upstream_client() {
5775 let request = GetDeclarations { position };
5776 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5777 return Task::ready(Ok(None));
5778 }
5779 let request_timeout = ProjectSettings::get_global(cx)
5780 .global_lsp_settings
5781 .get_request_timeout();
5782 let request_task = upstream_client.request_lsp(
5783 project_id,
5784 None,
5785 request_timeout,
5786 cx.background_executor().clone(),
5787 request.to_proto(project_id, buffer.read(cx)),
5788 );
5789 let buffer = buffer.clone();
5790 cx.spawn(async move |weak_lsp_store, cx| {
5791 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5792 return Ok(None);
5793 };
5794 let Some(responses) = request_task.await? else {
5795 return Ok(None);
5796 };
5797 let actions = join_all(responses.payload.into_iter().map(|response| {
5798 GetDeclarations { position }.response_from_proto(
5799 response.response,
5800 lsp_store.clone(),
5801 buffer.clone(),
5802 cx.clone(),
5803 )
5804 }))
5805 .await;
5806
5807 Ok(Some(
5808 actions
5809 .into_iter()
5810 .collect::<Result<Vec<Vec<_>>>>()?
5811 .into_iter()
5812 .flatten()
5813 .dedup()
5814 .collect(),
5815 ))
5816 })
5817 } else {
5818 let declarations_task = self.request_multiple_lsp_locally(
5819 buffer,
5820 Some(position),
5821 GetDeclarations { position },
5822 cx,
5823 );
5824 cx.background_spawn(async move {
5825 Ok(Some(
5826 declarations_task
5827 .await
5828 .into_iter()
5829 .flat_map(|(_, declarations)| declarations)
5830 .dedup()
5831 .collect(),
5832 ))
5833 })
5834 }
5835 }
5836
5837 pub fn type_definitions(
5838 &mut self,
5839 buffer: &Entity<Buffer>,
5840 position: PointUtf16,
5841 cx: &mut Context<Self>,
5842 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5843 if let Some((upstream_client, project_id)) = self.upstream_client() {
5844 let request = GetTypeDefinitions { position };
5845 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5846 return Task::ready(Ok(None));
5847 }
5848 let request_timeout = ProjectSettings::get_global(cx)
5849 .global_lsp_settings
5850 .get_request_timeout();
5851 let request_task = upstream_client.request_lsp(
5852 project_id,
5853 None,
5854 request_timeout,
5855 cx.background_executor().clone(),
5856 request.to_proto(project_id, buffer.read(cx)),
5857 );
5858 let buffer = buffer.clone();
5859 cx.spawn(async move |weak_lsp_store, cx| {
5860 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5861 return Ok(None);
5862 };
5863 let Some(responses) = request_task.await? else {
5864 return Ok(None);
5865 };
5866 let actions = join_all(responses.payload.into_iter().map(|response| {
5867 GetTypeDefinitions { position }.response_from_proto(
5868 response.response,
5869 lsp_store.clone(),
5870 buffer.clone(),
5871 cx.clone(),
5872 )
5873 }))
5874 .await;
5875
5876 Ok(Some(
5877 actions
5878 .into_iter()
5879 .collect::<Result<Vec<Vec<_>>>>()?
5880 .into_iter()
5881 .flatten()
5882 .dedup()
5883 .collect(),
5884 ))
5885 })
5886 } else {
5887 let type_definitions_task = self.request_multiple_lsp_locally(
5888 buffer,
5889 Some(position),
5890 GetTypeDefinitions { position },
5891 cx,
5892 );
5893 cx.background_spawn(async move {
5894 Ok(Some(
5895 type_definitions_task
5896 .await
5897 .into_iter()
5898 .flat_map(|(_, type_definitions)| type_definitions)
5899 .dedup()
5900 .collect(),
5901 ))
5902 })
5903 }
5904 }
5905
5906 pub fn implementations(
5907 &mut self,
5908 buffer: &Entity<Buffer>,
5909 position: PointUtf16,
5910 cx: &mut Context<Self>,
5911 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5912 if let Some((upstream_client, project_id)) = self.upstream_client() {
5913 let request = GetImplementations { position };
5914 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5915 return Task::ready(Ok(None));
5916 }
5917
5918 let request_timeout = ProjectSettings::get_global(cx)
5919 .global_lsp_settings
5920 .get_request_timeout();
5921 let request_task = upstream_client.request_lsp(
5922 project_id,
5923 None,
5924 request_timeout,
5925 cx.background_executor().clone(),
5926 request.to_proto(project_id, buffer.read(cx)),
5927 );
5928 let buffer = buffer.clone();
5929 cx.spawn(async move |weak_lsp_store, cx| {
5930 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5931 return Ok(None);
5932 };
5933 let Some(responses) = request_task.await? else {
5934 return Ok(None);
5935 };
5936 let actions = join_all(responses.payload.into_iter().map(|response| {
5937 GetImplementations { position }.response_from_proto(
5938 response.response,
5939 lsp_store.clone(),
5940 buffer.clone(),
5941 cx.clone(),
5942 )
5943 }))
5944 .await;
5945
5946 Ok(Some(
5947 actions
5948 .into_iter()
5949 .collect::<Result<Vec<Vec<_>>>>()?
5950 .into_iter()
5951 .flatten()
5952 .dedup()
5953 .collect(),
5954 ))
5955 })
5956 } else {
5957 let implementations_task = self.request_multiple_lsp_locally(
5958 buffer,
5959 Some(position),
5960 GetImplementations { position },
5961 cx,
5962 );
5963 cx.background_spawn(async move {
5964 Ok(Some(
5965 implementations_task
5966 .await
5967 .into_iter()
5968 .flat_map(|(_, implementations)| implementations)
5969 .dedup()
5970 .collect(),
5971 ))
5972 })
5973 }
5974 }
5975
5976 pub fn references(
5977 &mut self,
5978 buffer: &Entity<Buffer>,
5979 position: PointUtf16,
5980 cx: &mut Context<Self>,
5981 ) -> Task<Result<Option<Vec<Location>>>> {
5982 if let Some((upstream_client, project_id)) = self.upstream_client() {
5983 let request = GetReferences { position };
5984 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5985 return Task::ready(Ok(None));
5986 }
5987
5988 let request_timeout = ProjectSettings::get_global(cx)
5989 .global_lsp_settings
5990 .get_request_timeout();
5991 let request_task = upstream_client.request_lsp(
5992 project_id,
5993 None,
5994 request_timeout,
5995 cx.background_executor().clone(),
5996 request.to_proto(project_id, buffer.read(cx)),
5997 );
5998 let buffer = buffer.clone();
5999 cx.spawn(async move |weak_lsp_store, cx| {
6000 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6001 return Ok(None);
6002 };
6003 let Some(responses) = request_task.await? else {
6004 return Ok(None);
6005 };
6006
6007 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6008 GetReferences { position }.response_from_proto(
6009 lsp_response.response,
6010 lsp_store.clone(),
6011 buffer.clone(),
6012 cx.clone(),
6013 )
6014 }))
6015 .await
6016 .into_iter()
6017 .collect::<Result<Vec<Vec<_>>>>()?
6018 .into_iter()
6019 .flatten()
6020 .dedup()
6021 .collect();
6022 Ok(Some(locations))
6023 })
6024 } else {
6025 let references_task = self.request_multiple_lsp_locally(
6026 buffer,
6027 Some(position),
6028 GetReferences { position },
6029 cx,
6030 );
6031 cx.background_spawn(async move {
6032 Ok(Some(
6033 references_task
6034 .await
6035 .into_iter()
6036 .flat_map(|(_, references)| references)
6037 .dedup()
6038 .collect(),
6039 ))
6040 })
6041 }
6042 }
6043
6044 pub fn code_actions(
6045 &mut self,
6046 buffer: &Entity<Buffer>,
6047 range: Range<Anchor>,
6048 kinds: Option<Vec<CodeActionKind>>,
6049 cx: &mut Context<Self>,
6050 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6051 if let Some((upstream_client, project_id)) = self.upstream_client() {
6052 let request = GetCodeActions {
6053 range: range.clone(),
6054 kinds: kinds.clone(),
6055 };
6056 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6057 return Task::ready(Ok(None));
6058 }
6059 let request_timeout = ProjectSettings::get_global(cx)
6060 .global_lsp_settings
6061 .get_request_timeout();
6062 let request_task = upstream_client.request_lsp(
6063 project_id,
6064 None,
6065 request_timeout,
6066 cx.background_executor().clone(),
6067 request.to_proto(project_id, buffer.read(cx)),
6068 );
6069 let buffer = buffer.clone();
6070 cx.spawn(async move |weak_lsp_store, cx| {
6071 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6072 return Ok(None);
6073 };
6074 let Some(responses) = request_task.await? else {
6075 return Ok(None);
6076 };
6077 let actions = join_all(responses.payload.into_iter().map(|response| {
6078 GetCodeActions {
6079 range: range.clone(),
6080 kinds: kinds.clone(),
6081 }
6082 .response_from_proto(
6083 response.response,
6084 lsp_store.clone(),
6085 buffer.clone(),
6086 cx.clone(),
6087 )
6088 }))
6089 .await;
6090
6091 Ok(Some(
6092 actions
6093 .into_iter()
6094 .collect::<Result<Vec<Vec<_>>>>()?
6095 .into_iter()
6096 .flatten()
6097 .collect(),
6098 ))
6099 })
6100 } else {
6101 let all_actions_task = self.request_multiple_lsp_locally(
6102 buffer,
6103 Some(range.start),
6104 GetCodeActions { range, kinds },
6105 cx,
6106 );
6107 cx.background_spawn(async move {
6108 Ok(Some(
6109 all_actions_task
6110 .await
6111 .into_iter()
6112 .flat_map(|(_, actions)| actions)
6113 .collect(),
6114 ))
6115 })
6116 }
6117 }
6118
6119 #[inline(never)]
6120 pub fn completions(
6121 &self,
6122 buffer: &Entity<Buffer>,
6123 position: PointUtf16,
6124 context: CompletionContext,
6125 cx: &mut Context<Self>,
6126 ) -> Task<Result<Vec<CompletionResponse>>> {
6127 let language_registry = self.languages.clone();
6128
6129 if let Some((upstream_client, project_id)) = self.upstream_client() {
6130 let snapshot = buffer.read(cx).snapshot();
6131 let offset = position.to_offset(&snapshot);
6132 let scope = snapshot.language_scope_at(offset);
6133 let capable_lsps = self.all_capable_for_proto_request(
6134 buffer,
6135 |server_name, capabilities| {
6136 capabilities.completion_provider.is_some()
6137 && scope
6138 .as_ref()
6139 .map(|scope| scope.language_allowed(server_name))
6140 .unwrap_or(true)
6141 },
6142 cx,
6143 );
6144 if capable_lsps.is_empty() {
6145 return Task::ready(Ok(Vec::new()));
6146 }
6147
6148 let language = buffer.read(cx).language().cloned();
6149
6150 // In the future, we should provide project guests with the names of LSP adapters,
6151 // so that they can use the correct LSP adapter when computing labels. For now,
6152 // guests just use the first LSP adapter associated with the buffer's language.
6153 let lsp_adapter = language.as_ref().and_then(|language| {
6154 language_registry
6155 .lsp_adapters(&language.name())
6156 .first()
6157 .cloned()
6158 });
6159
6160 let buffer = buffer.clone();
6161
6162 cx.spawn(async move |this, cx| {
6163 let requests = join_all(
6164 capable_lsps
6165 .into_iter()
6166 .map(|id| {
6167 let request = GetCompletions {
6168 position,
6169 context: context.clone(),
6170 server_id: Some(id),
6171 };
6172 let buffer = buffer.clone();
6173 let language = language.clone();
6174 let lsp_adapter = lsp_adapter.clone();
6175 let upstream_client = upstream_client.clone();
6176 let response = this
6177 .update(cx, |this, cx| {
6178 this.send_lsp_proto_request(
6179 buffer,
6180 upstream_client,
6181 project_id,
6182 request,
6183 cx,
6184 )
6185 })
6186 .log_err();
6187 async move {
6188 let response = response?.await.log_err()?;
6189
6190 let completions = populate_labels_for_completions(
6191 response.completions,
6192 language,
6193 lsp_adapter,
6194 )
6195 .await;
6196
6197 Some(CompletionResponse {
6198 completions,
6199 display_options: CompletionDisplayOptions::default(),
6200 is_incomplete: response.is_incomplete,
6201 })
6202 }
6203 })
6204 .collect::<Vec<_>>(),
6205 );
6206 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6207 })
6208 } else if let Some(local) = self.as_local() {
6209 let snapshot = buffer.read(cx).snapshot();
6210 let offset = position.to_offset(&snapshot);
6211 let scope = snapshot.language_scope_at(offset);
6212 let language = snapshot.language().cloned();
6213 let completion_settings = language_settings(
6214 language.as_ref().map(|language| language.name()),
6215 buffer.read(cx).file(),
6216 cx,
6217 )
6218 .completions
6219 .clone();
6220 if !completion_settings.lsp {
6221 return Task::ready(Ok(Vec::new()));
6222 }
6223
6224 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6225 local
6226 .language_servers_for_buffer(buffer, cx)
6227 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6228 .filter(|(adapter, _)| {
6229 scope
6230 .as_ref()
6231 .map(|scope| scope.language_allowed(&adapter.name))
6232 .unwrap_or(true)
6233 })
6234 .map(|(_, server)| server.server_id())
6235 .collect()
6236 });
6237
6238 let buffer = buffer.clone();
6239 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6240 let lsp_timeout = if lsp_timeout > 0 {
6241 Some(Duration::from_millis(lsp_timeout))
6242 } else {
6243 None
6244 };
6245 cx.spawn(async move |this, cx| {
6246 let mut tasks = Vec::with_capacity(server_ids.len());
6247 this.update(cx, |lsp_store, cx| {
6248 for server_id in server_ids {
6249 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6250 let lsp_timeout = lsp_timeout
6251 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6252 let mut timeout = cx.background_spawn(async move {
6253 match lsp_timeout {
6254 Some(lsp_timeout) => {
6255 lsp_timeout.await;
6256 true
6257 },
6258 None => false,
6259 }
6260 }).fuse();
6261 let mut lsp_request = lsp_store.request_lsp(
6262 buffer.clone(),
6263 LanguageServerToQuery::Other(server_id),
6264 GetCompletions {
6265 position,
6266 context: context.clone(),
6267 server_id: Some(server_id),
6268 },
6269 cx,
6270 ).fuse();
6271 let new_task = cx.background_spawn(async move {
6272 select_biased! {
6273 response = lsp_request => anyhow::Ok(Some(response?)),
6274 timeout_happened = timeout => {
6275 if timeout_happened {
6276 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6277 Ok(None)
6278 } else {
6279 let completions = lsp_request.await?;
6280 Ok(Some(completions))
6281 }
6282 },
6283 }
6284 });
6285 tasks.push((lsp_adapter, new_task));
6286 }
6287 })?;
6288
6289 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6290 let completion_response = task.await.ok()??;
6291 let completions = populate_labels_for_completions(
6292 completion_response.completions,
6293 language.clone(),
6294 lsp_adapter,
6295 )
6296 .await;
6297 Some(CompletionResponse {
6298 completions,
6299 display_options: CompletionDisplayOptions::default(),
6300 is_incomplete: completion_response.is_incomplete,
6301 })
6302 });
6303
6304 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6305
6306 Ok(responses.into_iter().flatten().collect())
6307 })
6308 } else {
6309 Task::ready(Err(anyhow!("No upstream client or local language server")))
6310 }
6311 }
6312
6313 pub fn resolve_completions(
6314 &self,
6315 buffer: Entity<Buffer>,
6316 completion_indices: Vec<usize>,
6317 completions: Rc<RefCell<Box<[Completion]>>>,
6318 cx: &mut Context<Self>,
6319 ) -> Task<Result<bool>> {
6320 let client = self.upstream_client();
6321 let buffer_id = buffer.read(cx).remote_id();
6322 let buffer_snapshot = buffer.read(cx).snapshot();
6323
6324 if !self.check_if_capable_for_proto_request(
6325 &buffer,
6326 GetCompletions::can_resolve_completions,
6327 cx,
6328 ) {
6329 return Task::ready(Ok(false));
6330 }
6331 cx.spawn(async move |lsp_store, cx| {
6332 let request_timeout = cx.update(|app| {
6333 ProjectSettings::get_global(app)
6334 .global_lsp_settings
6335 .get_request_timeout()
6336 });
6337
6338 let mut did_resolve = false;
6339 if let Some((client, project_id)) = client {
6340 for completion_index in completion_indices {
6341 let server_id = {
6342 let completion = &completions.borrow()[completion_index];
6343 completion.source.server_id()
6344 };
6345 if let Some(server_id) = server_id {
6346 if Self::resolve_completion_remote(
6347 project_id,
6348 server_id,
6349 buffer_id,
6350 completions.clone(),
6351 completion_index,
6352 client.clone(),
6353 )
6354 .await
6355 .log_err()
6356 .is_some()
6357 {
6358 did_resolve = true;
6359 }
6360 } else {
6361 resolve_word_completion(
6362 &buffer_snapshot,
6363 &mut completions.borrow_mut()[completion_index],
6364 );
6365 }
6366 }
6367 } else {
6368 for completion_index in completion_indices {
6369 let server_id = {
6370 let completion = &completions.borrow()[completion_index];
6371 completion.source.server_id()
6372 };
6373 if let Some(server_id) = server_id {
6374 let server_and_adapter = lsp_store
6375 .read_with(cx, |lsp_store, _| {
6376 let server = lsp_store.language_server_for_id(server_id)?;
6377 let adapter =
6378 lsp_store.language_server_adapter_for_id(server.server_id())?;
6379 Some((server, adapter))
6380 })
6381 .ok()
6382 .flatten();
6383 let Some((server, adapter)) = server_and_adapter else {
6384 continue;
6385 };
6386
6387 let resolved = Self::resolve_completion_local(
6388 server,
6389 completions.clone(),
6390 completion_index,
6391 request_timeout,
6392 )
6393 .await
6394 .log_err()
6395 .is_some();
6396 if resolved {
6397 Self::regenerate_completion_labels(
6398 adapter,
6399 &buffer_snapshot,
6400 completions.clone(),
6401 completion_index,
6402 )
6403 .await
6404 .log_err();
6405 did_resolve = true;
6406 }
6407 } else {
6408 resolve_word_completion(
6409 &buffer_snapshot,
6410 &mut completions.borrow_mut()[completion_index],
6411 );
6412 }
6413 }
6414 }
6415
6416 Ok(did_resolve)
6417 })
6418 }
6419
6420 async fn resolve_completion_local(
6421 server: Arc<lsp::LanguageServer>,
6422 completions: Rc<RefCell<Box<[Completion]>>>,
6423 completion_index: usize,
6424 request_timeout: Duration,
6425 ) -> Result<()> {
6426 let server_id = server.server_id();
6427 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6428 return Ok(());
6429 }
6430
6431 let request = {
6432 let completion = &completions.borrow()[completion_index];
6433 match &completion.source {
6434 CompletionSource::Lsp {
6435 lsp_completion,
6436 resolved,
6437 server_id: completion_server_id,
6438 ..
6439 } => {
6440 if *resolved {
6441 return Ok(());
6442 }
6443 anyhow::ensure!(
6444 server_id == *completion_server_id,
6445 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6446 );
6447 server.request::<lsp::request::ResolveCompletionItem>(
6448 *lsp_completion.clone(),
6449 request_timeout,
6450 )
6451 }
6452 CompletionSource::BufferWord { .. }
6453 | CompletionSource::Dap { .. }
6454 | CompletionSource::Custom => {
6455 return Ok(());
6456 }
6457 }
6458 };
6459 let resolved_completion = request
6460 .await
6461 .into_response()
6462 .context("resolve completion")?;
6463
6464 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6465 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6466
6467 let mut completions = completions.borrow_mut();
6468 let completion = &mut completions[completion_index];
6469 if let CompletionSource::Lsp {
6470 lsp_completion,
6471 resolved,
6472 server_id: completion_server_id,
6473 ..
6474 } = &mut completion.source
6475 {
6476 if *resolved {
6477 return Ok(());
6478 }
6479 anyhow::ensure!(
6480 server_id == *completion_server_id,
6481 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6482 );
6483 **lsp_completion = resolved_completion;
6484 *resolved = true;
6485 }
6486 Ok(())
6487 }
6488
6489 async fn regenerate_completion_labels(
6490 adapter: Arc<CachedLspAdapter>,
6491 snapshot: &BufferSnapshot,
6492 completions: Rc<RefCell<Box<[Completion]>>>,
6493 completion_index: usize,
6494 ) -> Result<()> {
6495 let completion_item = completions.borrow()[completion_index]
6496 .source
6497 .lsp_completion(true)
6498 .map(Cow::into_owned);
6499 if let Some(lsp_documentation) = completion_item
6500 .as_ref()
6501 .and_then(|completion_item| completion_item.documentation.clone())
6502 {
6503 let mut completions = completions.borrow_mut();
6504 let completion = &mut completions[completion_index];
6505 completion.documentation = Some(lsp_documentation.into());
6506 } else {
6507 let mut completions = completions.borrow_mut();
6508 let completion = &mut completions[completion_index];
6509 completion.documentation = Some(CompletionDocumentation::Undocumented);
6510 }
6511
6512 let mut new_label = match completion_item {
6513 Some(completion_item) => {
6514 // Some language servers always return `detail` lazily via resolve, regardless of
6515 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6516 // See: https://github.com/yioneko/vtsls/issues/213
6517 let language = snapshot.language();
6518 match language {
6519 Some(language) => {
6520 adapter
6521 .labels_for_completions(
6522 std::slice::from_ref(&completion_item),
6523 language,
6524 )
6525 .await?
6526 }
6527 None => Vec::new(),
6528 }
6529 .pop()
6530 .flatten()
6531 .unwrap_or_else(|| {
6532 CodeLabel::fallback_for_completion(
6533 &completion_item,
6534 language.map(|language| language.as_ref()),
6535 )
6536 })
6537 }
6538 None => CodeLabel::plain(
6539 completions.borrow()[completion_index].new_text.clone(),
6540 None,
6541 ),
6542 };
6543 ensure_uniform_list_compatible_label(&mut new_label);
6544
6545 let mut completions = completions.borrow_mut();
6546 let completion = &mut completions[completion_index];
6547 if completion.label.filter_text() == new_label.filter_text() {
6548 completion.label = new_label;
6549 } else {
6550 log::error!(
6551 "Resolved completion changed display label from {} to {}. \
6552 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6553 completion.label.text(),
6554 new_label.text(),
6555 completion.label.filter_text(),
6556 new_label.filter_text()
6557 );
6558 }
6559
6560 Ok(())
6561 }
6562
6563 async fn resolve_completion_remote(
6564 project_id: u64,
6565 server_id: LanguageServerId,
6566 buffer_id: BufferId,
6567 completions: Rc<RefCell<Box<[Completion]>>>,
6568 completion_index: usize,
6569 client: AnyProtoClient,
6570 ) -> Result<()> {
6571 let lsp_completion = {
6572 let completion = &completions.borrow()[completion_index];
6573 match &completion.source {
6574 CompletionSource::Lsp {
6575 lsp_completion,
6576 resolved,
6577 server_id: completion_server_id,
6578 ..
6579 } => {
6580 anyhow::ensure!(
6581 server_id == *completion_server_id,
6582 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6583 );
6584 if *resolved {
6585 return Ok(());
6586 }
6587 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6588 }
6589 CompletionSource::Custom
6590 | CompletionSource::Dap { .. }
6591 | CompletionSource::BufferWord { .. } => {
6592 return Ok(());
6593 }
6594 }
6595 };
6596 let request = proto::ResolveCompletionDocumentation {
6597 project_id,
6598 language_server_id: server_id.0 as u64,
6599 lsp_completion,
6600 buffer_id: buffer_id.into(),
6601 };
6602
6603 let response = client
6604 .request(request)
6605 .await
6606 .context("completion documentation resolve proto request")?;
6607 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6608
6609 let documentation = if response.documentation.is_empty() {
6610 CompletionDocumentation::Undocumented
6611 } else if response.documentation_is_markdown {
6612 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6613 } else if response.documentation.lines().count() <= 1 {
6614 CompletionDocumentation::SingleLine(response.documentation.into())
6615 } else {
6616 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6617 };
6618
6619 let mut completions = completions.borrow_mut();
6620 let completion = &mut completions[completion_index];
6621 completion.documentation = Some(documentation);
6622 if let CompletionSource::Lsp {
6623 insert_range,
6624 lsp_completion,
6625 resolved,
6626 server_id: completion_server_id,
6627 lsp_defaults: _,
6628 } = &mut completion.source
6629 {
6630 let completion_insert_range = response
6631 .old_insert_start
6632 .and_then(deserialize_anchor)
6633 .zip(response.old_insert_end.and_then(deserialize_anchor));
6634 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6635
6636 if *resolved {
6637 return Ok(());
6638 }
6639 anyhow::ensure!(
6640 server_id == *completion_server_id,
6641 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6642 );
6643 **lsp_completion = resolved_lsp_completion;
6644 *resolved = true;
6645 }
6646
6647 let replace_range = response
6648 .old_replace_start
6649 .and_then(deserialize_anchor)
6650 .zip(response.old_replace_end.and_then(deserialize_anchor));
6651 if let Some((old_replace_start, old_replace_end)) = replace_range
6652 && !response.new_text.is_empty()
6653 {
6654 completion.new_text = response.new_text;
6655 completion.replace_range = old_replace_start..old_replace_end;
6656 }
6657
6658 Ok(())
6659 }
6660
6661 pub fn apply_additional_edits_for_completion(
6662 &self,
6663 buffer_handle: Entity<Buffer>,
6664 completions: Rc<RefCell<Box<[Completion]>>>,
6665 completion_index: usize,
6666 push_to_history: bool,
6667 cx: &mut Context<Self>,
6668 ) -> Task<Result<Option<Transaction>>> {
6669 if let Some((client, project_id)) = self.upstream_client() {
6670 let buffer = buffer_handle.read(cx);
6671 let buffer_id = buffer.remote_id();
6672 cx.spawn(async move |_, cx| {
6673 let request = {
6674 let completion = completions.borrow()[completion_index].clone();
6675 proto::ApplyCompletionAdditionalEdits {
6676 project_id,
6677 buffer_id: buffer_id.into(),
6678 completion: Some(Self::serialize_completion(&CoreCompletion {
6679 replace_range: completion.replace_range,
6680 new_text: completion.new_text,
6681 source: completion.source,
6682 })),
6683 }
6684 };
6685
6686 let Some(transaction) = client.request(request).await?.transaction else {
6687 return Ok(None);
6688 };
6689
6690 let transaction = language::proto::deserialize_transaction(transaction)?;
6691 buffer_handle
6692 .update(cx, |buffer, _| {
6693 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6694 })
6695 .await?;
6696 if push_to_history {
6697 buffer_handle.update(cx, |buffer, _| {
6698 buffer.push_transaction(transaction.clone(), Instant::now());
6699 buffer.finalize_last_transaction();
6700 });
6701 }
6702 Ok(Some(transaction))
6703 })
6704 } else {
6705 let request_timeout = ProjectSettings::get_global(cx)
6706 .global_lsp_settings
6707 .get_request_timeout();
6708
6709 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6710 let completion = &completions.borrow()[completion_index];
6711 let server_id = completion.source.server_id()?;
6712 Some(
6713 self.language_server_for_local_buffer(buffer, server_id, cx)?
6714 .1
6715 .clone(),
6716 )
6717 }) else {
6718 return Task::ready(Ok(None));
6719 };
6720
6721 cx.spawn(async move |this, cx| {
6722 Self::resolve_completion_local(
6723 server.clone(),
6724 completions.clone(),
6725 completion_index,
6726 request_timeout,
6727 )
6728 .await
6729 .context("resolving completion")?;
6730 let completion = completions.borrow()[completion_index].clone();
6731 let additional_text_edits = completion
6732 .source
6733 .lsp_completion(true)
6734 .as_ref()
6735 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6736 if let Some(edits) = additional_text_edits {
6737 let edits = this
6738 .update(cx, |this, cx| {
6739 this.as_local_mut().unwrap().edits_from_lsp(
6740 &buffer_handle,
6741 edits,
6742 server.server_id(),
6743 None,
6744 cx,
6745 )
6746 })?
6747 .await?;
6748
6749 buffer_handle.update(cx, |buffer, cx| {
6750 buffer.finalize_last_transaction();
6751 buffer.start_transaction();
6752
6753 for (range, text) in edits {
6754 let primary = &completion.replace_range;
6755
6756 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6757 // and the primary completion is just an insertion (empty range), then this is likely
6758 // an auto-import scenario and should not be considered overlapping
6759 // https://github.com/zed-industries/zed/issues/26136
6760 let is_file_start_auto_import = {
6761 let snapshot = buffer.snapshot();
6762 let primary_start_point = primary.start.to_point(&snapshot);
6763 let range_start_point = range.start.to_point(&snapshot);
6764
6765 let result = primary_start_point.row == 0
6766 && primary_start_point.column == 0
6767 && range_start_point.row == 0
6768 && range_start_point.column == 0;
6769
6770 result
6771 };
6772
6773 let has_overlap = if is_file_start_auto_import {
6774 false
6775 } else {
6776 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6777 && primary.end.cmp(&range.start, buffer).is_ge();
6778 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6779 && range.end.cmp(&primary.end, buffer).is_ge();
6780 let result = start_within || end_within;
6781 result
6782 };
6783
6784 //Skip additional edits which overlap with the primary completion edit
6785 //https://github.com/zed-industries/zed/pull/1871
6786 if !has_overlap {
6787 buffer.edit([(range, text)], None, cx);
6788 }
6789 }
6790
6791 let transaction = if buffer.end_transaction(cx).is_some() {
6792 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6793 if !push_to_history {
6794 buffer.forget_transaction(transaction.id);
6795 }
6796 Some(transaction)
6797 } else {
6798 None
6799 };
6800 Ok(transaction)
6801 })
6802 } else {
6803 Ok(None)
6804 }
6805 })
6806 }
6807 }
6808
6809 pub fn pull_diagnostics(
6810 &mut self,
6811 buffer: Entity<Buffer>,
6812 cx: &mut Context<Self>,
6813 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6814 let buffer_id = buffer.read(cx).remote_id();
6815
6816 if let Some((client, upstream_project_id)) = self.upstream_client() {
6817 let mut suitable_capabilities = None;
6818 // Are we capable for proto request?
6819 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6820 &buffer,
6821 |capabilities| {
6822 if let Some(caps) = &capabilities.diagnostic_provider {
6823 suitable_capabilities = Some(caps.clone());
6824 true
6825 } else {
6826 false
6827 }
6828 },
6829 cx,
6830 );
6831 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6832 let Some(dynamic_caps) = suitable_capabilities else {
6833 return Task::ready(Ok(None));
6834 };
6835 assert!(any_server_has_diagnostics_provider);
6836
6837 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6838 let request = GetDocumentDiagnostics {
6839 previous_result_id: None,
6840 identifier,
6841 registration_id: None,
6842 };
6843 let request_timeout = ProjectSettings::get_global(cx)
6844 .global_lsp_settings
6845 .get_request_timeout();
6846 let request_task = client.request_lsp(
6847 upstream_project_id,
6848 None,
6849 request_timeout,
6850 cx.background_executor().clone(),
6851 request.to_proto(upstream_project_id, buffer.read(cx)),
6852 );
6853 cx.background_spawn(async move {
6854 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6855 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6856 // Do not attempt to further process the dummy responses here.
6857 let _response = request_task.await?;
6858 Ok(None)
6859 })
6860 } else {
6861 let servers = buffer.update(cx, |buffer, cx| {
6862 self.running_language_servers_for_local_buffer(buffer, cx)
6863 .map(|(_, server)| server.clone())
6864 .collect::<Vec<_>>()
6865 });
6866
6867 let pull_diagnostics = servers
6868 .into_iter()
6869 .flat_map(|server| {
6870 let result = maybe!({
6871 let local = self.as_local()?;
6872 let server_id = server.server_id();
6873 let providers_with_identifiers = local
6874 .language_server_dynamic_registrations
6875 .get(&server_id)
6876 .into_iter()
6877 .flat_map(|registrations| registrations.diagnostics.clone())
6878 .collect::<Vec<_>>();
6879 Some(
6880 providers_with_identifiers
6881 .into_iter()
6882 .map(|(registration_id, dynamic_caps)| {
6883 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6884 let registration_id = registration_id.map(SharedString::from);
6885 let result_id = self.result_id_for_buffer_pull(
6886 server_id,
6887 buffer_id,
6888 ®istration_id,
6889 cx,
6890 );
6891 self.request_lsp(
6892 buffer.clone(),
6893 LanguageServerToQuery::Other(server_id),
6894 GetDocumentDiagnostics {
6895 previous_result_id: result_id,
6896 registration_id,
6897 identifier,
6898 },
6899 cx,
6900 )
6901 })
6902 .collect::<Vec<_>>(),
6903 )
6904 });
6905
6906 result.unwrap_or_default()
6907 })
6908 .collect::<Vec<_>>();
6909
6910 cx.background_spawn(async move {
6911 let mut responses = Vec::new();
6912 for diagnostics in join_all(pull_diagnostics).await {
6913 responses.extend(diagnostics?);
6914 }
6915 Ok(Some(responses))
6916 })
6917 }
6918 }
6919
6920 pub fn applicable_inlay_chunks(
6921 &mut self,
6922 buffer: &Entity<Buffer>,
6923 ranges: &[Range<text::Anchor>],
6924 cx: &mut Context<Self>,
6925 ) -> Vec<Range<BufferRow>> {
6926 let buffer_snapshot = buffer.read(cx).snapshot();
6927 let ranges = ranges
6928 .iter()
6929 .map(|range| range.to_point(&buffer_snapshot))
6930 .collect::<Vec<_>>();
6931
6932 self.latest_lsp_data(buffer, cx)
6933 .inlay_hints
6934 .applicable_chunks(ranges.as_slice())
6935 .map(|chunk| chunk.row_range())
6936 .collect()
6937 }
6938
6939 pub fn invalidate_inlay_hints<'a>(
6940 &'a mut self,
6941 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6942 ) {
6943 for buffer_id in for_buffers {
6944 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6945 lsp_data.inlay_hints.clear();
6946 }
6947 }
6948 }
6949
6950 pub fn inlay_hints(
6951 &mut self,
6952 invalidate: InvalidationStrategy,
6953 buffer: Entity<Buffer>,
6954 ranges: Vec<Range<text::Anchor>>,
6955 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6956 cx: &mut Context<Self>,
6957 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6958 let next_hint_id = self.next_hint_id.clone();
6959 let lsp_data = self.latest_lsp_data(&buffer, cx);
6960 let query_version = lsp_data.buffer_version.clone();
6961 let mut lsp_refresh_requested = false;
6962 let for_server = if let InvalidationStrategy::RefreshRequested {
6963 server_id,
6964 request_id,
6965 } = invalidate
6966 {
6967 let invalidated = lsp_data
6968 .inlay_hints
6969 .invalidate_for_server_refresh(server_id, request_id);
6970 lsp_refresh_requested = invalidated;
6971 Some(server_id)
6972 } else {
6973 None
6974 };
6975 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6976 let known_chunks = known_chunks
6977 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6978 .map(|(_, known_chunks)| known_chunks)
6979 .unwrap_or_default();
6980
6981 let buffer_snapshot = buffer.read(cx).snapshot();
6982 let ranges = ranges
6983 .iter()
6984 .map(|range| range.to_point(&buffer_snapshot))
6985 .collect::<Vec<_>>();
6986
6987 let mut hint_fetch_tasks = Vec::new();
6988 let mut cached_inlay_hints = None;
6989 let mut ranges_to_query = None;
6990 let applicable_chunks = existing_inlay_hints
6991 .applicable_chunks(ranges.as_slice())
6992 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6993 .collect::<Vec<_>>();
6994 if applicable_chunks.is_empty() {
6995 return HashMap::default();
6996 }
6997
6998 for row_chunk in applicable_chunks {
6999 match (
7000 existing_inlay_hints
7001 .cached_hints(&row_chunk)
7002 .filter(|_| !lsp_refresh_requested)
7003 .cloned(),
7004 existing_inlay_hints
7005 .fetched_hints(&row_chunk)
7006 .as_ref()
7007 .filter(|_| !lsp_refresh_requested)
7008 .cloned(),
7009 ) {
7010 (None, None) => {
7011 let chunk_range = row_chunk.anchor_range();
7012 ranges_to_query
7013 .get_or_insert_with(Vec::new)
7014 .push((row_chunk, chunk_range));
7015 }
7016 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7017 (Some(cached_hints), None) => {
7018 for (server_id, cached_hints) in cached_hints {
7019 if for_server.is_none_or(|for_server| for_server == server_id) {
7020 cached_inlay_hints
7021 .get_or_insert_with(HashMap::default)
7022 .entry(row_chunk.row_range())
7023 .or_insert_with(HashMap::default)
7024 .entry(server_id)
7025 .or_insert_with(Vec::new)
7026 .extend(cached_hints);
7027 }
7028 }
7029 }
7030 (Some(cached_hints), Some(fetched_hints)) => {
7031 hint_fetch_tasks.push((row_chunk, fetched_hints));
7032 for (server_id, cached_hints) in cached_hints {
7033 if for_server.is_none_or(|for_server| for_server == server_id) {
7034 cached_inlay_hints
7035 .get_or_insert_with(HashMap::default)
7036 .entry(row_chunk.row_range())
7037 .or_insert_with(HashMap::default)
7038 .entry(server_id)
7039 .or_insert_with(Vec::new)
7040 .extend(cached_hints);
7041 }
7042 }
7043 }
7044 }
7045 }
7046
7047 if hint_fetch_tasks.is_empty()
7048 && ranges_to_query
7049 .as_ref()
7050 .is_none_or(|ranges| ranges.is_empty())
7051 && let Some(cached_inlay_hints) = cached_inlay_hints
7052 {
7053 cached_inlay_hints
7054 .into_iter()
7055 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7056 .collect()
7057 } else {
7058 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7059 let next_hint_id = next_hint_id.clone();
7060 let buffer = buffer.clone();
7061 let query_version = query_version.clone();
7062 let new_inlay_hints = cx
7063 .spawn(async move |lsp_store, cx| {
7064 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7065 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7066 })?;
7067 new_fetch_task
7068 .await
7069 .and_then(|new_hints_by_server| {
7070 lsp_store.update(cx, |lsp_store, cx| {
7071 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7072 let update_cache = lsp_data.buffer_version == query_version;
7073 if new_hints_by_server.is_empty() {
7074 if update_cache {
7075 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7076 }
7077 HashMap::default()
7078 } else {
7079 new_hints_by_server
7080 .into_iter()
7081 .map(|(server_id, new_hints)| {
7082 let new_hints = new_hints
7083 .into_iter()
7084 .map(|new_hint| {
7085 (
7086 InlayId::Hint(next_hint_id.fetch_add(
7087 1,
7088 atomic::Ordering::AcqRel,
7089 )),
7090 new_hint,
7091 )
7092 })
7093 .collect::<Vec<_>>();
7094 if update_cache {
7095 lsp_data.inlay_hints.insert_new_hints(
7096 chunk,
7097 server_id,
7098 new_hints.clone(),
7099 );
7100 }
7101 (server_id, new_hints)
7102 })
7103 .collect()
7104 }
7105 })
7106 })
7107 .map_err(Arc::new)
7108 })
7109 .shared();
7110
7111 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7112 *fetch_task = Some(new_inlay_hints.clone());
7113 hint_fetch_tasks.push((chunk, new_inlay_hints));
7114 }
7115
7116 cached_inlay_hints
7117 .unwrap_or_default()
7118 .into_iter()
7119 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7120 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7121 (
7122 chunk.row_range(),
7123 cx.spawn(async move |_, _| {
7124 hints_fetch.await.map_err(|e| {
7125 if e.error_code() != ErrorCode::Internal {
7126 anyhow!(e.error_code())
7127 } else {
7128 anyhow!("{e:#}")
7129 }
7130 })
7131 }),
7132 )
7133 }))
7134 .collect()
7135 }
7136 }
7137
7138 fn fetch_inlay_hints(
7139 &mut self,
7140 for_server: Option<LanguageServerId>,
7141 buffer: &Entity<Buffer>,
7142 range: Range<Anchor>,
7143 cx: &mut Context<Self>,
7144 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7145 let request = InlayHints {
7146 range: range.clone(),
7147 };
7148 if let Some((upstream_client, project_id)) = self.upstream_client() {
7149 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7150 return Task::ready(Ok(HashMap::default()));
7151 }
7152 let request_timeout = ProjectSettings::get_global(cx)
7153 .global_lsp_settings
7154 .get_request_timeout();
7155 let request_task = upstream_client.request_lsp(
7156 project_id,
7157 for_server.map(|id| id.to_proto()),
7158 request_timeout,
7159 cx.background_executor().clone(),
7160 request.to_proto(project_id, buffer.read(cx)),
7161 );
7162 let buffer = buffer.clone();
7163 cx.spawn(async move |weak_lsp_store, cx| {
7164 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7165 return Ok(HashMap::default());
7166 };
7167 let Some(responses) = request_task.await? else {
7168 return Ok(HashMap::default());
7169 };
7170
7171 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7172 let lsp_store = lsp_store.clone();
7173 let buffer = buffer.clone();
7174 let cx = cx.clone();
7175 let request = request.clone();
7176 async move {
7177 (
7178 LanguageServerId::from_proto(response.server_id),
7179 request
7180 .response_from_proto(response.response, lsp_store, buffer, cx)
7181 .await,
7182 )
7183 }
7184 }))
7185 .await;
7186
7187 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7188 let mut has_errors = false;
7189 let inlay_hints = inlay_hints
7190 .into_iter()
7191 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7192 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7193 Err(e) => {
7194 has_errors = true;
7195 log::error!("{e:#}");
7196 None
7197 }
7198 })
7199 .map(|(server_id, mut new_hints)| {
7200 new_hints.retain(|hint| {
7201 hint.position.is_valid(&buffer_snapshot)
7202 && range.start.is_valid(&buffer_snapshot)
7203 && range.end.is_valid(&buffer_snapshot)
7204 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7205 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7206 });
7207 (server_id, new_hints)
7208 })
7209 .collect::<HashMap<_, _>>();
7210 anyhow::ensure!(
7211 !has_errors || !inlay_hints.is_empty(),
7212 "Failed to fetch inlay hints"
7213 );
7214 Ok(inlay_hints)
7215 })
7216 } else {
7217 let inlay_hints_task = match for_server {
7218 Some(server_id) => {
7219 let server_task = self.request_lsp(
7220 buffer.clone(),
7221 LanguageServerToQuery::Other(server_id),
7222 request,
7223 cx,
7224 );
7225 cx.background_spawn(async move {
7226 let mut responses = Vec::new();
7227 match server_task.await {
7228 Ok(response) => responses.push((server_id, response)),
7229 // rust-analyzer likes to error with this when its still loading up
7230 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7231 Err(e) => log::error!(
7232 "Error handling response for inlay hints request: {e:#}"
7233 ),
7234 }
7235 responses
7236 })
7237 }
7238 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7239 };
7240 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7241 cx.background_spawn(async move {
7242 Ok(inlay_hints_task
7243 .await
7244 .into_iter()
7245 .map(|(server_id, mut new_hints)| {
7246 new_hints.retain(|hint| {
7247 hint.position.is_valid(&buffer_snapshot)
7248 && range.start.is_valid(&buffer_snapshot)
7249 && range.end.is_valid(&buffer_snapshot)
7250 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7251 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7252 });
7253 (server_id, new_hints)
7254 })
7255 .collect())
7256 })
7257 }
7258 }
7259
7260 fn diagnostic_registration_exists(
7261 &self,
7262 server_id: LanguageServerId,
7263 registration_id: &Option<SharedString>,
7264 ) -> bool {
7265 let Some(local) = self.as_local() else {
7266 return false;
7267 };
7268 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7269 else {
7270 return false;
7271 };
7272 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7273 registrations.diagnostics.contains_key(®istration_key)
7274 }
7275
7276 pub fn pull_diagnostics_for_buffer(
7277 &mut self,
7278 buffer: Entity<Buffer>,
7279 cx: &mut Context<Self>,
7280 ) -> Task<anyhow::Result<()>> {
7281 let diagnostics = self.pull_diagnostics(buffer, cx);
7282 cx.spawn(async move |lsp_store, cx| {
7283 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7284 return Ok(());
7285 };
7286 lsp_store.update(cx, |lsp_store, cx| {
7287 if lsp_store.as_local().is_none() {
7288 return;
7289 }
7290
7291 let mut unchanged_buffers = HashMap::default();
7292 let server_diagnostics_updates = diagnostics
7293 .into_iter()
7294 .filter_map(|diagnostics_set| match diagnostics_set {
7295 LspPullDiagnostics::Response {
7296 server_id,
7297 uri,
7298 diagnostics,
7299 registration_id,
7300 } => Some((server_id, uri, diagnostics, registration_id)),
7301 LspPullDiagnostics::Default => None,
7302 })
7303 .filter(|(server_id, _, _, registration_id)| {
7304 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7305 })
7306 .fold(
7307 HashMap::default(),
7308 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7309 let (result_id, diagnostics) = match diagnostics {
7310 PulledDiagnostics::Unchanged { result_id } => {
7311 unchanged_buffers
7312 .entry(new_registration_id.clone())
7313 .or_insert_with(HashSet::default)
7314 .insert(uri.clone());
7315 (Some(result_id), Vec::new())
7316 }
7317 PulledDiagnostics::Changed {
7318 result_id,
7319 diagnostics,
7320 } => (result_id, diagnostics),
7321 };
7322 let disk_based_sources = Cow::Owned(
7323 lsp_store
7324 .language_server_adapter_for_id(server_id)
7325 .as_ref()
7326 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7327 .unwrap_or(&[])
7328 .to_vec(),
7329 );
7330 acc.entry(server_id)
7331 .or_insert_with(HashMap::default)
7332 .entry(new_registration_id.clone())
7333 .or_insert_with(Vec::new)
7334 .push(DocumentDiagnosticsUpdate {
7335 server_id,
7336 diagnostics: lsp::PublishDiagnosticsParams {
7337 uri,
7338 diagnostics,
7339 version: None,
7340 },
7341 result_id: result_id.map(SharedString::new),
7342 disk_based_sources,
7343 registration_id: new_registration_id,
7344 });
7345 acc
7346 },
7347 );
7348
7349 for diagnostic_updates in server_diagnostics_updates.into_values() {
7350 for (registration_id, diagnostic_updates) in diagnostic_updates {
7351 lsp_store
7352 .merge_lsp_diagnostics(
7353 DiagnosticSourceKind::Pulled,
7354 diagnostic_updates,
7355 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7356 DiagnosticSourceKind::Pulled => {
7357 old_diagnostic.registration_id != registration_id
7358 || unchanged_buffers
7359 .get(&old_diagnostic.registration_id)
7360 .is_some_and(|unchanged_buffers| {
7361 unchanged_buffers.contains(&document_uri)
7362 })
7363 }
7364 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7365 true
7366 }
7367 },
7368 cx,
7369 )
7370 .log_err();
7371 }
7372 }
7373 })
7374 })
7375 }
7376
7377 pub fn signature_help<T: ToPointUtf16>(
7378 &mut self,
7379 buffer: &Entity<Buffer>,
7380 position: T,
7381 cx: &mut Context<Self>,
7382 ) -> Task<Option<Vec<SignatureHelp>>> {
7383 let position = position.to_point_utf16(buffer.read(cx));
7384
7385 if let Some((client, upstream_project_id)) = self.upstream_client() {
7386 let request = GetSignatureHelp { position };
7387 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7388 return Task::ready(None);
7389 }
7390 let request_timeout = ProjectSettings::get_global(cx)
7391 .global_lsp_settings
7392 .get_request_timeout();
7393 let request_task = client.request_lsp(
7394 upstream_project_id,
7395 None,
7396 request_timeout,
7397 cx.background_executor().clone(),
7398 request.to_proto(upstream_project_id, buffer.read(cx)),
7399 );
7400 let buffer = buffer.clone();
7401 cx.spawn(async move |weak_lsp_store, cx| {
7402 let lsp_store = weak_lsp_store.upgrade()?;
7403 let signatures = join_all(
7404 request_task
7405 .await
7406 .log_err()
7407 .flatten()
7408 .map(|response| response.payload)
7409 .unwrap_or_default()
7410 .into_iter()
7411 .map(|response| {
7412 let response = GetSignatureHelp { position }.response_from_proto(
7413 response.response,
7414 lsp_store.clone(),
7415 buffer.clone(),
7416 cx.clone(),
7417 );
7418 async move { response.await.log_err().flatten() }
7419 }),
7420 )
7421 .await
7422 .into_iter()
7423 .flatten()
7424 .collect();
7425 Some(signatures)
7426 })
7427 } else {
7428 let all_actions_task = self.request_multiple_lsp_locally(
7429 buffer,
7430 Some(position),
7431 GetSignatureHelp { position },
7432 cx,
7433 );
7434 cx.background_spawn(async move {
7435 Some(
7436 all_actions_task
7437 .await
7438 .into_iter()
7439 .flat_map(|(_, actions)| actions)
7440 .collect::<Vec<_>>(),
7441 )
7442 })
7443 }
7444 }
7445
7446 pub fn hover(
7447 &mut self,
7448 buffer: &Entity<Buffer>,
7449 position: PointUtf16,
7450 cx: &mut Context<Self>,
7451 ) -> Task<Option<Vec<Hover>>> {
7452 if let Some((client, upstream_project_id)) = self.upstream_client() {
7453 let request = GetHover { position };
7454 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7455 return Task::ready(None);
7456 }
7457 let request_timeout = ProjectSettings::get_global(cx)
7458 .global_lsp_settings
7459 .get_request_timeout();
7460 let request_task = client.request_lsp(
7461 upstream_project_id,
7462 None,
7463 request_timeout,
7464 cx.background_executor().clone(),
7465 request.to_proto(upstream_project_id, buffer.read(cx)),
7466 );
7467 let buffer = buffer.clone();
7468 cx.spawn(async move |weak_lsp_store, cx| {
7469 let lsp_store = weak_lsp_store.upgrade()?;
7470 let hovers = join_all(
7471 request_task
7472 .await
7473 .log_err()
7474 .flatten()
7475 .map(|response| response.payload)
7476 .unwrap_or_default()
7477 .into_iter()
7478 .map(|response| {
7479 let response = GetHover { position }.response_from_proto(
7480 response.response,
7481 lsp_store.clone(),
7482 buffer.clone(),
7483 cx.clone(),
7484 );
7485 async move {
7486 response
7487 .await
7488 .log_err()
7489 .flatten()
7490 .and_then(remove_empty_hover_blocks)
7491 }
7492 }),
7493 )
7494 .await
7495 .into_iter()
7496 .flatten()
7497 .collect();
7498 Some(hovers)
7499 })
7500 } else {
7501 let all_actions_task = self.request_multiple_lsp_locally(
7502 buffer,
7503 Some(position),
7504 GetHover { position },
7505 cx,
7506 );
7507 cx.background_spawn(async move {
7508 Some(
7509 all_actions_task
7510 .await
7511 .into_iter()
7512 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7513 .collect::<Vec<Hover>>(),
7514 )
7515 })
7516 }
7517 }
7518
7519 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7520 let language_registry = self.languages.clone();
7521
7522 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7523 let request = upstream_client.request(proto::GetProjectSymbols {
7524 project_id: *project_id,
7525 query: query.to_string(),
7526 });
7527 cx.foreground_executor().spawn(async move {
7528 let response = request.await?;
7529 let mut symbols = Vec::new();
7530 let core_symbols = response
7531 .symbols
7532 .into_iter()
7533 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7534 .collect::<Vec<_>>();
7535 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7536 .await;
7537 Ok(symbols)
7538 })
7539 } else if let Some(local) = self.as_local() {
7540 struct WorkspaceSymbolsResult {
7541 server_id: LanguageServerId,
7542 lsp_adapter: Arc<CachedLspAdapter>,
7543 worktree: WeakEntity<Worktree>,
7544 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7545 }
7546
7547 let mut requests = Vec::new();
7548 let mut requested_servers = BTreeSet::new();
7549 let request_timeout = ProjectSettings::get_global(cx)
7550 .global_lsp_settings
7551 .get_request_timeout();
7552
7553 for (seed, state) in local.language_server_ids.iter() {
7554 let Some(worktree_handle) = self
7555 .worktree_store
7556 .read(cx)
7557 .worktree_for_id(seed.worktree_id, cx)
7558 else {
7559 continue;
7560 };
7561
7562 let worktree = worktree_handle.read(cx);
7563 if !worktree.is_visible() {
7564 continue;
7565 }
7566
7567 if !requested_servers.insert(state.id) {
7568 continue;
7569 }
7570
7571 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7572 Some(LanguageServerState::Running {
7573 adapter, server, ..
7574 }) => (adapter.clone(), server),
7575
7576 _ => continue,
7577 };
7578
7579 let supports_workspace_symbol_request =
7580 match server.capabilities().workspace_symbol_provider {
7581 Some(OneOf::Left(supported)) => supported,
7582 Some(OneOf::Right(_)) => true,
7583 None => false,
7584 };
7585
7586 if !supports_workspace_symbol_request {
7587 continue;
7588 }
7589
7590 let worktree_handle = worktree_handle.clone();
7591 let server_id = server.server_id();
7592 requests.push(
7593 server
7594 .request::<lsp::request::WorkspaceSymbolRequest>(
7595 lsp::WorkspaceSymbolParams {
7596 query: query.to_string(),
7597 ..Default::default()
7598 },
7599 request_timeout,
7600 )
7601 .map(move |response| {
7602 let lsp_symbols = response
7603 .into_response()
7604 .context("workspace symbols request")
7605 .log_err()
7606 .flatten()
7607 .map(|symbol_response| match symbol_response {
7608 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7609 flat_responses
7610 .into_iter()
7611 .map(|lsp_symbol| {
7612 (
7613 lsp_symbol.name,
7614 lsp_symbol.kind,
7615 lsp_symbol.location,
7616 lsp_symbol.container_name,
7617 )
7618 })
7619 .collect::<Vec<_>>()
7620 }
7621 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7622 nested_responses
7623 .into_iter()
7624 .filter_map(|lsp_symbol| {
7625 let location = match lsp_symbol.location {
7626 OneOf::Left(location) => location,
7627 OneOf::Right(_) => {
7628 log::error!(
7629 "Unexpected: client capabilities \
7630 forbid symbol resolutions in \
7631 workspace.symbol.resolveSupport"
7632 );
7633 return None;
7634 }
7635 };
7636 Some((
7637 lsp_symbol.name,
7638 lsp_symbol.kind,
7639 location,
7640 lsp_symbol.container_name,
7641 ))
7642 })
7643 .collect::<Vec<_>>()
7644 }
7645 })
7646 .unwrap_or_default();
7647
7648 WorkspaceSymbolsResult {
7649 server_id,
7650 lsp_adapter,
7651 worktree: worktree_handle.downgrade(),
7652 lsp_symbols,
7653 }
7654 }),
7655 );
7656 }
7657
7658 cx.spawn(async move |this, cx| {
7659 let responses = futures::future::join_all(requests).await;
7660 let this = match this.upgrade() {
7661 Some(this) => this,
7662 None => return Ok(Vec::new()),
7663 };
7664
7665 let mut symbols = Vec::new();
7666 for result in responses {
7667 let core_symbols = this.update(cx, |this, cx| {
7668 result
7669 .lsp_symbols
7670 .into_iter()
7671 .filter_map(
7672 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7673 let abs_path = symbol_location.uri.to_file_path().ok()?;
7674 let source_worktree = result.worktree.upgrade()?;
7675 let source_worktree_id = source_worktree.read(cx).id();
7676
7677 let path = if let Some((tree, rel_path)) =
7678 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7679 {
7680 let worktree_id = tree.read(cx).id();
7681 SymbolLocation::InProject(ProjectPath {
7682 worktree_id,
7683 path: rel_path,
7684 })
7685 } else {
7686 SymbolLocation::OutsideProject {
7687 signature: this.symbol_signature(&abs_path),
7688 abs_path: abs_path.into(),
7689 }
7690 };
7691
7692 Some(CoreSymbol {
7693 source_language_server_id: result.server_id,
7694 language_server_name: result.lsp_adapter.name.clone(),
7695 source_worktree_id,
7696 path,
7697 kind: symbol_kind,
7698 name: collapse_newlines(&symbol_name, "↵ "),
7699 range: range_from_lsp(symbol_location.range),
7700 container_name: container_name
7701 .map(|c| collapse_newlines(&c, "↵ ")),
7702 })
7703 },
7704 )
7705 .collect::<Vec<_>>()
7706 });
7707
7708 populate_labels_for_symbols(
7709 core_symbols,
7710 &language_registry,
7711 Some(result.lsp_adapter),
7712 &mut symbols,
7713 )
7714 .await;
7715 }
7716
7717 Ok(symbols)
7718 })
7719 } else {
7720 Task::ready(Err(anyhow!("No upstream client or local language server")))
7721 }
7722 }
7723
7724 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7725 let mut summary = DiagnosticSummary::default();
7726 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7727 summary.error_count += path_summary.error_count;
7728 summary.warning_count += path_summary.warning_count;
7729 }
7730 summary
7731 }
7732
7733 /// Returns the diagnostic summary for a specific project path.
7734 pub fn diagnostic_summary_for_path(
7735 &self,
7736 project_path: &ProjectPath,
7737 _: &App,
7738 ) -> DiagnosticSummary {
7739 if let Some(summaries) = self
7740 .diagnostic_summaries
7741 .get(&project_path.worktree_id)
7742 .and_then(|map| map.get(&project_path.path))
7743 {
7744 let (error_count, warning_count) = summaries.iter().fold(
7745 (0, 0),
7746 |(error_count, warning_count), (_language_server_id, summary)| {
7747 (
7748 error_count + summary.error_count,
7749 warning_count + summary.warning_count,
7750 )
7751 },
7752 );
7753
7754 DiagnosticSummary {
7755 error_count,
7756 warning_count,
7757 }
7758 } else {
7759 DiagnosticSummary::default()
7760 }
7761 }
7762
7763 pub fn diagnostic_summaries<'a>(
7764 &'a self,
7765 include_ignored: bool,
7766 cx: &'a App,
7767 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7768 self.worktree_store
7769 .read(cx)
7770 .visible_worktrees(cx)
7771 .filter_map(|worktree| {
7772 let worktree = worktree.read(cx);
7773 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7774 })
7775 .flat_map(move |(worktree, summaries)| {
7776 let worktree_id = worktree.id();
7777 summaries
7778 .iter()
7779 .filter(move |(path, _)| {
7780 include_ignored
7781 || worktree
7782 .entry_for_path(path.as_ref())
7783 .is_some_and(|entry| !entry.is_ignored)
7784 })
7785 .flat_map(move |(path, summaries)| {
7786 summaries.iter().map(move |(server_id, summary)| {
7787 (
7788 ProjectPath {
7789 worktree_id,
7790 path: path.clone(),
7791 },
7792 *server_id,
7793 *summary,
7794 )
7795 })
7796 })
7797 })
7798 }
7799
7800 pub fn on_buffer_edited(
7801 &mut self,
7802 buffer: Entity<Buffer>,
7803 cx: &mut Context<Self>,
7804 ) -> Option<()> {
7805 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7806 Some(
7807 self.as_local()?
7808 .language_servers_for_buffer(buffer, cx)
7809 .map(|i| i.1.clone())
7810 .collect(),
7811 )
7812 })?;
7813
7814 let buffer = buffer.read(cx);
7815 let file = File::from_dyn(buffer.file())?;
7816 let abs_path = file.as_local()?.abs_path(cx);
7817 let uri = lsp::Uri::from_file_path(&abs_path)
7818 .ok()
7819 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7820 .log_err()?;
7821 let next_snapshot = buffer.text_snapshot();
7822 for language_server in language_servers {
7823 let language_server = language_server.clone();
7824
7825 let buffer_snapshots = self
7826 .as_local_mut()?
7827 .buffer_snapshots
7828 .get_mut(&buffer.remote_id())
7829 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7830 let previous_snapshot = buffer_snapshots.last()?;
7831
7832 let build_incremental_change = || {
7833 buffer
7834 .edits_since::<Dimensions<PointUtf16, usize>>(
7835 previous_snapshot.snapshot.version(),
7836 )
7837 .map(|edit| {
7838 let edit_start = edit.new.start.0;
7839 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7840 let new_text = next_snapshot
7841 .text_for_range(edit.new.start.1..edit.new.end.1)
7842 .collect();
7843 lsp::TextDocumentContentChangeEvent {
7844 range: Some(lsp::Range::new(
7845 point_to_lsp(edit_start),
7846 point_to_lsp(edit_end),
7847 )),
7848 range_length: None,
7849 text: new_text,
7850 }
7851 })
7852 .collect()
7853 };
7854
7855 let document_sync_kind = language_server
7856 .capabilities()
7857 .text_document_sync
7858 .as_ref()
7859 .and_then(|sync| match sync {
7860 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7861 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7862 });
7863
7864 let content_changes: Vec<_> = match document_sync_kind {
7865 Some(lsp::TextDocumentSyncKind::FULL) => {
7866 vec![lsp::TextDocumentContentChangeEvent {
7867 range: None,
7868 range_length: None,
7869 text: next_snapshot.text(),
7870 }]
7871 }
7872 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7873 _ => {
7874 #[cfg(any(test, feature = "test-support"))]
7875 {
7876 build_incremental_change()
7877 }
7878
7879 #[cfg(not(any(test, feature = "test-support")))]
7880 {
7881 continue;
7882 }
7883 }
7884 };
7885
7886 let next_version = previous_snapshot.version + 1;
7887 buffer_snapshots.push(LspBufferSnapshot {
7888 version: next_version,
7889 snapshot: next_snapshot.clone(),
7890 });
7891
7892 language_server
7893 .notify::<lsp::notification::DidChangeTextDocument>(
7894 lsp::DidChangeTextDocumentParams {
7895 text_document: lsp::VersionedTextDocumentIdentifier::new(
7896 uri.clone(),
7897 next_version,
7898 ),
7899 content_changes,
7900 },
7901 )
7902 .ok();
7903 self.pull_workspace_diagnostics(language_server.server_id());
7904 }
7905
7906 None
7907 }
7908
7909 pub fn on_buffer_saved(
7910 &mut self,
7911 buffer: Entity<Buffer>,
7912 cx: &mut Context<Self>,
7913 ) -> Option<()> {
7914 let file = File::from_dyn(buffer.read(cx).file())?;
7915 let worktree_id = file.worktree_id(cx);
7916 let abs_path = file.as_local()?.abs_path(cx);
7917 let text_document = lsp::TextDocumentIdentifier {
7918 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7919 };
7920 let local = self.as_local()?;
7921
7922 for server in local.language_servers_for_worktree(worktree_id) {
7923 if let Some(include_text) = include_text(server.as_ref()) {
7924 let text = if include_text {
7925 Some(buffer.read(cx).text())
7926 } else {
7927 None
7928 };
7929 server
7930 .notify::<lsp::notification::DidSaveTextDocument>(
7931 lsp::DidSaveTextDocumentParams {
7932 text_document: text_document.clone(),
7933 text,
7934 },
7935 )
7936 .ok();
7937 }
7938 }
7939
7940 let language_servers = buffer.update(cx, |buffer, cx| {
7941 local.language_server_ids_for_buffer(buffer, cx)
7942 });
7943 for language_server_id in language_servers {
7944 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7945 }
7946
7947 None
7948 }
7949
7950 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7951 maybe!(async move {
7952 let mut refreshed_servers = HashSet::default();
7953 let servers = lsp_store
7954 .update(cx, |lsp_store, cx| {
7955 let local = lsp_store.as_local()?;
7956
7957 let servers = local
7958 .language_server_ids
7959 .iter()
7960 .filter_map(|(seed, state)| {
7961 let worktree = lsp_store
7962 .worktree_store
7963 .read(cx)
7964 .worktree_for_id(seed.worktree_id, cx);
7965 let delegate: Arc<dyn LspAdapterDelegate> =
7966 worktree.map(|worktree| {
7967 LocalLspAdapterDelegate::new(
7968 local.languages.clone(),
7969 &local.environment,
7970 cx.weak_entity(),
7971 &worktree,
7972 local.http_client.clone(),
7973 local.fs.clone(),
7974 cx,
7975 )
7976 })?;
7977 let server_id = state.id;
7978
7979 let states = local.language_servers.get(&server_id)?;
7980
7981 match states {
7982 LanguageServerState::Starting { .. } => None,
7983 LanguageServerState::Running {
7984 adapter, server, ..
7985 } => {
7986 let adapter = adapter.clone();
7987 let server = server.clone();
7988 refreshed_servers.insert(server.name());
7989 let toolchain = seed.toolchain.clone();
7990 Some(cx.spawn(async move |_, cx| {
7991 let settings =
7992 LocalLspStore::workspace_configuration_for_adapter(
7993 adapter.adapter.clone(),
7994 &delegate,
7995 toolchain,
7996 None,
7997 cx,
7998 )
7999 .await
8000 .ok()?;
8001 server
8002 .notify::<lsp::notification::DidChangeConfiguration>(
8003 lsp::DidChangeConfigurationParams { settings },
8004 )
8005 .ok()?;
8006 Some(())
8007 }))
8008 }
8009 }
8010 })
8011 .collect::<Vec<_>>();
8012
8013 Some(servers)
8014 })
8015 .ok()
8016 .flatten()?;
8017
8018 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8019 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8020 // to stop and unregister its language server wrapper.
8021 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8022 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8023 let _: Vec<Option<()>> = join_all(servers).await;
8024
8025 Some(())
8026 })
8027 .await;
8028 }
8029
8030 fn maintain_workspace_config(
8031 external_refresh_requests: watch::Receiver<()>,
8032 cx: &mut Context<Self>,
8033 ) -> Task<Result<()>> {
8034 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8035 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8036
8037 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8038 *settings_changed_tx.borrow_mut() = ();
8039 });
8040
8041 let mut joint_future =
8042 futures::stream::select(settings_changed_rx, external_refresh_requests);
8043 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8044 // - 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).
8045 // - 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.
8046 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8047 // - 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,
8048 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8049 cx.spawn(async move |this, cx| {
8050 while let Some(()) = joint_future.next().await {
8051 this.update(cx, |this, cx| {
8052 this.refresh_server_tree(cx);
8053 })
8054 .ok();
8055
8056 Self::refresh_workspace_configurations(&this, cx).await;
8057 }
8058
8059 drop(settings_observation);
8060 anyhow::Ok(())
8061 })
8062 }
8063
8064 pub fn running_language_servers_for_local_buffer<'a>(
8065 &'a self,
8066 buffer: &Buffer,
8067 cx: &mut App,
8068 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8069 let local = self.as_local();
8070 let language_server_ids = local
8071 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8072 .unwrap_or_default();
8073
8074 language_server_ids
8075 .into_iter()
8076 .filter_map(
8077 move |server_id| match local?.language_servers.get(&server_id)? {
8078 LanguageServerState::Running {
8079 adapter, server, ..
8080 } => Some((adapter, server)),
8081 _ => None,
8082 },
8083 )
8084 }
8085
8086 pub fn language_servers_for_local_buffer(
8087 &self,
8088 buffer: &Buffer,
8089 cx: &mut App,
8090 ) -> Vec<LanguageServerId> {
8091 let local = self.as_local();
8092 local
8093 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8094 .unwrap_or_default()
8095 }
8096
8097 pub fn language_server_for_local_buffer<'a>(
8098 &'a self,
8099 buffer: &'a Buffer,
8100 server_id: LanguageServerId,
8101 cx: &'a mut App,
8102 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8103 self.as_local()?
8104 .language_servers_for_buffer(buffer, cx)
8105 .find(|(_, s)| s.server_id() == server_id)
8106 }
8107
8108 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8109 self.diagnostic_summaries.remove(&id_to_remove);
8110 if let Some(local) = self.as_local_mut() {
8111 let to_remove = local.remove_worktree(id_to_remove, cx);
8112 for server in to_remove {
8113 self.language_server_statuses.remove(&server);
8114 }
8115 }
8116 }
8117
8118 pub fn shared(
8119 &mut self,
8120 project_id: u64,
8121 downstream_client: AnyProtoClient,
8122 _: &mut Context<Self>,
8123 ) {
8124 self.downstream_client = Some((downstream_client.clone(), project_id));
8125
8126 for (server_id, status) in &self.language_server_statuses {
8127 if let Some(server) = self.language_server_for_id(*server_id) {
8128 downstream_client
8129 .send(proto::StartLanguageServer {
8130 project_id,
8131 server: Some(proto::LanguageServer {
8132 id: server_id.to_proto(),
8133 name: status.name.to_string(),
8134 worktree_id: status.worktree.map(|id| id.to_proto()),
8135 }),
8136 capabilities: serde_json::to_string(&server.capabilities())
8137 .expect("serializing server LSP capabilities"),
8138 })
8139 .log_err();
8140 }
8141 }
8142 }
8143
8144 pub fn disconnected_from_host(&mut self) {
8145 self.downstream_client.take();
8146 }
8147
8148 pub fn disconnected_from_ssh_remote(&mut self) {
8149 if let LspStoreMode::Remote(RemoteLspStore {
8150 upstream_client, ..
8151 }) = &mut self.mode
8152 {
8153 upstream_client.take();
8154 }
8155 }
8156
8157 pub(crate) fn set_language_server_statuses_from_proto(
8158 &mut self,
8159 project: WeakEntity<Project>,
8160 language_servers: Vec<proto::LanguageServer>,
8161 server_capabilities: Vec<String>,
8162 cx: &mut Context<Self>,
8163 ) {
8164 let lsp_logs = cx
8165 .try_global::<GlobalLogStore>()
8166 .map(|lsp_store| lsp_store.0.clone());
8167
8168 self.language_server_statuses = language_servers
8169 .into_iter()
8170 .zip(server_capabilities)
8171 .map(|(server, server_capabilities)| {
8172 let server_id = LanguageServerId(server.id as usize);
8173 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8174 self.lsp_server_capabilities
8175 .insert(server_id, server_capabilities);
8176 }
8177
8178 let name = LanguageServerName::from_proto(server.name);
8179 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8180
8181 if let Some(lsp_logs) = &lsp_logs {
8182 lsp_logs.update(cx, |lsp_logs, cx| {
8183 lsp_logs.add_language_server(
8184 // Only remote clients get their language servers set from proto
8185 LanguageServerKind::Remote {
8186 project: project.clone(),
8187 },
8188 server_id,
8189 Some(name.clone()),
8190 worktree,
8191 None,
8192 cx,
8193 );
8194 });
8195 }
8196
8197 (
8198 server_id,
8199 LanguageServerStatus {
8200 name,
8201 server_version: None,
8202 pending_work: Default::default(),
8203 has_pending_diagnostic_updates: false,
8204 progress_tokens: Default::default(),
8205 worktree,
8206 binary: None,
8207 configuration: None,
8208 workspace_folders: BTreeSet::new(),
8209 process_id: None,
8210 },
8211 )
8212 })
8213 .collect();
8214 }
8215
8216 #[cfg(feature = "test-support")]
8217 pub fn update_diagnostic_entries(
8218 &mut self,
8219 server_id: LanguageServerId,
8220 abs_path: PathBuf,
8221 result_id: Option<SharedString>,
8222 version: Option<i32>,
8223 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8224 cx: &mut Context<Self>,
8225 ) -> anyhow::Result<()> {
8226 self.merge_diagnostic_entries(
8227 vec![DocumentDiagnosticsUpdate {
8228 diagnostics: DocumentDiagnostics {
8229 diagnostics,
8230 document_abs_path: abs_path,
8231 version,
8232 },
8233 result_id,
8234 server_id,
8235 disk_based_sources: Cow::Borrowed(&[]),
8236 registration_id: None,
8237 }],
8238 |_, _, _| false,
8239 cx,
8240 )?;
8241 Ok(())
8242 }
8243
8244 pub fn merge_diagnostic_entries<'a>(
8245 &mut self,
8246 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8247 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8248 cx: &mut Context<Self>,
8249 ) -> anyhow::Result<()> {
8250 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8251 let mut updated_diagnostics_paths = HashMap::default();
8252 for mut update in diagnostic_updates {
8253 let abs_path = &update.diagnostics.document_abs_path;
8254 let server_id = update.server_id;
8255 let Some((worktree, relative_path)) =
8256 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8257 else {
8258 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8259 return Ok(());
8260 };
8261
8262 let worktree_id = worktree.read(cx).id();
8263 let project_path = ProjectPath {
8264 worktree_id,
8265 path: relative_path,
8266 };
8267
8268 let document_uri = lsp::Uri::from_file_path(abs_path)
8269 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8270 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8271 let snapshot = buffer_handle.read(cx).snapshot();
8272 let buffer = buffer_handle.read(cx);
8273 let reused_diagnostics = buffer
8274 .buffer_diagnostics(Some(server_id))
8275 .iter()
8276 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8277 .map(|v| {
8278 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8279 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8280 DiagnosticEntry {
8281 range: start..end,
8282 diagnostic: v.diagnostic.clone(),
8283 }
8284 })
8285 .collect::<Vec<_>>();
8286
8287 self.as_local_mut()
8288 .context("cannot merge diagnostics on a remote LspStore")?
8289 .update_buffer_diagnostics(
8290 &buffer_handle,
8291 server_id,
8292 Some(update.registration_id),
8293 update.result_id,
8294 update.diagnostics.version,
8295 update.diagnostics.diagnostics.clone(),
8296 reused_diagnostics.clone(),
8297 cx,
8298 )?;
8299
8300 update.diagnostics.diagnostics.extend(reused_diagnostics);
8301 } else if let Some(local) = self.as_local() {
8302 let reused_diagnostics = local
8303 .diagnostics
8304 .get(&worktree_id)
8305 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8306 .and_then(|diagnostics_by_server_id| {
8307 diagnostics_by_server_id
8308 .binary_search_by_key(&server_id, |e| e.0)
8309 .ok()
8310 .map(|ix| &diagnostics_by_server_id[ix].1)
8311 })
8312 .into_iter()
8313 .flatten()
8314 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8315
8316 update
8317 .diagnostics
8318 .diagnostics
8319 .extend(reused_diagnostics.cloned());
8320 }
8321
8322 let updated = worktree.update(cx, |worktree, cx| {
8323 self.update_worktree_diagnostics(
8324 worktree.id(),
8325 server_id,
8326 project_path.path.clone(),
8327 update.diagnostics.diagnostics,
8328 cx,
8329 )
8330 })?;
8331 match updated {
8332 ControlFlow::Continue(new_summary) => {
8333 if let Some((project_id, new_summary)) = new_summary {
8334 match &mut diagnostics_summary {
8335 Some(diagnostics_summary) => {
8336 diagnostics_summary
8337 .more_summaries
8338 .push(proto::DiagnosticSummary {
8339 path: project_path.path.as_ref().to_proto(),
8340 language_server_id: server_id.0 as u64,
8341 error_count: new_summary.error_count,
8342 warning_count: new_summary.warning_count,
8343 })
8344 }
8345 None => {
8346 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8347 project_id,
8348 worktree_id: worktree_id.to_proto(),
8349 summary: Some(proto::DiagnosticSummary {
8350 path: project_path.path.as_ref().to_proto(),
8351 language_server_id: server_id.0 as u64,
8352 error_count: new_summary.error_count,
8353 warning_count: new_summary.warning_count,
8354 }),
8355 more_summaries: Vec::new(),
8356 })
8357 }
8358 }
8359 }
8360 updated_diagnostics_paths
8361 .entry(server_id)
8362 .or_insert_with(Vec::new)
8363 .push(project_path);
8364 }
8365 ControlFlow::Break(()) => {}
8366 }
8367 }
8368
8369 if let Some((diagnostics_summary, (downstream_client, _))) =
8370 diagnostics_summary.zip(self.downstream_client.as_ref())
8371 {
8372 downstream_client.send(diagnostics_summary).log_err();
8373 }
8374 for (server_id, paths) in updated_diagnostics_paths {
8375 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8376 }
8377 Ok(())
8378 }
8379
8380 fn update_worktree_diagnostics(
8381 &mut self,
8382 worktree_id: WorktreeId,
8383 server_id: LanguageServerId,
8384 path_in_worktree: Arc<RelPath>,
8385 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8386 _: &mut Context<Worktree>,
8387 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8388 let local = match &mut self.mode {
8389 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8390 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8391 };
8392
8393 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8394 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8395 let summaries_by_server_id = summaries_for_tree
8396 .entry(path_in_worktree.clone())
8397 .or_default();
8398
8399 let old_summary = summaries_by_server_id
8400 .remove(&server_id)
8401 .unwrap_or_default();
8402
8403 let new_summary = DiagnosticSummary::new(&diagnostics);
8404 if diagnostics.is_empty() {
8405 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8406 {
8407 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8408 diagnostics_by_server_id.remove(ix);
8409 }
8410 if diagnostics_by_server_id.is_empty() {
8411 diagnostics_for_tree.remove(&path_in_worktree);
8412 }
8413 }
8414 } else {
8415 summaries_by_server_id.insert(server_id, new_summary);
8416 let diagnostics_by_server_id = diagnostics_for_tree
8417 .entry(path_in_worktree.clone())
8418 .or_default();
8419 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8420 Ok(ix) => {
8421 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8422 }
8423 Err(ix) => {
8424 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8425 }
8426 }
8427 }
8428
8429 if !old_summary.is_empty() || !new_summary.is_empty() {
8430 if let Some((_, project_id)) = &self.downstream_client {
8431 Ok(ControlFlow::Continue(Some((
8432 *project_id,
8433 proto::DiagnosticSummary {
8434 path: path_in_worktree.to_proto(),
8435 language_server_id: server_id.0 as u64,
8436 error_count: new_summary.error_count as u32,
8437 warning_count: new_summary.warning_count as u32,
8438 },
8439 ))))
8440 } else {
8441 Ok(ControlFlow::Continue(None))
8442 }
8443 } else {
8444 Ok(ControlFlow::Break(()))
8445 }
8446 }
8447
8448 pub fn open_buffer_for_symbol(
8449 &mut self,
8450 symbol: &Symbol,
8451 cx: &mut Context<Self>,
8452 ) -> Task<Result<Entity<Buffer>>> {
8453 if let Some((client, project_id)) = self.upstream_client() {
8454 let request = client.request(proto::OpenBufferForSymbol {
8455 project_id,
8456 symbol: Some(Self::serialize_symbol(symbol)),
8457 });
8458 cx.spawn(async move |this, cx| {
8459 let response = request.await?;
8460 let buffer_id = BufferId::new(response.buffer_id)?;
8461 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8462 .await
8463 })
8464 } else if let Some(local) = self.as_local() {
8465 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8466 seed.worktree_id == symbol.source_worktree_id
8467 && state.id == symbol.source_language_server_id
8468 && symbol.language_server_name == seed.name
8469 });
8470 if !is_valid {
8471 return Task::ready(Err(anyhow!(
8472 "language server for worktree and language not found"
8473 )));
8474 };
8475
8476 let symbol_abs_path = match &symbol.path {
8477 SymbolLocation::InProject(project_path) => self
8478 .worktree_store
8479 .read(cx)
8480 .absolutize(&project_path, cx)
8481 .context("no such worktree"),
8482 SymbolLocation::OutsideProject {
8483 abs_path,
8484 signature: _,
8485 } => Ok(abs_path.to_path_buf()),
8486 };
8487 let symbol_abs_path = match symbol_abs_path {
8488 Ok(abs_path) => abs_path,
8489 Err(err) => return Task::ready(Err(err)),
8490 };
8491 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8492 uri
8493 } else {
8494 return Task::ready(Err(anyhow!("invalid symbol path")));
8495 };
8496
8497 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8498 } else {
8499 Task::ready(Err(anyhow!("no upstream client or local store")))
8500 }
8501 }
8502
8503 pub(crate) fn open_local_buffer_via_lsp(
8504 &mut self,
8505 abs_path: lsp::Uri,
8506 language_server_id: LanguageServerId,
8507 cx: &mut Context<Self>,
8508 ) -> Task<Result<Entity<Buffer>>> {
8509 let path_style = self.worktree_store.read(cx).path_style();
8510 cx.spawn(async move |lsp_store, cx| {
8511 // Escape percent-encoded string.
8512 let current_scheme = abs_path.scheme().to_owned();
8513 // Uri is immutable, so we can't modify the scheme
8514
8515 let abs_path = abs_path
8516 .to_file_path_ext(path_style)
8517 .map_err(|()| anyhow!("can't convert URI to path"))?;
8518 let p = abs_path.clone();
8519 let yarn_worktree = lsp_store
8520 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8521 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8522 cx.spawn(async move |this, cx| {
8523 let t = this
8524 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8525 .ok()?;
8526 t.await
8527 })
8528 }),
8529 None => Task::ready(None),
8530 })?
8531 .await;
8532 let (worktree_root_target, known_relative_path) =
8533 if let Some((zip_root, relative_path)) = yarn_worktree {
8534 (zip_root, Some(relative_path))
8535 } else {
8536 (Arc::<Path>::from(abs_path.as_path()), None)
8537 };
8538 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8539 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8540 worktree_store.find_worktree(&worktree_root_target, cx)
8541 })
8542 })?;
8543 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8544 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8545 (result.0, relative_path, None)
8546 } else {
8547 let worktree = lsp_store
8548 .update(cx, |lsp_store, cx| {
8549 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8550 worktree_store.create_worktree(&worktree_root_target, false, cx)
8551 })
8552 })?
8553 .await?;
8554 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8555 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8556 lsp_store
8557 .update(cx, |lsp_store, cx| {
8558 if let Some(local) = lsp_store.as_local_mut() {
8559 local.register_language_server_for_invisible_worktree(
8560 &worktree,
8561 language_server_id,
8562 cx,
8563 )
8564 }
8565 match lsp_store.language_server_statuses.get(&language_server_id) {
8566 Some(status) => status.worktree,
8567 None => None,
8568 }
8569 })
8570 .ok()
8571 .flatten()
8572 .zip(Some(worktree_root.clone()))
8573 } else {
8574 None
8575 };
8576 let relative_path = if let Some(known_path) = known_relative_path {
8577 known_path
8578 } else {
8579 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8580 .into_arc()
8581 };
8582 (worktree, relative_path, source_ws)
8583 };
8584 let project_path = ProjectPath {
8585 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8586 path: relative_path,
8587 };
8588 let buffer = lsp_store
8589 .update(cx, |lsp_store, cx| {
8590 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8591 buffer_store.open_buffer(project_path, cx)
8592 })
8593 })?
8594 .await?;
8595 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8596 if let Some((source_ws, worktree_root)) = source_ws {
8597 buffer.update(cx, |buffer, cx| {
8598 let settings = WorktreeSettings::get(
8599 Some(
8600 (&ProjectPath {
8601 worktree_id: source_ws,
8602 path: Arc::from(RelPath::empty()),
8603 })
8604 .into(),
8605 ),
8606 cx,
8607 );
8608 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8609 if is_read_only {
8610 buffer.set_capability(Capability::ReadOnly, cx);
8611 }
8612 });
8613 }
8614 Ok(buffer)
8615 })
8616 }
8617
8618 fn local_lsp_servers_for_buffer(
8619 &self,
8620 buffer: &Entity<Buffer>,
8621 cx: &mut Context<Self>,
8622 ) -> Vec<LanguageServerId> {
8623 let Some(local) = self.as_local() else {
8624 return Vec::new();
8625 };
8626
8627 let snapshot = buffer.read(cx).snapshot();
8628
8629 buffer.update(cx, |buffer, cx| {
8630 local
8631 .language_servers_for_buffer(buffer, cx)
8632 .map(|(_, server)| server.server_id())
8633 .filter(|server_id| {
8634 self.as_local().is_none_or(|local| {
8635 local
8636 .buffers_opened_in_servers
8637 .get(&snapshot.remote_id())
8638 .is_some_and(|servers| servers.contains(server_id))
8639 })
8640 })
8641 .collect()
8642 })
8643 }
8644
8645 fn request_multiple_lsp_locally<P, R>(
8646 &mut self,
8647 buffer: &Entity<Buffer>,
8648 position: Option<P>,
8649 request: R,
8650 cx: &mut Context<Self>,
8651 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8652 where
8653 P: ToOffset,
8654 R: LspCommand + Clone,
8655 <R::LspRequest as lsp::request::Request>::Result: Send,
8656 <R::LspRequest as lsp::request::Request>::Params: Send,
8657 {
8658 let Some(local) = self.as_local() else {
8659 return Task::ready(Vec::new());
8660 };
8661
8662 let snapshot = buffer.read(cx).snapshot();
8663 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8664
8665 let server_ids = buffer.update(cx, |buffer, cx| {
8666 local
8667 .language_servers_for_buffer(buffer, cx)
8668 .filter(|(adapter, _)| {
8669 scope
8670 .as_ref()
8671 .map(|scope| scope.language_allowed(&adapter.name))
8672 .unwrap_or(true)
8673 })
8674 .map(|(_, server)| server.server_id())
8675 .filter(|server_id| {
8676 self.as_local().is_none_or(|local| {
8677 local
8678 .buffers_opened_in_servers
8679 .get(&snapshot.remote_id())
8680 .is_some_and(|servers| servers.contains(server_id))
8681 })
8682 })
8683 .collect::<Vec<_>>()
8684 });
8685
8686 let mut response_results = server_ids
8687 .into_iter()
8688 .map(|server_id| {
8689 let task = self.request_lsp(
8690 buffer.clone(),
8691 LanguageServerToQuery::Other(server_id),
8692 request.clone(),
8693 cx,
8694 );
8695 async move { (server_id, task.await) }
8696 })
8697 .collect::<FuturesUnordered<_>>();
8698
8699 cx.background_spawn(async move {
8700 let mut responses = Vec::with_capacity(response_results.len());
8701 while let Some((server_id, response_result)) = response_results.next().await {
8702 match response_result {
8703 Ok(response) => responses.push((server_id, response)),
8704 // rust-analyzer likes to error with this when its still loading up
8705 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8706 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8707 }
8708 }
8709 responses
8710 })
8711 }
8712
8713 async fn handle_lsp_get_completions(
8714 this: Entity<Self>,
8715 envelope: TypedEnvelope<proto::GetCompletions>,
8716 mut cx: AsyncApp,
8717 ) -> Result<proto::GetCompletionsResponse> {
8718 let sender_id = envelope.original_sender_id().unwrap_or_default();
8719
8720 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8721 let buffer_handle = this.update(&mut cx, |this, cx| {
8722 this.buffer_store.read(cx).get_existing(buffer_id)
8723 })?;
8724 let request = GetCompletions::from_proto(
8725 envelope.payload,
8726 this.clone(),
8727 buffer_handle.clone(),
8728 cx.clone(),
8729 )
8730 .await?;
8731
8732 let server_to_query = match request.server_id {
8733 Some(server_id) => LanguageServerToQuery::Other(server_id),
8734 None => LanguageServerToQuery::FirstCapable,
8735 };
8736
8737 let response = this
8738 .update(&mut cx, |this, cx| {
8739 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8740 })
8741 .await?;
8742 this.update(&mut cx, |this, cx| {
8743 Ok(GetCompletions::response_to_proto(
8744 response,
8745 this,
8746 sender_id,
8747 &buffer_handle.read(cx).version(),
8748 cx,
8749 ))
8750 })
8751 }
8752
8753 async fn handle_lsp_command<T: LspCommand>(
8754 this: Entity<Self>,
8755 envelope: TypedEnvelope<T::ProtoRequest>,
8756 mut cx: AsyncApp,
8757 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8758 where
8759 <T::LspRequest as lsp::request::Request>::Params: Send,
8760 <T::LspRequest as lsp::request::Request>::Result: Send,
8761 {
8762 let sender_id = envelope.original_sender_id().unwrap_or_default();
8763 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8764 let buffer_handle = this.update(&mut cx, |this, cx| {
8765 this.buffer_store.read(cx).get_existing(buffer_id)
8766 })?;
8767 let request = T::from_proto(
8768 envelope.payload,
8769 this.clone(),
8770 buffer_handle.clone(),
8771 cx.clone(),
8772 )
8773 .await?;
8774 let response = this
8775 .update(&mut cx, |this, cx| {
8776 this.request_lsp(
8777 buffer_handle.clone(),
8778 LanguageServerToQuery::FirstCapable,
8779 request,
8780 cx,
8781 )
8782 })
8783 .await?;
8784 this.update(&mut cx, |this, cx| {
8785 Ok(T::response_to_proto(
8786 response,
8787 this,
8788 sender_id,
8789 &buffer_handle.read(cx).version(),
8790 cx,
8791 ))
8792 })
8793 }
8794
8795 async fn handle_lsp_query(
8796 lsp_store: Entity<Self>,
8797 envelope: TypedEnvelope<proto::LspQuery>,
8798 mut cx: AsyncApp,
8799 ) -> Result<proto::Ack> {
8800 use proto::lsp_query::Request;
8801 let sender_id = envelope.original_sender_id().unwrap_or_default();
8802 let lsp_query = envelope.payload;
8803 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8804 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8805 match lsp_query.request.context("invalid LSP query request")? {
8806 Request::GetReferences(get_references) => {
8807 let position = get_references.position.clone().and_then(deserialize_anchor);
8808 Self::query_lsp_locally::<GetReferences>(
8809 lsp_store,
8810 server_id,
8811 sender_id,
8812 lsp_request_id,
8813 get_references,
8814 position,
8815 &mut cx,
8816 )
8817 .await?;
8818 }
8819 Request::GetDocumentColor(get_document_color) => {
8820 Self::query_lsp_locally::<GetDocumentColor>(
8821 lsp_store,
8822 server_id,
8823 sender_id,
8824 lsp_request_id,
8825 get_document_color,
8826 None,
8827 &mut cx,
8828 )
8829 .await?;
8830 }
8831 Request::GetFoldingRanges(get_folding_ranges) => {
8832 Self::query_lsp_locally::<GetFoldingRanges>(
8833 lsp_store,
8834 server_id,
8835 sender_id,
8836 lsp_request_id,
8837 get_folding_ranges,
8838 None,
8839 &mut cx,
8840 )
8841 .await?;
8842 }
8843 Request::GetDocumentSymbols(get_document_symbols) => {
8844 Self::query_lsp_locally::<GetDocumentSymbols>(
8845 lsp_store,
8846 server_id,
8847 sender_id,
8848 lsp_request_id,
8849 get_document_symbols,
8850 None,
8851 &mut cx,
8852 )
8853 .await?;
8854 }
8855 Request::GetHover(get_hover) => {
8856 let position = get_hover.position.clone().and_then(deserialize_anchor);
8857 Self::query_lsp_locally::<GetHover>(
8858 lsp_store,
8859 server_id,
8860 sender_id,
8861 lsp_request_id,
8862 get_hover,
8863 position,
8864 &mut cx,
8865 )
8866 .await?;
8867 }
8868 Request::GetCodeActions(get_code_actions) => {
8869 Self::query_lsp_locally::<GetCodeActions>(
8870 lsp_store,
8871 server_id,
8872 sender_id,
8873 lsp_request_id,
8874 get_code_actions,
8875 None,
8876 &mut cx,
8877 )
8878 .await?;
8879 }
8880 Request::GetSignatureHelp(get_signature_help) => {
8881 let position = get_signature_help
8882 .position
8883 .clone()
8884 .and_then(deserialize_anchor);
8885 Self::query_lsp_locally::<GetSignatureHelp>(
8886 lsp_store,
8887 server_id,
8888 sender_id,
8889 lsp_request_id,
8890 get_signature_help,
8891 position,
8892 &mut cx,
8893 )
8894 .await?;
8895 }
8896 Request::GetCodeLens(get_code_lens) => {
8897 Self::query_lsp_locally::<GetCodeLens>(
8898 lsp_store,
8899 server_id,
8900 sender_id,
8901 lsp_request_id,
8902 get_code_lens,
8903 None,
8904 &mut cx,
8905 )
8906 .await?;
8907 }
8908 Request::GetDefinition(get_definition) => {
8909 let position = get_definition.position.clone().and_then(deserialize_anchor);
8910 Self::query_lsp_locally::<GetDefinitions>(
8911 lsp_store,
8912 server_id,
8913 sender_id,
8914 lsp_request_id,
8915 get_definition,
8916 position,
8917 &mut cx,
8918 )
8919 .await?;
8920 }
8921 Request::GetDeclaration(get_declaration) => {
8922 let position = get_declaration
8923 .position
8924 .clone()
8925 .and_then(deserialize_anchor);
8926 Self::query_lsp_locally::<GetDeclarations>(
8927 lsp_store,
8928 server_id,
8929 sender_id,
8930 lsp_request_id,
8931 get_declaration,
8932 position,
8933 &mut cx,
8934 )
8935 .await?;
8936 }
8937 Request::GetTypeDefinition(get_type_definition) => {
8938 let position = get_type_definition
8939 .position
8940 .clone()
8941 .and_then(deserialize_anchor);
8942 Self::query_lsp_locally::<GetTypeDefinitions>(
8943 lsp_store,
8944 server_id,
8945 sender_id,
8946 lsp_request_id,
8947 get_type_definition,
8948 position,
8949 &mut cx,
8950 )
8951 .await?;
8952 }
8953 Request::GetImplementation(get_implementation) => {
8954 let position = get_implementation
8955 .position
8956 .clone()
8957 .and_then(deserialize_anchor);
8958 Self::query_lsp_locally::<GetImplementations>(
8959 lsp_store,
8960 server_id,
8961 sender_id,
8962 lsp_request_id,
8963 get_implementation,
8964 position,
8965 &mut cx,
8966 )
8967 .await?;
8968 }
8969 Request::InlayHints(inlay_hints) => {
8970 let query_start = inlay_hints
8971 .start
8972 .clone()
8973 .and_then(deserialize_anchor)
8974 .context("invalid inlay hints range start")?;
8975 let query_end = inlay_hints
8976 .end
8977 .clone()
8978 .and_then(deserialize_anchor)
8979 .context("invalid inlay hints range end")?;
8980 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8981 &lsp_store,
8982 server_id,
8983 lsp_request_id,
8984 &inlay_hints,
8985 query_start..query_end,
8986 &mut cx,
8987 )
8988 .await
8989 .context("preparing inlay hints request")?;
8990 Self::query_lsp_locally::<InlayHints>(
8991 lsp_store,
8992 server_id,
8993 sender_id,
8994 lsp_request_id,
8995 inlay_hints,
8996 None,
8997 &mut cx,
8998 )
8999 .await
9000 .context("querying for inlay hints")?
9001 }
9002 //////////////////////////////
9003 // Below are LSP queries that need to fetch more data,
9004 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9005 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9006 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9007 &lsp_store,
9008 &get_document_diagnostics,
9009 &mut cx,
9010 )
9011 .await?;
9012 lsp_store.update(&mut cx, |lsp_store, cx| {
9013 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9014 let key = LspKey {
9015 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9016 server_queried: server_id,
9017 };
9018 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9019 ) {
9020 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9021 lsp_requests.clear();
9022 };
9023 }
9024
9025 lsp_data.lsp_requests.entry(key).or_default().insert(
9026 lsp_request_id,
9027 cx.spawn(async move |lsp_store, cx| {
9028 let diagnostics_pull = lsp_store
9029 .update(cx, |lsp_store, cx| {
9030 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9031 })
9032 .ok();
9033 if let Some(diagnostics_pull) = diagnostics_pull {
9034 match diagnostics_pull.await {
9035 Ok(()) => {}
9036 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9037 };
9038 }
9039 }),
9040 );
9041 });
9042 }
9043 Request::SemanticTokens(semantic_tokens) => {
9044 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9045 &lsp_store,
9046 &semantic_tokens,
9047 &mut cx,
9048 )
9049 .await?;
9050 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9051 lsp_store.update(&mut cx, |lsp_store, cx| {
9052 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9053 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9054 let key = LspKey {
9055 request_type: TypeId::of::<SemanticTokensFull>(),
9056 server_queried: server_id,
9057 };
9058 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9059 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9060 lsp_requests.clear();
9061 };
9062 }
9063
9064 lsp_data.lsp_requests.entry(key).or_default().insert(
9065 lsp_request_id,
9066 cx.spawn(async move |lsp_store, cx| {
9067 let tokens_fetch = lsp_store
9068 .update(cx, |lsp_store, cx| {
9069 lsp_store
9070 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9071 })
9072 .ok();
9073 if let Some(tokens_fetch) = tokens_fetch {
9074 let new_tokens = tokens_fetch.await;
9075 if let Some(new_tokens) = new_tokens {
9076 lsp_store
9077 .update(cx, |lsp_store, cx| {
9078 let response = new_tokens
9079 .into_iter()
9080 .map(|(server_id, response)| {
9081 (
9082 server_id.to_proto(),
9083 SemanticTokensFull::response_to_proto(
9084 response,
9085 lsp_store,
9086 sender_id,
9087 &buffer_version,
9088 cx,
9089 ),
9090 )
9091 })
9092 .collect::<HashMap<_, _>>();
9093 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9094 project_id,
9095 lsp_request_id,
9096 response,
9097 ) {
9098 Ok(()) => {}
9099 Err(e) => {
9100 log::error!(
9101 "Failed to send semantic tokens LSP response: {e:#}",
9102 )
9103 }
9104 }
9105 })
9106 .ok();
9107 }
9108 }
9109 }),
9110 );
9111 }
9112 });
9113 }
9114 }
9115 Ok(proto::Ack {})
9116 }
9117
9118 async fn handle_lsp_query_response(
9119 lsp_store: Entity<Self>,
9120 envelope: TypedEnvelope<proto::LspQueryResponse>,
9121 cx: AsyncApp,
9122 ) -> Result<()> {
9123 lsp_store.read_with(&cx, |lsp_store, _| {
9124 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9125 upstream_client.handle_lsp_response(envelope.clone());
9126 }
9127 });
9128 Ok(())
9129 }
9130
9131 async fn handle_apply_code_action(
9132 this: Entity<Self>,
9133 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9134 mut cx: AsyncApp,
9135 ) -> Result<proto::ApplyCodeActionResponse> {
9136 let sender_id = envelope.original_sender_id().unwrap_or_default();
9137 let action =
9138 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9139 let apply_code_action = this.update(&mut cx, |this, cx| {
9140 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9141 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9142 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9143 })?;
9144
9145 let project_transaction = apply_code_action.await?;
9146 let project_transaction = this.update(&mut cx, |this, cx| {
9147 this.buffer_store.update(cx, |buffer_store, cx| {
9148 buffer_store.serialize_project_transaction_for_peer(
9149 project_transaction,
9150 sender_id,
9151 cx,
9152 )
9153 })
9154 });
9155 Ok(proto::ApplyCodeActionResponse {
9156 transaction: Some(project_transaction),
9157 })
9158 }
9159
9160 async fn handle_register_buffer_with_language_servers(
9161 this: Entity<Self>,
9162 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9163 mut cx: AsyncApp,
9164 ) -> Result<proto::Ack> {
9165 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9166 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9167 this.update(&mut cx, |this, cx| {
9168 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9169 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9170 project_id: upstream_project_id,
9171 buffer_id: buffer_id.to_proto(),
9172 only_servers: envelope.payload.only_servers,
9173 });
9174 }
9175
9176 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9177 anyhow::bail!("buffer is not open");
9178 };
9179
9180 let handle = this.register_buffer_with_language_servers(
9181 &buffer,
9182 envelope
9183 .payload
9184 .only_servers
9185 .into_iter()
9186 .filter_map(|selector| {
9187 Some(match selector.selector? {
9188 proto::language_server_selector::Selector::ServerId(server_id) => {
9189 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9190 }
9191 proto::language_server_selector::Selector::Name(name) => {
9192 LanguageServerSelector::Name(LanguageServerName(
9193 SharedString::from(name),
9194 ))
9195 }
9196 })
9197 })
9198 .collect(),
9199 false,
9200 cx,
9201 );
9202 // Pull diagnostics for the buffer even if it was already registered.
9203 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9204 // but it's unclear if we need it.
9205 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9206 .detach();
9207 this.buffer_store().update(cx, |buffer_store, _| {
9208 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9209 });
9210
9211 Ok(())
9212 })?;
9213 Ok(proto::Ack {})
9214 }
9215
9216 async fn handle_rename_project_entry(
9217 this: Entity<Self>,
9218 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9219 mut cx: AsyncApp,
9220 ) -> Result<proto::ProjectEntryResponse> {
9221 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9222 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9223 let new_path =
9224 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9225
9226 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9227 .update(&mut cx, |this, cx| {
9228 let (worktree, entry) = this
9229 .worktree_store
9230 .read(cx)
9231 .worktree_and_entry_for_id(entry_id, cx)?;
9232 let new_worktree = this
9233 .worktree_store
9234 .read(cx)
9235 .worktree_for_id(new_worktree_id, cx)?;
9236 Some((
9237 this.worktree_store.clone(),
9238 worktree,
9239 new_worktree,
9240 entry.clone(),
9241 ))
9242 })
9243 .context("worktree not found")?;
9244 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9245 (worktree.absolutize(&old_entry.path), worktree.id())
9246 });
9247 let new_abs_path =
9248 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9249
9250 let _transaction = Self::will_rename_entry(
9251 this.downgrade(),
9252 old_worktree_id,
9253 &old_abs_path,
9254 &new_abs_path,
9255 old_entry.is_dir(),
9256 cx.clone(),
9257 )
9258 .await;
9259 let response = WorktreeStore::handle_rename_project_entry(
9260 worktree_store,
9261 envelope.payload,
9262 cx.clone(),
9263 )
9264 .await;
9265 this.read_with(&cx, |this, _| {
9266 this.did_rename_entry(
9267 old_worktree_id,
9268 &old_abs_path,
9269 &new_abs_path,
9270 old_entry.is_dir(),
9271 );
9272 });
9273 response
9274 }
9275
9276 async fn handle_update_diagnostic_summary(
9277 this: Entity<Self>,
9278 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9279 mut cx: AsyncApp,
9280 ) -> Result<()> {
9281 this.update(&mut cx, |lsp_store, cx| {
9282 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9283 let mut updated_diagnostics_paths = HashMap::default();
9284 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9285 for message_summary in envelope
9286 .payload
9287 .summary
9288 .into_iter()
9289 .chain(envelope.payload.more_summaries)
9290 {
9291 let project_path = ProjectPath {
9292 worktree_id,
9293 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9294 };
9295 let path = project_path.path.clone();
9296 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9297 let summary = DiagnosticSummary {
9298 error_count: message_summary.error_count as usize,
9299 warning_count: message_summary.warning_count as usize,
9300 };
9301
9302 if summary.is_empty() {
9303 if let Some(worktree_summaries) =
9304 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9305 && let Some(summaries) = worktree_summaries.get_mut(&path)
9306 {
9307 summaries.remove(&server_id);
9308 if summaries.is_empty() {
9309 worktree_summaries.remove(&path);
9310 }
9311 }
9312 } else {
9313 lsp_store
9314 .diagnostic_summaries
9315 .entry(worktree_id)
9316 .or_default()
9317 .entry(path)
9318 .or_default()
9319 .insert(server_id, summary);
9320 }
9321
9322 if let Some((_, project_id)) = &lsp_store.downstream_client {
9323 match &mut diagnostics_summary {
9324 Some(diagnostics_summary) => {
9325 diagnostics_summary
9326 .more_summaries
9327 .push(proto::DiagnosticSummary {
9328 path: project_path.path.as_ref().to_proto(),
9329 language_server_id: server_id.0 as u64,
9330 error_count: summary.error_count as u32,
9331 warning_count: summary.warning_count as u32,
9332 })
9333 }
9334 None => {
9335 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9336 project_id: *project_id,
9337 worktree_id: worktree_id.to_proto(),
9338 summary: Some(proto::DiagnosticSummary {
9339 path: project_path.path.as_ref().to_proto(),
9340 language_server_id: server_id.0 as u64,
9341 error_count: summary.error_count as u32,
9342 warning_count: summary.warning_count as u32,
9343 }),
9344 more_summaries: Vec::new(),
9345 })
9346 }
9347 }
9348 }
9349 updated_diagnostics_paths
9350 .entry(server_id)
9351 .or_insert_with(Vec::new)
9352 .push(project_path);
9353 }
9354
9355 if let Some((diagnostics_summary, (downstream_client, _))) =
9356 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9357 {
9358 downstream_client.send(diagnostics_summary).log_err();
9359 }
9360 for (server_id, paths) in updated_diagnostics_paths {
9361 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9362 }
9363 Ok(())
9364 })
9365 }
9366
9367 async fn handle_start_language_server(
9368 lsp_store: Entity<Self>,
9369 envelope: TypedEnvelope<proto::StartLanguageServer>,
9370 mut cx: AsyncApp,
9371 ) -> Result<()> {
9372 let server = envelope.payload.server.context("invalid server")?;
9373 let server_capabilities =
9374 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9375 .with_context(|| {
9376 format!(
9377 "incorrect server capabilities {}",
9378 envelope.payload.capabilities
9379 )
9380 })?;
9381 lsp_store.update(&mut cx, |lsp_store, cx| {
9382 let server_id = LanguageServerId(server.id as usize);
9383 let server_name = LanguageServerName::from_proto(server.name.clone());
9384 lsp_store
9385 .lsp_server_capabilities
9386 .insert(server_id, server_capabilities);
9387 lsp_store.language_server_statuses.insert(
9388 server_id,
9389 LanguageServerStatus {
9390 name: server_name.clone(),
9391 server_version: None,
9392 pending_work: Default::default(),
9393 has_pending_diagnostic_updates: false,
9394 progress_tokens: Default::default(),
9395 worktree: server.worktree_id.map(WorktreeId::from_proto),
9396 binary: None,
9397 configuration: None,
9398 workspace_folders: BTreeSet::new(),
9399 process_id: None,
9400 },
9401 );
9402 cx.emit(LspStoreEvent::LanguageServerAdded(
9403 server_id,
9404 server_name,
9405 server.worktree_id.map(WorktreeId::from_proto),
9406 ));
9407 cx.notify();
9408 });
9409 Ok(())
9410 }
9411
9412 async fn handle_update_language_server(
9413 lsp_store: Entity<Self>,
9414 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9415 mut cx: AsyncApp,
9416 ) -> Result<()> {
9417 lsp_store.update(&mut cx, |lsp_store, cx| {
9418 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9419
9420 match envelope.payload.variant.context("invalid variant")? {
9421 proto::update_language_server::Variant::WorkStart(payload) => {
9422 lsp_store.on_lsp_work_start(
9423 language_server_id,
9424 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9425 .context("invalid progress token value")?,
9426 LanguageServerProgress {
9427 title: payload.title,
9428 is_disk_based_diagnostics_progress: false,
9429 is_cancellable: payload.is_cancellable.unwrap_or(false),
9430 message: payload.message,
9431 percentage: payload.percentage.map(|p| p as usize),
9432 last_update_at: cx.background_executor().now(),
9433 },
9434 cx,
9435 );
9436 }
9437 proto::update_language_server::Variant::WorkProgress(payload) => {
9438 lsp_store.on_lsp_work_progress(
9439 language_server_id,
9440 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9441 .context("invalid progress token value")?,
9442 LanguageServerProgress {
9443 title: None,
9444 is_disk_based_diagnostics_progress: false,
9445 is_cancellable: payload.is_cancellable.unwrap_or(false),
9446 message: payload.message,
9447 percentage: payload.percentage.map(|p| p as usize),
9448 last_update_at: cx.background_executor().now(),
9449 },
9450 cx,
9451 );
9452 }
9453
9454 proto::update_language_server::Variant::WorkEnd(payload) => {
9455 lsp_store.on_lsp_work_end(
9456 language_server_id,
9457 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9458 .context("invalid progress token value")?,
9459 cx,
9460 );
9461 }
9462
9463 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9464 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9465 }
9466
9467 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9468 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9469 }
9470
9471 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9472 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9473 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9474 cx.emit(LspStoreEvent::LanguageServerUpdate {
9475 language_server_id,
9476 name: envelope
9477 .payload
9478 .server_name
9479 .map(SharedString::new)
9480 .map(LanguageServerName),
9481 message: non_lsp,
9482 });
9483 }
9484 }
9485
9486 Ok(())
9487 })
9488 }
9489
9490 async fn handle_language_server_log(
9491 this: Entity<Self>,
9492 envelope: TypedEnvelope<proto::LanguageServerLog>,
9493 mut cx: AsyncApp,
9494 ) -> Result<()> {
9495 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9496 let log_type = envelope
9497 .payload
9498 .log_type
9499 .map(LanguageServerLogType::from_proto)
9500 .context("invalid language server log type")?;
9501
9502 let message = envelope.payload.message;
9503
9504 this.update(&mut cx, |_, cx| {
9505 cx.emit(LspStoreEvent::LanguageServerLog(
9506 language_server_id,
9507 log_type,
9508 message,
9509 ));
9510 });
9511 Ok(())
9512 }
9513
9514 async fn handle_lsp_ext_cancel_flycheck(
9515 lsp_store: Entity<Self>,
9516 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9517 cx: AsyncApp,
9518 ) -> Result<proto::Ack> {
9519 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9520 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9521 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9522 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9523 } else {
9524 None
9525 }
9526 });
9527 if let Some(task) = task {
9528 task.context("handling lsp ext cancel flycheck")?;
9529 }
9530
9531 Ok(proto::Ack {})
9532 }
9533
9534 async fn handle_lsp_ext_run_flycheck(
9535 lsp_store: Entity<Self>,
9536 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9537 mut cx: AsyncApp,
9538 ) -> Result<proto::Ack> {
9539 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9540 lsp_store.update(&mut cx, |lsp_store, cx| {
9541 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9542 let text_document = if envelope.payload.current_file_only {
9543 let buffer_id = envelope
9544 .payload
9545 .buffer_id
9546 .map(|id| BufferId::new(id))
9547 .transpose()?;
9548 buffer_id
9549 .and_then(|buffer_id| {
9550 lsp_store
9551 .buffer_store()
9552 .read(cx)
9553 .get(buffer_id)
9554 .and_then(|buffer| {
9555 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9556 })
9557 .map(|path| make_text_document_identifier(&path))
9558 })
9559 .transpose()?
9560 } else {
9561 None
9562 };
9563 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9564 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9565 )?;
9566 }
9567 anyhow::Ok(())
9568 })?;
9569
9570 Ok(proto::Ack {})
9571 }
9572
9573 async fn handle_lsp_ext_clear_flycheck(
9574 lsp_store: Entity<Self>,
9575 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9576 cx: AsyncApp,
9577 ) -> Result<proto::Ack> {
9578 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9579 lsp_store.read_with(&cx, |lsp_store, _| {
9580 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9581 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9582 } else {
9583 None
9584 }
9585 });
9586
9587 Ok(proto::Ack {})
9588 }
9589
9590 pub fn disk_based_diagnostics_started(
9591 &mut self,
9592 language_server_id: LanguageServerId,
9593 cx: &mut Context<Self>,
9594 ) {
9595 if let Some(language_server_status) =
9596 self.language_server_statuses.get_mut(&language_server_id)
9597 {
9598 language_server_status.has_pending_diagnostic_updates = true;
9599 }
9600
9601 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9602 cx.emit(LspStoreEvent::LanguageServerUpdate {
9603 language_server_id,
9604 name: self
9605 .language_server_adapter_for_id(language_server_id)
9606 .map(|adapter| adapter.name()),
9607 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9608 Default::default(),
9609 ),
9610 })
9611 }
9612
9613 pub fn disk_based_diagnostics_finished(
9614 &mut self,
9615 language_server_id: LanguageServerId,
9616 cx: &mut Context<Self>,
9617 ) {
9618 if let Some(language_server_status) =
9619 self.language_server_statuses.get_mut(&language_server_id)
9620 {
9621 language_server_status.has_pending_diagnostic_updates = false;
9622 }
9623
9624 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9625 cx.emit(LspStoreEvent::LanguageServerUpdate {
9626 language_server_id,
9627 name: self
9628 .language_server_adapter_for_id(language_server_id)
9629 .map(|adapter| adapter.name()),
9630 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9631 Default::default(),
9632 ),
9633 })
9634 }
9635
9636 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9637 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9638 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9639 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9640 // the language server might take some time to publish diagnostics.
9641 fn simulate_disk_based_diagnostics_events_if_needed(
9642 &mut self,
9643 language_server_id: LanguageServerId,
9644 cx: &mut Context<Self>,
9645 ) {
9646 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9647
9648 let Some(LanguageServerState::Running {
9649 simulate_disk_based_diagnostics_completion,
9650 adapter,
9651 ..
9652 }) = self
9653 .as_local_mut()
9654 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9655 else {
9656 return;
9657 };
9658
9659 if adapter.disk_based_diagnostics_progress_token.is_some() {
9660 return;
9661 }
9662
9663 let prev_task =
9664 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9665 cx.background_executor()
9666 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9667 .await;
9668
9669 this.update(cx, |this, cx| {
9670 this.disk_based_diagnostics_finished(language_server_id, cx);
9671
9672 if let Some(LanguageServerState::Running {
9673 simulate_disk_based_diagnostics_completion,
9674 ..
9675 }) = this.as_local_mut().and_then(|local_store| {
9676 local_store.language_servers.get_mut(&language_server_id)
9677 }) {
9678 *simulate_disk_based_diagnostics_completion = None;
9679 }
9680 })
9681 .ok();
9682 }));
9683
9684 if prev_task.is_none() {
9685 self.disk_based_diagnostics_started(language_server_id, cx);
9686 }
9687 }
9688
9689 pub fn language_server_statuses(
9690 &self,
9691 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9692 self.language_server_statuses
9693 .iter()
9694 .map(|(key, value)| (*key, value))
9695 }
9696
9697 pub(super) fn did_rename_entry(
9698 &self,
9699 worktree_id: WorktreeId,
9700 old_path: &Path,
9701 new_path: &Path,
9702 is_dir: bool,
9703 ) {
9704 maybe!({
9705 let local_store = self.as_local()?;
9706
9707 let old_uri = lsp::Uri::from_file_path(old_path)
9708 .ok()
9709 .map(|uri| uri.to_string())?;
9710 let new_uri = lsp::Uri::from_file_path(new_path)
9711 .ok()
9712 .map(|uri| uri.to_string())?;
9713
9714 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9715 let Some(filter) = local_store
9716 .language_server_paths_watched_for_rename
9717 .get(&language_server.server_id())
9718 else {
9719 continue;
9720 };
9721
9722 if filter.should_send_did_rename(&old_uri, is_dir) {
9723 language_server
9724 .notify::<DidRenameFiles>(RenameFilesParams {
9725 files: vec![FileRename {
9726 old_uri: old_uri.clone(),
9727 new_uri: new_uri.clone(),
9728 }],
9729 })
9730 .ok();
9731 }
9732 }
9733 Some(())
9734 });
9735 }
9736
9737 pub(super) fn will_rename_entry(
9738 this: WeakEntity<Self>,
9739 worktree_id: WorktreeId,
9740 old_path: &Path,
9741 new_path: &Path,
9742 is_dir: bool,
9743 cx: AsyncApp,
9744 ) -> Task<ProjectTransaction> {
9745 let old_uri = lsp::Uri::from_file_path(old_path)
9746 .ok()
9747 .map(|uri| uri.to_string());
9748 let new_uri = lsp::Uri::from_file_path(new_path)
9749 .ok()
9750 .map(|uri| uri.to_string());
9751 cx.spawn(async move |cx| {
9752 let mut tasks = vec![];
9753 this.update(cx, |this, cx| {
9754 let local_store = this.as_local()?;
9755 let old_uri = old_uri?;
9756 let new_uri = new_uri?;
9757 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9758 let Some(filter) = local_store
9759 .language_server_paths_watched_for_rename
9760 .get(&language_server.server_id())
9761 else {
9762 continue;
9763 };
9764
9765 if !filter.should_send_will_rename(&old_uri, is_dir) {
9766 continue;
9767 }
9768 let request_timeout = ProjectSettings::get_global(cx)
9769 .global_lsp_settings
9770 .get_request_timeout();
9771
9772 let apply_edit = cx.spawn({
9773 let old_uri = old_uri.clone();
9774 let new_uri = new_uri.clone();
9775 let language_server = language_server.clone();
9776 async move |this, cx| {
9777 let edit = language_server
9778 .request::<WillRenameFiles>(
9779 RenameFilesParams {
9780 files: vec![FileRename { old_uri, new_uri }],
9781 },
9782 request_timeout,
9783 )
9784 .await
9785 .into_response()
9786 .context("will rename files")
9787 .log_err()
9788 .flatten()?;
9789
9790 LocalLspStore::deserialize_workspace_edit(
9791 this.upgrade()?,
9792 edit,
9793 false,
9794 language_server.clone(),
9795 cx,
9796 )
9797 .await
9798 .ok()
9799 }
9800 });
9801 tasks.push(apply_edit);
9802 }
9803 Some(())
9804 })
9805 .ok()
9806 .flatten();
9807 let mut merged_transaction = ProjectTransaction::default();
9808 for task in tasks {
9809 // Await on tasks sequentially so that the order of application of edits is deterministic
9810 // (at least with regards to the order of registration of language servers)
9811 if let Some(transaction) = task.await {
9812 for (buffer, buffer_transaction) in transaction.0 {
9813 merged_transaction.0.insert(buffer, buffer_transaction);
9814 }
9815 }
9816 }
9817 merged_transaction
9818 })
9819 }
9820
9821 fn lsp_notify_abs_paths_changed(
9822 &mut self,
9823 server_id: LanguageServerId,
9824 changes: Vec<PathEvent>,
9825 ) {
9826 maybe!({
9827 let server = self.language_server_for_id(server_id)?;
9828 let changes = changes
9829 .into_iter()
9830 .filter_map(|event| {
9831 let typ = match event.kind? {
9832 PathEventKind::Created => lsp::FileChangeType::CREATED,
9833 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9834 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9835 };
9836 Some(lsp::FileEvent {
9837 uri: file_path_to_lsp_url(&event.path).log_err()?,
9838 typ,
9839 })
9840 })
9841 .collect::<Vec<_>>();
9842 if !changes.is_empty() {
9843 server
9844 .notify::<lsp::notification::DidChangeWatchedFiles>(
9845 lsp::DidChangeWatchedFilesParams { changes },
9846 )
9847 .ok();
9848 }
9849 Some(())
9850 });
9851 }
9852
9853 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9854 self.as_local()?.language_server_for_id(id)
9855 }
9856
9857 fn on_lsp_progress(
9858 &mut self,
9859 progress_params: lsp::ProgressParams,
9860 language_server_id: LanguageServerId,
9861 disk_based_diagnostics_progress_token: Option<String>,
9862 cx: &mut Context<Self>,
9863 ) {
9864 match progress_params.value {
9865 lsp::ProgressParamsValue::WorkDone(progress) => {
9866 self.handle_work_done_progress(
9867 progress,
9868 language_server_id,
9869 disk_based_diagnostics_progress_token,
9870 ProgressToken::from_lsp(progress_params.token),
9871 cx,
9872 );
9873 }
9874 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9875 let registration_id = match progress_params.token {
9876 lsp::NumberOrString::Number(_) => None,
9877 lsp::NumberOrString::String(token) => token
9878 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9879 .map(|(_, id)| id.to_owned()),
9880 };
9881 if let Some(LanguageServerState::Running {
9882 workspace_diagnostics_refresh_tasks,
9883 ..
9884 }) = self
9885 .as_local_mut()
9886 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9887 && let Some(workspace_diagnostics) =
9888 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9889 {
9890 workspace_diagnostics.progress_tx.try_send(()).ok();
9891 self.apply_workspace_diagnostic_report(
9892 language_server_id,
9893 report,
9894 registration_id.map(SharedString::from),
9895 cx,
9896 )
9897 }
9898 }
9899 }
9900 }
9901
9902 fn handle_work_done_progress(
9903 &mut self,
9904 progress: lsp::WorkDoneProgress,
9905 language_server_id: LanguageServerId,
9906 disk_based_diagnostics_progress_token: Option<String>,
9907 token: ProgressToken,
9908 cx: &mut Context<Self>,
9909 ) {
9910 let language_server_status =
9911 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9912 status
9913 } else {
9914 return;
9915 };
9916
9917 if !language_server_status.progress_tokens.contains(&token) {
9918 return;
9919 }
9920
9921 let is_disk_based_diagnostics_progress =
9922 if let (Some(disk_based_token), ProgressToken::String(token)) =
9923 (&disk_based_diagnostics_progress_token, &token)
9924 {
9925 token.starts_with(disk_based_token)
9926 } else {
9927 false
9928 };
9929
9930 match progress {
9931 lsp::WorkDoneProgress::Begin(report) => {
9932 if is_disk_based_diagnostics_progress {
9933 self.disk_based_diagnostics_started(language_server_id, cx);
9934 }
9935 self.on_lsp_work_start(
9936 language_server_id,
9937 token.clone(),
9938 LanguageServerProgress {
9939 title: Some(report.title),
9940 is_disk_based_diagnostics_progress,
9941 is_cancellable: report.cancellable.unwrap_or(false),
9942 message: report.message.clone(),
9943 percentage: report.percentage.map(|p| p as usize),
9944 last_update_at: cx.background_executor().now(),
9945 },
9946 cx,
9947 );
9948 }
9949 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9950 language_server_id,
9951 token,
9952 LanguageServerProgress {
9953 title: None,
9954 is_disk_based_diagnostics_progress,
9955 is_cancellable: report.cancellable.unwrap_or(false),
9956 message: report.message,
9957 percentage: report.percentage.map(|p| p as usize),
9958 last_update_at: cx.background_executor().now(),
9959 },
9960 cx,
9961 ),
9962 lsp::WorkDoneProgress::End(_) => {
9963 language_server_status.progress_tokens.remove(&token);
9964 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9965 if is_disk_based_diagnostics_progress {
9966 self.disk_based_diagnostics_finished(language_server_id, cx);
9967 }
9968 }
9969 }
9970 }
9971
9972 fn on_lsp_work_start(
9973 &mut self,
9974 language_server_id: LanguageServerId,
9975 token: ProgressToken,
9976 progress: LanguageServerProgress,
9977 cx: &mut Context<Self>,
9978 ) {
9979 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9980 status.pending_work.insert(token.clone(), progress.clone());
9981 cx.notify();
9982 }
9983 cx.emit(LspStoreEvent::LanguageServerUpdate {
9984 language_server_id,
9985 name: self
9986 .language_server_adapter_for_id(language_server_id)
9987 .map(|adapter| adapter.name()),
9988 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9989 token: Some(token.to_proto()),
9990 title: progress.title,
9991 message: progress.message,
9992 percentage: progress.percentage.map(|p| p as u32),
9993 is_cancellable: Some(progress.is_cancellable),
9994 }),
9995 })
9996 }
9997
9998 fn on_lsp_work_progress(
9999 &mut self,
10000 language_server_id: LanguageServerId,
10001 token: ProgressToken,
10002 progress: LanguageServerProgress,
10003 cx: &mut Context<Self>,
10004 ) {
10005 let mut did_update = false;
10006 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10007 match status.pending_work.entry(token.clone()) {
10008 btree_map::Entry::Vacant(entry) => {
10009 entry.insert(progress.clone());
10010 did_update = true;
10011 }
10012 btree_map::Entry::Occupied(mut entry) => {
10013 let entry = entry.get_mut();
10014 if (progress.last_update_at - entry.last_update_at)
10015 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10016 {
10017 entry.last_update_at = progress.last_update_at;
10018 if progress.message.is_some() {
10019 entry.message = progress.message.clone();
10020 }
10021 if progress.percentage.is_some() {
10022 entry.percentage = progress.percentage;
10023 }
10024 if progress.is_cancellable != entry.is_cancellable {
10025 entry.is_cancellable = progress.is_cancellable;
10026 }
10027 did_update = true;
10028 }
10029 }
10030 }
10031 }
10032
10033 if did_update {
10034 cx.emit(LspStoreEvent::LanguageServerUpdate {
10035 language_server_id,
10036 name: self
10037 .language_server_adapter_for_id(language_server_id)
10038 .map(|adapter| adapter.name()),
10039 message: proto::update_language_server::Variant::WorkProgress(
10040 proto::LspWorkProgress {
10041 token: Some(token.to_proto()),
10042 message: progress.message,
10043 percentage: progress.percentage.map(|p| p as u32),
10044 is_cancellable: Some(progress.is_cancellable),
10045 },
10046 ),
10047 })
10048 }
10049 }
10050
10051 fn on_lsp_work_end(
10052 &mut self,
10053 language_server_id: LanguageServerId,
10054 token: ProgressToken,
10055 cx: &mut Context<Self>,
10056 ) {
10057 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10058 if let Some(work) = status.pending_work.remove(&token)
10059 && !work.is_disk_based_diagnostics_progress
10060 {
10061 cx.emit(LspStoreEvent::RefreshInlayHints {
10062 server_id: language_server_id,
10063 request_id: None,
10064 });
10065 }
10066 cx.notify();
10067 }
10068
10069 cx.emit(LspStoreEvent::LanguageServerUpdate {
10070 language_server_id,
10071 name: self
10072 .language_server_adapter_for_id(language_server_id)
10073 .map(|adapter| adapter.name()),
10074 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10075 token: Some(token.to_proto()),
10076 }),
10077 })
10078 }
10079
10080 pub async fn handle_resolve_completion_documentation(
10081 this: Entity<Self>,
10082 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10083 mut cx: AsyncApp,
10084 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10085 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10086
10087 let completion = this
10088 .read_with(&cx, |this, cx| {
10089 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10090 let server = this
10091 .language_server_for_id(id)
10092 .with_context(|| format!("No language server {id}"))?;
10093
10094 let request_timeout = ProjectSettings::get_global(cx)
10095 .global_lsp_settings
10096 .get_request_timeout();
10097
10098 anyhow::Ok(cx.background_spawn(async move {
10099 let can_resolve = server
10100 .capabilities()
10101 .completion_provider
10102 .as_ref()
10103 .and_then(|options| options.resolve_provider)
10104 .unwrap_or(false);
10105 if can_resolve {
10106 server
10107 .request::<lsp::request::ResolveCompletionItem>(
10108 lsp_completion,
10109 request_timeout,
10110 )
10111 .await
10112 .into_response()
10113 .context("resolve completion item")
10114 } else {
10115 anyhow::Ok(lsp_completion)
10116 }
10117 }))
10118 })?
10119 .await?;
10120
10121 let mut documentation_is_markdown = false;
10122 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10123 let documentation = match completion.documentation {
10124 Some(lsp::Documentation::String(text)) => text,
10125
10126 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10127 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10128 value
10129 }
10130
10131 _ => String::new(),
10132 };
10133
10134 // If we have a new buffer_id, that means we're talking to a new client
10135 // and want to check for new text_edits in the completion too.
10136 let mut old_replace_start = None;
10137 let mut old_replace_end = None;
10138 let mut old_insert_start = None;
10139 let mut old_insert_end = None;
10140 let mut new_text = String::default();
10141 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10142 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10143 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10144 anyhow::Ok(buffer.read(cx).snapshot())
10145 })?;
10146
10147 if let Some(text_edit) = completion.text_edit.as_ref() {
10148 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10149
10150 if let Some(mut edit) = edit {
10151 LineEnding::normalize(&mut edit.new_text);
10152
10153 new_text = edit.new_text;
10154 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10155 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10156 if let Some(insert_range) = edit.insert_range {
10157 old_insert_start = Some(serialize_anchor(&insert_range.start));
10158 old_insert_end = Some(serialize_anchor(&insert_range.end));
10159 }
10160 }
10161 }
10162 }
10163
10164 Ok(proto::ResolveCompletionDocumentationResponse {
10165 documentation,
10166 documentation_is_markdown,
10167 old_replace_start,
10168 old_replace_end,
10169 new_text,
10170 lsp_completion,
10171 old_insert_start,
10172 old_insert_end,
10173 })
10174 }
10175
10176 async fn handle_on_type_formatting(
10177 this: Entity<Self>,
10178 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10179 mut cx: AsyncApp,
10180 ) -> Result<proto::OnTypeFormattingResponse> {
10181 let on_type_formatting = this.update(&mut cx, |this, cx| {
10182 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10183 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10184 let position = envelope
10185 .payload
10186 .position
10187 .and_then(deserialize_anchor)
10188 .context("invalid position")?;
10189 anyhow::Ok(this.apply_on_type_formatting(
10190 buffer,
10191 position,
10192 envelope.payload.trigger.clone(),
10193 cx,
10194 ))
10195 })?;
10196
10197 let transaction = on_type_formatting
10198 .await?
10199 .as_ref()
10200 .map(language::proto::serialize_transaction);
10201 Ok(proto::OnTypeFormattingResponse { transaction })
10202 }
10203
10204 async fn handle_pull_workspace_diagnostics(
10205 lsp_store: Entity<Self>,
10206 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10207 mut cx: AsyncApp,
10208 ) -> Result<proto::Ack> {
10209 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10210 lsp_store.update(&mut cx, |lsp_store, _| {
10211 lsp_store.pull_workspace_diagnostics(server_id);
10212 });
10213 Ok(proto::Ack {})
10214 }
10215
10216 async fn handle_open_buffer_for_symbol(
10217 this: Entity<Self>,
10218 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10219 mut cx: AsyncApp,
10220 ) -> Result<proto::OpenBufferForSymbolResponse> {
10221 let peer_id = envelope.original_sender_id().unwrap_or_default();
10222 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10223 let symbol = Self::deserialize_symbol(symbol)?;
10224 this.read_with(&cx, |this, _| {
10225 if let SymbolLocation::OutsideProject {
10226 abs_path,
10227 signature,
10228 } = &symbol.path
10229 {
10230 let new_signature = this.symbol_signature(&abs_path);
10231 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10232 }
10233 Ok(())
10234 })?;
10235 let buffer = this
10236 .update(&mut cx, |this, cx| {
10237 this.open_buffer_for_symbol(
10238 &Symbol {
10239 language_server_name: symbol.language_server_name,
10240 source_worktree_id: symbol.source_worktree_id,
10241 source_language_server_id: symbol.source_language_server_id,
10242 path: symbol.path,
10243 name: symbol.name,
10244 kind: symbol.kind,
10245 range: symbol.range,
10246 label: CodeLabel::default(),
10247 container_name: symbol.container_name,
10248 },
10249 cx,
10250 )
10251 })
10252 .await?;
10253
10254 this.update(&mut cx, |this, cx| {
10255 let is_private = buffer
10256 .read(cx)
10257 .file()
10258 .map(|f| f.is_private())
10259 .unwrap_or_default();
10260 if is_private {
10261 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10262 } else {
10263 this.buffer_store
10264 .update(cx, |buffer_store, cx| {
10265 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10266 })
10267 .detach_and_log_err(cx);
10268 let buffer_id = buffer.read(cx).remote_id().to_proto();
10269 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10270 }
10271 })
10272 }
10273
10274 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10275 let mut hasher = Sha256::new();
10276 hasher.update(abs_path.to_string_lossy().as_bytes());
10277 hasher.update(self.nonce.to_be_bytes());
10278 hasher.finalize().as_slice().try_into().unwrap()
10279 }
10280
10281 pub async fn handle_get_project_symbols(
10282 this: Entity<Self>,
10283 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10284 mut cx: AsyncApp,
10285 ) -> Result<proto::GetProjectSymbolsResponse> {
10286 let symbols = this
10287 .update(&mut cx, |this, cx| {
10288 this.symbols(&envelope.payload.query, cx)
10289 })
10290 .await?;
10291
10292 Ok(proto::GetProjectSymbolsResponse {
10293 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10294 })
10295 }
10296
10297 pub async fn handle_restart_language_servers(
10298 this: Entity<Self>,
10299 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10300 mut cx: AsyncApp,
10301 ) -> Result<proto::Ack> {
10302 this.update(&mut cx, |lsp_store, cx| {
10303 let buffers =
10304 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10305 lsp_store.restart_language_servers_for_buffers(
10306 buffers,
10307 envelope
10308 .payload
10309 .only_servers
10310 .into_iter()
10311 .filter_map(|selector| {
10312 Some(match selector.selector? {
10313 proto::language_server_selector::Selector::ServerId(server_id) => {
10314 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10315 }
10316 proto::language_server_selector::Selector::Name(name) => {
10317 LanguageServerSelector::Name(LanguageServerName(
10318 SharedString::from(name),
10319 ))
10320 }
10321 })
10322 })
10323 .collect(),
10324 cx,
10325 );
10326 });
10327
10328 Ok(proto::Ack {})
10329 }
10330
10331 pub async fn handle_stop_language_servers(
10332 lsp_store: Entity<Self>,
10333 envelope: TypedEnvelope<proto::StopLanguageServers>,
10334 mut cx: AsyncApp,
10335 ) -> Result<proto::Ack> {
10336 lsp_store.update(&mut cx, |lsp_store, cx| {
10337 if envelope.payload.all
10338 && envelope.payload.also_servers.is_empty()
10339 && envelope.payload.buffer_ids.is_empty()
10340 {
10341 lsp_store.stop_all_language_servers(cx);
10342 } else {
10343 let buffers =
10344 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10345 lsp_store
10346 .stop_language_servers_for_buffers(
10347 buffers,
10348 envelope
10349 .payload
10350 .also_servers
10351 .into_iter()
10352 .filter_map(|selector| {
10353 Some(match selector.selector? {
10354 proto::language_server_selector::Selector::ServerId(
10355 server_id,
10356 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10357 server_id,
10358 )),
10359 proto::language_server_selector::Selector::Name(name) => {
10360 LanguageServerSelector::Name(LanguageServerName(
10361 SharedString::from(name),
10362 ))
10363 }
10364 })
10365 })
10366 .collect(),
10367 cx,
10368 )
10369 .detach_and_log_err(cx);
10370 }
10371 });
10372
10373 Ok(proto::Ack {})
10374 }
10375
10376 pub async fn handle_cancel_language_server_work(
10377 lsp_store: Entity<Self>,
10378 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10379 mut cx: AsyncApp,
10380 ) -> Result<proto::Ack> {
10381 lsp_store.update(&mut cx, |lsp_store, cx| {
10382 if let Some(work) = envelope.payload.work {
10383 match work {
10384 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10385 let buffers =
10386 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10387 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10388 }
10389 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10390 let server_id = LanguageServerId::from_proto(work.language_server_id);
10391 let token = work
10392 .token
10393 .map(|token| {
10394 ProgressToken::from_proto(token)
10395 .context("invalid work progress token")
10396 })
10397 .transpose()?;
10398 lsp_store.cancel_language_server_work(server_id, token, cx);
10399 }
10400 }
10401 }
10402 anyhow::Ok(())
10403 })?;
10404
10405 Ok(proto::Ack {})
10406 }
10407
10408 fn buffer_ids_to_buffers(
10409 &mut self,
10410 buffer_ids: impl Iterator<Item = u64>,
10411 cx: &mut Context<Self>,
10412 ) -> Vec<Entity<Buffer>> {
10413 buffer_ids
10414 .into_iter()
10415 .flat_map(|buffer_id| {
10416 self.buffer_store
10417 .read(cx)
10418 .get(BufferId::new(buffer_id).log_err()?)
10419 })
10420 .collect::<Vec<_>>()
10421 }
10422
10423 async fn handle_apply_additional_edits_for_completion(
10424 this: Entity<Self>,
10425 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10426 mut cx: AsyncApp,
10427 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10428 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10429 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10430 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10431 let completion = Self::deserialize_completion(
10432 envelope.payload.completion.context("invalid completion")?,
10433 )?;
10434 anyhow::Ok((buffer, completion))
10435 })?;
10436
10437 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10438 this.apply_additional_edits_for_completion(
10439 buffer,
10440 Rc::new(RefCell::new(Box::new([Completion {
10441 replace_range: completion.replace_range,
10442 new_text: completion.new_text,
10443 source: completion.source,
10444 documentation: None,
10445 label: CodeLabel::default(),
10446 match_start: None,
10447 snippet_deduplication_key: None,
10448 insert_text_mode: None,
10449 icon_path: None,
10450 confirm: None,
10451 }]))),
10452 0,
10453 false,
10454 cx,
10455 )
10456 });
10457
10458 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10459 transaction: apply_additional_edits
10460 .await?
10461 .as_ref()
10462 .map(language::proto::serialize_transaction),
10463 })
10464 }
10465
10466 pub fn last_formatting_failure(&self) -> Option<&str> {
10467 self.last_formatting_failure.as_deref()
10468 }
10469
10470 pub fn reset_last_formatting_failure(&mut self) {
10471 self.last_formatting_failure = None;
10472 }
10473
10474 pub fn environment_for_buffer(
10475 &self,
10476 buffer: &Entity<Buffer>,
10477 cx: &mut Context<Self>,
10478 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10479 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10480 environment.update(cx, |env, cx| {
10481 env.buffer_environment(buffer, &self.worktree_store, cx)
10482 })
10483 } else {
10484 Task::ready(None).shared()
10485 }
10486 }
10487
10488 pub fn format(
10489 &mut self,
10490 buffers: HashSet<Entity<Buffer>>,
10491 target: LspFormatTarget,
10492 push_to_history: bool,
10493 trigger: FormatTrigger,
10494 cx: &mut Context<Self>,
10495 ) -> Task<anyhow::Result<ProjectTransaction>> {
10496 let logger = zlog::scoped!("format");
10497 if self.as_local().is_some() {
10498 zlog::trace!(logger => "Formatting locally");
10499 let logger = zlog::scoped!(logger => "local");
10500 let buffers = buffers
10501 .into_iter()
10502 .map(|buffer_handle| {
10503 let buffer = buffer_handle.read(cx);
10504 let buffer_abs_path = File::from_dyn(buffer.file())
10505 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10506
10507 (buffer_handle, buffer_abs_path, buffer.remote_id())
10508 })
10509 .collect::<Vec<_>>();
10510
10511 cx.spawn(async move |lsp_store, cx| {
10512 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10513
10514 for (handle, abs_path, id) in buffers {
10515 let env = lsp_store
10516 .update(cx, |lsp_store, cx| {
10517 lsp_store.environment_for_buffer(&handle, cx)
10518 })?
10519 .await;
10520
10521 let ranges = match &target {
10522 LspFormatTarget::Buffers => None,
10523 LspFormatTarget::Ranges(ranges) => {
10524 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10525 }
10526 };
10527
10528 formattable_buffers.push(FormattableBuffer {
10529 handle,
10530 abs_path,
10531 env,
10532 ranges,
10533 });
10534 }
10535 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10536
10537 let format_timer = zlog::time!(logger => "Formatting buffers");
10538 let result = LocalLspStore::format_locally(
10539 lsp_store.clone(),
10540 formattable_buffers,
10541 push_to_history,
10542 trigger,
10543 logger,
10544 cx,
10545 )
10546 .await;
10547 format_timer.end();
10548
10549 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10550
10551 lsp_store.update(cx, |lsp_store, _| {
10552 lsp_store.update_last_formatting_failure(&result);
10553 })?;
10554
10555 result
10556 })
10557 } else if let Some((client, project_id)) = self.upstream_client() {
10558 zlog::trace!(logger => "Formatting remotely");
10559 let logger = zlog::scoped!(logger => "remote");
10560
10561 let buffer_ranges = match &target {
10562 LspFormatTarget::Buffers => Vec::new(),
10563 LspFormatTarget::Ranges(ranges) => ranges
10564 .iter()
10565 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10566 buffer_id: buffer_id.to_proto(),
10567 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10568 })
10569 .collect(),
10570 };
10571
10572 let buffer_store = self.buffer_store();
10573 cx.spawn(async move |lsp_store, cx| {
10574 zlog::trace!(logger => "Sending remote format request");
10575 let request_timer = zlog::time!(logger => "remote format request");
10576 let result = client
10577 .request(proto::FormatBuffers {
10578 project_id,
10579 trigger: trigger as i32,
10580 buffer_ids: buffers
10581 .iter()
10582 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10583 .collect(),
10584 buffer_ranges,
10585 })
10586 .await
10587 .and_then(|result| result.transaction.context("missing transaction"));
10588 request_timer.end();
10589
10590 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10591
10592 lsp_store.update(cx, |lsp_store, _| {
10593 lsp_store.update_last_formatting_failure(&result);
10594 })?;
10595
10596 let transaction_response = result?;
10597 let _timer = zlog::time!(logger => "deserializing project transaction");
10598 buffer_store
10599 .update(cx, |buffer_store, cx| {
10600 buffer_store.deserialize_project_transaction(
10601 transaction_response,
10602 push_to_history,
10603 cx,
10604 )
10605 })
10606 .await
10607 })
10608 } else {
10609 zlog::trace!(logger => "Not formatting");
10610 Task::ready(Ok(ProjectTransaction::default()))
10611 }
10612 }
10613
10614 async fn handle_format_buffers(
10615 this: Entity<Self>,
10616 envelope: TypedEnvelope<proto::FormatBuffers>,
10617 mut cx: AsyncApp,
10618 ) -> Result<proto::FormatBuffersResponse> {
10619 let sender_id = envelope.original_sender_id().unwrap_or_default();
10620 let format = this.update(&mut cx, |this, cx| {
10621 let mut buffers = HashSet::default();
10622 for buffer_id in &envelope.payload.buffer_ids {
10623 let buffer_id = BufferId::new(*buffer_id)?;
10624 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10625 }
10626
10627 let target = if envelope.payload.buffer_ranges.is_empty() {
10628 LspFormatTarget::Buffers
10629 } else {
10630 let mut ranges_map = BTreeMap::new();
10631 for buffer_range in &envelope.payload.buffer_ranges {
10632 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10633 let ranges: Result<Vec<_>> = buffer_range
10634 .ranges
10635 .iter()
10636 .map(|range| {
10637 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10638 })
10639 .collect();
10640 ranges_map.insert(buffer_id, ranges?);
10641 }
10642 LspFormatTarget::Ranges(ranges_map)
10643 };
10644
10645 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10646 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10647 })?;
10648
10649 let project_transaction = format.await?;
10650 let project_transaction = this.update(&mut cx, |this, cx| {
10651 this.buffer_store.update(cx, |buffer_store, cx| {
10652 buffer_store.serialize_project_transaction_for_peer(
10653 project_transaction,
10654 sender_id,
10655 cx,
10656 )
10657 })
10658 });
10659 Ok(proto::FormatBuffersResponse {
10660 transaction: Some(project_transaction),
10661 })
10662 }
10663
10664 async fn handle_apply_code_action_kind(
10665 this: Entity<Self>,
10666 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10667 mut cx: AsyncApp,
10668 ) -> Result<proto::ApplyCodeActionKindResponse> {
10669 let sender_id = envelope.original_sender_id().unwrap_or_default();
10670 let format = this.update(&mut cx, |this, cx| {
10671 let mut buffers = HashSet::default();
10672 for buffer_id in &envelope.payload.buffer_ids {
10673 let buffer_id = BufferId::new(*buffer_id)?;
10674 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10675 }
10676 let kind = match envelope.payload.kind.as_str() {
10677 "" => CodeActionKind::EMPTY,
10678 "quickfix" => CodeActionKind::QUICKFIX,
10679 "refactor" => CodeActionKind::REFACTOR,
10680 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10681 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10682 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10683 "source" => CodeActionKind::SOURCE,
10684 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10685 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10686 _ => anyhow::bail!(
10687 "Invalid code action kind {}",
10688 envelope.payload.kind.as_str()
10689 ),
10690 };
10691 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10692 })?;
10693
10694 let project_transaction = format.await?;
10695 let project_transaction = this.update(&mut cx, |this, cx| {
10696 this.buffer_store.update(cx, |buffer_store, cx| {
10697 buffer_store.serialize_project_transaction_for_peer(
10698 project_transaction,
10699 sender_id,
10700 cx,
10701 )
10702 })
10703 });
10704 Ok(proto::ApplyCodeActionKindResponse {
10705 transaction: Some(project_transaction),
10706 })
10707 }
10708
10709 async fn shutdown_language_server(
10710 server_state: Option<LanguageServerState>,
10711 name: LanguageServerName,
10712 cx: &mut AsyncApp,
10713 ) {
10714 let server = match server_state {
10715 Some(LanguageServerState::Starting { startup, .. }) => {
10716 let mut timer = cx
10717 .background_executor()
10718 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10719 .fuse();
10720
10721 select! {
10722 server = startup.fuse() => server,
10723 () = timer => {
10724 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10725 None
10726 },
10727 }
10728 }
10729
10730 Some(LanguageServerState::Running { server, .. }) => Some(server),
10731
10732 None => None,
10733 };
10734
10735 let Some(server) = server else { return };
10736 if let Some(shutdown) = server.shutdown() {
10737 shutdown.await;
10738 }
10739 }
10740
10741 // Returns a list of all of the worktrees which no longer have a language server and the root path
10742 // for the stopped server
10743 fn stop_local_language_server(
10744 &mut self,
10745 server_id: LanguageServerId,
10746 cx: &mut Context<Self>,
10747 ) -> Task<()> {
10748 let local = match &mut self.mode {
10749 LspStoreMode::Local(local) => local,
10750 _ => {
10751 return Task::ready(());
10752 }
10753 };
10754
10755 // Remove this server ID from all entries in the given worktree.
10756 local
10757 .language_server_ids
10758 .retain(|_, state| state.id != server_id);
10759 self.buffer_store.update(cx, |buffer_store, cx| {
10760 for buffer in buffer_store.buffers() {
10761 buffer.update(cx, |buffer, cx| {
10762 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10763 buffer.set_completion_triggers(server_id, Default::default(), cx);
10764 });
10765 }
10766 });
10767
10768 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10769 summaries.retain(|path, summaries_by_server_id| {
10770 if summaries_by_server_id.remove(&server_id).is_some() {
10771 if let Some((client, project_id)) = self.downstream_client.clone() {
10772 client
10773 .send(proto::UpdateDiagnosticSummary {
10774 project_id,
10775 worktree_id: worktree_id.to_proto(),
10776 summary: Some(proto::DiagnosticSummary {
10777 path: path.as_ref().to_proto(),
10778 language_server_id: server_id.0 as u64,
10779 error_count: 0,
10780 warning_count: 0,
10781 }),
10782 more_summaries: Vec::new(),
10783 })
10784 .log_err();
10785 }
10786 !summaries_by_server_id.is_empty()
10787 } else {
10788 true
10789 }
10790 });
10791 }
10792
10793 let local = self.as_local_mut().unwrap();
10794 for diagnostics in local.diagnostics.values_mut() {
10795 diagnostics.retain(|_, diagnostics_by_server_id| {
10796 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10797 diagnostics_by_server_id.remove(ix);
10798 !diagnostics_by_server_id.is_empty()
10799 } else {
10800 true
10801 }
10802 });
10803 }
10804 local.language_server_watched_paths.remove(&server_id);
10805
10806 let server_state = local.language_servers.remove(&server_id);
10807 self.cleanup_lsp_data(server_id);
10808 let name = self
10809 .language_server_statuses
10810 .remove(&server_id)
10811 .map(|status| status.name)
10812 .or_else(|| {
10813 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10814 Some(adapter.name())
10815 } else {
10816 None
10817 }
10818 });
10819
10820 if let Some(name) = name {
10821 log::info!("stopping language server {name}");
10822 self.languages
10823 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10824 cx.notify();
10825
10826 return cx.spawn(async move |lsp_store, cx| {
10827 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10828 lsp_store
10829 .update(cx, |lsp_store, cx| {
10830 lsp_store
10831 .languages
10832 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10833 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10834 cx.notify();
10835 })
10836 .ok();
10837 });
10838 }
10839
10840 if server_state.is_some() {
10841 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10842 }
10843 Task::ready(())
10844 }
10845
10846 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10847 self.shutdown_all_language_servers(cx).detach();
10848 }
10849
10850 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10851 if let Some((client, project_id)) = self.upstream_client() {
10852 let request = client.request(proto::StopLanguageServers {
10853 project_id,
10854 buffer_ids: Vec::new(),
10855 also_servers: Vec::new(),
10856 all: true,
10857 });
10858 cx.background_spawn(async move {
10859 request.await.ok();
10860 })
10861 } else {
10862 let Some(local) = self.as_local_mut() else {
10863 return Task::ready(());
10864 };
10865 let language_servers_to_stop = local
10866 .language_server_ids
10867 .values()
10868 .map(|state| state.id)
10869 .collect();
10870 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10871 let tasks = language_servers_to_stop
10872 .into_iter()
10873 .map(|server| self.stop_local_language_server(server, cx))
10874 .collect::<Vec<_>>();
10875 cx.background_spawn(async move {
10876 futures::future::join_all(tasks).await;
10877 })
10878 }
10879 }
10880
10881 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10882 let buffers = self.buffer_store.read(cx).buffers().collect();
10883 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10884 }
10885
10886 pub fn restart_language_servers_for_buffers(
10887 &mut self,
10888 buffers: Vec<Entity<Buffer>>,
10889 only_restart_servers: HashSet<LanguageServerSelector>,
10890 cx: &mut Context<Self>,
10891 ) {
10892 if let Some((client, project_id)) = self.upstream_client() {
10893 let request = client.request(proto::RestartLanguageServers {
10894 project_id,
10895 buffer_ids: buffers
10896 .into_iter()
10897 .map(|b| b.read(cx).remote_id().to_proto())
10898 .collect(),
10899 only_servers: only_restart_servers
10900 .into_iter()
10901 .map(|selector| {
10902 let selector = match selector {
10903 LanguageServerSelector::Id(language_server_id) => {
10904 proto::language_server_selector::Selector::ServerId(
10905 language_server_id.to_proto(),
10906 )
10907 }
10908 LanguageServerSelector::Name(language_server_name) => {
10909 proto::language_server_selector::Selector::Name(
10910 language_server_name.to_string(),
10911 )
10912 }
10913 };
10914 proto::LanguageServerSelector {
10915 selector: Some(selector),
10916 }
10917 })
10918 .collect(),
10919 all: false,
10920 });
10921 cx.background_spawn(request).detach_and_log_err(cx);
10922 } else {
10923 let stop_task = if only_restart_servers.is_empty() {
10924 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10925 } else {
10926 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10927 };
10928 cx.spawn(async move |lsp_store, cx| {
10929 stop_task.await;
10930 lsp_store.update(cx, |lsp_store, cx| {
10931 for buffer in buffers {
10932 lsp_store.register_buffer_with_language_servers(
10933 &buffer,
10934 only_restart_servers.clone(),
10935 true,
10936 cx,
10937 );
10938 }
10939 })
10940 })
10941 .detach();
10942 }
10943 }
10944
10945 pub fn stop_language_servers_for_buffers(
10946 &mut self,
10947 buffers: Vec<Entity<Buffer>>,
10948 also_stop_servers: HashSet<LanguageServerSelector>,
10949 cx: &mut Context<Self>,
10950 ) -> Task<Result<()>> {
10951 if let Some((client, project_id)) = self.upstream_client() {
10952 let request = client.request(proto::StopLanguageServers {
10953 project_id,
10954 buffer_ids: buffers
10955 .into_iter()
10956 .map(|b| b.read(cx).remote_id().to_proto())
10957 .collect(),
10958 also_servers: also_stop_servers
10959 .into_iter()
10960 .map(|selector| {
10961 let selector = match selector {
10962 LanguageServerSelector::Id(language_server_id) => {
10963 proto::language_server_selector::Selector::ServerId(
10964 language_server_id.to_proto(),
10965 )
10966 }
10967 LanguageServerSelector::Name(language_server_name) => {
10968 proto::language_server_selector::Selector::Name(
10969 language_server_name.to_string(),
10970 )
10971 }
10972 };
10973 proto::LanguageServerSelector {
10974 selector: Some(selector),
10975 }
10976 })
10977 .collect(),
10978 all: false,
10979 });
10980 cx.background_spawn(async move {
10981 let _ = request.await?;
10982 Ok(())
10983 })
10984 } else {
10985 let task =
10986 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10987 cx.background_spawn(async move {
10988 task.await;
10989 Ok(())
10990 })
10991 }
10992 }
10993
10994 fn stop_local_language_servers_for_buffers(
10995 &mut self,
10996 buffers: &[Entity<Buffer>],
10997 also_stop_servers: HashSet<LanguageServerSelector>,
10998 cx: &mut Context<Self>,
10999 ) -> Task<()> {
11000 let Some(local) = self.as_local_mut() else {
11001 return Task::ready(());
11002 };
11003 let mut language_server_names_to_stop = BTreeSet::default();
11004 let mut language_servers_to_stop = also_stop_servers
11005 .into_iter()
11006 .flat_map(|selector| match selector {
11007 LanguageServerSelector::Id(id) => Some(id),
11008 LanguageServerSelector::Name(name) => {
11009 language_server_names_to_stop.insert(name);
11010 None
11011 }
11012 })
11013 .collect::<BTreeSet<_>>();
11014
11015 let mut covered_worktrees = HashSet::default();
11016 for buffer in buffers {
11017 buffer.update(cx, |buffer, cx| {
11018 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11019 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11020 && covered_worktrees.insert(worktree_id)
11021 {
11022 language_server_names_to_stop.retain(|name| {
11023 let old_ids_count = language_servers_to_stop.len();
11024 let all_language_servers_with_this_name = local
11025 .language_server_ids
11026 .iter()
11027 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11028 language_servers_to_stop.extend(all_language_servers_with_this_name);
11029 old_ids_count == language_servers_to_stop.len()
11030 });
11031 }
11032 });
11033 }
11034 for name in language_server_names_to_stop {
11035 language_servers_to_stop.extend(
11036 local
11037 .language_server_ids
11038 .iter()
11039 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11040 );
11041 }
11042
11043 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11044 let tasks = language_servers_to_stop
11045 .into_iter()
11046 .map(|server| self.stop_local_language_server(server, cx))
11047 .collect::<Vec<_>>();
11048
11049 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11050 }
11051
11052 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11053 let (worktree, relative_path) =
11054 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11055
11056 let project_path = ProjectPath {
11057 worktree_id: worktree.read(cx).id(),
11058 path: relative_path,
11059 };
11060
11061 Some(
11062 self.buffer_store()
11063 .read(cx)
11064 .get_by_path(&project_path)?
11065 .read(cx),
11066 )
11067 }
11068
11069 #[cfg(any(test, feature = "test-support"))]
11070 pub fn update_diagnostics(
11071 &mut self,
11072 server_id: LanguageServerId,
11073 diagnostics: lsp::PublishDiagnosticsParams,
11074 result_id: Option<SharedString>,
11075 source_kind: DiagnosticSourceKind,
11076 disk_based_sources: &[String],
11077 cx: &mut Context<Self>,
11078 ) -> Result<()> {
11079 self.merge_lsp_diagnostics(
11080 source_kind,
11081 vec![DocumentDiagnosticsUpdate {
11082 diagnostics,
11083 result_id,
11084 server_id,
11085 disk_based_sources: Cow::Borrowed(disk_based_sources),
11086 registration_id: None,
11087 }],
11088 |_, _, _| false,
11089 cx,
11090 )
11091 }
11092
11093 pub fn merge_lsp_diagnostics(
11094 &mut self,
11095 source_kind: DiagnosticSourceKind,
11096 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11097 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11098 cx: &mut Context<Self>,
11099 ) -> Result<()> {
11100 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11101 let updates = lsp_diagnostics
11102 .into_iter()
11103 .filter_map(|update| {
11104 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11105 Some(DocumentDiagnosticsUpdate {
11106 diagnostics: self.lsp_to_document_diagnostics(
11107 abs_path,
11108 source_kind,
11109 update.server_id,
11110 update.diagnostics,
11111 &update.disk_based_sources,
11112 update.registration_id.clone(),
11113 ),
11114 result_id: update.result_id,
11115 server_id: update.server_id,
11116 disk_based_sources: update.disk_based_sources,
11117 registration_id: update.registration_id,
11118 })
11119 })
11120 .collect();
11121 self.merge_diagnostic_entries(updates, merge, cx)?;
11122 Ok(())
11123 }
11124
11125 fn lsp_to_document_diagnostics(
11126 &mut self,
11127 document_abs_path: PathBuf,
11128 source_kind: DiagnosticSourceKind,
11129 server_id: LanguageServerId,
11130 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11131 disk_based_sources: &[String],
11132 registration_id: Option<SharedString>,
11133 ) -> DocumentDiagnostics {
11134 let mut diagnostics = Vec::default();
11135 let mut primary_diagnostic_group_ids = HashMap::default();
11136 let mut sources_by_group_id = HashMap::default();
11137 let mut supporting_diagnostics = HashMap::default();
11138
11139 let adapter = self.language_server_adapter_for_id(server_id);
11140
11141 // Ensure that primary diagnostics are always the most severe
11142 lsp_diagnostics
11143 .diagnostics
11144 .sort_by_key(|item| item.severity);
11145
11146 for diagnostic in &lsp_diagnostics.diagnostics {
11147 let source = diagnostic.source.as_ref();
11148 let range = range_from_lsp(diagnostic.range);
11149 let is_supporting = diagnostic
11150 .related_information
11151 .as_ref()
11152 .is_some_and(|infos| {
11153 infos.iter().any(|info| {
11154 primary_diagnostic_group_ids.contains_key(&(
11155 source,
11156 diagnostic.code.clone(),
11157 range_from_lsp(info.location.range),
11158 ))
11159 })
11160 });
11161
11162 let is_unnecessary = diagnostic
11163 .tags
11164 .as_ref()
11165 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11166
11167 let underline = self
11168 .language_server_adapter_for_id(server_id)
11169 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11170
11171 if is_supporting {
11172 supporting_diagnostics.insert(
11173 (source, diagnostic.code.clone(), range),
11174 (diagnostic.severity, is_unnecessary),
11175 );
11176 } else {
11177 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11178 let is_disk_based =
11179 source.is_some_and(|source| disk_based_sources.contains(source));
11180
11181 sources_by_group_id.insert(group_id, source);
11182 primary_diagnostic_group_ids
11183 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11184
11185 diagnostics.push(DiagnosticEntry {
11186 range,
11187 diagnostic: Diagnostic {
11188 source: diagnostic.source.clone(),
11189 source_kind,
11190 code: diagnostic.code.clone(),
11191 code_description: diagnostic
11192 .code_description
11193 .as_ref()
11194 .and_then(|d| d.href.clone()),
11195 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11196 markdown: adapter.as_ref().and_then(|adapter| {
11197 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11198 }),
11199 message: diagnostic.message.trim().to_string(),
11200 group_id,
11201 is_primary: true,
11202 is_disk_based,
11203 is_unnecessary,
11204 underline,
11205 data: diagnostic.data.clone(),
11206 registration_id: registration_id.clone(),
11207 },
11208 });
11209 if let Some(infos) = &diagnostic.related_information {
11210 for info in infos {
11211 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11212 let range = range_from_lsp(info.location.range);
11213 diagnostics.push(DiagnosticEntry {
11214 range,
11215 diagnostic: Diagnostic {
11216 source: diagnostic.source.clone(),
11217 source_kind,
11218 code: diagnostic.code.clone(),
11219 code_description: diagnostic
11220 .code_description
11221 .as_ref()
11222 .and_then(|d| d.href.clone()),
11223 severity: DiagnosticSeverity::INFORMATION,
11224 markdown: adapter.as_ref().and_then(|adapter| {
11225 adapter.diagnostic_message_to_markdown(&info.message)
11226 }),
11227 message: info.message.trim().to_string(),
11228 group_id,
11229 is_primary: false,
11230 is_disk_based,
11231 is_unnecessary: false,
11232 underline,
11233 data: diagnostic.data.clone(),
11234 registration_id: registration_id.clone(),
11235 },
11236 });
11237 }
11238 }
11239 }
11240 }
11241 }
11242
11243 for entry in &mut diagnostics {
11244 let diagnostic = &mut entry.diagnostic;
11245 if !diagnostic.is_primary {
11246 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11247 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11248 source,
11249 diagnostic.code.clone(),
11250 entry.range.clone(),
11251 )) {
11252 if let Some(severity) = severity {
11253 diagnostic.severity = severity;
11254 }
11255 diagnostic.is_unnecessary = is_unnecessary;
11256 }
11257 }
11258 }
11259
11260 DocumentDiagnostics {
11261 diagnostics,
11262 document_abs_path,
11263 version: lsp_diagnostics.version,
11264 }
11265 }
11266
11267 fn insert_newly_running_language_server(
11268 &mut self,
11269 adapter: Arc<CachedLspAdapter>,
11270 language_server: Arc<LanguageServer>,
11271 server_id: LanguageServerId,
11272 key: LanguageServerSeed,
11273 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11274 cx: &mut Context<Self>,
11275 ) {
11276 let Some(local) = self.as_local_mut() else {
11277 return;
11278 };
11279 // If the language server for this key doesn't match the server id, don't store the
11280 // server. Which will cause it to be dropped, killing the process
11281 if local
11282 .language_server_ids
11283 .get(&key)
11284 .map(|state| state.id != server_id)
11285 .unwrap_or(false)
11286 {
11287 return;
11288 }
11289
11290 // Update language_servers collection with Running variant of LanguageServerState
11291 // indicating that the server is up and running and ready
11292 let workspace_folders = workspace_folders.lock().clone();
11293 language_server.set_workspace_folders(workspace_folders);
11294
11295 let workspace_diagnostics_refresh_tasks = language_server
11296 .capabilities()
11297 .diagnostic_provider
11298 .and_then(|provider| {
11299 local
11300 .language_server_dynamic_registrations
11301 .entry(server_id)
11302 .or_default()
11303 .diagnostics
11304 .entry(None)
11305 .or_insert(provider.clone());
11306 let workspace_refresher =
11307 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11308
11309 Some((None, workspace_refresher))
11310 })
11311 .into_iter()
11312 .collect();
11313 local.language_servers.insert(
11314 server_id,
11315 LanguageServerState::Running {
11316 workspace_diagnostics_refresh_tasks,
11317 adapter: adapter.clone(),
11318 server: language_server.clone(),
11319 simulate_disk_based_diagnostics_completion: None,
11320 },
11321 );
11322 local
11323 .languages
11324 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11325 if let Some(file_ops_caps) = language_server
11326 .capabilities()
11327 .workspace
11328 .as_ref()
11329 .and_then(|ws| ws.file_operations.as_ref())
11330 {
11331 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11332 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11333 if did_rename_caps.or(will_rename_caps).is_some() {
11334 let watcher = RenamePathsWatchedForServer::default()
11335 .with_did_rename_patterns(did_rename_caps)
11336 .with_will_rename_patterns(will_rename_caps);
11337 local
11338 .language_server_paths_watched_for_rename
11339 .insert(server_id, watcher);
11340 }
11341 }
11342
11343 self.language_server_statuses.insert(
11344 server_id,
11345 LanguageServerStatus {
11346 name: language_server.name(),
11347 server_version: language_server.version(),
11348 pending_work: Default::default(),
11349 has_pending_diagnostic_updates: false,
11350 progress_tokens: Default::default(),
11351 worktree: Some(key.worktree_id),
11352 binary: Some(language_server.binary().clone()),
11353 configuration: Some(language_server.configuration().clone()),
11354 workspace_folders: language_server.workspace_folders(),
11355 process_id: language_server.process_id(),
11356 },
11357 );
11358
11359 cx.emit(LspStoreEvent::LanguageServerAdded(
11360 server_id,
11361 language_server.name(),
11362 Some(key.worktree_id),
11363 ));
11364
11365 let server_capabilities = language_server.capabilities();
11366 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11367 downstream_client
11368 .send(proto::StartLanguageServer {
11369 project_id: *project_id,
11370 server: Some(proto::LanguageServer {
11371 id: server_id.to_proto(),
11372 name: language_server.name().to_string(),
11373 worktree_id: Some(key.worktree_id.to_proto()),
11374 }),
11375 capabilities: serde_json::to_string(&server_capabilities)
11376 .expect("serializing server LSP capabilities"),
11377 })
11378 .log_err();
11379 }
11380 self.lsp_server_capabilities
11381 .insert(server_id, server_capabilities);
11382
11383 // Tell the language server about every open buffer in the worktree that matches the language.
11384 // Also check for buffers in worktrees that reused this server
11385 let mut worktrees_using_server = vec![key.worktree_id];
11386 if let Some(local) = self.as_local() {
11387 // Find all worktrees that have this server in their language server tree
11388 for (worktree_id, servers) in &local.lsp_tree.instances {
11389 if *worktree_id != key.worktree_id {
11390 for server_map in servers.roots.values() {
11391 if server_map
11392 .values()
11393 .any(|(node, _)| node.id() == Some(server_id))
11394 {
11395 worktrees_using_server.push(*worktree_id);
11396 }
11397 }
11398 }
11399 }
11400 }
11401
11402 let mut buffer_paths_registered = Vec::new();
11403 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11404 let mut lsp_adapters = HashMap::default();
11405 for buffer_handle in buffer_store.buffers() {
11406 let buffer = buffer_handle.read(cx);
11407 let file = match File::from_dyn(buffer.file()) {
11408 Some(file) => file,
11409 None => continue,
11410 };
11411 let language = match buffer.language() {
11412 Some(language) => language,
11413 None => continue,
11414 };
11415
11416 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11417 || !lsp_adapters
11418 .entry(language.name())
11419 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11420 .iter()
11421 .any(|a| a.name == key.name)
11422 {
11423 continue;
11424 }
11425 // didOpen
11426 let file = match file.as_local() {
11427 Some(file) => file,
11428 None => continue,
11429 };
11430
11431 let local = self.as_local_mut().unwrap();
11432
11433 let buffer_id = buffer.remote_id();
11434 if local.registered_buffers.contains_key(&buffer_id) {
11435 let versions = local
11436 .buffer_snapshots
11437 .entry(buffer_id)
11438 .or_default()
11439 .entry(server_id)
11440 .and_modify(|_| {
11441 assert!(
11442 false,
11443 "There should not be an existing snapshot for a newly inserted buffer"
11444 )
11445 })
11446 .or_insert_with(|| {
11447 vec![LspBufferSnapshot {
11448 version: 0,
11449 snapshot: buffer.text_snapshot(),
11450 }]
11451 });
11452
11453 let snapshot = versions.last().unwrap();
11454 let version = snapshot.version;
11455 let initial_snapshot = &snapshot.snapshot;
11456 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11457 language_server.register_buffer(
11458 uri,
11459 adapter.language_id(&language.name()),
11460 version,
11461 initial_snapshot.text(),
11462 );
11463 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11464 local
11465 .buffers_opened_in_servers
11466 .entry(buffer_id)
11467 .or_default()
11468 .insert(server_id);
11469 }
11470 buffer_handle.update(cx, |buffer, cx| {
11471 buffer.set_completion_triggers(
11472 server_id,
11473 language_server
11474 .capabilities()
11475 .completion_provider
11476 .as_ref()
11477 .and_then(|provider| {
11478 provider
11479 .trigger_characters
11480 .as_ref()
11481 .map(|characters| characters.iter().cloned().collect())
11482 })
11483 .unwrap_or_default(),
11484 cx,
11485 )
11486 });
11487 }
11488 });
11489
11490 for (buffer_id, abs_path) in buffer_paths_registered {
11491 cx.emit(LspStoreEvent::LanguageServerUpdate {
11492 language_server_id: server_id,
11493 name: Some(adapter.name()),
11494 message: proto::update_language_server::Variant::RegisteredForBuffer(
11495 proto::RegisteredForBuffer {
11496 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11497 buffer_id: buffer_id.to_proto(),
11498 },
11499 ),
11500 });
11501 }
11502
11503 cx.notify();
11504 }
11505
11506 pub fn language_servers_running_disk_based_diagnostics(
11507 &self,
11508 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11509 self.language_server_statuses
11510 .iter()
11511 .filter_map(|(id, status)| {
11512 if status.has_pending_diagnostic_updates {
11513 Some(*id)
11514 } else {
11515 None
11516 }
11517 })
11518 }
11519
11520 pub(crate) fn cancel_language_server_work_for_buffers(
11521 &mut self,
11522 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11523 cx: &mut Context<Self>,
11524 ) {
11525 if let Some((client, project_id)) = self.upstream_client() {
11526 let request = client.request(proto::CancelLanguageServerWork {
11527 project_id,
11528 work: Some(proto::cancel_language_server_work::Work::Buffers(
11529 proto::cancel_language_server_work::Buffers {
11530 buffer_ids: buffers
11531 .into_iter()
11532 .map(|b| b.read(cx).remote_id().to_proto())
11533 .collect(),
11534 },
11535 )),
11536 });
11537 cx.background_spawn(request).detach_and_log_err(cx);
11538 } else if let Some(local) = self.as_local() {
11539 let servers = buffers
11540 .into_iter()
11541 .flat_map(|buffer| {
11542 buffer.update(cx, |buffer, cx| {
11543 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11544 })
11545 })
11546 .collect::<HashSet<_>>();
11547 for server_id in servers {
11548 self.cancel_language_server_work(server_id, None, cx);
11549 }
11550 }
11551 }
11552
11553 pub(crate) fn cancel_language_server_work(
11554 &mut self,
11555 server_id: LanguageServerId,
11556 token_to_cancel: Option<ProgressToken>,
11557 cx: &mut Context<Self>,
11558 ) {
11559 if let Some(local) = self.as_local() {
11560 let status = self.language_server_statuses.get(&server_id);
11561 let server = local.language_servers.get(&server_id);
11562 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11563 {
11564 for (token, progress) in &status.pending_work {
11565 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11566 && token != token_to_cancel
11567 {
11568 continue;
11569 }
11570 if progress.is_cancellable {
11571 server
11572 .notify::<lsp::notification::WorkDoneProgressCancel>(
11573 WorkDoneProgressCancelParams {
11574 token: token.to_lsp(),
11575 },
11576 )
11577 .ok();
11578 }
11579 }
11580 }
11581 } else if let Some((client, project_id)) = self.upstream_client() {
11582 let request = client.request(proto::CancelLanguageServerWork {
11583 project_id,
11584 work: Some(
11585 proto::cancel_language_server_work::Work::LanguageServerWork(
11586 proto::cancel_language_server_work::LanguageServerWork {
11587 language_server_id: server_id.to_proto(),
11588 token: token_to_cancel.map(|token| token.to_proto()),
11589 },
11590 ),
11591 ),
11592 });
11593 cx.background_spawn(request).detach_and_log_err(cx);
11594 }
11595 }
11596
11597 fn register_supplementary_language_server(
11598 &mut self,
11599 id: LanguageServerId,
11600 name: LanguageServerName,
11601 server: Arc<LanguageServer>,
11602 cx: &mut Context<Self>,
11603 ) {
11604 if let Some(local) = self.as_local_mut() {
11605 local
11606 .supplementary_language_servers
11607 .insert(id, (name.clone(), server));
11608 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11609 }
11610 }
11611
11612 fn unregister_supplementary_language_server(
11613 &mut self,
11614 id: LanguageServerId,
11615 cx: &mut Context<Self>,
11616 ) {
11617 if let Some(local) = self.as_local_mut() {
11618 local.supplementary_language_servers.remove(&id);
11619 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11620 }
11621 }
11622
11623 pub(crate) fn supplementary_language_servers(
11624 &self,
11625 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11626 self.as_local().into_iter().flat_map(|local| {
11627 local
11628 .supplementary_language_servers
11629 .iter()
11630 .map(|(id, (name, _))| (*id, name.clone()))
11631 })
11632 }
11633
11634 pub fn language_server_adapter_for_id(
11635 &self,
11636 id: LanguageServerId,
11637 ) -> Option<Arc<CachedLspAdapter>> {
11638 self.as_local()
11639 .and_then(|local| local.language_servers.get(&id))
11640 .and_then(|language_server_state| match language_server_state {
11641 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11642 _ => None,
11643 })
11644 }
11645
11646 pub(super) fn update_local_worktree_language_servers(
11647 &mut self,
11648 worktree_handle: &Entity<Worktree>,
11649 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11650 cx: &mut Context<Self>,
11651 ) {
11652 if changes.is_empty() {
11653 return;
11654 }
11655
11656 let Some(local) = self.as_local() else { return };
11657
11658 local.prettier_store.update(cx, |prettier_store, cx| {
11659 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11660 });
11661
11662 let worktree_id = worktree_handle.read(cx).id();
11663 let mut language_server_ids = local
11664 .language_server_ids
11665 .iter()
11666 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11667 .collect::<Vec<_>>();
11668 language_server_ids.sort();
11669 language_server_ids.dedup();
11670
11671 let active_servers: Vec<(LanguageServerId, &LanguageServerWatchedPaths)> =
11672 language_server_ids
11673 .iter()
11674 .filter_map(|server_id| {
11675 if !matches!(
11676 local.language_servers.get(server_id),
11677 Some(LanguageServerState::Running { .. })
11678 ) {
11679 return None;
11680 }
11681 let watched_paths = local.language_server_watched_paths.get(server_id)?;
11682 Some((*server_id, watched_paths))
11683 })
11684 .collect();
11685
11686 for (server_id, watched_paths) in &active_servers {
11687 if let Some(LanguageServerState::Running { server, .. }) =
11688 local.language_servers.get(server_id)
11689 {
11690 let params = lsp::DidChangeWatchedFilesParams {
11691 changes: changes
11692 .iter()
11693 .filter_map(|(path, _, change)| {
11694 let candidate = Candidate::new(path.as_std_path());
11695
11696 if !watched_paths
11697 .is_worktree_path_match_candidate(worktree_id, &candidate)
11698 {
11699 return None;
11700 }
11701 let typ = match change {
11702 PathChange::Loaded => return None,
11703 PathChange::Added => lsp::FileChangeType::CREATED,
11704 PathChange::Removed => lsp::FileChangeType::DELETED,
11705 PathChange::Updated => lsp::FileChangeType::CHANGED,
11706 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11707 };
11708 let uri =
11709 lsp::Uri::from_file_path(worktree_handle.read(cx).absolutize(path))
11710 .ok()?;
11711 Some(lsp::FileEvent { uri, typ })
11712 })
11713 .collect(),
11714 };
11715 if !params.changes.is_empty() {
11716 server
11717 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11718 .ok();
11719 }
11720 }
11721 }
11722 for (path, _, _) in changes {
11723 if let Some(file_name) = path.file_name()
11724 && local.watched_manifest_filenames.contains(file_name)
11725 {
11726 self.request_workspace_config_refresh();
11727 break;
11728 }
11729 }
11730 }
11731
11732 pub fn wait_for_remote_buffer(
11733 &mut self,
11734 id: BufferId,
11735 cx: &mut Context<Self>,
11736 ) -> Task<Result<Entity<Buffer>>> {
11737 self.buffer_store.update(cx, |buffer_store, cx| {
11738 buffer_store.wait_for_remote_buffer(id, cx)
11739 })
11740 }
11741
11742 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11743 let mut result = proto::Symbol {
11744 language_server_name: symbol.language_server_name.0.to_string(),
11745 source_worktree_id: symbol.source_worktree_id.to_proto(),
11746 language_server_id: symbol.source_language_server_id.to_proto(),
11747 name: symbol.name.clone(),
11748 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11749 start: Some(proto::PointUtf16 {
11750 row: symbol.range.start.0.row,
11751 column: symbol.range.start.0.column,
11752 }),
11753 end: Some(proto::PointUtf16 {
11754 row: symbol.range.end.0.row,
11755 column: symbol.range.end.0.column,
11756 }),
11757 worktree_id: Default::default(),
11758 path: Default::default(),
11759 signature: Default::default(),
11760 container_name: symbol.container_name.clone(),
11761 };
11762 match &symbol.path {
11763 SymbolLocation::InProject(path) => {
11764 result.worktree_id = path.worktree_id.to_proto();
11765 result.path = path.path.to_proto();
11766 }
11767 SymbolLocation::OutsideProject {
11768 abs_path,
11769 signature,
11770 } => {
11771 result.path = abs_path.to_string_lossy().into_owned();
11772 result.signature = signature.to_vec();
11773 }
11774 }
11775 result
11776 }
11777
11778 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11779 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11780 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11781 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11782
11783 let path = if serialized_symbol.signature.is_empty() {
11784 SymbolLocation::InProject(ProjectPath {
11785 worktree_id,
11786 path: RelPath::from_proto(&serialized_symbol.path)
11787 .context("invalid symbol path")?,
11788 })
11789 } else {
11790 SymbolLocation::OutsideProject {
11791 abs_path: Path::new(&serialized_symbol.path).into(),
11792 signature: serialized_symbol
11793 .signature
11794 .try_into()
11795 .map_err(|_| anyhow!("invalid signature"))?,
11796 }
11797 };
11798
11799 let start = serialized_symbol.start.context("invalid start")?;
11800 let end = serialized_symbol.end.context("invalid end")?;
11801 Ok(CoreSymbol {
11802 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11803 source_worktree_id,
11804 source_language_server_id: LanguageServerId::from_proto(
11805 serialized_symbol.language_server_id,
11806 ),
11807 path,
11808 name: serialized_symbol.name,
11809 range: Unclipped(PointUtf16::new(start.row, start.column))
11810 ..Unclipped(PointUtf16::new(end.row, end.column)),
11811 kind,
11812 container_name: serialized_symbol.container_name,
11813 })
11814 }
11815
11816 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11817 let mut serialized_completion = proto::Completion {
11818 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11819 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11820 new_text: completion.new_text.clone(),
11821 ..proto::Completion::default()
11822 };
11823 match &completion.source {
11824 CompletionSource::Lsp {
11825 insert_range,
11826 server_id,
11827 lsp_completion,
11828 lsp_defaults,
11829 resolved,
11830 } => {
11831 let (old_insert_start, old_insert_end) = insert_range
11832 .as_ref()
11833 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11834 .unzip();
11835
11836 serialized_completion.old_insert_start = old_insert_start;
11837 serialized_completion.old_insert_end = old_insert_end;
11838 serialized_completion.source = proto::completion::Source::Lsp as i32;
11839 serialized_completion.server_id = server_id.0 as u64;
11840 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11841 serialized_completion.lsp_defaults = lsp_defaults
11842 .as_deref()
11843 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11844 serialized_completion.resolved = *resolved;
11845 }
11846 CompletionSource::BufferWord {
11847 word_range,
11848 resolved,
11849 } => {
11850 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11851 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11852 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11853 serialized_completion.resolved = *resolved;
11854 }
11855 CompletionSource::Custom => {
11856 serialized_completion.source = proto::completion::Source::Custom as i32;
11857 serialized_completion.resolved = true;
11858 }
11859 CompletionSource::Dap { sort_text } => {
11860 serialized_completion.source = proto::completion::Source::Dap as i32;
11861 serialized_completion.sort_text = Some(sort_text.clone());
11862 }
11863 }
11864
11865 serialized_completion
11866 }
11867
11868 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11869 let old_replace_start = completion
11870 .old_replace_start
11871 .and_then(deserialize_anchor)
11872 .context("invalid old start")?;
11873 let old_replace_end = completion
11874 .old_replace_end
11875 .and_then(deserialize_anchor)
11876 .context("invalid old end")?;
11877 let insert_range = {
11878 match completion.old_insert_start.zip(completion.old_insert_end) {
11879 Some((start, end)) => {
11880 let start = deserialize_anchor(start).context("invalid insert old start")?;
11881 let end = deserialize_anchor(end).context("invalid insert old end")?;
11882 Some(start..end)
11883 }
11884 None => None,
11885 }
11886 };
11887 Ok(CoreCompletion {
11888 replace_range: old_replace_start..old_replace_end,
11889 new_text: completion.new_text,
11890 source: match proto::completion::Source::from_i32(completion.source) {
11891 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11892 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11893 insert_range,
11894 server_id: LanguageServerId::from_proto(completion.server_id),
11895 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11896 lsp_defaults: completion
11897 .lsp_defaults
11898 .as_deref()
11899 .map(serde_json::from_slice)
11900 .transpose()?,
11901 resolved: completion.resolved,
11902 },
11903 Some(proto::completion::Source::BufferWord) => {
11904 let word_range = completion
11905 .buffer_word_start
11906 .and_then(deserialize_anchor)
11907 .context("invalid buffer word start")?
11908 ..completion
11909 .buffer_word_end
11910 .and_then(deserialize_anchor)
11911 .context("invalid buffer word end")?;
11912 CompletionSource::BufferWord {
11913 word_range,
11914 resolved: completion.resolved,
11915 }
11916 }
11917 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11918 sort_text: completion
11919 .sort_text
11920 .context("expected sort text to exist")?,
11921 },
11922 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11923 },
11924 })
11925 }
11926
11927 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11928 let (kind, lsp_action) = match &action.lsp_action {
11929 LspAction::Action(code_action) => (
11930 proto::code_action::Kind::Action as i32,
11931 serde_json::to_vec(code_action).unwrap(),
11932 ),
11933 LspAction::Command(command) => (
11934 proto::code_action::Kind::Command as i32,
11935 serde_json::to_vec(command).unwrap(),
11936 ),
11937 LspAction::CodeLens(code_lens) => (
11938 proto::code_action::Kind::CodeLens as i32,
11939 serde_json::to_vec(code_lens).unwrap(),
11940 ),
11941 };
11942
11943 proto::CodeAction {
11944 server_id: action.server_id.0 as u64,
11945 start: Some(serialize_anchor(&action.range.start)),
11946 end: Some(serialize_anchor(&action.range.end)),
11947 lsp_action,
11948 kind,
11949 resolved: action.resolved,
11950 }
11951 }
11952
11953 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11954 let start = action
11955 .start
11956 .and_then(deserialize_anchor)
11957 .context("invalid start")?;
11958 let end = action
11959 .end
11960 .and_then(deserialize_anchor)
11961 .context("invalid end")?;
11962 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11963 Some(proto::code_action::Kind::Action) => {
11964 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11965 }
11966 Some(proto::code_action::Kind::Command) => {
11967 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11968 }
11969 Some(proto::code_action::Kind::CodeLens) => {
11970 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11971 }
11972 None => anyhow::bail!("Unknown action kind {}", action.kind),
11973 };
11974 Ok(CodeAction {
11975 server_id: LanguageServerId(action.server_id as usize),
11976 range: start..end,
11977 resolved: action.resolved,
11978 lsp_action,
11979 })
11980 }
11981
11982 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11983 match &formatting_result {
11984 Ok(_) => self.last_formatting_failure = None,
11985 Err(error) => {
11986 let error_string = format!("{error:#}");
11987 log::error!("Formatting failed: {error_string}");
11988 self.last_formatting_failure
11989 .replace(error_string.lines().join(" "));
11990 }
11991 }
11992 }
11993
11994 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11995 self.lsp_server_capabilities.remove(&for_server);
11996 self.semantic_token_config.remove_server_data(for_server);
11997 for lsp_data in self.lsp_data.values_mut() {
11998 lsp_data.remove_server_data(for_server);
11999 }
12000 if let Some(local) = self.as_local_mut() {
12001 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12002 local
12003 .workspace_pull_diagnostics_result_ids
12004 .remove(&for_server);
12005 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12006 buffer_servers.remove(&for_server);
12007 }
12008 }
12009 }
12010
12011 pub fn result_id_for_buffer_pull(
12012 &self,
12013 server_id: LanguageServerId,
12014 buffer_id: BufferId,
12015 registration_id: &Option<SharedString>,
12016 cx: &App,
12017 ) -> Option<SharedString> {
12018 let abs_path = self
12019 .buffer_store
12020 .read(cx)
12021 .get(buffer_id)
12022 .and_then(|b| File::from_dyn(b.read(cx).file()))
12023 .map(|f| f.abs_path(cx))?;
12024 self.as_local()?
12025 .buffer_pull_diagnostics_result_ids
12026 .get(&server_id)?
12027 .get(registration_id)?
12028 .get(&abs_path)?
12029 .clone()
12030 }
12031
12032 /// Gets all result_ids for a workspace diagnostics pull request.
12033 /// 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.
12034 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12035 pub fn result_ids_for_workspace_refresh(
12036 &self,
12037 server_id: LanguageServerId,
12038 registration_id: &Option<SharedString>,
12039 ) -> HashMap<PathBuf, SharedString> {
12040 let Some(local) = self.as_local() else {
12041 return HashMap::default();
12042 };
12043 local
12044 .workspace_pull_diagnostics_result_ids
12045 .get(&server_id)
12046 .into_iter()
12047 .filter_map(|diagnostics| diagnostics.get(registration_id))
12048 .flatten()
12049 .filter_map(|(abs_path, result_id)| {
12050 let result_id = local
12051 .buffer_pull_diagnostics_result_ids
12052 .get(&server_id)
12053 .and_then(|buffer_ids_result_ids| {
12054 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12055 })
12056 .cloned()
12057 .flatten()
12058 .or_else(|| result_id.clone())?;
12059 Some((abs_path.clone(), result_id))
12060 })
12061 .collect()
12062 }
12063
12064 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12065 if let Some(LanguageServerState::Running {
12066 workspace_diagnostics_refresh_tasks,
12067 ..
12068 }) = self
12069 .as_local_mut()
12070 .and_then(|local| local.language_servers.get_mut(&server_id))
12071 {
12072 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12073 diagnostics.refresh_tx.try_send(()).ok();
12074 }
12075 }
12076 }
12077
12078 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12079 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12080 /// which requires refreshing both workspace and document diagnostics.
12081 pub fn pull_document_diagnostics_for_server(
12082 &mut self,
12083 server_id: LanguageServerId,
12084 source_buffer_id: Option<BufferId>,
12085 cx: &mut Context<Self>,
12086 ) -> Shared<Task<()>> {
12087 let Some(local) = self.as_local_mut() else {
12088 return Task::ready(()).shared();
12089 };
12090 let mut buffers_to_refresh = HashSet::default();
12091 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12092 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12093 buffers_to_refresh.insert(*buffer_id);
12094 }
12095 }
12096
12097 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12098 }
12099
12100 pub fn pull_document_diagnostics_for_buffer_edit(
12101 &mut self,
12102 buffer_id: BufferId,
12103 cx: &mut Context<Self>,
12104 ) {
12105 let Some(local) = self.as_local_mut() else {
12106 return;
12107 };
12108 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12109 else {
12110 return;
12111 };
12112 for server_id in languages_servers {
12113 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12114 }
12115 }
12116
12117 fn apply_workspace_diagnostic_report(
12118 &mut self,
12119 server_id: LanguageServerId,
12120 report: lsp::WorkspaceDiagnosticReportResult,
12121 registration_id: Option<SharedString>,
12122 cx: &mut Context<Self>,
12123 ) {
12124 let mut workspace_diagnostics =
12125 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12126 report,
12127 server_id,
12128 registration_id,
12129 );
12130 workspace_diagnostics.retain(|d| match &d.diagnostics {
12131 LspPullDiagnostics::Response {
12132 server_id,
12133 registration_id,
12134 ..
12135 } => self.diagnostic_registration_exists(*server_id, registration_id),
12136 LspPullDiagnostics::Default => false,
12137 });
12138 let mut unchanged_buffers = HashMap::default();
12139 let workspace_diagnostics_updates = workspace_diagnostics
12140 .into_iter()
12141 .filter_map(
12142 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12143 LspPullDiagnostics::Response {
12144 server_id,
12145 uri,
12146 diagnostics,
12147 registration_id,
12148 } => Some((
12149 server_id,
12150 uri,
12151 diagnostics,
12152 workspace_diagnostics.version,
12153 registration_id,
12154 )),
12155 LspPullDiagnostics::Default => None,
12156 },
12157 )
12158 .fold(
12159 HashMap::default(),
12160 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12161 let (result_id, diagnostics) = match diagnostics {
12162 PulledDiagnostics::Unchanged { result_id } => {
12163 unchanged_buffers
12164 .entry(new_registration_id.clone())
12165 .or_insert_with(HashSet::default)
12166 .insert(uri.clone());
12167 (Some(result_id), Vec::new())
12168 }
12169 PulledDiagnostics::Changed {
12170 result_id,
12171 diagnostics,
12172 } => (result_id, diagnostics),
12173 };
12174 let disk_based_sources = Cow::Owned(
12175 self.language_server_adapter_for_id(server_id)
12176 .as_ref()
12177 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12178 .unwrap_or(&[])
12179 .to_vec(),
12180 );
12181
12182 let Some(abs_path) = uri.to_file_path().ok() else {
12183 return acc;
12184 };
12185 let Some((worktree, relative_path)) =
12186 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12187 else {
12188 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12189 return acc;
12190 };
12191 let worktree_id = worktree.read(cx).id();
12192 let project_path = ProjectPath {
12193 worktree_id,
12194 path: relative_path,
12195 };
12196 if let Some(local_lsp_store) = self.as_local_mut() {
12197 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12198 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12199 }
12200 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12201 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12202 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12203 acc.entry(server_id)
12204 .or_insert_with(HashMap::default)
12205 .entry(new_registration_id.clone())
12206 .or_insert_with(Vec::new)
12207 .push(DocumentDiagnosticsUpdate {
12208 server_id,
12209 diagnostics: lsp::PublishDiagnosticsParams {
12210 uri,
12211 diagnostics,
12212 version,
12213 },
12214 result_id: result_id.map(SharedString::new),
12215 disk_based_sources,
12216 registration_id: new_registration_id,
12217 });
12218 }
12219 acc
12220 },
12221 );
12222
12223 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12224 for (registration_id, diagnostic_updates) in diagnostic_updates {
12225 self.merge_lsp_diagnostics(
12226 DiagnosticSourceKind::Pulled,
12227 diagnostic_updates,
12228 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12229 DiagnosticSourceKind::Pulled => {
12230 old_diagnostic.registration_id != registration_id
12231 || unchanged_buffers
12232 .get(&old_diagnostic.registration_id)
12233 .is_some_and(|unchanged_buffers| {
12234 unchanged_buffers.contains(&document_uri)
12235 })
12236 }
12237 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12238 },
12239 cx,
12240 )
12241 .log_err();
12242 }
12243 }
12244 }
12245
12246 fn register_server_capabilities(
12247 &mut self,
12248 server_id: LanguageServerId,
12249 params: lsp::RegistrationParams,
12250 cx: &mut Context<Self>,
12251 ) -> anyhow::Result<()> {
12252 let server = self
12253 .language_server_for_id(server_id)
12254 .with_context(|| format!("no server {server_id} found"))?;
12255 for reg in params.registrations {
12256 match reg.method.as_str() {
12257 "workspace/didChangeWatchedFiles" => {
12258 if let Some(options) = reg.register_options {
12259 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12260 let caps = serde_json::from_value(options)?;
12261 local_lsp_store
12262 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12263 true
12264 } else {
12265 false
12266 };
12267 if notify {
12268 notify_server_capabilities_updated(&server, cx);
12269 }
12270 }
12271 }
12272 "workspace/didChangeConfiguration" => {
12273 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12274 }
12275 "workspace/didChangeWorkspaceFolders" => {
12276 // In this case register options is an empty object, we can ignore it
12277 let caps = lsp::WorkspaceFoldersServerCapabilities {
12278 supported: Some(true),
12279 change_notifications: Some(OneOf::Right(reg.id)),
12280 };
12281 server.update_capabilities(|capabilities| {
12282 capabilities
12283 .workspace
12284 .get_or_insert_default()
12285 .workspace_folders = Some(caps);
12286 });
12287 notify_server_capabilities_updated(&server, cx);
12288 }
12289 "workspace/symbol" => {
12290 let options = parse_register_capabilities(reg)?;
12291 server.update_capabilities(|capabilities| {
12292 capabilities.workspace_symbol_provider = Some(options);
12293 });
12294 notify_server_capabilities_updated(&server, cx);
12295 }
12296 "workspace/fileOperations" => {
12297 if let Some(options) = reg.register_options {
12298 let caps = serde_json::from_value(options)?;
12299 server.update_capabilities(|capabilities| {
12300 capabilities
12301 .workspace
12302 .get_or_insert_default()
12303 .file_operations = Some(caps);
12304 });
12305 notify_server_capabilities_updated(&server, cx);
12306 }
12307 }
12308 "workspace/executeCommand" => {
12309 if let Some(options) = reg.register_options {
12310 let options = serde_json::from_value(options)?;
12311 server.update_capabilities(|capabilities| {
12312 capabilities.execute_command_provider = Some(options);
12313 });
12314 notify_server_capabilities_updated(&server, cx);
12315 }
12316 }
12317 "textDocument/rangeFormatting" => {
12318 let options = parse_register_capabilities(reg)?;
12319 server.update_capabilities(|capabilities| {
12320 capabilities.document_range_formatting_provider = Some(options);
12321 });
12322 notify_server_capabilities_updated(&server, cx);
12323 }
12324 "textDocument/onTypeFormatting" => {
12325 if let Some(options) = reg
12326 .register_options
12327 .map(serde_json::from_value)
12328 .transpose()?
12329 {
12330 server.update_capabilities(|capabilities| {
12331 capabilities.document_on_type_formatting_provider = Some(options);
12332 });
12333 notify_server_capabilities_updated(&server, cx);
12334 }
12335 }
12336 "textDocument/formatting" => {
12337 let options = parse_register_capabilities(reg)?;
12338 server.update_capabilities(|capabilities| {
12339 capabilities.document_formatting_provider = Some(options);
12340 });
12341 notify_server_capabilities_updated(&server, cx);
12342 }
12343 "textDocument/rename" => {
12344 let options = parse_register_capabilities(reg)?;
12345 server.update_capabilities(|capabilities| {
12346 capabilities.rename_provider = Some(options);
12347 });
12348 notify_server_capabilities_updated(&server, cx);
12349 }
12350 "textDocument/inlayHint" => {
12351 let options = parse_register_capabilities(reg)?;
12352 server.update_capabilities(|capabilities| {
12353 capabilities.inlay_hint_provider = Some(options);
12354 });
12355 notify_server_capabilities_updated(&server, cx);
12356 }
12357 "textDocument/documentSymbol" => {
12358 let options = parse_register_capabilities(reg)?;
12359 server.update_capabilities(|capabilities| {
12360 capabilities.document_symbol_provider = Some(options);
12361 });
12362 notify_server_capabilities_updated(&server, cx);
12363 }
12364 "textDocument/codeAction" => {
12365 let options = parse_register_capabilities(reg)?;
12366 let provider = match options {
12367 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12368 OneOf::Right(caps) => caps,
12369 };
12370 server.update_capabilities(|capabilities| {
12371 capabilities.code_action_provider = Some(provider);
12372 });
12373 notify_server_capabilities_updated(&server, cx);
12374 }
12375 "textDocument/definition" => {
12376 let options = parse_register_capabilities(reg)?;
12377 server.update_capabilities(|capabilities| {
12378 capabilities.definition_provider = Some(options);
12379 });
12380 notify_server_capabilities_updated(&server, cx);
12381 }
12382 "textDocument/completion" => {
12383 if let Some(caps) = reg
12384 .register_options
12385 .map(serde_json::from_value::<CompletionOptions>)
12386 .transpose()?
12387 {
12388 server.update_capabilities(|capabilities| {
12389 capabilities.completion_provider = Some(caps.clone());
12390 });
12391
12392 if let Some(local) = self.as_local() {
12393 let mut buffers_with_language_server = Vec::new();
12394 for handle in self.buffer_store.read(cx).buffers() {
12395 let buffer_id = handle.read(cx).remote_id();
12396 if local
12397 .buffers_opened_in_servers
12398 .get(&buffer_id)
12399 .filter(|s| s.contains(&server_id))
12400 .is_some()
12401 {
12402 buffers_with_language_server.push(handle);
12403 }
12404 }
12405 let triggers = caps
12406 .trigger_characters
12407 .unwrap_or_default()
12408 .into_iter()
12409 .collect::<BTreeSet<_>>();
12410 for handle in buffers_with_language_server {
12411 let triggers = triggers.clone();
12412 let _ = handle.update(cx, move |buffer, cx| {
12413 buffer.set_completion_triggers(server_id, triggers, cx);
12414 });
12415 }
12416 }
12417 notify_server_capabilities_updated(&server, cx);
12418 }
12419 }
12420 "textDocument/hover" => {
12421 let options = parse_register_capabilities(reg)?;
12422 let provider = match options {
12423 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12424 OneOf::Right(caps) => caps,
12425 };
12426 server.update_capabilities(|capabilities| {
12427 capabilities.hover_provider = Some(provider);
12428 });
12429 notify_server_capabilities_updated(&server, cx);
12430 }
12431 "textDocument/signatureHelp" => {
12432 if let Some(caps) = reg
12433 .register_options
12434 .map(serde_json::from_value)
12435 .transpose()?
12436 {
12437 server.update_capabilities(|capabilities| {
12438 capabilities.signature_help_provider = Some(caps);
12439 });
12440 notify_server_capabilities_updated(&server, cx);
12441 }
12442 }
12443 "textDocument/didChange" => {
12444 if let Some(sync_kind) = reg
12445 .register_options
12446 .and_then(|opts| opts.get("syncKind").cloned())
12447 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12448 .transpose()?
12449 {
12450 server.update_capabilities(|capabilities| {
12451 let mut sync_options =
12452 Self::take_text_document_sync_options(capabilities);
12453 sync_options.change = Some(sync_kind);
12454 capabilities.text_document_sync =
12455 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12456 });
12457 notify_server_capabilities_updated(&server, cx);
12458 }
12459 }
12460 "textDocument/didSave" => {
12461 if let Some(include_text) = reg
12462 .register_options
12463 .map(|opts| {
12464 let transpose = opts
12465 .get("includeText")
12466 .cloned()
12467 .map(serde_json::from_value::<Option<bool>>)
12468 .transpose();
12469 match transpose {
12470 Ok(value) => Ok(value.flatten()),
12471 Err(e) => Err(e),
12472 }
12473 })
12474 .transpose()?
12475 {
12476 server.update_capabilities(|capabilities| {
12477 let mut sync_options =
12478 Self::take_text_document_sync_options(capabilities);
12479 sync_options.save =
12480 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12481 include_text,
12482 }));
12483 capabilities.text_document_sync =
12484 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12485 });
12486 notify_server_capabilities_updated(&server, cx);
12487 }
12488 }
12489 "textDocument/codeLens" => {
12490 if let Some(caps) = reg
12491 .register_options
12492 .map(serde_json::from_value)
12493 .transpose()?
12494 {
12495 server.update_capabilities(|capabilities| {
12496 capabilities.code_lens_provider = Some(caps);
12497 });
12498 notify_server_capabilities_updated(&server, cx);
12499 }
12500 }
12501 "textDocument/diagnostic" => {
12502 if let Some(caps) = reg
12503 .register_options
12504 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12505 .transpose()?
12506 {
12507 let local = self
12508 .as_local_mut()
12509 .context("Expected LSP Store to be local")?;
12510 let state = local
12511 .language_servers
12512 .get_mut(&server_id)
12513 .context("Could not obtain Language Servers state")?;
12514 local
12515 .language_server_dynamic_registrations
12516 .entry(server_id)
12517 .or_default()
12518 .diagnostics
12519 .insert(Some(reg.id.clone()), caps.clone());
12520
12521 let supports_workspace_diagnostics =
12522 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12523 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12524 diagnostic_options.workspace_diagnostics
12525 }
12526 DiagnosticServerCapabilities::RegistrationOptions(
12527 diagnostic_registration_options,
12528 ) => {
12529 diagnostic_registration_options
12530 .diagnostic_options
12531 .workspace_diagnostics
12532 }
12533 };
12534
12535 if supports_workspace_diagnostics(&caps) {
12536 if let LanguageServerState::Running {
12537 workspace_diagnostics_refresh_tasks,
12538 ..
12539 } = state
12540 && let Some(task) = lsp_workspace_diagnostics_refresh(
12541 Some(reg.id.clone()),
12542 caps.clone(),
12543 server.clone(),
12544 cx,
12545 )
12546 {
12547 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12548 }
12549 }
12550
12551 server.update_capabilities(|capabilities| {
12552 capabilities.diagnostic_provider = Some(caps);
12553 });
12554
12555 notify_server_capabilities_updated(&server, cx);
12556
12557 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12558 }
12559 }
12560 "textDocument/documentColor" => {
12561 let options = parse_register_capabilities(reg)?;
12562 let provider = match options {
12563 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12564 OneOf::Right(caps) => caps,
12565 };
12566 server.update_capabilities(|capabilities| {
12567 capabilities.color_provider = Some(provider);
12568 });
12569 notify_server_capabilities_updated(&server, cx);
12570 }
12571 "textDocument/foldingRange" => {
12572 let options = parse_register_capabilities(reg)?;
12573 let provider = match options {
12574 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12575 OneOf::Right(caps) => caps,
12576 };
12577 server.update_capabilities(|capabilities| {
12578 capabilities.folding_range_provider = Some(provider);
12579 });
12580 notify_server_capabilities_updated(&server, cx);
12581 }
12582 _ => log::warn!("unhandled capability registration: {reg:?}"),
12583 }
12584 }
12585
12586 Ok(())
12587 }
12588
12589 fn unregister_server_capabilities(
12590 &mut self,
12591 server_id: LanguageServerId,
12592 params: lsp::UnregistrationParams,
12593 cx: &mut Context<Self>,
12594 ) -> anyhow::Result<()> {
12595 let server = self
12596 .language_server_for_id(server_id)
12597 .with_context(|| format!("no server {server_id} found"))?;
12598 for unreg in params.unregisterations.iter() {
12599 match unreg.method.as_str() {
12600 "workspace/didChangeWatchedFiles" => {
12601 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12602 local_lsp_store
12603 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12604 true
12605 } else {
12606 false
12607 };
12608 if notify {
12609 notify_server_capabilities_updated(&server, cx);
12610 }
12611 }
12612 "workspace/didChangeConfiguration" => {
12613 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12614 }
12615 "workspace/didChangeWorkspaceFolders" => {
12616 server.update_capabilities(|capabilities| {
12617 capabilities
12618 .workspace
12619 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12620 workspace_folders: None,
12621 file_operations: None,
12622 })
12623 .workspace_folders = None;
12624 });
12625 notify_server_capabilities_updated(&server, cx);
12626 }
12627 "workspace/symbol" => {
12628 server.update_capabilities(|capabilities| {
12629 capabilities.workspace_symbol_provider = None
12630 });
12631 notify_server_capabilities_updated(&server, cx);
12632 }
12633 "workspace/fileOperations" => {
12634 server.update_capabilities(|capabilities| {
12635 capabilities
12636 .workspace
12637 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12638 workspace_folders: None,
12639 file_operations: None,
12640 })
12641 .file_operations = None;
12642 });
12643 notify_server_capabilities_updated(&server, cx);
12644 }
12645 "workspace/executeCommand" => {
12646 server.update_capabilities(|capabilities| {
12647 capabilities.execute_command_provider = None;
12648 });
12649 notify_server_capabilities_updated(&server, cx);
12650 }
12651 "textDocument/rangeFormatting" => {
12652 server.update_capabilities(|capabilities| {
12653 capabilities.document_range_formatting_provider = None
12654 });
12655 notify_server_capabilities_updated(&server, cx);
12656 }
12657 "textDocument/onTypeFormatting" => {
12658 server.update_capabilities(|capabilities| {
12659 capabilities.document_on_type_formatting_provider = None;
12660 });
12661 notify_server_capabilities_updated(&server, cx);
12662 }
12663 "textDocument/formatting" => {
12664 server.update_capabilities(|capabilities| {
12665 capabilities.document_formatting_provider = None;
12666 });
12667 notify_server_capabilities_updated(&server, cx);
12668 }
12669 "textDocument/rename" => {
12670 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12671 notify_server_capabilities_updated(&server, cx);
12672 }
12673 "textDocument/codeAction" => {
12674 server.update_capabilities(|capabilities| {
12675 capabilities.code_action_provider = None;
12676 });
12677 notify_server_capabilities_updated(&server, cx);
12678 }
12679 "textDocument/definition" => {
12680 server.update_capabilities(|capabilities| {
12681 capabilities.definition_provider = None;
12682 });
12683 notify_server_capabilities_updated(&server, cx);
12684 }
12685 "textDocument/completion" => {
12686 server.update_capabilities(|capabilities| {
12687 capabilities.completion_provider = None;
12688 });
12689 notify_server_capabilities_updated(&server, cx);
12690 }
12691 "textDocument/hover" => {
12692 server.update_capabilities(|capabilities| {
12693 capabilities.hover_provider = None;
12694 });
12695 notify_server_capabilities_updated(&server, cx);
12696 }
12697 "textDocument/signatureHelp" => {
12698 server.update_capabilities(|capabilities| {
12699 capabilities.signature_help_provider = None;
12700 });
12701 notify_server_capabilities_updated(&server, cx);
12702 }
12703 "textDocument/didChange" => {
12704 server.update_capabilities(|capabilities| {
12705 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12706 sync_options.change = None;
12707 capabilities.text_document_sync =
12708 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12709 });
12710 notify_server_capabilities_updated(&server, cx);
12711 }
12712 "textDocument/didSave" => {
12713 server.update_capabilities(|capabilities| {
12714 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12715 sync_options.save = None;
12716 capabilities.text_document_sync =
12717 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12718 });
12719 notify_server_capabilities_updated(&server, cx);
12720 }
12721 "textDocument/codeLens" => {
12722 server.update_capabilities(|capabilities| {
12723 capabilities.code_lens_provider = None;
12724 });
12725 notify_server_capabilities_updated(&server, cx);
12726 }
12727 "textDocument/diagnostic" => {
12728 let local = self
12729 .as_local_mut()
12730 .context("Expected LSP Store to be local")?;
12731
12732 let state = local
12733 .language_servers
12734 .get_mut(&server_id)
12735 .context("Could not obtain Language Servers state")?;
12736 let registrations = local
12737 .language_server_dynamic_registrations
12738 .get_mut(&server_id)
12739 .with_context(|| {
12740 format!("Expected dynamic registration to exist for server {server_id}")
12741 })?;
12742 registrations.diagnostics
12743 .remove(&Some(unreg.id.clone()))
12744 .with_context(|| format!(
12745 "Attempted to unregister non-existent diagnostic registration with ID {}",
12746 unreg.id)
12747 )?;
12748 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12749
12750 if let LanguageServerState::Running {
12751 workspace_diagnostics_refresh_tasks,
12752 ..
12753 } = state
12754 {
12755 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12756 }
12757
12758 self.clear_unregistered_diagnostics(
12759 server_id,
12760 SharedString::from(unreg.id.clone()),
12761 cx,
12762 )?;
12763
12764 if removed_last_diagnostic_provider {
12765 server.update_capabilities(|capabilities| {
12766 debug_assert!(capabilities.diagnostic_provider.is_some());
12767 capabilities.diagnostic_provider = None;
12768 });
12769 }
12770
12771 notify_server_capabilities_updated(&server, cx);
12772 }
12773 "textDocument/documentColor" => {
12774 server.update_capabilities(|capabilities| {
12775 capabilities.color_provider = None;
12776 });
12777 notify_server_capabilities_updated(&server, cx);
12778 }
12779 "textDocument/foldingRange" => {
12780 server.update_capabilities(|capabilities| {
12781 capabilities.folding_range_provider = None;
12782 });
12783 notify_server_capabilities_updated(&server, cx);
12784 }
12785 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12786 }
12787 }
12788
12789 Ok(())
12790 }
12791
12792 fn clear_unregistered_diagnostics(
12793 &mut self,
12794 server_id: LanguageServerId,
12795 cleared_registration_id: SharedString,
12796 cx: &mut Context<Self>,
12797 ) -> anyhow::Result<()> {
12798 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12799
12800 self.buffer_store.update(cx, |buffer_store, cx| {
12801 for buffer_handle in buffer_store.buffers() {
12802 let buffer = buffer_handle.read(cx);
12803 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12804 let Some(abs_path) = abs_path else {
12805 continue;
12806 };
12807 affected_abs_paths.insert(abs_path);
12808 }
12809 });
12810
12811 let local = self.as_local().context("Expected LSP Store to be local")?;
12812 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12813 let Some(worktree) = self
12814 .worktree_store
12815 .read(cx)
12816 .worktree_for_id(*worktree_id, cx)
12817 else {
12818 continue;
12819 };
12820
12821 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12822 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12823 let has_matching_registration =
12824 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12825 entry.diagnostic.registration_id.as_ref()
12826 == Some(&cleared_registration_id)
12827 });
12828 if has_matching_registration {
12829 let abs_path = worktree.read(cx).absolutize(rel_path);
12830 affected_abs_paths.insert(abs_path);
12831 }
12832 }
12833 }
12834 }
12835
12836 if affected_abs_paths.is_empty() {
12837 return Ok(());
12838 }
12839
12840 // Send a fake diagnostic update which clears the state for the registration ID
12841 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12842 affected_abs_paths
12843 .into_iter()
12844 .map(|abs_path| DocumentDiagnosticsUpdate {
12845 diagnostics: DocumentDiagnostics {
12846 diagnostics: Vec::new(),
12847 document_abs_path: abs_path,
12848 version: None,
12849 },
12850 result_id: None,
12851 registration_id: Some(cleared_registration_id.clone()),
12852 server_id,
12853 disk_based_sources: Cow::Borrowed(&[]),
12854 })
12855 .collect();
12856
12857 let merge_registration_id = cleared_registration_id.clone();
12858 self.merge_diagnostic_entries(
12859 clears,
12860 move |_, diagnostic, _| {
12861 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12862 diagnostic.registration_id != Some(merge_registration_id.clone())
12863 } else {
12864 true
12865 }
12866 },
12867 cx,
12868 )?;
12869
12870 Ok(())
12871 }
12872
12873 async fn deduplicate_range_based_lsp_requests<T>(
12874 lsp_store: &Entity<Self>,
12875 server_id: Option<LanguageServerId>,
12876 lsp_request_id: LspRequestId,
12877 proto_request: &T::ProtoRequest,
12878 range: Range<Anchor>,
12879 cx: &mut AsyncApp,
12880 ) -> Result<()>
12881 where
12882 T: LspCommand,
12883 T::ProtoRequest: proto::LspRequestMessage,
12884 {
12885 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12886 let version = deserialize_version(proto_request.buffer_version());
12887 let buffer = lsp_store.update(cx, |this, cx| {
12888 this.buffer_store.read(cx).get_existing(buffer_id)
12889 })?;
12890 buffer
12891 .update(cx, |buffer, _| buffer.wait_for_version(version))
12892 .await?;
12893 lsp_store.update(cx, |lsp_store, cx| {
12894 let buffer_snapshot = buffer.read(cx).snapshot();
12895 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12896 let chunks_queried_for = lsp_data
12897 .inlay_hints
12898 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12899 .collect::<Vec<_>>();
12900 match chunks_queried_for.as_slice() {
12901 &[chunk] => {
12902 let key = LspKey {
12903 request_type: TypeId::of::<T>(),
12904 server_queried: server_id,
12905 };
12906 let previous_request = lsp_data
12907 .chunk_lsp_requests
12908 .entry(key)
12909 .or_default()
12910 .insert(chunk, lsp_request_id);
12911 if let Some((previous_request, running_requests)) =
12912 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12913 {
12914 running_requests.remove(&previous_request);
12915 }
12916 }
12917 _ambiguous_chunks => {
12918 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12919 // there, a buffer version-based check will be performed and outdated requests discarded.
12920 }
12921 }
12922 anyhow::Ok(())
12923 })?;
12924
12925 Ok(())
12926 }
12927
12928 async fn query_lsp_locally<T>(
12929 lsp_store: Entity<Self>,
12930 for_server_id: Option<LanguageServerId>,
12931 sender_id: proto::PeerId,
12932 lsp_request_id: LspRequestId,
12933 proto_request: T::ProtoRequest,
12934 position: Option<Anchor>,
12935 cx: &mut AsyncApp,
12936 ) -> Result<()>
12937 where
12938 T: LspCommand + Clone,
12939 T::ProtoRequest: proto::LspRequestMessage,
12940 <T::ProtoRequest as proto::RequestMessage>::Response:
12941 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12942 {
12943 let (buffer_version, buffer) =
12944 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12945 let request =
12946 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12947 let key = LspKey {
12948 request_type: TypeId::of::<T>(),
12949 server_queried: for_server_id,
12950 };
12951 lsp_store.update(cx, |lsp_store, cx| {
12952 let request_task = match for_server_id {
12953 Some(server_id) => {
12954 let server_task = lsp_store.request_lsp(
12955 buffer.clone(),
12956 LanguageServerToQuery::Other(server_id),
12957 request.clone(),
12958 cx,
12959 );
12960 cx.background_spawn(async move {
12961 let mut responses = Vec::new();
12962 match server_task.await {
12963 Ok(response) => responses.push((server_id, response)),
12964 // rust-analyzer likes to error with this when its still loading up
12965 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12966 Err(e) => log::error!(
12967 "Error handling response for request {request:?}: {e:#}"
12968 ),
12969 }
12970 responses
12971 })
12972 }
12973 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12974 };
12975 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12976 if T::ProtoRequest::stop_previous_requests() {
12977 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12978 lsp_requests.clear();
12979 }
12980 }
12981 lsp_data.lsp_requests.entry(key).or_default().insert(
12982 lsp_request_id,
12983 cx.spawn(async move |lsp_store, cx| {
12984 let response = request_task.await;
12985 lsp_store
12986 .update(cx, |lsp_store, cx| {
12987 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12988 {
12989 let response = response
12990 .into_iter()
12991 .map(|(server_id, response)| {
12992 (
12993 server_id.to_proto(),
12994 T::response_to_proto(
12995 response,
12996 lsp_store,
12997 sender_id,
12998 &buffer_version,
12999 cx,
13000 )
13001 .into(),
13002 )
13003 })
13004 .collect::<HashMap<_, _>>();
13005 match client.send_lsp_response::<T::ProtoRequest>(
13006 project_id,
13007 lsp_request_id,
13008 response,
13009 ) {
13010 Ok(()) => {}
13011 Err(e) => {
13012 log::error!("Failed to send LSP response: {e:#}",)
13013 }
13014 }
13015 }
13016 })
13017 .ok();
13018 }),
13019 );
13020 });
13021 Ok(())
13022 }
13023
13024 async fn wait_for_buffer_version<T>(
13025 lsp_store: &Entity<Self>,
13026 proto_request: &T::ProtoRequest,
13027 cx: &mut AsyncApp,
13028 ) -> Result<(Global, Entity<Buffer>)>
13029 where
13030 T: LspCommand,
13031 T::ProtoRequest: proto::LspRequestMessage,
13032 {
13033 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13034 let version = deserialize_version(proto_request.buffer_version());
13035 let buffer = lsp_store.update(cx, |this, cx| {
13036 this.buffer_store.read(cx).get_existing(buffer_id)
13037 })?;
13038 buffer
13039 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13040 .await?;
13041 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13042 Ok((buffer_version, buffer))
13043 }
13044
13045 fn take_text_document_sync_options(
13046 capabilities: &mut lsp::ServerCapabilities,
13047 ) -> lsp::TextDocumentSyncOptions {
13048 match capabilities.text_document_sync.take() {
13049 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13050 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13051 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13052 sync_options.change = Some(sync_kind);
13053 sync_options
13054 }
13055 None => lsp::TextDocumentSyncOptions::default(),
13056 }
13057 }
13058
13059 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13060 self.downstream_client.clone()
13061 }
13062
13063 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13064 self.worktree_store.clone()
13065 }
13066
13067 /// Gets what's stored in the LSP data for the given buffer.
13068 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13069 self.lsp_data.get_mut(&buffer_id)
13070 }
13071
13072 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13073 /// new [`BufferLspData`] will be created to replace the previous state.
13074 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13075 let (buffer_id, buffer_version) =
13076 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13077 let lsp_data = self
13078 .lsp_data
13079 .entry(buffer_id)
13080 .or_insert_with(|| BufferLspData::new(buffer, cx));
13081 if buffer_version.changed_since(&lsp_data.buffer_version) {
13082 // To send delta requests for semantic tokens, the previous tokens
13083 // need to be kept between buffer changes.
13084 let semantic_tokens = lsp_data.semantic_tokens.take();
13085 *lsp_data = BufferLspData::new(buffer, cx);
13086 lsp_data.semantic_tokens = semantic_tokens;
13087 }
13088 lsp_data
13089 }
13090}
13091
13092// Registration with registerOptions as null, should fallback to true.
13093// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13094fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13095 reg: lsp::Registration,
13096) -> Result<OneOf<bool, T>> {
13097 Ok(match reg.register_options {
13098 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13099 None => OneOf::Left(true),
13100 })
13101}
13102
13103fn subscribe_to_binary_statuses(
13104 languages: &Arc<LanguageRegistry>,
13105 cx: &mut Context<'_, LspStore>,
13106) -> Task<()> {
13107 let mut server_statuses = languages.language_server_binary_statuses();
13108 cx.spawn(async move |lsp_store, cx| {
13109 while let Some((server_name, binary_status)) = server_statuses.next().await {
13110 if lsp_store
13111 .update(cx, |_, cx| {
13112 let mut message = None;
13113 let binary_status = match binary_status {
13114 BinaryStatus::None => proto::ServerBinaryStatus::None,
13115 BinaryStatus::CheckingForUpdate => {
13116 proto::ServerBinaryStatus::CheckingForUpdate
13117 }
13118 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13119 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13120 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13121 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13122 BinaryStatus::Failed { error } => {
13123 message = Some(error);
13124 proto::ServerBinaryStatus::Failed
13125 }
13126 };
13127 cx.emit(LspStoreEvent::LanguageServerUpdate {
13128 // Binary updates are about the binary that might not have any language server id at that point.
13129 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13130 language_server_id: LanguageServerId(0),
13131 name: Some(server_name),
13132 message: proto::update_language_server::Variant::StatusUpdate(
13133 proto::StatusUpdate {
13134 message,
13135 status: Some(proto::status_update::Status::Binary(
13136 binary_status as i32,
13137 )),
13138 },
13139 ),
13140 });
13141 })
13142 .is_err()
13143 {
13144 break;
13145 }
13146 }
13147 })
13148}
13149
13150fn lsp_workspace_diagnostics_refresh(
13151 registration_id: Option<String>,
13152 options: DiagnosticServerCapabilities,
13153 server: Arc<LanguageServer>,
13154 cx: &mut Context<'_, LspStore>,
13155) -> Option<WorkspaceRefreshTask> {
13156 let identifier = workspace_diagnostic_identifier(&options)?;
13157 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13158
13159 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13160 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13161 refresh_tx.try_send(()).ok();
13162
13163 let request_timeout = ProjectSettings::get_global(cx)
13164 .global_lsp_settings
13165 .get_request_timeout();
13166
13167 // 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.
13168 // This allows users to increase the duration if need be
13169 let timeout = if request_timeout != Duration::ZERO {
13170 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13171 } else {
13172 request_timeout
13173 };
13174
13175 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13176 let mut attempts = 0;
13177 let max_attempts = 50;
13178 let mut requests = 0;
13179
13180 loop {
13181 let Some(()) = refresh_rx.recv().await else {
13182 return;
13183 };
13184
13185 'request: loop {
13186 requests += 1;
13187 if attempts > max_attempts {
13188 log::error!(
13189 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13190 );
13191 return;
13192 }
13193 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13194 cx.background_executor()
13195 .timer(Duration::from_millis(backoff_millis))
13196 .await;
13197 attempts += 1;
13198
13199 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13200 lsp_store
13201 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13202 .into_iter()
13203 .filter_map(|(abs_path, result_id)| {
13204 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13205 Some(lsp::PreviousResultId {
13206 uri,
13207 value: result_id.to_string(),
13208 })
13209 })
13210 .collect()
13211 }) else {
13212 return;
13213 };
13214
13215 let token = if let Some(registration_id) = ®istration_id {
13216 format!(
13217 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13218 server.server_id(),
13219 )
13220 } else {
13221 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13222 };
13223
13224 progress_rx.try_recv().ok();
13225 let timer = server.request_timer(timeout).fuse();
13226 let progress = pin!(progress_rx.recv().fuse());
13227 let response_result = server
13228 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13229 lsp::WorkspaceDiagnosticParams {
13230 previous_result_ids,
13231 identifier: identifier.clone(),
13232 work_done_progress_params: Default::default(),
13233 partial_result_params: lsp::PartialResultParams {
13234 partial_result_token: Some(lsp::ProgressToken::String(token)),
13235 },
13236 },
13237 select(timer, progress).then(|either| match either {
13238 Either::Left((message, ..)) => ready(message).left_future(),
13239 Either::Right(..) => pending::<String>().right_future(),
13240 }),
13241 )
13242 .await;
13243
13244 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13245 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13246 match response_result {
13247 ConnectionResult::Timeout => {
13248 log::error!("Timeout during workspace diagnostics pull");
13249 continue 'request;
13250 }
13251 ConnectionResult::ConnectionReset => {
13252 log::error!("Server closed a workspace diagnostics pull request");
13253 continue 'request;
13254 }
13255 ConnectionResult::Result(Err(e)) => {
13256 log::error!("Error during workspace diagnostics pull: {e:#}");
13257 break 'request;
13258 }
13259 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13260 attempts = 0;
13261 if lsp_store
13262 .update(cx, |lsp_store, cx| {
13263 lsp_store.apply_workspace_diagnostic_report(
13264 server.server_id(),
13265 pulled_diagnostics,
13266 registration_id_shared.clone(),
13267 cx,
13268 )
13269 })
13270 .is_err()
13271 {
13272 return;
13273 }
13274 break 'request;
13275 }
13276 }
13277 }
13278 }
13279 });
13280
13281 Some(WorkspaceRefreshTask {
13282 refresh_tx,
13283 progress_tx,
13284 task: workspace_query_language_server,
13285 })
13286}
13287
13288fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13289 match &options {
13290 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13291 .identifier
13292 .as_deref()
13293 .map(SharedString::new),
13294 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13295 let diagnostic_options = ®istration_options.diagnostic_options;
13296 diagnostic_options
13297 .identifier
13298 .as_deref()
13299 .map(SharedString::new)
13300 }
13301 }
13302}
13303
13304fn workspace_diagnostic_identifier(
13305 options: &DiagnosticServerCapabilities,
13306) -> Option<Option<String>> {
13307 match &options {
13308 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13309 if !diagnostic_options.workspace_diagnostics {
13310 return None;
13311 }
13312 Some(diagnostic_options.identifier.clone())
13313 }
13314 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13315 let diagnostic_options = ®istration_options.diagnostic_options;
13316 if !diagnostic_options.workspace_diagnostics {
13317 return None;
13318 }
13319 Some(diagnostic_options.identifier.clone())
13320 }
13321 }
13322}
13323
13324fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13325 let CompletionSource::BufferWord {
13326 word_range,
13327 resolved,
13328 } = &mut completion.source
13329 else {
13330 return;
13331 };
13332 if *resolved {
13333 return;
13334 }
13335
13336 if completion.new_text
13337 != snapshot
13338 .text_for_range(word_range.clone())
13339 .collect::<String>()
13340 {
13341 return;
13342 }
13343
13344 let mut offset = 0;
13345 for chunk in snapshot.chunks(word_range.clone(), true) {
13346 let end_offset = offset + chunk.text.len();
13347 if let Some(highlight_id) = chunk.syntax_highlight_id {
13348 completion
13349 .label
13350 .runs
13351 .push((offset..end_offset, highlight_id));
13352 }
13353 offset = end_offset;
13354 }
13355 *resolved = true;
13356}
13357
13358impl EventEmitter<LspStoreEvent> for LspStore {}
13359
13360fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13361 hover
13362 .contents
13363 .retain(|hover_block| !hover_block.text.trim().is_empty());
13364 if hover.contents.is_empty() {
13365 None
13366 } else {
13367 Some(hover)
13368 }
13369}
13370
13371async fn populate_labels_for_completions(
13372 new_completions: Vec<CoreCompletion>,
13373 language: Option<Arc<Language>>,
13374 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13375) -> Vec<Completion> {
13376 let lsp_completions = new_completions
13377 .iter()
13378 .filter_map(|new_completion| {
13379 new_completion
13380 .source
13381 .lsp_completion(true)
13382 .map(|lsp_completion| lsp_completion.into_owned())
13383 })
13384 .collect::<Vec<_>>();
13385
13386 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13387 lsp_adapter
13388 .labels_for_completions(&lsp_completions, language)
13389 .await
13390 .log_err()
13391 .unwrap_or_default()
13392 } else {
13393 Vec::new()
13394 }
13395 .into_iter()
13396 .fuse();
13397
13398 let mut completions = Vec::new();
13399 for completion in new_completions {
13400 match completion.source.lsp_completion(true) {
13401 Some(lsp_completion) => {
13402 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13403
13404 let mut label = labels.next().flatten().unwrap_or_else(|| {
13405 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13406 });
13407 ensure_uniform_list_compatible_label(&mut label);
13408 completions.push(Completion {
13409 label,
13410 documentation,
13411 replace_range: completion.replace_range,
13412 new_text: completion.new_text,
13413 insert_text_mode: lsp_completion.insert_text_mode,
13414 source: completion.source,
13415 icon_path: None,
13416 confirm: None,
13417 match_start: None,
13418 snippet_deduplication_key: None,
13419 });
13420 }
13421 None => {
13422 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13423 ensure_uniform_list_compatible_label(&mut label);
13424 completions.push(Completion {
13425 label,
13426 documentation: None,
13427 replace_range: completion.replace_range,
13428 new_text: completion.new_text,
13429 source: completion.source,
13430 insert_text_mode: None,
13431 icon_path: None,
13432 confirm: None,
13433 match_start: None,
13434 snippet_deduplication_key: None,
13435 });
13436 }
13437 }
13438 }
13439 completions
13440}
13441
13442#[derive(Debug)]
13443pub enum LanguageServerToQuery {
13444 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13445 FirstCapable,
13446 /// Query a specific language server.
13447 Other(LanguageServerId),
13448}
13449
13450#[derive(Default)]
13451struct RenamePathsWatchedForServer {
13452 did_rename: Vec<RenameActionPredicate>,
13453 will_rename: Vec<RenameActionPredicate>,
13454}
13455
13456impl RenamePathsWatchedForServer {
13457 fn with_did_rename_patterns(
13458 mut self,
13459 did_rename: Option<&FileOperationRegistrationOptions>,
13460 ) -> Self {
13461 if let Some(did_rename) = did_rename {
13462 self.did_rename = did_rename
13463 .filters
13464 .iter()
13465 .filter_map(|filter| filter.try_into().log_err())
13466 .collect();
13467 }
13468 self
13469 }
13470 fn with_will_rename_patterns(
13471 mut self,
13472 will_rename: Option<&FileOperationRegistrationOptions>,
13473 ) -> Self {
13474 if let Some(will_rename) = will_rename {
13475 self.will_rename = will_rename
13476 .filters
13477 .iter()
13478 .filter_map(|filter| filter.try_into().log_err())
13479 .collect();
13480 }
13481 self
13482 }
13483
13484 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13485 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13486 }
13487 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13488 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13489 }
13490}
13491
13492impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13493 type Error = globset::Error;
13494 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13495 Ok(Self {
13496 kind: ops.pattern.matches.clone(),
13497 glob: GlobBuilder::new(&ops.pattern.glob)
13498 .case_insensitive(
13499 ops.pattern
13500 .options
13501 .as_ref()
13502 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13503 )
13504 .build()?
13505 .compile_matcher(),
13506 })
13507 }
13508}
13509struct RenameActionPredicate {
13510 glob: GlobMatcher,
13511 kind: Option<FileOperationPatternKind>,
13512}
13513
13514impl RenameActionPredicate {
13515 // Returns true if language server should be notified
13516 fn eval(&self, path: &str, is_dir: bool) -> bool {
13517 self.kind.as_ref().is_none_or(|kind| {
13518 let expected_kind = if is_dir {
13519 FileOperationPatternKind::Folder
13520 } else {
13521 FileOperationPatternKind::File
13522 };
13523 kind == &expected_kind
13524 }) && self.glob.is_match(path)
13525 }
13526}
13527
13528#[derive(Default)]
13529struct LanguageServerWatchedPaths {
13530 registrations: HashMap<String, WatchedPathsRegistration>,
13531}
13532
13533struct WatchedPathsRegistration {
13534 worktree_globs: HashMap<WorktreeId, GlobSet>,
13535 _abs_path_watchers: Vec<Task<()>>,
13536}
13537
13538impl LanguageServerWatchedPaths {
13539 fn is_worktree_path_match_candidate(
13540 &self,
13541 worktree_id: WorktreeId,
13542 candidate: &Candidate,
13543 ) -> bool {
13544 self.registrations.values().any(|reg| {
13545 reg.worktree_globs
13546 .get(&worktree_id)
13547 .is_some_and(|gs| gs.is_match_candidate(candidate))
13548 })
13549 }
13550}
13551
13552struct LspBufferSnapshot {
13553 version: i32,
13554 snapshot: TextBufferSnapshot,
13555}
13556
13557/// A prompt requested by LSP server.
13558#[derive(Clone, Debug)]
13559pub struct LanguageServerPromptRequest {
13560 pub id: usize,
13561 pub level: PromptLevel,
13562 pub message: String,
13563 pub actions: Vec<MessageActionItem>,
13564 pub lsp_name: String,
13565 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13566}
13567
13568impl LanguageServerPromptRequest {
13569 pub fn new(
13570 level: PromptLevel,
13571 message: String,
13572 actions: Vec<MessageActionItem>,
13573 lsp_name: String,
13574 response_channel: smol::channel::Sender<MessageActionItem>,
13575 ) -> Self {
13576 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13577 LanguageServerPromptRequest {
13578 id,
13579 level,
13580 message,
13581 actions,
13582 lsp_name,
13583 response_channel,
13584 }
13585 }
13586 pub async fn respond(self, index: usize) -> Option<()> {
13587 if let Some(response) = self.actions.into_iter().nth(index) {
13588 self.response_channel.send(response).await.ok()
13589 } else {
13590 None
13591 }
13592 }
13593
13594 #[cfg(any(test, feature = "test-support"))]
13595 pub fn test(
13596 level: PromptLevel,
13597 message: String,
13598 actions: Vec<MessageActionItem>,
13599 lsp_name: String,
13600 ) -> Self {
13601 let (tx, _rx) = smol::channel::unbounded();
13602 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13603 }
13604}
13605impl PartialEq for LanguageServerPromptRequest {
13606 fn eq(&self, other: &Self) -> bool {
13607 self.message == other.message && self.actions == other.actions
13608 }
13609}
13610
13611#[derive(Clone, Debug, PartialEq)]
13612pub enum LanguageServerLogType {
13613 Log(MessageType),
13614 Trace { verbose_info: Option<String> },
13615 Rpc { received: bool },
13616}
13617
13618impl LanguageServerLogType {
13619 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13620 match self {
13621 Self::Log(log_type) => {
13622 use proto::log_message::LogLevel;
13623 let level = match *log_type {
13624 MessageType::ERROR => LogLevel::Error,
13625 MessageType::WARNING => LogLevel::Warning,
13626 MessageType::INFO => LogLevel::Info,
13627 MessageType::LOG => LogLevel::Log,
13628 other => {
13629 log::warn!("Unknown lsp log message type: {other:?}");
13630 LogLevel::Log
13631 }
13632 };
13633 proto::language_server_log::LogType::Log(proto::LogMessage {
13634 level: level as i32,
13635 })
13636 }
13637 Self::Trace { verbose_info } => {
13638 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13639 verbose_info: verbose_info.to_owned(),
13640 })
13641 }
13642 Self::Rpc { received } => {
13643 let kind = if *received {
13644 proto::rpc_message::Kind::Received
13645 } else {
13646 proto::rpc_message::Kind::Sent
13647 };
13648 let kind = kind as i32;
13649 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13650 }
13651 }
13652 }
13653
13654 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13655 use proto::log_message::LogLevel;
13656 use proto::rpc_message;
13657 match log_type {
13658 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13659 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13660 LogLevel::Error => MessageType::ERROR,
13661 LogLevel::Warning => MessageType::WARNING,
13662 LogLevel::Info => MessageType::INFO,
13663 LogLevel::Log => MessageType::LOG,
13664 },
13665 ),
13666 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13667 verbose_info: trace_message.verbose_info,
13668 },
13669 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13670 received: match rpc_message::Kind::from_i32(message.kind)
13671 .unwrap_or(rpc_message::Kind::Received)
13672 {
13673 rpc_message::Kind::Received => true,
13674 rpc_message::Kind::Sent => false,
13675 },
13676 },
13677 }
13678 }
13679}
13680
13681pub struct WorkspaceRefreshTask {
13682 refresh_tx: mpsc::Sender<()>,
13683 progress_tx: mpsc::Sender<()>,
13684 #[allow(dead_code)]
13685 task: Task<()>,
13686}
13687
13688pub enum LanguageServerState {
13689 Starting {
13690 startup: Task<Option<Arc<LanguageServer>>>,
13691 /// List of language servers that will be added to the workspace once it's initialization completes.
13692 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13693 },
13694
13695 Running {
13696 adapter: Arc<CachedLspAdapter>,
13697 server: Arc<LanguageServer>,
13698 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13699 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13700 },
13701}
13702
13703impl LanguageServerState {
13704 fn add_workspace_folder(&self, uri: Uri) {
13705 match self {
13706 LanguageServerState::Starting {
13707 pending_workspace_folders,
13708 ..
13709 } => {
13710 pending_workspace_folders.lock().insert(uri);
13711 }
13712 LanguageServerState::Running { server, .. } => {
13713 server.add_workspace_folder(uri);
13714 }
13715 }
13716 }
13717 fn _remove_workspace_folder(&self, uri: Uri) {
13718 match self {
13719 LanguageServerState::Starting {
13720 pending_workspace_folders,
13721 ..
13722 } => {
13723 pending_workspace_folders.lock().remove(&uri);
13724 }
13725 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13726 }
13727 }
13728}
13729
13730impl std::fmt::Debug for LanguageServerState {
13731 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13732 match self {
13733 LanguageServerState::Starting { .. } => {
13734 f.debug_struct("LanguageServerState::Starting").finish()
13735 }
13736 LanguageServerState::Running { .. } => {
13737 f.debug_struct("LanguageServerState::Running").finish()
13738 }
13739 }
13740 }
13741}
13742
13743#[derive(Clone, Debug, Serialize)]
13744pub struct LanguageServerProgress {
13745 pub is_disk_based_diagnostics_progress: bool,
13746 pub is_cancellable: bool,
13747 pub title: Option<String>,
13748 pub message: Option<String>,
13749 pub percentage: Option<usize>,
13750 #[serde(skip_serializing)]
13751 pub last_update_at: Instant,
13752}
13753
13754#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13755pub struct DiagnosticSummary {
13756 pub error_count: usize,
13757 pub warning_count: usize,
13758}
13759
13760impl DiagnosticSummary {
13761 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13762 let mut this = Self {
13763 error_count: 0,
13764 warning_count: 0,
13765 };
13766
13767 for entry in diagnostics {
13768 if entry.diagnostic.is_primary {
13769 match entry.diagnostic.severity {
13770 DiagnosticSeverity::ERROR => this.error_count += 1,
13771 DiagnosticSeverity::WARNING => this.warning_count += 1,
13772 _ => {}
13773 }
13774 }
13775 }
13776
13777 this
13778 }
13779
13780 pub fn is_empty(&self) -> bool {
13781 self.error_count == 0 && self.warning_count == 0
13782 }
13783
13784 pub fn to_proto(
13785 self,
13786 language_server_id: LanguageServerId,
13787 path: &RelPath,
13788 ) -> proto::DiagnosticSummary {
13789 proto::DiagnosticSummary {
13790 path: path.to_proto(),
13791 language_server_id: language_server_id.0 as u64,
13792 error_count: self.error_count as u32,
13793 warning_count: self.warning_count as u32,
13794 }
13795 }
13796}
13797
13798#[derive(Clone, Debug)]
13799pub enum CompletionDocumentation {
13800 /// There is no documentation for this completion.
13801 Undocumented,
13802 /// A single line of documentation.
13803 SingleLine(SharedString),
13804 /// Multiple lines of plain text documentation.
13805 MultiLinePlainText(SharedString),
13806 /// Markdown documentation.
13807 MultiLineMarkdown(SharedString),
13808 /// Both single line and multiple lines of plain text documentation.
13809 SingleLineAndMultiLinePlainText {
13810 single_line: SharedString,
13811 plain_text: Option<SharedString>,
13812 },
13813}
13814
13815impl CompletionDocumentation {
13816 #[cfg(any(test, feature = "test-support"))]
13817 pub fn text(&self) -> SharedString {
13818 match self {
13819 CompletionDocumentation::Undocumented => "".into(),
13820 CompletionDocumentation::SingleLine(s) => s.clone(),
13821 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13822 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13823 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13824 single_line.clone()
13825 }
13826 }
13827 }
13828}
13829
13830impl From<lsp::Documentation> for CompletionDocumentation {
13831 fn from(docs: lsp::Documentation) -> Self {
13832 match docs {
13833 lsp::Documentation::String(text) => {
13834 if text.lines().count() <= 1 {
13835 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13836 } else {
13837 CompletionDocumentation::MultiLinePlainText(text.into())
13838 }
13839 }
13840
13841 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13842 lsp::MarkupKind::PlainText => {
13843 if value.lines().count() <= 1 {
13844 CompletionDocumentation::SingleLine(value.into())
13845 } else {
13846 CompletionDocumentation::MultiLinePlainText(value.into())
13847 }
13848 }
13849
13850 lsp::MarkupKind::Markdown => {
13851 CompletionDocumentation::MultiLineMarkdown(value.into())
13852 }
13853 },
13854 }
13855 }
13856}
13857
13858pub enum ResolvedHint {
13859 Resolved(InlayHint),
13860 Resolving(Shared<Task<()>>),
13861}
13862
13863pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13864 glob.components()
13865 .take_while(|component| match component {
13866 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13867 _ => true,
13868 })
13869 .collect()
13870}
13871
13872pub struct SshLspAdapter {
13873 name: LanguageServerName,
13874 binary: LanguageServerBinary,
13875 initialization_options: Option<String>,
13876 code_action_kinds: Option<Vec<CodeActionKind>>,
13877}
13878
13879impl SshLspAdapter {
13880 pub fn new(
13881 name: LanguageServerName,
13882 binary: LanguageServerBinary,
13883 initialization_options: Option<String>,
13884 code_action_kinds: Option<String>,
13885 ) -> Self {
13886 Self {
13887 name,
13888 binary,
13889 initialization_options,
13890 code_action_kinds: code_action_kinds
13891 .as_ref()
13892 .and_then(|c| serde_json::from_str(c).ok()),
13893 }
13894 }
13895}
13896
13897impl LspInstaller for SshLspAdapter {
13898 type BinaryVersion = ();
13899 async fn check_if_user_installed(
13900 &self,
13901 _: &dyn LspAdapterDelegate,
13902 _: Option<Toolchain>,
13903 _: &AsyncApp,
13904 ) -> Option<LanguageServerBinary> {
13905 Some(self.binary.clone())
13906 }
13907
13908 async fn cached_server_binary(
13909 &self,
13910 _: PathBuf,
13911 _: &dyn LspAdapterDelegate,
13912 ) -> Option<LanguageServerBinary> {
13913 None
13914 }
13915
13916 async fn fetch_latest_server_version(
13917 &self,
13918 _: &dyn LspAdapterDelegate,
13919 _: bool,
13920 _: &mut AsyncApp,
13921 ) -> Result<()> {
13922 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13923 }
13924
13925 async fn fetch_server_binary(
13926 &self,
13927 _: (),
13928 _: PathBuf,
13929 _: &dyn LspAdapterDelegate,
13930 ) -> Result<LanguageServerBinary> {
13931 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13932 }
13933}
13934
13935#[async_trait(?Send)]
13936impl LspAdapter for SshLspAdapter {
13937 fn name(&self) -> LanguageServerName {
13938 self.name.clone()
13939 }
13940
13941 async fn initialization_options(
13942 self: Arc<Self>,
13943 _: &Arc<dyn LspAdapterDelegate>,
13944 ) -> Result<Option<serde_json::Value>> {
13945 let Some(options) = &self.initialization_options else {
13946 return Ok(None);
13947 };
13948 let result = serde_json::from_str(options)?;
13949 Ok(result)
13950 }
13951
13952 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13953 self.code_action_kinds.clone()
13954 }
13955}
13956
13957pub fn language_server_settings<'a>(
13958 delegate: &'a dyn LspAdapterDelegate,
13959 language: &LanguageServerName,
13960 cx: &'a App,
13961) -> Option<&'a LspSettings> {
13962 language_server_settings_for(
13963 SettingsLocation {
13964 worktree_id: delegate.worktree_id(),
13965 path: RelPath::empty(),
13966 },
13967 language,
13968 cx,
13969 )
13970}
13971
13972pub fn language_server_settings_for<'a>(
13973 location: SettingsLocation<'a>,
13974 language: &LanguageServerName,
13975 cx: &'a App,
13976) -> Option<&'a LspSettings> {
13977 ProjectSettings::get(Some(location), cx).lsp.get(language)
13978}
13979
13980pub struct LocalLspAdapterDelegate {
13981 lsp_store: WeakEntity<LspStore>,
13982 worktree: worktree::Snapshot,
13983 fs: Arc<dyn Fs>,
13984 http_client: Arc<dyn HttpClient>,
13985 language_registry: Arc<LanguageRegistry>,
13986 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
13987}
13988
13989impl LocalLspAdapterDelegate {
13990 pub fn new(
13991 language_registry: Arc<LanguageRegistry>,
13992 environment: &Entity<ProjectEnvironment>,
13993 lsp_store: WeakEntity<LspStore>,
13994 worktree: &Entity<Worktree>,
13995 http_client: Arc<dyn HttpClient>,
13996 fs: Arc<dyn Fs>,
13997 cx: &mut App,
13998 ) -> Arc<Self> {
13999 let load_shell_env_task =
14000 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14001
14002 Arc::new(Self {
14003 lsp_store,
14004 worktree: worktree.read(cx).snapshot(),
14005 fs,
14006 http_client,
14007 language_registry,
14008 load_shell_env_task,
14009 })
14010 }
14011
14012 pub fn from_local_lsp(
14013 local: &LocalLspStore,
14014 worktree: &Entity<Worktree>,
14015 cx: &mut App,
14016 ) -> Arc<Self> {
14017 Self::new(
14018 local.languages.clone(),
14019 &local.environment,
14020 local.weak.clone(),
14021 worktree,
14022 local.http_client.clone(),
14023 local.fs.clone(),
14024 cx,
14025 )
14026 }
14027}
14028
14029#[async_trait]
14030impl LspAdapterDelegate for LocalLspAdapterDelegate {
14031 fn show_notification(&self, message: &str, cx: &mut App) {
14032 self.lsp_store
14033 .update(cx, |_, cx| {
14034 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14035 })
14036 .ok();
14037 }
14038
14039 fn http_client(&self) -> Arc<dyn HttpClient> {
14040 self.http_client.clone()
14041 }
14042
14043 fn worktree_id(&self) -> WorktreeId {
14044 self.worktree.id()
14045 }
14046
14047 fn worktree_root_path(&self) -> &Path {
14048 self.worktree.abs_path().as_ref()
14049 }
14050
14051 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14052 self.worktree.resolve_relative_path(path)
14053 }
14054
14055 async fn shell_env(&self) -> HashMap<String, String> {
14056 let task = self.load_shell_env_task.clone();
14057 task.await.unwrap_or_default()
14058 }
14059
14060 async fn npm_package_installed_version(
14061 &self,
14062 package_name: &str,
14063 ) -> Result<Option<(PathBuf, Version)>> {
14064 let local_package_directory = self.worktree_root_path();
14065 let node_modules_directory = local_package_directory.join("node_modules");
14066
14067 if let Some(version) =
14068 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14069 {
14070 return Ok(Some((node_modules_directory, version)));
14071 }
14072 let Some(npm) = self.which("npm".as_ref()).await else {
14073 log::warn!(
14074 "Failed to find npm executable for {:?}",
14075 local_package_directory
14076 );
14077 return Ok(None);
14078 };
14079
14080 let env = self.shell_env().await;
14081 let output = util::command::new_command(&npm)
14082 .args(["root", "-g"])
14083 .envs(env)
14084 .current_dir(local_package_directory)
14085 .output()
14086 .await?;
14087 let global_node_modules =
14088 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14089
14090 if let Some(version) =
14091 read_package_installed_version(global_node_modules.clone(), package_name).await?
14092 {
14093 return Ok(Some((global_node_modules, version)));
14094 }
14095 return Ok(None);
14096 }
14097
14098 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14099 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14100 if self.fs.is_file(&worktree_abs_path).await {
14101 worktree_abs_path.pop();
14102 }
14103
14104 let env = self.shell_env().await;
14105
14106 let shell_path = env.get("PATH").cloned();
14107
14108 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14109 }
14110
14111 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14112 let mut working_dir = self.worktree_root_path().to_path_buf();
14113 if self.fs.is_file(&working_dir).await {
14114 working_dir.pop();
14115 }
14116 let output = util::command::new_command(&command.path)
14117 .args(command.arguments)
14118 .envs(command.env.clone().unwrap_or_default())
14119 .current_dir(working_dir)
14120 .output()
14121 .await?;
14122
14123 anyhow::ensure!(
14124 output.status.success(),
14125 "{}, stdout: {:?}, stderr: {:?}",
14126 output.status,
14127 String::from_utf8_lossy(&output.stdout),
14128 String::from_utf8_lossy(&output.stderr)
14129 );
14130 Ok(())
14131 }
14132
14133 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14134 self.language_registry
14135 .update_lsp_binary_status(server_name, status);
14136 }
14137
14138 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14139 self.language_registry
14140 .all_lsp_adapters()
14141 .into_iter()
14142 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14143 .collect()
14144 }
14145
14146 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14147 let dir = self.language_registry.language_server_download_dir(name)?;
14148
14149 if !dir.exists() {
14150 smol::fs::create_dir_all(&dir)
14151 .await
14152 .context("failed to create container directory")
14153 .log_err()?;
14154 }
14155
14156 Some(dir)
14157 }
14158
14159 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14160 let entry = self
14161 .worktree
14162 .entry_for_path(path)
14163 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14164 let abs_path = self.worktree.absolutize(&entry.path);
14165 self.fs.load(&abs_path).await
14166 }
14167}
14168
14169async fn populate_labels_for_symbols(
14170 symbols: Vec<CoreSymbol>,
14171 language_registry: &Arc<LanguageRegistry>,
14172 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14173 output: &mut Vec<Symbol>,
14174) {
14175 #[allow(clippy::mutable_key_type)]
14176 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14177
14178 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14179 for symbol in symbols {
14180 let Some(file_name) = symbol.path.file_name() else {
14181 continue;
14182 };
14183 let language = language_registry
14184 .load_language_for_file_path(Path::new(file_name))
14185 .await
14186 .ok()
14187 .or_else(|| {
14188 unknown_paths.insert(file_name.into());
14189 None
14190 });
14191 symbols_by_language
14192 .entry(language)
14193 .or_default()
14194 .push(symbol);
14195 }
14196
14197 for unknown_path in unknown_paths {
14198 log::info!("no language found for symbol in file {unknown_path:?}");
14199 }
14200
14201 let mut label_params = Vec::new();
14202 for (language, mut symbols) in symbols_by_language {
14203 label_params.clear();
14204 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14205 name: mem::take(&mut symbol.name),
14206 kind: symbol.kind,
14207 container_name: symbol.container_name.take(),
14208 }));
14209
14210 let mut labels = Vec::new();
14211 if let Some(language) = language {
14212 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14213 language_registry
14214 .lsp_adapters(&language.name())
14215 .first()
14216 .cloned()
14217 });
14218 if let Some(lsp_adapter) = lsp_adapter {
14219 labels = lsp_adapter
14220 .labels_for_symbols(&label_params, &language)
14221 .await
14222 .log_err()
14223 .unwrap_or_default();
14224 }
14225 }
14226
14227 for (
14228 (
14229 symbol,
14230 language::Symbol {
14231 name,
14232 container_name,
14233 ..
14234 },
14235 ),
14236 label,
14237 ) in symbols
14238 .into_iter()
14239 .zip(label_params.drain(..))
14240 .zip(labels.into_iter().chain(iter::repeat(None)))
14241 {
14242 output.push(Symbol {
14243 language_server_name: symbol.language_server_name,
14244 source_worktree_id: symbol.source_worktree_id,
14245 source_language_server_id: symbol.source_language_server_id,
14246 path: symbol.path,
14247 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14248 name,
14249 kind: symbol.kind,
14250 range: symbol.range,
14251 container_name,
14252 });
14253 }
14254 }
14255}
14256
14257pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14258 text.lines()
14259 .map(|line| line.trim())
14260 .filter(|line| !line.is_empty())
14261 .join(separator)
14262}
14263
14264fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14265 match server.capabilities().text_document_sync.as_ref()? {
14266 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14267 // Server wants didSave but didn't specify includeText.
14268 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14269 // Server doesn't want didSave at all.
14270 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14271 // Server provided SaveOptions.
14272 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14273 Some(save_options.include_text.unwrap_or(false))
14274 }
14275 },
14276 // We do not have any save info. Kind affects didChange only.
14277 lsp::TextDocumentSyncCapability::Kind(_) => None,
14278 }
14279}
14280
14281/// Completion items are displayed in a `UniformList`.
14282/// Usually, those items are single-line strings, but in LSP responses,
14283/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14284/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14285/// 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,
14286/// breaking the completions menu presentation.
14287///
14288/// 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.
14289pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14290 let mut new_text = String::with_capacity(label.text.len());
14291 let mut offset_map = vec![0; label.text.len() + 1];
14292 let mut last_char_was_space = false;
14293 let mut new_idx = 0;
14294 let chars = label.text.char_indices().fuse();
14295 let mut newlines_removed = false;
14296
14297 for (idx, c) in chars {
14298 offset_map[idx] = new_idx;
14299
14300 match c {
14301 '\n' if last_char_was_space => {
14302 newlines_removed = true;
14303 }
14304 '\t' | ' ' if last_char_was_space => {}
14305 '\n' if !last_char_was_space => {
14306 new_text.push(' ');
14307 new_idx += 1;
14308 last_char_was_space = true;
14309 newlines_removed = true;
14310 }
14311 ' ' | '\t' => {
14312 new_text.push(' ');
14313 new_idx += 1;
14314 last_char_was_space = true;
14315 }
14316 _ => {
14317 new_text.push(c);
14318 new_idx += c.len_utf8();
14319 last_char_was_space = false;
14320 }
14321 }
14322 }
14323 offset_map[label.text.len()] = new_idx;
14324
14325 // Only modify the label if newlines were removed.
14326 if !newlines_removed {
14327 return;
14328 }
14329
14330 let last_index = new_idx;
14331 let mut run_ranges_errors = Vec::new();
14332 label.runs.retain_mut(|(range, _)| {
14333 match offset_map.get(range.start) {
14334 Some(&start) => range.start = start,
14335 None => {
14336 run_ranges_errors.push(range.clone());
14337 return false;
14338 }
14339 }
14340
14341 match offset_map.get(range.end) {
14342 Some(&end) => range.end = end,
14343 None => {
14344 run_ranges_errors.push(range.clone());
14345 range.end = last_index;
14346 }
14347 }
14348 true
14349 });
14350 if !run_ranges_errors.is_empty() {
14351 log::error!(
14352 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14353 label.text
14354 );
14355 }
14356
14357 let mut wrong_filter_range = None;
14358 if label.filter_range == (0..label.text.len()) {
14359 label.filter_range = 0..new_text.len();
14360 } else {
14361 let mut original_filter_range = Some(label.filter_range.clone());
14362 match offset_map.get(label.filter_range.start) {
14363 Some(&start) => label.filter_range.start = start,
14364 None => {
14365 wrong_filter_range = original_filter_range.take();
14366 label.filter_range.start = last_index;
14367 }
14368 }
14369
14370 match offset_map.get(label.filter_range.end) {
14371 Some(&end) => label.filter_range.end = end,
14372 None => {
14373 wrong_filter_range = original_filter_range.take();
14374 label.filter_range.end = last_index;
14375 }
14376 }
14377 }
14378 if let Some(wrong_filter_range) = wrong_filter_range {
14379 log::error!(
14380 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14381 label.text
14382 );
14383 }
14384
14385 label.text = new_text;
14386}