1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
77 Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 language_settings,
81 },
82 point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153pub use semantic_tokens::{
154 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
155};
156
157pub use worktree::{
158 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
159 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
160};
161
162const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
163pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
164const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
165const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
166static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
167
168#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
169pub enum ProgressToken {
170 Number(i32),
171 String(SharedString),
172}
173
174impl std::fmt::Display for ProgressToken {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Number(number) => write!(f, "{number}"),
178 Self::String(string) => write!(f, "{string}"),
179 }
180 }
181}
182
183impl ProgressToken {
184 fn from_lsp(value: lsp::NumberOrString) -> Self {
185 match value {
186 lsp::NumberOrString::Number(number) => Self::Number(number),
187 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
188 }
189 }
190
191 fn to_lsp(&self) -> lsp::NumberOrString {
192 match self {
193 Self::Number(number) => lsp::NumberOrString::Number(*number),
194 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
195 }
196 }
197
198 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
199 Some(match value.value? {
200 proto::progress_token::Value::Number(number) => Self::Number(number),
201 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
202 })
203 }
204
205 fn to_proto(&self) -> proto::ProgressToken {
206 proto::ProgressToken {
207 value: Some(match self {
208 Self::Number(number) => proto::progress_token::Value::Number(*number),
209 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
210 }),
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum FormatTrigger {
217 Save,
218 Manual,
219}
220
221pub enum LspFormatTarget {
222 Buffers,
223 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
228
229struct OpenLspBuffer(Entity<Buffer>);
230
231impl FormatTrigger {
232 fn from_proto(value: i32) -> FormatTrigger {
233 match value {
234 0 => FormatTrigger::Save,
235 1 => FormatTrigger::Manual,
236 _ => FormatTrigger::Save,
237 }
238 }
239}
240
241#[derive(Clone)]
242struct UnifiedLanguageServer {
243 id: LanguageServerId,
244 project_roots: HashSet<Arc<RelPath>>,
245}
246
247/// Settings that affect language server identity.
248///
249/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
250/// updated via `workspace/didChangeConfiguration` without restarting the server.
251#[derive(Clone, Debug, Hash, PartialEq, Eq)]
252struct LanguageServerSeedSettings {
253 binary: Option<BinarySettings>,
254 initialization_options: Option<serde_json::Value>,
255}
256
257#[derive(Clone, Debug, Hash, PartialEq, Eq)]
258struct LanguageServerSeed {
259 worktree_id: WorktreeId,
260 name: LanguageServerName,
261 toolchain: Option<Toolchain>,
262 settings: LanguageServerSeedSettings,
263}
264
265#[derive(Debug)]
266pub struct DocumentDiagnosticsUpdate<'a, D> {
267 pub diagnostics: D,
268 pub result_id: Option<SharedString>,
269 pub registration_id: Option<SharedString>,
270 pub server_id: LanguageServerId,
271 pub disk_based_sources: Cow<'a, [String]>,
272}
273
274pub struct DocumentDiagnostics {
275 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 document_abs_path: PathBuf,
277 version: Option<i32>,
278}
279
280#[derive(Default, Debug)]
281struct DynamicRegistrations {
282 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
283 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
284}
285
286pub struct LocalLspStore {
287 weak: WeakEntity<LspStore>,
288 pub worktree_store: Entity<WorktreeStore>,
289 toolchain_store: Entity<LocalToolchainStore>,
290 http_client: Arc<dyn HttpClient>,
291 environment: Entity<ProjectEnvironment>,
292 fs: Arc<dyn Fs>,
293 languages: Arc<LanguageRegistry>,
294 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
295 yarn: Entity<YarnPathStore>,
296 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
297 buffers_being_formatted: HashSet<BufferId>,
298 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
299 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
300 watched_manifest_filenames: HashSet<ManifestName>,
301 language_server_paths_watched_for_rename:
302 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
303 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
304 supplementary_language_servers:
305 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
306 prettier_store: Entity<PrettierStore>,
307 next_diagnostic_group_id: usize,
308 diagnostics: HashMap<
309 WorktreeId,
310 HashMap<
311 Arc<RelPath>,
312 Vec<(
313 LanguageServerId,
314 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
315 )>,
316 >,
317 >,
318 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
319 _subscription: gpui::Subscription,
320 lsp_tree: LanguageServerTree,
321 registered_buffers: HashMap<BufferId, usize>,
322 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
323 buffer_pull_diagnostics_result_ids: HashMap<
324 LanguageServerId,
325 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
326 >,
327 workspace_pull_diagnostics_result_ids: HashMap<
328 LanguageServerId,
329 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
330 >,
331 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
332
333 buffers_to_refresh_hash_set: HashSet<BufferId>,
334 buffers_to_refresh_queue: VecDeque<BufferId>,
335 _background_diagnostics_worker: Shared<Task<()>>,
336}
337
338impl LocalLspStore {
339 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
340 pub fn running_language_server_for_id(
341 &self,
342 id: LanguageServerId,
343 ) -> Option<&Arc<LanguageServer>> {
344 let language_server_state = self.language_servers.get(&id)?;
345
346 match language_server_state {
347 LanguageServerState::Running { server, .. } => Some(server),
348 LanguageServerState::Starting { .. } => None,
349 }
350 }
351
352 fn get_or_insert_language_server(
353 &mut self,
354 worktree_handle: &Entity<Worktree>,
355 delegate: Arc<LocalLspAdapterDelegate>,
356 disposition: &Arc<LaunchDisposition>,
357 language_name: &LanguageName,
358 cx: &mut App,
359 ) -> LanguageServerId {
360 let key = LanguageServerSeed {
361 worktree_id: worktree_handle.read(cx).id(),
362 name: disposition.server_name.clone(),
363 settings: LanguageServerSeedSettings {
364 binary: disposition.settings.binary.clone(),
365 initialization_options: disposition.settings.initialization_options.clone(),
366 },
367 toolchain: disposition.toolchain.clone(),
368 };
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 state.id
372 } else {
373 let adapter = self
374 .languages
375 .lsp_adapters(language_name)
376 .into_iter()
377 .find(|adapter| adapter.name() == disposition.server_name)
378 .expect("To find LSP adapter");
379 let new_language_server_id = self.start_language_server(
380 worktree_handle,
381 delegate,
382 adapter,
383 disposition.settings.clone(),
384 key.clone(),
385 language_name.clone(),
386 cx,
387 );
388 if let Some(state) = self.language_server_ids.get_mut(&key) {
389 state.project_roots.insert(disposition.path.path.clone());
390 } else {
391 debug_assert!(
392 false,
393 "Expected `start_language_server` to ensure that `key` exists in a map"
394 );
395 }
396 new_language_server_id
397 }
398 }
399
400 fn start_language_server(
401 &mut self,
402 worktree_handle: &Entity<Worktree>,
403 delegate: Arc<LocalLspAdapterDelegate>,
404 adapter: Arc<CachedLspAdapter>,
405 settings: Arc<LspSettings>,
406 key: LanguageServerSeed,
407 language_name: LanguageName,
408 cx: &mut App,
409 ) -> LanguageServerId {
410 let worktree = worktree_handle.read(cx);
411
412 let worktree_id = worktree.id();
413 let worktree_abs_path = worktree.abs_path();
414 let toolchain = key.toolchain.clone();
415 let override_options = settings.initialization_options.clone();
416
417 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
418
419 let server_id = self.languages.next_language_server_id();
420 log::trace!(
421 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
422 adapter.name.0
423 );
424
425 let wait_until_worktree_trust =
426 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
427 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
428 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
429 });
430 if can_trust {
431 self.restricted_worktrees_tasks.remove(&worktree_id);
432 None
433 } else {
434 match self.restricted_worktrees_tasks.entry(worktree_id) {
435 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
436 hash_map::Entry::Vacant(v) => {
437 let (mut tx, rx) = watch::channel::<bool>();
438 let lsp_store = self.weak.clone();
439 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
440 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
441 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
442 tx.blocking_send(true).ok();
443 lsp_store
444 .update(cx, |lsp_store, _| {
445 if let Some(local_lsp_store) =
446 lsp_store.as_local_mut()
447 {
448 local_lsp_store
449 .restricted_worktrees_tasks
450 .remove(&worktree_id);
451 }
452 })
453 .ok();
454 }
455 }
456 });
457 v.insert((subscription, rx.clone()));
458 Some(rx)
459 }
460 }
461 }
462 });
463 let update_binary_status = wait_until_worktree_trust.is_none();
464
465 let binary = self.get_language_server_binary(
466 worktree_abs_path.clone(),
467 adapter.clone(),
468 settings,
469 toolchain.clone(),
470 delegate.clone(),
471 true,
472 wait_until_worktree_trust,
473 cx,
474 );
475 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
476
477 let pending_server = cx.spawn({
478 let adapter = adapter.clone();
479 let server_name = adapter.name.clone();
480 let stderr_capture = stderr_capture.clone();
481 #[cfg(any(test, feature = "test-support"))]
482 let lsp_store = self.weak.clone();
483 let pending_workspace_folders = pending_workspace_folders.clone();
484 async move |cx| {
485 let binary = binary.await?;
486 #[cfg(any(test, feature = "test-support"))]
487 if let Some(server) = lsp_store
488 .update(&mut cx.clone(), |this, cx| {
489 this.languages.create_fake_language_server(
490 server_id,
491 &server_name,
492 binary.clone(),
493 &mut cx.to_async(),
494 )
495 })
496 .ok()
497 .flatten()
498 {
499 return Ok(server);
500 }
501
502 let code_action_kinds = adapter.code_action_kinds();
503 lsp::LanguageServer::new(
504 stderr_capture,
505 server_id,
506 server_name,
507 binary,
508 &worktree_abs_path,
509 code_action_kinds,
510 Some(pending_workspace_folders),
511 cx,
512 )
513 }
514 });
515
516 let startup = {
517 let server_name = adapter.name.0.clone();
518 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
519 let key = key.clone();
520 let adapter = adapter.clone();
521 let lsp_store = self.weak.clone();
522 let pending_workspace_folders = pending_workspace_folders.clone();
523 let pull_diagnostics = ProjectSettings::get_global(cx)
524 .diagnostics
525 .lsp_pull_diagnostics
526 .enabled;
527 let settings_location = SettingsLocation {
528 worktree_id,
529 path: RelPath::empty(),
530 };
531 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
532 .language(Some(settings_location), Some(&language_name), cx)
533 .semantic_tokens
534 .use_tree_sitter();
535 cx.spawn(async move |cx| {
536 let result = async {
537 let language_server = pending_server.await?;
538
539 let workspace_config = Self::workspace_configuration_for_adapter(
540 adapter.adapter.clone(),
541 &delegate,
542 toolchain,
543 None,
544 cx,
545 )
546 .await?;
547
548 let mut initialization_options = Self::initialization_options_for_adapter(
549 adapter.adapter.clone(),
550 &delegate,
551 cx,
552 )
553 .await?;
554
555 match (&mut initialization_options, override_options) {
556 (Some(initialization_options), Some(override_options)) => {
557 merge_json_value_into(override_options, initialization_options);
558 }
559 (None, override_options) => initialization_options = override_options,
560 _ => {}
561 }
562
563 let initialization_params = cx.update(|cx| {
564 let mut params = language_server.default_initialize_params(
565 pull_diagnostics,
566 augments_syntax_tokens,
567 cx,
568 );
569 params.initialization_options = initialization_options;
570 adapter.adapter.prepare_initialize_params(params, cx)
571 })?;
572
573 Self::setup_lsp_messages(
574 lsp_store.clone(),
575 &language_server,
576 delegate.clone(),
577 adapter.clone(),
578 );
579
580 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
581 settings: workspace_config,
582 };
583 let language_server = cx
584 .update(|cx| {
585 let request_timeout = ProjectSettings::get_global(cx)
586 .global_lsp_settings
587 .get_request_timeout();
588
589 language_server.initialize(
590 initialization_params,
591 Arc::new(did_change_configuration_params.clone()),
592 request_timeout,
593 cx,
594 )
595 })
596 .await
597 .inspect_err(|_| {
598 if let Some(lsp_store) = lsp_store.upgrade() {
599 lsp_store.update(cx, |lsp_store, cx| {
600 lsp_store.cleanup_lsp_data(server_id);
601 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
602 });
603 }
604 })?;
605
606 language_server.notify::<lsp::notification::DidChangeConfiguration>(
607 did_change_configuration_params,
608 )?;
609
610 anyhow::Ok(language_server)
611 }
612 .await;
613
614 match result {
615 Ok(server) => {
616 lsp_store
617 .update(cx, |lsp_store, cx| {
618 lsp_store.insert_newly_running_language_server(
619 adapter,
620 server.clone(),
621 server_id,
622 key,
623 pending_workspace_folders,
624 cx,
625 );
626 })
627 .ok();
628 stderr_capture.lock().take();
629 Some(server)
630 }
631
632 Err(err) => {
633 let log = stderr_capture.lock().take().unwrap_or_default();
634 delegate.update_status(
635 adapter.name(),
636 BinaryStatus::Failed {
637 error: if log.is_empty() {
638 format!("{err:#}")
639 } else {
640 format!("{err:#}\n-- stderr --\n{log}")
641 },
642 },
643 );
644 log::error!(
645 "Failed to start language server {server_name:?}: {}",
646 redact_command(&format!("{err:?}"))
647 );
648 if !log.is_empty() {
649 log::error!("server stderr: {}", redact_command(&log));
650 }
651 None
652 }
653 }
654 })
655 };
656 let state = LanguageServerState::Starting {
657 startup,
658 pending_workspace_folders,
659 };
660
661 if update_binary_status {
662 self.languages
663 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
664 }
665
666 self.language_servers.insert(server_id, state);
667 self.language_server_ids
668 .entry(key)
669 .or_insert(UnifiedLanguageServer {
670 id: server_id,
671 project_roots: Default::default(),
672 });
673 server_id
674 }
675
676 fn get_language_server_binary(
677 &self,
678 worktree_abs_path: Arc<Path>,
679 adapter: Arc<CachedLspAdapter>,
680 settings: Arc<LspSettings>,
681 toolchain: Option<Toolchain>,
682 delegate: Arc<dyn LspAdapterDelegate>,
683 allow_binary_download: bool,
684 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
685 cx: &mut App,
686 ) -> Task<Result<LanguageServerBinary>> {
687 if let Some(settings) = &settings.binary
688 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
689 {
690 let settings = settings.clone();
691 let languages = self.languages.clone();
692 return cx.background_spawn(async move {
693 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
694 let already_trusted = *wait_until_worktree_trust.borrow();
695 if !already_trusted {
696 log::info!(
697 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
698 adapter.name(),
699 );
700 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
701 if worktree_trusted {
702 break;
703 }
704 }
705 log::info!(
706 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
707 adapter.name(),
708 );
709 }
710 languages
711 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
712 }
713 let mut env = delegate.shell_env().await;
714 env.extend(settings.env.unwrap_or_default());
715
716 Ok(LanguageServerBinary {
717 path: delegate.resolve_relative_path(path),
718 env: Some(env),
719 arguments: settings
720 .arguments
721 .unwrap_or_default()
722 .iter()
723 .map(Into::into)
724 .collect(),
725 })
726 });
727 }
728 let lsp_binary_options = LanguageServerBinaryOptions {
729 allow_path_lookup: !settings
730 .binary
731 .as_ref()
732 .and_then(|b| b.ignore_system_version)
733 .unwrap_or_default(),
734 allow_binary_download,
735 pre_release: settings
736 .fetch
737 .as_ref()
738 .and_then(|f| f.pre_release)
739 .unwrap_or(false),
740 };
741
742 cx.spawn(async move |cx| {
743 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
744 let already_trusted = *wait_until_worktree_trust.borrow();
745 if !already_trusted {
746 log::info!(
747 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
748 adapter.name(),
749 );
750 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
751 if worktree_trusted {
752 break;
753 }
754 }
755 log::info!(
756 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
757 adapter.name(),
758 );
759 }
760 }
761
762 let (existing_binary, maybe_download_binary) = adapter
763 .clone()
764 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
765 .await
766 .await;
767
768 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
769
770 let mut binary = match (existing_binary, maybe_download_binary) {
771 (binary, None) => binary?,
772 (Err(_), Some(downloader)) => downloader.await?,
773 (Ok(existing_binary), Some(downloader)) => {
774 let mut download_timeout = cx
775 .background_executor()
776 .timer(SERVER_DOWNLOAD_TIMEOUT)
777 .fuse();
778 let mut downloader = downloader.fuse();
779 futures::select! {
780 _ = download_timeout => {
781 // Return existing binary and kick the existing work to the background.
782 cx.spawn(async move |_| downloader.await).detach();
783 Ok(existing_binary)
784 },
785 downloaded_or_existing_binary = downloader => {
786 // If download fails, this results in the existing binary.
787 downloaded_or_existing_binary
788 }
789 }?
790 }
791 };
792 let mut shell_env = delegate.shell_env().await;
793
794 shell_env.extend(binary.env.unwrap_or_default());
795
796 if let Some(settings) = settings.binary.as_ref() {
797 if let Some(arguments) = &settings.arguments {
798 binary.arguments = arguments.iter().map(Into::into).collect();
799 }
800 if let Some(env) = &settings.env {
801 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
802 }
803 }
804
805 binary.env = Some(shell_env);
806 Ok(binary)
807 })
808 }
809
810 fn setup_lsp_messages(
811 lsp_store: WeakEntity<LspStore>,
812 language_server: &LanguageServer,
813 delegate: Arc<dyn LspAdapterDelegate>,
814 adapter: Arc<CachedLspAdapter>,
815 ) {
816 let name = language_server.name();
817 let server_id = language_server.server_id();
818 language_server
819 .on_notification::<lsp::notification::PublishDiagnostics, _>({
820 let adapter = adapter.clone();
821 let this = lsp_store.clone();
822 move |mut params, cx| {
823 let adapter = adapter.clone();
824 if let Some(this) = this.upgrade() {
825 this.update(cx, |this, cx| {
826 {
827 let buffer = params
828 .uri
829 .to_file_path()
830 .map(|file_path| this.get_buffer(&file_path, cx))
831 .ok()
832 .flatten();
833 adapter.process_diagnostics(&mut params, server_id, buffer);
834 }
835
836 this.merge_lsp_diagnostics(
837 DiagnosticSourceKind::Pushed,
838 vec![DocumentDiagnosticsUpdate {
839 server_id,
840 diagnostics: params,
841 result_id: None,
842 disk_based_sources: Cow::Borrowed(
843 &adapter.disk_based_diagnostic_sources,
844 ),
845 registration_id: None,
846 }],
847 |_, diagnostic, cx| match diagnostic.source_kind {
848 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
849 adapter.retain_old_diagnostic(diagnostic, cx)
850 }
851 DiagnosticSourceKind::Pulled => true,
852 },
853 cx,
854 )
855 .log_err();
856 });
857 }
858 }
859 })
860 .detach();
861 language_server
862 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
863 let adapter = adapter.adapter.clone();
864 let delegate = delegate.clone();
865 let this = lsp_store.clone();
866 move |params, cx| {
867 let adapter = adapter.clone();
868 let delegate = delegate.clone();
869 let this = this.clone();
870 let mut cx = cx.clone();
871 async move {
872 let toolchain_for_id = this
873 .update(&mut cx, |this, _| {
874 this.as_local()?.language_server_ids.iter().find_map(
875 |(seed, value)| {
876 (value.id == server_id).then(|| seed.toolchain.clone())
877 },
878 )
879 })?
880 .context("Expected the LSP store to be in a local mode")?;
881
882 let mut scope_uri_to_workspace_config = BTreeMap::new();
883 for item in ¶ms.items {
884 let scope_uri = item.scope_uri.clone();
885 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
886 scope_uri_to_workspace_config.entry(scope_uri.clone())
887 else {
888 // We've already queried workspace configuration of this URI.
889 continue;
890 };
891 let workspace_config = Self::workspace_configuration_for_adapter(
892 adapter.clone(),
893 &delegate,
894 toolchain_for_id.clone(),
895 scope_uri,
896 &mut cx,
897 )
898 .await?;
899 new_scope_uri.insert(workspace_config);
900 }
901
902 Ok(params
903 .items
904 .into_iter()
905 .filter_map(|item| {
906 let workspace_config =
907 scope_uri_to_workspace_config.get(&item.scope_uri)?;
908 if let Some(section) = &item.section {
909 Some(
910 workspace_config
911 .get(section)
912 .cloned()
913 .unwrap_or(serde_json::Value::Null),
914 )
915 } else {
916 Some(workspace_config.clone())
917 }
918 })
919 .collect())
920 }
921 }
922 })
923 .detach();
924
925 language_server
926 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
927 let this = lsp_store.clone();
928 move |_, cx| {
929 let this = this.clone();
930 let cx = cx.clone();
931 async move {
932 let Some(server) =
933 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
934 else {
935 return Ok(None);
936 };
937 let root = server.workspace_folders();
938 Ok(Some(
939 root.into_iter()
940 .map(|uri| WorkspaceFolder {
941 uri,
942 name: Default::default(),
943 })
944 .collect(),
945 ))
946 }
947 }
948 })
949 .detach();
950 // Even though we don't have handling for these requests, respond to them to
951 // avoid stalling any language server like `gopls` which waits for a response
952 // to these requests when initializing.
953 language_server
954 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
955 let this = lsp_store.clone();
956 move |params, cx| {
957 let this = this.clone();
958 let mut cx = cx.clone();
959 async move {
960 this.update(&mut cx, |this, _| {
961 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
962 {
963 status
964 .progress_tokens
965 .insert(ProgressToken::from_lsp(params.token));
966 }
967 })?;
968
969 Ok(())
970 }
971 }
972 })
973 .detach();
974
975 language_server
976 .on_request::<lsp::request::RegisterCapability, _, _>({
977 let lsp_store = lsp_store.clone();
978 move |params, cx| {
979 let lsp_store = lsp_store.clone();
980 let mut cx = cx.clone();
981 async move {
982 lsp_store
983 .update(&mut cx, |lsp_store, cx| {
984 if lsp_store.as_local().is_some() {
985 match lsp_store
986 .register_server_capabilities(server_id, params, cx)
987 {
988 Ok(()) => {}
989 Err(e) => {
990 log::error!(
991 "Failed to register server capabilities: {e:#}"
992 );
993 }
994 };
995 }
996 })
997 .ok();
998 Ok(())
999 }
1000 }
1001 })
1002 .detach();
1003
1004 language_server
1005 .on_request::<lsp::request::UnregisterCapability, _, _>({
1006 let lsp_store = lsp_store.clone();
1007 move |params, cx| {
1008 let lsp_store = lsp_store.clone();
1009 let mut cx = cx.clone();
1010 async move {
1011 lsp_store
1012 .update(&mut cx, |lsp_store, cx| {
1013 if lsp_store.as_local().is_some() {
1014 match lsp_store
1015 .unregister_server_capabilities(server_id, params, cx)
1016 {
1017 Ok(()) => {}
1018 Err(e) => {
1019 log::error!(
1020 "Failed to unregister server capabilities: {e:#}"
1021 );
1022 }
1023 }
1024 }
1025 })
1026 .ok();
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1035 let this = lsp_store.clone();
1036 move |params, cx| {
1037 let mut cx = cx.clone();
1038 let this = this.clone();
1039 async move {
1040 LocalLspStore::on_lsp_workspace_edit(
1041 this.clone(),
1042 params,
1043 server_id,
1044 &mut cx,
1045 )
1046 .await
1047 }
1048 }
1049 })
1050 .detach();
1051
1052 language_server
1053 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1054 let lsp_store = lsp_store.clone();
1055 let request_id = Arc::new(AtomicUsize::new(0));
1056 move |(), cx| {
1057 let lsp_store = lsp_store.clone();
1058 let request_id = request_id.clone();
1059 let mut cx = cx.clone();
1060 async move {
1061 lsp_store
1062 .update(&mut cx, |lsp_store, cx| {
1063 let request_id =
1064 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1065 cx.emit(LspStoreEvent::RefreshInlayHints {
1066 server_id,
1067 request_id,
1068 });
1069 lsp_store
1070 .downstream_client
1071 .as_ref()
1072 .map(|(client, project_id)| {
1073 client.send(proto::RefreshInlayHints {
1074 project_id: *project_id,
1075 server_id: server_id.to_proto(),
1076 request_id: request_id.map(|id| id as u64),
1077 })
1078 })
1079 })?
1080 .transpose()?;
1081 Ok(())
1082 }
1083 }
1084 })
1085 .detach();
1086
1087 language_server
1088 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1089 let this = lsp_store.clone();
1090 move |(), cx| {
1091 let this = this.clone();
1092 let mut cx = cx.clone();
1093 async move {
1094 this.update(&mut cx, |this, cx| {
1095 cx.emit(LspStoreEvent::RefreshCodeLens);
1096 this.downstream_client.as_ref().map(|(client, project_id)| {
1097 client.send(proto::RefreshCodeLens {
1098 project_id: *project_id,
1099 })
1100 })
1101 })?
1102 .transpose()?;
1103 Ok(())
1104 }
1105 }
1106 })
1107 .detach();
1108
1109 language_server
1110 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1111 let lsp_store = lsp_store.clone();
1112 let request_id = Arc::new(AtomicUsize::new(0));
1113 move |(), cx| {
1114 let lsp_store = lsp_store.clone();
1115 let request_id = request_id.clone();
1116 let mut cx = cx.clone();
1117 async move {
1118 lsp_store
1119 .update(&mut cx, |lsp_store, cx| {
1120 let request_id =
1121 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1122 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1123 server_id,
1124 request_id,
1125 });
1126 lsp_store
1127 .downstream_client
1128 .as_ref()
1129 .map(|(client, project_id)| {
1130 client.send(proto::RefreshSemanticTokens {
1131 project_id: *project_id,
1132 server_id: server_id.to_proto(),
1133 request_id: request_id.map(|id| id as u64),
1134 })
1135 })
1136 })?
1137 .transpose()?;
1138 Ok(())
1139 }
1140 }
1141 })
1142 .detach();
1143
1144 language_server
1145 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1146 let this = lsp_store.clone();
1147 move |(), cx| {
1148 let this = this.clone();
1149 let mut cx = cx.clone();
1150 async move {
1151 this.update(&mut cx, |lsp_store, cx| {
1152 lsp_store.pull_workspace_diagnostics(server_id);
1153 lsp_store
1154 .downstream_client
1155 .as_ref()
1156 .map(|(client, project_id)| {
1157 client.send(proto::PullWorkspaceDiagnostics {
1158 project_id: *project_id,
1159 server_id: server_id.to_proto(),
1160 })
1161 })
1162 .transpose()?;
1163 anyhow::Ok(
1164 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1165 )
1166 })??
1167 .await;
1168 Ok(())
1169 }
1170 }
1171 })
1172 .detach();
1173
1174 language_server
1175 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1176 let this = lsp_store.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 move |params, cx| {
1180 let this = this.clone();
1181 let name = name.to_string();
1182 let adapter = adapter.clone();
1183 let mut cx = cx.clone();
1184 async move {
1185 let actions = params.actions.unwrap_or_default();
1186 let message = params.message.clone();
1187 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1188 let level = match params.typ {
1189 lsp::MessageType::ERROR => PromptLevel::Critical,
1190 lsp::MessageType::WARNING => PromptLevel::Warning,
1191 _ => PromptLevel::Info,
1192 };
1193 let request = LanguageServerPromptRequest::new(
1194 level,
1195 params.message,
1196 actions,
1197 name.clone(),
1198 tx,
1199 );
1200
1201 let did_update = this
1202 .update(&mut cx, |_, cx| {
1203 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1204 })
1205 .is_ok();
1206 if did_update {
1207 let response = rx.recv().await.ok();
1208 if let Some(ref selected_action) = response {
1209 let context = language::PromptResponseContext {
1210 message,
1211 selected_action: selected_action.clone(),
1212 };
1213 adapter.process_prompt_response(&context, &mut cx)
1214 }
1215
1216 Ok(response)
1217 } else {
1218 Ok(None)
1219 }
1220 }
1221 }
1222 })
1223 .detach();
1224 language_server
1225 .on_notification::<lsp::notification::ShowMessage, _>({
1226 let this = lsp_store.clone();
1227 let name = name.to_string();
1228 move |params, cx| {
1229 let this = this.clone();
1230 let name = name.to_string();
1231 let mut cx = cx.clone();
1232
1233 let (tx, _) = smol::channel::bounded(1);
1234 let level = match params.typ {
1235 lsp::MessageType::ERROR => PromptLevel::Critical,
1236 lsp::MessageType::WARNING => PromptLevel::Warning,
1237 _ => PromptLevel::Info,
1238 };
1239 let request =
1240 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1241
1242 let _ = this.update(&mut cx, |_, cx| {
1243 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1244 });
1245 }
1246 })
1247 .detach();
1248
1249 let disk_based_diagnostics_progress_token =
1250 adapter.disk_based_diagnostics_progress_token.clone();
1251
1252 language_server
1253 .on_notification::<lsp::notification::Progress, _>({
1254 let this = lsp_store.clone();
1255 move |params, cx| {
1256 if let Some(this) = this.upgrade() {
1257 this.update(cx, |this, cx| {
1258 this.on_lsp_progress(
1259 params,
1260 server_id,
1261 disk_based_diagnostics_progress_token.clone(),
1262 cx,
1263 );
1264 });
1265 }
1266 }
1267 })
1268 .detach();
1269
1270 language_server
1271 .on_notification::<lsp::notification::LogMessage, _>({
1272 let this = lsp_store.clone();
1273 move |params, cx| {
1274 if let Some(this) = this.upgrade() {
1275 this.update(cx, |_, cx| {
1276 cx.emit(LspStoreEvent::LanguageServerLog(
1277 server_id,
1278 LanguageServerLogType::Log(params.typ),
1279 params.message,
1280 ));
1281 });
1282 }
1283 }
1284 })
1285 .detach();
1286
1287 language_server
1288 .on_notification::<lsp::notification::LogTrace, _>({
1289 let this = lsp_store.clone();
1290 move |params, cx| {
1291 let mut cx = cx.clone();
1292 if let Some(this) = this.upgrade() {
1293 this.update(&mut cx, |_, cx| {
1294 cx.emit(LspStoreEvent::LanguageServerLog(
1295 server_id,
1296 LanguageServerLogType::Trace {
1297 verbose_info: params.verbose,
1298 },
1299 params.message,
1300 ));
1301 });
1302 }
1303 }
1304 })
1305 .detach();
1306
1307 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1309 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1310 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1311 }
1312
1313 pub(crate) fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1314 let shutdown_futures = self
1315 .language_servers
1316 .drain()
1317 .map(|(_, server_state)| Self::shutdown_server(server_state))
1318 .collect::<Vec<_>>();
1319
1320 let supplementary_shutdown_futures = self
1321 .supplementary_language_servers
1322 .drain()
1323 .filter_map(|(_, (_, server))| server.shutdown())
1324 .collect::<Vec<_>>();
1325
1326 async move {
1327 join_all(shutdown_futures).await;
1328 join_all(supplementary_shutdown_futures).await;
1329 }
1330 }
1331
1332 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1333 match server_state {
1334 LanguageServerState::Running { server, .. } => {
1335 if let Some(shutdown) = server.shutdown() {
1336 shutdown.await;
1337 }
1338 }
1339 LanguageServerState::Starting { startup, .. } => {
1340 if let Some(server) = startup.await
1341 && let Some(shutdown) = server.shutdown()
1342 {
1343 shutdown.await;
1344 }
1345 }
1346 }
1347 Ok(())
1348 }
1349
1350 fn language_servers_for_worktree(
1351 &self,
1352 worktree_id: WorktreeId,
1353 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1354 self.language_server_ids
1355 .iter()
1356 .filter_map(move |(seed, state)| {
1357 if seed.worktree_id != worktree_id {
1358 return None;
1359 }
1360
1361 if let Some(LanguageServerState::Running { server, .. }) =
1362 self.language_servers.get(&state.id)
1363 {
1364 Some(server)
1365 } else {
1366 None
1367 }
1368 })
1369 }
1370
1371 fn language_server_ids_for_project_path(
1372 &self,
1373 project_path: ProjectPath,
1374 language: &Language,
1375 cx: &mut App,
1376 ) -> Vec<LanguageServerId> {
1377 let Some(worktree) = self
1378 .worktree_store
1379 .read(cx)
1380 .worktree_for_id(project_path.worktree_id, cx)
1381 else {
1382 return Vec::new();
1383 };
1384 let delegate: Arc<dyn ManifestDelegate> =
1385 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1386
1387 self.lsp_tree
1388 .get(
1389 project_path,
1390 language.name(),
1391 language.manifest(),
1392 &delegate,
1393 cx,
1394 )
1395 .collect::<Vec<_>>()
1396 }
1397
1398 fn language_server_ids_for_buffer(
1399 &self,
1400 buffer: &Buffer,
1401 cx: &mut App,
1402 ) -> Vec<LanguageServerId> {
1403 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1404 let worktree_id = file.worktree_id(cx);
1405
1406 let path: Arc<RelPath> = file
1407 .path()
1408 .parent()
1409 .map(Arc::from)
1410 .unwrap_or_else(|| file.path().clone());
1411 let worktree_path = ProjectPath { worktree_id, path };
1412 self.language_server_ids_for_project_path(worktree_path, language, cx)
1413 } else {
1414 Vec::new()
1415 }
1416 }
1417
1418 fn language_servers_for_buffer<'a>(
1419 &'a self,
1420 buffer: &'a Buffer,
1421 cx: &'a mut App,
1422 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1423 self.language_server_ids_for_buffer(buffer, cx)
1424 .into_iter()
1425 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1426 LanguageServerState::Running {
1427 adapter, server, ..
1428 } => Some((adapter, server)),
1429 _ => None,
1430 })
1431 }
1432
1433 async fn execute_code_action_kind_locally(
1434 lsp_store: WeakEntity<LspStore>,
1435 mut buffers: Vec<Entity<Buffer>>,
1436 kind: CodeActionKind,
1437 push_to_history: bool,
1438 cx: &mut AsyncApp,
1439 ) -> anyhow::Result<ProjectTransaction> {
1440 // Do not allow multiple concurrent code actions requests for the
1441 // same buffer.
1442 lsp_store.update(cx, |this, cx| {
1443 let this = this.as_local_mut().unwrap();
1444 buffers.retain(|buffer| {
1445 this.buffers_being_formatted
1446 .insert(buffer.read(cx).remote_id())
1447 });
1448 })?;
1449 let _cleanup = defer({
1450 let this = lsp_store.clone();
1451 let mut cx = cx.clone();
1452 let buffers = &buffers;
1453 move || {
1454 this.update(&mut cx, |this, cx| {
1455 let this = this.as_local_mut().unwrap();
1456 for buffer in buffers {
1457 this.buffers_being_formatted
1458 .remove(&buffer.read(cx).remote_id());
1459 }
1460 })
1461 .ok();
1462 }
1463 });
1464 let mut project_transaction = ProjectTransaction::default();
1465
1466 for buffer in &buffers {
1467 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1468 buffer.update(cx, |buffer, cx| {
1469 lsp_store
1470 .as_local()
1471 .unwrap()
1472 .language_servers_for_buffer(buffer, cx)
1473 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1474 .collect::<Vec<_>>()
1475 })
1476 })?;
1477 for (_, language_server) in adapters_and_servers.iter() {
1478 let actions = Self::get_server_code_actions_from_action_kinds(
1479 &lsp_store,
1480 language_server.server_id(),
1481 vec![kind.clone()],
1482 buffer,
1483 cx,
1484 )
1485 .await?;
1486 Self::execute_code_actions_on_server(
1487 &lsp_store,
1488 language_server,
1489 actions,
1490 push_to_history,
1491 &mut project_transaction,
1492 cx,
1493 )
1494 .await?;
1495 }
1496 }
1497 Ok(project_transaction)
1498 }
1499
1500 async fn format_locally(
1501 lsp_store: WeakEntity<LspStore>,
1502 mut buffers: Vec<FormattableBuffer>,
1503 push_to_history: bool,
1504 trigger: FormatTrigger,
1505 logger: zlog::Logger,
1506 cx: &mut AsyncApp,
1507 ) -> anyhow::Result<ProjectTransaction> {
1508 // Do not allow multiple concurrent formatting requests for the
1509 // same buffer.
1510 lsp_store.update(cx, |this, cx| {
1511 let this = this.as_local_mut().unwrap();
1512 buffers.retain(|buffer| {
1513 this.buffers_being_formatted
1514 .insert(buffer.handle.read(cx).remote_id())
1515 });
1516 })?;
1517
1518 let _cleanup = defer({
1519 let this = lsp_store.clone();
1520 let mut cx = cx.clone();
1521 let buffers = &buffers;
1522 move || {
1523 this.update(&mut cx, |this, cx| {
1524 let this = this.as_local_mut().unwrap();
1525 for buffer in buffers {
1526 this.buffers_being_formatted
1527 .remove(&buffer.handle.read(cx).remote_id());
1528 }
1529 })
1530 .ok();
1531 }
1532 });
1533
1534 let mut project_transaction = ProjectTransaction::default();
1535
1536 for buffer in &buffers {
1537 zlog::debug!(
1538 logger =>
1539 "formatting buffer '{:?}'",
1540 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1541 );
1542 // Create an empty transaction to hold all of the formatting edits.
1543 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1544 // ensure no transactions created while formatting are
1545 // grouped with the previous transaction in the history
1546 // based on the transaction group interval
1547 buffer.finalize_last_transaction();
1548 buffer
1549 .start_transaction()
1550 .context("transaction already open")?;
1551 buffer.end_transaction(cx);
1552 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1553 buffer.finalize_last_transaction();
1554 anyhow::Ok(transaction_id)
1555 })?;
1556
1557 let result = Self::format_buffer_locally(
1558 lsp_store.clone(),
1559 buffer,
1560 formatting_transaction_id,
1561 trigger,
1562 logger,
1563 cx,
1564 )
1565 .await;
1566
1567 buffer.handle.update(cx, |buffer, cx| {
1568 let Some(formatting_transaction) =
1569 buffer.get_transaction(formatting_transaction_id).cloned()
1570 else {
1571 zlog::warn!(logger => "no formatting transaction");
1572 return;
1573 };
1574 if formatting_transaction.edit_ids.is_empty() {
1575 zlog::debug!(logger => "no changes made while formatting");
1576 buffer.forget_transaction(formatting_transaction_id);
1577 return;
1578 }
1579 if !push_to_history {
1580 zlog::trace!(logger => "forgetting format transaction");
1581 buffer.forget_transaction(formatting_transaction.id);
1582 }
1583 project_transaction
1584 .0
1585 .insert(cx.entity(), formatting_transaction);
1586 });
1587
1588 result?;
1589 }
1590
1591 Ok(project_transaction)
1592 }
1593
1594 async fn format_buffer_locally(
1595 lsp_store: WeakEntity<LspStore>,
1596 buffer: &FormattableBuffer,
1597 formatting_transaction_id: clock::Lamport,
1598 trigger: FormatTrigger,
1599 logger: zlog::Logger,
1600 cx: &mut AsyncApp,
1601 ) -> Result<()> {
1602 let (adapters_and_servers, settings, request_timeout) =
1603 lsp_store.update(cx, |lsp_store, cx| {
1604 buffer.handle.update(cx, |buffer, cx| {
1605 let adapters_and_servers = lsp_store
1606 .as_local()
1607 .unwrap()
1608 .language_servers_for_buffer(buffer, cx)
1609 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1610 .collect::<Vec<_>>();
1611 let settings =
1612 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1613 .into_owned();
1614 let request_timeout = ProjectSettings::get_global(cx)
1615 .global_lsp_settings
1616 .get_request_timeout();
1617 (adapters_and_servers, settings, request_timeout)
1618 })
1619 })?;
1620
1621 /// Apply edits to the buffer that will become part of the formatting transaction.
1622 /// Fails if the buffer has been edited since the start of that transaction.
1623 fn extend_formatting_transaction(
1624 buffer: &FormattableBuffer,
1625 formatting_transaction_id: text::TransactionId,
1626 cx: &mut AsyncApp,
1627 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1628 ) -> anyhow::Result<()> {
1629 buffer.handle.update(cx, |buffer, cx| {
1630 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1631 if last_transaction_id != Some(formatting_transaction_id) {
1632 anyhow::bail!("Buffer edited while formatting. Aborting")
1633 }
1634 buffer.start_transaction();
1635 operation(buffer, cx);
1636 if let Some(transaction_id) = buffer.end_transaction(cx) {
1637 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1638 }
1639 Ok(())
1640 })
1641 }
1642
1643 // handle whitespace formatting
1644 if settings.remove_trailing_whitespace_on_save {
1645 zlog::trace!(logger => "removing trailing whitespace");
1646 let diff = buffer
1647 .handle
1648 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1649 .await;
1650 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1651 buffer.apply_diff(diff, cx);
1652 })?;
1653 }
1654
1655 if settings.ensure_final_newline_on_save {
1656 zlog::trace!(logger => "ensuring final newline");
1657 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1658 buffer.ensure_final_newline(cx);
1659 })?;
1660 }
1661
1662 // Formatter for `code_actions_on_format` that runs before
1663 // the rest of the formatters
1664 let mut code_actions_on_format_formatters = None;
1665 let should_run_code_actions_on_format = !matches!(
1666 (trigger, &settings.format_on_save),
1667 (FormatTrigger::Save, &FormatOnSave::Off)
1668 );
1669 if should_run_code_actions_on_format {
1670 let have_code_actions_to_run_on_format = settings
1671 .code_actions_on_format
1672 .values()
1673 .any(|enabled| *enabled);
1674 if have_code_actions_to_run_on_format {
1675 zlog::trace!(logger => "going to run code actions on format");
1676 code_actions_on_format_formatters = Some(
1677 settings
1678 .code_actions_on_format
1679 .iter()
1680 .filter_map(|(action, enabled)| enabled.then_some(action))
1681 .cloned()
1682 .map(Formatter::CodeAction)
1683 .collect::<Vec<_>>(),
1684 );
1685 }
1686 }
1687
1688 let formatters = match (trigger, &settings.format_on_save) {
1689 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1690 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1691 settings.formatter.as_ref()
1692 }
1693 };
1694
1695 let formatters = code_actions_on_format_formatters
1696 .iter()
1697 .flatten()
1698 .chain(formatters);
1699
1700 for formatter in formatters {
1701 let formatter = if formatter == &Formatter::Auto {
1702 if settings.prettier.allowed {
1703 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1704 &Formatter::Prettier
1705 } else {
1706 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1707 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1708 }
1709 } else {
1710 formatter
1711 };
1712 match formatter {
1713 Formatter::Auto => unreachable!("Auto resolved above"),
1714 Formatter::Prettier => {
1715 let logger = zlog::scoped!(logger => "prettier");
1716 zlog::trace!(logger => "formatting");
1717 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1718
1719 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1720 lsp_store.prettier_store().unwrap().downgrade()
1721 })?;
1722 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1723 .await
1724 .transpose()?;
1725 let Some(diff) = diff else {
1726 zlog::trace!(logger => "No changes");
1727 continue;
1728 };
1729
1730 extend_formatting_transaction(
1731 buffer,
1732 formatting_transaction_id,
1733 cx,
1734 |buffer, cx| {
1735 buffer.apply_diff(diff, cx);
1736 },
1737 )?;
1738 }
1739 Formatter::External { command, arguments } => {
1740 let logger = zlog::scoped!(logger => "command");
1741 zlog::trace!(logger => "formatting");
1742 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1743
1744 let diff = Self::format_via_external_command(
1745 buffer,
1746 &command,
1747 arguments.as_deref(),
1748 cx,
1749 )
1750 .await
1751 .with_context(|| {
1752 format!("Failed to format buffer via external command: {}", command)
1753 })?;
1754 let Some(diff) = diff else {
1755 zlog::trace!(logger => "No changes");
1756 continue;
1757 };
1758
1759 extend_formatting_transaction(
1760 buffer,
1761 formatting_transaction_id,
1762 cx,
1763 |buffer, cx| {
1764 buffer.apply_diff(diff, cx);
1765 },
1766 )?;
1767 }
1768 Formatter::LanguageServer(specifier) => {
1769 let logger = zlog::scoped!(logger => "language-server");
1770 zlog::trace!(logger => "formatting");
1771 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1772
1773 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1774 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1775 continue;
1776 };
1777
1778 let language_server = match specifier {
1779 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1780 adapters_and_servers.iter().find_map(|(adapter, server)| {
1781 if adapter.name.0.as_ref() == name {
1782 Some(server.clone())
1783 } else {
1784 None
1785 }
1786 })
1787 }
1788 settings::LanguageServerFormatterSpecifier::Current => {
1789 adapters_and_servers.first().map(|e| e.1.clone())
1790 }
1791 };
1792
1793 let Some(language_server) = language_server else {
1794 log::debug!(
1795 "No language server found to format buffer '{:?}'. Skipping",
1796 buffer_path_abs.as_path().to_string_lossy()
1797 );
1798 continue;
1799 };
1800
1801 zlog::trace!(
1802 logger =>
1803 "Formatting buffer '{:?}' using language server '{:?}'",
1804 buffer_path_abs.as_path().to_string_lossy(),
1805 language_server.name()
1806 );
1807
1808 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1809 zlog::trace!(logger => "formatting ranges");
1810 Self::format_ranges_via_lsp(
1811 &lsp_store,
1812 &buffer.handle,
1813 ranges,
1814 buffer_path_abs,
1815 &language_server,
1816 &settings,
1817 cx,
1818 )
1819 .await
1820 .context("Failed to format ranges via language server")?
1821 } else {
1822 zlog::trace!(logger => "formatting full");
1823 Self::format_via_lsp(
1824 &lsp_store,
1825 &buffer.handle,
1826 buffer_path_abs,
1827 &language_server,
1828 &settings,
1829 cx,
1830 )
1831 .await
1832 .context("failed to format via language server")?
1833 };
1834
1835 if edits.is_empty() {
1836 zlog::trace!(logger => "No changes");
1837 continue;
1838 }
1839 extend_formatting_transaction(
1840 buffer,
1841 formatting_transaction_id,
1842 cx,
1843 |buffer, cx| {
1844 buffer.edit(edits, None, cx);
1845 },
1846 )?;
1847 }
1848 Formatter::CodeAction(code_action_name) => {
1849 let logger = zlog::scoped!(logger => "code-actions");
1850 zlog::trace!(logger => "formatting");
1851 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1852
1853 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1854 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1855 continue;
1856 };
1857
1858 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1859 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1860
1861 let mut actions_and_servers = Vec::new();
1862
1863 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1864 let actions_result = Self::get_server_code_actions_from_action_kinds(
1865 &lsp_store,
1866 language_server.server_id(),
1867 vec![code_action_kind.clone()],
1868 &buffer.handle,
1869 cx,
1870 )
1871 .await
1872 .with_context(|| {
1873 format!(
1874 "Failed to resolve code action {:?} with language server {}",
1875 code_action_kind,
1876 language_server.name()
1877 )
1878 });
1879 let Ok(actions) = actions_result else {
1880 // note: it may be better to set result to the error and break formatters here
1881 // but for now we try to execute the actions that we can resolve and skip the rest
1882 zlog::error!(
1883 logger =>
1884 "Failed to resolve code action {:?} with language server {}",
1885 code_action_kind,
1886 language_server.name()
1887 );
1888 continue;
1889 };
1890 for action in actions {
1891 actions_and_servers.push((action, index));
1892 }
1893 }
1894
1895 if actions_and_servers.is_empty() {
1896 zlog::warn!(logger => "No code actions were resolved, continuing");
1897 continue;
1898 }
1899
1900 'actions: for (mut action, server_index) in actions_and_servers {
1901 let server = &adapters_and_servers[server_index].1;
1902
1903 let describe_code_action = |action: &CodeAction| {
1904 format!(
1905 "code action '{}' with title \"{}\" on server {}",
1906 action
1907 .lsp_action
1908 .action_kind()
1909 .unwrap_or("unknown".into())
1910 .as_str(),
1911 action.lsp_action.title(),
1912 server.name(),
1913 )
1914 };
1915
1916 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1917
1918 if let Err(err) =
1919 Self::try_resolve_code_action(server, &mut action, request_timeout)
1920 .await
1921 {
1922 zlog::error!(
1923 logger =>
1924 "Failed to resolve {}. Error: {}",
1925 describe_code_action(&action),
1926 err
1927 );
1928 continue;
1929 }
1930
1931 if let Some(edit) = action.lsp_action.edit().cloned() {
1932 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1933 // but filters out and logs warnings for code actions that require unreasonably
1934 // difficult handling on our part, such as:
1935 // - applying edits that call commands
1936 // which can result in arbitrary workspace edits being sent from the server that
1937 // have no way of being tied back to the command that initiated them (i.e. we
1938 // can't know which edits are part of the format request, or if the server is done sending
1939 // actions in response to the command)
1940 // - actions that create/delete/modify/rename files other than the one we are formatting
1941 // as we then would need to handle such changes correctly in the local history as well
1942 // as the remote history through the ProjectTransaction
1943 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1944 // Supporting these actions is not impossible, but not supported as of yet.
1945 if edit.changes.is_none() && edit.document_changes.is_none() {
1946 zlog::trace!(
1947 logger =>
1948 "No changes for code action. Skipping {}",
1949 describe_code_action(&action),
1950 );
1951 continue;
1952 }
1953
1954 let mut operations = Vec::new();
1955 if let Some(document_changes) = edit.document_changes {
1956 match document_changes {
1957 lsp::DocumentChanges::Edits(edits) => operations.extend(
1958 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1959 ),
1960 lsp::DocumentChanges::Operations(ops) => operations = ops,
1961 }
1962 } else if let Some(changes) = edit.changes {
1963 operations.extend(changes.into_iter().map(|(uri, edits)| {
1964 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1965 text_document:
1966 lsp::OptionalVersionedTextDocumentIdentifier {
1967 uri,
1968 version: None,
1969 },
1970 edits: edits.into_iter().map(Edit::Plain).collect(),
1971 })
1972 }));
1973 }
1974
1975 let mut edits = Vec::with_capacity(operations.len());
1976
1977 if operations.is_empty() {
1978 zlog::trace!(
1979 logger =>
1980 "No changes for code action. Skipping {}",
1981 describe_code_action(&action),
1982 );
1983 continue;
1984 }
1985 for operation in operations {
1986 let op = match operation {
1987 lsp::DocumentChangeOperation::Edit(op) => op,
1988 lsp::DocumentChangeOperation::Op(_) => {
1989 zlog::warn!(
1990 logger =>
1991 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1992 describe_code_action(&action),
1993 );
1994 continue 'actions;
1995 }
1996 };
1997 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1998 zlog::warn!(
1999 logger =>
2000 "Failed to convert URI '{:?}' to file path. Skipping {}",
2001 &op.text_document.uri,
2002 describe_code_action(&action),
2003 );
2004 continue 'actions;
2005 };
2006 if &file_path != buffer_path_abs {
2007 zlog::warn!(
2008 logger =>
2009 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2010 file_path,
2011 buffer_path_abs,
2012 describe_code_action(&action),
2013 );
2014 continue 'actions;
2015 }
2016
2017 let mut lsp_edits = Vec::new();
2018 for edit in op.edits {
2019 match edit {
2020 Edit::Plain(edit) => {
2021 if !lsp_edits.contains(&edit) {
2022 lsp_edits.push(edit);
2023 }
2024 }
2025 Edit::Annotated(edit) => {
2026 if !lsp_edits.contains(&edit.text_edit) {
2027 lsp_edits.push(edit.text_edit);
2028 }
2029 }
2030 Edit::Snippet(_) => {
2031 zlog::warn!(
2032 logger =>
2033 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2034 describe_code_action(&action),
2035 );
2036 continue 'actions;
2037 }
2038 }
2039 }
2040 let edits_result = lsp_store
2041 .update(cx, |lsp_store, cx| {
2042 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2043 &buffer.handle,
2044 lsp_edits,
2045 server.server_id(),
2046 op.text_document.version,
2047 cx,
2048 )
2049 })?
2050 .await;
2051 let Ok(resolved_edits) = edits_result else {
2052 zlog::warn!(
2053 logger =>
2054 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2055 buffer_path_abs.as_path(),
2056 describe_code_action(&action),
2057 );
2058 continue 'actions;
2059 };
2060 edits.extend(resolved_edits);
2061 }
2062
2063 if edits.is_empty() {
2064 zlog::warn!(logger => "No edits resolved from LSP");
2065 continue;
2066 }
2067
2068 extend_formatting_transaction(
2069 buffer,
2070 formatting_transaction_id,
2071 cx,
2072 |buffer, cx| {
2073 zlog::info!(
2074 "Applying edits {edits:?}. Content: {:?}",
2075 buffer.text()
2076 );
2077 buffer.edit(edits, None, cx);
2078 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2079 },
2080 )?;
2081 }
2082
2083 // bail early if command is invalid
2084 let Some(command) = action.lsp_action.command() else {
2085 continue;
2086 };
2087
2088 zlog::warn!(
2089 logger =>
2090 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2091 &command.command,
2092 );
2093
2094 let server_capabilities = server.capabilities();
2095 let available_commands = server_capabilities
2096 .execute_command_provider
2097 .as_ref()
2098 .map(|options| options.commands.as_slice())
2099 .unwrap_or_default();
2100 if !available_commands.contains(&command.command) {
2101 zlog::warn!(
2102 logger =>
2103 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2104 command.command,
2105 server.name(),
2106 );
2107 continue;
2108 }
2109
2110 // noop so we just ensure buffer hasn't been edited since resolving code actions
2111 extend_formatting_transaction(
2112 buffer,
2113 formatting_transaction_id,
2114 cx,
2115 |_, _| {},
2116 )?;
2117 zlog::info!(logger => "Executing command {}", &command.command);
2118
2119 lsp_store.update(cx, |this, _| {
2120 this.as_local_mut()
2121 .unwrap()
2122 .last_workspace_edits_by_language_server
2123 .remove(&server.server_id());
2124 })?;
2125
2126 let execute_command_result = server
2127 .request::<lsp::request::ExecuteCommand>(
2128 lsp::ExecuteCommandParams {
2129 command: command.command.clone(),
2130 arguments: command.arguments.clone().unwrap_or_default(),
2131 ..Default::default()
2132 },
2133 request_timeout,
2134 )
2135 .await
2136 .into_response();
2137
2138 if execute_command_result.is_err() {
2139 zlog::error!(
2140 logger =>
2141 "Failed to execute command '{}' as part of {}",
2142 &command.command,
2143 describe_code_action(&action),
2144 );
2145 continue 'actions;
2146 }
2147
2148 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2149 this.as_local_mut()
2150 .unwrap()
2151 .last_workspace_edits_by_language_server
2152 .remove(&server.server_id())
2153 .unwrap_or_default()
2154 })?;
2155
2156 if let Some(transaction) =
2157 project_transaction_command.0.remove(&buffer.handle)
2158 {
2159 zlog::trace!(
2160 logger =>
2161 "Successfully captured {} edits that resulted from command {}",
2162 transaction.edit_ids.len(),
2163 &command.command,
2164 );
2165 let transaction_id_project_transaction = transaction.id;
2166 buffer.handle.update(cx, |buffer, _| {
2167 // it may have been removed from history if push_to_history was
2168 // false in deserialize_workspace_edit. If so push it so we
2169 // can merge it with the format transaction
2170 // and pop the combined transaction off the history stack
2171 // later if push_to_history is false
2172 if buffer.get_transaction(transaction.id).is_none() {
2173 buffer.push_transaction(transaction, Instant::now());
2174 }
2175 buffer.merge_transactions(
2176 transaction_id_project_transaction,
2177 formatting_transaction_id,
2178 );
2179 });
2180 }
2181
2182 if project_transaction_command.0.is_empty() {
2183 continue;
2184 }
2185
2186 let mut extra_buffers = String::new();
2187 for buffer in project_transaction_command.0.keys() {
2188 buffer.read_with(cx, |b, cx| {
2189 let Some(path) = b.project_path(cx) else {
2190 return;
2191 };
2192
2193 if !extra_buffers.is_empty() {
2194 extra_buffers.push_str(", ");
2195 }
2196 extra_buffers.push_str(path.path.as_unix_str());
2197 });
2198 }
2199 zlog::warn!(
2200 logger =>
2201 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2202 &command.command,
2203 extra_buffers,
2204 );
2205 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2206 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2207 // add it so it's included, and merge it into the format transaction when its created later
2208 }
2209 }
2210 }
2211 }
2212
2213 Ok(())
2214 }
2215
2216 pub async fn format_ranges_via_lsp(
2217 this: &WeakEntity<LspStore>,
2218 buffer_handle: &Entity<Buffer>,
2219 ranges: &[Range<Anchor>],
2220 abs_path: &Path,
2221 language_server: &Arc<LanguageServer>,
2222 settings: &LanguageSettings,
2223 cx: &mut AsyncApp,
2224 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2225 let capabilities = &language_server.capabilities();
2226 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2227 if range_formatting_provider == Some(&OneOf::Left(false)) {
2228 anyhow::bail!(
2229 "{} language server does not support range formatting",
2230 language_server.name()
2231 );
2232 }
2233
2234 let uri = file_path_to_lsp_url(abs_path)?;
2235 let text_document = lsp::TextDocumentIdentifier::new(uri);
2236
2237 let request_timeout = cx.update(|app| {
2238 ProjectSettings::get_global(app)
2239 .global_lsp_settings
2240 .get_request_timeout()
2241 });
2242 let lsp_edits = {
2243 let mut lsp_ranges = Vec::new();
2244 this.update(cx, |_this, cx| {
2245 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2246 // not have been sent to the language server. This seems like a fairly systemic
2247 // issue, though, the resolution probably is not specific to formatting.
2248 //
2249 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2250 // LSP.
2251 let snapshot = buffer_handle.read(cx).snapshot();
2252 for range in ranges {
2253 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2254 }
2255 anyhow::Ok(())
2256 })??;
2257
2258 let mut edits = None;
2259 for range in lsp_ranges {
2260 if let Some(mut edit) = language_server
2261 .request::<lsp::request::RangeFormatting>(
2262 lsp::DocumentRangeFormattingParams {
2263 text_document: text_document.clone(),
2264 range,
2265 options: lsp_command::lsp_formatting_options(settings),
2266 work_done_progress_params: Default::default(),
2267 },
2268 request_timeout,
2269 )
2270 .await
2271 .into_response()?
2272 {
2273 edits.get_or_insert_with(Vec::new).append(&mut edit);
2274 }
2275 }
2276 edits
2277 };
2278
2279 if let Some(lsp_edits) = lsp_edits {
2280 this.update(cx, |this, cx| {
2281 this.as_local_mut().unwrap().edits_from_lsp(
2282 buffer_handle,
2283 lsp_edits,
2284 language_server.server_id(),
2285 None,
2286 cx,
2287 )
2288 })?
2289 .await
2290 } else {
2291 Ok(Vec::with_capacity(0))
2292 }
2293 }
2294
2295 async fn format_via_lsp(
2296 this: &WeakEntity<LspStore>,
2297 buffer: &Entity<Buffer>,
2298 abs_path: &Path,
2299 language_server: &Arc<LanguageServer>,
2300 settings: &LanguageSettings,
2301 cx: &mut AsyncApp,
2302 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2303 let logger = zlog::scoped!("lsp_format");
2304 zlog::debug!(logger => "Formatting via LSP");
2305
2306 let uri = file_path_to_lsp_url(abs_path)?;
2307 let text_document = lsp::TextDocumentIdentifier::new(uri);
2308 let capabilities = &language_server.capabilities();
2309
2310 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2311 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2312
2313 let request_timeout = cx.update(|app| {
2314 ProjectSettings::get_global(app)
2315 .global_lsp_settings
2316 .get_request_timeout()
2317 });
2318
2319 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2320 let _timer = zlog::time!(logger => "format-full");
2321 language_server
2322 .request::<lsp::request::Formatting>(
2323 lsp::DocumentFormattingParams {
2324 text_document,
2325 options: lsp_command::lsp_formatting_options(settings),
2326 work_done_progress_params: Default::default(),
2327 },
2328 request_timeout,
2329 )
2330 .await
2331 .into_response()?
2332 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2333 let _timer = zlog::time!(logger => "format-range");
2334 let buffer_start = lsp::Position::new(0, 0);
2335 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2336 language_server
2337 .request::<lsp::request::RangeFormatting>(
2338 lsp::DocumentRangeFormattingParams {
2339 text_document: text_document.clone(),
2340 range: lsp::Range::new(buffer_start, buffer_end),
2341 options: lsp_command::lsp_formatting_options(settings),
2342 work_done_progress_params: Default::default(),
2343 },
2344 request_timeout,
2345 )
2346 .await
2347 .into_response()?
2348 } else {
2349 None
2350 };
2351
2352 if let Some(lsp_edits) = lsp_edits {
2353 this.update(cx, |this, cx| {
2354 this.as_local_mut().unwrap().edits_from_lsp(
2355 buffer,
2356 lsp_edits,
2357 language_server.server_id(),
2358 None,
2359 cx,
2360 )
2361 })?
2362 .await
2363 } else {
2364 Ok(Vec::with_capacity(0))
2365 }
2366 }
2367
2368 async fn format_via_external_command(
2369 buffer: &FormattableBuffer,
2370 command: &str,
2371 arguments: Option<&[String]>,
2372 cx: &mut AsyncApp,
2373 ) -> Result<Option<Diff>> {
2374 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2375 let file = File::from_dyn(buffer.file())?;
2376 let worktree = file.worktree.read(cx);
2377 let mut worktree_path = worktree.abs_path().to_path_buf();
2378 if worktree.root_entry()?.is_file() {
2379 worktree_path.pop();
2380 }
2381 Some(worktree_path)
2382 });
2383
2384 use util::command::Stdio;
2385 let mut child = util::command::new_command(command);
2386
2387 if let Some(buffer_env) = buffer.env.as_ref() {
2388 child.envs(buffer_env);
2389 }
2390
2391 if let Some(working_dir_path) = working_dir_path {
2392 child.current_dir(working_dir_path);
2393 }
2394
2395 if let Some(arguments) = arguments {
2396 child.args(arguments.iter().map(|arg| {
2397 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2398 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2399 } else {
2400 arg.replace("{buffer_path}", "Untitled")
2401 }
2402 }));
2403 }
2404
2405 let mut child = child
2406 .stdin(Stdio::piped())
2407 .stdout(Stdio::piped())
2408 .stderr(Stdio::piped())
2409 .spawn()?;
2410
2411 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2412 let text = buffer
2413 .handle
2414 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2415 for chunk in text.chunks() {
2416 stdin.write_all(chunk.as_bytes()).await?;
2417 }
2418 stdin.flush().await?;
2419
2420 let output = child.output().await?;
2421 anyhow::ensure!(
2422 output.status.success(),
2423 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2424 output.status.code(),
2425 String::from_utf8_lossy(&output.stdout),
2426 String::from_utf8_lossy(&output.stderr),
2427 );
2428
2429 let stdout = String::from_utf8(output.stdout)?;
2430 Ok(Some(
2431 buffer
2432 .handle
2433 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2434 .await,
2435 ))
2436 }
2437
2438 async fn try_resolve_code_action(
2439 lang_server: &LanguageServer,
2440 action: &mut CodeAction,
2441 request_timeout: Duration,
2442 ) -> anyhow::Result<()> {
2443 match &mut action.lsp_action {
2444 LspAction::Action(lsp_action) => {
2445 if !action.resolved
2446 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2447 && lsp_action.data.is_some()
2448 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2449 {
2450 **lsp_action = lang_server
2451 .request::<lsp::request::CodeActionResolveRequest>(
2452 *lsp_action.clone(),
2453 request_timeout,
2454 )
2455 .await
2456 .into_response()?;
2457 }
2458 }
2459 LspAction::CodeLens(lens) => {
2460 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2461 *lens = lang_server
2462 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2463 .await
2464 .into_response()?;
2465 }
2466 }
2467 LspAction::Command(_) => {}
2468 }
2469
2470 action.resolved = true;
2471 anyhow::Ok(())
2472 }
2473
2474 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2475 let buffer = buffer_handle.read(cx);
2476
2477 let file = buffer.file().cloned();
2478
2479 let Some(file) = File::from_dyn(file.as_ref()) else {
2480 return;
2481 };
2482 if !file.is_local() {
2483 return;
2484 }
2485 let path = ProjectPath::from_file(file, cx);
2486 let worktree_id = file.worktree_id(cx);
2487 let language = buffer.language().cloned();
2488
2489 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2490 for (server_id, diagnostics) in
2491 diagnostics.get(file.path()).cloned().unwrap_or_default()
2492 {
2493 self.update_buffer_diagnostics(
2494 buffer_handle,
2495 server_id,
2496 None,
2497 None,
2498 None,
2499 Vec::new(),
2500 diagnostics,
2501 cx,
2502 )
2503 .log_err();
2504 }
2505 }
2506 let Some(language) = language else {
2507 return;
2508 };
2509 let Some(snapshot) = self
2510 .worktree_store
2511 .read(cx)
2512 .worktree_for_id(worktree_id, cx)
2513 .map(|worktree| worktree.read(cx).snapshot())
2514 else {
2515 return;
2516 };
2517 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2518
2519 for server_id in
2520 self.lsp_tree
2521 .get(path, language.name(), language.manifest(), &delegate, cx)
2522 {
2523 let server = self
2524 .language_servers
2525 .get(&server_id)
2526 .and_then(|server_state| {
2527 if let LanguageServerState::Running { server, .. } = server_state {
2528 Some(server.clone())
2529 } else {
2530 None
2531 }
2532 });
2533 let server = match server {
2534 Some(server) => server,
2535 None => continue,
2536 };
2537
2538 buffer_handle.update(cx, |buffer, cx| {
2539 buffer.set_completion_triggers(
2540 server.server_id(),
2541 server
2542 .capabilities()
2543 .completion_provider
2544 .as_ref()
2545 .and_then(|provider| {
2546 provider
2547 .trigger_characters
2548 .as_ref()
2549 .map(|characters| characters.iter().cloned().collect())
2550 })
2551 .unwrap_or_default(),
2552 cx,
2553 );
2554 });
2555 }
2556 }
2557
2558 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2559 buffer.update(cx, |buffer, cx| {
2560 let Some(language) = buffer.language() else {
2561 return;
2562 };
2563 let path = ProjectPath {
2564 worktree_id: old_file.worktree_id(cx),
2565 path: old_file.path.clone(),
2566 };
2567 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2568 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2569 buffer.set_completion_triggers(server_id, Default::default(), cx);
2570 }
2571 });
2572 }
2573
2574 fn update_buffer_diagnostics(
2575 &mut self,
2576 buffer: &Entity<Buffer>,
2577 server_id: LanguageServerId,
2578 registration_id: Option<Option<SharedString>>,
2579 result_id: Option<SharedString>,
2580 version: Option<i32>,
2581 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2582 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2583 cx: &mut Context<LspStore>,
2584 ) -> Result<()> {
2585 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2586 Ordering::Equal
2587 .then_with(|| b.is_primary.cmp(&a.is_primary))
2588 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2589 .then_with(|| a.severity.cmp(&b.severity))
2590 .then_with(|| a.message.cmp(&b.message))
2591 }
2592
2593 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2594 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2595 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2596
2597 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2598 Ordering::Equal
2599 .then_with(|| a.range.start.cmp(&b.range.start))
2600 .then_with(|| b.range.end.cmp(&a.range.end))
2601 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2602 });
2603
2604 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2605
2606 let edits_since_save = std::cell::LazyCell::new(|| {
2607 let saved_version = buffer.read(cx).saved_version();
2608 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2609 });
2610
2611 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2612
2613 for (new_diagnostic, entry) in diagnostics {
2614 let start;
2615 let end;
2616 if new_diagnostic && entry.diagnostic.is_disk_based {
2617 // Some diagnostics are based on files on disk instead of buffers'
2618 // current contents. Adjust these diagnostics' ranges to reflect
2619 // any unsaved edits.
2620 // Do not alter the reused ones though, as their coordinates were stored as anchors
2621 // and were properly adjusted on reuse.
2622 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2623 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2624 } else {
2625 start = entry.range.start;
2626 end = entry.range.end;
2627 }
2628
2629 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2630 ..snapshot.clip_point_utf16(end, Bias::Right);
2631
2632 // Expand empty ranges by one codepoint
2633 if range.start == range.end {
2634 // This will be go to the next boundary when being clipped
2635 range.end.column += 1;
2636 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2637 if range.start == range.end && range.end.column > 0 {
2638 range.start.column -= 1;
2639 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2640 }
2641 }
2642
2643 sanitized_diagnostics.push(DiagnosticEntry {
2644 range,
2645 diagnostic: entry.diagnostic,
2646 });
2647 }
2648 drop(edits_since_save);
2649
2650 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2651 buffer.update(cx, |buffer, cx| {
2652 if let Some(registration_id) = registration_id {
2653 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2654 self.buffer_pull_diagnostics_result_ids
2655 .entry(server_id)
2656 .or_default()
2657 .entry(registration_id)
2658 .or_default()
2659 .insert(abs_path, result_id);
2660 }
2661 }
2662
2663 buffer.update_diagnostics(server_id, set, cx)
2664 });
2665
2666 Ok(())
2667 }
2668
2669 fn register_language_server_for_invisible_worktree(
2670 &mut self,
2671 worktree: &Entity<Worktree>,
2672 language_server_id: LanguageServerId,
2673 cx: &mut App,
2674 ) {
2675 let worktree = worktree.read(cx);
2676 let worktree_id = worktree.id();
2677 debug_assert!(!worktree.is_visible());
2678 let Some(mut origin_seed) = self
2679 .language_server_ids
2680 .iter()
2681 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2682 else {
2683 return;
2684 };
2685 origin_seed.worktree_id = worktree_id;
2686 self.language_server_ids
2687 .entry(origin_seed)
2688 .or_insert_with(|| UnifiedLanguageServer {
2689 id: language_server_id,
2690 project_roots: Default::default(),
2691 });
2692 }
2693
2694 fn register_buffer_with_language_servers(
2695 &mut self,
2696 buffer_handle: &Entity<Buffer>,
2697 only_register_servers: HashSet<LanguageServerSelector>,
2698 cx: &mut Context<LspStore>,
2699 ) {
2700 let buffer = buffer_handle.read(cx);
2701 let buffer_id = buffer.remote_id();
2702
2703 let Some(file) = File::from_dyn(buffer.file()) else {
2704 return;
2705 };
2706 if !file.is_local() {
2707 return;
2708 }
2709
2710 let abs_path = file.abs_path(cx);
2711 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2712 return;
2713 };
2714 let initial_snapshot = buffer.text_snapshot();
2715 let worktree_id = file.worktree_id(cx);
2716
2717 let Some(language) = buffer.language().cloned() else {
2718 return;
2719 };
2720 let path: Arc<RelPath> = file
2721 .path()
2722 .parent()
2723 .map(Arc::from)
2724 .unwrap_or_else(|| file.path().clone());
2725 let Some(worktree) = self
2726 .worktree_store
2727 .read(cx)
2728 .worktree_for_id(worktree_id, cx)
2729 else {
2730 return;
2731 };
2732 let language_name = language.name();
2733 let (reused, delegate, servers) = self
2734 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2735 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2736 .unwrap_or_else(|| {
2737 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2738 let delegate: Arc<dyn ManifestDelegate> =
2739 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2740
2741 let servers = self
2742 .lsp_tree
2743 .walk(
2744 ProjectPath { worktree_id, path },
2745 language.name(),
2746 language.manifest(),
2747 &delegate,
2748 cx,
2749 )
2750 .collect::<Vec<_>>();
2751 (false, lsp_delegate, servers)
2752 });
2753 let servers_and_adapters = servers
2754 .into_iter()
2755 .filter_map(|server_node| {
2756 if reused && server_node.server_id().is_none() {
2757 return None;
2758 }
2759 if !only_register_servers.is_empty() {
2760 if let Some(server_id) = server_node.server_id()
2761 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2762 {
2763 return None;
2764 }
2765 if let Some(name) = server_node.name()
2766 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2767 {
2768 return None;
2769 }
2770 }
2771
2772 let server_id = server_node.server_id_or_init(|disposition| {
2773 let path = &disposition.path;
2774
2775 {
2776 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2777
2778 let server_id = self.get_or_insert_language_server(
2779 &worktree,
2780 delegate.clone(),
2781 disposition,
2782 &language_name,
2783 cx,
2784 );
2785
2786 if let Some(state) = self.language_servers.get(&server_id)
2787 && let Ok(uri) = uri
2788 {
2789 state.add_workspace_folder(uri);
2790 };
2791 server_id
2792 }
2793 })?;
2794 let server_state = self.language_servers.get(&server_id)?;
2795 if let LanguageServerState::Running {
2796 server, adapter, ..
2797 } = server_state
2798 {
2799 Some((server.clone(), adapter.clone()))
2800 } else {
2801 None
2802 }
2803 })
2804 .collect::<Vec<_>>();
2805 for (server, adapter) in servers_and_adapters {
2806 buffer_handle.update(cx, |buffer, cx| {
2807 buffer.set_completion_triggers(
2808 server.server_id(),
2809 server
2810 .capabilities()
2811 .completion_provider
2812 .as_ref()
2813 .and_then(|provider| {
2814 provider
2815 .trigger_characters
2816 .as_ref()
2817 .map(|characters| characters.iter().cloned().collect())
2818 })
2819 .unwrap_or_default(),
2820 cx,
2821 );
2822 });
2823
2824 let snapshot = LspBufferSnapshot {
2825 version: 0,
2826 snapshot: initial_snapshot.clone(),
2827 };
2828
2829 let mut registered = false;
2830 self.buffer_snapshots
2831 .entry(buffer_id)
2832 .or_default()
2833 .entry(server.server_id())
2834 .or_insert_with(|| {
2835 registered = true;
2836 server.register_buffer(
2837 uri.clone(),
2838 adapter.language_id(&language.name()),
2839 0,
2840 initial_snapshot.text(),
2841 );
2842
2843 vec![snapshot]
2844 });
2845
2846 self.buffers_opened_in_servers
2847 .entry(buffer_id)
2848 .or_default()
2849 .insert(server.server_id());
2850 if registered {
2851 cx.emit(LspStoreEvent::LanguageServerUpdate {
2852 language_server_id: server.server_id(),
2853 name: None,
2854 message: proto::update_language_server::Variant::RegisteredForBuffer(
2855 proto::RegisteredForBuffer {
2856 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2857 buffer_id: buffer_id.to_proto(),
2858 },
2859 ),
2860 });
2861 }
2862 }
2863 }
2864
2865 fn reuse_existing_language_server<'lang_name>(
2866 &self,
2867 server_tree: &LanguageServerTree,
2868 worktree: &Entity<Worktree>,
2869 language_name: &'lang_name LanguageName,
2870 cx: &mut App,
2871 ) -> Option<(
2872 Arc<LocalLspAdapterDelegate>,
2873 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2874 )> {
2875 if worktree.read(cx).is_visible() {
2876 return None;
2877 }
2878
2879 let worktree_store = self.worktree_store.read(cx);
2880 let servers = server_tree
2881 .instances
2882 .iter()
2883 .filter(|(worktree_id, _)| {
2884 worktree_store
2885 .worktree_for_id(**worktree_id, cx)
2886 .is_some_and(|worktree| worktree.read(cx).is_visible())
2887 })
2888 .flat_map(|(worktree_id, servers)| {
2889 servers
2890 .roots
2891 .iter()
2892 .flat_map(|(_, language_servers)| language_servers)
2893 .map(move |(_, (server_node, server_languages))| {
2894 (worktree_id, server_node, server_languages)
2895 })
2896 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2897 .map(|(worktree_id, server_node, _)| {
2898 (
2899 *worktree_id,
2900 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2901 )
2902 })
2903 })
2904 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2905 acc.entry(worktree_id)
2906 .or_insert_with(Vec::new)
2907 .push(server_node);
2908 acc
2909 })
2910 .into_values()
2911 .max_by_key(|servers| servers.len())?;
2912
2913 let worktree_id = worktree.read(cx).id();
2914 let apply = move |tree: &mut LanguageServerTree| {
2915 for server_node in &servers {
2916 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2917 }
2918 servers
2919 };
2920
2921 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2922 Some((delegate, apply))
2923 }
2924
2925 pub(crate) fn unregister_old_buffer_from_language_servers(
2926 &mut self,
2927 buffer: &Entity<Buffer>,
2928 old_file: &File,
2929 cx: &mut App,
2930 ) {
2931 let old_path = match old_file.as_local() {
2932 Some(local) => local.abs_path(cx),
2933 None => return,
2934 };
2935
2936 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2937 debug_panic!("{old_path:?} is not parseable as an URI");
2938 return;
2939 };
2940 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2941 }
2942
2943 pub(crate) fn unregister_buffer_from_language_servers(
2944 &mut self,
2945 buffer: &Entity<Buffer>,
2946 file_url: &lsp::Uri,
2947 cx: &mut App,
2948 ) {
2949 buffer.update(cx, |buffer, cx| {
2950 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2951
2952 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2953 if snapshots
2954 .as_mut()
2955 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2956 {
2957 language_server.unregister_buffer(file_url.clone());
2958 }
2959 }
2960 });
2961 }
2962
2963 fn buffer_snapshot_for_lsp_version(
2964 &mut self,
2965 buffer: &Entity<Buffer>,
2966 server_id: LanguageServerId,
2967 version: Option<i32>,
2968 cx: &App,
2969 ) -> Result<TextBufferSnapshot> {
2970 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2971
2972 if let Some(version) = version {
2973 let buffer_id = buffer.read(cx).remote_id();
2974 let snapshots = if let Some(snapshots) = self
2975 .buffer_snapshots
2976 .get_mut(&buffer_id)
2977 .and_then(|m| m.get_mut(&server_id))
2978 {
2979 snapshots
2980 } else if version == 0 {
2981 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2982 // We detect this case and treat it as if the version was `None`.
2983 return Ok(buffer.read(cx).text_snapshot());
2984 } else {
2985 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2986 };
2987
2988 let found_snapshot = snapshots
2989 .binary_search_by_key(&version, |e| e.version)
2990 .map(|ix| snapshots[ix].snapshot.clone())
2991 .map_err(|_| {
2992 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2993 })?;
2994
2995 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2996 Ok(found_snapshot)
2997 } else {
2998 Ok((buffer.read(cx)).text_snapshot())
2999 }
3000 }
3001
3002 async fn get_server_code_actions_from_action_kinds(
3003 lsp_store: &WeakEntity<LspStore>,
3004 language_server_id: LanguageServerId,
3005 code_action_kinds: Vec<lsp::CodeActionKind>,
3006 buffer: &Entity<Buffer>,
3007 cx: &mut AsyncApp,
3008 ) -> Result<Vec<CodeAction>> {
3009 let actions = lsp_store
3010 .update(cx, move |this, cx| {
3011 let request = GetCodeActions {
3012 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3013 kinds: Some(code_action_kinds),
3014 };
3015 let server = LanguageServerToQuery::Other(language_server_id);
3016 this.request_lsp(buffer.clone(), server, request, cx)
3017 })?
3018 .await?;
3019 Ok(actions)
3020 }
3021
3022 pub async fn execute_code_actions_on_server(
3023 lsp_store: &WeakEntity<LspStore>,
3024 language_server: &Arc<LanguageServer>,
3025 actions: Vec<CodeAction>,
3026 push_to_history: bool,
3027 project_transaction: &mut ProjectTransaction,
3028 cx: &mut AsyncApp,
3029 ) -> anyhow::Result<()> {
3030 let request_timeout = cx.update(|app| {
3031 ProjectSettings::get_global(app)
3032 .global_lsp_settings
3033 .get_request_timeout()
3034 });
3035
3036 for mut action in actions {
3037 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3038 .await
3039 .context("resolving a formatting code action")?;
3040
3041 if let Some(edit) = action.lsp_action.edit() {
3042 if edit.changes.is_none() && edit.document_changes.is_none() {
3043 continue;
3044 }
3045
3046 let new = Self::deserialize_workspace_edit(
3047 lsp_store.upgrade().context("project dropped")?,
3048 edit.clone(),
3049 push_to_history,
3050 language_server.clone(),
3051 cx,
3052 )
3053 .await?;
3054 project_transaction.0.extend(new.0);
3055 }
3056
3057 let Some(command) = action.lsp_action.command() else {
3058 continue;
3059 };
3060
3061 let server_capabilities = language_server.capabilities();
3062 let available_commands = server_capabilities
3063 .execute_command_provider
3064 .as_ref()
3065 .map(|options| options.commands.as_slice())
3066 .unwrap_or_default();
3067 if !available_commands.contains(&command.command) {
3068 log::warn!(
3069 "Cannot execute a command {} not listed in the language server capabilities",
3070 command.command
3071 );
3072 continue;
3073 }
3074
3075 lsp_store.update(cx, |lsp_store, _| {
3076 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3077 mode.last_workspace_edits_by_language_server
3078 .remove(&language_server.server_id());
3079 }
3080 })?;
3081
3082 language_server
3083 .request::<lsp::request::ExecuteCommand>(
3084 lsp::ExecuteCommandParams {
3085 command: command.command.clone(),
3086 arguments: command.arguments.clone().unwrap_or_default(),
3087 ..Default::default()
3088 },
3089 request_timeout,
3090 )
3091 .await
3092 .into_response()
3093 .context("execute command")?;
3094
3095 lsp_store.update(cx, |this, _| {
3096 if let LspStoreMode::Local(mode) = &mut this.mode {
3097 project_transaction.0.extend(
3098 mode.last_workspace_edits_by_language_server
3099 .remove(&language_server.server_id())
3100 .unwrap_or_default()
3101 .0,
3102 )
3103 }
3104 })?;
3105 }
3106 Ok(())
3107 }
3108
3109 pub async fn deserialize_text_edits(
3110 this: Entity<LspStore>,
3111 buffer_to_edit: Entity<Buffer>,
3112 edits: Vec<lsp::TextEdit>,
3113 push_to_history: bool,
3114 _: Arc<CachedLspAdapter>,
3115 language_server: Arc<LanguageServer>,
3116 cx: &mut AsyncApp,
3117 ) -> Result<Option<Transaction>> {
3118 let edits = this
3119 .update(cx, |this, cx| {
3120 this.as_local_mut().unwrap().edits_from_lsp(
3121 &buffer_to_edit,
3122 edits,
3123 language_server.server_id(),
3124 None,
3125 cx,
3126 )
3127 })
3128 .await?;
3129
3130 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3131 buffer.finalize_last_transaction();
3132 buffer.start_transaction();
3133 for (range, text) in edits {
3134 buffer.edit([(range, text)], None, cx);
3135 }
3136
3137 if buffer.end_transaction(cx).is_some() {
3138 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3139 if !push_to_history {
3140 buffer.forget_transaction(transaction.id);
3141 }
3142 Some(transaction)
3143 } else {
3144 None
3145 }
3146 });
3147
3148 Ok(transaction)
3149 }
3150
3151 #[allow(clippy::type_complexity)]
3152 pub fn edits_from_lsp(
3153 &mut self,
3154 buffer: &Entity<Buffer>,
3155 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3156 server_id: LanguageServerId,
3157 version: Option<i32>,
3158 cx: &mut Context<LspStore>,
3159 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3160 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3161 cx.background_spawn(async move {
3162 let snapshot = snapshot?;
3163 let mut lsp_edits = lsp_edits
3164 .into_iter()
3165 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3166 .collect::<Vec<_>>();
3167
3168 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3169
3170 let mut lsp_edits = lsp_edits.into_iter().peekable();
3171 let mut edits = Vec::new();
3172 while let Some((range, mut new_text)) = lsp_edits.next() {
3173 // Clip invalid ranges provided by the language server.
3174 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3175 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3176
3177 // Combine any LSP edits that are adjacent.
3178 //
3179 // Also, combine LSP edits that are separated from each other by only
3180 // a newline. This is important because for some code actions,
3181 // Rust-analyzer rewrites the entire buffer via a series of edits that
3182 // are separated by unchanged newline characters.
3183 //
3184 // In order for the diffing logic below to work properly, any edits that
3185 // cancel each other out must be combined into one.
3186 while let Some((next_range, next_text)) = lsp_edits.peek() {
3187 if next_range.start.0 > range.end {
3188 if next_range.start.0.row > range.end.row + 1
3189 || next_range.start.0.column > 0
3190 || snapshot.clip_point_utf16(
3191 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3192 Bias::Left,
3193 ) > range.end
3194 {
3195 break;
3196 }
3197 new_text.push('\n');
3198 }
3199 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3200 new_text.push_str(next_text);
3201 lsp_edits.next();
3202 }
3203
3204 // For multiline edits, perform a diff of the old and new text so that
3205 // we can identify the changes more precisely, preserving the locations
3206 // of any anchors positioned in the unchanged regions.
3207 if range.end.row > range.start.row {
3208 let offset = range.start.to_offset(&snapshot);
3209 let old_text = snapshot.text_for_range(range).collect::<String>();
3210 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3211 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3212 (
3213 snapshot.anchor_after(offset + range.start)
3214 ..snapshot.anchor_before(offset + range.end),
3215 replacement,
3216 )
3217 }));
3218 } else if range.end == range.start {
3219 let anchor = snapshot.anchor_after(range.start);
3220 edits.push((anchor..anchor, new_text.into()));
3221 } else {
3222 let edit_start = snapshot.anchor_after(range.start);
3223 let edit_end = snapshot.anchor_before(range.end);
3224 edits.push((edit_start..edit_end, new_text.into()));
3225 }
3226 }
3227
3228 Ok(edits)
3229 })
3230 }
3231
3232 pub(crate) async fn deserialize_workspace_edit(
3233 this: Entity<LspStore>,
3234 edit: lsp::WorkspaceEdit,
3235 push_to_history: bool,
3236 language_server: Arc<LanguageServer>,
3237 cx: &mut AsyncApp,
3238 ) -> Result<ProjectTransaction> {
3239 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3240
3241 let mut operations = Vec::new();
3242 if let Some(document_changes) = edit.document_changes {
3243 match document_changes {
3244 lsp::DocumentChanges::Edits(edits) => {
3245 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3246 }
3247 lsp::DocumentChanges::Operations(ops) => operations = ops,
3248 }
3249 } else if let Some(changes) = edit.changes {
3250 operations.extend(changes.into_iter().map(|(uri, edits)| {
3251 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3252 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3253 uri,
3254 version: None,
3255 },
3256 edits: edits.into_iter().map(Edit::Plain).collect(),
3257 })
3258 }));
3259 }
3260
3261 let mut project_transaction = ProjectTransaction::default();
3262 for operation in operations {
3263 match operation {
3264 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3265 let abs_path = op
3266 .uri
3267 .to_file_path()
3268 .map_err(|()| anyhow!("can't convert URI to path"))?;
3269
3270 if let Some(parent_path) = abs_path.parent() {
3271 fs.create_dir(parent_path).await?;
3272 }
3273 if abs_path.ends_with("/") {
3274 fs.create_dir(&abs_path).await?;
3275 } else {
3276 fs.create_file(
3277 &abs_path,
3278 op.options
3279 .map(|options| fs::CreateOptions {
3280 overwrite: options.overwrite.unwrap_or(false),
3281 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3282 })
3283 .unwrap_or_default(),
3284 )
3285 .await?;
3286 }
3287 }
3288
3289 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3290 let source_abs_path = op
3291 .old_uri
3292 .to_file_path()
3293 .map_err(|()| anyhow!("can't convert URI to path"))?;
3294 let target_abs_path = op
3295 .new_uri
3296 .to_file_path()
3297 .map_err(|()| anyhow!("can't convert URI to path"))?;
3298
3299 let options = fs::RenameOptions {
3300 overwrite: op
3301 .options
3302 .as_ref()
3303 .and_then(|options| options.overwrite)
3304 .unwrap_or(false),
3305 ignore_if_exists: op
3306 .options
3307 .as_ref()
3308 .and_then(|options| options.ignore_if_exists)
3309 .unwrap_or(false),
3310 create_parents: true,
3311 };
3312
3313 fs.rename(&source_abs_path, &target_abs_path, options)
3314 .await?;
3315 }
3316
3317 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3318 let abs_path = op
3319 .uri
3320 .to_file_path()
3321 .map_err(|()| anyhow!("can't convert URI to path"))?;
3322 let options = op
3323 .options
3324 .map(|options| fs::RemoveOptions {
3325 recursive: options.recursive.unwrap_or(false),
3326 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3327 })
3328 .unwrap_or_default();
3329 if abs_path.ends_with("/") {
3330 fs.remove_dir(&abs_path, options).await?;
3331 } else {
3332 fs.remove_file(&abs_path, options).await?;
3333 }
3334 }
3335
3336 lsp::DocumentChangeOperation::Edit(op) => {
3337 let buffer_to_edit = this
3338 .update(cx, |this, cx| {
3339 this.open_local_buffer_via_lsp(
3340 op.text_document.uri.clone(),
3341 language_server.server_id(),
3342 cx,
3343 )
3344 })
3345 .await?;
3346
3347 let edits = this
3348 .update(cx, |this, cx| {
3349 let path = buffer_to_edit.read(cx).project_path(cx);
3350 let active_entry = this.active_entry;
3351 let is_active_entry = path.is_some_and(|project_path| {
3352 this.worktree_store
3353 .read(cx)
3354 .entry_for_path(&project_path, cx)
3355 .is_some_and(|entry| Some(entry.id) == active_entry)
3356 });
3357 let local = this.as_local_mut().unwrap();
3358
3359 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3360 for edit in op.edits {
3361 match edit {
3362 Edit::Plain(edit) => {
3363 if !edits.contains(&edit) {
3364 edits.push(edit)
3365 }
3366 }
3367 Edit::Annotated(edit) => {
3368 if !edits.contains(&edit.text_edit) {
3369 edits.push(edit.text_edit)
3370 }
3371 }
3372 Edit::Snippet(edit) => {
3373 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3374 else {
3375 continue;
3376 };
3377
3378 if is_active_entry {
3379 snippet_edits.push((edit.range, snippet));
3380 } else {
3381 // Since this buffer is not focused, apply a normal edit.
3382 let new_edit = TextEdit {
3383 range: edit.range,
3384 new_text: snippet.text,
3385 };
3386 if !edits.contains(&new_edit) {
3387 edits.push(new_edit);
3388 }
3389 }
3390 }
3391 }
3392 }
3393 if !snippet_edits.is_empty() {
3394 let buffer_id = buffer_to_edit.read(cx).remote_id();
3395 let version = if let Some(buffer_version) = op.text_document.version
3396 {
3397 local
3398 .buffer_snapshot_for_lsp_version(
3399 &buffer_to_edit,
3400 language_server.server_id(),
3401 Some(buffer_version),
3402 cx,
3403 )
3404 .ok()
3405 .map(|snapshot| snapshot.version)
3406 } else {
3407 Some(buffer_to_edit.read(cx).saved_version().clone())
3408 };
3409
3410 let most_recent_edit =
3411 version.and_then(|version| version.most_recent());
3412 // Check if the edit that triggered that edit has been made by this participant.
3413
3414 if let Some(most_recent_edit) = most_recent_edit {
3415 cx.emit(LspStoreEvent::SnippetEdit {
3416 buffer_id,
3417 edits: snippet_edits,
3418 most_recent_edit,
3419 });
3420 }
3421 }
3422
3423 local.edits_from_lsp(
3424 &buffer_to_edit,
3425 edits,
3426 language_server.server_id(),
3427 op.text_document.version,
3428 cx,
3429 )
3430 })
3431 .await?;
3432
3433 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3434 buffer.finalize_last_transaction();
3435 buffer.start_transaction();
3436 for (range, text) in edits {
3437 buffer.edit([(range, text)], None, cx);
3438 }
3439
3440 buffer.end_transaction(cx).and_then(|transaction_id| {
3441 if push_to_history {
3442 buffer.finalize_last_transaction();
3443 buffer.get_transaction(transaction_id).cloned()
3444 } else {
3445 buffer.forget_transaction(transaction_id)
3446 }
3447 })
3448 });
3449 if let Some(transaction) = transaction {
3450 project_transaction.0.insert(buffer_to_edit, transaction);
3451 }
3452 }
3453 }
3454 }
3455
3456 Ok(project_transaction)
3457 }
3458
3459 async fn on_lsp_workspace_edit(
3460 this: WeakEntity<LspStore>,
3461 params: lsp::ApplyWorkspaceEditParams,
3462 server_id: LanguageServerId,
3463 cx: &mut AsyncApp,
3464 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3465 let this = this.upgrade().context("project project closed")?;
3466 let language_server = this
3467 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3468 .context("language server not found")?;
3469 let transaction = Self::deserialize_workspace_edit(
3470 this.clone(),
3471 params.edit,
3472 true,
3473 language_server.clone(),
3474 cx,
3475 )
3476 .await
3477 .log_err();
3478 this.update(cx, |this, cx| {
3479 if let Some(transaction) = transaction {
3480 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3481
3482 this.as_local_mut()
3483 .unwrap()
3484 .last_workspace_edits_by_language_server
3485 .insert(server_id, transaction);
3486 }
3487 });
3488 Ok(lsp::ApplyWorkspaceEditResponse {
3489 applied: true,
3490 failed_change: None,
3491 failure_reason: None,
3492 })
3493 }
3494
3495 fn remove_worktree(
3496 &mut self,
3497 id_to_remove: WorktreeId,
3498 cx: &mut Context<LspStore>,
3499 ) -> Vec<LanguageServerId> {
3500 self.restricted_worktrees_tasks.remove(&id_to_remove);
3501 self.diagnostics.remove(&id_to_remove);
3502 self.prettier_store.update(cx, |prettier_store, cx| {
3503 prettier_store.remove_worktree(id_to_remove, cx);
3504 });
3505
3506 let mut servers_to_remove = BTreeSet::default();
3507 let mut servers_to_preserve = HashSet::default();
3508 for (seed, state) in &self.language_server_ids {
3509 if seed.worktree_id == id_to_remove {
3510 servers_to_remove.insert(state.id);
3511 } else {
3512 servers_to_preserve.insert(state.id);
3513 }
3514 }
3515 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3516 self.language_server_ids
3517 .retain(|_, state| !servers_to_remove.contains(&state.id));
3518 for server_id_to_remove in &servers_to_remove {
3519 self.language_server_watched_paths
3520 .remove(server_id_to_remove);
3521 self.language_server_paths_watched_for_rename
3522 .remove(server_id_to_remove);
3523 self.last_workspace_edits_by_language_server
3524 .remove(server_id_to_remove);
3525 self.language_servers.remove(server_id_to_remove);
3526 self.buffer_pull_diagnostics_result_ids
3527 .remove(server_id_to_remove);
3528 self.workspace_pull_diagnostics_result_ids
3529 .remove(server_id_to_remove);
3530 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3531 buffer_servers.remove(server_id_to_remove);
3532 }
3533 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3534 }
3535 servers_to_remove.into_iter().collect()
3536 }
3537
3538 fn rebuild_watched_paths_inner<'a>(
3539 &'a self,
3540 language_server_id: LanguageServerId,
3541 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3542 cx: &mut Context<LspStore>,
3543 ) -> LanguageServerWatchedPathsBuilder {
3544 let worktrees = self
3545 .worktree_store
3546 .read(cx)
3547 .worktrees()
3548 .filter_map(|worktree| {
3549 self.language_servers_for_worktree(worktree.read(cx).id())
3550 .find(|server| server.server_id() == language_server_id)
3551 .map(|_| worktree)
3552 })
3553 .collect::<Vec<_>>();
3554
3555 let mut worktree_globs = HashMap::default();
3556 let mut abs_globs = HashMap::default();
3557 log::trace!(
3558 "Processing new watcher paths for language server with id {}",
3559 language_server_id
3560 );
3561
3562 for watcher in watchers {
3563 if let Some((worktree, literal_prefix, pattern)) =
3564 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3565 {
3566 worktree.update(cx, |worktree, _| {
3567 if let Some((tree, glob)) =
3568 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3569 {
3570 tree.add_path_prefix_to_scan(literal_prefix);
3571 worktree_globs
3572 .entry(tree.id())
3573 .or_insert_with(GlobSetBuilder::new)
3574 .add(glob);
3575 }
3576 });
3577 } else {
3578 let (path, pattern) = match &watcher.glob_pattern {
3579 lsp::GlobPattern::String(s) => {
3580 let watcher_path = SanitizedPath::new(s);
3581 let path = glob_literal_prefix(watcher_path.as_path());
3582 let pattern = watcher_path
3583 .as_path()
3584 .strip_prefix(&path)
3585 .map(|p| p.to_string_lossy().into_owned())
3586 .unwrap_or_else(|e| {
3587 debug_panic!(
3588 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3589 s,
3590 path.display(),
3591 e
3592 );
3593 watcher_path.as_path().to_string_lossy().into_owned()
3594 });
3595 (path, pattern)
3596 }
3597 lsp::GlobPattern::Relative(rp) => {
3598 let Ok(mut base_uri) = match &rp.base_uri {
3599 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3600 lsp::OneOf::Right(base_uri) => base_uri,
3601 }
3602 .to_file_path() else {
3603 continue;
3604 };
3605
3606 let path = glob_literal_prefix(Path::new(&rp.pattern));
3607 let pattern = Path::new(&rp.pattern)
3608 .strip_prefix(&path)
3609 .map(|p| p.to_string_lossy().into_owned())
3610 .unwrap_or_else(|e| {
3611 debug_panic!(
3612 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3613 rp.pattern,
3614 path.display(),
3615 e
3616 );
3617 rp.pattern.clone()
3618 });
3619 base_uri.push(path);
3620 (base_uri, pattern)
3621 }
3622 };
3623
3624 if let Some(glob) = Glob::new(&pattern).log_err() {
3625 if !path
3626 .components()
3627 .any(|c| matches!(c, path::Component::Normal(_)))
3628 {
3629 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3630 // rather than adding a new watcher for `/`.
3631 for worktree in &worktrees {
3632 worktree_globs
3633 .entry(worktree.read(cx).id())
3634 .or_insert_with(GlobSetBuilder::new)
3635 .add(glob.clone());
3636 }
3637 } else {
3638 abs_globs
3639 .entry(path.into())
3640 .or_insert_with(GlobSetBuilder::new)
3641 .add(glob);
3642 }
3643 }
3644 }
3645 }
3646
3647 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3648 for (worktree_id, builder) in worktree_globs {
3649 if let Ok(globset) = builder.build() {
3650 watch_builder.watch_worktree(worktree_id, globset);
3651 }
3652 }
3653 for (abs_path, builder) in abs_globs {
3654 if let Ok(globset) = builder.build() {
3655 watch_builder.watch_abs_path(abs_path, globset);
3656 }
3657 }
3658 watch_builder
3659 }
3660
3661 fn worktree_and_path_for_file_watcher(
3662 worktrees: &[Entity<Worktree>],
3663 watcher: &FileSystemWatcher,
3664 cx: &App,
3665 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3666 worktrees.iter().find_map(|worktree| {
3667 let tree = worktree.read(cx);
3668 let worktree_root_path = tree.abs_path();
3669 let path_style = tree.path_style();
3670 match &watcher.glob_pattern {
3671 lsp::GlobPattern::String(s) => {
3672 let watcher_path = SanitizedPath::new(s);
3673 let relative = watcher_path
3674 .as_path()
3675 .strip_prefix(&worktree_root_path)
3676 .ok()?;
3677 let literal_prefix = glob_literal_prefix(relative);
3678 Some((
3679 worktree.clone(),
3680 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3681 relative.to_string_lossy().into_owned(),
3682 ))
3683 }
3684 lsp::GlobPattern::Relative(rp) => {
3685 let base_uri = match &rp.base_uri {
3686 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3687 lsp::OneOf::Right(base_uri) => base_uri,
3688 }
3689 .to_file_path()
3690 .ok()?;
3691 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3692 let mut literal_prefix = relative.to_owned();
3693 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3694 Some((
3695 worktree.clone(),
3696 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3697 rp.pattern.clone(),
3698 ))
3699 }
3700 }
3701 })
3702 }
3703
3704 fn rebuild_watched_paths(
3705 &mut self,
3706 language_server_id: LanguageServerId,
3707 cx: &mut Context<LspStore>,
3708 ) {
3709 let Some(registrations) = self
3710 .language_server_dynamic_registrations
3711 .get(&language_server_id)
3712 else {
3713 return;
3714 };
3715
3716 let watch_builder = self.rebuild_watched_paths_inner(
3717 language_server_id,
3718 registrations.did_change_watched_files.values().flatten(),
3719 cx,
3720 );
3721 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3722 self.language_server_watched_paths
3723 .insert(language_server_id, watcher);
3724
3725 cx.notify();
3726 }
3727
3728 fn on_lsp_did_change_watched_files(
3729 &mut self,
3730 language_server_id: LanguageServerId,
3731 registration_id: &str,
3732 params: DidChangeWatchedFilesRegistrationOptions,
3733 cx: &mut Context<LspStore>,
3734 ) {
3735 let registrations = self
3736 .language_server_dynamic_registrations
3737 .entry(language_server_id)
3738 .or_default();
3739
3740 registrations
3741 .did_change_watched_files
3742 .insert(registration_id.to_string(), params.watchers);
3743
3744 self.rebuild_watched_paths(language_server_id, cx);
3745 }
3746
3747 fn on_lsp_unregister_did_change_watched_files(
3748 &mut self,
3749 language_server_id: LanguageServerId,
3750 registration_id: &str,
3751 cx: &mut Context<LspStore>,
3752 ) {
3753 let registrations = self
3754 .language_server_dynamic_registrations
3755 .entry(language_server_id)
3756 .or_default();
3757
3758 if registrations
3759 .did_change_watched_files
3760 .remove(registration_id)
3761 .is_some()
3762 {
3763 log::info!(
3764 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3765 language_server_id,
3766 registration_id
3767 );
3768 } else {
3769 log::warn!(
3770 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3771 language_server_id,
3772 registration_id
3773 );
3774 }
3775
3776 self.rebuild_watched_paths(language_server_id, cx);
3777 }
3778
3779 async fn initialization_options_for_adapter(
3780 adapter: Arc<dyn LspAdapter>,
3781 delegate: &Arc<dyn LspAdapterDelegate>,
3782 cx: &mut AsyncApp,
3783 ) -> Result<Option<serde_json::Value>> {
3784 let Some(mut initialization_config) =
3785 adapter.clone().initialization_options(delegate, cx).await?
3786 else {
3787 return Ok(None);
3788 };
3789
3790 for other_adapter in delegate.registered_lsp_adapters() {
3791 if other_adapter.name() == adapter.name() {
3792 continue;
3793 }
3794 if let Ok(Some(target_config)) = other_adapter
3795 .clone()
3796 .additional_initialization_options(adapter.name(), delegate)
3797 .await
3798 {
3799 merge_json_value_into(target_config.clone(), &mut initialization_config);
3800 }
3801 }
3802
3803 Ok(Some(initialization_config))
3804 }
3805
3806 async fn workspace_configuration_for_adapter(
3807 adapter: Arc<dyn LspAdapter>,
3808 delegate: &Arc<dyn LspAdapterDelegate>,
3809 toolchain: Option<Toolchain>,
3810 requested_uri: Option<Uri>,
3811 cx: &mut AsyncApp,
3812 ) -> Result<serde_json::Value> {
3813 let mut workspace_config = adapter
3814 .clone()
3815 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3816 .await?;
3817
3818 for other_adapter in delegate.registered_lsp_adapters() {
3819 if other_adapter.name() == adapter.name() {
3820 continue;
3821 }
3822 if let Ok(Some(target_config)) = other_adapter
3823 .clone()
3824 .additional_workspace_configuration(adapter.name(), delegate, cx)
3825 .await
3826 {
3827 merge_json_value_into(target_config.clone(), &mut workspace_config);
3828 }
3829 }
3830
3831 Ok(workspace_config)
3832 }
3833
3834 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3835 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3836 Some(server.clone())
3837 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3838 Some(Arc::clone(server))
3839 } else {
3840 None
3841 }
3842 }
3843}
3844
3845fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3846 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3847 cx.emit(LspStoreEvent::LanguageServerUpdate {
3848 language_server_id: server.server_id(),
3849 name: Some(server.name()),
3850 message: proto::update_language_server::Variant::MetadataUpdated(
3851 proto::ServerMetadataUpdated {
3852 capabilities: Some(capabilities),
3853 binary: Some(proto::LanguageServerBinaryInfo {
3854 path: server.binary().path.to_string_lossy().into_owned(),
3855 arguments: server
3856 .binary()
3857 .arguments
3858 .iter()
3859 .map(|arg| arg.to_string_lossy().into_owned())
3860 .collect(),
3861 }),
3862 configuration: serde_json::to_string(server.configuration()).ok(),
3863 workspace_folders: server
3864 .workspace_folders()
3865 .iter()
3866 .map(|uri| uri.to_string())
3867 .collect(),
3868 },
3869 ),
3870 });
3871 }
3872}
3873
3874#[derive(Debug)]
3875pub struct FormattableBuffer {
3876 handle: Entity<Buffer>,
3877 abs_path: Option<PathBuf>,
3878 env: Option<HashMap<String, String>>,
3879 ranges: Option<Vec<Range<Anchor>>>,
3880}
3881
3882pub struct RemoteLspStore {
3883 upstream_client: Option<AnyProtoClient>,
3884 upstream_project_id: u64,
3885}
3886
3887pub(crate) enum LspStoreMode {
3888 Local(LocalLspStore), // ssh host and collab host
3889 Remote(RemoteLspStore), // collab guest
3890}
3891
3892impl LspStoreMode {
3893 fn is_local(&self) -> bool {
3894 matches!(self, LspStoreMode::Local(_))
3895 }
3896}
3897
3898pub struct LspStore {
3899 mode: LspStoreMode,
3900 last_formatting_failure: Option<String>,
3901 downstream_client: Option<(AnyProtoClient, u64)>,
3902 nonce: u128,
3903 buffer_store: Entity<BufferStore>,
3904 worktree_store: Entity<WorktreeStore>,
3905 pub languages: Arc<LanguageRegistry>,
3906 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3907 active_entry: Option<ProjectEntryId>,
3908 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3909 _maintain_buffer_languages: Task<()>,
3910 diagnostic_summaries:
3911 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3912 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3913 semantic_token_config: SemanticTokenConfig,
3914 lsp_data: HashMap<BufferId, BufferLspData>,
3915 next_hint_id: Arc<AtomicUsize>,
3916}
3917
3918#[derive(Debug)]
3919pub struct BufferLspData {
3920 buffer_version: Global,
3921 document_colors: Option<DocumentColorData>,
3922 code_lens: Option<CodeLensData>,
3923 semantic_tokens: Option<SemanticTokensData>,
3924 folding_ranges: Option<FoldingRangeData>,
3925 document_symbols: Option<DocumentSymbolsData>,
3926 inlay_hints: BufferInlayHints,
3927 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3928 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3929}
3930
3931#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3932struct LspKey {
3933 request_type: TypeId,
3934 server_queried: Option<LanguageServerId>,
3935}
3936
3937impl BufferLspData {
3938 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3939 Self {
3940 buffer_version: buffer.read(cx).version(),
3941 document_colors: None,
3942 code_lens: None,
3943 semantic_tokens: None,
3944 folding_ranges: None,
3945 document_symbols: None,
3946 inlay_hints: BufferInlayHints::new(buffer, cx),
3947 lsp_requests: HashMap::default(),
3948 chunk_lsp_requests: HashMap::default(),
3949 }
3950 }
3951
3952 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3953 if let Some(document_colors) = &mut self.document_colors {
3954 document_colors.remove_server_data(for_server);
3955 }
3956
3957 if let Some(code_lens) = &mut self.code_lens {
3958 code_lens.remove_server_data(for_server);
3959 }
3960
3961 self.inlay_hints.remove_server_data(for_server);
3962
3963 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3964 semantic_tokens.raw_tokens.servers.remove(&for_server);
3965 semantic_tokens
3966 .latest_invalidation_requests
3967 .remove(&for_server);
3968 }
3969
3970 if let Some(folding_ranges) = &mut self.folding_ranges {
3971 folding_ranges.ranges.remove(&for_server);
3972 }
3973
3974 if let Some(document_symbols) = &mut self.document_symbols {
3975 document_symbols.remove_server_data(for_server);
3976 }
3977 }
3978
3979 #[cfg(any(test, feature = "test-support"))]
3980 pub fn inlay_hints(&self) -> &BufferInlayHints {
3981 &self.inlay_hints
3982 }
3983}
3984
3985#[derive(Debug)]
3986pub enum LspStoreEvent {
3987 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3988 LanguageServerRemoved(LanguageServerId),
3989 LanguageServerUpdate {
3990 language_server_id: LanguageServerId,
3991 name: Option<LanguageServerName>,
3992 message: proto::update_language_server::Variant,
3993 },
3994 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3995 LanguageServerPrompt(LanguageServerPromptRequest),
3996 LanguageDetected {
3997 buffer: Entity<Buffer>,
3998 new_language: Option<Arc<Language>>,
3999 },
4000 Notification(String),
4001 RefreshInlayHints {
4002 server_id: LanguageServerId,
4003 request_id: Option<usize>,
4004 },
4005 RefreshSemanticTokens {
4006 server_id: LanguageServerId,
4007 request_id: Option<usize>,
4008 },
4009 RefreshCodeLens,
4010 DiagnosticsUpdated {
4011 server_id: LanguageServerId,
4012 paths: Vec<ProjectPath>,
4013 },
4014 DiskBasedDiagnosticsStarted {
4015 language_server_id: LanguageServerId,
4016 },
4017 DiskBasedDiagnosticsFinished {
4018 language_server_id: LanguageServerId,
4019 },
4020 SnippetEdit {
4021 buffer_id: BufferId,
4022 edits: Vec<(lsp::Range, Snippet)>,
4023 most_recent_edit: clock::Lamport,
4024 },
4025 WorkspaceEditApplied(ProjectTransaction),
4026}
4027
4028#[derive(Clone, Debug, Serialize)]
4029pub struct LanguageServerStatus {
4030 pub name: LanguageServerName,
4031 pub server_version: Option<SharedString>,
4032 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4033 pub has_pending_diagnostic_updates: bool,
4034 pub progress_tokens: HashSet<ProgressToken>,
4035 pub worktree: Option<WorktreeId>,
4036 pub binary: Option<LanguageServerBinary>,
4037 pub configuration: Option<Value>,
4038 pub workspace_folders: BTreeSet<Uri>,
4039 pub process_id: Option<u32>,
4040}
4041
4042#[derive(Clone, Debug)]
4043struct CoreSymbol {
4044 pub language_server_name: LanguageServerName,
4045 pub source_worktree_id: WorktreeId,
4046 pub source_language_server_id: LanguageServerId,
4047 pub path: SymbolLocation,
4048 pub name: String,
4049 pub kind: lsp::SymbolKind,
4050 pub range: Range<Unclipped<PointUtf16>>,
4051 pub container_name: Option<String>,
4052}
4053
4054#[derive(Clone, Debug, PartialEq, Eq)]
4055pub enum SymbolLocation {
4056 InProject(ProjectPath),
4057 OutsideProject {
4058 abs_path: Arc<Path>,
4059 signature: [u8; 32],
4060 },
4061}
4062
4063impl SymbolLocation {
4064 fn file_name(&self) -> Option<&str> {
4065 match self {
4066 Self::InProject(path) => path.path.file_name(),
4067 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4068 }
4069 }
4070}
4071
4072impl LspStore {
4073 pub fn init(client: &AnyProtoClient) {
4074 client.add_entity_request_handler(Self::handle_lsp_query);
4075 client.add_entity_message_handler(Self::handle_lsp_query_response);
4076 client.add_entity_request_handler(Self::handle_restart_language_servers);
4077 client.add_entity_request_handler(Self::handle_stop_language_servers);
4078 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4079 client.add_entity_message_handler(Self::handle_start_language_server);
4080 client.add_entity_message_handler(Self::handle_update_language_server);
4081 client.add_entity_message_handler(Self::handle_language_server_log);
4082 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4083 client.add_entity_request_handler(Self::handle_format_buffers);
4084 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4085 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4086 client.add_entity_request_handler(Self::handle_apply_code_action);
4087 client.add_entity_request_handler(Self::handle_get_project_symbols);
4088 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4089 client.add_entity_request_handler(Self::handle_get_color_presentation);
4090 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4091 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4092 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4093 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4094 client.add_entity_request_handler(Self::handle_on_type_formatting);
4095 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4096 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4097 client.add_entity_request_handler(Self::handle_rename_project_entry);
4098 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4099 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4100 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4101 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4102 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4103 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4104 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4105
4106 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4107 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4108 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4109 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4110 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4111 client.add_entity_request_handler(
4112 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4113 );
4114 client.add_entity_request_handler(
4115 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4116 );
4117 client.add_entity_request_handler(
4118 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4119 );
4120 }
4121
4122 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4123 match &self.mode {
4124 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4125 _ => None,
4126 }
4127 }
4128
4129 pub fn as_local(&self) -> Option<&LocalLspStore> {
4130 match &self.mode {
4131 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4132 _ => None,
4133 }
4134 }
4135
4136 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4137 match &mut self.mode {
4138 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4139 _ => None,
4140 }
4141 }
4142
4143 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4144 match &self.mode {
4145 LspStoreMode::Remote(RemoteLspStore {
4146 upstream_client: Some(upstream_client),
4147 upstream_project_id,
4148 ..
4149 }) => Some((upstream_client.clone(), *upstream_project_id)),
4150
4151 LspStoreMode::Remote(RemoteLspStore {
4152 upstream_client: None,
4153 ..
4154 }) => None,
4155 LspStoreMode::Local(_) => None,
4156 }
4157 }
4158
4159 pub fn new_local(
4160 buffer_store: Entity<BufferStore>,
4161 worktree_store: Entity<WorktreeStore>,
4162 prettier_store: Entity<PrettierStore>,
4163 toolchain_store: Entity<LocalToolchainStore>,
4164 environment: Entity<ProjectEnvironment>,
4165 manifest_tree: Entity<ManifestTree>,
4166 languages: Arc<LanguageRegistry>,
4167 http_client: Arc<dyn HttpClient>,
4168 fs: Arc<dyn Fs>,
4169 cx: &mut Context<Self>,
4170 ) -> Self {
4171 let yarn = YarnPathStore::new(fs.clone(), cx);
4172 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4173 .detach();
4174 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4175 .detach();
4176 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4177 .detach();
4178 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4179 .detach();
4180 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4181 .detach();
4182 subscribe_to_binary_statuses(&languages, cx).detach();
4183
4184 let _maintain_workspace_config = {
4185 let (sender, receiver) = watch::channel();
4186 (Self::maintain_workspace_config(receiver, cx), sender)
4187 };
4188
4189 Self {
4190 mode: LspStoreMode::Local(LocalLspStore {
4191 weak: cx.weak_entity(),
4192 worktree_store: worktree_store.clone(),
4193
4194 supplementary_language_servers: Default::default(),
4195 languages: languages.clone(),
4196 language_server_ids: Default::default(),
4197 language_servers: Default::default(),
4198 last_workspace_edits_by_language_server: Default::default(),
4199 language_server_watched_paths: Default::default(),
4200 language_server_paths_watched_for_rename: Default::default(),
4201 language_server_dynamic_registrations: Default::default(),
4202 buffers_being_formatted: Default::default(),
4203 buffers_to_refresh_hash_set: HashSet::default(),
4204 buffers_to_refresh_queue: VecDeque::new(),
4205 _background_diagnostics_worker: Task::ready(()).shared(),
4206 buffer_snapshots: Default::default(),
4207 prettier_store,
4208 environment,
4209 http_client,
4210 fs,
4211 yarn,
4212 next_diagnostic_group_id: Default::default(),
4213 diagnostics: Default::default(),
4214 _subscription: cx.on_app_quit(|this, _| {
4215 this.as_local_mut()
4216 .unwrap()
4217 .shutdown_language_servers_on_quit()
4218 }),
4219 lsp_tree: LanguageServerTree::new(
4220 manifest_tree,
4221 languages.clone(),
4222 toolchain_store.clone(),
4223 ),
4224 toolchain_store,
4225 registered_buffers: HashMap::default(),
4226 buffers_opened_in_servers: HashMap::default(),
4227 buffer_pull_diagnostics_result_ids: HashMap::default(),
4228 workspace_pull_diagnostics_result_ids: HashMap::default(),
4229 restricted_worktrees_tasks: HashMap::default(),
4230 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4231 .manifest_file_names(),
4232 }),
4233 last_formatting_failure: None,
4234 downstream_client: None,
4235 buffer_store,
4236 worktree_store,
4237 languages: languages.clone(),
4238 language_server_statuses: Default::default(),
4239 nonce: StdRng::from_os_rng().random(),
4240 diagnostic_summaries: HashMap::default(),
4241 lsp_server_capabilities: HashMap::default(),
4242 semantic_token_config: SemanticTokenConfig::new(cx),
4243 lsp_data: HashMap::default(),
4244 next_hint_id: Arc::default(),
4245 active_entry: None,
4246 _maintain_workspace_config,
4247 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4248 }
4249 }
4250
4251 fn send_lsp_proto_request<R: LspCommand>(
4252 &self,
4253 buffer: Entity<Buffer>,
4254 client: AnyProtoClient,
4255 upstream_project_id: u64,
4256 request: R,
4257 cx: &mut Context<LspStore>,
4258 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4259 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4260 return Task::ready(Ok(R::Response::default()));
4261 }
4262 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4263 cx.spawn(async move |this, cx| {
4264 let response = client.request(message).await?;
4265 let this = this.upgrade().context("project dropped")?;
4266 request
4267 .response_from_proto(response, this, buffer, cx.clone())
4268 .await
4269 })
4270 }
4271
4272 pub(super) fn new_remote(
4273 buffer_store: Entity<BufferStore>,
4274 worktree_store: Entity<WorktreeStore>,
4275 languages: Arc<LanguageRegistry>,
4276 upstream_client: AnyProtoClient,
4277 project_id: u64,
4278 cx: &mut Context<Self>,
4279 ) -> Self {
4280 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4281 .detach();
4282 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4283 .detach();
4284 subscribe_to_binary_statuses(&languages, cx).detach();
4285 let _maintain_workspace_config = {
4286 let (sender, receiver) = watch::channel();
4287 (Self::maintain_workspace_config(receiver, cx), sender)
4288 };
4289 Self {
4290 mode: LspStoreMode::Remote(RemoteLspStore {
4291 upstream_client: Some(upstream_client),
4292 upstream_project_id: project_id,
4293 }),
4294 downstream_client: None,
4295 last_formatting_failure: None,
4296 buffer_store,
4297 worktree_store,
4298 languages: languages.clone(),
4299 language_server_statuses: Default::default(),
4300 nonce: StdRng::from_os_rng().random(),
4301 diagnostic_summaries: HashMap::default(),
4302 lsp_server_capabilities: HashMap::default(),
4303 semantic_token_config: SemanticTokenConfig::new(cx),
4304 next_hint_id: Arc::default(),
4305 lsp_data: HashMap::default(),
4306 active_entry: None,
4307
4308 _maintain_workspace_config,
4309 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4310 }
4311 }
4312
4313 fn on_buffer_store_event(
4314 &mut self,
4315 _: Entity<BufferStore>,
4316 event: &BufferStoreEvent,
4317 cx: &mut Context<Self>,
4318 ) {
4319 match event {
4320 BufferStoreEvent::BufferAdded(buffer) => {
4321 self.on_buffer_added(buffer, cx).log_err();
4322 }
4323 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4324 let buffer_id = buffer.read(cx).remote_id();
4325 if let Some(local) = self.as_local_mut()
4326 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4327 {
4328 local.reset_buffer(buffer, old_file, cx);
4329
4330 if local.registered_buffers.contains_key(&buffer_id) {
4331 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4332 }
4333 }
4334
4335 self.detect_language_for_buffer(buffer, cx);
4336 if let Some(local) = self.as_local_mut() {
4337 local.initialize_buffer(buffer, cx);
4338 if local.registered_buffers.contains_key(&buffer_id) {
4339 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4340 }
4341 }
4342 }
4343 _ => {}
4344 }
4345 }
4346
4347 fn on_worktree_store_event(
4348 &mut self,
4349 _: Entity<WorktreeStore>,
4350 event: &WorktreeStoreEvent,
4351 cx: &mut Context<Self>,
4352 ) {
4353 match event {
4354 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4355 if !worktree.read(cx).is_local() {
4356 return;
4357 }
4358 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4359 worktree::Event::UpdatedEntries(changes) => {
4360 this.update_local_worktree_language_servers(&worktree, changes, cx);
4361 }
4362 worktree::Event::UpdatedGitRepositories(_)
4363 | worktree::Event::DeletedEntry(_) => {}
4364 })
4365 .detach()
4366 }
4367 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4368 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4369 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4370 }
4371 WorktreeStoreEvent::WorktreeReleased(..)
4372 | WorktreeStoreEvent::WorktreeOrderChanged
4373 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4374 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4375 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4376 }
4377 }
4378
4379 fn on_prettier_store_event(
4380 &mut self,
4381 _: Entity<PrettierStore>,
4382 event: &PrettierStoreEvent,
4383 cx: &mut Context<Self>,
4384 ) {
4385 match event {
4386 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4387 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4388 }
4389 PrettierStoreEvent::LanguageServerAdded {
4390 new_server_id,
4391 name,
4392 prettier_server,
4393 } => {
4394 self.register_supplementary_language_server(
4395 *new_server_id,
4396 name.clone(),
4397 prettier_server.clone(),
4398 cx,
4399 );
4400 }
4401 }
4402 }
4403
4404 fn on_toolchain_store_event(
4405 &mut self,
4406 _: Entity<LocalToolchainStore>,
4407 event: &ToolchainStoreEvent,
4408 _: &mut Context<Self>,
4409 ) {
4410 if let ToolchainStoreEvent::ToolchainActivated = event {
4411 self.request_workspace_config_refresh()
4412 }
4413 }
4414
4415 fn request_workspace_config_refresh(&mut self) {
4416 *self._maintain_workspace_config.1.borrow_mut() = ();
4417 }
4418
4419 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4420 self.as_local().map(|local| local.prettier_store.clone())
4421 }
4422
4423 fn on_buffer_event(
4424 &mut self,
4425 buffer: Entity<Buffer>,
4426 event: &language::BufferEvent,
4427 cx: &mut Context<Self>,
4428 ) {
4429 match event {
4430 language::BufferEvent::Edited => {
4431 self.on_buffer_edited(buffer, cx);
4432 }
4433
4434 language::BufferEvent::Saved => {
4435 self.on_buffer_saved(buffer, cx);
4436 }
4437
4438 _ => {}
4439 }
4440 }
4441
4442 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4443 buffer
4444 .read(cx)
4445 .set_language_registry(self.languages.clone());
4446
4447 cx.subscribe(buffer, |this, buffer, event, cx| {
4448 this.on_buffer_event(buffer, event, cx);
4449 })
4450 .detach();
4451
4452 self.detect_language_for_buffer(buffer, cx);
4453 if let Some(local) = self.as_local_mut() {
4454 local.initialize_buffer(buffer, cx);
4455 }
4456
4457 Ok(())
4458 }
4459
4460 pub fn refresh_background_diagnostics_for_buffers(
4461 &mut self,
4462 buffers: HashSet<BufferId>,
4463 cx: &mut Context<Self>,
4464 ) -> Shared<Task<()>> {
4465 let Some(local) = self.as_local_mut() else {
4466 return Task::ready(()).shared();
4467 };
4468 for buffer in buffers {
4469 if local.buffers_to_refresh_hash_set.insert(buffer) {
4470 local.buffers_to_refresh_queue.push_back(buffer);
4471 if local.buffers_to_refresh_queue.len() == 1 {
4472 local._background_diagnostics_worker =
4473 Self::background_diagnostics_worker(cx).shared();
4474 }
4475 }
4476 }
4477
4478 local._background_diagnostics_worker.clone()
4479 }
4480
4481 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4482 let buffer_store = self.buffer_store.clone();
4483 let local = self.as_local_mut()?;
4484 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4485 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4486 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4487 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4488 }
4489 }
4490 None
4491 }
4492
4493 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4494 cx.spawn(async move |this, cx| {
4495 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4496 task.await.log_err();
4497 }
4498 })
4499 }
4500
4501 pub(crate) fn register_buffer_with_language_servers(
4502 &mut self,
4503 buffer: &Entity<Buffer>,
4504 only_register_servers: HashSet<LanguageServerSelector>,
4505 ignore_refcounts: bool,
4506 cx: &mut Context<Self>,
4507 ) -> OpenLspBufferHandle {
4508 let buffer_id = buffer.read(cx).remote_id();
4509 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4510 if let Some(local) = self.as_local_mut() {
4511 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4512 if !ignore_refcounts {
4513 *refcount += 1;
4514 }
4515
4516 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4517 // 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
4518 // 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
4519 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4520 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4521 return handle;
4522 };
4523 if !file.is_local() {
4524 return handle;
4525 }
4526
4527 if ignore_refcounts || *refcount == 1 {
4528 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4529 }
4530 if !ignore_refcounts {
4531 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4532 let refcount = {
4533 let local = lsp_store.as_local_mut().unwrap();
4534 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4535 debug_panic!("bad refcounting");
4536 return;
4537 };
4538
4539 *refcount -= 1;
4540 *refcount
4541 };
4542 if refcount == 0 {
4543 lsp_store.lsp_data.remove(&buffer_id);
4544 let local = lsp_store.as_local_mut().unwrap();
4545 local.registered_buffers.remove(&buffer_id);
4546
4547 local.buffers_opened_in_servers.remove(&buffer_id);
4548 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4549 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4550
4551 let buffer_abs_path = file.abs_path(cx);
4552 for (_, buffer_pull_diagnostics_result_ids) in
4553 &mut local.buffer_pull_diagnostics_result_ids
4554 {
4555 buffer_pull_diagnostics_result_ids.retain(
4556 |_, buffer_result_ids| {
4557 buffer_result_ids.remove(&buffer_abs_path);
4558 !buffer_result_ids.is_empty()
4559 },
4560 );
4561 }
4562
4563 let diagnostic_updates = local
4564 .language_servers
4565 .keys()
4566 .cloned()
4567 .map(|server_id| DocumentDiagnosticsUpdate {
4568 diagnostics: DocumentDiagnostics {
4569 document_abs_path: buffer_abs_path.clone(),
4570 version: None,
4571 diagnostics: Vec::new(),
4572 },
4573 result_id: None,
4574 registration_id: None,
4575 server_id,
4576 disk_based_sources: Cow::Borrowed(&[]),
4577 })
4578 .collect::<Vec<_>>();
4579
4580 lsp_store
4581 .merge_diagnostic_entries(
4582 diagnostic_updates,
4583 |_, diagnostic, _| {
4584 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4585 },
4586 cx,
4587 )
4588 .context("Clearing diagnostics for the closed buffer")
4589 .log_err();
4590 }
4591 }
4592 })
4593 .detach();
4594 }
4595 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4596 let buffer_id = buffer.read(cx).remote_id().to_proto();
4597 cx.background_spawn(async move {
4598 upstream_client
4599 .request(proto::RegisterBufferWithLanguageServers {
4600 project_id: upstream_project_id,
4601 buffer_id,
4602 only_servers: only_register_servers
4603 .into_iter()
4604 .map(|selector| {
4605 let selector = match selector {
4606 LanguageServerSelector::Id(language_server_id) => {
4607 proto::language_server_selector::Selector::ServerId(
4608 language_server_id.to_proto(),
4609 )
4610 }
4611 LanguageServerSelector::Name(language_server_name) => {
4612 proto::language_server_selector::Selector::Name(
4613 language_server_name.to_string(),
4614 )
4615 }
4616 };
4617 proto::LanguageServerSelector {
4618 selector: Some(selector),
4619 }
4620 })
4621 .collect(),
4622 })
4623 .await
4624 })
4625 .detach();
4626 } else {
4627 // Our remote connection got closed
4628 }
4629 handle
4630 }
4631
4632 fn maintain_buffer_languages(
4633 languages: Arc<LanguageRegistry>,
4634 cx: &mut Context<Self>,
4635 ) -> Task<()> {
4636 let mut subscription = languages.subscribe();
4637 let mut prev_reload_count = languages.reload_count();
4638 cx.spawn(async move |this, cx| {
4639 while let Some(()) = subscription.next().await {
4640 if let Some(this) = this.upgrade() {
4641 // If the language registry has been reloaded, then remove and
4642 // re-assign the languages on all open buffers.
4643 let reload_count = languages.reload_count();
4644 if reload_count > prev_reload_count {
4645 prev_reload_count = reload_count;
4646 this.update(cx, |this, cx| {
4647 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4648 for buffer in buffer_store.buffers() {
4649 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4650 {
4651 buffer.update(cx, |buffer, cx| {
4652 buffer.set_language_async(None, cx)
4653 });
4654 if let Some(local) = this.as_local_mut() {
4655 local.reset_buffer(&buffer, &f, cx);
4656
4657 if local
4658 .registered_buffers
4659 .contains_key(&buffer.read(cx).remote_id())
4660 && let Some(file_url) =
4661 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4662 {
4663 local.unregister_buffer_from_language_servers(
4664 &buffer, &file_url, cx,
4665 );
4666 }
4667 }
4668 }
4669 }
4670 });
4671 });
4672 }
4673
4674 this.update(cx, |this, cx| {
4675 let mut plain_text_buffers = Vec::new();
4676 let mut buffers_with_unknown_injections = Vec::new();
4677 for handle in this.buffer_store.read(cx).buffers() {
4678 let buffer = handle.read(cx);
4679 if buffer.language().is_none()
4680 || buffer.language() == Some(&*language::PLAIN_TEXT)
4681 {
4682 plain_text_buffers.push(handle);
4683 } else if buffer.contains_unknown_injections() {
4684 buffers_with_unknown_injections.push(handle);
4685 }
4686 }
4687
4688 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4689 // and reused later in the invisible worktrees.
4690 plain_text_buffers.sort_by_key(|buffer| {
4691 Reverse(
4692 File::from_dyn(buffer.read(cx).file())
4693 .map(|file| file.worktree.read(cx).is_visible()),
4694 )
4695 });
4696
4697 for buffer in plain_text_buffers {
4698 this.detect_language_for_buffer(&buffer, cx);
4699 if let Some(local) = this.as_local_mut() {
4700 local.initialize_buffer(&buffer, cx);
4701 if local
4702 .registered_buffers
4703 .contains_key(&buffer.read(cx).remote_id())
4704 {
4705 local.register_buffer_with_language_servers(
4706 &buffer,
4707 HashSet::default(),
4708 cx,
4709 );
4710 }
4711 }
4712 }
4713
4714 for buffer in buffers_with_unknown_injections {
4715 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4716 }
4717 });
4718 }
4719 }
4720 })
4721 }
4722
4723 fn detect_language_for_buffer(
4724 &mut self,
4725 buffer_handle: &Entity<Buffer>,
4726 cx: &mut Context<Self>,
4727 ) -> Option<language::AvailableLanguage> {
4728 // If the buffer has a language, set it and start the language server if we haven't already.
4729 let buffer = buffer_handle.read(cx);
4730 let file = buffer.file()?;
4731
4732 let content = buffer.as_rope();
4733 let available_language = self.languages.language_for_file(file, Some(content), cx);
4734 if let Some(available_language) = &available_language {
4735 if let Some(Ok(Ok(new_language))) = self
4736 .languages
4737 .load_language(available_language)
4738 .now_or_never()
4739 {
4740 self.set_language_for_buffer(buffer_handle, new_language, cx);
4741 }
4742 } else {
4743 cx.emit(LspStoreEvent::LanguageDetected {
4744 buffer: buffer_handle.clone(),
4745 new_language: None,
4746 });
4747 }
4748
4749 available_language
4750 }
4751
4752 pub(crate) fn set_language_for_buffer(
4753 &mut self,
4754 buffer_entity: &Entity<Buffer>,
4755 new_language: Arc<Language>,
4756 cx: &mut Context<Self>,
4757 ) {
4758 let buffer = buffer_entity.read(cx);
4759 let buffer_file = buffer.file().cloned();
4760 let buffer_id = buffer.remote_id();
4761 if let Some(local_store) = self.as_local_mut()
4762 && local_store.registered_buffers.contains_key(&buffer_id)
4763 && let Some(abs_path) =
4764 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4765 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4766 {
4767 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4768 }
4769 buffer_entity.update(cx, |buffer, cx| {
4770 if buffer
4771 .language()
4772 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4773 {
4774 buffer.set_language_async(Some(new_language.clone()), cx);
4775 }
4776 });
4777
4778 let settings =
4779 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4780 let buffer_file = File::from_dyn(buffer_file.as_ref());
4781
4782 let worktree_id = if let Some(file) = buffer_file {
4783 let worktree = file.worktree.clone();
4784
4785 if let Some(local) = self.as_local_mut()
4786 && local.registered_buffers.contains_key(&buffer_id)
4787 {
4788 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4789 }
4790 Some(worktree.read(cx).id())
4791 } else {
4792 None
4793 };
4794
4795 if settings.prettier.allowed
4796 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4797 {
4798 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4799 if let Some(prettier_store) = prettier_store {
4800 prettier_store.update(cx, |prettier_store, cx| {
4801 prettier_store.install_default_prettier(
4802 worktree_id,
4803 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4804 cx,
4805 )
4806 })
4807 }
4808 }
4809
4810 cx.emit(LspStoreEvent::LanguageDetected {
4811 buffer: buffer_entity.clone(),
4812 new_language: Some(new_language),
4813 })
4814 }
4815
4816 pub fn buffer_store(&self) -> Entity<BufferStore> {
4817 self.buffer_store.clone()
4818 }
4819
4820 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4821 self.active_entry = active_entry;
4822 }
4823
4824 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4825 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4826 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4827 {
4828 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4829 summaries
4830 .iter()
4831 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4832 });
4833 if let Some(summary) = summaries.next() {
4834 client
4835 .send(proto::UpdateDiagnosticSummary {
4836 project_id: downstream_project_id,
4837 worktree_id: worktree.id().to_proto(),
4838 summary: Some(summary),
4839 more_summaries: summaries.collect(),
4840 })
4841 .log_err();
4842 }
4843 }
4844 }
4845
4846 fn is_capable_for_proto_request<R>(
4847 &self,
4848 buffer: &Entity<Buffer>,
4849 request: &R,
4850 cx: &App,
4851 ) -> bool
4852 where
4853 R: LspCommand,
4854 {
4855 self.check_if_capable_for_proto_request(
4856 buffer,
4857 |capabilities| {
4858 request.check_capabilities(AdapterServerCapabilities {
4859 server_capabilities: capabilities.clone(),
4860 code_action_kinds: None,
4861 })
4862 },
4863 cx,
4864 )
4865 }
4866
4867 fn check_if_capable_for_proto_request<F>(
4868 &self,
4869 buffer: &Entity<Buffer>,
4870 check: F,
4871 cx: &App,
4872 ) -> bool
4873 where
4874 F: FnMut(&lsp::ServerCapabilities) -> bool,
4875 {
4876 let Some(language) = buffer.read(cx).language().cloned() else {
4877 return false;
4878 };
4879 let registered_language_servers = self
4880 .languages
4881 .lsp_adapters(&language.name())
4882 .into_iter()
4883 .map(|lsp_adapter| lsp_adapter.name())
4884 .collect::<HashSet<_>>();
4885 self.language_server_statuses
4886 .iter()
4887 .filter_map(|(server_id, server_status)| {
4888 // Include servers that are either registered for this language OR
4889 // available to be loaded (for SSH remote mode where adapters like
4890 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4891 // but only loaded on the server side)
4892 let is_relevant = registered_language_servers.contains(&server_status.name)
4893 || self.languages.is_lsp_adapter_available(&server_status.name);
4894 is_relevant.then_some(server_id)
4895 })
4896 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4897 .any(check)
4898 }
4899
4900 fn all_capable_for_proto_request<F>(
4901 &self,
4902 buffer: &Entity<Buffer>,
4903 mut check: F,
4904 cx: &App,
4905 ) -> Vec<lsp::LanguageServerId>
4906 where
4907 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4908 {
4909 let Some(language) = buffer.read(cx).language().cloned() else {
4910 return Vec::default();
4911 };
4912 let registered_language_servers = self
4913 .languages
4914 .lsp_adapters(&language.name())
4915 .into_iter()
4916 .map(|lsp_adapter| lsp_adapter.name())
4917 .collect::<HashSet<_>>();
4918 self.language_server_statuses
4919 .iter()
4920 .filter_map(|(server_id, server_status)| {
4921 // Include servers that are either registered for this language OR
4922 // available to be loaded (for SSH remote mode where adapters like
4923 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4924 // but only loaded on the server side)
4925 let is_relevant = registered_language_servers.contains(&server_status.name)
4926 || self.languages.is_lsp_adapter_available(&server_status.name);
4927 is_relevant.then_some((server_id, &server_status.name))
4928 })
4929 .filter_map(|(server_id, server_name)| {
4930 self.lsp_server_capabilities
4931 .get(server_id)
4932 .map(|c| (server_id, server_name, c))
4933 })
4934 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4935 .map(|(server_id, _, _)| *server_id)
4936 .collect()
4937 }
4938
4939 pub fn request_lsp<R>(
4940 &mut self,
4941 buffer: Entity<Buffer>,
4942 server: LanguageServerToQuery,
4943 request: R,
4944 cx: &mut Context<Self>,
4945 ) -> Task<Result<R::Response>>
4946 where
4947 R: LspCommand,
4948 <R::LspRequest as lsp::request::Request>::Result: Send,
4949 <R::LspRequest as lsp::request::Request>::Params: Send,
4950 {
4951 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4952 return self.send_lsp_proto_request(
4953 buffer,
4954 upstream_client,
4955 upstream_project_id,
4956 request,
4957 cx,
4958 );
4959 }
4960
4961 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4962 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4963 local
4964 .language_servers_for_buffer(buffer, cx)
4965 .find(|(_, server)| {
4966 request.check_capabilities(server.adapter_server_capabilities())
4967 })
4968 .map(|(_, server)| server.clone())
4969 }),
4970 LanguageServerToQuery::Other(id) => self
4971 .language_server_for_local_buffer(buffer, id, cx)
4972 .and_then(|(_, server)| {
4973 request
4974 .check_capabilities(server.adapter_server_capabilities())
4975 .then(|| Arc::clone(server))
4976 }),
4977 }) else {
4978 return Task::ready(Ok(Default::default()));
4979 };
4980
4981 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4982
4983 let Some(file) = file else {
4984 return Task::ready(Ok(Default::default()));
4985 };
4986
4987 let lsp_params = match request.to_lsp_params_or_response(
4988 &file.abs_path(cx),
4989 buffer.read(cx),
4990 &language_server,
4991 cx,
4992 ) {
4993 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4994 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4995 Err(err) => {
4996 let message = format!(
4997 "{} via {} failed: {}",
4998 request.display_name(),
4999 language_server.name(),
5000 err
5001 );
5002 // rust-analyzer likes to error with this when its still loading up
5003 if !message.ends_with("content modified") {
5004 log::warn!("{message}");
5005 }
5006 return Task::ready(Err(anyhow!(message)));
5007 }
5008 };
5009
5010 let status = request.status();
5011 let request_timeout = ProjectSettings::get_global(cx)
5012 .global_lsp_settings
5013 .get_request_timeout();
5014
5015 cx.spawn(async move |this, cx| {
5016 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5017
5018 let id = lsp_request.id();
5019 let _cleanup = if status.is_some() {
5020 cx.update(|cx| {
5021 this.update(cx, |this, cx| {
5022 this.on_lsp_work_start(
5023 language_server.server_id(),
5024 ProgressToken::Number(id),
5025 LanguageServerProgress {
5026 is_disk_based_diagnostics_progress: false,
5027 is_cancellable: false,
5028 title: None,
5029 message: status.clone(),
5030 percentage: None,
5031 last_update_at: cx.background_executor().now(),
5032 },
5033 cx,
5034 );
5035 })
5036 })
5037 .log_err();
5038
5039 Some(defer(|| {
5040 cx.update(|cx| {
5041 this.update(cx, |this, cx| {
5042 this.on_lsp_work_end(
5043 language_server.server_id(),
5044 ProgressToken::Number(id),
5045 cx,
5046 );
5047 })
5048 })
5049 .log_err();
5050 }))
5051 } else {
5052 None
5053 };
5054
5055 let result = lsp_request.await.into_response();
5056
5057 let response = result.map_err(|err| {
5058 let message = format!(
5059 "{} via {} failed: {}",
5060 request.display_name(),
5061 language_server.name(),
5062 err
5063 );
5064 // rust-analyzer likes to error with this when its still loading up
5065 if !message.ends_with("content modified") {
5066 log::warn!("{message}");
5067 }
5068 anyhow::anyhow!(message)
5069 })?;
5070
5071 request
5072 .response_from_lsp(
5073 response,
5074 this.upgrade().context("no app context")?,
5075 buffer,
5076 language_server.server_id(),
5077 cx.clone(),
5078 )
5079 .await
5080 })
5081 }
5082
5083 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5084 let mut language_formatters_to_check = Vec::new();
5085 for buffer in self.buffer_store.read(cx).buffers() {
5086 let buffer = buffer.read(cx);
5087 let buffer_file = File::from_dyn(buffer.file());
5088 let buffer_language = buffer.language();
5089 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5090 if buffer_language.is_some() {
5091 language_formatters_to_check.push((
5092 buffer_file.map(|f| f.worktree_id(cx)),
5093 settings.into_owned(),
5094 ));
5095 }
5096 }
5097
5098 self.request_workspace_config_refresh();
5099
5100 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5101 prettier_store.update(cx, |prettier_store, cx| {
5102 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5103 })
5104 }
5105
5106 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5107 .global_lsp_settings
5108 .semantic_token_rules
5109 .clone();
5110 self.semantic_token_config
5111 .update_rules(new_semantic_token_rules);
5112 // Always clear cached stylizers so that changes to language-specific
5113 // semantic token rules (e.g. from extension install/uninstall) are
5114 // picked up. Stylizers are recreated lazily, so this is cheap.
5115 self.semantic_token_config.clear_stylizers();
5116
5117 let new_global_semantic_tokens_mode =
5118 all_language_settings(None, cx).defaults.semantic_tokens;
5119 if self
5120 .semantic_token_config
5121 .update_global_mode(new_global_semantic_tokens_mode)
5122 {
5123 self.restart_all_language_servers(cx);
5124 }
5125
5126 cx.notify();
5127 }
5128
5129 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5130 let buffer_store = self.buffer_store.clone();
5131 let Some(local) = self.as_local_mut() else {
5132 return;
5133 };
5134 let mut adapters = BTreeMap::default();
5135 let get_adapter = {
5136 let languages = local.languages.clone();
5137 let environment = local.environment.clone();
5138 let weak = local.weak.clone();
5139 let worktree_store = local.worktree_store.clone();
5140 let http_client = local.http_client.clone();
5141 let fs = local.fs.clone();
5142 move |worktree_id, cx: &mut App| {
5143 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5144 Some(LocalLspAdapterDelegate::new(
5145 languages.clone(),
5146 &environment,
5147 weak.clone(),
5148 &worktree,
5149 http_client.clone(),
5150 fs.clone(),
5151 cx,
5152 ))
5153 }
5154 };
5155
5156 let mut messages_to_report = Vec::new();
5157 let (new_tree, to_stop) = {
5158 let mut rebase = local.lsp_tree.rebase();
5159 let buffers = buffer_store
5160 .read(cx)
5161 .buffers()
5162 .filter_map(|buffer| {
5163 let raw_buffer = buffer.read(cx);
5164 if !local
5165 .registered_buffers
5166 .contains_key(&raw_buffer.remote_id())
5167 {
5168 return None;
5169 }
5170 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5171 let language = raw_buffer.language().cloned()?;
5172 Some((file, language, raw_buffer.remote_id()))
5173 })
5174 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5175 for (file, language, buffer_id) in buffers {
5176 let worktree_id = file.worktree_id(cx);
5177 let Some(worktree) = local
5178 .worktree_store
5179 .read(cx)
5180 .worktree_for_id(worktree_id, cx)
5181 else {
5182 continue;
5183 };
5184
5185 if let Some((_, apply)) = local.reuse_existing_language_server(
5186 rebase.server_tree(),
5187 &worktree,
5188 &language.name(),
5189 cx,
5190 ) {
5191 (apply)(rebase.server_tree());
5192 } else if let Some(lsp_delegate) = adapters
5193 .entry(worktree_id)
5194 .or_insert_with(|| get_adapter(worktree_id, cx))
5195 .clone()
5196 {
5197 let delegate =
5198 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5199 let path = file
5200 .path()
5201 .parent()
5202 .map(Arc::from)
5203 .unwrap_or_else(|| file.path().clone());
5204 let worktree_path = ProjectPath { worktree_id, path };
5205 let abs_path = file.abs_path(cx);
5206 let nodes = rebase
5207 .walk(
5208 worktree_path,
5209 language.name(),
5210 language.manifest(),
5211 delegate.clone(),
5212 cx,
5213 )
5214 .collect::<Vec<_>>();
5215 for node in nodes {
5216 let server_id = node.server_id_or_init(|disposition| {
5217 let path = &disposition.path;
5218 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5219 let key = LanguageServerSeed {
5220 worktree_id,
5221 name: disposition.server_name.clone(),
5222 settings: LanguageServerSeedSettings {
5223 binary: disposition.settings.binary.clone(),
5224 initialization_options: disposition
5225 .settings
5226 .initialization_options
5227 .clone(),
5228 },
5229 toolchain: local.toolchain_store.read(cx).active_toolchain(
5230 path.worktree_id,
5231 &path.path,
5232 language.name(),
5233 ),
5234 };
5235 local.language_server_ids.remove(&key);
5236
5237 let server_id = local.get_or_insert_language_server(
5238 &worktree,
5239 lsp_delegate.clone(),
5240 disposition,
5241 &language.name(),
5242 cx,
5243 );
5244 if let Some(state) = local.language_servers.get(&server_id)
5245 && let Ok(uri) = uri
5246 {
5247 state.add_workspace_folder(uri);
5248 };
5249 server_id
5250 });
5251
5252 if let Some(language_server_id) = server_id {
5253 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5254 language_server_id,
5255 name: node.name(),
5256 message:
5257 proto::update_language_server::Variant::RegisteredForBuffer(
5258 proto::RegisteredForBuffer {
5259 buffer_abs_path: abs_path
5260 .to_string_lossy()
5261 .into_owned(),
5262 buffer_id: buffer_id.to_proto(),
5263 },
5264 ),
5265 });
5266 }
5267 }
5268 } else {
5269 continue;
5270 }
5271 }
5272 rebase.finish()
5273 };
5274 for message in messages_to_report {
5275 cx.emit(message);
5276 }
5277 local.lsp_tree = new_tree;
5278 for (id, _) in to_stop {
5279 self.stop_local_language_server(id, cx).detach();
5280 }
5281 }
5282
5283 pub fn apply_code_action(
5284 &self,
5285 buffer_handle: Entity<Buffer>,
5286 mut action: CodeAction,
5287 push_to_history: bool,
5288 cx: &mut Context<Self>,
5289 ) -> Task<Result<ProjectTransaction>> {
5290 if let Some((upstream_client, project_id)) = self.upstream_client() {
5291 let request = proto::ApplyCodeAction {
5292 project_id,
5293 buffer_id: buffer_handle.read(cx).remote_id().into(),
5294 action: Some(Self::serialize_code_action(&action)),
5295 };
5296 let buffer_store = self.buffer_store();
5297 cx.spawn(async move |_, cx| {
5298 let response = upstream_client
5299 .request(request)
5300 .await?
5301 .transaction
5302 .context("missing transaction")?;
5303
5304 buffer_store
5305 .update(cx, |buffer_store, cx| {
5306 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5307 })
5308 .await
5309 })
5310 } else if self.mode.is_local() {
5311 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5312 let request_timeout = ProjectSettings::get_global(cx)
5313 .global_lsp_settings
5314 .get_request_timeout();
5315 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5316 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5317 }) else {
5318 return Task::ready(Ok(ProjectTransaction::default()));
5319 };
5320
5321 cx.spawn(async move |this, cx| {
5322 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5323 .await
5324 .context("resolving a code action")?;
5325 if let Some(edit) = action.lsp_action.edit()
5326 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5327 return LocalLspStore::deserialize_workspace_edit(
5328 this.upgrade().context("no app present")?,
5329 edit.clone(),
5330 push_to_history,
5331
5332 lang_server.clone(),
5333 cx,
5334 )
5335 .await;
5336 }
5337
5338 let Some(command) = action.lsp_action.command() else {
5339 return Ok(ProjectTransaction::default())
5340 };
5341
5342 let server_capabilities = lang_server.capabilities();
5343 let available_commands = server_capabilities
5344 .execute_command_provider
5345 .as_ref()
5346 .map(|options| options.commands.as_slice())
5347 .unwrap_or_default();
5348
5349 if !available_commands.contains(&command.command) {
5350 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5351 return Ok(ProjectTransaction::default())
5352 }
5353
5354 let request_timeout = cx.update(|app|
5355 ProjectSettings::get_global(app)
5356 .global_lsp_settings
5357 .get_request_timeout()
5358 );
5359
5360 this.update(cx, |this, _| {
5361 this.as_local_mut()
5362 .unwrap()
5363 .last_workspace_edits_by_language_server
5364 .remove(&lang_server.server_id());
5365 })?;
5366
5367 let _result = lang_server
5368 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5369 command: command.command.clone(),
5370 arguments: command.arguments.clone().unwrap_or_default(),
5371 ..lsp::ExecuteCommandParams::default()
5372 }, request_timeout)
5373 .await.into_response()
5374 .context("execute command")?;
5375
5376 return this.update(cx, |this, _| {
5377 this.as_local_mut()
5378 .unwrap()
5379 .last_workspace_edits_by_language_server
5380 .remove(&lang_server.server_id())
5381 .unwrap_or_default()
5382 });
5383 })
5384 } else {
5385 Task::ready(Err(anyhow!("no upstream client and not local")))
5386 }
5387 }
5388
5389 pub fn apply_code_action_kind(
5390 &mut self,
5391 buffers: HashSet<Entity<Buffer>>,
5392 kind: CodeActionKind,
5393 push_to_history: bool,
5394 cx: &mut Context<Self>,
5395 ) -> Task<anyhow::Result<ProjectTransaction>> {
5396 if self.as_local().is_some() {
5397 cx.spawn(async move |lsp_store, cx| {
5398 let buffers = buffers.into_iter().collect::<Vec<_>>();
5399 let result = LocalLspStore::execute_code_action_kind_locally(
5400 lsp_store.clone(),
5401 buffers,
5402 kind,
5403 push_to_history,
5404 cx,
5405 )
5406 .await;
5407 lsp_store.update(cx, |lsp_store, _| {
5408 lsp_store.update_last_formatting_failure(&result);
5409 })?;
5410 result
5411 })
5412 } else if let Some((client, project_id)) = self.upstream_client() {
5413 let buffer_store = self.buffer_store();
5414 cx.spawn(async move |lsp_store, cx| {
5415 let result = client
5416 .request(proto::ApplyCodeActionKind {
5417 project_id,
5418 kind: kind.as_str().to_owned(),
5419 buffer_ids: buffers
5420 .iter()
5421 .map(|buffer| {
5422 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5423 })
5424 .collect(),
5425 })
5426 .await
5427 .and_then(|result| result.transaction.context("missing transaction"));
5428 lsp_store.update(cx, |lsp_store, _| {
5429 lsp_store.update_last_formatting_failure(&result);
5430 })?;
5431
5432 let transaction_response = result?;
5433 buffer_store
5434 .update(cx, |buffer_store, cx| {
5435 buffer_store.deserialize_project_transaction(
5436 transaction_response,
5437 push_to_history,
5438 cx,
5439 )
5440 })
5441 .await
5442 })
5443 } else {
5444 Task::ready(Ok(ProjectTransaction::default()))
5445 }
5446 }
5447
5448 pub fn resolved_hint(
5449 &mut self,
5450 buffer_id: BufferId,
5451 id: InlayId,
5452 cx: &mut Context<Self>,
5453 ) -> Option<ResolvedHint> {
5454 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5455
5456 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5457 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5458 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5459 let (server_id, resolve_data) = match &hint.resolve_state {
5460 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5461 ResolveState::Resolving => {
5462 return Some(ResolvedHint::Resolving(
5463 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5464 ));
5465 }
5466 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5467 };
5468
5469 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5470 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5471 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5472 id,
5473 cx.spawn(async move |lsp_store, cx| {
5474 let resolved_hint = resolve_task.await;
5475 lsp_store
5476 .update(cx, |lsp_store, _| {
5477 if let Some(old_inlay_hint) = lsp_store
5478 .lsp_data
5479 .get_mut(&buffer_id)
5480 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5481 {
5482 match resolved_hint {
5483 Ok(resolved_hint) => {
5484 *old_inlay_hint = resolved_hint;
5485 }
5486 Err(e) => {
5487 old_inlay_hint.resolve_state =
5488 ResolveState::CanResolve(server_id, resolve_data);
5489 log::error!("Inlay hint resolve failed: {e:#}");
5490 }
5491 }
5492 }
5493 })
5494 .ok();
5495 })
5496 .shared(),
5497 );
5498 debug_assert!(
5499 previous_task.is_none(),
5500 "Did not change hint's resolve state after spawning its resolve"
5501 );
5502 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5503 None
5504 }
5505
5506 pub(crate) fn linked_edits(
5507 &mut self,
5508 buffer: &Entity<Buffer>,
5509 position: Anchor,
5510 cx: &mut Context<Self>,
5511 ) -> Task<Result<Vec<Range<Anchor>>>> {
5512 let snapshot = buffer.read(cx).snapshot();
5513 let scope = snapshot.language_scope_at(position);
5514 let Some(server_id) = self
5515 .as_local()
5516 .and_then(|local| {
5517 buffer.update(cx, |buffer, cx| {
5518 local
5519 .language_servers_for_buffer(buffer, cx)
5520 .filter(|(_, server)| {
5521 LinkedEditingRange::check_server_capabilities(server.capabilities())
5522 })
5523 .filter(|(adapter, _)| {
5524 scope
5525 .as_ref()
5526 .map(|scope| scope.language_allowed(&adapter.name))
5527 .unwrap_or(true)
5528 })
5529 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5530 .next()
5531 })
5532 })
5533 .or_else(|| {
5534 self.upstream_client()
5535 .is_some()
5536 .then_some(LanguageServerToQuery::FirstCapable)
5537 })
5538 .filter(|_| {
5539 maybe!({
5540 let language = buffer.read(cx).language_at(position)?;
5541 Some(
5542 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5543 .linked_edits,
5544 )
5545 }) == Some(true)
5546 })
5547 else {
5548 return Task::ready(Ok(Vec::new()));
5549 };
5550
5551 self.request_lsp(
5552 buffer.clone(),
5553 server_id,
5554 LinkedEditingRange { position },
5555 cx,
5556 )
5557 }
5558
5559 fn apply_on_type_formatting(
5560 &mut self,
5561 buffer: Entity<Buffer>,
5562 position: Anchor,
5563 trigger: String,
5564 cx: &mut Context<Self>,
5565 ) -> Task<Result<Option<Transaction>>> {
5566 if let Some((client, project_id)) = self.upstream_client() {
5567 if !self.check_if_capable_for_proto_request(
5568 &buffer,
5569 |capabilities| {
5570 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5571 },
5572 cx,
5573 ) {
5574 return Task::ready(Ok(None));
5575 }
5576 let request = proto::OnTypeFormatting {
5577 project_id,
5578 buffer_id: buffer.read(cx).remote_id().into(),
5579 position: Some(serialize_anchor(&position)),
5580 trigger,
5581 version: serialize_version(&buffer.read(cx).version()),
5582 };
5583 cx.background_spawn(async move {
5584 client
5585 .request(request)
5586 .await?
5587 .transaction
5588 .map(language::proto::deserialize_transaction)
5589 .transpose()
5590 })
5591 } else if let Some(local) = self.as_local_mut() {
5592 let buffer_id = buffer.read(cx).remote_id();
5593 local.buffers_being_formatted.insert(buffer_id);
5594 cx.spawn(async move |this, cx| {
5595 let _cleanup = defer({
5596 let this = this.clone();
5597 let mut cx = cx.clone();
5598 move || {
5599 this.update(&mut cx, |this, _| {
5600 if let Some(local) = this.as_local_mut() {
5601 local.buffers_being_formatted.remove(&buffer_id);
5602 }
5603 })
5604 .ok();
5605 }
5606 });
5607
5608 buffer
5609 .update(cx, |buffer, _| {
5610 buffer.wait_for_edits(Some(position.timestamp()))
5611 })
5612 .await?;
5613 this.update(cx, |this, cx| {
5614 let position = position.to_point_utf16(buffer.read(cx));
5615 this.on_type_format(buffer, position, trigger, false, cx)
5616 })?
5617 .await
5618 })
5619 } else {
5620 Task::ready(Err(anyhow!("No upstream client or local language server")))
5621 }
5622 }
5623
5624 pub fn on_type_format<T: ToPointUtf16>(
5625 &mut self,
5626 buffer: Entity<Buffer>,
5627 position: T,
5628 trigger: String,
5629 push_to_history: bool,
5630 cx: &mut Context<Self>,
5631 ) -> Task<Result<Option<Transaction>>> {
5632 let position = position.to_point_utf16(buffer.read(cx));
5633 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5634 }
5635
5636 fn on_type_format_impl(
5637 &mut self,
5638 buffer: Entity<Buffer>,
5639 position: PointUtf16,
5640 trigger: String,
5641 push_to_history: bool,
5642 cx: &mut Context<Self>,
5643 ) -> Task<Result<Option<Transaction>>> {
5644 let options = buffer.update(cx, |buffer, cx| {
5645 lsp_command::lsp_formatting_options(
5646 language_settings(
5647 buffer.language_at(position).map(|l| l.name()),
5648 buffer.file(),
5649 cx,
5650 )
5651 .as_ref(),
5652 )
5653 });
5654
5655 cx.spawn(async move |this, cx| {
5656 if let Some(waiter) =
5657 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5658 {
5659 waiter.await?;
5660 }
5661 cx.update(|cx| {
5662 this.update(cx, |this, cx| {
5663 this.request_lsp(
5664 buffer.clone(),
5665 LanguageServerToQuery::FirstCapable,
5666 OnTypeFormatting {
5667 position,
5668 trigger,
5669 options,
5670 push_to_history,
5671 },
5672 cx,
5673 )
5674 })
5675 })?
5676 .await
5677 })
5678 }
5679
5680 pub fn definitions(
5681 &mut self,
5682 buffer: &Entity<Buffer>,
5683 position: PointUtf16,
5684 cx: &mut Context<Self>,
5685 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5686 if let Some((upstream_client, project_id)) = self.upstream_client() {
5687 let request = GetDefinitions { position };
5688 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5689 return Task::ready(Ok(None));
5690 }
5691
5692 let request_timeout = ProjectSettings::get_global(cx)
5693 .global_lsp_settings
5694 .get_request_timeout();
5695
5696 let request_task = upstream_client.request_lsp(
5697 project_id,
5698 None,
5699 request_timeout,
5700 cx.background_executor().clone(),
5701 request.to_proto(project_id, buffer.read(cx)),
5702 );
5703 let buffer = buffer.clone();
5704 cx.spawn(async move |weak_lsp_store, cx| {
5705 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5706 return Ok(None);
5707 };
5708 let Some(responses) = request_task.await? else {
5709 return Ok(None);
5710 };
5711 let actions = join_all(responses.payload.into_iter().map(|response| {
5712 GetDefinitions { position }.response_from_proto(
5713 response.response,
5714 lsp_store.clone(),
5715 buffer.clone(),
5716 cx.clone(),
5717 )
5718 }))
5719 .await;
5720
5721 Ok(Some(
5722 actions
5723 .into_iter()
5724 .collect::<Result<Vec<Vec<_>>>>()?
5725 .into_iter()
5726 .flatten()
5727 .dedup()
5728 .collect(),
5729 ))
5730 })
5731 } else {
5732 let definitions_task = self.request_multiple_lsp_locally(
5733 buffer,
5734 Some(position),
5735 GetDefinitions { position },
5736 cx,
5737 );
5738 cx.background_spawn(async move {
5739 Ok(Some(
5740 definitions_task
5741 .await
5742 .into_iter()
5743 .flat_map(|(_, definitions)| definitions)
5744 .dedup()
5745 .collect(),
5746 ))
5747 })
5748 }
5749 }
5750
5751 pub fn declarations(
5752 &mut self,
5753 buffer: &Entity<Buffer>,
5754 position: PointUtf16,
5755 cx: &mut Context<Self>,
5756 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5757 if let Some((upstream_client, project_id)) = self.upstream_client() {
5758 let request = GetDeclarations { position };
5759 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5760 return Task::ready(Ok(None));
5761 }
5762 let request_timeout = ProjectSettings::get_global(cx)
5763 .global_lsp_settings
5764 .get_request_timeout();
5765 let request_task = upstream_client.request_lsp(
5766 project_id,
5767 None,
5768 request_timeout,
5769 cx.background_executor().clone(),
5770 request.to_proto(project_id, buffer.read(cx)),
5771 );
5772 let buffer = buffer.clone();
5773 cx.spawn(async move |weak_lsp_store, cx| {
5774 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5775 return Ok(None);
5776 };
5777 let Some(responses) = request_task.await? else {
5778 return Ok(None);
5779 };
5780 let actions = join_all(responses.payload.into_iter().map(|response| {
5781 GetDeclarations { position }.response_from_proto(
5782 response.response,
5783 lsp_store.clone(),
5784 buffer.clone(),
5785 cx.clone(),
5786 )
5787 }))
5788 .await;
5789
5790 Ok(Some(
5791 actions
5792 .into_iter()
5793 .collect::<Result<Vec<Vec<_>>>>()?
5794 .into_iter()
5795 .flatten()
5796 .dedup()
5797 .collect(),
5798 ))
5799 })
5800 } else {
5801 let declarations_task = self.request_multiple_lsp_locally(
5802 buffer,
5803 Some(position),
5804 GetDeclarations { position },
5805 cx,
5806 );
5807 cx.background_spawn(async move {
5808 Ok(Some(
5809 declarations_task
5810 .await
5811 .into_iter()
5812 .flat_map(|(_, declarations)| declarations)
5813 .dedup()
5814 .collect(),
5815 ))
5816 })
5817 }
5818 }
5819
5820 pub fn type_definitions(
5821 &mut self,
5822 buffer: &Entity<Buffer>,
5823 position: PointUtf16,
5824 cx: &mut Context<Self>,
5825 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5826 if let Some((upstream_client, project_id)) = self.upstream_client() {
5827 let request = GetTypeDefinitions { position };
5828 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5829 return Task::ready(Ok(None));
5830 }
5831 let request_timeout = ProjectSettings::get_global(cx)
5832 .global_lsp_settings
5833 .get_request_timeout();
5834 let request_task = upstream_client.request_lsp(
5835 project_id,
5836 None,
5837 request_timeout,
5838 cx.background_executor().clone(),
5839 request.to_proto(project_id, buffer.read(cx)),
5840 );
5841 let buffer = buffer.clone();
5842 cx.spawn(async move |weak_lsp_store, cx| {
5843 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5844 return Ok(None);
5845 };
5846 let Some(responses) = request_task.await? else {
5847 return Ok(None);
5848 };
5849 let actions = join_all(responses.payload.into_iter().map(|response| {
5850 GetTypeDefinitions { position }.response_from_proto(
5851 response.response,
5852 lsp_store.clone(),
5853 buffer.clone(),
5854 cx.clone(),
5855 )
5856 }))
5857 .await;
5858
5859 Ok(Some(
5860 actions
5861 .into_iter()
5862 .collect::<Result<Vec<Vec<_>>>>()?
5863 .into_iter()
5864 .flatten()
5865 .dedup()
5866 .collect(),
5867 ))
5868 })
5869 } else {
5870 let type_definitions_task = self.request_multiple_lsp_locally(
5871 buffer,
5872 Some(position),
5873 GetTypeDefinitions { position },
5874 cx,
5875 );
5876 cx.background_spawn(async move {
5877 Ok(Some(
5878 type_definitions_task
5879 .await
5880 .into_iter()
5881 .flat_map(|(_, type_definitions)| type_definitions)
5882 .dedup()
5883 .collect(),
5884 ))
5885 })
5886 }
5887 }
5888
5889 pub fn implementations(
5890 &mut self,
5891 buffer: &Entity<Buffer>,
5892 position: PointUtf16,
5893 cx: &mut Context<Self>,
5894 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5895 if let Some((upstream_client, project_id)) = self.upstream_client() {
5896 let request = GetImplementations { position };
5897 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5898 return Task::ready(Ok(None));
5899 }
5900
5901 let request_timeout = ProjectSettings::get_global(cx)
5902 .global_lsp_settings
5903 .get_request_timeout();
5904 let request_task = upstream_client.request_lsp(
5905 project_id,
5906 None,
5907 request_timeout,
5908 cx.background_executor().clone(),
5909 request.to_proto(project_id, buffer.read(cx)),
5910 );
5911 let buffer = buffer.clone();
5912 cx.spawn(async move |weak_lsp_store, cx| {
5913 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5914 return Ok(None);
5915 };
5916 let Some(responses) = request_task.await? else {
5917 return Ok(None);
5918 };
5919 let actions = join_all(responses.payload.into_iter().map(|response| {
5920 GetImplementations { position }.response_from_proto(
5921 response.response,
5922 lsp_store.clone(),
5923 buffer.clone(),
5924 cx.clone(),
5925 )
5926 }))
5927 .await;
5928
5929 Ok(Some(
5930 actions
5931 .into_iter()
5932 .collect::<Result<Vec<Vec<_>>>>()?
5933 .into_iter()
5934 .flatten()
5935 .dedup()
5936 .collect(),
5937 ))
5938 })
5939 } else {
5940 let implementations_task = self.request_multiple_lsp_locally(
5941 buffer,
5942 Some(position),
5943 GetImplementations { position },
5944 cx,
5945 );
5946 cx.background_spawn(async move {
5947 Ok(Some(
5948 implementations_task
5949 .await
5950 .into_iter()
5951 .flat_map(|(_, implementations)| implementations)
5952 .dedup()
5953 .collect(),
5954 ))
5955 })
5956 }
5957 }
5958
5959 pub fn references(
5960 &mut self,
5961 buffer: &Entity<Buffer>,
5962 position: PointUtf16,
5963 cx: &mut Context<Self>,
5964 ) -> Task<Result<Option<Vec<Location>>>> {
5965 if let Some((upstream_client, project_id)) = self.upstream_client() {
5966 let request = GetReferences { position };
5967 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5968 return Task::ready(Ok(None));
5969 }
5970
5971 let request_timeout = ProjectSettings::get_global(cx)
5972 .global_lsp_settings
5973 .get_request_timeout();
5974 let request_task = upstream_client.request_lsp(
5975 project_id,
5976 None,
5977 request_timeout,
5978 cx.background_executor().clone(),
5979 request.to_proto(project_id, buffer.read(cx)),
5980 );
5981 let buffer = buffer.clone();
5982 cx.spawn(async move |weak_lsp_store, cx| {
5983 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5984 return Ok(None);
5985 };
5986 let Some(responses) = request_task.await? else {
5987 return Ok(None);
5988 };
5989
5990 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5991 GetReferences { position }.response_from_proto(
5992 lsp_response.response,
5993 lsp_store.clone(),
5994 buffer.clone(),
5995 cx.clone(),
5996 )
5997 }))
5998 .await
5999 .into_iter()
6000 .collect::<Result<Vec<Vec<_>>>>()?
6001 .into_iter()
6002 .flatten()
6003 .dedup()
6004 .collect();
6005 Ok(Some(locations))
6006 })
6007 } else {
6008 let references_task = self.request_multiple_lsp_locally(
6009 buffer,
6010 Some(position),
6011 GetReferences { position },
6012 cx,
6013 );
6014 cx.background_spawn(async move {
6015 Ok(Some(
6016 references_task
6017 .await
6018 .into_iter()
6019 .flat_map(|(_, references)| references)
6020 .dedup()
6021 .collect(),
6022 ))
6023 })
6024 }
6025 }
6026
6027 pub fn code_actions(
6028 &mut self,
6029 buffer: &Entity<Buffer>,
6030 range: Range<Anchor>,
6031 kinds: Option<Vec<CodeActionKind>>,
6032 cx: &mut Context<Self>,
6033 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6034 if let Some((upstream_client, project_id)) = self.upstream_client() {
6035 let request = GetCodeActions {
6036 range: range.clone(),
6037 kinds: kinds.clone(),
6038 };
6039 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6040 return Task::ready(Ok(None));
6041 }
6042 let request_timeout = ProjectSettings::get_global(cx)
6043 .global_lsp_settings
6044 .get_request_timeout();
6045 let request_task = upstream_client.request_lsp(
6046 project_id,
6047 None,
6048 request_timeout,
6049 cx.background_executor().clone(),
6050 request.to_proto(project_id, buffer.read(cx)),
6051 );
6052 let buffer = buffer.clone();
6053 cx.spawn(async move |weak_lsp_store, cx| {
6054 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6055 return Ok(None);
6056 };
6057 let Some(responses) = request_task.await? else {
6058 return Ok(None);
6059 };
6060 let actions = join_all(responses.payload.into_iter().map(|response| {
6061 GetCodeActions {
6062 range: range.clone(),
6063 kinds: kinds.clone(),
6064 }
6065 .response_from_proto(
6066 response.response,
6067 lsp_store.clone(),
6068 buffer.clone(),
6069 cx.clone(),
6070 )
6071 }))
6072 .await;
6073
6074 Ok(Some(
6075 actions
6076 .into_iter()
6077 .collect::<Result<Vec<Vec<_>>>>()?
6078 .into_iter()
6079 .flatten()
6080 .collect(),
6081 ))
6082 })
6083 } else {
6084 let all_actions_task = self.request_multiple_lsp_locally(
6085 buffer,
6086 Some(range.start),
6087 GetCodeActions { range, kinds },
6088 cx,
6089 );
6090 cx.background_spawn(async move {
6091 Ok(Some(
6092 all_actions_task
6093 .await
6094 .into_iter()
6095 .flat_map(|(_, actions)| actions)
6096 .collect(),
6097 ))
6098 })
6099 }
6100 }
6101
6102 #[inline(never)]
6103 pub fn completions(
6104 &self,
6105 buffer: &Entity<Buffer>,
6106 position: PointUtf16,
6107 context: CompletionContext,
6108 cx: &mut Context<Self>,
6109 ) -> Task<Result<Vec<CompletionResponse>>> {
6110 let language_registry = self.languages.clone();
6111
6112 if let Some((upstream_client, project_id)) = self.upstream_client() {
6113 let snapshot = buffer.read(cx).snapshot();
6114 let offset = position.to_offset(&snapshot);
6115 let scope = snapshot.language_scope_at(offset);
6116 let capable_lsps = self.all_capable_for_proto_request(
6117 buffer,
6118 |server_name, capabilities| {
6119 capabilities.completion_provider.is_some()
6120 && scope
6121 .as_ref()
6122 .map(|scope| scope.language_allowed(server_name))
6123 .unwrap_or(true)
6124 },
6125 cx,
6126 );
6127 if capable_lsps.is_empty() {
6128 return Task::ready(Ok(Vec::new()));
6129 }
6130
6131 let language = buffer.read(cx).language().cloned();
6132
6133 // In the future, we should provide project guests with the names of LSP adapters,
6134 // so that they can use the correct LSP adapter when computing labels. For now,
6135 // guests just use the first LSP adapter associated with the buffer's language.
6136 let lsp_adapter = language.as_ref().and_then(|language| {
6137 language_registry
6138 .lsp_adapters(&language.name())
6139 .first()
6140 .cloned()
6141 });
6142
6143 let buffer = buffer.clone();
6144
6145 cx.spawn(async move |this, cx| {
6146 let requests = join_all(
6147 capable_lsps
6148 .into_iter()
6149 .map(|id| {
6150 let request = GetCompletions {
6151 position,
6152 context: context.clone(),
6153 server_id: Some(id),
6154 };
6155 let buffer = buffer.clone();
6156 let language = language.clone();
6157 let lsp_adapter = lsp_adapter.clone();
6158 let upstream_client = upstream_client.clone();
6159 let response = this
6160 .update(cx, |this, cx| {
6161 this.send_lsp_proto_request(
6162 buffer,
6163 upstream_client,
6164 project_id,
6165 request,
6166 cx,
6167 )
6168 })
6169 .log_err();
6170 async move {
6171 let response = response?.await.log_err()?;
6172
6173 let completions = populate_labels_for_completions(
6174 response.completions,
6175 language,
6176 lsp_adapter,
6177 )
6178 .await;
6179
6180 Some(CompletionResponse {
6181 completions,
6182 display_options: CompletionDisplayOptions::default(),
6183 is_incomplete: response.is_incomplete,
6184 })
6185 }
6186 })
6187 .collect::<Vec<_>>(),
6188 );
6189 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6190 })
6191 } else if let Some(local) = self.as_local() {
6192 let snapshot = buffer.read(cx).snapshot();
6193 let offset = position.to_offset(&snapshot);
6194 let scope = snapshot.language_scope_at(offset);
6195 let language = snapshot.language().cloned();
6196 let completion_settings = language_settings(
6197 language.as_ref().map(|language| language.name()),
6198 buffer.read(cx).file(),
6199 cx,
6200 )
6201 .completions
6202 .clone();
6203 if !completion_settings.lsp {
6204 return Task::ready(Ok(Vec::new()));
6205 }
6206
6207 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6208 local
6209 .language_servers_for_buffer(buffer, cx)
6210 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6211 .filter(|(adapter, _)| {
6212 scope
6213 .as_ref()
6214 .map(|scope| scope.language_allowed(&adapter.name))
6215 .unwrap_or(true)
6216 })
6217 .map(|(_, server)| server.server_id())
6218 .collect()
6219 });
6220
6221 let buffer = buffer.clone();
6222 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6223 let lsp_timeout = if lsp_timeout > 0 {
6224 Some(Duration::from_millis(lsp_timeout))
6225 } else {
6226 None
6227 };
6228 cx.spawn(async move |this, cx| {
6229 let mut tasks = Vec::with_capacity(server_ids.len());
6230 this.update(cx, |lsp_store, cx| {
6231 for server_id in server_ids {
6232 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6233 let lsp_timeout = lsp_timeout
6234 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6235 let mut timeout = cx.background_spawn(async move {
6236 match lsp_timeout {
6237 Some(lsp_timeout) => {
6238 lsp_timeout.await;
6239 true
6240 },
6241 None => false,
6242 }
6243 }).fuse();
6244 let mut lsp_request = lsp_store.request_lsp(
6245 buffer.clone(),
6246 LanguageServerToQuery::Other(server_id),
6247 GetCompletions {
6248 position,
6249 context: context.clone(),
6250 server_id: Some(server_id),
6251 },
6252 cx,
6253 ).fuse();
6254 let new_task = cx.background_spawn(async move {
6255 select_biased! {
6256 response = lsp_request => anyhow::Ok(Some(response?)),
6257 timeout_happened = timeout => {
6258 if timeout_happened {
6259 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6260 Ok(None)
6261 } else {
6262 let completions = lsp_request.await?;
6263 Ok(Some(completions))
6264 }
6265 },
6266 }
6267 });
6268 tasks.push((lsp_adapter, new_task));
6269 }
6270 })?;
6271
6272 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6273 let completion_response = task.await.ok()??;
6274 let completions = populate_labels_for_completions(
6275 completion_response.completions,
6276 language.clone(),
6277 lsp_adapter,
6278 )
6279 .await;
6280 Some(CompletionResponse {
6281 completions,
6282 display_options: CompletionDisplayOptions::default(),
6283 is_incomplete: completion_response.is_incomplete,
6284 })
6285 });
6286
6287 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6288
6289 Ok(responses.into_iter().flatten().collect())
6290 })
6291 } else {
6292 Task::ready(Err(anyhow!("No upstream client or local language server")))
6293 }
6294 }
6295
6296 pub fn resolve_completions(
6297 &self,
6298 buffer: Entity<Buffer>,
6299 completion_indices: Vec<usize>,
6300 completions: Rc<RefCell<Box<[Completion]>>>,
6301 cx: &mut Context<Self>,
6302 ) -> Task<Result<bool>> {
6303 let client = self.upstream_client();
6304 let buffer_id = buffer.read(cx).remote_id();
6305 let buffer_snapshot = buffer.read(cx).snapshot();
6306
6307 if !self.check_if_capable_for_proto_request(
6308 &buffer,
6309 GetCompletions::can_resolve_completions,
6310 cx,
6311 ) {
6312 return Task::ready(Ok(false));
6313 }
6314 cx.spawn(async move |lsp_store, cx| {
6315 let request_timeout = cx.update(|app| {
6316 ProjectSettings::get_global(app)
6317 .global_lsp_settings
6318 .get_request_timeout()
6319 });
6320
6321 let mut did_resolve = false;
6322 if let Some((client, project_id)) = client {
6323 for completion_index in completion_indices {
6324 let server_id = {
6325 let completion = &completions.borrow()[completion_index];
6326 completion.source.server_id()
6327 };
6328 if let Some(server_id) = server_id {
6329 if Self::resolve_completion_remote(
6330 project_id,
6331 server_id,
6332 buffer_id,
6333 completions.clone(),
6334 completion_index,
6335 client.clone(),
6336 )
6337 .await
6338 .log_err()
6339 .is_some()
6340 {
6341 did_resolve = true;
6342 }
6343 } else {
6344 resolve_word_completion(
6345 &buffer_snapshot,
6346 &mut completions.borrow_mut()[completion_index],
6347 );
6348 }
6349 }
6350 } else {
6351 for completion_index in completion_indices {
6352 let server_id = {
6353 let completion = &completions.borrow()[completion_index];
6354 completion.source.server_id()
6355 };
6356 if let Some(server_id) = server_id {
6357 let server_and_adapter = lsp_store
6358 .read_with(cx, |lsp_store, _| {
6359 let server = lsp_store.language_server_for_id(server_id)?;
6360 let adapter =
6361 lsp_store.language_server_adapter_for_id(server.server_id())?;
6362 Some((server, adapter))
6363 })
6364 .ok()
6365 .flatten();
6366 let Some((server, adapter)) = server_and_adapter else {
6367 continue;
6368 };
6369
6370 let resolved = Self::resolve_completion_local(
6371 server,
6372 completions.clone(),
6373 completion_index,
6374 request_timeout,
6375 )
6376 .await
6377 .log_err()
6378 .is_some();
6379 if resolved {
6380 Self::regenerate_completion_labels(
6381 adapter,
6382 &buffer_snapshot,
6383 completions.clone(),
6384 completion_index,
6385 )
6386 .await
6387 .log_err();
6388 did_resolve = true;
6389 }
6390 } else {
6391 resolve_word_completion(
6392 &buffer_snapshot,
6393 &mut completions.borrow_mut()[completion_index],
6394 );
6395 }
6396 }
6397 }
6398
6399 Ok(did_resolve)
6400 })
6401 }
6402
6403 async fn resolve_completion_local(
6404 server: Arc<lsp::LanguageServer>,
6405 completions: Rc<RefCell<Box<[Completion]>>>,
6406 completion_index: usize,
6407 request_timeout: Duration,
6408 ) -> Result<()> {
6409 let server_id = server.server_id();
6410 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6411 return Ok(());
6412 }
6413
6414 let request = {
6415 let completion = &completions.borrow()[completion_index];
6416 match &completion.source {
6417 CompletionSource::Lsp {
6418 lsp_completion,
6419 resolved,
6420 server_id: completion_server_id,
6421 ..
6422 } => {
6423 if *resolved {
6424 return Ok(());
6425 }
6426 anyhow::ensure!(
6427 server_id == *completion_server_id,
6428 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6429 );
6430 server.request::<lsp::request::ResolveCompletionItem>(
6431 *lsp_completion.clone(),
6432 request_timeout,
6433 )
6434 }
6435 CompletionSource::BufferWord { .. }
6436 | CompletionSource::Dap { .. }
6437 | CompletionSource::Custom => {
6438 return Ok(());
6439 }
6440 }
6441 };
6442 let resolved_completion = request
6443 .await
6444 .into_response()
6445 .context("resolve completion")?;
6446
6447 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6448 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6449
6450 let mut completions = completions.borrow_mut();
6451 let completion = &mut completions[completion_index];
6452 if let CompletionSource::Lsp {
6453 lsp_completion,
6454 resolved,
6455 server_id: completion_server_id,
6456 ..
6457 } = &mut completion.source
6458 {
6459 if *resolved {
6460 return Ok(());
6461 }
6462 anyhow::ensure!(
6463 server_id == *completion_server_id,
6464 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6465 );
6466 **lsp_completion = resolved_completion;
6467 *resolved = true;
6468 }
6469 Ok(())
6470 }
6471
6472 async fn regenerate_completion_labels(
6473 adapter: Arc<CachedLspAdapter>,
6474 snapshot: &BufferSnapshot,
6475 completions: Rc<RefCell<Box<[Completion]>>>,
6476 completion_index: usize,
6477 ) -> Result<()> {
6478 let completion_item = completions.borrow()[completion_index]
6479 .source
6480 .lsp_completion(true)
6481 .map(Cow::into_owned);
6482 if let Some(lsp_documentation) = completion_item
6483 .as_ref()
6484 .and_then(|completion_item| completion_item.documentation.clone())
6485 {
6486 let mut completions = completions.borrow_mut();
6487 let completion = &mut completions[completion_index];
6488 completion.documentation = Some(lsp_documentation.into());
6489 } else {
6490 let mut completions = completions.borrow_mut();
6491 let completion = &mut completions[completion_index];
6492 completion.documentation = Some(CompletionDocumentation::Undocumented);
6493 }
6494
6495 let mut new_label = match completion_item {
6496 Some(completion_item) => {
6497 // Some language servers always return `detail` lazily via resolve, regardless of
6498 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6499 // See: https://github.com/yioneko/vtsls/issues/213
6500 let language = snapshot.language();
6501 match language {
6502 Some(language) => {
6503 adapter
6504 .labels_for_completions(
6505 std::slice::from_ref(&completion_item),
6506 language,
6507 )
6508 .await?
6509 }
6510 None => Vec::new(),
6511 }
6512 .pop()
6513 .flatten()
6514 .unwrap_or_else(|| {
6515 CodeLabel::fallback_for_completion(
6516 &completion_item,
6517 language.map(|language| language.as_ref()),
6518 )
6519 })
6520 }
6521 None => CodeLabel::plain(
6522 completions.borrow()[completion_index].new_text.clone(),
6523 None,
6524 ),
6525 };
6526 ensure_uniform_list_compatible_label(&mut new_label);
6527
6528 let mut completions = completions.borrow_mut();
6529 let completion = &mut completions[completion_index];
6530 if completion.label.filter_text() == new_label.filter_text() {
6531 completion.label = new_label;
6532 } else {
6533 log::error!(
6534 "Resolved completion changed display label from {} to {}. \
6535 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6536 completion.label.text(),
6537 new_label.text(),
6538 completion.label.filter_text(),
6539 new_label.filter_text()
6540 );
6541 }
6542
6543 Ok(())
6544 }
6545
6546 async fn resolve_completion_remote(
6547 project_id: u64,
6548 server_id: LanguageServerId,
6549 buffer_id: BufferId,
6550 completions: Rc<RefCell<Box<[Completion]>>>,
6551 completion_index: usize,
6552 client: AnyProtoClient,
6553 ) -> Result<()> {
6554 let lsp_completion = {
6555 let completion = &completions.borrow()[completion_index];
6556 match &completion.source {
6557 CompletionSource::Lsp {
6558 lsp_completion,
6559 resolved,
6560 server_id: completion_server_id,
6561 ..
6562 } => {
6563 anyhow::ensure!(
6564 server_id == *completion_server_id,
6565 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6566 );
6567 if *resolved {
6568 return Ok(());
6569 }
6570 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6571 }
6572 CompletionSource::Custom
6573 | CompletionSource::Dap { .. }
6574 | CompletionSource::BufferWord { .. } => {
6575 return Ok(());
6576 }
6577 }
6578 };
6579 let request = proto::ResolveCompletionDocumentation {
6580 project_id,
6581 language_server_id: server_id.0 as u64,
6582 lsp_completion,
6583 buffer_id: buffer_id.into(),
6584 };
6585
6586 let response = client
6587 .request(request)
6588 .await
6589 .context("completion documentation resolve proto request")?;
6590 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6591
6592 let documentation = if response.documentation.is_empty() {
6593 CompletionDocumentation::Undocumented
6594 } else if response.documentation_is_markdown {
6595 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6596 } else if response.documentation.lines().count() <= 1 {
6597 CompletionDocumentation::SingleLine(response.documentation.into())
6598 } else {
6599 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6600 };
6601
6602 let mut completions = completions.borrow_mut();
6603 let completion = &mut completions[completion_index];
6604 completion.documentation = Some(documentation);
6605 if let CompletionSource::Lsp {
6606 insert_range,
6607 lsp_completion,
6608 resolved,
6609 server_id: completion_server_id,
6610 lsp_defaults: _,
6611 } = &mut completion.source
6612 {
6613 let completion_insert_range = response
6614 .old_insert_start
6615 .and_then(deserialize_anchor)
6616 .zip(response.old_insert_end.and_then(deserialize_anchor));
6617 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6618
6619 if *resolved {
6620 return Ok(());
6621 }
6622 anyhow::ensure!(
6623 server_id == *completion_server_id,
6624 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6625 );
6626 **lsp_completion = resolved_lsp_completion;
6627 *resolved = true;
6628 }
6629
6630 let replace_range = response
6631 .old_replace_start
6632 .and_then(deserialize_anchor)
6633 .zip(response.old_replace_end.and_then(deserialize_anchor));
6634 if let Some((old_replace_start, old_replace_end)) = replace_range
6635 && !response.new_text.is_empty()
6636 {
6637 completion.new_text = response.new_text;
6638 completion.replace_range = old_replace_start..old_replace_end;
6639 }
6640
6641 Ok(())
6642 }
6643
6644 pub fn apply_additional_edits_for_completion(
6645 &self,
6646 buffer_handle: Entity<Buffer>,
6647 completions: Rc<RefCell<Box<[Completion]>>>,
6648 completion_index: usize,
6649 push_to_history: bool,
6650 cx: &mut Context<Self>,
6651 ) -> Task<Result<Option<Transaction>>> {
6652 if let Some((client, project_id)) = self.upstream_client() {
6653 let buffer = buffer_handle.read(cx);
6654 let buffer_id = buffer.remote_id();
6655 cx.spawn(async move |_, cx| {
6656 let request = {
6657 let completion = completions.borrow()[completion_index].clone();
6658 proto::ApplyCompletionAdditionalEdits {
6659 project_id,
6660 buffer_id: buffer_id.into(),
6661 completion: Some(Self::serialize_completion(&CoreCompletion {
6662 replace_range: completion.replace_range,
6663 new_text: completion.new_text,
6664 source: completion.source,
6665 })),
6666 }
6667 };
6668
6669 let Some(transaction) = client.request(request).await?.transaction else {
6670 return Ok(None);
6671 };
6672
6673 let transaction = language::proto::deserialize_transaction(transaction)?;
6674 buffer_handle
6675 .update(cx, |buffer, _| {
6676 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6677 })
6678 .await?;
6679 if push_to_history {
6680 buffer_handle.update(cx, |buffer, _| {
6681 buffer.push_transaction(transaction.clone(), Instant::now());
6682 buffer.finalize_last_transaction();
6683 });
6684 }
6685 Ok(Some(transaction))
6686 })
6687 } else {
6688 let request_timeout = ProjectSettings::get_global(cx)
6689 .global_lsp_settings
6690 .get_request_timeout();
6691
6692 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6693 let completion = &completions.borrow()[completion_index];
6694 let server_id = completion.source.server_id()?;
6695 Some(
6696 self.language_server_for_local_buffer(buffer, server_id, cx)?
6697 .1
6698 .clone(),
6699 )
6700 }) else {
6701 return Task::ready(Ok(None));
6702 };
6703
6704 cx.spawn(async move |this, cx| {
6705 Self::resolve_completion_local(
6706 server.clone(),
6707 completions.clone(),
6708 completion_index,
6709 request_timeout,
6710 )
6711 .await
6712 .context("resolving completion")?;
6713 let completion = completions.borrow()[completion_index].clone();
6714 let additional_text_edits = completion
6715 .source
6716 .lsp_completion(true)
6717 .as_ref()
6718 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6719 if let Some(edits) = additional_text_edits {
6720 let edits = this
6721 .update(cx, |this, cx| {
6722 this.as_local_mut().unwrap().edits_from_lsp(
6723 &buffer_handle,
6724 edits,
6725 server.server_id(),
6726 None,
6727 cx,
6728 )
6729 })?
6730 .await?;
6731
6732 buffer_handle.update(cx, |buffer, cx| {
6733 buffer.finalize_last_transaction();
6734 buffer.start_transaction();
6735
6736 for (range, text) in edits {
6737 let primary = &completion.replace_range;
6738
6739 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6740 // and the primary completion is just an insertion (empty range), then this is likely
6741 // an auto-import scenario and should not be considered overlapping
6742 // https://github.com/zed-industries/zed/issues/26136
6743 let is_file_start_auto_import = {
6744 let snapshot = buffer.snapshot();
6745 let primary_start_point = primary.start.to_point(&snapshot);
6746 let range_start_point = range.start.to_point(&snapshot);
6747
6748 let result = primary_start_point.row == 0
6749 && primary_start_point.column == 0
6750 && range_start_point.row == 0
6751 && range_start_point.column == 0;
6752
6753 result
6754 };
6755
6756 let has_overlap = if is_file_start_auto_import {
6757 false
6758 } else {
6759 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6760 && primary.end.cmp(&range.start, buffer).is_ge();
6761 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6762 && range.end.cmp(&primary.end, buffer).is_ge();
6763 let result = start_within || end_within;
6764 result
6765 };
6766
6767 //Skip additional edits which overlap with the primary completion edit
6768 //https://github.com/zed-industries/zed/pull/1871
6769 if !has_overlap {
6770 buffer.edit([(range, text)], None, cx);
6771 }
6772 }
6773
6774 let transaction = if buffer.end_transaction(cx).is_some() {
6775 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6776 if !push_to_history {
6777 buffer.forget_transaction(transaction.id);
6778 }
6779 Some(transaction)
6780 } else {
6781 None
6782 };
6783 Ok(transaction)
6784 })
6785 } else {
6786 Ok(None)
6787 }
6788 })
6789 }
6790 }
6791
6792 pub fn pull_diagnostics(
6793 &mut self,
6794 buffer: Entity<Buffer>,
6795 cx: &mut Context<Self>,
6796 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6797 let buffer_id = buffer.read(cx).remote_id();
6798
6799 if let Some((client, upstream_project_id)) = self.upstream_client() {
6800 let mut suitable_capabilities = None;
6801 // Are we capable for proto request?
6802 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6803 &buffer,
6804 |capabilities| {
6805 if let Some(caps) = &capabilities.diagnostic_provider {
6806 suitable_capabilities = Some(caps.clone());
6807 true
6808 } else {
6809 false
6810 }
6811 },
6812 cx,
6813 );
6814 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6815 let Some(dynamic_caps) = suitable_capabilities else {
6816 return Task::ready(Ok(None));
6817 };
6818 assert!(any_server_has_diagnostics_provider);
6819
6820 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6821 let request = GetDocumentDiagnostics {
6822 previous_result_id: None,
6823 identifier,
6824 registration_id: None,
6825 };
6826 let request_timeout = ProjectSettings::get_global(cx)
6827 .global_lsp_settings
6828 .get_request_timeout();
6829 let request_task = client.request_lsp(
6830 upstream_project_id,
6831 None,
6832 request_timeout,
6833 cx.background_executor().clone(),
6834 request.to_proto(upstream_project_id, buffer.read(cx)),
6835 );
6836 cx.background_spawn(async move {
6837 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6838 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6839 // Do not attempt to further process the dummy responses here.
6840 let _response = request_task.await?;
6841 Ok(None)
6842 })
6843 } else {
6844 let servers = buffer.update(cx, |buffer, cx| {
6845 self.running_language_servers_for_local_buffer(buffer, cx)
6846 .map(|(_, server)| server.clone())
6847 .collect::<Vec<_>>()
6848 });
6849
6850 let pull_diagnostics = servers
6851 .into_iter()
6852 .flat_map(|server| {
6853 let result = maybe!({
6854 let local = self.as_local()?;
6855 let server_id = server.server_id();
6856 let providers_with_identifiers = local
6857 .language_server_dynamic_registrations
6858 .get(&server_id)
6859 .into_iter()
6860 .flat_map(|registrations| registrations.diagnostics.clone())
6861 .collect::<Vec<_>>();
6862 Some(
6863 providers_with_identifiers
6864 .into_iter()
6865 .map(|(registration_id, dynamic_caps)| {
6866 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6867 let registration_id = registration_id.map(SharedString::from);
6868 let result_id = self.result_id_for_buffer_pull(
6869 server_id,
6870 buffer_id,
6871 ®istration_id,
6872 cx,
6873 );
6874 self.request_lsp(
6875 buffer.clone(),
6876 LanguageServerToQuery::Other(server_id),
6877 GetDocumentDiagnostics {
6878 previous_result_id: result_id,
6879 registration_id,
6880 identifier,
6881 },
6882 cx,
6883 )
6884 })
6885 .collect::<Vec<_>>(),
6886 )
6887 });
6888
6889 result.unwrap_or_default()
6890 })
6891 .collect::<Vec<_>>();
6892
6893 cx.background_spawn(async move {
6894 let mut responses = Vec::new();
6895 for diagnostics in join_all(pull_diagnostics).await {
6896 responses.extend(diagnostics?);
6897 }
6898 Ok(Some(responses))
6899 })
6900 }
6901 }
6902
6903 pub fn applicable_inlay_chunks(
6904 &mut self,
6905 buffer: &Entity<Buffer>,
6906 ranges: &[Range<text::Anchor>],
6907 cx: &mut Context<Self>,
6908 ) -> Vec<Range<BufferRow>> {
6909 let buffer_snapshot = buffer.read(cx).snapshot();
6910 let ranges = ranges
6911 .iter()
6912 .map(|range| range.to_point(&buffer_snapshot))
6913 .collect::<Vec<_>>();
6914
6915 self.latest_lsp_data(buffer, cx)
6916 .inlay_hints
6917 .applicable_chunks(ranges.as_slice())
6918 .map(|chunk| chunk.row_range())
6919 .collect()
6920 }
6921
6922 pub fn invalidate_inlay_hints<'a>(
6923 &'a mut self,
6924 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6925 ) {
6926 for buffer_id in for_buffers {
6927 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6928 lsp_data.inlay_hints.clear();
6929 }
6930 }
6931 }
6932
6933 pub fn inlay_hints(
6934 &mut self,
6935 invalidate: InvalidationStrategy,
6936 buffer: Entity<Buffer>,
6937 ranges: Vec<Range<text::Anchor>>,
6938 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6939 cx: &mut Context<Self>,
6940 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6941 let next_hint_id = self.next_hint_id.clone();
6942 let lsp_data = self.latest_lsp_data(&buffer, cx);
6943 let query_version = lsp_data.buffer_version.clone();
6944 let mut lsp_refresh_requested = false;
6945 let for_server = if let InvalidationStrategy::RefreshRequested {
6946 server_id,
6947 request_id,
6948 } = invalidate
6949 {
6950 let invalidated = lsp_data
6951 .inlay_hints
6952 .invalidate_for_server_refresh(server_id, request_id);
6953 lsp_refresh_requested = invalidated;
6954 Some(server_id)
6955 } else {
6956 None
6957 };
6958 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6959 let known_chunks = known_chunks
6960 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6961 .map(|(_, known_chunks)| known_chunks)
6962 .unwrap_or_default();
6963
6964 let buffer_snapshot = buffer.read(cx).snapshot();
6965 let ranges = ranges
6966 .iter()
6967 .map(|range| range.to_point(&buffer_snapshot))
6968 .collect::<Vec<_>>();
6969
6970 let mut hint_fetch_tasks = Vec::new();
6971 let mut cached_inlay_hints = None;
6972 let mut ranges_to_query = None;
6973 let applicable_chunks = existing_inlay_hints
6974 .applicable_chunks(ranges.as_slice())
6975 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6976 .collect::<Vec<_>>();
6977 if applicable_chunks.is_empty() {
6978 return HashMap::default();
6979 }
6980
6981 for row_chunk in applicable_chunks {
6982 match (
6983 existing_inlay_hints
6984 .cached_hints(&row_chunk)
6985 .filter(|_| !lsp_refresh_requested)
6986 .cloned(),
6987 existing_inlay_hints
6988 .fetched_hints(&row_chunk)
6989 .as_ref()
6990 .filter(|_| !lsp_refresh_requested)
6991 .cloned(),
6992 ) {
6993 (None, None) => {
6994 let chunk_range = row_chunk.anchor_range();
6995 ranges_to_query
6996 .get_or_insert_with(Vec::new)
6997 .push((row_chunk, chunk_range));
6998 }
6999 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7000 (Some(cached_hints), None) => {
7001 for (server_id, cached_hints) in cached_hints {
7002 if for_server.is_none_or(|for_server| for_server == server_id) {
7003 cached_inlay_hints
7004 .get_or_insert_with(HashMap::default)
7005 .entry(row_chunk.row_range())
7006 .or_insert_with(HashMap::default)
7007 .entry(server_id)
7008 .or_insert_with(Vec::new)
7009 .extend(cached_hints);
7010 }
7011 }
7012 }
7013 (Some(cached_hints), Some(fetched_hints)) => {
7014 hint_fetch_tasks.push((row_chunk, fetched_hints));
7015 for (server_id, cached_hints) in cached_hints {
7016 if for_server.is_none_or(|for_server| for_server == server_id) {
7017 cached_inlay_hints
7018 .get_or_insert_with(HashMap::default)
7019 .entry(row_chunk.row_range())
7020 .or_insert_with(HashMap::default)
7021 .entry(server_id)
7022 .or_insert_with(Vec::new)
7023 .extend(cached_hints);
7024 }
7025 }
7026 }
7027 }
7028 }
7029
7030 if hint_fetch_tasks.is_empty()
7031 && ranges_to_query
7032 .as_ref()
7033 .is_none_or(|ranges| ranges.is_empty())
7034 && let Some(cached_inlay_hints) = cached_inlay_hints
7035 {
7036 cached_inlay_hints
7037 .into_iter()
7038 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7039 .collect()
7040 } else {
7041 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7042 // When a server refresh was requested, other servers' cached hints
7043 // are unaffected by the refresh and must be included in the result.
7044 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7045 // removes all visible hints but only adds back the requesting
7046 // server's new hints, permanently losing other servers' hints.
7047 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7048 lsp_data
7049 .inlay_hints
7050 .cached_hints(&chunk)
7051 .cloned()
7052 .unwrap_or_default()
7053 } else {
7054 HashMap::default()
7055 };
7056
7057 let next_hint_id = next_hint_id.clone();
7058 let buffer = buffer.clone();
7059 let query_version = query_version.clone();
7060 let new_inlay_hints = cx
7061 .spawn(async move |lsp_store, cx| {
7062 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7063 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7064 })?;
7065 new_fetch_task
7066 .await
7067 .and_then(|new_hints_by_server| {
7068 lsp_store.update(cx, |lsp_store, cx| {
7069 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7070 let update_cache = lsp_data.buffer_version == query_version;
7071 if new_hints_by_server.is_empty() {
7072 if update_cache {
7073 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7074 }
7075 other_servers_cached
7076 } else {
7077 let mut result = other_servers_cached;
7078 for (server_id, new_hints) in new_hints_by_server {
7079 let new_hints = new_hints
7080 .into_iter()
7081 .map(|new_hint| {
7082 (
7083 InlayId::Hint(next_hint_id.fetch_add(
7084 1,
7085 atomic::Ordering::AcqRel,
7086 )),
7087 new_hint,
7088 )
7089 })
7090 .collect::<Vec<_>>();
7091 if update_cache {
7092 lsp_data.inlay_hints.insert_new_hints(
7093 chunk,
7094 server_id,
7095 new_hints.clone(),
7096 );
7097 }
7098 result.insert(server_id, new_hints);
7099 }
7100 result
7101 }
7102 })
7103 })
7104 .map_err(Arc::new)
7105 })
7106 .shared();
7107
7108 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7109 *fetch_task = Some(new_inlay_hints.clone());
7110 hint_fetch_tasks.push((chunk, new_inlay_hints));
7111 }
7112
7113 cached_inlay_hints
7114 .unwrap_or_default()
7115 .into_iter()
7116 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7117 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7118 (
7119 chunk.row_range(),
7120 cx.spawn(async move |_, _| {
7121 hints_fetch.await.map_err(|e| {
7122 if e.error_code() != ErrorCode::Internal {
7123 anyhow!(e.error_code())
7124 } else {
7125 anyhow!("{e:#}")
7126 }
7127 })
7128 }),
7129 )
7130 }))
7131 .collect()
7132 }
7133 }
7134
7135 fn fetch_inlay_hints(
7136 &mut self,
7137 for_server: Option<LanguageServerId>,
7138 buffer: &Entity<Buffer>,
7139 range: Range<Anchor>,
7140 cx: &mut Context<Self>,
7141 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7142 let request = InlayHints {
7143 range: range.clone(),
7144 };
7145 if let Some((upstream_client, project_id)) = self.upstream_client() {
7146 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7147 return Task::ready(Ok(HashMap::default()));
7148 }
7149 let request_timeout = ProjectSettings::get_global(cx)
7150 .global_lsp_settings
7151 .get_request_timeout();
7152 let request_task = upstream_client.request_lsp(
7153 project_id,
7154 for_server.map(|id| id.to_proto()),
7155 request_timeout,
7156 cx.background_executor().clone(),
7157 request.to_proto(project_id, buffer.read(cx)),
7158 );
7159 let buffer = buffer.clone();
7160 cx.spawn(async move |weak_lsp_store, cx| {
7161 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7162 return Ok(HashMap::default());
7163 };
7164 let Some(responses) = request_task.await? else {
7165 return Ok(HashMap::default());
7166 };
7167
7168 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7169 let lsp_store = lsp_store.clone();
7170 let buffer = buffer.clone();
7171 let cx = cx.clone();
7172 let request = request.clone();
7173 async move {
7174 (
7175 LanguageServerId::from_proto(response.server_id),
7176 request
7177 .response_from_proto(response.response, lsp_store, buffer, cx)
7178 .await,
7179 )
7180 }
7181 }))
7182 .await;
7183
7184 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7185 let mut has_errors = false;
7186 let inlay_hints = inlay_hints
7187 .into_iter()
7188 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7189 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7190 Err(e) => {
7191 has_errors = true;
7192 log::error!("{e:#}");
7193 None
7194 }
7195 })
7196 .map(|(server_id, mut new_hints)| {
7197 new_hints.retain(|hint| {
7198 hint.position.is_valid(&buffer_snapshot)
7199 && range.start.is_valid(&buffer_snapshot)
7200 && range.end.is_valid(&buffer_snapshot)
7201 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7202 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7203 });
7204 (server_id, new_hints)
7205 })
7206 .collect::<HashMap<_, _>>();
7207 anyhow::ensure!(
7208 !has_errors || !inlay_hints.is_empty(),
7209 "Failed to fetch inlay hints"
7210 );
7211 Ok(inlay_hints)
7212 })
7213 } else {
7214 let inlay_hints_task = match for_server {
7215 Some(server_id) => {
7216 let server_task = self.request_lsp(
7217 buffer.clone(),
7218 LanguageServerToQuery::Other(server_id),
7219 request,
7220 cx,
7221 );
7222 cx.background_spawn(async move {
7223 let mut responses = Vec::new();
7224 match server_task.await {
7225 Ok(response) => responses.push((server_id, response)),
7226 // rust-analyzer likes to error with this when its still loading up
7227 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7228 Err(e) => log::error!(
7229 "Error handling response for inlay hints request: {e:#}"
7230 ),
7231 }
7232 responses
7233 })
7234 }
7235 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7236 };
7237 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7238 cx.background_spawn(async move {
7239 Ok(inlay_hints_task
7240 .await
7241 .into_iter()
7242 .map(|(server_id, mut new_hints)| {
7243 new_hints.retain(|hint| {
7244 hint.position.is_valid(&buffer_snapshot)
7245 && range.start.is_valid(&buffer_snapshot)
7246 && range.end.is_valid(&buffer_snapshot)
7247 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7248 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7249 });
7250 (server_id, new_hints)
7251 })
7252 .collect())
7253 })
7254 }
7255 }
7256
7257 fn diagnostic_registration_exists(
7258 &self,
7259 server_id: LanguageServerId,
7260 registration_id: &Option<SharedString>,
7261 ) -> bool {
7262 let Some(local) = self.as_local() else {
7263 return false;
7264 };
7265 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7266 else {
7267 return false;
7268 };
7269 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7270 registrations.diagnostics.contains_key(®istration_key)
7271 }
7272
7273 pub fn pull_diagnostics_for_buffer(
7274 &mut self,
7275 buffer: Entity<Buffer>,
7276 cx: &mut Context<Self>,
7277 ) -> Task<anyhow::Result<()>> {
7278 let diagnostics = self.pull_diagnostics(buffer, cx);
7279 cx.spawn(async move |lsp_store, cx| {
7280 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7281 return Ok(());
7282 };
7283 lsp_store.update(cx, |lsp_store, cx| {
7284 if lsp_store.as_local().is_none() {
7285 return;
7286 }
7287
7288 let mut unchanged_buffers = HashMap::default();
7289 let server_diagnostics_updates = diagnostics
7290 .into_iter()
7291 .filter_map(|diagnostics_set| match diagnostics_set {
7292 LspPullDiagnostics::Response {
7293 server_id,
7294 uri,
7295 diagnostics,
7296 registration_id,
7297 } => Some((server_id, uri, diagnostics, registration_id)),
7298 LspPullDiagnostics::Default => None,
7299 })
7300 .filter(|(server_id, _, _, registration_id)| {
7301 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7302 })
7303 .fold(
7304 HashMap::default(),
7305 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7306 let (result_id, diagnostics) = match diagnostics {
7307 PulledDiagnostics::Unchanged { result_id } => {
7308 unchanged_buffers
7309 .entry(new_registration_id.clone())
7310 .or_insert_with(HashSet::default)
7311 .insert(uri.clone());
7312 (Some(result_id), Vec::new())
7313 }
7314 PulledDiagnostics::Changed {
7315 result_id,
7316 diagnostics,
7317 } => (result_id, diagnostics),
7318 };
7319 let disk_based_sources = Cow::Owned(
7320 lsp_store
7321 .language_server_adapter_for_id(server_id)
7322 .as_ref()
7323 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7324 .unwrap_or(&[])
7325 .to_vec(),
7326 );
7327 acc.entry(server_id)
7328 .or_insert_with(HashMap::default)
7329 .entry(new_registration_id.clone())
7330 .or_insert_with(Vec::new)
7331 .push(DocumentDiagnosticsUpdate {
7332 server_id,
7333 diagnostics: lsp::PublishDiagnosticsParams {
7334 uri,
7335 diagnostics,
7336 version: None,
7337 },
7338 result_id: result_id.map(SharedString::new),
7339 disk_based_sources,
7340 registration_id: new_registration_id,
7341 });
7342 acc
7343 },
7344 );
7345
7346 for diagnostic_updates in server_diagnostics_updates.into_values() {
7347 for (registration_id, diagnostic_updates) in diagnostic_updates {
7348 lsp_store
7349 .merge_lsp_diagnostics(
7350 DiagnosticSourceKind::Pulled,
7351 diagnostic_updates,
7352 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7353 DiagnosticSourceKind::Pulled => {
7354 old_diagnostic.registration_id != registration_id
7355 || unchanged_buffers
7356 .get(&old_diagnostic.registration_id)
7357 .is_some_and(|unchanged_buffers| {
7358 unchanged_buffers.contains(&document_uri)
7359 })
7360 }
7361 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7362 true
7363 }
7364 },
7365 cx,
7366 )
7367 .log_err();
7368 }
7369 }
7370 })
7371 })
7372 }
7373
7374 pub fn signature_help<T: ToPointUtf16>(
7375 &mut self,
7376 buffer: &Entity<Buffer>,
7377 position: T,
7378 cx: &mut Context<Self>,
7379 ) -> Task<Option<Vec<SignatureHelp>>> {
7380 let position = position.to_point_utf16(buffer.read(cx));
7381
7382 if let Some((client, upstream_project_id)) = self.upstream_client() {
7383 let request = GetSignatureHelp { position };
7384 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7385 return Task::ready(None);
7386 }
7387 let request_timeout = ProjectSettings::get_global(cx)
7388 .global_lsp_settings
7389 .get_request_timeout();
7390 let request_task = client.request_lsp(
7391 upstream_project_id,
7392 None,
7393 request_timeout,
7394 cx.background_executor().clone(),
7395 request.to_proto(upstream_project_id, buffer.read(cx)),
7396 );
7397 let buffer = buffer.clone();
7398 cx.spawn(async move |weak_lsp_store, cx| {
7399 let lsp_store = weak_lsp_store.upgrade()?;
7400 let signatures = join_all(
7401 request_task
7402 .await
7403 .log_err()
7404 .flatten()
7405 .map(|response| response.payload)
7406 .unwrap_or_default()
7407 .into_iter()
7408 .map(|response| {
7409 let response = GetSignatureHelp { position }.response_from_proto(
7410 response.response,
7411 lsp_store.clone(),
7412 buffer.clone(),
7413 cx.clone(),
7414 );
7415 async move { response.await.log_err().flatten() }
7416 }),
7417 )
7418 .await
7419 .into_iter()
7420 .flatten()
7421 .collect();
7422 Some(signatures)
7423 })
7424 } else {
7425 let all_actions_task = self.request_multiple_lsp_locally(
7426 buffer,
7427 Some(position),
7428 GetSignatureHelp { position },
7429 cx,
7430 );
7431 cx.background_spawn(async move {
7432 Some(
7433 all_actions_task
7434 .await
7435 .into_iter()
7436 .flat_map(|(_, actions)| actions)
7437 .collect::<Vec<_>>(),
7438 )
7439 })
7440 }
7441 }
7442
7443 pub fn hover(
7444 &mut self,
7445 buffer: &Entity<Buffer>,
7446 position: PointUtf16,
7447 cx: &mut Context<Self>,
7448 ) -> Task<Option<Vec<Hover>>> {
7449 if let Some((client, upstream_project_id)) = self.upstream_client() {
7450 let request = GetHover { position };
7451 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7452 return Task::ready(None);
7453 }
7454 let request_timeout = ProjectSettings::get_global(cx)
7455 .global_lsp_settings
7456 .get_request_timeout();
7457 let request_task = client.request_lsp(
7458 upstream_project_id,
7459 None,
7460 request_timeout,
7461 cx.background_executor().clone(),
7462 request.to_proto(upstream_project_id, buffer.read(cx)),
7463 );
7464 let buffer = buffer.clone();
7465 cx.spawn(async move |weak_lsp_store, cx| {
7466 let lsp_store = weak_lsp_store.upgrade()?;
7467 let hovers = join_all(
7468 request_task
7469 .await
7470 .log_err()
7471 .flatten()
7472 .map(|response| response.payload)
7473 .unwrap_or_default()
7474 .into_iter()
7475 .map(|response| {
7476 let response = GetHover { position }.response_from_proto(
7477 response.response,
7478 lsp_store.clone(),
7479 buffer.clone(),
7480 cx.clone(),
7481 );
7482 async move {
7483 response
7484 .await
7485 .log_err()
7486 .flatten()
7487 .and_then(remove_empty_hover_blocks)
7488 }
7489 }),
7490 )
7491 .await
7492 .into_iter()
7493 .flatten()
7494 .collect();
7495 Some(hovers)
7496 })
7497 } else {
7498 let all_actions_task = self.request_multiple_lsp_locally(
7499 buffer,
7500 Some(position),
7501 GetHover { position },
7502 cx,
7503 );
7504 cx.background_spawn(async move {
7505 Some(
7506 all_actions_task
7507 .await
7508 .into_iter()
7509 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7510 .collect::<Vec<Hover>>(),
7511 )
7512 })
7513 }
7514 }
7515
7516 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7517 let language_registry = self.languages.clone();
7518
7519 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7520 let request = upstream_client.request(proto::GetProjectSymbols {
7521 project_id: *project_id,
7522 query: query.to_string(),
7523 });
7524 cx.foreground_executor().spawn(async move {
7525 let response = request.await?;
7526 let mut symbols = Vec::new();
7527 let core_symbols = response
7528 .symbols
7529 .into_iter()
7530 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7531 .collect::<Vec<_>>();
7532 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7533 .await;
7534 Ok(symbols)
7535 })
7536 } else if let Some(local) = self.as_local() {
7537 struct WorkspaceSymbolsResult {
7538 server_id: LanguageServerId,
7539 lsp_adapter: Arc<CachedLspAdapter>,
7540 worktree: WeakEntity<Worktree>,
7541 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7542 }
7543
7544 let mut requests = Vec::new();
7545 let mut requested_servers = BTreeSet::new();
7546 let request_timeout = ProjectSettings::get_global(cx)
7547 .global_lsp_settings
7548 .get_request_timeout();
7549
7550 for (seed, state) in local.language_server_ids.iter() {
7551 let Some(worktree_handle) = self
7552 .worktree_store
7553 .read(cx)
7554 .worktree_for_id(seed.worktree_id, cx)
7555 else {
7556 continue;
7557 };
7558
7559 let worktree = worktree_handle.read(cx);
7560 if !worktree.is_visible() {
7561 continue;
7562 }
7563
7564 if !requested_servers.insert(state.id) {
7565 continue;
7566 }
7567
7568 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7569 Some(LanguageServerState::Running {
7570 adapter, server, ..
7571 }) => (adapter.clone(), server),
7572
7573 _ => continue,
7574 };
7575
7576 let supports_workspace_symbol_request =
7577 match server.capabilities().workspace_symbol_provider {
7578 Some(OneOf::Left(supported)) => supported,
7579 Some(OneOf::Right(_)) => true,
7580 None => false,
7581 };
7582
7583 if !supports_workspace_symbol_request {
7584 continue;
7585 }
7586
7587 let worktree_handle = worktree_handle.clone();
7588 let server_id = server.server_id();
7589 requests.push(
7590 server
7591 .request::<lsp::request::WorkspaceSymbolRequest>(
7592 lsp::WorkspaceSymbolParams {
7593 query: query.to_string(),
7594 ..Default::default()
7595 },
7596 request_timeout,
7597 )
7598 .map(move |response| {
7599 let lsp_symbols = response
7600 .into_response()
7601 .context("workspace symbols request")
7602 .log_err()
7603 .flatten()
7604 .map(|symbol_response| match symbol_response {
7605 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7606 flat_responses
7607 .into_iter()
7608 .map(|lsp_symbol| {
7609 (
7610 lsp_symbol.name,
7611 lsp_symbol.kind,
7612 lsp_symbol.location,
7613 lsp_symbol.container_name,
7614 )
7615 })
7616 .collect::<Vec<_>>()
7617 }
7618 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7619 nested_responses
7620 .into_iter()
7621 .filter_map(|lsp_symbol| {
7622 let location = match lsp_symbol.location {
7623 OneOf::Left(location) => location,
7624 OneOf::Right(_) => {
7625 log::error!(
7626 "Unexpected: client capabilities \
7627 forbid symbol resolutions in \
7628 workspace.symbol.resolveSupport"
7629 );
7630 return None;
7631 }
7632 };
7633 Some((
7634 lsp_symbol.name,
7635 lsp_symbol.kind,
7636 location,
7637 lsp_symbol.container_name,
7638 ))
7639 })
7640 .collect::<Vec<_>>()
7641 }
7642 })
7643 .unwrap_or_default();
7644
7645 WorkspaceSymbolsResult {
7646 server_id,
7647 lsp_adapter,
7648 worktree: worktree_handle.downgrade(),
7649 lsp_symbols,
7650 }
7651 }),
7652 );
7653 }
7654
7655 cx.spawn(async move |this, cx| {
7656 let responses = futures::future::join_all(requests).await;
7657 let this = match this.upgrade() {
7658 Some(this) => this,
7659 None => return Ok(Vec::new()),
7660 };
7661
7662 let mut symbols = Vec::new();
7663 for result in responses {
7664 let core_symbols = this.update(cx, |this, cx| {
7665 result
7666 .lsp_symbols
7667 .into_iter()
7668 .filter_map(
7669 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7670 let abs_path = symbol_location.uri.to_file_path().ok()?;
7671 let source_worktree = result.worktree.upgrade()?;
7672 let source_worktree_id = source_worktree.read(cx).id();
7673
7674 let path = if let Some((tree, rel_path)) =
7675 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7676 {
7677 let worktree_id = tree.read(cx).id();
7678 SymbolLocation::InProject(ProjectPath {
7679 worktree_id,
7680 path: rel_path,
7681 })
7682 } else {
7683 SymbolLocation::OutsideProject {
7684 signature: this.symbol_signature(&abs_path),
7685 abs_path: abs_path.into(),
7686 }
7687 };
7688
7689 Some(CoreSymbol {
7690 source_language_server_id: result.server_id,
7691 language_server_name: result.lsp_adapter.name.clone(),
7692 source_worktree_id,
7693 path,
7694 kind: symbol_kind,
7695 name: collapse_newlines(&symbol_name, "↵ "),
7696 range: range_from_lsp(symbol_location.range),
7697 container_name: container_name
7698 .map(|c| collapse_newlines(&c, "↵ ")),
7699 })
7700 },
7701 )
7702 .collect::<Vec<_>>()
7703 });
7704
7705 populate_labels_for_symbols(
7706 core_symbols,
7707 &language_registry,
7708 Some(result.lsp_adapter),
7709 &mut symbols,
7710 )
7711 .await;
7712 }
7713
7714 Ok(symbols)
7715 })
7716 } else {
7717 Task::ready(Err(anyhow!("No upstream client or local language server")))
7718 }
7719 }
7720
7721 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7722 let mut summary = DiagnosticSummary::default();
7723 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7724 summary.error_count += path_summary.error_count;
7725 summary.warning_count += path_summary.warning_count;
7726 }
7727 summary
7728 }
7729
7730 /// Returns the diagnostic summary for a specific project path.
7731 pub fn diagnostic_summary_for_path(
7732 &self,
7733 project_path: &ProjectPath,
7734 _: &App,
7735 ) -> DiagnosticSummary {
7736 if let Some(summaries) = self
7737 .diagnostic_summaries
7738 .get(&project_path.worktree_id)
7739 .and_then(|map| map.get(&project_path.path))
7740 {
7741 let (error_count, warning_count) = summaries.iter().fold(
7742 (0, 0),
7743 |(error_count, warning_count), (_language_server_id, summary)| {
7744 (
7745 error_count + summary.error_count,
7746 warning_count + summary.warning_count,
7747 )
7748 },
7749 );
7750
7751 DiagnosticSummary {
7752 error_count,
7753 warning_count,
7754 }
7755 } else {
7756 DiagnosticSummary::default()
7757 }
7758 }
7759
7760 pub fn diagnostic_summaries<'a>(
7761 &'a self,
7762 include_ignored: bool,
7763 cx: &'a App,
7764 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7765 self.worktree_store
7766 .read(cx)
7767 .visible_worktrees(cx)
7768 .filter_map(|worktree| {
7769 let worktree = worktree.read(cx);
7770 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7771 })
7772 .flat_map(move |(worktree, summaries)| {
7773 let worktree_id = worktree.id();
7774 summaries
7775 .iter()
7776 .filter(move |(path, _)| {
7777 include_ignored
7778 || worktree
7779 .entry_for_path(path.as_ref())
7780 .is_some_and(|entry| !entry.is_ignored)
7781 })
7782 .flat_map(move |(path, summaries)| {
7783 summaries.iter().map(move |(server_id, summary)| {
7784 (
7785 ProjectPath {
7786 worktree_id,
7787 path: path.clone(),
7788 },
7789 *server_id,
7790 *summary,
7791 )
7792 })
7793 })
7794 })
7795 }
7796
7797 pub fn on_buffer_edited(
7798 &mut self,
7799 buffer: Entity<Buffer>,
7800 cx: &mut Context<Self>,
7801 ) -> Option<()> {
7802 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7803 Some(
7804 self.as_local()?
7805 .language_servers_for_buffer(buffer, cx)
7806 .map(|i| i.1.clone())
7807 .collect(),
7808 )
7809 })?;
7810
7811 let buffer = buffer.read(cx);
7812 let file = File::from_dyn(buffer.file())?;
7813 let abs_path = file.as_local()?.abs_path(cx);
7814 let uri = lsp::Uri::from_file_path(&abs_path)
7815 .ok()
7816 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7817 .log_err()?;
7818 let next_snapshot = buffer.text_snapshot();
7819 for language_server in language_servers {
7820 let language_server = language_server.clone();
7821
7822 let buffer_snapshots = self
7823 .as_local_mut()?
7824 .buffer_snapshots
7825 .get_mut(&buffer.remote_id())
7826 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7827 let previous_snapshot = buffer_snapshots.last()?;
7828
7829 let build_incremental_change = || {
7830 buffer
7831 .edits_since::<Dimensions<PointUtf16, usize>>(
7832 previous_snapshot.snapshot.version(),
7833 )
7834 .map(|edit| {
7835 let edit_start = edit.new.start.0;
7836 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7837 let new_text = next_snapshot
7838 .text_for_range(edit.new.start.1..edit.new.end.1)
7839 .collect();
7840 lsp::TextDocumentContentChangeEvent {
7841 range: Some(lsp::Range::new(
7842 point_to_lsp(edit_start),
7843 point_to_lsp(edit_end),
7844 )),
7845 range_length: None,
7846 text: new_text,
7847 }
7848 })
7849 .collect()
7850 };
7851
7852 let document_sync_kind = language_server
7853 .capabilities()
7854 .text_document_sync
7855 .as_ref()
7856 .and_then(|sync| match sync {
7857 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7858 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7859 });
7860
7861 let content_changes: Vec<_> = match document_sync_kind {
7862 Some(lsp::TextDocumentSyncKind::FULL) => {
7863 vec![lsp::TextDocumentContentChangeEvent {
7864 range: None,
7865 range_length: None,
7866 text: next_snapshot.text(),
7867 }]
7868 }
7869 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7870 _ => {
7871 #[cfg(any(test, feature = "test-support"))]
7872 {
7873 build_incremental_change()
7874 }
7875
7876 #[cfg(not(any(test, feature = "test-support")))]
7877 {
7878 continue;
7879 }
7880 }
7881 };
7882
7883 let next_version = previous_snapshot.version + 1;
7884 buffer_snapshots.push(LspBufferSnapshot {
7885 version: next_version,
7886 snapshot: next_snapshot.clone(),
7887 });
7888
7889 language_server
7890 .notify::<lsp::notification::DidChangeTextDocument>(
7891 lsp::DidChangeTextDocumentParams {
7892 text_document: lsp::VersionedTextDocumentIdentifier::new(
7893 uri.clone(),
7894 next_version,
7895 ),
7896 content_changes,
7897 },
7898 )
7899 .ok();
7900 self.pull_workspace_diagnostics(language_server.server_id());
7901 }
7902
7903 None
7904 }
7905
7906 pub fn on_buffer_saved(
7907 &mut self,
7908 buffer: Entity<Buffer>,
7909 cx: &mut Context<Self>,
7910 ) -> Option<()> {
7911 let file = File::from_dyn(buffer.read(cx).file())?;
7912 let worktree_id = file.worktree_id(cx);
7913 let abs_path = file.as_local()?.abs_path(cx);
7914 let text_document = lsp::TextDocumentIdentifier {
7915 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7916 };
7917 let local = self.as_local()?;
7918
7919 for server in local.language_servers_for_worktree(worktree_id) {
7920 if let Some(include_text) = include_text(server.as_ref()) {
7921 let text = if include_text {
7922 Some(buffer.read(cx).text())
7923 } else {
7924 None
7925 };
7926 server
7927 .notify::<lsp::notification::DidSaveTextDocument>(
7928 lsp::DidSaveTextDocumentParams {
7929 text_document: text_document.clone(),
7930 text,
7931 },
7932 )
7933 .ok();
7934 }
7935 }
7936
7937 let language_servers = buffer.update(cx, |buffer, cx| {
7938 local.language_server_ids_for_buffer(buffer, cx)
7939 });
7940 for language_server_id in language_servers {
7941 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7942 }
7943
7944 None
7945 }
7946
7947 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7948 maybe!(async move {
7949 let mut refreshed_servers = HashSet::default();
7950 let servers = lsp_store
7951 .update(cx, |lsp_store, cx| {
7952 let local = lsp_store.as_local()?;
7953
7954 let servers = local
7955 .language_server_ids
7956 .iter()
7957 .filter_map(|(seed, state)| {
7958 let worktree = lsp_store
7959 .worktree_store
7960 .read(cx)
7961 .worktree_for_id(seed.worktree_id, cx);
7962 let delegate: Arc<dyn LspAdapterDelegate> =
7963 worktree.map(|worktree| {
7964 LocalLspAdapterDelegate::new(
7965 local.languages.clone(),
7966 &local.environment,
7967 cx.weak_entity(),
7968 &worktree,
7969 local.http_client.clone(),
7970 local.fs.clone(),
7971 cx,
7972 )
7973 })?;
7974 let server_id = state.id;
7975
7976 let states = local.language_servers.get(&server_id)?;
7977
7978 match states {
7979 LanguageServerState::Starting { .. } => None,
7980 LanguageServerState::Running {
7981 adapter, server, ..
7982 } => {
7983 let adapter = adapter.clone();
7984 let server = server.clone();
7985 refreshed_servers.insert(server.name());
7986 let toolchain = seed.toolchain.clone();
7987 Some(cx.spawn(async move |_, cx| {
7988 let settings =
7989 LocalLspStore::workspace_configuration_for_adapter(
7990 adapter.adapter.clone(),
7991 &delegate,
7992 toolchain,
7993 None,
7994 cx,
7995 )
7996 .await
7997 .ok()?;
7998 server
7999 .notify::<lsp::notification::DidChangeConfiguration>(
8000 lsp::DidChangeConfigurationParams { settings },
8001 )
8002 .ok()?;
8003 Some(())
8004 }))
8005 }
8006 }
8007 })
8008 .collect::<Vec<_>>();
8009
8010 Some(servers)
8011 })
8012 .ok()
8013 .flatten()?;
8014
8015 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8016 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8017 // to stop and unregister its language server wrapper.
8018 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8019 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8020 let _: Vec<Option<()>> = join_all(servers).await;
8021
8022 Some(())
8023 })
8024 .await;
8025 }
8026
8027 fn maintain_workspace_config(
8028 external_refresh_requests: watch::Receiver<()>,
8029 cx: &mut Context<Self>,
8030 ) -> Task<Result<()>> {
8031 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8032 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8033
8034 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8035 *settings_changed_tx.borrow_mut() = ();
8036 });
8037
8038 let mut joint_future =
8039 futures::stream::select(settings_changed_rx, external_refresh_requests);
8040 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8041 // - 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).
8042 // - 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.
8043 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8044 // - 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,
8045 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8046 cx.spawn(async move |this, cx| {
8047 while let Some(()) = joint_future.next().await {
8048 this.update(cx, |this, cx| {
8049 this.refresh_server_tree(cx);
8050 })
8051 .ok();
8052
8053 Self::refresh_workspace_configurations(&this, cx).await;
8054 }
8055
8056 drop(settings_observation);
8057 anyhow::Ok(())
8058 })
8059 }
8060
8061 pub fn running_language_servers_for_local_buffer<'a>(
8062 &'a self,
8063 buffer: &Buffer,
8064 cx: &mut App,
8065 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8066 let local = self.as_local();
8067 let language_server_ids = local
8068 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8069 .unwrap_or_default();
8070
8071 language_server_ids
8072 .into_iter()
8073 .filter_map(
8074 move |server_id| match local?.language_servers.get(&server_id)? {
8075 LanguageServerState::Running {
8076 adapter, server, ..
8077 } => Some((adapter, server)),
8078 _ => None,
8079 },
8080 )
8081 }
8082
8083 pub fn language_servers_for_local_buffer(
8084 &self,
8085 buffer: &Buffer,
8086 cx: &mut App,
8087 ) -> Vec<LanguageServerId> {
8088 let local = self.as_local();
8089 local
8090 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8091 .unwrap_or_default()
8092 }
8093
8094 pub fn language_server_for_local_buffer<'a>(
8095 &'a self,
8096 buffer: &'a Buffer,
8097 server_id: LanguageServerId,
8098 cx: &'a mut App,
8099 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8100 self.as_local()?
8101 .language_servers_for_buffer(buffer, cx)
8102 .find(|(_, s)| s.server_id() == server_id)
8103 }
8104
8105 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8106 self.diagnostic_summaries.remove(&id_to_remove);
8107 if let Some(local) = self.as_local_mut() {
8108 let to_remove = local.remove_worktree(id_to_remove, cx);
8109 for server in to_remove {
8110 self.language_server_statuses.remove(&server);
8111 }
8112 }
8113 }
8114
8115 pub fn shared(
8116 &mut self,
8117 project_id: u64,
8118 downstream_client: AnyProtoClient,
8119 _: &mut Context<Self>,
8120 ) {
8121 self.downstream_client = Some((downstream_client.clone(), project_id));
8122
8123 for (server_id, status) in &self.language_server_statuses {
8124 if let Some(server) = self.language_server_for_id(*server_id) {
8125 downstream_client
8126 .send(proto::StartLanguageServer {
8127 project_id,
8128 server: Some(proto::LanguageServer {
8129 id: server_id.to_proto(),
8130 name: status.name.to_string(),
8131 worktree_id: status.worktree.map(|id| id.to_proto()),
8132 }),
8133 capabilities: serde_json::to_string(&server.capabilities())
8134 .expect("serializing server LSP capabilities"),
8135 })
8136 .log_err();
8137 }
8138 }
8139 }
8140
8141 pub fn disconnected_from_host(&mut self) {
8142 self.downstream_client.take();
8143 }
8144
8145 pub fn disconnected_from_ssh_remote(&mut self) {
8146 if let LspStoreMode::Remote(RemoteLspStore {
8147 upstream_client, ..
8148 }) = &mut self.mode
8149 {
8150 upstream_client.take();
8151 }
8152 }
8153
8154 pub(crate) fn set_language_server_statuses_from_proto(
8155 &mut self,
8156 project: WeakEntity<Project>,
8157 language_servers: Vec<proto::LanguageServer>,
8158 server_capabilities: Vec<String>,
8159 cx: &mut Context<Self>,
8160 ) {
8161 let lsp_logs = cx
8162 .try_global::<GlobalLogStore>()
8163 .map(|lsp_store| lsp_store.0.clone());
8164
8165 self.language_server_statuses = language_servers
8166 .into_iter()
8167 .zip(server_capabilities)
8168 .map(|(server, server_capabilities)| {
8169 let server_id = LanguageServerId(server.id as usize);
8170 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8171 self.lsp_server_capabilities
8172 .insert(server_id, server_capabilities);
8173 }
8174
8175 let name = LanguageServerName::from_proto(server.name);
8176 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8177
8178 if let Some(lsp_logs) = &lsp_logs {
8179 lsp_logs.update(cx, |lsp_logs, cx| {
8180 lsp_logs.add_language_server(
8181 // Only remote clients get their language servers set from proto
8182 LanguageServerKind::Remote {
8183 project: project.clone(),
8184 },
8185 server_id,
8186 Some(name.clone()),
8187 worktree,
8188 None,
8189 cx,
8190 );
8191 });
8192 }
8193
8194 (
8195 server_id,
8196 LanguageServerStatus {
8197 name,
8198 server_version: None,
8199 pending_work: Default::default(),
8200 has_pending_diagnostic_updates: false,
8201 progress_tokens: Default::default(),
8202 worktree,
8203 binary: None,
8204 configuration: None,
8205 workspace_folders: BTreeSet::new(),
8206 process_id: None,
8207 },
8208 )
8209 })
8210 .collect();
8211 }
8212
8213 #[cfg(feature = "test-support")]
8214 pub fn update_diagnostic_entries(
8215 &mut self,
8216 server_id: LanguageServerId,
8217 abs_path: PathBuf,
8218 result_id: Option<SharedString>,
8219 version: Option<i32>,
8220 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8221 cx: &mut Context<Self>,
8222 ) -> anyhow::Result<()> {
8223 self.merge_diagnostic_entries(
8224 vec![DocumentDiagnosticsUpdate {
8225 diagnostics: DocumentDiagnostics {
8226 diagnostics,
8227 document_abs_path: abs_path,
8228 version,
8229 },
8230 result_id,
8231 server_id,
8232 disk_based_sources: Cow::Borrowed(&[]),
8233 registration_id: None,
8234 }],
8235 |_, _, _| false,
8236 cx,
8237 )?;
8238 Ok(())
8239 }
8240
8241 pub fn merge_diagnostic_entries<'a>(
8242 &mut self,
8243 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8244 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8245 cx: &mut Context<Self>,
8246 ) -> anyhow::Result<()> {
8247 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8248 let mut updated_diagnostics_paths = HashMap::default();
8249 for mut update in diagnostic_updates {
8250 let abs_path = &update.diagnostics.document_abs_path;
8251 let server_id = update.server_id;
8252 let Some((worktree, relative_path)) =
8253 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8254 else {
8255 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8256 return Ok(());
8257 };
8258
8259 let worktree_id = worktree.read(cx).id();
8260 let project_path = ProjectPath {
8261 worktree_id,
8262 path: relative_path,
8263 };
8264
8265 let document_uri = lsp::Uri::from_file_path(abs_path)
8266 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8267 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8268 let snapshot = buffer_handle.read(cx).snapshot();
8269 let buffer = buffer_handle.read(cx);
8270 let reused_diagnostics = buffer
8271 .buffer_diagnostics(Some(server_id))
8272 .iter()
8273 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8274 .map(|v| {
8275 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8276 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8277 DiagnosticEntry {
8278 range: start..end,
8279 diagnostic: v.diagnostic.clone(),
8280 }
8281 })
8282 .collect::<Vec<_>>();
8283
8284 self.as_local_mut()
8285 .context("cannot merge diagnostics on a remote LspStore")?
8286 .update_buffer_diagnostics(
8287 &buffer_handle,
8288 server_id,
8289 Some(update.registration_id),
8290 update.result_id,
8291 update.diagnostics.version,
8292 update.diagnostics.diagnostics.clone(),
8293 reused_diagnostics.clone(),
8294 cx,
8295 )?;
8296
8297 update.diagnostics.diagnostics.extend(reused_diagnostics);
8298 } else if let Some(local) = self.as_local() {
8299 let reused_diagnostics = local
8300 .diagnostics
8301 .get(&worktree_id)
8302 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8303 .and_then(|diagnostics_by_server_id| {
8304 diagnostics_by_server_id
8305 .binary_search_by_key(&server_id, |e| e.0)
8306 .ok()
8307 .map(|ix| &diagnostics_by_server_id[ix].1)
8308 })
8309 .into_iter()
8310 .flatten()
8311 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8312
8313 update
8314 .diagnostics
8315 .diagnostics
8316 .extend(reused_diagnostics.cloned());
8317 }
8318
8319 let updated = worktree.update(cx, |worktree, cx| {
8320 self.update_worktree_diagnostics(
8321 worktree.id(),
8322 server_id,
8323 project_path.path.clone(),
8324 update.diagnostics.diagnostics,
8325 cx,
8326 )
8327 })?;
8328 match updated {
8329 ControlFlow::Continue(new_summary) => {
8330 if let Some((project_id, new_summary)) = new_summary {
8331 match &mut diagnostics_summary {
8332 Some(diagnostics_summary) => {
8333 diagnostics_summary
8334 .more_summaries
8335 .push(proto::DiagnosticSummary {
8336 path: project_path.path.as_ref().to_proto(),
8337 language_server_id: server_id.0 as u64,
8338 error_count: new_summary.error_count,
8339 warning_count: new_summary.warning_count,
8340 })
8341 }
8342 None => {
8343 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8344 project_id,
8345 worktree_id: worktree_id.to_proto(),
8346 summary: Some(proto::DiagnosticSummary {
8347 path: project_path.path.as_ref().to_proto(),
8348 language_server_id: server_id.0 as u64,
8349 error_count: new_summary.error_count,
8350 warning_count: new_summary.warning_count,
8351 }),
8352 more_summaries: Vec::new(),
8353 })
8354 }
8355 }
8356 }
8357 updated_diagnostics_paths
8358 .entry(server_id)
8359 .or_insert_with(Vec::new)
8360 .push(project_path);
8361 }
8362 ControlFlow::Break(()) => {}
8363 }
8364 }
8365
8366 if let Some((diagnostics_summary, (downstream_client, _))) =
8367 diagnostics_summary.zip(self.downstream_client.as_ref())
8368 {
8369 downstream_client.send(diagnostics_summary).log_err();
8370 }
8371 for (server_id, paths) in updated_diagnostics_paths {
8372 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8373 }
8374 Ok(())
8375 }
8376
8377 fn update_worktree_diagnostics(
8378 &mut self,
8379 worktree_id: WorktreeId,
8380 server_id: LanguageServerId,
8381 path_in_worktree: Arc<RelPath>,
8382 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8383 _: &mut Context<Worktree>,
8384 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8385 let local = match &mut self.mode {
8386 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8387 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8388 };
8389
8390 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8391 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8392 let summaries_by_server_id = summaries_for_tree
8393 .entry(path_in_worktree.clone())
8394 .or_default();
8395
8396 let old_summary = summaries_by_server_id
8397 .remove(&server_id)
8398 .unwrap_or_default();
8399
8400 let new_summary = DiagnosticSummary::new(&diagnostics);
8401 if diagnostics.is_empty() {
8402 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8403 {
8404 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8405 diagnostics_by_server_id.remove(ix);
8406 }
8407 if diagnostics_by_server_id.is_empty() {
8408 diagnostics_for_tree.remove(&path_in_worktree);
8409 }
8410 }
8411 } else {
8412 summaries_by_server_id.insert(server_id, new_summary);
8413 let diagnostics_by_server_id = diagnostics_for_tree
8414 .entry(path_in_worktree.clone())
8415 .or_default();
8416 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8417 Ok(ix) => {
8418 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8419 }
8420 Err(ix) => {
8421 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8422 }
8423 }
8424 }
8425
8426 if !old_summary.is_empty() || !new_summary.is_empty() {
8427 if let Some((_, project_id)) = &self.downstream_client {
8428 Ok(ControlFlow::Continue(Some((
8429 *project_id,
8430 proto::DiagnosticSummary {
8431 path: path_in_worktree.to_proto(),
8432 language_server_id: server_id.0 as u64,
8433 error_count: new_summary.error_count as u32,
8434 warning_count: new_summary.warning_count as u32,
8435 },
8436 ))))
8437 } else {
8438 Ok(ControlFlow::Continue(None))
8439 }
8440 } else {
8441 Ok(ControlFlow::Break(()))
8442 }
8443 }
8444
8445 pub fn open_buffer_for_symbol(
8446 &mut self,
8447 symbol: &Symbol,
8448 cx: &mut Context<Self>,
8449 ) -> Task<Result<Entity<Buffer>>> {
8450 if let Some((client, project_id)) = self.upstream_client() {
8451 let request = client.request(proto::OpenBufferForSymbol {
8452 project_id,
8453 symbol: Some(Self::serialize_symbol(symbol)),
8454 });
8455 cx.spawn(async move |this, cx| {
8456 let response = request.await?;
8457 let buffer_id = BufferId::new(response.buffer_id)?;
8458 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8459 .await
8460 })
8461 } else if let Some(local) = self.as_local() {
8462 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8463 seed.worktree_id == symbol.source_worktree_id
8464 && state.id == symbol.source_language_server_id
8465 && symbol.language_server_name == seed.name
8466 });
8467 if !is_valid {
8468 return Task::ready(Err(anyhow!(
8469 "language server for worktree and language not found"
8470 )));
8471 };
8472
8473 let symbol_abs_path = match &symbol.path {
8474 SymbolLocation::InProject(project_path) => self
8475 .worktree_store
8476 .read(cx)
8477 .absolutize(&project_path, cx)
8478 .context("no such worktree"),
8479 SymbolLocation::OutsideProject {
8480 abs_path,
8481 signature: _,
8482 } => Ok(abs_path.to_path_buf()),
8483 };
8484 let symbol_abs_path = match symbol_abs_path {
8485 Ok(abs_path) => abs_path,
8486 Err(err) => return Task::ready(Err(err)),
8487 };
8488 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8489 uri
8490 } else {
8491 return Task::ready(Err(anyhow!("invalid symbol path")));
8492 };
8493
8494 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8495 } else {
8496 Task::ready(Err(anyhow!("no upstream client or local store")))
8497 }
8498 }
8499
8500 pub(crate) fn open_local_buffer_via_lsp(
8501 &mut self,
8502 abs_path: lsp::Uri,
8503 language_server_id: LanguageServerId,
8504 cx: &mut Context<Self>,
8505 ) -> Task<Result<Entity<Buffer>>> {
8506 let path_style = self.worktree_store.read(cx).path_style();
8507 cx.spawn(async move |lsp_store, cx| {
8508 // Escape percent-encoded string.
8509 let current_scheme = abs_path.scheme().to_owned();
8510 // Uri is immutable, so we can't modify the scheme
8511
8512 let abs_path = abs_path
8513 .to_file_path_ext(path_style)
8514 .map_err(|()| anyhow!("can't convert URI to path"))?;
8515 let p = abs_path.clone();
8516 let yarn_worktree = lsp_store
8517 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8518 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8519 cx.spawn(async move |this, cx| {
8520 let t = this
8521 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8522 .ok()?;
8523 t.await
8524 })
8525 }),
8526 None => Task::ready(None),
8527 })?
8528 .await;
8529 let (worktree_root_target, known_relative_path) =
8530 if let Some((zip_root, relative_path)) = yarn_worktree {
8531 (zip_root, Some(relative_path))
8532 } else {
8533 (Arc::<Path>::from(abs_path.as_path()), None)
8534 };
8535 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8536 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8537 worktree_store.find_worktree(&worktree_root_target, cx)
8538 })
8539 })?;
8540 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8541 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8542 (result.0, relative_path, None)
8543 } else {
8544 let worktree = lsp_store
8545 .update(cx, |lsp_store, cx| {
8546 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8547 worktree_store.create_worktree(&worktree_root_target, false, cx)
8548 })
8549 })?
8550 .await?;
8551 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8552 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8553 lsp_store
8554 .update(cx, |lsp_store, cx| {
8555 if let Some(local) = lsp_store.as_local_mut() {
8556 local.register_language_server_for_invisible_worktree(
8557 &worktree,
8558 language_server_id,
8559 cx,
8560 )
8561 }
8562 match lsp_store.language_server_statuses.get(&language_server_id) {
8563 Some(status) => status.worktree,
8564 None => None,
8565 }
8566 })
8567 .ok()
8568 .flatten()
8569 .zip(Some(worktree_root.clone()))
8570 } else {
8571 None
8572 };
8573 let relative_path = if let Some(known_path) = known_relative_path {
8574 known_path
8575 } else {
8576 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8577 .into_arc()
8578 };
8579 (worktree, relative_path, source_ws)
8580 };
8581 let project_path = ProjectPath {
8582 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8583 path: relative_path,
8584 };
8585 let buffer = lsp_store
8586 .update(cx, |lsp_store, cx| {
8587 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8588 buffer_store.open_buffer(project_path, cx)
8589 })
8590 })?
8591 .await?;
8592 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8593 if let Some((source_ws, worktree_root)) = source_ws {
8594 buffer.update(cx, |buffer, cx| {
8595 let settings = WorktreeSettings::get(
8596 Some(
8597 (&ProjectPath {
8598 worktree_id: source_ws,
8599 path: Arc::from(RelPath::empty()),
8600 })
8601 .into(),
8602 ),
8603 cx,
8604 );
8605 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8606 if is_read_only {
8607 buffer.set_capability(Capability::ReadOnly, cx);
8608 }
8609 });
8610 }
8611 Ok(buffer)
8612 })
8613 }
8614
8615 fn local_lsp_servers_for_buffer(
8616 &self,
8617 buffer: &Entity<Buffer>,
8618 cx: &mut Context<Self>,
8619 ) -> Vec<LanguageServerId> {
8620 let Some(local) = self.as_local() else {
8621 return Vec::new();
8622 };
8623
8624 let snapshot = buffer.read(cx).snapshot();
8625
8626 buffer.update(cx, |buffer, cx| {
8627 local
8628 .language_servers_for_buffer(buffer, cx)
8629 .map(|(_, server)| server.server_id())
8630 .filter(|server_id| {
8631 self.as_local().is_none_or(|local| {
8632 local
8633 .buffers_opened_in_servers
8634 .get(&snapshot.remote_id())
8635 .is_some_and(|servers| servers.contains(server_id))
8636 })
8637 })
8638 .collect()
8639 })
8640 }
8641
8642 fn request_multiple_lsp_locally<P, R>(
8643 &mut self,
8644 buffer: &Entity<Buffer>,
8645 position: Option<P>,
8646 request: R,
8647 cx: &mut Context<Self>,
8648 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8649 where
8650 P: ToOffset,
8651 R: LspCommand + Clone,
8652 <R::LspRequest as lsp::request::Request>::Result: Send,
8653 <R::LspRequest as lsp::request::Request>::Params: Send,
8654 {
8655 let Some(local) = self.as_local() else {
8656 return Task::ready(Vec::new());
8657 };
8658
8659 let snapshot = buffer.read(cx).snapshot();
8660 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8661
8662 let server_ids = buffer.update(cx, |buffer, cx| {
8663 local
8664 .language_servers_for_buffer(buffer, cx)
8665 .filter(|(adapter, _)| {
8666 scope
8667 .as_ref()
8668 .map(|scope| scope.language_allowed(&adapter.name))
8669 .unwrap_or(true)
8670 })
8671 .map(|(_, server)| server.server_id())
8672 .filter(|server_id| {
8673 self.as_local().is_none_or(|local| {
8674 local
8675 .buffers_opened_in_servers
8676 .get(&snapshot.remote_id())
8677 .is_some_and(|servers| servers.contains(server_id))
8678 })
8679 })
8680 .collect::<Vec<_>>()
8681 });
8682
8683 let mut response_results = server_ids
8684 .into_iter()
8685 .map(|server_id| {
8686 let task = self.request_lsp(
8687 buffer.clone(),
8688 LanguageServerToQuery::Other(server_id),
8689 request.clone(),
8690 cx,
8691 );
8692 async move { (server_id, task.await) }
8693 })
8694 .collect::<FuturesUnordered<_>>();
8695
8696 cx.background_spawn(async move {
8697 let mut responses = Vec::with_capacity(response_results.len());
8698 while let Some((server_id, response_result)) = response_results.next().await {
8699 match response_result {
8700 Ok(response) => responses.push((server_id, response)),
8701 // rust-analyzer likes to error with this when its still loading up
8702 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8703 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8704 }
8705 }
8706 responses
8707 })
8708 }
8709
8710 async fn handle_lsp_get_completions(
8711 this: Entity<Self>,
8712 envelope: TypedEnvelope<proto::GetCompletions>,
8713 mut cx: AsyncApp,
8714 ) -> Result<proto::GetCompletionsResponse> {
8715 let sender_id = envelope.original_sender_id().unwrap_or_default();
8716
8717 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8718 let buffer_handle = this.update(&mut cx, |this, cx| {
8719 this.buffer_store.read(cx).get_existing(buffer_id)
8720 })?;
8721 let request = GetCompletions::from_proto(
8722 envelope.payload,
8723 this.clone(),
8724 buffer_handle.clone(),
8725 cx.clone(),
8726 )
8727 .await?;
8728
8729 let server_to_query = match request.server_id {
8730 Some(server_id) => LanguageServerToQuery::Other(server_id),
8731 None => LanguageServerToQuery::FirstCapable,
8732 };
8733
8734 let response = this
8735 .update(&mut cx, |this, cx| {
8736 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8737 })
8738 .await?;
8739 this.update(&mut cx, |this, cx| {
8740 Ok(GetCompletions::response_to_proto(
8741 response,
8742 this,
8743 sender_id,
8744 &buffer_handle.read(cx).version(),
8745 cx,
8746 ))
8747 })
8748 }
8749
8750 async fn handle_lsp_command<T: LspCommand>(
8751 this: Entity<Self>,
8752 envelope: TypedEnvelope<T::ProtoRequest>,
8753 mut cx: AsyncApp,
8754 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8755 where
8756 <T::LspRequest as lsp::request::Request>::Params: Send,
8757 <T::LspRequest as lsp::request::Request>::Result: Send,
8758 {
8759 let sender_id = envelope.original_sender_id().unwrap_or_default();
8760 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8761 let buffer_handle = this.update(&mut cx, |this, cx| {
8762 this.buffer_store.read(cx).get_existing(buffer_id)
8763 })?;
8764 let request = T::from_proto(
8765 envelope.payload,
8766 this.clone(),
8767 buffer_handle.clone(),
8768 cx.clone(),
8769 )
8770 .await?;
8771 let response = this
8772 .update(&mut cx, |this, cx| {
8773 this.request_lsp(
8774 buffer_handle.clone(),
8775 LanguageServerToQuery::FirstCapable,
8776 request,
8777 cx,
8778 )
8779 })
8780 .await?;
8781 this.update(&mut cx, |this, cx| {
8782 Ok(T::response_to_proto(
8783 response,
8784 this,
8785 sender_id,
8786 &buffer_handle.read(cx).version(),
8787 cx,
8788 ))
8789 })
8790 }
8791
8792 async fn handle_lsp_query(
8793 lsp_store: Entity<Self>,
8794 envelope: TypedEnvelope<proto::LspQuery>,
8795 mut cx: AsyncApp,
8796 ) -> Result<proto::Ack> {
8797 use proto::lsp_query::Request;
8798 let sender_id = envelope.original_sender_id().unwrap_or_default();
8799 let lsp_query = envelope.payload;
8800 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8801 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8802 match lsp_query.request.context("invalid LSP query request")? {
8803 Request::GetReferences(get_references) => {
8804 let position = get_references.position.clone().and_then(deserialize_anchor);
8805 Self::query_lsp_locally::<GetReferences>(
8806 lsp_store,
8807 server_id,
8808 sender_id,
8809 lsp_request_id,
8810 get_references,
8811 position,
8812 &mut cx,
8813 )
8814 .await?;
8815 }
8816 Request::GetDocumentColor(get_document_color) => {
8817 Self::query_lsp_locally::<GetDocumentColor>(
8818 lsp_store,
8819 server_id,
8820 sender_id,
8821 lsp_request_id,
8822 get_document_color,
8823 None,
8824 &mut cx,
8825 )
8826 .await?;
8827 }
8828 Request::GetFoldingRanges(get_folding_ranges) => {
8829 Self::query_lsp_locally::<GetFoldingRanges>(
8830 lsp_store,
8831 server_id,
8832 sender_id,
8833 lsp_request_id,
8834 get_folding_ranges,
8835 None,
8836 &mut cx,
8837 )
8838 .await?;
8839 }
8840 Request::GetDocumentSymbols(get_document_symbols) => {
8841 Self::query_lsp_locally::<GetDocumentSymbols>(
8842 lsp_store,
8843 server_id,
8844 sender_id,
8845 lsp_request_id,
8846 get_document_symbols,
8847 None,
8848 &mut cx,
8849 )
8850 .await?;
8851 }
8852 Request::GetHover(get_hover) => {
8853 let position = get_hover.position.clone().and_then(deserialize_anchor);
8854 Self::query_lsp_locally::<GetHover>(
8855 lsp_store,
8856 server_id,
8857 sender_id,
8858 lsp_request_id,
8859 get_hover,
8860 position,
8861 &mut cx,
8862 )
8863 .await?;
8864 }
8865 Request::GetCodeActions(get_code_actions) => {
8866 Self::query_lsp_locally::<GetCodeActions>(
8867 lsp_store,
8868 server_id,
8869 sender_id,
8870 lsp_request_id,
8871 get_code_actions,
8872 None,
8873 &mut cx,
8874 )
8875 .await?;
8876 }
8877 Request::GetSignatureHelp(get_signature_help) => {
8878 let position = get_signature_help
8879 .position
8880 .clone()
8881 .and_then(deserialize_anchor);
8882 Self::query_lsp_locally::<GetSignatureHelp>(
8883 lsp_store,
8884 server_id,
8885 sender_id,
8886 lsp_request_id,
8887 get_signature_help,
8888 position,
8889 &mut cx,
8890 )
8891 .await?;
8892 }
8893 Request::GetCodeLens(get_code_lens) => {
8894 Self::query_lsp_locally::<GetCodeLens>(
8895 lsp_store,
8896 server_id,
8897 sender_id,
8898 lsp_request_id,
8899 get_code_lens,
8900 None,
8901 &mut cx,
8902 )
8903 .await?;
8904 }
8905 Request::GetDefinition(get_definition) => {
8906 let position = get_definition.position.clone().and_then(deserialize_anchor);
8907 Self::query_lsp_locally::<GetDefinitions>(
8908 lsp_store,
8909 server_id,
8910 sender_id,
8911 lsp_request_id,
8912 get_definition,
8913 position,
8914 &mut cx,
8915 )
8916 .await?;
8917 }
8918 Request::GetDeclaration(get_declaration) => {
8919 let position = get_declaration
8920 .position
8921 .clone()
8922 .and_then(deserialize_anchor);
8923 Self::query_lsp_locally::<GetDeclarations>(
8924 lsp_store,
8925 server_id,
8926 sender_id,
8927 lsp_request_id,
8928 get_declaration,
8929 position,
8930 &mut cx,
8931 )
8932 .await?;
8933 }
8934 Request::GetTypeDefinition(get_type_definition) => {
8935 let position = get_type_definition
8936 .position
8937 .clone()
8938 .and_then(deserialize_anchor);
8939 Self::query_lsp_locally::<GetTypeDefinitions>(
8940 lsp_store,
8941 server_id,
8942 sender_id,
8943 lsp_request_id,
8944 get_type_definition,
8945 position,
8946 &mut cx,
8947 )
8948 .await?;
8949 }
8950 Request::GetImplementation(get_implementation) => {
8951 let position = get_implementation
8952 .position
8953 .clone()
8954 .and_then(deserialize_anchor);
8955 Self::query_lsp_locally::<GetImplementations>(
8956 lsp_store,
8957 server_id,
8958 sender_id,
8959 lsp_request_id,
8960 get_implementation,
8961 position,
8962 &mut cx,
8963 )
8964 .await?;
8965 }
8966 Request::InlayHints(inlay_hints) => {
8967 let query_start = inlay_hints
8968 .start
8969 .clone()
8970 .and_then(deserialize_anchor)
8971 .context("invalid inlay hints range start")?;
8972 let query_end = inlay_hints
8973 .end
8974 .clone()
8975 .and_then(deserialize_anchor)
8976 .context("invalid inlay hints range end")?;
8977 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8978 &lsp_store,
8979 server_id,
8980 lsp_request_id,
8981 &inlay_hints,
8982 query_start..query_end,
8983 &mut cx,
8984 )
8985 .await
8986 .context("preparing inlay hints request")?;
8987 Self::query_lsp_locally::<InlayHints>(
8988 lsp_store,
8989 server_id,
8990 sender_id,
8991 lsp_request_id,
8992 inlay_hints,
8993 None,
8994 &mut cx,
8995 )
8996 .await
8997 .context("querying for inlay hints")?
8998 }
8999 //////////////////////////////
9000 // Below are LSP queries that need to fetch more data,
9001 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9002 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9003 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9004 &lsp_store,
9005 &get_document_diagnostics,
9006 &mut cx,
9007 )
9008 .await?;
9009 lsp_store.update(&mut cx, |lsp_store, cx| {
9010 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9011 let key = LspKey {
9012 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9013 server_queried: server_id,
9014 };
9015 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9016 ) {
9017 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9018 lsp_requests.clear();
9019 };
9020 }
9021
9022 lsp_data.lsp_requests.entry(key).or_default().insert(
9023 lsp_request_id,
9024 cx.spawn(async move |lsp_store, cx| {
9025 let diagnostics_pull = lsp_store
9026 .update(cx, |lsp_store, cx| {
9027 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9028 })
9029 .ok();
9030 if let Some(diagnostics_pull) = diagnostics_pull {
9031 match diagnostics_pull.await {
9032 Ok(()) => {}
9033 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9034 };
9035 }
9036 }),
9037 );
9038 });
9039 }
9040 Request::SemanticTokens(semantic_tokens) => {
9041 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9042 &lsp_store,
9043 &semantic_tokens,
9044 &mut cx,
9045 )
9046 .await?;
9047 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9048 lsp_store.update(&mut cx, |lsp_store, cx| {
9049 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9050 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9051 let key = LspKey {
9052 request_type: TypeId::of::<SemanticTokensFull>(),
9053 server_queried: server_id,
9054 };
9055 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9056 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9057 lsp_requests.clear();
9058 };
9059 }
9060
9061 lsp_data.lsp_requests.entry(key).or_default().insert(
9062 lsp_request_id,
9063 cx.spawn(async move |lsp_store, cx| {
9064 let tokens_fetch = lsp_store
9065 .update(cx, |lsp_store, cx| {
9066 lsp_store
9067 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9068 })
9069 .ok();
9070 if let Some(tokens_fetch) = tokens_fetch {
9071 let new_tokens = tokens_fetch.await;
9072 if let Some(new_tokens) = new_tokens {
9073 lsp_store
9074 .update(cx, |lsp_store, cx| {
9075 let response = new_tokens
9076 .into_iter()
9077 .map(|(server_id, response)| {
9078 (
9079 server_id.to_proto(),
9080 SemanticTokensFull::response_to_proto(
9081 response,
9082 lsp_store,
9083 sender_id,
9084 &buffer_version,
9085 cx,
9086 ),
9087 )
9088 })
9089 .collect::<HashMap<_, _>>();
9090 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9091 project_id,
9092 lsp_request_id,
9093 response,
9094 ) {
9095 Ok(()) => {}
9096 Err(e) => {
9097 log::error!(
9098 "Failed to send semantic tokens LSP response: {e:#}",
9099 )
9100 }
9101 }
9102 })
9103 .ok();
9104 }
9105 }
9106 }),
9107 );
9108 }
9109 });
9110 }
9111 }
9112 Ok(proto::Ack {})
9113 }
9114
9115 async fn handle_lsp_query_response(
9116 lsp_store: Entity<Self>,
9117 envelope: TypedEnvelope<proto::LspQueryResponse>,
9118 cx: AsyncApp,
9119 ) -> Result<()> {
9120 lsp_store.read_with(&cx, |lsp_store, _| {
9121 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9122 upstream_client.handle_lsp_response(envelope.clone());
9123 }
9124 });
9125 Ok(())
9126 }
9127
9128 async fn handle_apply_code_action(
9129 this: Entity<Self>,
9130 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9131 mut cx: AsyncApp,
9132 ) -> Result<proto::ApplyCodeActionResponse> {
9133 let sender_id = envelope.original_sender_id().unwrap_or_default();
9134 let action =
9135 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9136 let apply_code_action = this.update(&mut cx, |this, cx| {
9137 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9138 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9139 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9140 })?;
9141
9142 let project_transaction = apply_code_action.await?;
9143 let project_transaction = this.update(&mut cx, |this, cx| {
9144 this.buffer_store.update(cx, |buffer_store, cx| {
9145 buffer_store.serialize_project_transaction_for_peer(
9146 project_transaction,
9147 sender_id,
9148 cx,
9149 )
9150 })
9151 });
9152 Ok(proto::ApplyCodeActionResponse {
9153 transaction: Some(project_transaction),
9154 })
9155 }
9156
9157 async fn handle_register_buffer_with_language_servers(
9158 this: Entity<Self>,
9159 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9160 mut cx: AsyncApp,
9161 ) -> Result<proto::Ack> {
9162 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9163 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9164 this.update(&mut cx, |this, cx| {
9165 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9166 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9167 project_id: upstream_project_id,
9168 buffer_id: buffer_id.to_proto(),
9169 only_servers: envelope.payload.only_servers,
9170 });
9171 }
9172
9173 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9174 anyhow::bail!("buffer is not open");
9175 };
9176
9177 let handle = this.register_buffer_with_language_servers(
9178 &buffer,
9179 envelope
9180 .payload
9181 .only_servers
9182 .into_iter()
9183 .filter_map(|selector| {
9184 Some(match selector.selector? {
9185 proto::language_server_selector::Selector::ServerId(server_id) => {
9186 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9187 }
9188 proto::language_server_selector::Selector::Name(name) => {
9189 LanguageServerSelector::Name(LanguageServerName(
9190 SharedString::from(name),
9191 ))
9192 }
9193 })
9194 })
9195 .collect(),
9196 false,
9197 cx,
9198 );
9199 // Pull diagnostics for the buffer even if it was already registered.
9200 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9201 // but it's unclear if we need it.
9202 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9203 .detach();
9204 this.buffer_store().update(cx, |buffer_store, _| {
9205 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9206 });
9207
9208 Ok(())
9209 })?;
9210 Ok(proto::Ack {})
9211 }
9212
9213 async fn handle_rename_project_entry(
9214 this: Entity<Self>,
9215 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9216 mut cx: AsyncApp,
9217 ) -> Result<proto::ProjectEntryResponse> {
9218 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9219 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9220 let new_path =
9221 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9222
9223 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9224 .update(&mut cx, |this, cx| {
9225 let (worktree, entry) = this
9226 .worktree_store
9227 .read(cx)
9228 .worktree_and_entry_for_id(entry_id, cx)?;
9229 let new_worktree = this
9230 .worktree_store
9231 .read(cx)
9232 .worktree_for_id(new_worktree_id, cx)?;
9233 Some((
9234 this.worktree_store.clone(),
9235 worktree,
9236 new_worktree,
9237 entry.clone(),
9238 ))
9239 })
9240 .context("worktree not found")?;
9241 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9242 (worktree.absolutize(&old_entry.path), worktree.id())
9243 });
9244 let new_abs_path =
9245 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9246
9247 let _transaction = Self::will_rename_entry(
9248 this.downgrade(),
9249 old_worktree_id,
9250 &old_abs_path,
9251 &new_abs_path,
9252 old_entry.is_dir(),
9253 cx.clone(),
9254 )
9255 .await;
9256 let response = WorktreeStore::handle_rename_project_entry(
9257 worktree_store,
9258 envelope.payload,
9259 cx.clone(),
9260 )
9261 .await;
9262 this.read_with(&cx, |this, _| {
9263 this.did_rename_entry(
9264 old_worktree_id,
9265 &old_abs_path,
9266 &new_abs_path,
9267 old_entry.is_dir(),
9268 );
9269 });
9270 response
9271 }
9272
9273 async fn handle_update_diagnostic_summary(
9274 this: Entity<Self>,
9275 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9276 mut cx: AsyncApp,
9277 ) -> Result<()> {
9278 this.update(&mut cx, |lsp_store, cx| {
9279 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9280 let mut updated_diagnostics_paths = HashMap::default();
9281 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9282 for message_summary in envelope
9283 .payload
9284 .summary
9285 .into_iter()
9286 .chain(envelope.payload.more_summaries)
9287 {
9288 let project_path = ProjectPath {
9289 worktree_id,
9290 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9291 };
9292 let path = project_path.path.clone();
9293 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9294 let summary = DiagnosticSummary {
9295 error_count: message_summary.error_count as usize,
9296 warning_count: message_summary.warning_count as usize,
9297 };
9298
9299 if summary.is_empty() {
9300 if let Some(worktree_summaries) =
9301 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9302 && let Some(summaries) = worktree_summaries.get_mut(&path)
9303 {
9304 summaries.remove(&server_id);
9305 if summaries.is_empty() {
9306 worktree_summaries.remove(&path);
9307 }
9308 }
9309 } else {
9310 lsp_store
9311 .diagnostic_summaries
9312 .entry(worktree_id)
9313 .or_default()
9314 .entry(path)
9315 .or_default()
9316 .insert(server_id, summary);
9317 }
9318
9319 if let Some((_, project_id)) = &lsp_store.downstream_client {
9320 match &mut diagnostics_summary {
9321 Some(diagnostics_summary) => {
9322 diagnostics_summary
9323 .more_summaries
9324 .push(proto::DiagnosticSummary {
9325 path: project_path.path.as_ref().to_proto(),
9326 language_server_id: server_id.0 as u64,
9327 error_count: summary.error_count as u32,
9328 warning_count: summary.warning_count as u32,
9329 })
9330 }
9331 None => {
9332 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9333 project_id: *project_id,
9334 worktree_id: worktree_id.to_proto(),
9335 summary: Some(proto::DiagnosticSummary {
9336 path: project_path.path.as_ref().to_proto(),
9337 language_server_id: server_id.0 as u64,
9338 error_count: summary.error_count as u32,
9339 warning_count: summary.warning_count as u32,
9340 }),
9341 more_summaries: Vec::new(),
9342 })
9343 }
9344 }
9345 }
9346 updated_diagnostics_paths
9347 .entry(server_id)
9348 .or_insert_with(Vec::new)
9349 .push(project_path);
9350 }
9351
9352 if let Some((diagnostics_summary, (downstream_client, _))) =
9353 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9354 {
9355 downstream_client.send(diagnostics_summary).log_err();
9356 }
9357 for (server_id, paths) in updated_diagnostics_paths {
9358 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9359 }
9360 Ok(())
9361 })
9362 }
9363
9364 async fn handle_start_language_server(
9365 lsp_store: Entity<Self>,
9366 envelope: TypedEnvelope<proto::StartLanguageServer>,
9367 mut cx: AsyncApp,
9368 ) -> Result<()> {
9369 let server = envelope.payload.server.context("invalid server")?;
9370 let server_capabilities =
9371 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9372 .with_context(|| {
9373 format!(
9374 "incorrect server capabilities {}",
9375 envelope.payload.capabilities
9376 )
9377 })?;
9378 lsp_store.update(&mut cx, |lsp_store, cx| {
9379 let server_id = LanguageServerId(server.id as usize);
9380 let server_name = LanguageServerName::from_proto(server.name.clone());
9381 lsp_store
9382 .lsp_server_capabilities
9383 .insert(server_id, server_capabilities);
9384 lsp_store.language_server_statuses.insert(
9385 server_id,
9386 LanguageServerStatus {
9387 name: server_name.clone(),
9388 server_version: None,
9389 pending_work: Default::default(),
9390 has_pending_diagnostic_updates: false,
9391 progress_tokens: Default::default(),
9392 worktree: server.worktree_id.map(WorktreeId::from_proto),
9393 binary: None,
9394 configuration: None,
9395 workspace_folders: BTreeSet::new(),
9396 process_id: None,
9397 },
9398 );
9399 cx.emit(LspStoreEvent::LanguageServerAdded(
9400 server_id,
9401 server_name,
9402 server.worktree_id.map(WorktreeId::from_proto),
9403 ));
9404 cx.notify();
9405 });
9406 Ok(())
9407 }
9408
9409 async fn handle_update_language_server(
9410 lsp_store: Entity<Self>,
9411 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9412 mut cx: AsyncApp,
9413 ) -> Result<()> {
9414 lsp_store.update(&mut cx, |lsp_store, cx| {
9415 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9416
9417 match envelope.payload.variant.context("invalid variant")? {
9418 proto::update_language_server::Variant::WorkStart(payload) => {
9419 lsp_store.on_lsp_work_start(
9420 language_server_id,
9421 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9422 .context("invalid progress token value")?,
9423 LanguageServerProgress {
9424 title: payload.title,
9425 is_disk_based_diagnostics_progress: false,
9426 is_cancellable: payload.is_cancellable.unwrap_or(false),
9427 message: payload.message,
9428 percentage: payload.percentage.map(|p| p as usize),
9429 last_update_at: cx.background_executor().now(),
9430 },
9431 cx,
9432 );
9433 }
9434 proto::update_language_server::Variant::WorkProgress(payload) => {
9435 lsp_store.on_lsp_work_progress(
9436 language_server_id,
9437 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9438 .context("invalid progress token value")?,
9439 LanguageServerProgress {
9440 title: None,
9441 is_disk_based_diagnostics_progress: false,
9442 is_cancellable: payload.is_cancellable.unwrap_or(false),
9443 message: payload.message,
9444 percentage: payload.percentage.map(|p| p as usize),
9445 last_update_at: cx.background_executor().now(),
9446 },
9447 cx,
9448 );
9449 }
9450
9451 proto::update_language_server::Variant::WorkEnd(payload) => {
9452 lsp_store.on_lsp_work_end(
9453 language_server_id,
9454 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9455 .context("invalid progress token value")?,
9456 cx,
9457 );
9458 }
9459
9460 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9461 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9462 }
9463
9464 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9465 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9466 }
9467
9468 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9469 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9470 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9471 cx.emit(LspStoreEvent::LanguageServerUpdate {
9472 language_server_id,
9473 name: envelope
9474 .payload
9475 .server_name
9476 .map(SharedString::new)
9477 .map(LanguageServerName),
9478 message: non_lsp,
9479 });
9480 }
9481 }
9482
9483 Ok(())
9484 })
9485 }
9486
9487 async fn handle_language_server_log(
9488 this: Entity<Self>,
9489 envelope: TypedEnvelope<proto::LanguageServerLog>,
9490 mut cx: AsyncApp,
9491 ) -> Result<()> {
9492 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9493 let log_type = envelope
9494 .payload
9495 .log_type
9496 .map(LanguageServerLogType::from_proto)
9497 .context("invalid language server log type")?;
9498
9499 let message = envelope.payload.message;
9500
9501 this.update(&mut cx, |_, cx| {
9502 cx.emit(LspStoreEvent::LanguageServerLog(
9503 language_server_id,
9504 log_type,
9505 message,
9506 ));
9507 });
9508 Ok(())
9509 }
9510
9511 async fn handle_lsp_ext_cancel_flycheck(
9512 lsp_store: Entity<Self>,
9513 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9514 cx: AsyncApp,
9515 ) -> Result<proto::Ack> {
9516 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9517 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9518 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9519 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9520 } else {
9521 None
9522 }
9523 });
9524 if let Some(task) = task {
9525 task.context("handling lsp ext cancel flycheck")?;
9526 }
9527
9528 Ok(proto::Ack {})
9529 }
9530
9531 async fn handle_lsp_ext_run_flycheck(
9532 lsp_store: Entity<Self>,
9533 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9534 mut cx: AsyncApp,
9535 ) -> Result<proto::Ack> {
9536 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9537 lsp_store.update(&mut cx, |lsp_store, cx| {
9538 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9539 let text_document = if envelope.payload.current_file_only {
9540 let buffer_id = envelope
9541 .payload
9542 .buffer_id
9543 .map(|id| BufferId::new(id))
9544 .transpose()?;
9545 buffer_id
9546 .and_then(|buffer_id| {
9547 lsp_store
9548 .buffer_store()
9549 .read(cx)
9550 .get(buffer_id)
9551 .and_then(|buffer| {
9552 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9553 })
9554 .map(|path| make_text_document_identifier(&path))
9555 })
9556 .transpose()?
9557 } else {
9558 None
9559 };
9560 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9561 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9562 )?;
9563 }
9564 anyhow::Ok(())
9565 })?;
9566
9567 Ok(proto::Ack {})
9568 }
9569
9570 async fn handle_lsp_ext_clear_flycheck(
9571 lsp_store: Entity<Self>,
9572 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9573 cx: AsyncApp,
9574 ) -> Result<proto::Ack> {
9575 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9576 lsp_store.read_with(&cx, |lsp_store, _| {
9577 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9578 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9579 } else {
9580 None
9581 }
9582 });
9583
9584 Ok(proto::Ack {})
9585 }
9586
9587 pub fn disk_based_diagnostics_started(
9588 &mut self,
9589 language_server_id: LanguageServerId,
9590 cx: &mut Context<Self>,
9591 ) {
9592 if let Some(language_server_status) =
9593 self.language_server_statuses.get_mut(&language_server_id)
9594 {
9595 language_server_status.has_pending_diagnostic_updates = true;
9596 }
9597
9598 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9599 cx.emit(LspStoreEvent::LanguageServerUpdate {
9600 language_server_id,
9601 name: self
9602 .language_server_adapter_for_id(language_server_id)
9603 .map(|adapter| adapter.name()),
9604 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9605 Default::default(),
9606 ),
9607 })
9608 }
9609
9610 pub fn disk_based_diagnostics_finished(
9611 &mut self,
9612 language_server_id: LanguageServerId,
9613 cx: &mut Context<Self>,
9614 ) {
9615 if let Some(language_server_status) =
9616 self.language_server_statuses.get_mut(&language_server_id)
9617 {
9618 language_server_status.has_pending_diagnostic_updates = false;
9619 }
9620
9621 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9622 cx.emit(LspStoreEvent::LanguageServerUpdate {
9623 language_server_id,
9624 name: self
9625 .language_server_adapter_for_id(language_server_id)
9626 .map(|adapter| adapter.name()),
9627 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9628 Default::default(),
9629 ),
9630 })
9631 }
9632
9633 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9634 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9635 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9636 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9637 // the language server might take some time to publish diagnostics.
9638 fn simulate_disk_based_diagnostics_events_if_needed(
9639 &mut self,
9640 language_server_id: LanguageServerId,
9641 cx: &mut Context<Self>,
9642 ) {
9643 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9644
9645 let Some(LanguageServerState::Running {
9646 simulate_disk_based_diagnostics_completion,
9647 adapter,
9648 ..
9649 }) = self
9650 .as_local_mut()
9651 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9652 else {
9653 return;
9654 };
9655
9656 if adapter.disk_based_diagnostics_progress_token.is_some() {
9657 return;
9658 }
9659
9660 let prev_task =
9661 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9662 cx.background_executor()
9663 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9664 .await;
9665
9666 this.update(cx, |this, cx| {
9667 this.disk_based_diagnostics_finished(language_server_id, cx);
9668
9669 if let Some(LanguageServerState::Running {
9670 simulate_disk_based_diagnostics_completion,
9671 ..
9672 }) = this.as_local_mut().and_then(|local_store| {
9673 local_store.language_servers.get_mut(&language_server_id)
9674 }) {
9675 *simulate_disk_based_diagnostics_completion = None;
9676 }
9677 })
9678 .ok();
9679 }));
9680
9681 if prev_task.is_none() {
9682 self.disk_based_diagnostics_started(language_server_id, cx);
9683 }
9684 }
9685
9686 pub fn language_server_statuses(
9687 &self,
9688 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9689 self.language_server_statuses
9690 .iter()
9691 .map(|(key, value)| (*key, value))
9692 }
9693
9694 pub(super) fn did_rename_entry(
9695 &self,
9696 worktree_id: WorktreeId,
9697 old_path: &Path,
9698 new_path: &Path,
9699 is_dir: bool,
9700 ) {
9701 maybe!({
9702 let local_store = self.as_local()?;
9703
9704 let old_uri = lsp::Uri::from_file_path(old_path)
9705 .ok()
9706 .map(|uri| uri.to_string())?;
9707 let new_uri = lsp::Uri::from_file_path(new_path)
9708 .ok()
9709 .map(|uri| uri.to_string())?;
9710
9711 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9712 let Some(filter) = local_store
9713 .language_server_paths_watched_for_rename
9714 .get(&language_server.server_id())
9715 else {
9716 continue;
9717 };
9718
9719 if filter.should_send_did_rename(&old_uri, is_dir) {
9720 language_server
9721 .notify::<DidRenameFiles>(RenameFilesParams {
9722 files: vec![FileRename {
9723 old_uri: old_uri.clone(),
9724 new_uri: new_uri.clone(),
9725 }],
9726 })
9727 .ok();
9728 }
9729 }
9730 Some(())
9731 });
9732 }
9733
9734 pub(super) fn will_rename_entry(
9735 this: WeakEntity<Self>,
9736 worktree_id: WorktreeId,
9737 old_path: &Path,
9738 new_path: &Path,
9739 is_dir: bool,
9740 cx: AsyncApp,
9741 ) -> Task<ProjectTransaction> {
9742 let old_uri = lsp::Uri::from_file_path(old_path)
9743 .ok()
9744 .map(|uri| uri.to_string());
9745 let new_uri = lsp::Uri::from_file_path(new_path)
9746 .ok()
9747 .map(|uri| uri.to_string());
9748 cx.spawn(async move |cx| {
9749 let mut tasks = vec![];
9750 this.update(cx, |this, cx| {
9751 let local_store = this.as_local()?;
9752 let old_uri = old_uri?;
9753 let new_uri = new_uri?;
9754 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9755 let Some(filter) = local_store
9756 .language_server_paths_watched_for_rename
9757 .get(&language_server.server_id())
9758 else {
9759 continue;
9760 };
9761
9762 if !filter.should_send_will_rename(&old_uri, is_dir) {
9763 continue;
9764 }
9765 let request_timeout = ProjectSettings::get_global(cx)
9766 .global_lsp_settings
9767 .get_request_timeout();
9768
9769 let apply_edit = cx.spawn({
9770 let old_uri = old_uri.clone();
9771 let new_uri = new_uri.clone();
9772 let language_server = language_server.clone();
9773 async move |this, cx| {
9774 let edit = language_server
9775 .request::<WillRenameFiles>(
9776 RenameFilesParams {
9777 files: vec![FileRename { old_uri, new_uri }],
9778 },
9779 request_timeout,
9780 )
9781 .await
9782 .into_response()
9783 .context("will rename files")
9784 .log_err()
9785 .flatten()?;
9786
9787 LocalLspStore::deserialize_workspace_edit(
9788 this.upgrade()?,
9789 edit,
9790 false,
9791 language_server.clone(),
9792 cx,
9793 )
9794 .await
9795 .ok()
9796 }
9797 });
9798 tasks.push(apply_edit);
9799 }
9800 Some(())
9801 })
9802 .ok()
9803 .flatten();
9804 let mut merged_transaction = ProjectTransaction::default();
9805 for task in tasks {
9806 // Await on tasks sequentially so that the order of application of edits is deterministic
9807 // (at least with regards to the order of registration of language servers)
9808 if let Some(transaction) = task.await {
9809 for (buffer, buffer_transaction) in transaction.0 {
9810 merged_transaction.0.insert(buffer, buffer_transaction);
9811 }
9812 }
9813 }
9814 merged_transaction
9815 })
9816 }
9817
9818 fn lsp_notify_abs_paths_changed(
9819 &mut self,
9820 server_id: LanguageServerId,
9821 changes: Vec<PathEvent>,
9822 ) {
9823 maybe!({
9824 let server = self.language_server_for_id(server_id)?;
9825 let changes = changes
9826 .into_iter()
9827 .filter_map(|event| {
9828 let typ = match event.kind? {
9829 PathEventKind::Created => lsp::FileChangeType::CREATED,
9830 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9831 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9832 };
9833 Some(lsp::FileEvent {
9834 uri: file_path_to_lsp_url(&event.path).log_err()?,
9835 typ,
9836 })
9837 })
9838 .collect::<Vec<_>>();
9839 if !changes.is_empty() {
9840 server
9841 .notify::<lsp::notification::DidChangeWatchedFiles>(
9842 lsp::DidChangeWatchedFilesParams { changes },
9843 )
9844 .ok();
9845 }
9846 Some(())
9847 });
9848 }
9849
9850 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9851 self.as_local()?.language_server_for_id(id)
9852 }
9853
9854 fn on_lsp_progress(
9855 &mut self,
9856 progress_params: lsp::ProgressParams,
9857 language_server_id: LanguageServerId,
9858 disk_based_diagnostics_progress_token: Option<String>,
9859 cx: &mut Context<Self>,
9860 ) {
9861 match progress_params.value {
9862 lsp::ProgressParamsValue::WorkDone(progress) => {
9863 self.handle_work_done_progress(
9864 progress,
9865 language_server_id,
9866 disk_based_diagnostics_progress_token,
9867 ProgressToken::from_lsp(progress_params.token),
9868 cx,
9869 );
9870 }
9871 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9872 let registration_id = match progress_params.token {
9873 lsp::NumberOrString::Number(_) => None,
9874 lsp::NumberOrString::String(token) => token
9875 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9876 .map(|(_, id)| id.to_owned()),
9877 };
9878 if let Some(LanguageServerState::Running {
9879 workspace_diagnostics_refresh_tasks,
9880 ..
9881 }) = self
9882 .as_local_mut()
9883 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9884 && let Some(workspace_diagnostics) =
9885 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9886 {
9887 workspace_diagnostics.progress_tx.try_send(()).ok();
9888 self.apply_workspace_diagnostic_report(
9889 language_server_id,
9890 report,
9891 registration_id.map(SharedString::from),
9892 cx,
9893 )
9894 }
9895 }
9896 }
9897 }
9898
9899 fn handle_work_done_progress(
9900 &mut self,
9901 progress: lsp::WorkDoneProgress,
9902 language_server_id: LanguageServerId,
9903 disk_based_diagnostics_progress_token: Option<String>,
9904 token: ProgressToken,
9905 cx: &mut Context<Self>,
9906 ) {
9907 let language_server_status =
9908 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9909 status
9910 } else {
9911 return;
9912 };
9913
9914 if !language_server_status.progress_tokens.contains(&token) {
9915 return;
9916 }
9917
9918 let is_disk_based_diagnostics_progress =
9919 if let (Some(disk_based_token), ProgressToken::String(token)) =
9920 (&disk_based_diagnostics_progress_token, &token)
9921 {
9922 token.starts_with(disk_based_token)
9923 } else {
9924 false
9925 };
9926
9927 match progress {
9928 lsp::WorkDoneProgress::Begin(report) => {
9929 if is_disk_based_diagnostics_progress {
9930 self.disk_based_diagnostics_started(language_server_id, cx);
9931 }
9932 self.on_lsp_work_start(
9933 language_server_id,
9934 token.clone(),
9935 LanguageServerProgress {
9936 title: Some(report.title),
9937 is_disk_based_diagnostics_progress,
9938 is_cancellable: report.cancellable.unwrap_or(false),
9939 message: report.message.clone(),
9940 percentage: report.percentage.map(|p| p as usize),
9941 last_update_at: cx.background_executor().now(),
9942 },
9943 cx,
9944 );
9945 }
9946 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9947 language_server_id,
9948 token,
9949 LanguageServerProgress {
9950 title: None,
9951 is_disk_based_diagnostics_progress,
9952 is_cancellable: report.cancellable.unwrap_or(false),
9953 message: report.message,
9954 percentage: report.percentage.map(|p| p as usize),
9955 last_update_at: cx.background_executor().now(),
9956 },
9957 cx,
9958 ),
9959 lsp::WorkDoneProgress::End(_) => {
9960 language_server_status.progress_tokens.remove(&token);
9961 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9962 if is_disk_based_diagnostics_progress {
9963 self.disk_based_diagnostics_finished(language_server_id, cx);
9964 }
9965 }
9966 }
9967 }
9968
9969 fn on_lsp_work_start(
9970 &mut self,
9971 language_server_id: LanguageServerId,
9972 token: ProgressToken,
9973 progress: LanguageServerProgress,
9974 cx: &mut Context<Self>,
9975 ) {
9976 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9977 status.pending_work.insert(token.clone(), progress.clone());
9978 cx.notify();
9979 }
9980 cx.emit(LspStoreEvent::LanguageServerUpdate {
9981 language_server_id,
9982 name: self
9983 .language_server_adapter_for_id(language_server_id)
9984 .map(|adapter| adapter.name()),
9985 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9986 token: Some(token.to_proto()),
9987 title: progress.title,
9988 message: progress.message,
9989 percentage: progress.percentage.map(|p| p as u32),
9990 is_cancellable: Some(progress.is_cancellable),
9991 }),
9992 })
9993 }
9994
9995 fn on_lsp_work_progress(
9996 &mut self,
9997 language_server_id: LanguageServerId,
9998 token: ProgressToken,
9999 progress: LanguageServerProgress,
10000 cx: &mut Context<Self>,
10001 ) {
10002 let mut did_update = false;
10003 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10004 match status.pending_work.entry(token.clone()) {
10005 btree_map::Entry::Vacant(entry) => {
10006 entry.insert(progress.clone());
10007 did_update = true;
10008 }
10009 btree_map::Entry::Occupied(mut entry) => {
10010 let entry = entry.get_mut();
10011 if (progress.last_update_at - entry.last_update_at)
10012 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10013 {
10014 entry.last_update_at = progress.last_update_at;
10015 if progress.message.is_some() {
10016 entry.message = progress.message.clone();
10017 }
10018 if progress.percentage.is_some() {
10019 entry.percentage = progress.percentage;
10020 }
10021 if progress.is_cancellable != entry.is_cancellable {
10022 entry.is_cancellable = progress.is_cancellable;
10023 }
10024 did_update = true;
10025 }
10026 }
10027 }
10028 }
10029
10030 if did_update {
10031 cx.emit(LspStoreEvent::LanguageServerUpdate {
10032 language_server_id,
10033 name: self
10034 .language_server_adapter_for_id(language_server_id)
10035 .map(|adapter| adapter.name()),
10036 message: proto::update_language_server::Variant::WorkProgress(
10037 proto::LspWorkProgress {
10038 token: Some(token.to_proto()),
10039 message: progress.message,
10040 percentage: progress.percentage.map(|p| p as u32),
10041 is_cancellable: Some(progress.is_cancellable),
10042 },
10043 ),
10044 })
10045 }
10046 }
10047
10048 fn on_lsp_work_end(
10049 &mut self,
10050 language_server_id: LanguageServerId,
10051 token: ProgressToken,
10052 cx: &mut Context<Self>,
10053 ) {
10054 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10055 if let Some(work) = status.pending_work.remove(&token)
10056 && !work.is_disk_based_diagnostics_progress
10057 {
10058 cx.emit(LspStoreEvent::RefreshInlayHints {
10059 server_id: language_server_id,
10060 request_id: None,
10061 });
10062 }
10063 cx.notify();
10064 }
10065
10066 cx.emit(LspStoreEvent::LanguageServerUpdate {
10067 language_server_id,
10068 name: self
10069 .language_server_adapter_for_id(language_server_id)
10070 .map(|adapter| adapter.name()),
10071 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10072 token: Some(token.to_proto()),
10073 }),
10074 })
10075 }
10076
10077 pub async fn handle_resolve_completion_documentation(
10078 this: Entity<Self>,
10079 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10080 mut cx: AsyncApp,
10081 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10082 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10083
10084 let completion = this
10085 .read_with(&cx, |this, cx| {
10086 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10087 let server = this
10088 .language_server_for_id(id)
10089 .with_context(|| format!("No language server {id}"))?;
10090
10091 let request_timeout = ProjectSettings::get_global(cx)
10092 .global_lsp_settings
10093 .get_request_timeout();
10094
10095 anyhow::Ok(cx.background_spawn(async move {
10096 let can_resolve = server
10097 .capabilities()
10098 .completion_provider
10099 .as_ref()
10100 .and_then(|options| options.resolve_provider)
10101 .unwrap_or(false);
10102 if can_resolve {
10103 server
10104 .request::<lsp::request::ResolveCompletionItem>(
10105 lsp_completion,
10106 request_timeout,
10107 )
10108 .await
10109 .into_response()
10110 .context("resolve completion item")
10111 } else {
10112 anyhow::Ok(lsp_completion)
10113 }
10114 }))
10115 })?
10116 .await?;
10117
10118 let mut documentation_is_markdown = false;
10119 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10120 let documentation = match completion.documentation {
10121 Some(lsp::Documentation::String(text)) => text,
10122
10123 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10124 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10125 value
10126 }
10127
10128 _ => String::new(),
10129 };
10130
10131 // If we have a new buffer_id, that means we're talking to a new client
10132 // and want to check for new text_edits in the completion too.
10133 let mut old_replace_start = None;
10134 let mut old_replace_end = None;
10135 let mut old_insert_start = None;
10136 let mut old_insert_end = None;
10137 let mut new_text = String::default();
10138 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10139 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10140 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10141 anyhow::Ok(buffer.read(cx).snapshot())
10142 })?;
10143
10144 if let Some(text_edit) = completion.text_edit.as_ref() {
10145 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10146
10147 if let Some(mut edit) = edit {
10148 LineEnding::normalize(&mut edit.new_text);
10149
10150 new_text = edit.new_text;
10151 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10152 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10153 if let Some(insert_range) = edit.insert_range {
10154 old_insert_start = Some(serialize_anchor(&insert_range.start));
10155 old_insert_end = Some(serialize_anchor(&insert_range.end));
10156 }
10157 }
10158 }
10159 }
10160
10161 Ok(proto::ResolveCompletionDocumentationResponse {
10162 documentation,
10163 documentation_is_markdown,
10164 old_replace_start,
10165 old_replace_end,
10166 new_text,
10167 lsp_completion,
10168 old_insert_start,
10169 old_insert_end,
10170 })
10171 }
10172
10173 async fn handle_on_type_formatting(
10174 this: Entity<Self>,
10175 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10176 mut cx: AsyncApp,
10177 ) -> Result<proto::OnTypeFormattingResponse> {
10178 let on_type_formatting = this.update(&mut cx, |this, cx| {
10179 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10180 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10181 let position = envelope
10182 .payload
10183 .position
10184 .and_then(deserialize_anchor)
10185 .context("invalid position")?;
10186 anyhow::Ok(this.apply_on_type_formatting(
10187 buffer,
10188 position,
10189 envelope.payload.trigger.clone(),
10190 cx,
10191 ))
10192 })?;
10193
10194 let transaction = on_type_formatting
10195 .await?
10196 .as_ref()
10197 .map(language::proto::serialize_transaction);
10198 Ok(proto::OnTypeFormattingResponse { transaction })
10199 }
10200
10201 async fn handle_pull_workspace_diagnostics(
10202 lsp_store: Entity<Self>,
10203 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10204 mut cx: AsyncApp,
10205 ) -> Result<proto::Ack> {
10206 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10207 lsp_store.update(&mut cx, |lsp_store, _| {
10208 lsp_store.pull_workspace_diagnostics(server_id);
10209 });
10210 Ok(proto::Ack {})
10211 }
10212
10213 async fn handle_open_buffer_for_symbol(
10214 this: Entity<Self>,
10215 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10216 mut cx: AsyncApp,
10217 ) -> Result<proto::OpenBufferForSymbolResponse> {
10218 let peer_id = envelope.original_sender_id().unwrap_or_default();
10219 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10220 let symbol = Self::deserialize_symbol(symbol)?;
10221 this.read_with(&cx, |this, _| {
10222 if let SymbolLocation::OutsideProject {
10223 abs_path,
10224 signature,
10225 } = &symbol.path
10226 {
10227 let new_signature = this.symbol_signature(&abs_path);
10228 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10229 }
10230 Ok(())
10231 })?;
10232 let buffer = this
10233 .update(&mut cx, |this, cx| {
10234 this.open_buffer_for_symbol(
10235 &Symbol {
10236 language_server_name: symbol.language_server_name,
10237 source_worktree_id: symbol.source_worktree_id,
10238 source_language_server_id: symbol.source_language_server_id,
10239 path: symbol.path,
10240 name: symbol.name,
10241 kind: symbol.kind,
10242 range: symbol.range,
10243 label: CodeLabel::default(),
10244 container_name: symbol.container_name,
10245 },
10246 cx,
10247 )
10248 })
10249 .await?;
10250
10251 this.update(&mut cx, |this, cx| {
10252 let is_private = buffer
10253 .read(cx)
10254 .file()
10255 .map(|f| f.is_private())
10256 .unwrap_or_default();
10257 if is_private {
10258 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10259 } else {
10260 this.buffer_store
10261 .update(cx, |buffer_store, cx| {
10262 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10263 })
10264 .detach_and_log_err(cx);
10265 let buffer_id = buffer.read(cx).remote_id().to_proto();
10266 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10267 }
10268 })
10269 }
10270
10271 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10272 let mut hasher = Sha256::new();
10273 hasher.update(abs_path.to_string_lossy().as_bytes());
10274 hasher.update(self.nonce.to_be_bytes());
10275 hasher.finalize().as_slice().try_into().unwrap()
10276 }
10277
10278 pub async fn handle_get_project_symbols(
10279 this: Entity<Self>,
10280 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10281 mut cx: AsyncApp,
10282 ) -> Result<proto::GetProjectSymbolsResponse> {
10283 let symbols = this
10284 .update(&mut cx, |this, cx| {
10285 this.symbols(&envelope.payload.query, cx)
10286 })
10287 .await?;
10288
10289 Ok(proto::GetProjectSymbolsResponse {
10290 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10291 })
10292 }
10293
10294 pub async fn handle_restart_language_servers(
10295 this: Entity<Self>,
10296 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10297 mut cx: AsyncApp,
10298 ) -> Result<proto::Ack> {
10299 this.update(&mut cx, |lsp_store, cx| {
10300 let buffers =
10301 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10302 lsp_store.restart_language_servers_for_buffers(
10303 buffers,
10304 envelope
10305 .payload
10306 .only_servers
10307 .into_iter()
10308 .filter_map(|selector| {
10309 Some(match selector.selector? {
10310 proto::language_server_selector::Selector::ServerId(server_id) => {
10311 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10312 }
10313 proto::language_server_selector::Selector::Name(name) => {
10314 LanguageServerSelector::Name(LanguageServerName(
10315 SharedString::from(name),
10316 ))
10317 }
10318 })
10319 })
10320 .collect(),
10321 cx,
10322 );
10323 });
10324
10325 Ok(proto::Ack {})
10326 }
10327
10328 pub async fn handle_stop_language_servers(
10329 lsp_store: Entity<Self>,
10330 envelope: TypedEnvelope<proto::StopLanguageServers>,
10331 mut cx: AsyncApp,
10332 ) -> Result<proto::Ack> {
10333 lsp_store.update(&mut cx, |lsp_store, cx| {
10334 if envelope.payload.all
10335 && envelope.payload.also_servers.is_empty()
10336 && envelope.payload.buffer_ids.is_empty()
10337 {
10338 lsp_store.stop_all_language_servers(cx);
10339 } else {
10340 let buffers =
10341 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10342 lsp_store
10343 .stop_language_servers_for_buffers(
10344 buffers,
10345 envelope
10346 .payload
10347 .also_servers
10348 .into_iter()
10349 .filter_map(|selector| {
10350 Some(match selector.selector? {
10351 proto::language_server_selector::Selector::ServerId(
10352 server_id,
10353 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10354 server_id,
10355 )),
10356 proto::language_server_selector::Selector::Name(name) => {
10357 LanguageServerSelector::Name(LanguageServerName(
10358 SharedString::from(name),
10359 ))
10360 }
10361 })
10362 })
10363 .collect(),
10364 cx,
10365 )
10366 .detach_and_log_err(cx);
10367 }
10368 });
10369
10370 Ok(proto::Ack {})
10371 }
10372
10373 pub async fn handle_cancel_language_server_work(
10374 lsp_store: Entity<Self>,
10375 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10376 mut cx: AsyncApp,
10377 ) -> Result<proto::Ack> {
10378 lsp_store.update(&mut cx, |lsp_store, cx| {
10379 if let Some(work) = envelope.payload.work {
10380 match work {
10381 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10382 let buffers =
10383 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10384 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10385 }
10386 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10387 let server_id = LanguageServerId::from_proto(work.language_server_id);
10388 let token = work
10389 .token
10390 .map(|token| {
10391 ProgressToken::from_proto(token)
10392 .context("invalid work progress token")
10393 })
10394 .transpose()?;
10395 lsp_store.cancel_language_server_work(server_id, token, cx);
10396 }
10397 }
10398 }
10399 anyhow::Ok(())
10400 })?;
10401
10402 Ok(proto::Ack {})
10403 }
10404
10405 fn buffer_ids_to_buffers(
10406 &mut self,
10407 buffer_ids: impl Iterator<Item = u64>,
10408 cx: &mut Context<Self>,
10409 ) -> Vec<Entity<Buffer>> {
10410 buffer_ids
10411 .into_iter()
10412 .flat_map(|buffer_id| {
10413 self.buffer_store
10414 .read(cx)
10415 .get(BufferId::new(buffer_id).log_err()?)
10416 })
10417 .collect::<Vec<_>>()
10418 }
10419
10420 async fn handle_apply_additional_edits_for_completion(
10421 this: Entity<Self>,
10422 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10423 mut cx: AsyncApp,
10424 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10425 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10426 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10427 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10428 let completion = Self::deserialize_completion(
10429 envelope.payload.completion.context("invalid completion")?,
10430 )?;
10431 anyhow::Ok((buffer, completion))
10432 })?;
10433
10434 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10435 this.apply_additional_edits_for_completion(
10436 buffer,
10437 Rc::new(RefCell::new(Box::new([Completion {
10438 replace_range: completion.replace_range,
10439 new_text: completion.new_text,
10440 source: completion.source,
10441 documentation: None,
10442 label: CodeLabel::default(),
10443 match_start: None,
10444 snippet_deduplication_key: None,
10445 insert_text_mode: None,
10446 icon_path: None,
10447 confirm: None,
10448 }]))),
10449 0,
10450 false,
10451 cx,
10452 )
10453 });
10454
10455 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10456 transaction: apply_additional_edits
10457 .await?
10458 .as_ref()
10459 .map(language::proto::serialize_transaction),
10460 })
10461 }
10462
10463 pub fn last_formatting_failure(&self) -> Option<&str> {
10464 self.last_formatting_failure.as_deref()
10465 }
10466
10467 pub fn reset_last_formatting_failure(&mut self) {
10468 self.last_formatting_failure = None;
10469 }
10470
10471 pub fn environment_for_buffer(
10472 &self,
10473 buffer: &Entity<Buffer>,
10474 cx: &mut Context<Self>,
10475 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10476 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10477 environment.update(cx, |env, cx| {
10478 env.buffer_environment(buffer, &self.worktree_store, cx)
10479 })
10480 } else {
10481 Task::ready(None).shared()
10482 }
10483 }
10484
10485 pub fn format(
10486 &mut self,
10487 buffers: HashSet<Entity<Buffer>>,
10488 target: LspFormatTarget,
10489 push_to_history: bool,
10490 trigger: FormatTrigger,
10491 cx: &mut Context<Self>,
10492 ) -> Task<anyhow::Result<ProjectTransaction>> {
10493 let logger = zlog::scoped!("format");
10494 if self.as_local().is_some() {
10495 zlog::trace!(logger => "Formatting locally");
10496 let logger = zlog::scoped!(logger => "local");
10497 let buffers = buffers
10498 .into_iter()
10499 .map(|buffer_handle| {
10500 let buffer = buffer_handle.read(cx);
10501 let buffer_abs_path = File::from_dyn(buffer.file())
10502 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10503
10504 (buffer_handle, buffer_abs_path, buffer.remote_id())
10505 })
10506 .collect::<Vec<_>>();
10507
10508 cx.spawn(async move |lsp_store, cx| {
10509 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10510
10511 for (handle, abs_path, id) in buffers {
10512 let env = lsp_store
10513 .update(cx, |lsp_store, cx| {
10514 lsp_store.environment_for_buffer(&handle, cx)
10515 })?
10516 .await;
10517
10518 let ranges = match &target {
10519 LspFormatTarget::Buffers => None,
10520 LspFormatTarget::Ranges(ranges) => {
10521 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10522 }
10523 };
10524
10525 formattable_buffers.push(FormattableBuffer {
10526 handle,
10527 abs_path,
10528 env,
10529 ranges,
10530 });
10531 }
10532 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10533
10534 let format_timer = zlog::time!(logger => "Formatting buffers");
10535 let result = LocalLspStore::format_locally(
10536 lsp_store.clone(),
10537 formattable_buffers,
10538 push_to_history,
10539 trigger,
10540 logger,
10541 cx,
10542 )
10543 .await;
10544 format_timer.end();
10545
10546 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10547
10548 lsp_store.update(cx, |lsp_store, _| {
10549 lsp_store.update_last_formatting_failure(&result);
10550 })?;
10551
10552 result
10553 })
10554 } else if let Some((client, project_id)) = self.upstream_client() {
10555 zlog::trace!(logger => "Formatting remotely");
10556 let logger = zlog::scoped!(logger => "remote");
10557
10558 let buffer_ranges = match &target {
10559 LspFormatTarget::Buffers => Vec::new(),
10560 LspFormatTarget::Ranges(ranges) => ranges
10561 .iter()
10562 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10563 buffer_id: buffer_id.to_proto(),
10564 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10565 })
10566 .collect(),
10567 };
10568
10569 let buffer_store = self.buffer_store();
10570 cx.spawn(async move |lsp_store, cx| {
10571 zlog::trace!(logger => "Sending remote format request");
10572 let request_timer = zlog::time!(logger => "remote format request");
10573 let result = client
10574 .request(proto::FormatBuffers {
10575 project_id,
10576 trigger: trigger as i32,
10577 buffer_ids: buffers
10578 .iter()
10579 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10580 .collect(),
10581 buffer_ranges,
10582 })
10583 .await
10584 .and_then(|result| result.transaction.context("missing transaction"));
10585 request_timer.end();
10586
10587 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10588
10589 lsp_store.update(cx, |lsp_store, _| {
10590 lsp_store.update_last_formatting_failure(&result);
10591 })?;
10592
10593 let transaction_response = result?;
10594 let _timer = zlog::time!(logger => "deserializing project transaction");
10595 buffer_store
10596 .update(cx, |buffer_store, cx| {
10597 buffer_store.deserialize_project_transaction(
10598 transaction_response,
10599 push_to_history,
10600 cx,
10601 )
10602 })
10603 .await
10604 })
10605 } else {
10606 zlog::trace!(logger => "Not formatting");
10607 Task::ready(Ok(ProjectTransaction::default()))
10608 }
10609 }
10610
10611 async fn handle_format_buffers(
10612 this: Entity<Self>,
10613 envelope: TypedEnvelope<proto::FormatBuffers>,
10614 mut cx: AsyncApp,
10615 ) -> Result<proto::FormatBuffersResponse> {
10616 let sender_id = envelope.original_sender_id().unwrap_or_default();
10617 let format = this.update(&mut cx, |this, cx| {
10618 let mut buffers = HashSet::default();
10619 for buffer_id in &envelope.payload.buffer_ids {
10620 let buffer_id = BufferId::new(*buffer_id)?;
10621 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10622 }
10623
10624 let target = if envelope.payload.buffer_ranges.is_empty() {
10625 LspFormatTarget::Buffers
10626 } else {
10627 let mut ranges_map = BTreeMap::new();
10628 for buffer_range in &envelope.payload.buffer_ranges {
10629 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10630 let ranges: Result<Vec<_>> = buffer_range
10631 .ranges
10632 .iter()
10633 .map(|range| {
10634 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10635 })
10636 .collect();
10637 ranges_map.insert(buffer_id, ranges?);
10638 }
10639 LspFormatTarget::Ranges(ranges_map)
10640 };
10641
10642 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10643 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10644 })?;
10645
10646 let project_transaction = format.await?;
10647 let project_transaction = this.update(&mut cx, |this, cx| {
10648 this.buffer_store.update(cx, |buffer_store, cx| {
10649 buffer_store.serialize_project_transaction_for_peer(
10650 project_transaction,
10651 sender_id,
10652 cx,
10653 )
10654 })
10655 });
10656 Ok(proto::FormatBuffersResponse {
10657 transaction: Some(project_transaction),
10658 })
10659 }
10660
10661 async fn handle_apply_code_action_kind(
10662 this: Entity<Self>,
10663 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10664 mut cx: AsyncApp,
10665 ) -> Result<proto::ApplyCodeActionKindResponse> {
10666 let sender_id = envelope.original_sender_id().unwrap_or_default();
10667 let format = this.update(&mut cx, |this, cx| {
10668 let mut buffers = HashSet::default();
10669 for buffer_id in &envelope.payload.buffer_ids {
10670 let buffer_id = BufferId::new(*buffer_id)?;
10671 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10672 }
10673 let kind = match envelope.payload.kind.as_str() {
10674 "" => CodeActionKind::EMPTY,
10675 "quickfix" => CodeActionKind::QUICKFIX,
10676 "refactor" => CodeActionKind::REFACTOR,
10677 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10678 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10679 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10680 "source" => CodeActionKind::SOURCE,
10681 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10682 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10683 _ => anyhow::bail!(
10684 "Invalid code action kind {}",
10685 envelope.payload.kind.as_str()
10686 ),
10687 };
10688 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10689 })?;
10690
10691 let project_transaction = format.await?;
10692 let project_transaction = this.update(&mut cx, |this, cx| {
10693 this.buffer_store.update(cx, |buffer_store, cx| {
10694 buffer_store.serialize_project_transaction_for_peer(
10695 project_transaction,
10696 sender_id,
10697 cx,
10698 )
10699 })
10700 });
10701 Ok(proto::ApplyCodeActionKindResponse {
10702 transaction: Some(project_transaction),
10703 })
10704 }
10705
10706 async fn shutdown_language_server(
10707 server_state: Option<LanguageServerState>,
10708 name: LanguageServerName,
10709 cx: &mut AsyncApp,
10710 ) {
10711 let server = match server_state {
10712 Some(LanguageServerState::Starting { startup, .. }) => {
10713 let mut timer = cx
10714 .background_executor()
10715 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10716 .fuse();
10717
10718 select! {
10719 server = startup.fuse() => server,
10720 () = timer => {
10721 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10722 None
10723 },
10724 }
10725 }
10726
10727 Some(LanguageServerState::Running { server, .. }) => Some(server),
10728
10729 None => None,
10730 };
10731
10732 let Some(server) = server else { return };
10733 if let Some(shutdown) = server.shutdown() {
10734 shutdown.await;
10735 }
10736 }
10737
10738 // Returns a list of all of the worktrees which no longer have a language server and the root path
10739 // for the stopped server
10740 fn stop_local_language_server(
10741 &mut self,
10742 server_id: LanguageServerId,
10743 cx: &mut Context<Self>,
10744 ) -> Task<()> {
10745 let local = match &mut self.mode {
10746 LspStoreMode::Local(local) => local,
10747 _ => {
10748 return Task::ready(());
10749 }
10750 };
10751
10752 // Remove this server ID from all entries in the given worktree.
10753 local
10754 .language_server_ids
10755 .retain(|_, state| state.id != server_id);
10756 self.buffer_store.update(cx, |buffer_store, cx| {
10757 for buffer in buffer_store.buffers() {
10758 buffer.update(cx, |buffer, cx| {
10759 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10760 buffer.set_completion_triggers(server_id, Default::default(), cx);
10761 });
10762 }
10763 });
10764
10765 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10766 summaries.retain(|path, summaries_by_server_id| {
10767 if summaries_by_server_id.remove(&server_id).is_some() {
10768 if let Some((client, project_id)) = self.downstream_client.clone() {
10769 client
10770 .send(proto::UpdateDiagnosticSummary {
10771 project_id,
10772 worktree_id: worktree_id.to_proto(),
10773 summary: Some(proto::DiagnosticSummary {
10774 path: path.as_ref().to_proto(),
10775 language_server_id: server_id.0 as u64,
10776 error_count: 0,
10777 warning_count: 0,
10778 }),
10779 more_summaries: Vec::new(),
10780 })
10781 .log_err();
10782 }
10783 !summaries_by_server_id.is_empty()
10784 } else {
10785 true
10786 }
10787 });
10788 }
10789
10790 let local = self.as_local_mut().unwrap();
10791 for diagnostics in local.diagnostics.values_mut() {
10792 diagnostics.retain(|_, diagnostics_by_server_id| {
10793 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10794 diagnostics_by_server_id.remove(ix);
10795 !diagnostics_by_server_id.is_empty()
10796 } else {
10797 true
10798 }
10799 });
10800 }
10801 local.language_server_watched_paths.remove(&server_id);
10802
10803 let server_state = local.language_servers.remove(&server_id);
10804 self.cleanup_lsp_data(server_id);
10805 let name = self
10806 .language_server_statuses
10807 .remove(&server_id)
10808 .map(|status| status.name)
10809 .or_else(|| {
10810 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10811 Some(adapter.name())
10812 } else {
10813 None
10814 }
10815 });
10816
10817 if let Some(name) = name {
10818 log::info!("stopping language server {name}");
10819 self.languages
10820 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10821 cx.notify();
10822
10823 return cx.spawn(async move |lsp_store, cx| {
10824 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10825 lsp_store
10826 .update(cx, |lsp_store, cx| {
10827 lsp_store
10828 .languages
10829 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10830 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10831 cx.notify();
10832 })
10833 .ok();
10834 });
10835 }
10836
10837 if server_state.is_some() {
10838 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10839 }
10840 Task::ready(())
10841 }
10842
10843 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10844 self.shutdown_all_language_servers(cx).detach();
10845 }
10846
10847 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10848 if let Some((client, project_id)) = self.upstream_client() {
10849 let request = client.request(proto::StopLanguageServers {
10850 project_id,
10851 buffer_ids: Vec::new(),
10852 also_servers: Vec::new(),
10853 all: true,
10854 });
10855 cx.background_spawn(async move {
10856 request.await.ok();
10857 })
10858 } else {
10859 let Some(local) = self.as_local_mut() else {
10860 return Task::ready(());
10861 };
10862 let language_servers_to_stop = local
10863 .language_server_ids
10864 .values()
10865 .map(|state| state.id)
10866 .collect();
10867 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10868
10869 let supplementary_shutdown_futures: Vec<_> = local
10870 .supplementary_language_servers
10871 .drain()
10872 .filter_map(|(_, (_, server))| server.shutdown())
10873 .collect();
10874
10875 let tasks = language_servers_to_stop
10876 .into_iter()
10877 .map(|server| self.stop_local_language_server(server, cx))
10878 .collect::<Vec<_>>();
10879 cx.background_spawn(async move {
10880 futures::future::join_all(tasks).await;
10881 futures::future::join_all(supplementary_shutdown_futures).await;
10882 })
10883 }
10884 }
10885
10886 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10887 let buffers = self.buffer_store.read(cx).buffers().collect();
10888 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10889 }
10890
10891 pub fn restart_language_servers_for_buffers(
10892 &mut self,
10893 buffers: Vec<Entity<Buffer>>,
10894 only_restart_servers: HashSet<LanguageServerSelector>,
10895 cx: &mut Context<Self>,
10896 ) {
10897 if let Some((client, project_id)) = self.upstream_client() {
10898 let request = client.request(proto::RestartLanguageServers {
10899 project_id,
10900 buffer_ids: buffers
10901 .into_iter()
10902 .map(|b| b.read(cx).remote_id().to_proto())
10903 .collect(),
10904 only_servers: only_restart_servers
10905 .into_iter()
10906 .map(|selector| {
10907 let selector = match selector {
10908 LanguageServerSelector::Id(language_server_id) => {
10909 proto::language_server_selector::Selector::ServerId(
10910 language_server_id.to_proto(),
10911 )
10912 }
10913 LanguageServerSelector::Name(language_server_name) => {
10914 proto::language_server_selector::Selector::Name(
10915 language_server_name.to_string(),
10916 )
10917 }
10918 };
10919 proto::LanguageServerSelector {
10920 selector: Some(selector),
10921 }
10922 })
10923 .collect(),
10924 all: false,
10925 });
10926 cx.background_spawn(request).detach_and_log_err(cx);
10927 } else {
10928 let stop_task = if only_restart_servers.is_empty() {
10929 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10930 } else {
10931 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10932 };
10933 cx.spawn(async move |lsp_store, cx| {
10934 stop_task.await;
10935 lsp_store.update(cx, |lsp_store, cx| {
10936 for buffer in buffers {
10937 lsp_store.register_buffer_with_language_servers(
10938 &buffer,
10939 only_restart_servers.clone(),
10940 true,
10941 cx,
10942 );
10943 }
10944 })
10945 })
10946 .detach();
10947 }
10948 }
10949
10950 pub fn stop_language_servers_for_buffers(
10951 &mut self,
10952 buffers: Vec<Entity<Buffer>>,
10953 also_stop_servers: HashSet<LanguageServerSelector>,
10954 cx: &mut Context<Self>,
10955 ) -> Task<Result<()>> {
10956 if let Some((client, project_id)) = self.upstream_client() {
10957 let request = client.request(proto::StopLanguageServers {
10958 project_id,
10959 buffer_ids: buffers
10960 .into_iter()
10961 .map(|b| b.read(cx).remote_id().to_proto())
10962 .collect(),
10963 also_servers: also_stop_servers
10964 .into_iter()
10965 .map(|selector| {
10966 let selector = match selector {
10967 LanguageServerSelector::Id(language_server_id) => {
10968 proto::language_server_selector::Selector::ServerId(
10969 language_server_id.to_proto(),
10970 )
10971 }
10972 LanguageServerSelector::Name(language_server_name) => {
10973 proto::language_server_selector::Selector::Name(
10974 language_server_name.to_string(),
10975 )
10976 }
10977 };
10978 proto::LanguageServerSelector {
10979 selector: Some(selector),
10980 }
10981 })
10982 .collect(),
10983 all: false,
10984 });
10985 cx.background_spawn(async move {
10986 let _ = request.await?;
10987 Ok(())
10988 })
10989 } else {
10990 let task =
10991 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10992 cx.background_spawn(async move {
10993 task.await;
10994 Ok(())
10995 })
10996 }
10997 }
10998
10999 fn stop_local_language_servers_for_buffers(
11000 &mut self,
11001 buffers: &[Entity<Buffer>],
11002 also_stop_servers: HashSet<LanguageServerSelector>,
11003 cx: &mut Context<Self>,
11004 ) -> Task<()> {
11005 let Some(local) = self.as_local_mut() else {
11006 return Task::ready(());
11007 };
11008 let mut language_server_names_to_stop = BTreeSet::default();
11009 let mut language_servers_to_stop = also_stop_servers
11010 .into_iter()
11011 .flat_map(|selector| match selector {
11012 LanguageServerSelector::Id(id) => Some(id),
11013 LanguageServerSelector::Name(name) => {
11014 language_server_names_to_stop.insert(name);
11015 None
11016 }
11017 })
11018 .collect::<BTreeSet<_>>();
11019
11020 let mut covered_worktrees = HashSet::default();
11021 for buffer in buffers {
11022 buffer.update(cx, |buffer, cx| {
11023 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11024 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11025 && covered_worktrees.insert(worktree_id)
11026 {
11027 language_server_names_to_stop.retain(|name| {
11028 let old_ids_count = language_servers_to_stop.len();
11029 let all_language_servers_with_this_name = local
11030 .language_server_ids
11031 .iter()
11032 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11033 language_servers_to_stop.extend(all_language_servers_with_this_name);
11034 old_ids_count == language_servers_to_stop.len()
11035 });
11036 }
11037 });
11038 }
11039 for name in language_server_names_to_stop {
11040 language_servers_to_stop.extend(
11041 local
11042 .language_server_ids
11043 .iter()
11044 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11045 );
11046 }
11047
11048 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11049 let tasks = language_servers_to_stop
11050 .into_iter()
11051 .map(|server| self.stop_local_language_server(server, cx))
11052 .collect::<Vec<_>>();
11053
11054 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11055 }
11056
11057 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11058 let (worktree, relative_path) =
11059 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11060
11061 let project_path = ProjectPath {
11062 worktree_id: worktree.read(cx).id(),
11063 path: relative_path,
11064 };
11065
11066 Some(
11067 self.buffer_store()
11068 .read(cx)
11069 .get_by_path(&project_path)?
11070 .read(cx),
11071 )
11072 }
11073
11074 #[cfg(any(test, feature = "test-support"))]
11075 pub fn update_diagnostics(
11076 &mut self,
11077 server_id: LanguageServerId,
11078 diagnostics: lsp::PublishDiagnosticsParams,
11079 result_id: Option<SharedString>,
11080 source_kind: DiagnosticSourceKind,
11081 disk_based_sources: &[String],
11082 cx: &mut Context<Self>,
11083 ) -> Result<()> {
11084 self.merge_lsp_diagnostics(
11085 source_kind,
11086 vec![DocumentDiagnosticsUpdate {
11087 diagnostics,
11088 result_id,
11089 server_id,
11090 disk_based_sources: Cow::Borrowed(disk_based_sources),
11091 registration_id: None,
11092 }],
11093 |_, _, _| false,
11094 cx,
11095 )
11096 }
11097
11098 pub fn merge_lsp_diagnostics(
11099 &mut self,
11100 source_kind: DiagnosticSourceKind,
11101 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11102 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11103 cx: &mut Context<Self>,
11104 ) -> Result<()> {
11105 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11106 let updates = lsp_diagnostics
11107 .into_iter()
11108 .filter_map(|update| {
11109 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11110 Some(DocumentDiagnosticsUpdate {
11111 diagnostics: self.lsp_to_document_diagnostics(
11112 abs_path,
11113 source_kind,
11114 update.server_id,
11115 update.diagnostics,
11116 &update.disk_based_sources,
11117 update.registration_id.clone(),
11118 ),
11119 result_id: update.result_id,
11120 server_id: update.server_id,
11121 disk_based_sources: update.disk_based_sources,
11122 registration_id: update.registration_id,
11123 })
11124 })
11125 .collect();
11126 self.merge_diagnostic_entries(updates, merge, cx)?;
11127 Ok(())
11128 }
11129
11130 fn lsp_to_document_diagnostics(
11131 &mut self,
11132 document_abs_path: PathBuf,
11133 source_kind: DiagnosticSourceKind,
11134 server_id: LanguageServerId,
11135 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11136 disk_based_sources: &[String],
11137 registration_id: Option<SharedString>,
11138 ) -> DocumentDiagnostics {
11139 let mut diagnostics = Vec::default();
11140 let mut primary_diagnostic_group_ids = HashMap::default();
11141 let mut sources_by_group_id = HashMap::default();
11142 let mut supporting_diagnostics = HashMap::default();
11143
11144 let adapter = self.language_server_adapter_for_id(server_id);
11145
11146 // Ensure that primary diagnostics are always the most severe
11147 lsp_diagnostics
11148 .diagnostics
11149 .sort_by_key(|item| item.severity);
11150
11151 for diagnostic in &lsp_diagnostics.diagnostics {
11152 let source = diagnostic.source.as_ref();
11153 let range = range_from_lsp(diagnostic.range);
11154 let is_supporting = diagnostic
11155 .related_information
11156 .as_ref()
11157 .is_some_and(|infos| {
11158 infos.iter().any(|info| {
11159 primary_diagnostic_group_ids.contains_key(&(
11160 source,
11161 diagnostic.code.clone(),
11162 range_from_lsp(info.location.range),
11163 ))
11164 })
11165 });
11166
11167 let is_unnecessary = diagnostic
11168 .tags
11169 .as_ref()
11170 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11171
11172 let underline = self
11173 .language_server_adapter_for_id(server_id)
11174 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11175
11176 if is_supporting {
11177 supporting_diagnostics.insert(
11178 (source, diagnostic.code.clone(), range),
11179 (diagnostic.severity, is_unnecessary),
11180 );
11181 } else {
11182 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11183 let is_disk_based =
11184 source.is_some_and(|source| disk_based_sources.contains(source));
11185
11186 sources_by_group_id.insert(group_id, source);
11187 primary_diagnostic_group_ids
11188 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11189
11190 diagnostics.push(DiagnosticEntry {
11191 range,
11192 diagnostic: Diagnostic {
11193 source: diagnostic.source.clone(),
11194 source_kind,
11195 code: diagnostic.code.clone(),
11196 code_description: diagnostic
11197 .code_description
11198 .as_ref()
11199 .and_then(|d| d.href.clone()),
11200 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11201 markdown: adapter.as_ref().and_then(|adapter| {
11202 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11203 }),
11204 message: diagnostic.message.trim().to_string(),
11205 group_id,
11206 is_primary: true,
11207 is_disk_based,
11208 is_unnecessary,
11209 underline,
11210 data: diagnostic.data.clone(),
11211 registration_id: registration_id.clone(),
11212 },
11213 });
11214 if let Some(infos) = &diagnostic.related_information {
11215 for info in infos {
11216 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11217 let range = range_from_lsp(info.location.range);
11218 diagnostics.push(DiagnosticEntry {
11219 range,
11220 diagnostic: Diagnostic {
11221 source: diagnostic.source.clone(),
11222 source_kind,
11223 code: diagnostic.code.clone(),
11224 code_description: diagnostic
11225 .code_description
11226 .as_ref()
11227 .and_then(|d| d.href.clone()),
11228 severity: DiagnosticSeverity::INFORMATION,
11229 markdown: adapter.as_ref().and_then(|adapter| {
11230 adapter.diagnostic_message_to_markdown(&info.message)
11231 }),
11232 message: info.message.trim().to_string(),
11233 group_id,
11234 is_primary: false,
11235 is_disk_based,
11236 is_unnecessary: false,
11237 underline,
11238 data: diagnostic.data.clone(),
11239 registration_id: registration_id.clone(),
11240 },
11241 });
11242 }
11243 }
11244 }
11245 }
11246 }
11247
11248 for entry in &mut diagnostics {
11249 let diagnostic = &mut entry.diagnostic;
11250 if !diagnostic.is_primary {
11251 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11252 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11253 source,
11254 diagnostic.code.clone(),
11255 entry.range.clone(),
11256 )) {
11257 if let Some(severity) = severity {
11258 diagnostic.severity = severity;
11259 }
11260 diagnostic.is_unnecessary = is_unnecessary;
11261 }
11262 }
11263 }
11264
11265 DocumentDiagnostics {
11266 diagnostics,
11267 document_abs_path,
11268 version: lsp_diagnostics.version,
11269 }
11270 }
11271
11272 fn insert_newly_running_language_server(
11273 &mut self,
11274 adapter: Arc<CachedLspAdapter>,
11275 language_server: Arc<LanguageServer>,
11276 server_id: LanguageServerId,
11277 key: LanguageServerSeed,
11278 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11279 cx: &mut Context<Self>,
11280 ) {
11281 let Some(local) = self.as_local_mut() else {
11282 return;
11283 };
11284 // If the language server for this key doesn't match the server id, don't store the
11285 // server. Which will cause it to be dropped, killing the process
11286 if local
11287 .language_server_ids
11288 .get(&key)
11289 .map(|state| state.id != server_id)
11290 .unwrap_or(false)
11291 {
11292 return;
11293 }
11294
11295 // Update language_servers collection with Running variant of LanguageServerState
11296 // indicating that the server is up and running and ready
11297 let workspace_folders = workspace_folders.lock().clone();
11298 language_server.set_workspace_folders(workspace_folders);
11299
11300 let workspace_diagnostics_refresh_tasks = language_server
11301 .capabilities()
11302 .diagnostic_provider
11303 .and_then(|provider| {
11304 local
11305 .language_server_dynamic_registrations
11306 .entry(server_id)
11307 .or_default()
11308 .diagnostics
11309 .entry(None)
11310 .or_insert(provider.clone());
11311 let workspace_refresher =
11312 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11313
11314 Some((None, workspace_refresher))
11315 })
11316 .into_iter()
11317 .collect();
11318 local.language_servers.insert(
11319 server_id,
11320 LanguageServerState::Running {
11321 workspace_diagnostics_refresh_tasks,
11322 adapter: adapter.clone(),
11323 server: language_server.clone(),
11324 simulate_disk_based_diagnostics_completion: None,
11325 },
11326 );
11327 local
11328 .languages
11329 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11330 if let Some(file_ops_caps) = language_server
11331 .capabilities()
11332 .workspace
11333 .as_ref()
11334 .and_then(|ws| ws.file_operations.as_ref())
11335 {
11336 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11337 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11338 if did_rename_caps.or(will_rename_caps).is_some() {
11339 let watcher = RenamePathsWatchedForServer::default()
11340 .with_did_rename_patterns(did_rename_caps)
11341 .with_will_rename_patterns(will_rename_caps);
11342 local
11343 .language_server_paths_watched_for_rename
11344 .insert(server_id, watcher);
11345 }
11346 }
11347
11348 self.language_server_statuses.insert(
11349 server_id,
11350 LanguageServerStatus {
11351 name: language_server.name(),
11352 server_version: language_server.version(),
11353 pending_work: Default::default(),
11354 has_pending_diagnostic_updates: false,
11355 progress_tokens: Default::default(),
11356 worktree: Some(key.worktree_id),
11357 binary: Some(language_server.binary().clone()),
11358 configuration: Some(language_server.configuration().clone()),
11359 workspace_folders: language_server.workspace_folders(),
11360 process_id: language_server.process_id(),
11361 },
11362 );
11363
11364 cx.emit(LspStoreEvent::LanguageServerAdded(
11365 server_id,
11366 language_server.name(),
11367 Some(key.worktree_id),
11368 ));
11369
11370 let server_capabilities = language_server.capabilities();
11371 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11372 downstream_client
11373 .send(proto::StartLanguageServer {
11374 project_id: *project_id,
11375 server: Some(proto::LanguageServer {
11376 id: server_id.to_proto(),
11377 name: language_server.name().to_string(),
11378 worktree_id: Some(key.worktree_id.to_proto()),
11379 }),
11380 capabilities: serde_json::to_string(&server_capabilities)
11381 .expect("serializing server LSP capabilities"),
11382 })
11383 .log_err();
11384 }
11385 self.lsp_server_capabilities
11386 .insert(server_id, server_capabilities);
11387
11388 // Tell the language server about every open buffer in the worktree that matches the language.
11389 // Also check for buffers in worktrees that reused this server
11390 let mut worktrees_using_server = vec![key.worktree_id];
11391 if let Some(local) = self.as_local() {
11392 // Find all worktrees that have this server in their language server tree
11393 for (worktree_id, servers) in &local.lsp_tree.instances {
11394 if *worktree_id != key.worktree_id {
11395 for server_map in servers.roots.values() {
11396 if server_map
11397 .values()
11398 .any(|(node, _)| node.id() == Some(server_id))
11399 {
11400 worktrees_using_server.push(*worktree_id);
11401 }
11402 }
11403 }
11404 }
11405 }
11406
11407 let mut buffer_paths_registered = Vec::new();
11408 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11409 let mut lsp_adapters = HashMap::default();
11410 for buffer_handle in buffer_store.buffers() {
11411 let buffer = buffer_handle.read(cx);
11412 let file = match File::from_dyn(buffer.file()) {
11413 Some(file) => file,
11414 None => continue,
11415 };
11416 let language = match buffer.language() {
11417 Some(language) => language,
11418 None => continue,
11419 };
11420
11421 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11422 || !lsp_adapters
11423 .entry(language.name())
11424 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11425 .iter()
11426 .any(|a| a.name == key.name)
11427 {
11428 continue;
11429 }
11430 // didOpen
11431 let file = match file.as_local() {
11432 Some(file) => file,
11433 None => continue,
11434 };
11435
11436 let local = self.as_local_mut().unwrap();
11437
11438 let buffer_id = buffer.remote_id();
11439 if local.registered_buffers.contains_key(&buffer_id) {
11440 let abs_path = file.abs_path(cx);
11441 let uri = match lsp::Uri::from_file_path(&abs_path) {
11442 Ok(uri) => uri,
11443 Err(()) => {
11444 log::error!("failed to convert path to URI: {:?}", abs_path);
11445 continue;
11446 }
11447 };
11448
11449 let versions = local
11450 .buffer_snapshots
11451 .entry(buffer_id)
11452 .or_default()
11453 .entry(server_id)
11454 .and_modify(|_| {
11455 assert!(
11456 false,
11457 "There should not be an existing snapshot for a newly inserted buffer"
11458 )
11459 })
11460 .or_insert_with(|| {
11461 vec![LspBufferSnapshot {
11462 version: 0,
11463 snapshot: buffer.text_snapshot(),
11464 }]
11465 });
11466
11467 let snapshot = versions.last().unwrap();
11468 let version = snapshot.version;
11469 let initial_snapshot = &snapshot.snapshot;
11470 language_server.register_buffer(
11471 uri,
11472 adapter.language_id(&language.name()),
11473 version,
11474 initial_snapshot.text(),
11475 );
11476 buffer_paths_registered.push((buffer_id, abs_path));
11477 local
11478 .buffers_opened_in_servers
11479 .entry(buffer_id)
11480 .or_default()
11481 .insert(server_id);
11482 }
11483 buffer_handle.update(cx, |buffer, cx| {
11484 buffer.set_completion_triggers(
11485 server_id,
11486 language_server
11487 .capabilities()
11488 .completion_provider
11489 .as_ref()
11490 .and_then(|provider| {
11491 provider
11492 .trigger_characters
11493 .as_ref()
11494 .map(|characters| characters.iter().cloned().collect())
11495 })
11496 .unwrap_or_default(),
11497 cx,
11498 )
11499 });
11500 }
11501 });
11502
11503 for (buffer_id, abs_path) in buffer_paths_registered {
11504 cx.emit(LspStoreEvent::LanguageServerUpdate {
11505 language_server_id: server_id,
11506 name: Some(adapter.name()),
11507 message: proto::update_language_server::Variant::RegisteredForBuffer(
11508 proto::RegisteredForBuffer {
11509 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11510 buffer_id: buffer_id.to_proto(),
11511 },
11512 ),
11513 });
11514 }
11515
11516 cx.notify();
11517 }
11518
11519 pub fn language_servers_running_disk_based_diagnostics(
11520 &self,
11521 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11522 self.language_server_statuses
11523 .iter()
11524 .filter_map(|(id, status)| {
11525 if status.has_pending_diagnostic_updates {
11526 Some(*id)
11527 } else {
11528 None
11529 }
11530 })
11531 }
11532
11533 pub(crate) fn cancel_language_server_work_for_buffers(
11534 &mut self,
11535 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11536 cx: &mut Context<Self>,
11537 ) {
11538 if let Some((client, project_id)) = self.upstream_client() {
11539 let request = client.request(proto::CancelLanguageServerWork {
11540 project_id,
11541 work: Some(proto::cancel_language_server_work::Work::Buffers(
11542 proto::cancel_language_server_work::Buffers {
11543 buffer_ids: buffers
11544 .into_iter()
11545 .map(|b| b.read(cx).remote_id().to_proto())
11546 .collect(),
11547 },
11548 )),
11549 });
11550 cx.background_spawn(request).detach_and_log_err(cx);
11551 } else if let Some(local) = self.as_local() {
11552 let servers = buffers
11553 .into_iter()
11554 .flat_map(|buffer| {
11555 buffer.update(cx, |buffer, cx| {
11556 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11557 })
11558 })
11559 .collect::<HashSet<_>>();
11560 for server_id in servers {
11561 self.cancel_language_server_work(server_id, None, cx);
11562 }
11563 }
11564 }
11565
11566 pub(crate) fn cancel_language_server_work(
11567 &mut self,
11568 server_id: LanguageServerId,
11569 token_to_cancel: Option<ProgressToken>,
11570 cx: &mut Context<Self>,
11571 ) {
11572 if let Some(local) = self.as_local() {
11573 let status = self.language_server_statuses.get(&server_id);
11574 let server = local.language_servers.get(&server_id);
11575 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11576 {
11577 for (token, progress) in &status.pending_work {
11578 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11579 && token != token_to_cancel
11580 {
11581 continue;
11582 }
11583 if progress.is_cancellable {
11584 server
11585 .notify::<lsp::notification::WorkDoneProgressCancel>(
11586 WorkDoneProgressCancelParams {
11587 token: token.to_lsp(),
11588 },
11589 )
11590 .ok();
11591 }
11592 }
11593 }
11594 } else if let Some((client, project_id)) = self.upstream_client() {
11595 let request = client.request(proto::CancelLanguageServerWork {
11596 project_id,
11597 work: Some(
11598 proto::cancel_language_server_work::Work::LanguageServerWork(
11599 proto::cancel_language_server_work::LanguageServerWork {
11600 language_server_id: server_id.to_proto(),
11601 token: token_to_cancel.map(|token| token.to_proto()),
11602 },
11603 ),
11604 ),
11605 });
11606 cx.background_spawn(request).detach_and_log_err(cx);
11607 }
11608 }
11609
11610 fn register_supplementary_language_server(
11611 &mut self,
11612 id: LanguageServerId,
11613 name: LanguageServerName,
11614 server: Arc<LanguageServer>,
11615 cx: &mut Context<Self>,
11616 ) {
11617 if let Some(local) = self.as_local_mut() {
11618 local
11619 .supplementary_language_servers
11620 .insert(id, (name.clone(), server));
11621 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11622 }
11623 }
11624
11625 fn unregister_supplementary_language_server(
11626 &mut self,
11627 id: LanguageServerId,
11628 cx: &mut Context<Self>,
11629 ) {
11630 if let Some(local) = self.as_local_mut() {
11631 local.supplementary_language_servers.remove(&id);
11632 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11633 }
11634 }
11635
11636 pub(crate) fn supplementary_language_servers(
11637 &self,
11638 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11639 self.as_local().into_iter().flat_map(|local| {
11640 local
11641 .supplementary_language_servers
11642 .iter()
11643 .map(|(id, (name, _))| (*id, name.clone()))
11644 })
11645 }
11646
11647 pub fn language_server_adapter_for_id(
11648 &self,
11649 id: LanguageServerId,
11650 ) -> Option<Arc<CachedLspAdapter>> {
11651 self.as_local()
11652 .and_then(|local| local.language_servers.get(&id))
11653 .and_then(|language_server_state| match language_server_state {
11654 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11655 _ => None,
11656 })
11657 }
11658
11659 pub(super) fn update_local_worktree_language_servers(
11660 &mut self,
11661 worktree_handle: &Entity<Worktree>,
11662 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11663 cx: &mut Context<Self>,
11664 ) {
11665 if changes.is_empty() {
11666 return;
11667 }
11668
11669 let Some(local) = self.as_local() else { return };
11670
11671 local.prettier_store.update(cx, |prettier_store, cx| {
11672 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11673 });
11674
11675 let worktree_id = worktree_handle.read(cx).id();
11676 let mut language_server_ids = local
11677 .language_server_ids
11678 .iter()
11679 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11680 .collect::<Vec<_>>();
11681 language_server_ids.sort();
11682 language_server_ids.dedup();
11683
11684 // let abs_path = worktree_handle.read(cx).abs_path();
11685 for server_id in &language_server_ids {
11686 if let Some(LanguageServerState::Running { server, .. }) =
11687 local.language_servers.get(server_id)
11688 && let Some(watched_paths) = local
11689 .language_server_watched_paths
11690 .get(server_id)
11691 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11692 {
11693 let params = lsp::DidChangeWatchedFilesParams {
11694 changes: changes
11695 .iter()
11696 .filter_map(|(path, _, change)| {
11697 if !watched_paths.is_match(path.as_std_path()) {
11698 return None;
11699 }
11700 let typ = match change {
11701 PathChange::Loaded => return None,
11702 PathChange::Added => lsp::FileChangeType::CREATED,
11703 PathChange::Removed => lsp::FileChangeType::DELETED,
11704 PathChange::Updated => lsp::FileChangeType::CHANGED,
11705 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11706 };
11707 let uri = lsp::Uri::from_file_path(
11708 worktree_handle.read(cx).absolutize(&path),
11709 )
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 worktree_paths: HashMap<WorktreeId, GlobSet>,
13531 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13532}
13533
13534#[derive(Default)]
13535struct LanguageServerWatchedPathsBuilder {
13536 worktree_paths: HashMap<WorktreeId, GlobSet>,
13537 abs_paths: HashMap<Arc<Path>, GlobSet>,
13538}
13539
13540impl LanguageServerWatchedPathsBuilder {
13541 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13542 self.worktree_paths.insert(worktree_id, glob_set);
13543 }
13544 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13545 self.abs_paths.insert(path, glob_set);
13546 }
13547 fn build(
13548 self,
13549 fs: Arc<dyn Fs>,
13550 language_server_id: LanguageServerId,
13551 cx: &mut Context<LspStore>,
13552 ) -> LanguageServerWatchedPaths {
13553 let lsp_store = cx.weak_entity();
13554
13555 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13556 let abs_paths = self
13557 .abs_paths
13558 .into_iter()
13559 .map(|(abs_path, globset)| {
13560 let task = cx.spawn({
13561 let abs_path = abs_path.clone();
13562 let fs = fs.clone();
13563
13564 let lsp_store = lsp_store.clone();
13565 async move |_, cx| {
13566 maybe!(async move {
13567 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13568 while let Some(update) = push_updates.0.next().await {
13569 let action = lsp_store
13570 .update(cx, |this, _| {
13571 let Some(local) = this.as_local() else {
13572 return ControlFlow::Break(());
13573 };
13574 let Some(watcher) = local
13575 .language_server_watched_paths
13576 .get(&language_server_id)
13577 else {
13578 return ControlFlow::Break(());
13579 };
13580 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13581 "Watched abs path is not registered with a watcher",
13582 );
13583 let matching_entries = update
13584 .into_iter()
13585 .filter(|event| globs.is_match(&event.path))
13586 .collect::<Vec<_>>();
13587 this.lsp_notify_abs_paths_changed(
13588 language_server_id,
13589 matching_entries,
13590 );
13591 ControlFlow::Continue(())
13592 })
13593 .ok()?;
13594
13595 if action.is_break() {
13596 break;
13597 }
13598 }
13599 Some(())
13600 })
13601 .await;
13602 }
13603 });
13604 (abs_path, (globset, task))
13605 })
13606 .collect();
13607 LanguageServerWatchedPaths {
13608 worktree_paths: self.worktree_paths,
13609 abs_paths,
13610 }
13611 }
13612}
13613
13614struct LspBufferSnapshot {
13615 version: i32,
13616 snapshot: TextBufferSnapshot,
13617}
13618
13619/// A prompt requested by LSP server.
13620#[derive(Clone, Debug)]
13621pub struct LanguageServerPromptRequest {
13622 pub id: usize,
13623 pub level: PromptLevel,
13624 pub message: String,
13625 pub actions: Vec<MessageActionItem>,
13626 pub lsp_name: String,
13627 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13628}
13629
13630impl LanguageServerPromptRequest {
13631 pub fn new(
13632 level: PromptLevel,
13633 message: String,
13634 actions: Vec<MessageActionItem>,
13635 lsp_name: String,
13636 response_channel: smol::channel::Sender<MessageActionItem>,
13637 ) -> Self {
13638 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13639 LanguageServerPromptRequest {
13640 id,
13641 level,
13642 message,
13643 actions,
13644 lsp_name,
13645 response_channel,
13646 }
13647 }
13648 pub async fn respond(self, index: usize) -> Option<()> {
13649 if let Some(response) = self.actions.into_iter().nth(index) {
13650 self.response_channel.send(response).await.ok()
13651 } else {
13652 None
13653 }
13654 }
13655
13656 #[cfg(any(test, feature = "test-support"))]
13657 pub fn test(
13658 level: PromptLevel,
13659 message: String,
13660 actions: Vec<MessageActionItem>,
13661 lsp_name: String,
13662 ) -> Self {
13663 let (tx, _rx) = smol::channel::unbounded();
13664 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13665 }
13666}
13667impl PartialEq for LanguageServerPromptRequest {
13668 fn eq(&self, other: &Self) -> bool {
13669 self.message == other.message && self.actions == other.actions
13670 }
13671}
13672
13673#[derive(Clone, Debug, PartialEq)]
13674pub enum LanguageServerLogType {
13675 Log(MessageType),
13676 Trace { verbose_info: Option<String> },
13677 Rpc { received: bool },
13678}
13679
13680impl LanguageServerLogType {
13681 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13682 match self {
13683 Self::Log(log_type) => {
13684 use proto::log_message::LogLevel;
13685 let level = match *log_type {
13686 MessageType::ERROR => LogLevel::Error,
13687 MessageType::WARNING => LogLevel::Warning,
13688 MessageType::INFO => LogLevel::Info,
13689 MessageType::LOG => LogLevel::Log,
13690 other => {
13691 log::warn!("Unknown lsp log message type: {other:?}");
13692 LogLevel::Log
13693 }
13694 };
13695 proto::language_server_log::LogType::Log(proto::LogMessage {
13696 level: level as i32,
13697 })
13698 }
13699 Self::Trace { verbose_info } => {
13700 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13701 verbose_info: verbose_info.to_owned(),
13702 })
13703 }
13704 Self::Rpc { received } => {
13705 let kind = if *received {
13706 proto::rpc_message::Kind::Received
13707 } else {
13708 proto::rpc_message::Kind::Sent
13709 };
13710 let kind = kind as i32;
13711 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13712 }
13713 }
13714 }
13715
13716 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13717 use proto::log_message::LogLevel;
13718 use proto::rpc_message;
13719 match log_type {
13720 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13721 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13722 LogLevel::Error => MessageType::ERROR,
13723 LogLevel::Warning => MessageType::WARNING,
13724 LogLevel::Info => MessageType::INFO,
13725 LogLevel::Log => MessageType::LOG,
13726 },
13727 ),
13728 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13729 verbose_info: trace_message.verbose_info,
13730 },
13731 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13732 received: match rpc_message::Kind::from_i32(message.kind)
13733 .unwrap_or(rpc_message::Kind::Received)
13734 {
13735 rpc_message::Kind::Received => true,
13736 rpc_message::Kind::Sent => false,
13737 },
13738 },
13739 }
13740 }
13741}
13742
13743pub struct WorkspaceRefreshTask {
13744 refresh_tx: mpsc::Sender<()>,
13745 progress_tx: mpsc::Sender<()>,
13746 #[allow(dead_code)]
13747 task: Task<()>,
13748}
13749
13750pub enum LanguageServerState {
13751 Starting {
13752 startup: Task<Option<Arc<LanguageServer>>>,
13753 /// List of language servers that will be added to the workspace once it's initialization completes.
13754 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13755 },
13756
13757 Running {
13758 adapter: Arc<CachedLspAdapter>,
13759 server: Arc<LanguageServer>,
13760 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13761 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13762 },
13763}
13764
13765impl LanguageServerState {
13766 fn add_workspace_folder(&self, uri: Uri) {
13767 match self {
13768 LanguageServerState::Starting {
13769 pending_workspace_folders,
13770 ..
13771 } => {
13772 pending_workspace_folders.lock().insert(uri);
13773 }
13774 LanguageServerState::Running { server, .. } => {
13775 server.add_workspace_folder(uri);
13776 }
13777 }
13778 }
13779 fn _remove_workspace_folder(&self, uri: Uri) {
13780 match self {
13781 LanguageServerState::Starting {
13782 pending_workspace_folders,
13783 ..
13784 } => {
13785 pending_workspace_folders.lock().remove(&uri);
13786 }
13787 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13788 }
13789 }
13790}
13791
13792impl std::fmt::Debug for LanguageServerState {
13793 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13794 match self {
13795 LanguageServerState::Starting { .. } => {
13796 f.debug_struct("LanguageServerState::Starting").finish()
13797 }
13798 LanguageServerState::Running { .. } => {
13799 f.debug_struct("LanguageServerState::Running").finish()
13800 }
13801 }
13802 }
13803}
13804
13805#[derive(Clone, Debug, Serialize)]
13806pub struct LanguageServerProgress {
13807 pub is_disk_based_diagnostics_progress: bool,
13808 pub is_cancellable: bool,
13809 pub title: Option<String>,
13810 pub message: Option<String>,
13811 pub percentage: Option<usize>,
13812 #[serde(skip_serializing)]
13813 pub last_update_at: Instant,
13814}
13815
13816#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13817pub struct DiagnosticSummary {
13818 pub error_count: usize,
13819 pub warning_count: usize,
13820}
13821
13822impl DiagnosticSummary {
13823 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13824 let mut this = Self {
13825 error_count: 0,
13826 warning_count: 0,
13827 };
13828
13829 for entry in diagnostics {
13830 if entry.diagnostic.is_primary {
13831 match entry.diagnostic.severity {
13832 DiagnosticSeverity::ERROR => this.error_count += 1,
13833 DiagnosticSeverity::WARNING => this.warning_count += 1,
13834 _ => {}
13835 }
13836 }
13837 }
13838
13839 this
13840 }
13841
13842 pub fn is_empty(&self) -> bool {
13843 self.error_count == 0 && self.warning_count == 0
13844 }
13845
13846 pub fn to_proto(
13847 self,
13848 language_server_id: LanguageServerId,
13849 path: &RelPath,
13850 ) -> proto::DiagnosticSummary {
13851 proto::DiagnosticSummary {
13852 path: path.to_proto(),
13853 language_server_id: language_server_id.0 as u64,
13854 error_count: self.error_count as u32,
13855 warning_count: self.warning_count as u32,
13856 }
13857 }
13858}
13859
13860#[derive(Clone, Debug)]
13861pub enum CompletionDocumentation {
13862 /// There is no documentation for this completion.
13863 Undocumented,
13864 /// A single line of documentation.
13865 SingleLine(SharedString),
13866 /// Multiple lines of plain text documentation.
13867 MultiLinePlainText(SharedString),
13868 /// Markdown documentation.
13869 MultiLineMarkdown(SharedString),
13870 /// Both single line and multiple lines of plain text documentation.
13871 SingleLineAndMultiLinePlainText {
13872 single_line: SharedString,
13873 plain_text: Option<SharedString>,
13874 },
13875}
13876
13877impl CompletionDocumentation {
13878 #[cfg(any(test, feature = "test-support"))]
13879 pub fn text(&self) -> SharedString {
13880 match self {
13881 CompletionDocumentation::Undocumented => "".into(),
13882 CompletionDocumentation::SingleLine(s) => s.clone(),
13883 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13884 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13885 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13886 single_line.clone()
13887 }
13888 }
13889 }
13890}
13891
13892impl From<lsp::Documentation> for CompletionDocumentation {
13893 fn from(docs: lsp::Documentation) -> Self {
13894 match docs {
13895 lsp::Documentation::String(text) => {
13896 if text.lines().count() <= 1 {
13897 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13898 } else {
13899 CompletionDocumentation::MultiLinePlainText(text.into())
13900 }
13901 }
13902
13903 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13904 lsp::MarkupKind::PlainText => {
13905 if value.lines().count() <= 1 {
13906 CompletionDocumentation::SingleLine(value.into())
13907 } else {
13908 CompletionDocumentation::MultiLinePlainText(value.into())
13909 }
13910 }
13911
13912 lsp::MarkupKind::Markdown => {
13913 CompletionDocumentation::MultiLineMarkdown(value.into())
13914 }
13915 },
13916 }
13917 }
13918}
13919
13920pub enum ResolvedHint {
13921 Resolved(InlayHint),
13922 Resolving(Shared<Task<()>>),
13923}
13924
13925pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13926 glob.components()
13927 .take_while(|component| match component {
13928 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13929 _ => true,
13930 })
13931 .collect()
13932}
13933
13934pub struct SshLspAdapter {
13935 name: LanguageServerName,
13936 binary: LanguageServerBinary,
13937 initialization_options: Option<String>,
13938 code_action_kinds: Option<Vec<CodeActionKind>>,
13939}
13940
13941impl SshLspAdapter {
13942 pub fn new(
13943 name: LanguageServerName,
13944 binary: LanguageServerBinary,
13945 initialization_options: Option<String>,
13946 code_action_kinds: Option<String>,
13947 ) -> Self {
13948 Self {
13949 name,
13950 binary,
13951 initialization_options,
13952 code_action_kinds: code_action_kinds
13953 .as_ref()
13954 .and_then(|c| serde_json::from_str(c).ok()),
13955 }
13956 }
13957}
13958
13959impl LspInstaller for SshLspAdapter {
13960 type BinaryVersion = ();
13961 async fn check_if_user_installed(
13962 &self,
13963 _: &dyn LspAdapterDelegate,
13964 _: Option<Toolchain>,
13965 _: &AsyncApp,
13966 ) -> Option<LanguageServerBinary> {
13967 Some(self.binary.clone())
13968 }
13969
13970 async fn cached_server_binary(
13971 &self,
13972 _: PathBuf,
13973 _: &dyn LspAdapterDelegate,
13974 ) -> Option<LanguageServerBinary> {
13975 None
13976 }
13977
13978 async fn fetch_latest_server_version(
13979 &self,
13980 _: &dyn LspAdapterDelegate,
13981 _: bool,
13982 _: &mut AsyncApp,
13983 ) -> Result<()> {
13984 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13985 }
13986
13987 async fn fetch_server_binary(
13988 &self,
13989 _: (),
13990 _: PathBuf,
13991 _: &dyn LspAdapterDelegate,
13992 ) -> Result<LanguageServerBinary> {
13993 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13994 }
13995}
13996
13997#[async_trait(?Send)]
13998impl LspAdapter for SshLspAdapter {
13999 fn name(&self) -> LanguageServerName {
14000 self.name.clone()
14001 }
14002
14003 async fn initialization_options(
14004 self: Arc<Self>,
14005 _: &Arc<dyn LspAdapterDelegate>,
14006 _: &mut AsyncApp,
14007 ) -> Result<Option<serde_json::Value>> {
14008 let Some(options) = &self.initialization_options else {
14009 return Ok(None);
14010 };
14011 let result = serde_json::from_str(options)?;
14012 Ok(result)
14013 }
14014
14015 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14016 self.code_action_kinds.clone()
14017 }
14018}
14019
14020pub fn language_server_settings<'a>(
14021 delegate: &'a dyn LspAdapterDelegate,
14022 language: &LanguageServerName,
14023 cx: &'a App,
14024) -> Option<&'a LspSettings> {
14025 language_server_settings_for(
14026 SettingsLocation {
14027 worktree_id: delegate.worktree_id(),
14028 path: RelPath::empty(),
14029 },
14030 language,
14031 cx,
14032 )
14033}
14034
14035pub fn language_server_settings_for<'a>(
14036 location: SettingsLocation<'a>,
14037 language: &LanguageServerName,
14038 cx: &'a App,
14039) -> Option<&'a LspSettings> {
14040 ProjectSettings::get(Some(location), cx).lsp.get(language)
14041}
14042
14043pub struct LocalLspAdapterDelegate {
14044 lsp_store: WeakEntity<LspStore>,
14045 worktree: worktree::Snapshot,
14046 fs: Arc<dyn Fs>,
14047 http_client: Arc<dyn HttpClient>,
14048 language_registry: Arc<LanguageRegistry>,
14049 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14050}
14051
14052impl LocalLspAdapterDelegate {
14053 pub fn new(
14054 language_registry: Arc<LanguageRegistry>,
14055 environment: &Entity<ProjectEnvironment>,
14056 lsp_store: WeakEntity<LspStore>,
14057 worktree: &Entity<Worktree>,
14058 http_client: Arc<dyn HttpClient>,
14059 fs: Arc<dyn Fs>,
14060 cx: &mut App,
14061 ) -> Arc<Self> {
14062 let load_shell_env_task =
14063 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14064
14065 Arc::new(Self {
14066 lsp_store,
14067 worktree: worktree.read(cx).snapshot(),
14068 fs,
14069 http_client,
14070 language_registry,
14071 load_shell_env_task,
14072 })
14073 }
14074
14075 pub fn from_local_lsp(
14076 local: &LocalLspStore,
14077 worktree: &Entity<Worktree>,
14078 cx: &mut App,
14079 ) -> Arc<Self> {
14080 Self::new(
14081 local.languages.clone(),
14082 &local.environment,
14083 local.weak.clone(),
14084 worktree,
14085 local.http_client.clone(),
14086 local.fs.clone(),
14087 cx,
14088 )
14089 }
14090}
14091
14092#[async_trait]
14093impl LspAdapterDelegate for LocalLspAdapterDelegate {
14094 fn show_notification(&self, message: &str, cx: &mut App) {
14095 self.lsp_store
14096 .update(cx, |_, cx| {
14097 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14098 })
14099 .ok();
14100 }
14101
14102 fn http_client(&self) -> Arc<dyn HttpClient> {
14103 self.http_client.clone()
14104 }
14105
14106 fn worktree_id(&self) -> WorktreeId {
14107 self.worktree.id()
14108 }
14109
14110 fn worktree_root_path(&self) -> &Path {
14111 self.worktree.abs_path().as_ref()
14112 }
14113
14114 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14115 self.worktree.resolve_relative_path(path)
14116 }
14117
14118 async fn shell_env(&self) -> HashMap<String, String> {
14119 let task = self.load_shell_env_task.clone();
14120 task.await.unwrap_or_default()
14121 }
14122
14123 async fn npm_package_installed_version(
14124 &self,
14125 package_name: &str,
14126 ) -> Result<Option<(PathBuf, Version)>> {
14127 let local_package_directory = self.worktree_root_path();
14128 let node_modules_directory = local_package_directory.join("node_modules");
14129
14130 if let Some(version) =
14131 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14132 {
14133 return Ok(Some((node_modules_directory, version)));
14134 }
14135 let Some(npm) = self.which("npm".as_ref()).await else {
14136 log::warn!(
14137 "Failed to find npm executable for {:?}",
14138 local_package_directory
14139 );
14140 return Ok(None);
14141 };
14142
14143 let env = self.shell_env().await;
14144 let output = util::command::new_command(&npm)
14145 .args(["root", "-g"])
14146 .envs(env)
14147 .current_dir(local_package_directory)
14148 .output()
14149 .await?;
14150 let global_node_modules =
14151 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14152
14153 if let Some(version) =
14154 read_package_installed_version(global_node_modules.clone(), package_name).await?
14155 {
14156 return Ok(Some((global_node_modules, version)));
14157 }
14158 return Ok(None);
14159 }
14160
14161 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14162 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14163 if self.fs.is_file(&worktree_abs_path).await {
14164 worktree_abs_path.pop();
14165 }
14166
14167 let env = self.shell_env().await;
14168
14169 let shell_path = env.get("PATH").cloned();
14170
14171 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14172 }
14173
14174 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14175 let mut working_dir = self.worktree_root_path().to_path_buf();
14176 if self.fs.is_file(&working_dir).await {
14177 working_dir.pop();
14178 }
14179 let output = util::command::new_command(&command.path)
14180 .args(command.arguments)
14181 .envs(command.env.clone().unwrap_or_default())
14182 .current_dir(working_dir)
14183 .output()
14184 .await?;
14185
14186 anyhow::ensure!(
14187 output.status.success(),
14188 "{}, stdout: {:?}, stderr: {:?}",
14189 output.status,
14190 String::from_utf8_lossy(&output.stdout),
14191 String::from_utf8_lossy(&output.stderr)
14192 );
14193 Ok(())
14194 }
14195
14196 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14197 self.language_registry
14198 .update_lsp_binary_status(server_name, status);
14199 }
14200
14201 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14202 self.language_registry
14203 .all_lsp_adapters()
14204 .into_iter()
14205 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14206 .collect()
14207 }
14208
14209 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14210 let dir = self.language_registry.language_server_download_dir(name)?;
14211
14212 if !dir.exists() {
14213 smol::fs::create_dir_all(&dir)
14214 .await
14215 .context("failed to create container directory")
14216 .log_err()?;
14217 }
14218
14219 Some(dir)
14220 }
14221
14222 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14223 let entry = self
14224 .worktree
14225 .entry_for_path(path)
14226 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14227 let abs_path = self.worktree.absolutize(&entry.path);
14228 self.fs.load(&abs_path).await
14229 }
14230}
14231
14232async fn populate_labels_for_symbols(
14233 symbols: Vec<CoreSymbol>,
14234 language_registry: &Arc<LanguageRegistry>,
14235 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14236 output: &mut Vec<Symbol>,
14237) {
14238 #[allow(clippy::mutable_key_type)]
14239 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14240
14241 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14242 for symbol in symbols {
14243 let Some(file_name) = symbol.path.file_name() else {
14244 continue;
14245 };
14246 let language = language_registry
14247 .load_language_for_file_path(Path::new(file_name))
14248 .await
14249 .ok()
14250 .or_else(|| {
14251 unknown_paths.insert(file_name.into());
14252 None
14253 });
14254 symbols_by_language
14255 .entry(language)
14256 .or_default()
14257 .push(symbol);
14258 }
14259
14260 for unknown_path in unknown_paths {
14261 log::info!("no language found for symbol in file {unknown_path:?}");
14262 }
14263
14264 let mut label_params = Vec::new();
14265 for (language, mut symbols) in symbols_by_language {
14266 label_params.clear();
14267 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14268 name: mem::take(&mut symbol.name),
14269 kind: symbol.kind,
14270 container_name: symbol.container_name.take(),
14271 }));
14272
14273 let mut labels = Vec::new();
14274 if let Some(language) = language {
14275 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14276 language_registry
14277 .lsp_adapters(&language.name())
14278 .first()
14279 .cloned()
14280 });
14281 if let Some(lsp_adapter) = lsp_adapter {
14282 labels = lsp_adapter
14283 .labels_for_symbols(&label_params, &language)
14284 .await
14285 .log_err()
14286 .unwrap_or_default();
14287 }
14288 }
14289
14290 for (
14291 (
14292 symbol,
14293 language::Symbol {
14294 name,
14295 container_name,
14296 ..
14297 },
14298 ),
14299 label,
14300 ) in symbols
14301 .into_iter()
14302 .zip(label_params.drain(..))
14303 .zip(labels.into_iter().chain(iter::repeat(None)))
14304 {
14305 output.push(Symbol {
14306 language_server_name: symbol.language_server_name,
14307 source_worktree_id: symbol.source_worktree_id,
14308 source_language_server_id: symbol.source_language_server_id,
14309 path: symbol.path,
14310 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14311 name,
14312 kind: symbol.kind,
14313 range: symbol.range,
14314 container_name,
14315 });
14316 }
14317 }
14318}
14319
14320pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14321 text.lines()
14322 .map(|line| line.trim())
14323 .filter(|line| !line.is_empty())
14324 .join(separator)
14325}
14326
14327fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14328 match server.capabilities().text_document_sync.as_ref()? {
14329 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14330 // Server wants didSave but didn't specify includeText.
14331 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14332 // Server doesn't want didSave at all.
14333 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14334 // Server provided SaveOptions.
14335 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14336 Some(save_options.include_text.unwrap_or(false))
14337 }
14338 },
14339 // We do not have any save info. Kind affects didChange only.
14340 lsp::TextDocumentSyncCapability::Kind(_) => None,
14341 }
14342}
14343
14344/// Completion items are displayed in a `UniformList`.
14345/// Usually, those items are single-line strings, but in LSP responses,
14346/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14347/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14348/// 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,
14349/// breaking the completions menu presentation.
14350///
14351/// 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.
14352pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14353 let mut new_text = String::with_capacity(label.text.len());
14354 let mut offset_map = vec![0; label.text.len() + 1];
14355 let mut last_char_was_space = false;
14356 let mut new_idx = 0;
14357 let chars = label.text.char_indices().fuse();
14358 let mut newlines_removed = false;
14359
14360 for (idx, c) in chars {
14361 offset_map[idx] = new_idx;
14362
14363 match c {
14364 '\n' if last_char_was_space => {
14365 newlines_removed = true;
14366 }
14367 '\t' | ' ' if last_char_was_space => {}
14368 '\n' if !last_char_was_space => {
14369 new_text.push(' ');
14370 new_idx += 1;
14371 last_char_was_space = true;
14372 newlines_removed = true;
14373 }
14374 ' ' | '\t' => {
14375 new_text.push(' ');
14376 new_idx += 1;
14377 last_char_was_space = true;
14378 }
14379 _ => {
14380 new_text.push(c);
14381 new_idx += c.len_utf8();
14382 last_char_was_space = false;
14383 }
14384 }
14385 }
14386 offset_map[label.text.len()] = new_idx;
14387
14388 // Only modify the label if newlines were removed.
14389 if !newlines_removed {
14390 return;
14391 }
14392
14393 let last_index = new_idx;
14394 let mut run_ranges_errors = Vec::new();
14395 label.runs.retain_mut(|(range, _)| {
14396 match offset_map.get(range.start) {
14397 Some(&start) => range.start = start,
14398 None => {
14399 run_ranges_errors.push(range.clone());
14400 return false;
14401 }
14402 }
14403
14404 match offset_map.get(range.end) {
14405 Some(&end) => range.end = end,
14406 None => {
14407 run_ranges_errors.push(range.clone());
14408 range.end = last_index;
14409 }
14410 }
14411 true
14412 });
14413 if !run_ranges_errors.is_empty() {
14414 log::error!(
14415 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14416 label.text
14417 );
14418 }
14419
14420 let mut wrong_filter_range = None;
14421 if label.filter_range == (0..label.text.len()) {
14422 label.filter_range = 0..new_text.len();
14423 } else {
14424 let mut original_filter_range = Some(label.filter_range.clone());
14425 match offset_map.get(label.filter_range.start) {
14426 Some(&start) => label.filter_range.start = start,
14427 None => {
14428 wrong_filter_range = original_filter_range.take();
14429 label.filter_range.start = last_index;
14430 }
14431 }
14432
14433 match offset_map.get(label.filter_range.end) {
14434 Some(&end) => label.filter_range.end = end,
14435 None => {
14436 wrong_filter_range = original_filter_range.take();
14437 label.filter_range.end = last_index;
14438 }
14439 }
14440 }
14441 if let Some(wrong_filter_range) = wrong_filter_range {
14442 log::error!(
14443 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14444 label.text
14445 );
14446 }
14447
14448 label.text = new_text;
14449}