1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
77 Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 language_settings,
81 },
82 point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153pub use semantic_tokens::{
154 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
155};
156
157pub use worktree::{
158 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
159 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
160};
161
162const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
163pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
164const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
165const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
166static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
167
168#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
169pub enum ProgressToken {
170 Number(i32),
171 String(SharedString),
172}
173
174impl std::fmt::Display for ProgressToken {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Number(number) => write!(f, "{number}"),
178 Self::String(string) => write!(f, "{string}"),
179 }
180 }
181}
182
183impl ProgressToken {
184 fn from_lsp(value: lsp::NumberOrString) -> Self {
185 match value {
186 lsp::NumberOrString::Number(number) => Self::Number(number),
187 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
188 }
189 }
190
191 fn to_lsp(&self) -> lsp::NumberOrString {
192 match self {
193 Self::Number(number) => lsp::NumberOrString::Number(*number),
194 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
195 }
196 }
197
198 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
199 Some(match value.value? {
200 proto::progress_token::Value::Number(number) => Self::Number(number),
201 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
202 })
203 }
204
205 fn to_proto(&self) -> proto::ProgressToken {
206 proto::ProgressToken {
207 value: Some(match self {
208 Self::Number(number) => proto::progress_token::Value::Number(*number),
209 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
210 }),
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum FormatTrigger {
217 Save,
218 Manual,
219}
220
221pub enum LspFormatTarget {
222 Buffers,
223 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
228
229struct OpenLspBuffer(Entity<Buffer>);
230
231impl FormatTrigger {
232 fn from_proto(value: i32) -> FormatTrigger {
233 match value {
234 0 => FormatTrigger::Save,
235 1 => FormatTrigger::Manual,
236 _ => FormatTrigger::Save,
237 }
238 }
239}
240
241#[derive(Clone)]
242struct UnifiedLanguageServer {
243 id: LanguageServerId,
244 project_roots: HashSet<Arc<RelPath>>,
245}
246
247/// Settings that affect language server identity.
248///
249/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
250/// updated via `workspace/didChangeConfiguration` without restarting the server.
251#[derive(Clone, Debug, Hash, PartialEq, Eq)]
252struct LanguageServerSeedSettings {
253 binary: Option<BinarySettings>,
254 initialization_options: Option<serde_json::Value>,
255}
256
257#[derive(Clone, Debug, Hash, PartialEq, Eq)]
258struct LanguageServerSeed {
259 worktree_id: WorktreeId,
260 name: LanguageServerName,
261 toolchain: Option<Toolchain>,
262 settings: LanguageServerSeedSettings,
263}
264
265#[derive(Debug)]
266pub struct DocumentDiagnosticsUpdate<'a, D> {
267 pub diagnostics: D,
268 pub result_id: Option<SharedString>,
269 pub registration_id: Option<SharedString>,
270 pub server_id: LanguageServerId,
271 pub disk_based_sources: Cow<'a, [String]>,
272}
273
274pub struct DocumentDiagnostics {
275 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 document_abs_path: PathBuf,
277 version: Option<i32>,
278}
279
280#[derive(Default, Debug)]
281struct DynamicRegistrations {
282 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
283 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
284}
285
286pub struct LocalLspStore {
287 weak: WeakEntity<LspStore>,
288 pub worktree_store: Entity<WorktreeStore>,
289 toolchain_store: Entity<LocalToolchainStore>,
290 http_client: Arc<dyn HttpClient>,
291 environment: Entity<ProjectEnvironment>,
292 fs: Arc<dyn Fs>,
293 languages: Arc<LanguageRegistry>,
294 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
295 yarn: Entity<YarnPathStore>,
296 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
297 buffers_being_formatted: HashSet<BufferId>,
298 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
299 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
300 watched_manifest_filenames: HashSet<ManifestName>,
301 language_server_paths_watched_for_rename:
302 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
303 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
304 supplementary_language_servers:
305 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
306 prettier_store: Entity<PrettierStore>,
307 next_diagnostic_group_id: usize,
308 diagnostics: HashMap<
309 WorktreeId,
310 HashMap<
311 Arc<RelPath>,
312 Vec<(
313 LanguageServerId,
314 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
315 )>,
316 >,
317 >,
318 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
319 _subscription: gpui::Subscription,
320 lsp_tree: LanguageServerTree,
321 registered_buffers: HashMap<BufferId, usize>,
322 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
323 buffer_pull_diagnostics_result_ids: HashMap<
324 LanguageServerId,
325 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
326 >,
327 workspace_pull_diagnostics_result_ids: HashMap<
328 LanguageServerId,
329 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
330 >,
331 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
332
333 buffers_to_refresh_hash_set: HashSet<BufferId>,
334 buffers_to_refresh_queue: VecDeque<BufferId>,
335 _background_diagnostics_worker: Shared<Task<()>>,
336}
337
338impl LocalLspStore {
339 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
340 pub fn running_language_server_for_id(
341 &self,
342 id: LanguageServerId,
343 ) -> Option<&Arc<LanguageServer>> {
344 let language_server_state = self.language_servers.get(&id)?;
345
346 match language_server_state {
347 LanguageServerState::Running { server, .. } => Some(server),
348 LanguageServerState::Starting { .. } => None,
349 }
350 }
351
352 fn get_or_insert_language_server(
353 &mut self,
354 worktree_handle: &Entity<Worktree>,
355 delegate: Arc<LocalLspAdapterDelegate>,
356 disposition: &Arc<LaunchDisposition>,
357 language_name: &LanguageName,
358 cx: &mut App,
359 ) -> LanguageServerId {
360 let key = LanguageServerSeed {
361 worktree_id: worktree_handle.read(cx).id(),
362 name: disposition.server_name.clone(),
363 settings: LanguageServerSeedSettings {
364 binary: disposition.settings.binary.clone(),
365 initialization_options: disposition.settings.initialization_options.clone(),
366 },
367 toolchain: disposition.toolchain.clone(),
368 };
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 state.id
372 } else {
373 let adapter = self
374 .languages
375 .lsp_adapters(language_name)
376 .into_iter()
377 .find(|adapter| adapter.name() == disposition.server_name)
378 .expect("To find LSP adapter");
379 let new_language_server_id = self.start_language_server(
380 worktree_handle,
381 delegate,
382 adapter,
383 disposition.settings.clone(),
384 key.clone(),
385 language_name.clone(),
386 cx,
387 );
388 if let Some(state) = self.language_server_ids.get_mut(&key) {
389 state.project_roots.insert(disposition.path.path.clone());
390 } else {
391 debug_assert!(
392 false,
393 "Expected `start_language_server` to ensure that `key` exists in a map"
394 );
395 }
396 new_language_server_id
397 }
398 }
399
400 fn start_language_server(
401 &mut self,
402 worktree_handle: &Entity<Worktree>,
403 delegate: Arc<LocalLspAdapterDelegate>,
404 adapter: Arc<CachedLspAdapter>,
405 settings: Arc<LspSettings>,
406 key: LanguageServerSeed,
407 language_name: LanguageName,
408 cx: &mut App,
409 ) -> LanguageServerId {
410 let worktree = worktree_handle.read(cx);
411
412 let worktree_id = worktree.id();
413 let worktree_abs_path = worktree.abs_path();
414 let toolchain = key.toolchain.clone();
415 let override_options = settings.initialization_options.clone();
416
417 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
418
419 let server_id = self.languages.next_language_server_id();
420 log::trace!(
421 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
422 adapter.name.0
423 );
424
425 let wait_until_worktree_trust =
426 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
427 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
428 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
429 });
430 if can_trust {
431 self.restricted_worktrees_tasks.remove(&worktree_id);
432 None
433 } else {
434 match self.restricted_worktrees_tasks.entry(worktree_id) {
435 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
436 hash_map::Entry::Vacant(v) => {
437 let (mut tx, rx) = watch::channel::<bool>();
438 let lsp_store = self.weak.clone();
439 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
440 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
441 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
442 tx.blocking_send(true).ok();
443 lsp_store
444 .update(cx, |lsp_store, _| {
445 if let Some(local_lsp_store) =
446 lsp_store.as_local_mut()
447 {
448 local_lsp_store
449 .restricted_worktrees_tasks
450 .remove(&worktree_id);
451 }
452 })
453 .ok();
454 }
455 }
456 });
457 v.insert((subscription, rx.clone()));
458 Some(rx)
459 }
460 }
461 }
462 });
463 let update_binary_status = wait_until_worktree_trust.is_none();
464
465 let binary = self.get_language_server_binary(
466 worktree_abs_path.clone(),
467 adapter.clone(),
468 settings,
469 toolchain.clone(),
470 delegate.clone(),
471 true,
472 wait_until_worktree_trust,
473 cx,
474 );
475 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
476
477 let pending_server = cx.spawn({
478 let adapter = adapter.clone();
479 let server_name = adapter.name.clone();
480 let stderr_capture = stderr_capture.clone();
481 #[cfg(any(test, feature = "test-support"))]
482 let lsp_store = self.weak.clone();
483 let pending_workspace_folders = pending_workspace_folders.clone();
484 async move |cx| {
485 let binary = binary.await?;
486 #[cfg(any(test, feature = "test-support"))]
487 if let Some(server) = lsp_store
488 .update(&mut cx.clone(), |this, cx| {
489 this.languages.create_fake_language_server(
490 server_id,
491 &server_name,
492 binary.clone(),
493 &mut cx.to_async(),
494 )
495 })
496 .ok()
497 .flatten()
498 {
499 return Ok(server);
500 }
501
502 let code_action_kinds = adapter.code_action_kinds();
503 lsp::LanguageServer::new(
504 stderr_capture,
505 server_id,
506 server_name,
507 binary,
508 &worktree_abs_path,
509 code_action_kinds,
510 Some(pending_workspace_folders),
511 cx,
512 )
513 }
514 });
515
516 let startup = {
517 let server_name = adapter.name.0.clone();
518 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
519 let key = key.clone();
520 let adapter = adapter.clone();
521 let lsp_store = self.weak.clone();
522 let pending_workspace_folders = pending_workspace_folders.clone();
523 let pull_diagnostics = ProjectSettings::get_global(cx)
524 .diagnostics
525 .lsp_pull_diagnostics
526 .enabled;
527 let settings_location = SettingsLocation {
528 worktree_id,
529 path: RelPath::empty(),
530 };
531 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
532 .language(Some(settings_location), Some(&language_name), cx)
533 .semantic_tokens
534 .use_tree_sitter();
535 cx.spawn(async move |cx| {
536 let result = async {
537 let language_server = pending_server.await?;
538
539 let workspace_config = Self::workspace_configuration_for_adapter(
540 adapter.adapter.clone(),
541 &delegate,
542 toolchain,
543 None,
544 cx,
545 )
546 .await?;
547
548 let mut initialization_options = Self::initialization_options_for_adapter(
549 adapter.adapter.clone(),
550 &delegate,
551 cx,
552 )
553 .await?;
554
555 match (&mut initialization_options, override_options) {
556 (Some(initialization_options), Some(override_options)) => {
557 merge_json_value_into(override_options, initialization_options);
558 }
559 (None, override_options) => initialization_options = override_options,
560 _ => {}
561 }
562
563 let initialization_params = cx.update(|cx| {
564 let mut params = language_server.default_initialize_params(
565 pull_diagnostics,
566 augments_syntax_tokens,
567 cx,
568 );
569 params.initialization_options = initialization_options;
570 adapter.adapter.prepare_initialize_params(params, cx)
571 })?;
572
573 Self::setup_lsp_messages(
574 lsp_store.clone(),
575 &language_server,
576 delegate.clone(),
577 adapter.clone(),
578 );
579
580 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
581 settings: workspace_config,
582 };
583 let language_server = cx
584 .update(|cx| {
585 let request_timeout = ProjectSettings::get_global(cx)
586 .global_lsp_settings
587 .get_request_timeout();
588
589 language_server.initialize(
590 initialization_params,
591 Arc::new(did_change_configuration_params.clone()),
592 request_timeout,
593 cx,
594 )
595 })
596 .await
597 .inspect_err(|_| {
598 if let Some(lsp_store) = lsp_store.upgrade() {
599 lsp_store.update(cx, |lsp_store, cx| {
600 lsp_store.cleanup_lsp_data(server_id);
601 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
602 });
603 }
604 })?;
605
606 language_server.notify::<lsp::notification::DidChangeConfiguration>(
607 did_change_configuration_params,
608 )?;
609
610 anyhow::Ok(language_server)
611 }
612 .await;
613
614 match result {
615 Ok(server) => {
616 lsp_store
617 .update(cx, |lsp_store, cx| {
618 lsp_store.insert_newly_running_language_server(
619 adapter,
620 server.clone(),
621 server_id,
622 key,
623 pending_workspace_folders,
624 cx,
625 );
626 })
627 .ok();
628 stderr_capture.lock().take();
629 Some(server)
630 }
631
632 Err(err) => {
633 let log = stderr_capture.lock().take().unwrap_or_default();
634 delegate.update_status(
635 adapter.name(),
636 BinaryStatus::Failed {
637 error: if log.is_empty() {
638 format!("{err:#}")
639 } else {
640 format!("{err:#}\n-- stderr --\n{log}")
641 },
642 },
643 );
644 log::error!(
645 "Failed to start language server {server_name:?}: {}",
646 redact_command(&format!("{err:?}"))
647 );
648 if !log.is_empty() {
649 log::error!("server stderr: {}", redact_command(&log));
650 }
651 None
652 }
653 }
654 })
655 };
656 let state = LanguageServerState::Starting {
657 startup,
658 pending_workspace_folders,
659 };
660
661 if update_binary_status {
662 self.languages
663 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
664 }
665
666 self.language_servers.insert(server_id, state);
667 self.language_server_ids
668 .entry(key)
669 .or_insert(UnifiedLanguageServer {
670 id: server_id,
671 project_roots: Default::default(),
672 });
673 server_id
674 }
675
676 fn get_language_server_binary(
677 &self,
678 worktree_abs_path: Arc<Path>,
679 adapter: Arc<CachedLspAdapter>,
680 settings: Arc<LspSettings>,
681 toolchain: Option<Toolchain>,
682 delegate: Arc<dyn LspAdapterDelegate>,
683 allow_binary_download: bool,
684 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
685 cx: &mut App,
686 ) -> Task<Result<LanguageServerBinary>> {
687 if let Some(settings) = &settings.binary
688 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
689 {
690 let settings = settings.clone();
691 let languages = self.languages.clone();
692 return cx.background_spawn(async move {
693 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
694 let already_trusted = *wait_until_worktree_trust.borrow();
695 if !already_trusted {
696 log::info!(
697 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
698 adapter.name(),
699 );
700 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
701 if worktree_trusted {
702 break;
703 }
704 }
705 log::info!(
706 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
707 adapter.name(),
708 );
709 }
710 languages
711 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
712 }
713 let mut env = delegate.shell_env().await;
714 env.extend(settings.env.unwrap_or_default());
715
716 Ok(LanguageServerBinary {
717 path: delegate.resolve_relative_path(path),
718 env: Some(env),
719 arguments: settings
720 .arguments
721 .unwrap_or_default()
722 .iter()
723 .map(Into::into)
724 .collect(),
725 })
726 });
727 }
728 let lsp_binary_options = LanguageServerBinaryOptions {
729 allow_path_lookup: !settings
730 .binary
731 .as_ref()
732 .and_then(|b| b.ignore_system_version)
733 .unwrap_or_default(),
734 allow_binary_download,
735 pre_release: settings
736 .fetch
737 .as_ref()
738 .and_then(|f| f.pre_release)
739 .unwrap_or(false),
740 };
741
742 cx.spawn(async move |cx| {
743 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
744 let already_trusted = *wait_until_worktree_trust.borrow();
745 if !already_trusted {
746 log::info!(
747 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
748 adapter.name(),
749 );
750 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
751 if worktree_trusted {
752 break;
753 }
754 }
755 log::info!(
756 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
757 adapter.name(),
758 );
759 }
760 }
761
762 let (existing_binary, maybe_download_binary) = adapter
763 .clone()
764 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
765 .await
766 .await;
767
768 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
769
770 let mut binary = match (existing_binary, maybe_download_binary) {
771 (binary, None) => binary?,
772 (Err(_), Some(downloader)) => downloader.await?,
773 (Ok(existing_binary), Some(downloader)) => {
774 let mut download_timeout = cx
775 .background_executor()
776 .timer(SERVER_DOWNLOAD_TIMEOUT)
777 .fuse();
778 let mut downloader = downloader.fuse();
779 futures::select! {
780 _ = download_timeout => {
781 // Return existing binary and kick the existing work to the background.
782 cx.spawn(async move |_| downloader.await).detach();
783 Ok(existing_binary)
784 },
785 downloaded_or_existing_binary = downloader => {
786 // If download fails, this results in the existing binary.
787 downloaded_or_existing_binary
788 }
789 }?
790 }
791 };
792 let mut shell_env = delegate.shell_env().await;
793
794 shell_env.extend(binary.env.unwrap_or_default());
795
796 if let Some(settings) = settings.binary.as_ref() {
797 if let Some(arguments) = &settings.arguments {
798 binary.arguments = arguments.iter().map(Into::into).collect();
799 }
800 if let Some(env) = &settings.env {
801 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
802 }
803 }
804
805 binary.env = Some(shell_env);
806 Ok(binary)
807 })
808 }
809
810 fn setup_lsp_messages(
811 lsp_store: WeakEntity<LspStore>,
812 language_server: &LanguageServer,
813 delegate: Arc<dyn LspAdapterDelegate>,
814 adapter: Arc<CachedLspAdapter>,
815 ) {
816 let name = language_server.name();
817 let server_id = language_server.server_id();
818 language_server
819 .on_notification::<lsp::notification::PublishDiagnostics, _>({
820 let adapter = adapter.clone();
821 let this = lsp_store.clone();
822 move |mut params, cx| {
823 let adapter = adapter.clone();
824 if let Some(this) = this.upgrade() {
825 this.update(cx, |this, cx| {
826 {
827 let buffer = params
828 .uri
829 .to_file_path()
830 .map(|file_path| this.get_buffer(&file_path, cx))
831 .ok()
832 .flatten();
833 adapter.process_diagnostics(&mut params, server_id, buffer);
834 }
835
836 this.merge_lsp_diagnostics(
837 DiagnosticSourceKind::Pushed,
838 vec![DocumentDiagnosticsUpdate {
839 server_id,
840 diagnostics: params,
841 result_id: None,
842 disk_based_sources: Cow::Borrowed(
843 &adapter.disk_based_diagnostic_sources,
844 ),
845 registration_id: None,
846 }],
847 |_, diagnostic, cx| match diagnostic.source_kind {
848 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
849 adapter.retain_old_diagnostic(diagnostic, cx)
850 }
851 DiagnosticSourceKind::Pulled => true,
852 },
853 cx,
854 )
855 .log_err();
856 });
857 }
858 }
859 })
860 .detach();
861 language_server
862 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
863 let adapter = adapter.adapter.clone();
864 let delegate = delegate.clone();
865 let this = lsp_store.clone();
866 move |params, cx| {
867 let adapter = adapter.clone();
868 let delegate = delegate.clone();
869 let this = this.clone();
870 let mut cx = cx.clone();
871 async move {
872 let toolchain_for_id = this
873 .update(&mut cx, |this, _| {
874 this.as_local()?.language_server_ids.iter().find_map(
875 |(seed, value)| {
876 (value.id == server_id).then(|| seed.toolchain.clone())
877 },
878 )
879 })?
880 .context("Expected the LSP store to be in a local mode")?;
881
882 let mut scope_uri_to_workspace_config = BTreeMap::new();
883 for item in ¶ms.items {
884 let scope_uri = item.scope_uri.clone();
885 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
886 scope_uri_to_workspace_config.entry(scope_uri.clone())
887 else {
888 // We've already queried workspace configuration of this URI.
889 continue;
890 };
891 let workspace_config = Self::workspace_configuration_for_adapter(
892 adapter.clone(),
893 &delegate,
894 toolchain_for_id.clone(),
895 scope_uri,
896 &mut cx,
897 )
898 .await?;
899 new_scope_uri.insert(workspace_config);
900 }
901
902 Ok(params
903 .items
904 .into_iter()
905 .filter_map(|item| {
906 let workspace_config =
907 scope_uri_to_workspace_config.get(&item.scope_uri)?;
908 if let Some(section) = &item.section {
909 Some(
910 workspace_config
911 .get(section)
912 .cloned()
913 .unwrap_or(serde_json::Value::Null),
914 )
915 } else {
916 Some(workspace_config.clone())
917 }
918 })
919 .collect())
920 }
921 }
922 })
923 .detach();
924
925 language_server
926 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
927 let this = lsp_store.clone();
928 move |_, cx| {
929 let this = this.clone();
930 let cx = cx.clone();
931 async move {
932 let Some(server) =
933 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
934 else {
935 return Ok(None);
936 };
937 let root = server.workspace_folders();
938 Ok(Some(
939 root.into_iter()
940 .map(|uri| WorkspaceFolder {
941 uri,
942 name: Default::default(),
943 })
944 .collect(),
945 ))
946 }
947 }
948 })
949 .detach();
950 // Even though we don't have handling for these requests, respond to them to
951 // avoid stalling any language server like `gopls` which waits for a response
952 // to these requests when initializing.
953 language_server
954 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
955 let this = lsp_store.clone();
956 move |params, cx| {
957 let this = this.clone();
958 let mut cx = cx.clone();
959 async move {
960 this.update(&mut cx, |this, _| {
961 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
962 {
963 status
964 .progress_tokens
965 .insert(ProgressToken::from_lsp(params.token));
966 }
967 })?;
968
969 Ok(())
970 }
971 }
972 })
973 .detach();
974
975 language_server
976 .on_request::<lsp::request::RegisterCapability, _, _>({
977 let lsp_store = lsp_store.clone();
978 move |params, cx| {
979 let lsp_store = lsp_store.clone();
980 let mut cx = cx.clone();
981 async move {
982 lsp_store
983 .update(&mut cx, |lsp_store, cx| {
984 if lsp_store.as_local().is_some() {
985 match lsp_store
986 .register_server_capabilities(server_id, params, cx)
987 {
988 Ok(()) => {}
989 Err(e) => {
990 log::error!(
991 "Failed to register server capabilities: {e:#}"
992 );
993 }
994 };
995 }
996 })
997 .ok();
998 Ok(())
999 }
1000 }
1001 })
1002 .detach();
1003
1004 language_server
1005 .on_request::<lsp::request::UnregisterCapability, _, _>({
1006 let lsp_store = lsp_store.clone();
1007 move |params, cx| {
1008 let lsp_store = lsp_store.clone();
1009 let mut cx = cx.clone();
1010 async move {
1011 lsp_store
1012 .update(&mut cx, |lsp_store, cx| {
1013 if lsp_store.as_local().is_some() {
1014 match lsp_store
1015 .unregister_server_capabilities(server_id, params, cx)
1016 {
1017 Ok(()) => {}
1018 Err(e) => {
1019 log::error!(
1020 "Failed to unregister server capabilities: {e:#}"
1021 );
1022 }
1023 }
1024 }
1025 })
1026 .ok();
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1035 let this = lsp_store.clone();
1036 move |params, cx| {
1037 let mut cx = cx.clone();
1038 let this = this.clone();
1039 async move {
1040 LocalLspStore::on_lsp_workspace_edit(
1041 this.clone(),
1042 params,
1043 server_id,
1044 &mut cx,
1045 )
1046 .await
1047 }
1048 }
1049 })
1050 .detach();
1051
1052 language_server
1053 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1054 let lsp_store = lsp_store.clone();
1055 let request_id = Arc::new(AtomicUsize::new(0));
1056 move |(), cx| {
1057 let lsp_store = lsp_store.clone();
1058 let request_id = request_id.clone();
1059 let mut cx = cx.clone();
1060 async move {
1061 lsp_store
1062 .update(&mut cx, |lsp_store, cx| {
1063 let request_id =
1064 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1065 cx.emit(LspStoreEvent::RefreshInlayHints {
1066 server_id,
1067 request_id,
1068 });
1069 lsp_store
1070 .downstream_client
1071 .as_ref()
1072 .map(|(client, project_id)| {
1073 client.send(proto::RefreshInlayHints {
1074 project_id: *project_id,
1075 server_id: server_id.to_proto(),
1076 request_id: request_id.map(|id| id as u64),
1077 })
1078 })
1079 })?
1080 .transpose()?;
1081 Ok(())
1082 }
1083 }
1084 })
1085 .detach();
1086
1087 language_server
1088 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1089 let this = lsp_store.clone();
1090 move |(), cx| {
1091 let this = this.clone();
1092 let mut cx = cx.clone();
1093 async move {
1094 this.update(&mut cx, |this, cx| {
1095 cx.emit(LspStoreEvent::RefreshCodeLens);
1096 this.downstream_client.as_ref().map(|(client, project_id)| {
1097 client.send(proto::RefreshCodeLens {
1098 project_id: *project_id,
1099 })
1100 })
1101 })?
1102 .transpose()?;
1103 Ok(())
1104 }
1105 }
1106 })
1107 .detach();
1108
1109 language_server
1110 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1111 let lsp_store = lsp_store.clone();
1112 let request_id = Arc::new(AtomicUsize::new(0));
1113 move |(), cx| {
1114 let lsp_store = lsp_store.clone();
1115 let request_id = request_id.clone();
1116 let mut cx = cx.clone();
1117 async move {
1118 lsp_store
1119 .update(&mut cx, |lsp_store, cx| {
1120 let request_id =
1121 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1122 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1123 server_id,
1124 request_id,
1125 });
1126 lsp_store
1127 .downstream_client
1128 .as_ref()
1129 .map(|(client, project_id)| {
1130 client.send(proto::RefreshSemanticTokens {
1131 project_id: *project_id,
1132 server_id: server_id.to_proto(),
1133 request_id: request_id.map(|id| id as u64),
1134 })
1135 })
1136 })?
1137 .transpose()?;
1138 Ok(())
1139 }
1140 }
1141 })
1142 .detach();
1143
1144 language_server
1145 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1146 let this = lsp_store.clone();
1147 move |(), cx| {
1148 let this = this.clone();
1149 let mut cx = cx.clone();
1150 async move {
1151 this.update(&mut cx, |lsp_store, cx| {
1152 lsp_store.pull_workspace_diagnostics(server_id);
1153 lsp_store
1154 .downstream_client
1155 .as_ref()
1156 .map(|(client, project_id)| {
1157 client.send(proto::PullWorkspaceDiagnostics {
1158 project_id: *project_id,
1159 server_id: server_id.to_proto(),
1160 })
1161 })
1162 .transpose()?;
1163 anyhow::Ok(
1164 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1165 )
1166 })??
1167 .await;
1168 Ok(())
1169 }
1170 }
1171 })
1172 .detach();
1173
1174 language_server
1175 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1176 let this = lsp_store.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 move |params, cx| {
1180 let this = this.clone();
1181 let name = name.to_string();
1182 let adapter = adapter.clone();
1183 let mut cx = cx.clone();
1184 async move {
1185 let actions = params.actions.unwrap_or_default();
1186 let message = params.message.clone();
1187 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1188 let level = match params.typ {
1189 lsp::MessageType::ERROR => PromptLevel::Critical,
1190 lsp::MessageType::WARNING => PromptLevel::Warning,
1191 _ => PromptLevel::Info,
1192 };
1193 let request = LanguageServerPromptRequest::new(
1194 level,
1195 params.message,
1196 actions,
1197 name.clone(),
1198 tx,
1199 );
1200
1201 let did_update = this
1202 .update(&mut cx, |_, cx| {
1203 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1204 })
1205 .is_ok();
1206 if did_update {
1207 let response = rx.recv().await.ok();
1208 if let Some(ref selected_action) = response {
1209 let context = language::PromptResponseContext {
1210 message,
1211 selected_action: selected_action.clone(),
1212 };
1213 adapter.process_prompt_response(&context, &mut cx)
1214 }
1215
1216 Ok(response)
1217 } else {
1218 Ok(None)
1219 }
1220 }
1221 }
1222 })
1223 .detach();
1224 language_server
1225 .on_notification::<lsp::notification::ShowMessage, _>({
1226 let this = lsp_store.clone();
1227 let name = name.to_string();
1228 move |params, cx| {
1229 let this = this.clone();
1230 let name = name.to_string();
1231 let mut cx = cx.clone();
1232
1233 let (tx, _) = smol::channel::bounded(1);
1234 let level = match params.typ {
1235 lsp::MessageType::ERROR => PromptLevel::Critical,
1236 lsp::MessageType::WARNING => PromptLevel::Warning,
1237 _ => PromptLevel::Info,
1238 };
1239 let request =
1240 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1241
1242 let _ = this.update(&mut cx, |_, cx| {
1243 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1244 });
1245 }
1246 })
1247 .detach();
1248
1249 let disk_based_diagnostics_progress_token =
1250 adapter.disk_based_diagnostics_progress_token.clone();
1251
1252 language_server
1253 .on_notification::<lsp::notification::Progress, _>({
1254 let this = lsp_store.clone();
1255 move |params, cx| {
1256 if let Some(this) = this.upgrade() {
1257 this.update(cx, |this, cx| {
1258 this.on_lsp_progress(
1259 params,
1260 server_id,
1261 disk_based_diagnostics_progress_token.clone(),
1262 cx,
1263 );
1264 });
1265 }
1266 }
1267 })
1268 .detach();
1269
1270 language_server
1271 .on_notification::<lsp::notification::LogMessage, _>({
1272 let this = lsp_store.clone();
1273 move |params, cx| {
1274 if let Some(this) = this.upgrade() {
1275 this.update(cx, |_, cx| {
1276 cx.emit(LspStoreEvent::LanguageServerLog(
1277 server_id,
1278 LanguageServerLogType::Log(params.typ),
1279 params.message,
1280 ));
1281 });
1282 }
1283 }
1284 })
1285 .detach();
1286
1287 language_server
1288 .on_notification::<lsp::notification::LogTrace, _>({
1289 let this = lsp_store.clone();
1290 move |params, cx| {
1291 let mut cx = cx.clone();
1292 if let Some(this) = this.upgrade() {
1293 this.update(&mut cx, |_, cx| {
1294 cx.emit(LspStoreEvent::LanguageServerLog(
1295 server_id,
1296 LanguageServerLogType::Trace {
1297 verbose_info: params.verbose,
1298 },
1299 params.message,
1300 ));
1301 });
1302 }
1303 }
1304 })
1305 .detach();
1306
1307 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1309 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1310 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1311 }
1312
1313 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1314 let shutdown_futures = self
1315 .language_servers
1316 .drain()
1317 .map(|(_, server_state)| Self::shutdown_server(server_state))
1318 .collect::<Vec<_>>();
1319
1320 async move {
1321 join_all(shutdown_futures).await;
1322 }
1323 }
1324
1325 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1326 match server_state {
1327 LanguageServerState::Running { server, .. } => {
1328 if let Some(shutdown) = server.shutdown() {
1329 shutdown.await;
1330 }
1331 }
1332 LanguageServerState::Starting { startup, .. } => {
1333 if let Some(server) = startup.await
1334 && let Some(shutdown) = server.shutdown()
1335 {
1336 shutdown.await;
1337 }
1338 }
1339 }
1340 Ok(())
1341 }
1342
1343 fn language_servers_for_worktree(
1344 &self,
1345 worktree_id: WorktreeId,
1346 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1347 self.language_server_ids
1348 .iter()
1349 .filter_map(move |(seed, state)| {
1350 if seed.worktree_id != worktree_id {
1351 return None;
1352 }
1353
1354 if let Some(LanguageServerState::Running { server, .. }) =
1355 self.language_servers.get(&state.id)
1356 {
1357 Some(server)
1358 } else {
1359 None
1360 }
1361 })
1362 }
1363
1364 fn language_server_ids_for_project_path(
1365 &self,
1366 project_path: ProjectPath,
1367 language: &Language,
1368 cx: &mut App,
1369 ) -> Vec<LanguageServerId> {
1370 let Some(worktree) = self
1371 .worktree_store
1372 .read(cx)
1373 .worktree_for_id(project_path.worktree_id, cx)
1374 else {
1375 return Vec::new();
1376 };
1377 let delegate: Arc<dyn ManifestDelegate> =
1378 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1379
1380 self.lsp_tree
1381 .get(
1382 project_path,
1383 language.name(),
1384 language.manifest(),
1385 &delegate,
1386 cx,
1387 )
1388 .collect::<Vec<_>>()
1389 }
1390
1391 fn language_server_ids_for_buffer(
1392 &self,
1393 buffer: &Buffer,
1394 cx: &mut App,
1395 ) -> Vec<LanguageServerId> {
1396 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1397 let worktree_id = file.worktree_id(cx);
1398
1399 let path: Arc<RelPath> = file
1400 .path()
1401 .parent()
1402 .map(Arc::from)
1403 .unwrap_or_else(|| file.path().clone());
1404 let worktree_path = ProjectPath { worktree_id, path };
1405 self.language_server_ids_for_project_path(worktree_path, language, cx)
1406 } else {
1407 Vec::new()
1408 }
1409 }
1410
1411 fn language_servers_for_buffer<'a>(
1412 &'a self,
1413 buffer: &'a Buffer,
1414 cx: &'a mut App,
1415 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1416 self.language_server_ids_for_buffer(buffer, cx)
1417 .into_iter()
1418 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1419 LanguageServerState::Running {
1420 adapter, server, ..
1421 } => Some((adapter, server)),
1422 _ => None,
1423 })
1424 }
1425
1426 async fn execute_code_action_kind_locally(
1427 lsp_store: WeakEntity<LspStore>,
1428 mut buffers: Vec<Entity<Buffer>>,
1429 kind: CodeActionKind,
1430 push_to_history: bool,
1431 cx: &mut AsyncApp,
1432 ) -> anyhow::Result<ProjectTransaction> {
1433 // Do not allow multiple concurrent code actions requests for the
1434 // same buffer.
1435 lsp_store.update(cx, |this, cx| {
1436 let this = this.as_local_mut().unwrap();
1437 buffers.retain(|buffer| {
1438 this.buffers_being_formatted
1439 .insert(buffer.read(cx).remote_id())
1440 });
1441 })?;
1442 let _cleanup = defer({
1443 let this = lsp_store.clone();
1444 let mut cx = cx.clone();
1445 let buffers = &buffers;
1446 move || {
1447 this.update(&mut cx, |this, cx| {
1448 let this = this.as_local_mut().unwrap();
1449 for buffer in buffers {
1450 this.buffers_being_formatted
1451 .remove(&buffer.read(cx).remote_id());
1452 }
1453 })
1454 .ok();
1455 }
1456 });
1457 let mut project_transaction = ProjectTransaction::default();
1458
1459 for buffer in &buffers {
1460 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1461 buffer.update(cx, |buffer, cx| {
1462 lsp_store
1463 .as_local()
1464 .unwrap()
1465 .language_servers_for_buffer(buffer, cx)
1466 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1467 .collect::<Vec<_>>()
1468 })
1469 })?;
1470 for (_, language_server) in adapters_and_servers.iter() {
1471 let actions = Self::get_server_code_actions_from_action_kinds(
1472 &lsp_store,
1473 language_server.server_id(),
1474 vec![kind.clone()],
1475 buffer,
1476 cx,
1477 )
1478 .await?;
1479 Self::execute_code_actions_on_server(
1480 &lsp_store,
1481 language_server,
1482 actions,
1483 push_to_history,
1484 &mut project_transaction,
1485 cx,
1486 )
1487 .await?;
1488 }
1489 }
1490 Ok(project_transaction)
1491 }
1492
1493 async fn format_locally(
1494 lsp_store: WeakEntity<LspStore>,
1495 mut buffers: Vec<FormattableBuffer>,
1496 push_to_history: bool,
1497 trigger: FormatTrigger,
1498 logger: zlog::Logger,
1499 cx: &mut AsyncApp,
1500 ) -> anyhow::Result<ProjectTransaction> {
1501 // Do not allow multiple concurrent formatting requests for the
1502 // same buffer.
1503 lsp_store.update(cx, |this, cx| {
1504 let this = this.as_local_mut().unwrap();
1505 buffers.retain(|buffer| {
1506 this.buffers_being_formatted
1507 .insert(buffer.handle.read(cx).remote_id())
1508 });
1509 })?;
1510
1511 let _cleanup = defer({
1512 let this = lsp_store.clone();
1513 let mut cx = cx.clone();
1514 let buffers = &buffers;
1515 move || {
1516 this.update(&mut cx, |this, cx| {
1517 let this = this.as_local_mut().unwrap();
1518 for buffer in buffers {
1519 this.buffers_being_formatted
1520 .remove(&buffer.handle.read(cx).remote_id());
1521 }
1522 })
1523 .ok();
1524 }
1525 });
1526
1527 let mut project_transaction = ProjectTransaction::default();
1528
1529 for buffer in &buffers {
1530 zlog::debug!(
1531 logger =>
1532 "formatting buffer '{:?}'",
1533 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1534 );
1535 // Create an empty transaction to hold all of the formatting edits.
1536 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1537 // ensure no transactions created while formatting are
1538 // grouped with the previous transaction in the history
1539 // based on the transaction group interval
1540 buffer.finalize_last_transaction();
1541 buffer
1542 .start_transaction()
1543 .context("transaction already open")?;
1544 buffer.end_transaction(cx);
1545 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1546 buffer.finalize_last_transaction();
1547 anyhow::Ok(transaction_id)
1548 })?;
1549
1550 let result = Self::format_buffer_locally(
1551 lsp_store.clone(),
1552 buffer,
1553 formatting_transaction_id,
1554 trigger,
1555 logger,
1556 cx,
1557 )
1558 .await;
1559
1560 buffer.handle.update(cx, |buffer, cx| {
1561 let Some(formatting_transaction) =
1562 buffer.get_transaction(formatting_transaction_id).cloned()
1563 else {
1564 zlog::warn!(logger => "no formatting transaction");
1565 return;
1566 };
1567 if formatting_transaction.edit_ids.is_empty() {
1568 zlog::debug!(logger => "no changes made while formatting");
1569 buffer.forget_transaction(formatting_transaction_id);
1570 return;
1571 }
1572 if !push_to_history {
1573 zlog::trace!(logger => "forgetting format transaction");
1574 buffer.forget_transaction(formatting_transaction.id);
1575 }
1576 project_transaction
1577 .0
1578 .insert(cx.entity(), formatting_transaction);
1579 });
1580
1581 result?;
1582 }
1583
1584 Ok(project_transaction)
1585 }
1586
1587 async fn format_buffer_locally(
1588 lsp_store: WeakEntity<LspStore>,
1589 buffer: &FormattableBuffer,
1590 formatting_transaction_id: clock::Lamport,
1591 trigger: FormatTrigger,
1592 logger: zlog::Logger,
1593 cx: &mut AsyncApp,
1594 ) -> Result<()> {
1595 let (adapters_and_servers, settings, request_timeout) =
1596 lsp_store.update(cx, |lsp_store, cx| {
1597 buffer.handle.update(cx, |buffer, cx| {
1598 let adapters_and_servers = lsp_store
1599 .as_local()
1600 .unwrap()
1601 .language_servers_for_buffer(buffer, cx)
1602 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1603 .collect::<Vec<_>>();
1604 let settings =
1605 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1606 .into_owned();
1607 let request_timeout = ProjectSettings::get_global(cx)
1608 .global_lsp_settings
1609 .get_request_timeout();
1610 (adapters_and_servers, settings, request_timeout)
1611 })
1612 })?;
1613
1614 /// Apply edits to the buffer that will become part of the formatting transaction.
1615 /// Fails if the buffer has been edited since the start of that transaction.
1616 fn extend_formatting_transaction(
1617 buffer: &FormattableBuffer,
1618 formatting_transaction_id: text::TransactionId,
1619 cx: &mut AsyncApp,
1620 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1621 ) -> anyhow::Result<()> {
1622 buffer.handle.update(cx, |buffer, cx| {
1623 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1624 if last_transaction_id != Some(formatting_transaction_id) {
1625 anyhow::bail!("Buffer edited while formatting. Aborting")
1626 }
1627 buffer.start_transaction();
1628 operation(buffer, cx);
1629 if let Some(transaction_id) = buffer.end_transaction(cx) {
1630 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1631 }
1632 Ok(())
1633 })
1634 }
1635
1636 // handle whitespace formatting
1637 if settings.remove_trailing_whitespace_on_save {
1638 zlog::trace!(logger => "removing trailing whitespace");
1639 let diff = buffer
1640 .handle
1641 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1642 .await;
1643 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1644 buffer.apply_diff(diff, cx);
1645 })?;
1646 }
1647
1648 if settings.ensure_final_newline_on_save {
1649 zlog::trace!(logger => "ensuring final newline");
1650 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1651 buffer.ensure_final_newline(cx);
1652 })?;
1653 }
1654
1655 // Formatter for `code_actions_on_format` that runs before
1656 // the rest of the formatters
1657 let mut code_actions_on_format_formatters = None;
1658 let should_run_code_actions_on_format = !matches!(
1659 (trigger, &settings.format_on_save),
1660 (FormatTrigger::Save, &FormatOnSave::Off)
1661 );
1662 if should_run_code_actions_on_format {
1663 let have_code_actions_to_run_on_format = settings
1664 .code_actions_on_format
1665 .values()
1666 .any(|enabled| *enabled);
1667 if have_code_actions_to_run_on_format {
1668 zlog::trace!(logger => "going to run code actions on format");
1669 code_actions_on_format_formatters = Some(
1670 settings
1671 .code_actions_on_format
1672 .iter()
1673 .filter_map(|(action, enabled)| enabled.then_some(action))
1674 .cloned()
1675 .map(Formatter::CodeAction)
1676 .collect::<Vec<_>>(),
1677 );
1678 }
1679 }
1680
1681 let formatters = match (trigger, &settings.format_on_save) {
1682 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1683 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1684 settings.formatter.as_ref()
1685 }
1686 };
1687
1688 let formatters = code_actions_on_format_formatters
1689 .iter()
1690 .flatten()
1691 .chain(formatters);
1692
1693 for formatter in formatters {
1694 let formatter = if formatter == &Formatter::Auto {
1695 if settings.prettier.allowed {
1696 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1697 &Formatter::Prettier
1698 } else {
1699 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1700 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1701 }
1702 } else {
1703 formatter
1704 };
1705 match formatter {
1706 Formatter::Auto => unreachable!("Auto resolved above"),
1707 Formatter::Prettier => {
1708 let logger = zlog::scoped!(logger => "prettier");
1709 zlog::trace!(logger => "formatting");
1710 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1711
1712 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1713 lsp_store.prettier_store().unwrap().downgrade()
1714 })?;
1715 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1716 .await
1717 .transpose()?;
1718 let Some(diff) = diff else {
1719 zlog::trace!(logger => "No changes");
1720 continue;
1721 };
1722
1723 extend_formatting_transaction(
1724 buffer,
1725 formatting_transaction_id,
1726 cx,
1727 |buffer, cx| {
1728 buffer.apply_diff(diff, cx);
1729 },
1730 )?;
1731 }
1732 Formatter::External { command, arguments } => {
1733 let logger = zlog::scoped!(logger => "command");
1734 zlog::trace!(logger => "formatting");
1735 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1736
1737 let diff = Self::format_via_external_command(
1738 buffer,
1739 &command,
1740 arguments.as_deref(),
1741 cx,
1742 )
1743 .await
1744 .with_context(|| {
1745 format!("Failed to format buffer via external command: {}", command)
1746 })?;
1747 let Some(diff) = diff else {
1748 zlog::trace!(logger => "No changes");
1749 continue;
1750 };
1751
1752 extend_formatting_transaction(
1753 buffer,
1754 formatting_transaction_id,
1755 cx,
1756 |buffer, cx| {
1757 buffer.apply_diff(diff, cx);
1758 },
1759 )?;
1760 }
1761 Formatter::LanguageServer(specifier) => {
1762 let logger = zlog::scoped!(logger => "language-server");
1763 zlog::trace!(logger => "formatting");
1764 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1765
1766 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1767 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1768 continue;
1769 };
1770
1771 let language_server = match specifier {
1772 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1773 adapters_and_servers.iter().find_map(|(adapter, server)| {
1774 if adapter.name.0.as_ref() == name {
1775 Some(server.clone())
1776 } else {
1777 None
1778 }
1779 })
1780 }
1781 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1782 .iter()
1783 .find(|(_, server)| Self::server_supports_formatting(server))
1784 .map(|(_, server)| server.clone()),
1785 };
1786
1787 let Some(language_server) = language_server else {
1788 log::debug!(
1789 "No language server found to format buffer '{:?}'. Skipping",
1790 buffer_path_abs.as_path().to_string_lossy()
1791 );
1792 continue;
1793 };
1794
1795 zlog::trace!(
1796 logger =>
1797 "Formatting buffer '{:?}' using language server '{:?}'",
1798 buffer_path_abs.as_path().to_string_lossy(),
1799 language_server.name()
1800 );
1801
1802 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1803 zlog::trace!(logger => "formatting ranges");
1804 Self::format_ranges_via_lsp(
1805 &lsp_store,
1806 &buffer.handle,
1807 ranges,
1808 buffer_path_abs,
1809 &language_server,
1810 &settings,
1811 cx,
1812 )
1813 .await
1814 .context("Failed to format ranges via language server")?
1815 } else {
1816 zlog::trace!(logger => "formatting full");
1817 Self::format_via_lsp(
1818 &lsp_store,
1819 &buffer.handle,
1820 buffer_path_abs,
1821 &language_server,
1822 &settings,
1823 cx,
1824 )
1825 .await
1826 .context("failed to format via language server")?
1827 };
1828
1829 if edits.is_empty() {
1830 zlog::trace!(logger => "No changes");
1831 continue;
1832 }
1833 extend_formatting_transaction(
1834 buffer,
1835 formatting_transaction_id,
1836 cx,
1837 |buffer, cx| {
1838 buffer.edit(edits, None, cx);
1839 },
1840 )?;
1841 }
1842 Formatter::CodeAction(code_action_name) => {
1843 let logger = zlog::scoped!(logger => "code-actions");
1844 zlog::trace!(logger => "formatting");
1845 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1846
1847 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1848 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1849 continue;
1850 };
1851
1852 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1853 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1854
1855 let mut actions_and_servers = Vec::new();
1856
1857 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1858 let actions_result = Self::get_server_code_actions_from_action_kinds(
1859 &lsp_store,
1860 language_server.server_id(),
1861 vec![code_action_kind.clone()],
1862 &buffer.handle,
1863 cx,
1864 )
1865 .await
1866 .with_context(|| {
1867 format!(
1868 "Failed to resolve code action {:?} with language server {}",
1869 code_action_kind,
1870 language_server.name()
1871 )
1872 });
1873 let Ok(actions) = actions_result else {
1874 // note: it may be better to set result to the error and break formatters here
1875 // but for now we try to execute the actions that we can resolve and skip the rest
1876 zlog::error!(
1877 logger =>
1878 "Failed to resolve code action {:?} with language server {}",
1879 code_action_kind,
1880 language_server.name()
1881 );
1882 continue;
1883 };
1884 for action in actions {
1885 actions_and_servers.push((action, index));
1886 }
1887 }
1888
1889 if actions_and_servers.is_empty() {
1890 zlog::warn!(logger => "No code actions were resolved, continuing");
1891 continue;
1892 }
1893
1894 'actions: for (mut action, server_index) in actions_and_servers {
1895 let server = &adapters_and_servers[server_index].1;
1896
1897 let describe_code_action = |action: &CodeAction| {
1898 format!(
1899 "code action '{}' with title \"{}\" on server {}",
1900 action
1901 .lsp_action
1902 .action_kind()
1903 .unwrap_or("unknown".into())
1904 .as_str(),
1905 action.lsp_action.title(),
1906 server.name(),
1907 )
1908 };
1909
1910 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1911
1912 if let Err(err) =
1913 Self::try_resolve_code_action(server, &mut action, request_timeout)
1914 .await
1915 {
1916 zlog::error!(
1917 logger =>
1918 "Failed to resolve {}. Error: {}",
1919 describe_code_action(&action),
1920 err
1921 );
1922 continue;
1923 }
1924
1925 if let Some(edit) = action.lsp_action.edit().cloned() {
1926 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1927 // but filters out and logs warnings for code actions that require unreasonably
1928 // difficult handling on our part, such as:
1929 // - applying edits that call commands
1930 // which can result in arbitrary workspace edits being sent from the server that
1931 // have no way of being tied back to the command that initiated them (i.e. we
1932 // can't know which edits are part of the format request, or if the server is done sending
1933 // actions in response to the command)
1934 // - actions that create/delete/modify/rename files other than the one we are formatting
1935 // as we then would need to handle such changes correctly in the local history as well
1936 // as the remote history through the ProjectTransaction
1937 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1938 // Supporting these actions is not impossible, but not supported as of yet.
1939 if edit.changes.is_none() && edit.document_changes.is_none() {
1940 zlog::trace!(
1941 logger =>
1942 "No changes for code action. Skipping {}",
1943 describe_code_action(&action),
1944 );
1945 continue;
1946 }
1947
1948 let mut operations = Vec::new();
1949 if let Some(document_changes) = edit.document_changes {
1950 match document_changes {
1951 lsp::DocumentChanges::Edits(edits) => operations.extend(
1952 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1953 ),
1954 lsp::DocumentChanges::Operations(ops) => operations = ops,
1955 }
1956 } else if let Some(changes) = edit.changes {
1957 operations.extend(changes.into_iter().map(|(uri, edits)| {
1958 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1959 text_document:
1960 lsp::OptionalVersionedTextDocumentIdentifier {
1961 uri,
1962 version: None,
1963 },
1964 edits: edits.into_iter().map(Edit::Plain).collect(),
1965 })
1966 }));
1967 }
1968
1969 let mut edits = Vec::with_capacity(operations.len());
1970
1971 if operations.is_empty() {
1972 zlog::trace!(
1973 logger =>
1974 "No changes for code action. Skipping {}",
1975 describe_code_action(&action),
1976 );
1977 continue;
1978 }
1979 for operation in operations {
1980 let op = match operation {
1981 lsp::DocumentChangeOperation::Edit(op) => op,
1982 lsp::DocumentChangeOperation::Op(_) => {
1983 zlog::warn!(
1984 logger =>
1985 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1986 describe_code_action(&action),
1987 );
1988 continue 'actions;
1989 }
1990 };
1991 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1992 zlog::warn!(
1993 logger =>
1994 "Failed to convert URI '{:?}' to file path. Skipping {}",
1995 &op.text_document.uri,
1996 describe_code_action(&action),
1997 );
1998 continue 'actions;
1999 };
2000 if &file_path != buffer_path_abs {
2001 zlog::warn!(
2002 logger =>
2003 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2004 file_path,
2005 buffer_path_abs,
2006 describe_code_action(&action),
2007 );
2008 continue 'actions;
2009 }
2010
2011 let mut lsp_edits = Vec::new();
2012 for edit in op.edits {
2013 match edit {
2014 Edit::Plain(edit) => {
2015 if !lsp_edits.contains(&edit) {
2016 lsp_edits.push(edit);
2017 }
2018 }
2019 Edit::Annotated(edit) => {
2020 if !lsp_edits.contains(&edit.text_edit) {
2021 lsp_edits.push(edit.text_edit);
2022 }
2023 }
2024 Edit::Snippet(_) => {
2025 zlog::warn!(
2026 logger =>
2027 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2028 describe_code_action(&action),
2029 );
2030 continue 'actions;
2031 }
2032 }
2033 }
2034 let edits_result = lsp_store
2035 .update(cx, |lsp_store, cx| {
2036 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2037 &buffer.handle,
2038 lsp_edits,
2039 server.server_id(),
2040 op.text_document.version,
2041 cx,
2042 )
2043 })?
2044 .await;
2045 let Ok(resolved_edits) = edits_result else {
2046 zlog::warn!(
2047 logger =>
2048 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2049 buffer_path_abs.as_path(),
2050 describe_code_action(&action),
2051 );
2052 continue 'actions;
2053 };
2054 edits.extend(resolved_edits);
2055 }
2056
2057 if edits.is_empty() {
2058 zlog::warn!(logger => "No edits resolved from LSP");
2059 continue;
2060 }
2061
2062 extend_formatting_transaction(
2063 buffer,
2064 formatting_transaction_id,
2065 cx,
2066 |buffer, cx| {
2067 zlog::info!(
2068 "Applying edits {edits:?}. Content: {:?}",
2069 buffer.text()
2070 );
2071 buffer.edit(edits, None, cx);
2072 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2073 },
2074 )?;
2075 }
2076
2077 // bail early if command is invalid
2078 let Some(command) = action.lsp_action.command() else {
2079 continue;
2080 };
2081
2082 zlog::warn!(
2083 logger =>
2084 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2085 &command.command,
2086 );
2087
2088 let server_capabilities = server.capabilities();
2089 let available_commands = server_capabilities
2090 .execute_command_provider
2091 .as_ref()
2092 .map(|options| options.commands.as_slice())
2093 .unwrap_or_default();
2094 if !available_commands.contains(&command.command) {
2095 zlog::warn!(
2096 logger =>
2097 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2098 command.command,
2099 server.name(),
2100 );
2101 continue;
2102 }
2103
2104 // noop so we just ensure buffer hasn't been edited since resolving code actions
2105 extend_formatting_transaction(
2106 buffer,
2107 formatting_transaction_id,
2108 cx,
2109 |_, _| {},
2110 )?;
2111 zlog::info!(logger => "Executing command {}", &command.command);
2112
2113 lsp_store.update(cx, |this, _| {
2114 this.as_local_mut()
2115 .unwrap()
2116 .last_workspace_edits_by_language_server
2117 .remove(&server.server_id());
2118 })?;
2119
2120 let execute_command_result = server
2121 .request::<lsp::request::ExecuteCommand>(
2122 lsp::ExecuteCommandParams {
2123 command: command.command.clone(),
2124 arguments: command.arguments.clone().unwrap_or_default(),
2125 ..Default::default()
2126 },
2127 request_timeout,
2128 )
2129 .await
2130 .into_response();
2131
2132 if execute_command_result.is_err() {
2133 zlog::error!(
2134 logger =>
2135 "Failed to execute command '{}' as part of {}",
2136 &command.command,
2137 describe_code_action(&action),
2138 );
2139 continue 'actions;
2140 }
2141
2142 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2143 this.as_local_mut()
2144 .unwrap()
2145 .last_workspace_edits_by_language_server
2146 .remove(&server.server_id())
2147 .unwrap_or_default()
2148 })?;
2149
2150 if let Some(transaction) =
2151 project_transaction_command.0.remove(&buffer.handle)
2152 {
2153 zlog::trace!(
2154 logger =>
2155 "Successfully captured {} edits that resulted from command {}",
2156 transaction.edit_ids.len(),
2157 &command.command,
2158 );
2159 let transaction_id_project_transaction = transaction.id;
2160 buffer.handle.update(cx, |buffer, _| {
2161 // it may have been removed from history if push_to_history was
2162 // false in deserialize_workspace_edit. If so push it so we
2163 // can merge it with the format transaction
2164 // and pop the combined transaction off the history stack
2165 // later if push_to_history is false
2166 if buffer.get_transaction(transaction.id).is_none() {
2167 buffer.push_transaction(transaction, Instant::now());
2168 }
2169 buffer.merge_transactions(
2170 transaction_id_project_transaction,
2171 formatting_transaction_id,
2172 );
2173 });
2174 }
2175
2176 if project_transaction_command.0.is_empty() {
2177 continue;
2178 }
2179
2180 let mut extra_buffers = String::new();
2181 for buffer in project_transaction_command.0.keys() {
2182 buffer.read_with(cx, |b, cx| {
2183 let Some(path) = b.project_path(cx) else {
2184 return;
2185 };
2186
2187 if !extra_buffers.is_empty() {
2188 extra_buffers.push_str(", ");
2189 }
2190 extra_buffers.push_str(path.path.as_unix_str());
2191 });
2192 }
2193 zlog::warn!(
2194 logger =>
2195 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2196 &command.command,
2197 extra_buffers,
2198 );
2199 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2200 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2201 // add it so it's included, and merge it into the format transaction when its created later
2202 }
2203 }
2204 }
2205 }
2206
2207 Ok(())
2208 }
2209
2210 pub async fn format_ranges_via_lsp(
2211 this: &WeakEntity<LspStore>,
2212 buffer_handle: &Entity<Buffer>,
2213 ranges: &[Range<Anchor>],
2214 abs_path: &Path,
2215 language_server: &Arc<LanguageServer>,
2216 settings: &LanguageSettings,
2217 cx: &mut AsyncApp,
2218 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2219 let capabilities = &language_server.capabilities();
2220 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2221 if range_formatting_provider == Some(&OneOf::Left(false)) {
2222 anyhow::bail!(
2223 "{} language server does not support range formatting",
2224 language_server.name()
2225 );
2226 }
2227
2228 let uri = file_path_to_lsp_url(abs_path)?;
2229 let text_document = lsp::TextDocumentIdentifier::new(uri);
2230
2231 let request_timeout = cx.update(|app| {
2232 ProjectSettings::get_global(app)
2233 .global_lsp_settings
2234 .get_request_timeout()
2235 });
2236 let lsp_edits = {
2237 let mut lsp_ranges = Vec::new();
2238 this.update(cx, |_this, cx| {
2239 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2240 // not have been sent to the language server. This seems like a fairly systemic
2241 // issue, though, the resolution probably is not specific to formatting.
2242 //
2243 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2244 // LSP.
2245 let snapshot = buffer_handle.read(cx).snapshot();
2246 for range in ranges {
2247 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2248 }
2249 anyhow::Ok(())
2250 })??;
2251
2252 let mut edits = None;
2253 for range in lsp_ranges {
2254 if let Some(mut edit) = language_server
2255 .request::<lsp::request::RangeFormatting>(
2256 lsp::DocumentRangeFormattingParams {
2257 text_document: text_document.clone(),
2258 range,
2259 options: lsp_command::lsp_formatting_options(settings),
2260 work_done_progress_params: Default::default(),
2261 },
2262 request_timeout,
2263 )
2264 .await
2265 .into_response()?
2266 {
2267 edits.get_or_insert_with(Vec::new).append(&mut edit);
2268 }
2269 }
2270 edits
2271 };
2272
2273 if let Some(lsp_edits) = lsp_edits {
2274 this.update(cx, |this, cx| {
2275 this.as_local_mut().unwrap().edits_from_lsp(
2276 buffer_handle,
2277 lsp_edits,
2278 language_server.server_id(),
2279 None,
2280 cx,
2281 )
2282 })?
2283 .await
2284 } else {
2285 Ok(Vec::with_capacity(0))
2286 }
2287 }
2288
2289 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2290 let capabilities = server.capabilities();
2291 let formatting = capabilities.document_formatting_provider.as_ref();
2292 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2293 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2294 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2295 }
2296
2297 async fn format_via_lsp(
2298 this: &WeakEntity<LspStore>,
2299 buffer: &Entity<Buffer>,
2300 abs_path: &Path,
2301 language_server: &Arc<LanguageServer>,
2302 settings: &LanguageSettings,
2303 cx: &mut AsyncApp,
2304 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2305 let logger = zlog::scoped!("lsp_format");
2306 zlog::debug!(logger => "Formatting via LSP");
2307
2308 let uri = file_path_to_lsp_url(abs_path)?;
2309 let text_document = lsp::TextDocumentIdentifier::new(uri);
2310 let capabilities = &language_server.capabilities();
2311
2312 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2313 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2314
2315 let request_timeout = cx.update(|app| {
2316 ProjectSettings::get_global(app)
2317 .global_lsp_settings
2318 .get_request_timeout()
2319 });
2320
2321 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2322 let _timer = zlog::time!(logger => "format-full");
2323 language_server
2324 .request::<lsp::request::Formatting>(
2325 lsp::DocumentFormattingParams {
2326 text_document,
2327 options: lsp_command::lsp_formatting_options(settings),
2328 work_done_progress_params: Default::default(),
2329 },
2330 request_timeout,
2331 )
2332 .await
2333 .into_response()?
2334 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2335 let _timer = zlog::time!(logger => "format-range");
2336 let buffer_start = lsp::Position::new(0, 0);
2337 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2338 language_server
2339 .request::<lsp::request::RangeFormatting>(
2340 lsp::DocumentRangeFormattingParams {
2341 text_document: text_document.clone(),
2342 range: lsp::Range::new(buffer_start, buffer_end),
2343 options: lsp_command::lsp_formatting_options(settings),
2344 work_done_progress_params: Default::default(),
2345 },
2346 request_timeout,
2347 )
2348 .await
2349 .into_response()?
2350 } else {
2351 None
2352 };
2353
2354 if let Some(lsp_edits) = lsp_edits {
2355 this.update(cx, |this, cx| {
2356 this.as_local_mut().unwrap().edits_from_lsp(
2357 buffer,
2358 lsp_edits,
2359 language_server.server_id(),
2360 None,
2361 cx,
2362 )
2363 })?
2364 .await
2365 } else {
2366 Ok(Vec::with_capacity(0))
2367 }
2368 }
2369
2370 async fn format_via_external_command(
2371 buffer: &FormattableBuffer,
2372 command: &str,
2373 arguments: Option<&[String]>,
2374 cx: &mut AsyncApp,
2375 ) -> Result<Option<Diff>> {
2376 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2377 let file = File::from_dyn(buffer.file())?;
2378 let worktree = file.worktree.read(cx);
2379 let mut worktree_path = worktree.abs_path().to_path_buf();
2380 if worktree.root_entry()?.is_file() {
2381 worktree_path.pop();
2382 }
2383 Some(worktree_path)
2384 });
2385
2386 use util::command::Stdio;
2387 let mut child = util::command::new_command(command);
2388
2389 if let Some(buffer_env) = buffer.env.as_ref() {
2390 child.envs(buffer_env);
2391 }
2392
2393 if let Some(working_dir_path) = working_dir_path {
2394 child.current_dir(working_dir_path);
2395 }
2396
2397 if let Some(arguments) = arguments {
2398 child.args(arguments.iter().map(|arg| {
2399 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2400 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2401 } else {
2402 arg.replace("{buffer_path}", "Untitled")
2403 }
2404 }));
2405 }
2406
2407 let mut child = child
2408 .stdin(Stdio::piped())
2409 .stdout(Stdio::piped())
2410 .stderr(Stdio::piped())
2411 .spawn()?;
2412
2413 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2414 let text = buffer
2415 .handle
2416 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2417 for chunk in text.chunks() {
2418 stdin.write_all(chunk.as_bytes()).await?;
2419 }
2420 stdin.flush().await?;
2421
2422 let output = child.output().await?;
2423 anyhow::ensure!(
2424 output.status.success(),
2425 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2426 output.status.code(),
2427 String::from_utf8_lossy(&output.stdout),
2428 String::from_utf8_lossy(&output.stderr),
2429 );
2430
2431 let stdout = String::from_utf8(output.stdout)?;
2432 Ok(Some(
2433 buffer
2434 .handle
2435 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2436 .await,
2437 ))
2438 }
2439
2440 async fn try_resolve_code_action(
2441 lang_server: &LanguageServer,
2442 action: &mut CodeAction,
2443 request_timeout: Duration,
2444 ) -> anyhow::Result<()> {
2445 match &mut action.lsp_action {
2446 LspAction::Action(lsp_action) => {
2447 if !action.resolved
2448 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2449 && lsp_action.data.is_some()
2450 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2451 {
2452 **lsp_action = lang_server
2453 .request::<lsp::request::CodeActionResolveRequest>(
2454 *lsp_action.clone(),
2455 request_timeout,
2456 )
2457 .await
2458 .into_response()?;
2459 }
2460 }
2461 LspAction::CodeLens(lens) => {
2462 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2463 *lens = lang_server
2464 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2465 .await
2466 .into_response()?;
2467 }
2468 }
2469 LspAction::Command(_) => {}
2470 }
2471
2472 action.resolved = true;
2473 anyhow::Ok(())
2474 }
2475
2476 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2477 let buffer = buffer_handle.read(cx);
2478
2479 let file = buffer.file().cloned();
2480
2481 let Some(file) = File::from_dyn(file.as_ref()) else {
2482 return;
2483 };
2484 if !file.is_local() {
2485 return;
2486 }
2487 let path = ProjectPath::from_file(file, cx);
2488 let worktree_id = file.worktree_id(cx);
2489 let language = buffer.language().cloned();
2490
2491 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2492 for (server_id, diagnostics) in
2493 diagnostics.get(file.path()).cloned().unwrap_or_default()
2494 {
2495 self.update_buffer_diagnostics(
2496 buffer_handle,
2497 server_id,
2498 None,
2499 None,
2500 None,
2501 Vec::new(),
2502 diagnostics,
2503 cx,
2504 )
2505 .log_err();
2506 }
2507 }
2508 let Some(language) = language else {
2509 return;
2510 };
2511 let Some(snapshot) = self
2512 .worktree_store
2513 .read(cx)
2514 .worktree_for_id(worktree_id, cx)
2515 .map(|worktree| worktree.read(cx).snapshot())
2516 else {
2517 return;
2518 };
2519 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2520
2521 for server_id in
2522 self.lsp_tree
2523 .get(path, language.name(), language.manifest(), &delegate, cx)
2524 {
2525 let server = self
2526 .language_servers
2527 .get(&server_id)
2528 .and_then(|server_state| {
2529 if let LanguageServerState::Running { server, .. } = server_state {
2530 Some(server.clone())
2531 } else {
2532 None
2533 }
2534 });
2535 let server = match server {
2536 Some(server) => server,
2537 None => continue,
2538 };
2539
2540 buffer_handle.update(cx, |buffer, cx| {
2541 buffer.set_completion_triggers(
2542 server.server_id(),
2543 server
2544 .capabilities()
2545 .completion_provider
2546 .as_ref()
2547 .and_then(|provider| {
2548 provider
2549 .trigger_characters
2550 .as_ref()
2551 .map(|characters| characters.iter().cloned().collect())
2552 })
2553 .unwrap_or_default(),
2554 cx,
2555 );
2556 });
2557 }
2558 }
2559
2560 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2561 buffer.update(cx, |buffer, cx| {
2562 let Some(language) = buffer.language() else {
2563 return;
2564 };
2565 let path = ProjectPath {
2566 worktree_id: old_file.worktree_id(cx),
2567 path: old_file.path.clone(),
2568 };
2569 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2570 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2571 buffer.set_completion_triggers(server_id, Default::default(), cx);
2572 }
2573 });
2574 }
2575
2576 fn update_buffer_diagnostics(
2577 &mut self,
2578 buffer: &Entity<Buffer>,
2579 server_id: LanguageServerId,
2580 registration_id: Option<Option<SharedString>>,
2581 result_id: Option<SharedString>,
2582 version: Option<i32>,
2583 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2584 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2585 cx: &mut Context<LspStore>,
2586 ) -> Result<()> {
2587 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2588 Ordering::Equal
2589 .then_with(|| b.is_primary.cmp(&a.is_primary))
2590 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2591 .then_with(|| a.severity.cmp(&b.severity))
2592 .then_with(|| a.message.cmp(&b.message))
2593 }
2594
2595 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2596 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2597 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2598
2599 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2600 Ordering::Equal
2601 .then_with(|| a.range.start.cmp(&b.range.start))
2602 .then_with(|| b.range.end.cmp(&a.range.end))
2603 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2604 });
2605
2606 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2607
2608 let edits_since_save = std::cell::LazyCell::new(|| {
2609 let saved_version = buffer.read(cx).saved_version();
2610 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2611 });
2612
2613 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2614
2615 for (new_diagnostic, entry) in diagnostics {
2616 let start;
2617 let end;
2618 if new_diagnostic && entry.diagnostic.is_disk_based {
2619 // Some diagnostics are based on files on disk instead of buffers'
2620 // current contents. Adjust these diagnostics' ranges to reflect
2621 // any unsaved edits.
2622 // Do not alter the reused ones though, as their coordinates were stored as anchors
2623 // and were properly adjusted on reuse.
2624 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2625 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2626 } else {
2627 start = entry.range.start;
2628 end = entry.range.end;
2629 }
2630
2631 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2632 ..snapshot.clip_point_utf16(end, Bias::Right);
2633
2634 // Expand empty ranges by one codepoint
2635 if range.start == range.end {
2636 // This will be go to the next boundary when being clipped
2637 range.end.column += 1;
2638 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2639 if range.start == range.end && range.end.column > 0 {
2640 range.start.column -= 1;
2641 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2642 }
2643 }
2644
2645 sanitized_diagnostics.push(DiagnosticEntry {
2646 range,
2647 diagnostic: entry.diagnostic,
2648 });
2649 }
2650 drop(edits_since_save);
2651
2652 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2653 buffer.update(cx, |buffer, cx| {
2654 if let Some(registration_id) = registration_id {
2655 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2656 self.buffer_pull_diagnostics_result_ids
2657 .entry(server_id)
2658 .or_default()
2659 .entry(registration_id)
2660 .or_default()
2661 .insert(abs_path, result_id);
2662 }
2663 }
2664
2665 buffer.update_diagnostics(server_id, set, cx)
2666 });
2667
2668 Ok(())
2669 }
2670
2671 fn register_language_server_for_invisible_worktree(
2672 &mut self,
2673 worktree: &Entity<Worktree>,
2674 language_server_id: LanguageServerId,
2675 cx: &mut App,
2676 ) {
2677 let worktree = worktree.read(cx);
2678 let worktree_id = worktree.id();
2679 debug_assert!(!worktree.is_visible());
2680 let Some(mut origin_seed) = self
2681 .language_server_ids
2682 .iter()
2683 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2684 else {
2685 return;
2686 };
2687 origin_seed.worktree_id = worktree_id;
2688 self.language_server_ids
2689 .entry(origin_seed)
2690 .or_insert_with(|| UnifiedLanguageServer {
2691 id: language_server_id,
2692 project_roots: Default::default(),
2693 });
2694 }
2695
2696 fn register_buffer_with_language_servers(
2697 &mut self,
2698 buffer_handle: &Entity<Buffer>,
2699 only_register_servers: HashSet<LanguageServerSelector>,
2700 cx: &mut Context<LspStore>,
2701 ) {
2702 let buffer = buffer_handle.read(cx);
2703 let buffer_id = buffer.remote_id();
2704
2705 let Some(file) = File::from_dyn(buffer.file()) else {
2706 return;
2707 };
2708 if !file.is_local() {
2709 return;
2710 }
2711
2712 let abs_path = file.abs_path(cx);
2713 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2714 return;
2715 };
2716 let initial_snapshot = buffer.text_snapshot();
2717 let worktree_id = file.worktree_id(cx);
2718
2719 let Some(language) = buffer.language().cloned() else {
2720 return;
2721 };
2722 let path: Arc<RelPath> = file
2723 .path()
2724 .parent()
2725 .map(Arc::from)
2726 .unwrap_or_else(|| file.path().clone());
2727 let Some(worktree) = self
2728 .worktree_store
2729 .read(cx)
2730 .worktree_for_id(worktree_id, cx)
2731 else {
2732 return;
2733 };
2734 let language_name = language.name();
2735 let (reused, delegate, servers) = self
2736 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2737 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2738 .unwrap_or_else(|| {
2739 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2740 let delegate: Arc<dyn ManifestDelegate> =
2741 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2742
2743 let servers = self
2744 .lsp_tree
2745 .walk(
2746 ProjectPath { worktree_id, path },
2747 language.name(),
2748 language.manifest(),
2749 &delegate,
2750 cx,
2751 )
2752 .collect::<Vec<_>>();
2753 (false, lsp_delegate, servers)
2754 });
2755 let servers_and_adapters = servers
2756 .into_iter()
2757 .filter_map(|server_node| {
2758 if reused && server_node.server_id().is_none() {
2759 return None;
2760 }
2761 if !only_register_servers.is_empty() {
2762 if let Some(server_id) = server_node.server_id()
2763 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2764 {
2765 return None;
2766 }
2767 if let Some(name) = server_node.name()
2768 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2769 {
2770 return None;
2771 }
2772 }
2773
2774 let server_id = server_node.server_id_or_init(|disposition| {
2775 let path = &disposition.path;
2776
2777 {
2778 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2779
2780 let server_id = self.get_or_insert_language_server(
2781 &worktree,
2782 delegate.clone(),
2783 disposition,
2784 &language_name,
2785 cx,
2786 );
2787
2788 if let Some(state) = self.language_servers.get(&server_id)
2789 && let Ok(uri) = uri
2790 {
2791 state.add_workspace_folder(uri);
2792 };
2793 server_id
2794 }
2795 })?;
2796 let server_state = self.language_servers.get(&server_id)?;
2797 if let LanguageServerState::Running {
2798 server, adapter, ..
2799 } = server_state
2800 {
2801 Some((server.clone(), adapter.clone()))
2802 } else {
2803 None
2804 }
2805 })
2806 .collect::<Vec<_>>();
2807 for (server, adapter) in servers_and_adapters {
2808 buffer_handle.update(cx, |buffer, cx| {
2809 buffer.set_completion_triggers(
2810 server.server_id(),
2811 server
2812 .capabilities()
2813 .completion_provider
2814 .as_ref()
2815 .and_then(|provider| {
2816 provider
2817 .trigger_characters
2818 .as_ref()
2819 .map(|characters| characters.iter().cloned().collect())
2820 })
2821 .unwrap_or_default(),
2822 cx,
2823 );
2824 });
2825
2826 let snapshot = LspBufferSnapshot {
2827 version: 0,
2828 snapshot: initial_snapshot.clone(),
2829 };
2830
2831 let mut registered = false;
2832 self.buffer_snapshots
2833 .entry(buffer_id)
2834 .or_default()
2835 .entry(server.server_id())
2836 .or_insert_with(|| {
2837 registered = true;
2838 server.register_buffer(
2839 uri.clone(),
2840 adapter.language_id(&language.name()),
2841 0,
2842 initial_snapshot.text(),
2843 );
2844
2845 vec![snapshot]
2846 });
2847
2848 self.buffers_opened_in_servers
2849 .entry(buffer_id)
2850 .or_default()
2851 .insert(server.server_id());
2852 if registered {
2853 cx.emit(LspStoreEvent::LanguageServerUpdate {
2854 language_server_id: server.server_id(),
2855 name: None,
2856 message: proto::update_language_server::Variant::RegisteredForBuffer(
2857 proto::RegisteredForBuffer {
2858 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2859 buffer_id: buffer_id.to_proto(),
2860 },
2861 ),
2862 });
2863 }
2864 }
2865 }
2866
2867 fn reuse_existing_language_server<'lang_name>(
2868 &self,
2869 server_tree: &LanguageServerTree,
2870 worktree: &Entity<Worktree>,
2871 language_name: &'lang_name LanguageName,
2872 cx: &mut App,
2873 ) -> Option<(
2874 Arc<LocalLspAdapterDelegate>,
2875 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2876 )> {
2877 if worktree.read(cx).is_visible() {
2878 return None;
2879 }
2880
2881 let worktree_store = self.worktree_store.read(cx);
2882 let servers = server_tree
2883 .instances
2884 .iter()
2885 .filter(|(worktree_id, _)| {
2886 worktree_store
2887 .worktree_for_id(**worktree_id, cx)
2888 .is_some_and(|worktree| worktree.read(cx).is_visible())
2889 })
2890 .flat_map(|(worktree_id, servers)| {
2891 servers
2892 .roots
2893 .iter()
2894 .flat_map(|(_, language_servers)| language_servers)
2895 .map(move |(_, (server_node, server_languages))| {
2896 (worktree_id, server_node, server_languages)
2897 })
2898 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2899 .map(|(worktree_id, server_node, _)| {
2900 (
2901 *worktree_id,
2902 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2903 )
2904 })
2905 })
2906 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2907 acc.entry(worktree_id)
2908 .or_insert_with(Vec::new)
2909 .push(server_node);
2910 acc
2911 })
2912 .into_values()
2913 .max_by_key(|servers| servers.len())?;
2914
2915 let worktree_id = worktree.read(cx).id();
2916 let apply = move |tree: &mut LanguageServerTree| {
2917 for server_node in &servers {
2918 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2919 }
2920 servers
2921 };
2922
2923 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2924 Some((delegate, apply))
2925 }
2926
2927 pub(crate) fn unregister_old_buffer_from_language_servers(
2928 &mut self,
2929 buffer: &Entity<Buffer>,
2930 old_file: &File,
2931 cx: &mut App,
2932 ) {
2933 let old_path = match old_file.as_local() {
2934 Some(local) => local.abs_path(cx),
2935 None => return,
2936 };
2937
2938 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2939 debug_panic!("{old_path:?} is not parseable as an URI");
2940 return;
2941 };
2942 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2943 }
2944
2945 pub(crate) fn unregister_buffer_from_language_servers(
2946 &mut self,
2947 buffer: &Entity<Buffer>,
2948 file_url: &lsp::Uri,
2949 cx: &mut App,
2950 ) {
2951 buffer.update(cx, |buffer, cx| {
2952 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2953
2954 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2955 if snapshots
2956 .as_mut()
2957 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2958 {
2959 language_server.unregister_buffer(file_url.clone());
2960 }
2961 }
2962 });
2963 }
2964
2965 fn buffer_snapshot_for_lsp_version(
2966 &mut self,
2967 buffer: &Entity<Buffer>,
2968 server_id: LanguageServerId,
2969 version: Option<i32>,
2970 cx: &App,
2971 ) -> Result<TextBufferSnapshot> {
2972 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2973
2974 if let Some(version) = version {
2975 let buffer_id = buffer.read(cx).remote_id();
2976 let snapshots = if let Some(snapshots) = self
2977 .buffer_snapshots
2978 .get_mut(&buffer_id)
2979 .and_then(|m| m.get_mut(&server_id))
2980 {
2981 snapshots
2982 } else if version == 0 {
2983 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2984 // We detect this case and treat it as if the version was `None`.
2985 return Ok(buffer.read(cx).text_snapshot());
2986 } else {
2987 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2988 };
2989
2990 let found_snapshot = snapshots
2991 .binary_search_by_key(&version, |e| e.version)
2992 .map(|ix| snapshots[ix].snapshot.clone())
2993 .map_err(|_| {
2994 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2995 })?;
2996
2997 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2998 Ok(found_snapshot)
2999 } else {
3000 Ok((buffer.read(cx)).text_snapshot())
3001 }
3002 }
3003
3004 async fn get_server_code_actions_from_action_kinds(
3005 lsp_store: &WeakEntity<LspStore>,
3006 language_server_id: LanguageServerId,
3007 code_action_kinds: Vec<lsp::CodeActionKind>,
3008 buffer: &Entity<Buffer>,
3009 cx: &mut AsyncApp,
3010 ) -> Result<Vec<CodeAction>> {
3011 let actions = lsp_store
3012 .update(cx, move |this, cx| {
3013 let request = GetCodeActions {
3014 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3015 kinds: Some(code_action_kinds),
3016 };
3017 let server = LanguageServerToQuery::Other(language_server_id);
3018 this.request_lsp(buffer.clone(), server, request, cx)
3019 })?
3020 .await?;
3021 Ok(actions)
3022 }
3023
3024 pub async fn execute_code_actions_on_server(
3025 lsp_store: &WeakEntity<LspStore>,
3026 language_server: &Arc<LanguageServer>,
3027 actions: Vec<CodeAction>,
3028 push_to_history: bool,
3029 project_transaction: &mut ProjectTransaction,
3030 cx: &mut AsyncApp,
3031 ) -> anyhow::Result<()> {
3032 let request_timeout = cx.update(|app| {
3033 ProjectSettings::get_global(app)
3034 .global_lsp_settings
3035 .get_request_timeout()
3036 });
3037
3038 for mut action in actions {
3039 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3040 .await
3041 .context("resolving a formatting code action")?;
3042
3043 if let Some(edit) = action.lsp_action.edit() {
3044 if edit.changes.is_none() && edit.document_changes.is_none() {
3045 continue;
3046 }
3047
3048 let new = Self::deserialize_workspace_edit(
3049 lsp_store.upgrade().context("project dropped")?,
3050 edit.clone(),
3051 push_to_history,
3052 language_server.clone(),
3053 cx,
3054 )
3055 .await?;
3056 project_transaction.0.extend(new.0);
3057 }
3058
3059 let Some(command) = action.lsp_action.command() else {
3060 continue;
3061 };
3062
3063 let server_capabilities = language_server.capabilities();
3064 let available_commands = server_capabilities
3065 .execute_command_provider
3066 .as_ref()
3067 .map(|options| options.commands.as_slice())
3068 .unwrap_or_default();
3069 if !available_commands.contains(&command.command) {
3070 log::warn!(
3071 "Cannot execute a command {} not listed in the language server capabilities",
3072 command.command
3073 );
3074 continue;
3075 }
3076
3077 lsp_store.update(cx, |lsp_store, _| {
3078 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3079 mode.last_workspace_edits_by_language_server
3080 .remove(&language_server.server_id());
3081 }
3082 })?;
3083
3084 language_server
3085 .request::<lsp::request::ExecuteCommand>(
3086 lsp::ExecuteCommandParams {
3087 command: command.command.clone(),
3088 arguments: command.arguments.clone().unwrap_or_default(),
3089 ..Default::default()
3090 },
3091 request_timeout,
3092 )
3093 .await
3094 .into_response()
3095 .context("execute command")?;
3096
3097 lsp_store.update(cx, |this, _| {
3098 if let LspStoreMode::Local(mode) = &mut this.mode {
3099 project_transaction.0.extend(
3100 mode.last_workspace_edits_by_language_server
3101 .remove(&language_server.server_id())
3102 .unwrap_or_default()
3103 .0,
3104 )
3105 }
3106 })?;
3107 }
3108 Ok(())
3109 }
3110
3111 pub async fn deserialize_text_edits(
3112 this: Entity<LspStore>,
3113 buffer_to_edit: Entity<Buffer>,
3114 edits: Vec<lsp::TextEdit>,
3115 push_to_history: bool,
3116 _: Arc<CachedLspAdapter>,
3117 language_server: Arc<LanguageServer>,
3118 cx: &mut AsyncApp,
3119 ) -> Result<Option<Transaction>> {
3120 let edits = this
3121 .update(cx, |this, cx| {
3122 this.as_local_mut().unwrap().edits_from_lsp(
3123 &buffer_to_edit,
3124 edits,
3125 language_server.server_id(),
3126 None,
3127 cx,
3128 )
3129 })
3130 .await?;
3131
3132 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3133 buffer.finalize_last_transaction();
3134 buffer.start_transaction();
3135 for (range, text) in edits {
3136 buffer.edit([(range, text)], None, cx);
3137 }
3138
3139 if buffer.end_transaction(cx).is_some() {
3140 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3141 if !push_to_history {
3142 buffer.forget_transaction(transaction.id);
3143 }
3144 Some(transaction)
3145 } else {
3146 None
3147 }
3148 });
3149
3150 Ok(transaction)
3151 }
3152
3153 #[allow(clippy::type_complexity)]
3154 pub fn edits_from_lsp(
3155 &mut self,
3156 buffer: &Entity<Buffer>,
3157 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3158 server_id: LanguageServerId,
3159 version: Option<i32>,
3160 cx: &mut Context<LspStore>,
3161 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3162 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3163 cx.background_spawn(async move {
3164 let snapshot = snapshot?;
3165 let mut lsp_edits = lsp_edits
3166 .into_iter()
3167 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3168 .collect::<Vec<_>>();
3169
3170 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3171
3172 let mut lsp_edits = lsp_edits.into_iter().peekable();
3173 let mut edits = Vec::new();
3174 while let Some((range, mut new_text)) = lsp_edits.next() {
3175 // Clip invalid ranges provided by the language server.
3176 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3177 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3178
3179 // Combine any LSP edits that are adjacent.
3180 //
3181 // Also, combine LSP edits that are separated from each other by only
3182 // a newline. This is important because for some code actions,
3183 // Rust-analyzer rewrites the entire buffer via a series of edits that
3184 // are separated by unchanged newline characters.
3185 //
3186 // In order for the diffing logic below to work properly, any edits that
3187 // cancel each other out must be combined into one.
3188 while let Some((next_range, next_text)) = lsp_edits.peek() {
3189 if next_range.start.0 > range.end {
3190 if next_range.start.0.row > range.end.row + 1
3191 || next_range.start.0.column > 0
3192 || snapshot.clip_point_utf16(
3193 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3194 Bias::Left,
3195 ) > range.end
3196 {
3197 break;
3198 }
3199 new_text.push('\n');
3200 }
3201 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3202 new_text.push_str(next_text);
3203 lsp_edits.next();
3204 }
3205
3206 // For multiline edits, perform a diff of the old and new text so that
3207 // we can identify the changes more precisely, preserving the locations
3208 // of any anchors positioned in the unchanged regions.
3209 if range.end.row > range.start.row {
3210 let offset = range.start.to_offset(&snapshot);
3211 let old_text = snapshot.text_for_range(range).collect::<String>();
3212 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3213 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3214 (
3215 snapshot.anchor_after(offset + range.start)
3216 ..snapshot.anchor_before(offset + range.end),
3217 replacement,
3218 )
3219 }));
3220 } else if range.end == range.start {
3221 let anchor = snapshot.anchor_after(range.start);
3222 edits.push((anchor..anchor, new_text.into()));
3223 } else {
3224 let edit_start = snapshot.anchor_after(range.start);
3225 let edit_end = snapshot.anchor_before(range.end);
3226 edits.push((edit_start..edit_end, new_text.into()));
3227 }
3228 }
3229
3230 Ok(edits)
3231 })
3232 }
3233
3234 pub(crate) async fn deserialize_workspace_edit(
3235 this: Entity<LspStore>,
3236 edit: lsp::WorkspaceEdit,
3237 push_to_history: bool,
3238 language_server: Arc<LanguageServer>,
3239 cx: &mut AsyncApp,
3240 ) -> Result<ProjectTransaction> {
3241 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3242
3243 let mut operations = Vec::new();
3244 if let Some(document_changes) = edit.document_changes {
3245 match document_changes {
3246 lsp::DocumentChanges::Edits(edits) => {
3247 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3248 }
3249 lsp::DocumentChanges::Operations(ops) => operations = ops,
3250 }
3251 } else if let Some(changes) = edit.changes {
3252 operations.extend(changes.into_iter().map(|(uri, edits)| {
3253 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3254 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3255 uri,
3256 version: None,
3257 },
3258 edits: edits.into_iter().map(Edit::Plain).collect(),
3259 })
3260 }));
3261 }
3262
3263 let mut project_transaction = ProjectTransaction::default();
3264 for operation in operations {
3265 match operation {
3266 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3267 let abs_path = op
3268 .uri
3269 .to_file_path()
3270 .map_err(|()| anyhow!("can't convert URI to path"))?;
3271
3272 if let Some(parent_path) = abs_path.parent() {
3273 fs.create_dir(parent_path).await?;
3274 }
3275 if abs_path.ends_with("/") {
3276 fs.create_dir(&abs_path).await?;
3277 } else {
3278 fs.create_file(
3279 &abs_path,
3280 op.options
3281 .map(|options| fs::CreateOptions {
3282 overwrite: options.overwrite.unwrap_or(false),
3283 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3284 })
3285 .unwrap_or_default(),
3286 )
3287 .await?;
3288 }
3289 }
3290
3291 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3292 let source_abs_path = op
3293 .old_uri
3294 .to_file_path()
3295 .map_err(|()| anyhow!("can't convert URI to path"))?;
3296 let target_abs_path = op
3297 .new_uri
3298 .to_file_path()
3299 .map_err(|()| anyhow!("can't convert URI to path"))?;
3300
3301 let options = fs::RenameOptions {
3302 overwrite: op
3303 .options
3304 .as_ref()
3305 .and_then(|options| options.overwrite)
3306 .unwrap_or(false),
3307 ignore_if_exists: op
3308 .options
3309 .as_ref()
3310 .and_then(|options| options.ignore_if_exists)
3311 .unwrap_or(false),
3312 create_parents: true,
3313 };
3314
3315 fs.rename(&source_abs_path, &target_abs_path, options)
3316 .await?;
3317 }
3318
3319 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3320 let abs_path = op
3321 .uri
3322 .to_file_path()
3323 .map_err(|()| anyhow!("can't convert URI to path"))?;
3324 let options = op
3325 .options
3326 .map(|options| fs::RemoveOptions {
3327 recursive: options.recursive.unwrap_or(false),
3328 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3329 })
3330 .unwrap_or_default();
3331 if abs_path.ends_with("/") {
3332 fs.remove_dir(&abs_path, options).await?;
3333 } else {
3334 fs.remove_file(&abs_path, options).await?;
3335 }
3336 }
3337
3338 lsp::DocumentChangeOperation::Edit(op) => {
3339 let buffer_to_edit = this
3340 .update(cx, |this, cx| {
3341 this.open_local_buffer_via_lsp(
3342 op.text_document.uri.clone(),
3343 language_server.server_id(),
3344 cx,
3345 )
3346 })
3347 .await?;
3348
3349 let edits = this
3350 .update(cx, |this, cx| {
3351 let path = buffer_to_edit.read(cx).project_path(cx);
3352 let active_entry = this.active_entry;
3353 let is_active_entry = path.is_some_and(|project_path| {
3354 this.worktree_store
3355 .read(cx)
3356 .entry_for_path(&project_path, cx)
3357 .is_some_and(|entry| Some(entry.id) == active_entry)
3358 });
3359 let local = this.as_local_mut().unwrap();
3360
3361 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3362 for edit in op.edits {
3363 match edit {
3364 Edit::Plain(edit) => {
3365 if !edits.contains(&edit) {
3366 edits.push(edit)
3367 }
3368 }
3369 Edit::Annotated(edit) => {
3370 if !edits.contains(&edit.text_edit) {
3371 edits.push(edit.text_edit)
3372 }
3373 }
3374 Edit::Snippet(edit) => {
3375 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3376 else {
3377 continue;
3378 };
3379
3380 if is_active_entry {
3381 snippet_edits.push((edit.range, snippet));
3382 } else {
3383 // Since this buffer is not focused, apply a normal edit.
3384 let new_edit = TextEdit {
3385 range: edit.range,
3386 new_text: snippet.text,
3387 };
3388 if !edits.contains(&new_edit) {
3389 edits.push(new_edit);
3390 }
3391 }
3392 }
3393 }
3394 }
3395 if !snippet_edits.is_empty() {
3396 let buffer_id = buffer_to_edit.read(cx).remote_id();
3397 let version = if let Some(buffer_version) = op.text_document.version
3398 {
3399 local
3400 .buffer_snapshot_for_lsp_version(
3401 &buffer_to_edit,
3402 language_server.server_id(),
3403 Some(buffer_version),
3404 cx,
3405 )
3406 .ok()
3407 .map(|snapshot| snapshot.version)
3408 } else {
3409 Some(buffer_to_edit.read(cx).saved_version().clone())
3410 };
3411
3412 let most_recent_edit =
3413 version.and_then(|version| version.most_recent());
3414 // Check if the edit that triggered that edit has been made by this participant.
3415
3416 if let Some(most_recent_edit) = most_recent_edit {
3417 cx.emit(LspStoreEvent::SnippetEdit {
3418 buffer_id,
3419 edits: snippet_edits,
3420 most_recent_edit,
3421 });
3422 }
3423 }
3424
3425 local.edits_from_lsp(
3426 &buffer_to_edit,
3427 edits,
3428 language_server.server_id(),
3429 op.text_document.version,
3430 cx,
3431 )
3432 })
3433 .await?;
3434
3435 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3436 buffer.finalize_last_transaction();
3437 buffer.start_transaction();
3438 for (range, text) in edits {
3439 buffer.edit([(range, text)], None, cx);
3440 }
3441
3442 buffer.end_transaction(cx).and_then(|transaction_id| {
3443 if push_to_history {
3444 buffer.finalize_last_transaction();
3445 buffer.get_transaction(transaction_id).cloned()
3446 } else {
3447 buffer.forget_transaction(transaction_id)
3448 }
3449 })
3450 });
3451 if let Some(transaction) = transaction {
3452 project_transaction.0.insert(buffer_to_edit, transaction);
3453 }
3454 }
3455 }
3456 }
3457
3458 Ok(project_transaction)
3459 }
3460
3461 async fn on_lsp_workspace_edit(
3462 this: WeakEntity<LspStore>,
3463 params: lsp::ApplyWorkspaceEditParams,
3464 server_id: LanguageServerId,
3465 cx: &mut AsyncApp,
3466 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3467 let this = this.upgrade().context("project project closed")?;
3468 let language_server = this
3469 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3470 .context("language server not found")?;
3471 let transaction = Self::deserialize_workspace_edit(
3472 this.clone(),
3473 params.edit,
3474 true,
3475 language_server.clone(),
3476 cx,
3477 )
3478 .await
3479 .log_err();
3480 this.update(cx, |this, cx| {
3481 if let Some(transaction) = transaction {
3482 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3483
3484 this.as_local_mut()
3485 .unwrap()
3486 .last_workspace_edits_by_language_server
3487 .insert(server_id, transaction);
3488 }
3489 });
3490 Ok(lsp::ApplyWorkspaceEditResponse {
3491 applied: true,
3492 failed_change: None,
3493 failure_reason: None,
3494 })
3495 }
3496
3497 fn remove_worktree(
3498 &mut self,
3499 id_to_remove: WorktreeId,
3500 cx: &mut Context<LspStore>,
3501 ) -> Vec<LanguageServerId> {
3502 self.restricted_worktrees_tasks.remove(&id_to_remove);
3503 self.diagnostics.remove(&id_to_remove);
3504 self.prettier_store.update(cx, |prettier_store, cx| {
3505 prettier_store.remove_worktree(id_to_remove, cx);
3506 });
3507
3508 let mut servers_to_remove = BTreeSet::default();
3509 let mut servers_to_preserve = HashSet::default();
3510 for (seed, state) in &self.language_server_ids {
3511 if seed.worktree_id == id_to_remove {
3512 servers_to_remove.insert(state.id);
3513 } else {
3514 servers_to_preserve.insert(state.id);
3515 }
3516 }
3517 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3518 self.language_server_ids
3519 .retain(|_, state| !servers_to_remove.contains(&state.id));
3520 for server_id_to_remove in &servers_to_remove {
3521 self.language_server_watched_paths
3522 .remove(server_id_to_remove);
3523 self.language_server_paths_watched_for_rename
3524 .remove(server_id_to_remove);
3525 self.last_workspace_edits_by_language_server
3526 .remove(server_id_to_remove);
3527 self.language_servers.remove(server_id_to_remove);
3528 self.buffer_pull_diagnostics_result_ids
3529 .remove(server_id_to_remove);
3530 self.workspace_pull_diagnostics_result_ids
3531 .remove(server_id_to_remove);
3532 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3533 buffer_servers.remove(server_id_to_remove);
3534 }
3535 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3536 }
3537 servers_to_remove.into_iter().collect()
3538 }
3539
3540 fn rebuild_watched_paths_inner<'a>(
3541 &'a self,
3542 language_server_id: LanguageServerId,
3543 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3544 cx: &mut Context<LspStore>,
3545 ) -> LanguageServerWatchedPathsBuilder {
3546 let worktrees = self
3547 .worktree_store
3548 .read(cx)
3549 .worktrees()
3550 .filter_map(|worktree| {
3551 self.language_servers_for_worktree(worktree.read(cx).id())
3552 .find(|server| server.server_id() == language_server_id)
3553 .map(|_| worktree)
3554 })
3555 .collect::<Vec<_>>();
3556
3557 let mut worktree_globs = HashMap::default();
3558 let mut abs_globs = HashMap::default();
3559 log::trace!(
3560 "Processing new watcher paths for language server with id {}",
3561 language_server_id
3562 );
3563
3564 for watcher in watchers {
3565 if let Some((worktree, literal_prefix, pattern)) =
3566 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3567 {
3568 worktree.update(cx, |worktree, _| {
3569 if let Some((tree, glob)) =
3570 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3571 {
3572 tree.add_path_prefix_to_scan(literal_prefix);
3573 worktree_globs
3574 .entry(tree.id())
3575 .or_insert_with(GlobSetBuilder::new)
3576 .add(glob);
3577 }
3578 });
3579 } else {
3580 let (path, pattern) = match &watcher.glob_pattern {
3581 lsp::GlobPattern::String(s) => {
3582 let watcher_path = SanitizedPath::new(s);
3583 let path = glob_literal_prefix(watcher_path.as_path());
3584 let pattern = watcher_path
3585 .as_path()
3586 .strip_prefix(&path)
3587 .map(|p| p.to_string_lossy().into_owned())
3588 .unwrap_or_else(|e| {
3589 debug_panic!(
3590 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3591 s,
3592 path.display(),
3593 e
3594 );
3595 watcher_path.as_path().to_string_lossy().into_owned()
3596 });
3597 (path, pattern)
3598 }
3599 lsp::GlobPattern::Relative(rp) => {
3600 let Ok(mut base_uri) = match &rp.base_uri {
3601 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3602 lsp::OneOf::Right(base_uri) => base_uri,
3603 }
3604 .to_file_path() else {
3605 continue;
3606 };
3607
3608 let path = glob_literal_prefix(Path::new(&rp.pattern));
3609 let pattern = Path::new(&rp.pattern)
3610 .strip_prefix(&path)
3611 .map(|p| p.to_string_lossy().into_owned())
3612 .unwrap_or_else(|e| {
3613 debug_panic!(
3614 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3615 rp.pattern,
3616 path.display(),
3617 e
3618 );
3619 rp.pattern.clone()
3620 });
3621 base_uri.push(path);
3622 (base_uri, pattern)
3623 }
3624 };
3625
3626 if let Some(glob) = Glob::new(&pattern).log_err() {
3627 if !path
3628 .components()
3629 .any(|c| matches!(c, path::Component::Normal(_)))
3630 {
3631 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3632 // rather than adding a new watcher for `/`.
3633 for worktree in &worktrees {
3634 worktree_globs
3635 .entry(worktree.read(cx).id())
3636 .or_insert_with(GlobSetBuilder::new)
3637 .add(glob.clone());
3638 }
3639 } else {
3640 abs_globs
3641 .entry(path.into())
3642 .or_insert_with(GlobSetBuilder::new)
3643 .add(glob);
3644 }
3645 }
3646 }
3647 }
3648
3649 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3650 for (worktree_id, builder) in worktree_globs {
3651 if let Ok(globset) = builder.build() {
3652 watch_builder.watch_worktree(worktree_id, globset);
3653 }
3654 }
3655 for (abs_path, builder) in abs_globs {
3656 if let Ok(globset) = builder.build() {
3657 watch_builder.watch_abs_path(abs_path, globset);
3658 }
3659 }
3660 watch_builder
3661 }
3662
3663 fn worktree_and_path_for_file_watcher(
3664 worktrees: &[Entity<Worktree>],
3665 watcher: &FileSystemWatcher,
3666 cx: &App,
3667 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3668 worktrees.iter().find_map(|worktree| {
3669 let tree = worktree.read(cx);
3670 let worktree_root_path = tree.abs_path();
3671 let path_style = tree.path_style();
3672 match &watcher.glob_pattern {
3673 lsp::GlobPattern::String(s) => {
3674 let watcher_path = SanitizedPath::new(s);
3675 let relative = watcher_path
3676 .as_path()
3677 .strip_prefix(&worktree_root_path)
3678 .ok()?;
3679 let literal_prefix = glob_literal_prefix(relative);
3680 Some((
3681 worktree.clone(),
3682 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3683 relative.to_string_lossy().into_owned(),
3684 ))
3685 }
3686 lsp::GlobPattern::Relative(rp) => {
3687 let base_uri = match &rp.base_uri {
3688 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3689 lsp::OneOf::Right(base_uri) => base_uri,
3690 }
3691 .to_file_path()
3692 .ok()?;
3693 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3694 let mut literal_prefix = relative.to_owned();
3695 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3696 Some((
3697 worktree.clone(),
3698 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3699 rp.pattern.clone(),
3700 ))
3701 }
3702 }
3703 })
3704 }
3705
3706 fn rebuild_watched_paths(
3707 &mut self,
3708 language_server_id: LanguageServerId,
3709 cx: &mut Context<LspStore>,
3710 ) {
3711 let Some(registrations) = self
3712 .language_server_dynamic_registrations
3713 .get(&language_server_id)
3714 else {
3715 return;
3716 };
3717
3718 let watch_builder = self.rebuild_watched_paths_inner(
3719 language_server_id,
3720 registrations.did_change_watched_files.values().flatten(),
3721 cx,
3722 );
3723 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3724 self.language_server_watched_paths
3725 .insert(language_server_id, watcher);
3726
3727 cx.notify();
3728 }
3729
3730 fn on_lsp_did_change_watched_files(
3731 &mut self,
3732 language_server_id: LanguageServerId,
3733 registration_id: &str,
3734 params: DidChangeWatchedFilesRegistrationOptions,
3735 cx: &mut Context<LspStore>,
3736 ) {
3737 let registrations = self
3738 .language_server_dynamic_registrations
3739 .entry(language_server_id)
3740 .or_default();
3741
3742 registrations
3743 .did_change_watched_files
3744 .insert(registration_id.to_string(), params.watchers);
3745
3746 self.rebuild_watched_paths(language_server_id, cx);
3747 }
3748
3749 fn on_lsp_unregister_did_change_watched_files(
3750 &mut self,
3751 language_server_id: LanguageServerId,
3752 registration_id: &str,
3753 cx: &mut Context<LspStore>,
3754 ) {
3755 let registrations = self
3756 .language_server_dynamic_registrations
3757 .entry(language_server_id)
3758 .or_default();
3759
3760 if registrations
3761 .did_change_watched_files
3762 .remove(registration_id)
3763 .is_some()
3764 {
3765 log::info!(
3766 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3767 language_server_id,
3768 registration_id
3769 );
3770 } else {
3771 log::warn!(
3772 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3773 language_server_id,
3774 registration_id
3775 );
3776 }
3777
3778 self.rebuild_watched_paths(language_server_id, cx);
3779 }
3780
3781 async fn initialization_options_for_adapter(
3782 adapter: Arc<dyn LspAdapter>,
3783 delegate: &Arc<dyn LspAdapterDelegate>,
3784 cx: &mut AsyncApp,
3785 ) -> Result<Option<serde_json::Value>> {
3786 let Some(mut initialization_config) =
3787 adapter.clone().initialization_options(delegate, cx).await?
3788 else {
3789 return Ok(None);
3790 };
3791
3792 for other_adapter in delegate.registered_lsp_adapters() {
3793 if other_adapter.name() == adapter.name() {
3794 continue;
3795 }
3796 if let Ok(Some(target_config)) = other_adapter
3797 .clone()
3798 .additional_initialization_options(adapter.name(), delegate)
3799 .await
3800 {
3801 merge_json_value_into(target_config.clone(), &mut initialization_config);
3802 }
3803 }
3804
3805 Ok(Some(initialization_config))
3806 }
3807
3808 async fn workspace_configuration_for_adapter(
3809 adapter: Arc<dyn LspAdapter>,
3810 delegate: &Arc<dyn LspAdapterDelegate>,
3811 toolchain: Option<Toolchain>,
3812 requested_uri: Option<Uri>,
3813 cx: &mut AsyncApp,
3814 ) -> Result<serde_json::Value> {
3815 let mut workspace_config = adapter
3816 .clone()
3817 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3818 .await?;
3819
3820 for other_adapter in delegate.registered_lsp_adapters() {
3821 if other_adapter.name() == adapter.name() {
3822 continue;
3823 }
3824 if let Ok(Some(target_config)) = other_adapter
3825 .clone()
3826 .additional_workspace_configuration(adapter.name(), delegate, cx)
3827 .await
3828 {
3829 merge_json_value_into(target_config.clone(), &mut workspace_config);
3830 }
3831 }
3832
3833 Ok(workspace_config)
3834 }
3835
3836 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3837 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3838 Some(server.clone())
3839 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3840 Some(Arc::clone(server))
3841 } else {
3842 None
3843 }
3844 }
3845}
3846
3847fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3848 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3849 cx.emit(LspStoreEvent::LanguageServerUpdate {
3850 language_server_id: server.server_id(),
3851 name: Some(server.name()),
3852 message: proto::update_language_server::Variant::MetadataUpdated(
3853 proto::ServerMetadataUpdated {
3854 capabilities: Some(capabilities),
3855 binary: Some(proto::LanguageServerBinaryInfo {
3856 path: server.binary().path.to_string_lossy().into_owned(),
3857 arguments: server
3858 .binary()
3859 .arguments
3860 .iter()
3861 .map(|arg| arg.to_string_lossy().into_owned())
3862 .collect(),
3863 }),
3864 configuration: serde_json::to_string(server.configuration()).ok(),
3865 workspace_folders: server
3866 .workspace_folders()
3867 .iter()
3868 .map(|uri| uri.to_string())
3869 .collect(),
3870 },
3871 ),
3872 });
3873 }
3874}
3875
3876#[derive(Debug)]
3877pub struct FormattableBuffer {
3878 handle: Entity<Buffer>,
3879 abs_path: Option<PathBuf>,
3880 env: Option<HashMap<String, String>>,
3881 ranges: Option<Vec<Range<Anchor>>>,
3882}
3883
3884pub struct RemoteLspStore {
3885 upstream_client: Option<AnyProtoClient>,
3886 upstream_project_id: u64,
3887}
3888
3889pub(crate) enum LspStoreMode {
3890 Local(LocalLspStore), // ssh host and collab host
3891 Remote(RemoteLspStore), // collab guest
3892}
3893
3894impl LspStoreMode {
3895 fn is_local(&self) -> bool {
3896 matches!(self, LspStoreMode::Local(_))
3897 }
3898}
3899
3900pub struct LspStore {
3901 mode: LspStoreMode,
3902 last_formatting_failure: Option<String>,
3903 downstream_client: Option<(AnyProtoClient, u64)>,
3904 nonce: u128,
3905 buffer_store: Entity<BufferStore>,
3906 worktree_store: Entity<WorktreeStore>,
3907 pub languages: Arc<LanguageRegistry>,
3908 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3909 active_entry: Option<ProjectEntryId>,
3910 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3911 _maintain_buffer_languages: Task<()>,
3912 diagnostic_summaries:
3913 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3914 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3915 semantic_token_config: SemanticTokenConfig,
3916 lsp_data: HashMap<BufferId, BufferLspData>,
3917 next_hint_id: Arc<AtomicUsize>,
3918}
3919
3920#[derive(Debug)]
3921pub struct BufferLspData {
3922 buffer_version: Global,
3923 document_colors: Option<DocumentColorData>,
3924 code_lens: Option<CodeLensData>,
3925 semantic_tokens: Option<SemanticTokensData>,
3926 folding_ranges: Option<FoldingRangeData>,
3927 document_symbols: Option<DocumentSymbolsData>,
3928 inlay_hints: BufferInlayHints,
3929 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3930 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3931}
3932
3933#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3934struct LspKey {
3935 request_type: TypeId,
3936 server_queried: Option<LanguageServerId>,
3937}
3938
3939impl BufferLspData {
3940 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3941 Self {
3942 buffer_version: buffer.read(cx).version(),
3943 document_colors: None,
3944 code_lens: None,
3945 semantic_tokens: None,
3946 folding_ranges: None,
3947 document_symbols: None,
3948 inlay_hints: BufferInlayHints::new(buffer, cx),
3949 lsp_requests: HashMap::default(),
3950 chunk_lsp_requests: HashMap::default(),
3951 }
3952 }
3953
3954 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3955 if let Some(document_colors) = &mut self.document_colors {
3956 document_colors.remove_server_data(for_server);
3957 }
3958
3959 if let Some(code_lens) = &mut self.code_lens {
3960 code_lens.remove_server_data(for_server);
3961 }
3962
3963 self.inlay_hints.remove_server_data(for_server);
3964
3965 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3966 semantic_tokens.raw_tokens.servers.remove(&for_server);
3967 semantic_tokens
3968 .latest_invalidation_requests
3969 .remove(&for_server);
3970 }
3971
3972 if let Some(folding_ranges) = &mut self.folding_ranges {
3973 folding_ranges.ranges.remove(&for_server);
3974 }
3975
3976 if let Some(document_symbols) = &mut self.document_symbols {
3977 document_symbols.remove_server_data(for_server);
3978 }
3979 }
3980
3981 #[cfg(any(test, feature = "test-support"))]
3982 pub fn inlay_hints(&self) -> &BufferInlayHints {
3983 &self.inlay_hints
3984 }
3985}
3986
3987#[derive(Debug)]
3988pub enum LspStoreEvent {
3989 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3990 LanguageServerRemoved(LanguageServerId),
3991 LanguageServerUpdate {
3992 language_server_id: LanguageServerId,
3993 name: Option<LanguageServerName>,
3994 message: proto::update_language_server::Variant,
3995 },
3996 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3997 LanguageServerPrompt(LanguageServerPromptRequest),
3998 LanguageDetected {
3999 buffer: Entity<Buffer>,
4000 new_language: Option<Arc<Language>>,
4001 },
4002 Notification(String),
4003 RefreshInlayHints {
4004 server_id: LanguageServerId,
4005 request_id: Option<usize>,
4006 },
4007 RefreshSemanticTokens {
4008 server_id: LanguageServerId,
4009 request_id: Option<usize>,
4010 },
4011 RefreshCodeLens,
4012 DiagnosticsUpdated {
4013 server_id: LanguageServerId,
4014 paths: Vec<ProjectPath>,
4015 },
4016 DiskBasedDiagnosticsStarted {
4017 language_server_id: LanguageServerId,
4018 },
4019 DiskBasedDiagnosticsFinished {
4020 language_server_id: LanguageServerId,
4021 },
4022 SnippetEdit {
4023 buffer_id: BufferId,
4024 edits: Vec<(lsp::Range, Snippet)>,
4025 most_recent_edit: clock::Lamport,
4026 },
4027 WorkspaceEditApplied(ProjectTransaction),
4028}
4029
4030#[derive(Clone, Debug, Serialize)]
4031pub struct LanguageServerStatus {
4032 pub name: LanguageServerName,
4033 pub server_version: Option<SharedString>,
4034 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4035 pub has_pending_diagnostic_updates: bool,
4036 pub progress_tokens: HashSet<ProgressToken>,
4037 pub worktree: Option<WorktreeId>,
4038 pub binary: Option<LanguageServerBinary>,
4039 pub configuration: Option<Value>,
4040 pub workspace_folders: BTreeSet<Uri>,
4041 pub process_id: Option<u32>,
4042}
4043
4044#[derive(Clone, Debug)]
4045struct CoreSymbol {
4046 pub language_server_name: LanguageServerName,
4047 pub source_worktree_id: WorktreeId,
4048 pub source_language_server_id: LanguageServerId,
4049 pub path: SymbolLocation,
4050 pub name: String,
4051 pub kind: lsp::SymbolKind,
4052 pub range: Range<Unclipped<PointUtf16>>,
4053 pub container_name: Option<String>,
4054}
4055
4056#[derive(Clone, Debug, PartialEq, Eq)]
4057pub enum SymbolLocation {
4058 InProject(ProjectPath),
4059 OutsideProject {
4060 abs_path: Arc<Path>,
4061 signature: [u8; 32],
4062 },
4063}
4064
4065impl SymbolLocation {
4066 fn file_name(&self) -> Option<&str> {
4067 match self {
4068 Self::InProject(path) => path.path.file_name(),
4069 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4070 }
4071 }
4072}
4073
4074impl LspStore {
4075 pub fn init(client: &AnyProtoClient) {
4076 client.add_entity_request_handler(Self::handle_lsp_query);
4077 client.add_entity_message_handler(Self::handle_lsp_query_response);
4078 client.add_entity_request_handler(Self::handle_restart_language_servers);
4079 client.add_entity_request_handler(Self::handle_stop_language_servers);
4080 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4081 client.add_entity_message_handler(Self::handle_start_language_server);
4082 client.add_entity_message_handler(Self::handle_update_language_server);
4083 client.add_entity_message_handler(Self::handle_language_server_log);
4084 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4085 client.add_entity_request_handler(Self::handle_format_buffers);
4086 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4087 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4088 client.add_entity_request_handler(Self::handle_apply_code_action);
4089 client.add_entity_request_handler(Self::handle_get_project_symbols);
4090 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4091 client.add_entity_request_handler(Self::handle_get_color_presentation);
4092 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4093 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4094 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4095 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4096 client.add_entity_request_handler(Self::handle_on_type_formatting);
4097 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4098 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4099 client.add_entity_request_handler(Self::handle_rename_project_entry);
4100 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4101 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4102 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4103 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4104 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4105 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4106 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4107
4108 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4109 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4110 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4111 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4112 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4113 client.add_entity_request_handler(
4114 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4115 );
4116 client.add_entity_request_handler(
4117 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4118 );
4119 client.add_entity_request_handler(
4120 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4121 );
4122 }
4123
4124 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4125 match &self.mode {
4126 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4127 _ => None,
4128 }
4129 }
4130
4131 pub fn as_local(&self) -> Option<&LocalLspStore> {
4132 match &self.mode {
4133 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4134 _ => None,
4135 }
4136 }
4137
4138 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4139 match &mut self.mode {
4140 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4141 _ => None,
4142 }
4143 }
4144
4145 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4146 match &self.mode {
4147 LspStoreMode::Remote(RemoteLspStore {
4148 upstream_client: Some(upstream_client),
4149 upstream_project_id,
4150 ..
4151 }) => Some((upstream_client.clone(), *upstream_project_id)),
4152
4153 LspStoreMode::Remote(RemoteLspStore {
4154 upstream_client: None,
4155 ..
4156 }) => None,
4157 LspStoreMode::Local(_) => None,
4158 }
4159 }
4160
4161 pub fn new_local(
4162 buffer_store: Entity<BufferStore>,
4163 worktree_store: Entity<WorktreeStore>,
4164 prettier_store: Entity<PrettierStore>,
4165 toolchain_store: Entity<LocalToolchainStore>,
4166 environment: Entity<ProjectEnvironment>,
4167 manifest_tree: Entity<ManifestTree>,
4168 languages: Arc<LanguageRegistry>,
4169 http_client: Arc<dyn HttpClient>,
4170 fs: Arc<dyn Fs>,
4171 cx: &mut Context<Self>,
4172 ) -> Self {
4173 let yarn = YarnPathStore::new(fs.clone(), cx);
4174 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4175 .detach();
4176 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4177 .detach();
4178 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4179 .detach();
4180 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4181 .detach();
4182 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4183 .detach();
4184 subscribe_to_binary_statuses(&languages, cx).detach();
4185
4186 let _maintain_workspace_config = {
4187 let (sender, receiver) = watch::channel();
4188 (Self::maintain_workspace_config(receiver, cx), sender)
4189 };
4190
4191 Self {
4192 mode: LspStoreMode::Local(LocalLspStore {
4193 weak: cx.weak_entity(),
4194 worktree_store: worktree_store.clone(),
4195
4196 supplementary_language_servers: Default::default(),
4197 languages: languages.clone(),
4198 language_server_ids: Default::default(),
4199 language_servers: Default::default(),
4200 last_workspace_edits_by_language_server: Default::default(),
4201 language_server_watched_paths: Default::default(),
4202 language_server_paths_watched_for_rename: Default::default(),
4203 language_server_dynamic_registrations: Default::default(),
4204 buffers_being_formatted: Default::default(),
4205 buffers_to_refresh_hash_set: HashSet::default(),
4206 buffers_to_refresh_queue: VecDeque::new(),
4207 _background_diagnostics_worker: Task::ready(()).shared(),
4208 buffer_snapshots: Default::default(),
4209 prettier_store,
4210 environment,
4211 http_client,
4212 fs,
4213 yarn,
4214 next_diagnostic_group_id: Default::default(),
4215 diagnostics: Default::default(),
4216 _subscription: cx.on_app_quit(|this, _| {
4217 this.as_local_mut()
4218 .unwrap()
4219 .shutdown_language_servers_on_quit()
4220 }),
4221 lsp_tree: LanguageServerTree::new(
4222 manifest_tree,
4223 languages.clone(),
4224 toolchain_store.clone(),
4225 ),
4226 toolchain_store,
4227 registered_buffers: HashMap::default(),
4228 buffers_opened_in_servers: HashMap::default(),
4229 buffer_pull_diagnostics_result_ids: HashMap::default(),
4230 workspace_pull_diagnostics_result_ids: HashMap::default(),
4231 restricted_worktrees_tasks: HashMap::default(),
4232 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4233 .manifest_file_names(),
4234 }),
4235 last_formatting_failure: None,
4236 downstream_client: None,
4237 buffer_store,
4238 worktree_store,
4239 languages: languages.clone(),
4240 language_server_statuses: Default::default(),
4241 nonce: StdRng::from_os_rng().random(),
4242 diagnostic_summaries: HashMap::default(),
4243 lsp_server_capabilities: HashMap::default(),
4244 semantic_token_config: SemanticTokenConfig::new(cx),
4245 lsp_data: HashMap::default(),
4246 next_hint_id: Arc::default(),
4247 active_entry: None,
4248 _maintain_workspace_config,
4249 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4250 }
4251 }
4252
4253 fn send_lsp_proto_request<R: LspCommand>(
4254 &self,
4255 buffer: Entity<Buffer>,
4256 client: AnyProtoClient,
4257 upstream_project_id: u64,
4258 request: R,
4259 cx: &mut Context<LspStore>,
4260 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4261 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4262 return Task::ready(Ok(R::Response::default()));
4263 }
4264 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4265 cx.spawn(async move |this, cx| {
4266 let response = client.request(message).await?;
4267 let this = this.upgrade().context("project dropped")?;
4268 request
4269 .response_from_proto(response, this, buffer, cx.clone())
4270 .await
4271 })
4272 }
4273
4274 pub(super) fn new_remote(
4275 buffer_store: Entity<BufferStore>,
4276 worktree_store: Entity<WorktreeStore>,
4277 languages: Arc<LanguageRegistry>,
4278 upstream_client: AnyProtoClient,
4279 project_id: u64,
4280 cx: &mut Context<Self>,
4281 ) -> Self {
4282 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4283 .detach();
4284 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4285 .detach();
4286 subscribe_to_binary_statuses(&languages, cx).detach();
4287 let _maintain_workspace_config = {
4288 let (sender, receiver) = watch::channel();
4289 (Self::maintain_workspace_config(receiver, cx), sender)
4290 };
4291 Self {
4292 mode: LspStoreMode::Remote(RemoteLspStore {
4293 upstream_client: Some(upstream_client),
4294 upstream_project_id: project_id,
4295 }),
4296 downstream_client: None,
4297 last_formatting_failure: None,
4298 buffer_store,
4299 worktree_store,
4300 languages: languages.clone(),
4301 language_server_statuses: Default::default(),
4302 nonce: StdRng::from_os_rng().random(),
4303 diagnostic_summaries: HashMap::default(),
4304 lsp_server_capabilities: HashMap::default(),
4305 semantic_token_config: SemanticTokenConfig::new(cx),
4306 next_hint_id: Arc::default(),
4307 lsp_data: HashMap::default(),
4308 active_entry: None,
4309
4310 _maintain_workspace_config,
4311 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4312 }
4313 }
4314
4315 fn on_buffer_store_event(
4316 &mut self,
4317 _: Entity<BufferStore>,
4318 event: &BufferStoreEvent,
4319 cx: &mut Context<Self>,
4320 ) {
4321 match event {
4322 BufferStoreEvent::BufferAdded(buffer) => {
4323 self.on_buffer_added(buffer, cx).log_err();
4324 }
4325 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4326 let buffer_id = buffer.read(cx).remote_id();
4327 if let Some(local) = self.as_local_mut()
4328 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4329 {
4330 local.reset_buffer(buffer, old_file, cx);
4331
4332 if local.registered_buffers.contains_key(&buffer_id) {
4333 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4334 }
4335 }
4336
4337 self.detect_language_for_buffer(buffer, cx);
4338 if let Some(local) = self.as_local_mut() {
4339 local.initialize_buffer(buffer, cx);
4340 if local.registered_buffers.contains_key(&buffer_id) {
4341 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4342 }
4343 }
4344 }
4345 _ => {}
4346 }
4347 }
4348
4349 fn on_worktree_store_event(
4350 &mut self,
4351 _: Entity<WorktreeStore>,
4352 event: &WorktreeStoreEvent,
4353 cx: &mut Context<Self>,
4354 ) {
4355 match event {
4356 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4357 if !worktree.read(cx).is_local() {
4358 return;
4359 }
4360 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4361 worktree::Event::UpdatedEntries(changes) => {
4362 this.update_local_worktree_language_servers(&worktree, changes, cx);
4363 }
4364 worktree::Event::UpdatedGitRepositories(_)
4365 | worktree::Event::DeletedEntry(_) => {}
4366 })
4367 .detach()
4368 }
4369 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4370 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4371 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4372 }
4373 WorktreeStoreEvent::WorktreeReleased(..)
4374 | WorktreeStoreEvent::WorktreeOrderChanged
4375 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4376 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4377 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4378 }
4379 }
4380
4381 fn on_prettier_store_event(
4382 &mut self,
4383 _: Entity<PrettierStore>,
4384 event: &PrettierStoreEvent,
4385 cx: &mut Context<Self>,
4386 ) {
4387 match event {
4388 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4389 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4390 }
4391 PrettierStoreEvent::LanguageServerAdded {
4392 new_server_id,
4393 name,
4394 prettier_server,
4395 } => {
4396 self.register_supplementary_language_server(
4397 *new_server_id,
4398 name.clone(),
4399 prettier_server.clone(),
4400 cx,
4401 );
4402 }
4403 }
4404 }
4405
4406 fn on_toolchain_store_event(
4407 &mut self,
4408 _: Entity<LocalToolchainStore>,
4409 event: &ToolchainStoreEvent,
4410 _: &mut Context<Self>,
4411 ) {
4412 if let ToolchainStoreEvent::ToolchainActivated = event {
4413 self.request_workspace_config_refresh()
4414 }
4415 }
4416
4417 fn request_workspace_config_refresh(&mut self) {
4418 *self._maintain_workspace_config.1.borrow_mut() = ();
4419 }
4420
4421 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4422 self.as_local().map(|local| local.prettier_store.clone())
4423 }
4424
4425 fn on_buffer_event(
4426 &mut self,
4427 buffer: Entity<Buffer>,
4428 event: &language::BufferEvent,
4429 cx: &mut Context<Self>,
4430 ) {
4431 match event {
4432 language::BufferEvent::Edited { .. } => {
4433 self.on_buffer_edited(buffer, cx);
4434 }
4435
4436 language::BufferEvent::Saved => {
4437 self.on_buffer_saved(buffer, cx);
4438 }
4439
4440 _ => {}
4441 }
4442 }
4443
4444 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4445 buffer
4446 .read(cx)
4447 .set_language_registry(self.languages.clone());
4448
4449 cx.subscribe(buffer, |this, buffer, event, cx| {
4450 this.on_buffer_event(buffer, event, cx);
4451 })
4452 .detach();
4453
4454 self.detect_language_for_buffer(buffer, cx);
4455 if let Some(local) = self.as_local_mut() {
4456 local.initialize_buffer(buffer, cx);
4457 }
4458
4459 Ok(())
4460 }
4461
4462 pub fn refresh_background_diagnostics_for_buffers(
4463 &mut self,
4464 buffers: HashSet<BufferId>,
4465 cx: &mut Context<Self>,
4466 ) -> Shared<Task<()>> {
4467 let Some(local) = self.as_local_mut() else {
4468 return Task::ready(()).shared();
4469 };
4470 for buffer in buffers {
4471 if local.buffers_to_refresh_hash_set.insert(buffer) {
4472 local.buffers_to_refresh_queue.push_back(buffer);
4473 if local.buffers_to_refresh_queue.len() == 1 {
4474 local._background_diagnostics_worker =
4475 Self::background_diagnostics_worker(cx).shared();
4476 }
4477 }
4478 }
4479
4480 local._background_diagnostics_worker.clone()
4481 }
4482
4483 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4484 let buffer_store = self.buffer_store.clone();
4485 let local = self.as_local_mut()?;
4486 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4487 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4488 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4489 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4490 }
4491 }
4492 None
4493 }
4494
4495 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4496 cx.spawn(async move |this, cx| {
4497 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4498 task.await.log_err();
4499 }
4500 })
4501 }
4502
4503 pub(crate) fn register_buffer_with_language_servers(
4504 &mut self,
4505 buffer: &Entity<Buffer>,
4506 only_register_servers: HashSet<LanguageServerSelector>,
4507 ignore_refcounts: bool,
4508 cx: &mut Context<Self>,
4509 ) -> OpenLspBufferHandle {
4510 let buffer_id = buffer.read(cx).remote_id();
4511 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4512 if let Some(local) = self.as_local_mut() {
4513 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4514 if !ignore_refcounts {
4515 *refcount += 1;
4516 }
4517
4518 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4519 // 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
4520 // 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
4521 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4522 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4523 return handle;
4524 };
4525 if !file.is_local() {
4526 return handle;
4527 }
4528
4529 if ignore_refcounts || *refcount == 1 {
4530 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4531 }
4532 if !ignore_refcounts {
4533 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4534 let refcount = {
4535 let local = lsp_store.as_local_mut().unwrap();
4536 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4537 debug_panic!("bad refcounting");
4538 return;
4539 };
4540
4541 *refcount -= 1;
4542 *refcount
4543 };
4544 if refcount == 0 {
4545 lsp_store.lsp_data.remove(&buffer_id);
4546 let local = lsp_store.as_local_mut().unwrap();
4547 local.registered_buffers.remove(&buffer_id);
4548
4549 local.buffers_opened_in_servers.remove(&buffer_id);
4550 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4551 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4552
4553 let buffer_abs_path = file.abs_path(cx);
4554 for (_, buffer_pull_diagnostics_result_ids) in
4555 &mut local.buffer_pull_diagnostics_result_ids
4556 {
4557 buffer_pull_diagnostics_result_ids.retain(
4558 |_, buffer_result_ids| {
4559 buffer_result_ids.remove(&buffer_abs_path);
4560 !buffer_result_ids.is_empty()
4561 },
4562 );
4563 }
4564
4565 let diagnostic_updates = local
4566 .language_servers
4567 .keys()
4568 .cloned()
4569 .map(|server_id| DocumentDiagnosticsUpdate {
4570 diagnostics: DocumentDiagnostics {
4571 document_abs_path: buffer_abs_path.clone(),
4572 version: None,
4573 diagnostics: Vec::new(),
4574 },
4575 result_id: None,
4576 registration_id: None,
4577 server_id,
4578 disk_based_sources: Cow::Borrowed(&[]),
4579 })
4580 .collect::<Vec<_>>();
4581
4582 lsp_store
4583 .merge_diagnostic_entries(
4584 diagnostic_updates,
4585 |_, diagnostic, _| {
4586 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4587 },
4588 cx,
4589 )
4590 .context("Clearing diagnostics for the closed buffer")
4591 .log_err();
4592 }
4593 }
4594 })
4595 .detach();
4596 }
4597 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4598 let buffer_id = buffer.read(cx).remote_id().to_proto();
4599 cx.background_spawn(async move {
4600 upstream_client
4601 .request(proto::RegisterBufferWithLanguageServers {
4602 project_id: upstream_project_id,
4603 buffer_id,
4604 only_servers: only_register_servers
4605 .into_iter()
4606 .map(|selector| {
4607 let selector = match selector {
4608 LanguageServerSelector::Id(language_server_id) => {
4609 proto::language_server_selector::Selector::ServerId(
4610 language_server_id.to_proto(),
4611 )
4612 }
4613 LanguageServerSelector::Name(language_server_name) => {
4614 proto::language_server_selector::Selector::Name(
4615 language_server_name.to_string(),
4616 )
4617 }
4618 };
4619 proto::LanguageServerSelector {
4620 selector: Some(selector),
4621 }
4622 })
4623 .collect(),
4624 })
4625 .await
4626 })
4627 .detach();
4628 } else {
4629 // Our remote connection got closed
4630 }
4631 handle
4632 }
4633
4634 fn maintain_buffer_languages(
4635 languages: Arc<LanguageRegistry>,
4636 cx: &mut Context<Self>,
4637 ) -> Task<()> {
4638 let mut subscription = languages.subscribe();
4639 let mut prev_reload_count = languages.reload_count();
4640 cx.spawn(async move |this, cx| {
4641 while let Some(()) = subscription.next().await {
4642 if let Some(this) = this.upgrade() {
4643 // If the language registry has been reloaded, then remove and
4644 // re-assign the languages on all open buffers.
4645 let reload_count = languages.reload_count();
4646 if reload_count > prev_reload_count {
4647 prev_reload_count = reload_count;
4648 this.update(cx, |this, cx| {
4649 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4650 for buffer in buffer_store.buffers() {
4651 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4652 {
4653 buffer.update(cx, |buffer, cx| {
4654 buffer.set_language_async(None, cx)
4655 });
4656 if let Some(local) = this.as_local_mut() {
4657 local.reset_buffer(&buffer, &f, cx);
4658
4659 if local
4660 .registered_buffers
4661 .contains_key(&buffer.read(cx).remote_id())
4662 && let Some(file_url) =
4663 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4664 {
4665 local.unregister_buffer_from_language_servers(
4666 &buffer, &file_url, cx,
4667 );
4668 }
4669 }
4670 }
4671 }
4672 });
4673 });
4674 }
4675
4676 this.update(cx, |this, cx| {
4677 let mut plain_text_buffers = Vec::new();
4678 let mut buffers_with_unknown_injections = Vec::new();
4679 for handle in this.buffer_store.read(cx).buffers() {
4680 let buffer = handle.read(cx);
4681 if buffer.language().is_none()
4682 || buffer.language() == Some(&*language::PLAIN_TEXT)
4683 {
4684 plain_text_buffers.push(handle);
4685 } else if buffer.contains_unknown_injections() {
4686 buffers_with_unknown_injections.push(handle);
4687 }
4688 }
4689
4690 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4691 // and reused later in the invisible worktrees.
4692 plain_text_buffers.sort_by_key(|buffer| {
4693 Reverse(
4694 File::from_dyn(buffer.read(cx).file())
4695 .map(|file| file.worktree.read(cx).is_visible()),
4696 )
4697 });
4698
4699 for buffer in plain_text_buffers {
4700 this.detect_language_for_buffer(&buffer, cx);
4701 if let Some(local) = this.as_local_mut() {
4702 local.initialize_buffer(&buffer, cx);
4703 if local
4704 .registered_buffers
4705 .contains_key(&buffer.read(cx).remote_id())
4706 {
4707 local.register_buffer_with_language_servers(
4708 &buffer,
4709 HashSet::default(),
4710 cx,
4711 );
4712 }
4713 }
4714 }
4715
4716 for buffer in buffers_with_unknown_injections {
4717 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4718 }
4719 });
4720 }
4721 }
4722 })
4723 }
4724
4725 fn detect_language_for_buffer(
4726 &mut self,
4727 buffer_handle: &Entity<Buffer>,
4728 cx: &mut Context<Self>,
4729 ) -> Option<language::AvailableLanguage> {
4730 // If the buffer has a language, set it and start the language server if we haven't already.
4731 let buffer = buffer_handle.read(cx);
4732 let file = buffer.file()?;
4733
4734 let content = buffer.as_rope();
4735 let available_language = self.languages.language_for_file(file, Some(content), cx);
4736 if let Some(available_language) = &available_language {
4737 if let Some(Ok(Ok(new_language))) = self
4738 .languages
4739 .load_language(available_language)
4740 .now_or_never()
4741 {
4742 self.set_language_for_buffer(buffer_handle, new_language, cx);
4743 }
4744 } else {
4745 cx.emit(LspStoreEvent::LanguageDetected {
4746 buffer: buffer_handle.clone(),
4747 new_language: None,
4748 });
4749 }
4750
4751 available_language
4752 }
4753
4754 pub(crate) fn set_language_for_buffer(
4755 &mut self,
4756 buffer_entity: &Entity<Buffer>,
4757 new_language: Arc<Language>,
4758 cx: &mut Context<Self>,
4759 ) {
4760 let buffer = buffer_entity.read(cx);
4761 let buffer_file = buffer.file().cloned();
4762 let buffer_id = buffer.remote_id();
4763 if let Some(local_store) = self.as_local_mut()
4764 && local_store.registered_buffers.contains_key(&buffer_id)
4765 && let Some(abs_path) =
4766 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4767 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4768 {
4769 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4770 }
4771 buffer_entity.update(cx, |buffer, cx| {
4772 if buffer
4773 .language()
4774 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4775 {
4776 buffer.set_language_async(Some(new_language.clone()), cx);
4777 }
4778 });
4779
4780 let settings =
4781 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4782 let buffer_file = File::from_dyn(buffer_file.as_ref());
4783
4784 let worktree_id = if let Some(file) = buffer_file {
4785 let worktree = file.worktree.clone();
4786
4787 if let Some(local) = self.as_local_mut()
4788 && local.registered_buffers.contains_key(&buffer_id)
4789 {
4790 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4791 }
4792 Some(worktree.read(cx).id())
4793 } else {
4794 None
4795 };
4796
4797 if settings.prettier.allowed
4798 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4799 {
4800 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4801 if let Some(prettier_store) = prettier_store {
4802 prettier_store.update(cx, |prettier_store, cx| {
4803 prettier_store.install_default_prettier(
4804 worktree_id,
4805 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4806 cx,
4807 )
4808 })
4809 }
4810 }
4811
4812 cx.emit(LspStoreEvent::LanguageDetected {
4813 buffer: buffer_entity.clone(),
4814 new_language: Some(new_language),
4815 })
4816 }
4817
4818 pub fn buffer_store(&self) -> Entity<BufferStore> {
4819 self.buffer_store.clone()
4820 }
4821
4822 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4823 self.active_entry = active_entry;
4824 }
4825
4826 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4827 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4828 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4829 {
4830 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4831 summaries
4832 .iter()
4833 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4834 });
4835 if let Some(summary) = summaries.next() {
4836 client
4837 .send(proto::UpdateDiagnosticSummary {
4838 project_id: downstream_project_id,
4839 worktree_id: worktree.id().to_proto(),
4840 summary: Some(summary),
4841 more_summaries: summaries.collect(),
4842 })
4843 .log_err();
4844 }
4845 }
4846 }
4847
4848 fn is_capable_for_proto_request<R>(
4849 &self,
4850 buffer: &Entity<Buffer>,
4851 request: &R,
4852 cx: &App,
4853 ) -> bool
4854 where
4855 R: LspCommand,
4856 {
4857 self.check_if_capable_for_proto_request(
4858 buffer,
4859 |capabilities| {
4860 request.check_capabilities(AdapterServerCapabilities {
4861 server_capabilities: capabilities.clone(),
4862 code_action_kinds: None,
4863 })
4864 },
4865 cx,
4866 )
4867 }
4868
4869 fn check_if_capable_for_proto_request<F>(
4870 &self,
4871 buffer: &Entity<Buffer>,
4872 check: F,
4873 cx: &App,
4874 ) -> bool
4875 where
4876 F: FnMut(&lsp::ServerCapabilities) -> bool,
4877 {
4878 let Some(language) = buffer.read(cx).language().cloned() else {
4879 return false;
4880 };
4881 let registered_language_servers = self
4882 .languages
4883 .lsp_adapters(&language.name())
4884 .into_iter()
4885 .map(|lsp_adapter| lsp_adapter.name())
4886 .collect::<HashSet<_>>();
4887 self.language_server_statuses
4888 .iter()
4889 .filter_map(|(server_id, server_status)| {
4890 // Include servers that are either registered for this language OR
4891 // available to be loaded (for SSH remote mode where adapters like
4892 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4893 // but only loaded on the server side)
4894 let is_relevant = registered_language_servers.contains(&server_status.name)
4895 || self.languages.is_lsp_adapter_available(&server_status.name);
4896 is_relevant.then_some(server_id)
4897 })
4898 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4899 .any(check)
4900 }
4901
4902 fn all_capable_for_proto_request<F>(
4903 &self,
4904 buffer: &Entity<Buffer>,
4905 mut check: F,
4906 cx: &App,
4907 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4908 where
4909 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4910 {
4911 let Some(language) = buffer.read(cx).language().cloned() else {
4912 return Vec::default();
4913 };
4914 let registered_language_servers = self
4915 .languages
4916 .lsp_adapters(&language.name())
4917 .into_iter()
4918 .map(|lsp_adapter| lsp_adapter.name())
4919 .collect::<HashSet<_>>();
4920 self.language_server_statuses
4921 .iter()
4922 .filter_map(|(server_id, server_status)| {
4923 // Include servers that are either registered for this language OR
4924 // available to be loaded (for SSH remote mode where adapters like
4925 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4926 // but only loaded on the server side)
4927 let is_relevant = registered_language_servers.contains(&server_status.name)
4928 || self.languages.is_lsp_adapter_available(&server_status.name);
4929 is_relevant.then_some((server_id, &server_status.name))
4930 })
4931 .filter_map(|(server_id, server_name)| {
4932 self.lsp_server_capabilities
4933 .get(server_id)
4934 .map(|c| (server_id, server_name, c))
4935 })
4936 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4937 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
4938 .collect()
4939 }
4940
4941 pub fn request_lsp<R>(
4942 &mut self,
4943 buffer: Entity<Buffer>,
4944 server: LanguageServerToQuery,
4945 request: R,
4946 cx: &mut Context<Self>,
4947 ) -> Task<Result<R::Response>>
4948 where
4949 R: LspCommand,
4950 <R::LspRequest as lsp::request::Request>::Result: Send,
4951 <R::LspRequest as lsp::request::Request>::Params: Send,
4952 {
4953 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4954 return self.send_lsp_proto_request(
4955 buffer,
4956 upstream_client,
4957 upstream_project_id,
4958 request,
4959 cx,
4960 );
4961 }
4962
4963 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4964 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4965 local
4966 .language_servers_for_buffer(buffer, cx)
4967 .find(|(_, server)| {
4968 request.check_capabilities(server.adapter_server_capabilities())
4969 })
4970 .map(|(_, server)| server.clone())
4971 }),
4972 LanguageServerToQuery::Other(id) => self
4973 .language_server_for_local_buffer(buffer, id, cx)
4974 .and_then(|(_, server)| {
4975 request
4976 .check_capabilities(server.adapter_server_capabilities())
4977 .then(|| Arc::clone(server))
4978 }),
4979 }) else {
4980 return Task::ready(Ok(Default::default()));
4981 };
4982
4983 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4984
4985 let Some(file) = file else {
4986 return Task::ready(Ok(Default::default()));
4987 };
4988
4989 let lsp_params = match request.to_lsp_params_or_response(
4990 &file.abs_path(cx),
4991 buffer.read(cx),
4992 &language_server,
4993 cx,
4994 ) {
4995 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4996 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4997 Err(err) => {
4998 let message = format!(
4999 "{} via {} failed: {}",
5000 request.display_name(),
5001 language_server.name(),
5002 err
5003 );
5004 // rust-analyzer likes to error with this when its still loading up
5005 if !message.ends_with("content modified") {
5006 log::warn!("{message}");
5007 }
5008 return Task::ready(Err(anyhow!(message)));
5009 }
5010 };
5011
5012 let status = request.status();
5013 let request_timeout = ProjectSettings::get_global(cx)
5014 .global_lsp_settings
5015 .get_request_timeout();
5016
5017 cx.spawn(async move |this, cx| {
5018 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5019
5020 let id = lsp_request.id();
5021 let _cleanup = if status.is_some() {
5022 cx.update(|cx| {
5023 this.update(cx, |this, cx| {
5024 this.on_lsp_work_start(
5025 language_server.server_id(),
5026 ProgressToken::Number(id),
5027 LanguageServerProgress {
5028 is_disk_based_diagnostics_progress: false,
5029 is_cancellable: false,
5030 title: None,
5031 message: status.clone(),
5032 percentage: None,
5033 last_update_at: cx.background_executor().now(),
5034 },
5035 cx,
5036 );
5037 })
5038 })
5039 .log_err();
5040
5041 Some(defer(|| {
5042 cx.update(|cx| {
5043 this.update(cx, |this, cx| {
5044 this.on_lsp_work_end(
5045 language_server.server_id(),
5046 ProgressToken::Number(id),
5047 cx,
5048 );
5049 })
5050 })
5051 .log_err();
5052 }))
5053 } else {
5054 None
5055 };
5056
5057 let result = lsp_request.await.into_response();
5058
5059 let response = result.map_err(|err| {
5060 let message = format!(
5061 "{} via {} failed: {}",
5062 request.display_name(),
5063 language_server.name(),
5064 err
5065 );
5066 // rust-analyzer likes to error with this when its still loading up
5067 if !message.ends_with("content modified") {
5068 log::warn!("{message}");
5069 }
5070 anyhow::anyhow!(message)
5071 })?;
5072
5073 request
5074 .response_from_lsp(
5075 response,
5076 this.upgrade().context("no app context")?,
5077 buffer,
5078 language_server.server_id(),
5079 cx.clone(),
5080 )
5081 .await
5082 })
5083 }
5084
5085 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5086 let mut language_formatters_to_check = Vec::new();
5087 for buffer in self.buffer_store.read(cx).buffers() {
5088 let buffer = buffer.read(cx);
5089 let buffer_file = File::from_dyn(buffer.file());
5090 let buffer_language = buffer.language();
5091 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5092 if buffer_language.is_some() {
5093 language_formatters_to_check.push((
5094 buffer_file.map(|f| f.worktree_id(cx)),
5095 settings.into_owned(),
5096 ));
5097 }
5098 }
5099
5100 self.request_workspace_config_refresh();
5101
5102 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5103 prettier_store.update(cx, |prettier_store, cx| {
5104 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5105 })
5106 }
5107
5108 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5109 .global_lsp_settings
5110 .semantic_token_rules
5111 .clone();
5112 self.semantic_token_config
5113 .update_rules(new_semantic_token_rules);
5114 // Always clear cached stylizers so that changes to language-specific
5115 // semantic token rules (e.g. from extension install/uninstall) are
5116 // picked up. Stylizers are recreated lazily, so this is cheap.
5117 self.semantic_token_config.clear_stylizers();
5118
5119 let new_global_semantic_tokens_mode =
5120 all_language_settings(None, cx).defaults.semantic_tokens;
5121 if self
5122 .semantic_token_config
5123 .update_global_mode(new_global_semantic_tokens_mode)
5124 {
5125 self.restart_all_language_servers(cx);
5126 }
5127
5128 cx.notify();
5129 }
5130
5131 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5132 let buffer_store = self.buffer_store.clone();
5133 let Some(local) = self.as_local_mut() else {
5134 return;
5135 };
5136 let mut adapters = BTreeMap::default();
5137 let get_adapter = {
5138 let languages = local.languages.clone();
5139 let environment = local.environment.clone();
5140 let weak = local.weak.clone();
5141 let worktree_store = local.worktree_store.clone();
5142 let http_client = local.http_client.clone();
5143 let fs = local.fs.clone();
5144 move |worktree_id, cx: &mut App| {
5145 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5146 Some(LocalLspAdapterDelegate::new(
5147 languages.clone(),
5148 &environment,
5149 weak.clone(),
5150 &worktree,
5151 http_client.clone(),
5152 fs.clone(),
5153 cx,
5154 ))
5155 }
5156 };
5157
5158 let mut messages_to_report = Vec::new();
5159 let (new_tree, to_stop) = {
5160 let mut rebase = local.lsp_tree.rebase();
5161 let buffers = buffer_store
5162 .read(cx)
5163 .buffers()
5164 .filter_map(|buffer| {
5165 let raw_buffer = buffer.read(cx);
5166 if !local
5167 .registered_buffers
5168 .contains_key(&raw_buffer.remote_id())
5169 {
5170 return None;
5171 }
5172 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5173 let language = raw_buffer.language().cloned()?;
5174 Some((file, language, raw_buffer.remote_id()))
5175 })
5176 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5177 for (file, language, buffer_id) in buffers {
5178 let worktree_id = file.worktree_id(cx);
5179 let Some(worktree) = local
5180 .worktree_store
5181 .read(cx)
5182 .worktree_for_id(worktree_id, cx)
5183 else {
5184 continue;
5185 };
5186
5187 if let Some((_, apply)) = local.reuse_existing_language_server(
5188 rebase.server_tree(),
5189 &worktree,
5190 &language.name(),
5191 cx,
5192 ) {
5193 (apply)(rebase.server_tree());
5194 } else if let Some(lsp_delegate) = adapters
5195 .entry(worktree_id)
5196 .or_insert_with(|| get_adapter(worktree_id, cx))
5197 .clone()
5198 {
5199 let delegate =
5200 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5201 let path = file
5202 .path()
5203 .parent()
5204 .map(Arc::from)
5205 .unwrap_or_else(|| file.path().clone());
5206 let worktree_path = ProjectPath { worktree_id, path };
5207 let abs_path = file.abs_path(cx);
5208 let nodes = rebase
5209 .walk(
5210 worktree_path,
5211 language.name(),
5212 language.manifest(),
5213 delegate.clone(),
5214 cx,
5215 )
5216 .collect::<Vec<_>>();
5217 for node in nodes {
5218 let server_id = node.server_id_or_init(|disposition| {
5219 let path = &disposition.path;
5220 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5221 let key = LanguageServerSeed {
5222 worktree_id,
5223 name: disposition.server_name.clone(),
5224 settings: LanguageServerSeedSettings {
5225 binary: disposition.settings.binary.clone(),
5226 initialization_options: disposition
5227 .settings
5228 .initialization_options
5229 .clone(),
5230 },
5231 toolchain: local.toolchain_store.read(cx).active_toolchain(
5232 path.worktree_id,
5233 &path.path,
5234 language.name(),
5235 ),
5236 };
5237 local.language_server_ids.remove(&key);
5238
5239 let server_id = local.get_or_insert_language_server(
5240 &worktree,
5241 lsp_delegate.clone(),
5242 disposition,
5243 &language.name(),
5244 cx,
5245 );
5246 if let Some(state) = local.language_servers.get(&server_id)
5247 && let Ok(uri) = uri
5248 {
5249 state.add_workspace_folder(uri);
5250 };
5251 server_id
5252 });
5253
5254 if let Some(language_server_id) = server_id {
5255 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5256 language_server_id,
5257 name: node.name(),
5258 message:
5259 proto::update_language_server::Variant::RegisteredForBuffer(
5260 proto::RegisteredForBuffer {
5261 buffer_abs_path: abs_path
5262 .to_string_lossy()
5263 .into_owned(),
5264 buffer_id: buffer_id.to_proto(),
5265 },
5266 ),
5267 });
5268 }
5269 }
5270 } else {
5271 continue;
5272 }
5273 }
5274 rebase.finish()
5275 };
5276 for message in messages_to_report {
5277 cx.emit(message);
5278 }
5279 local.lsp_tree = new_tree;
5280 for (id, _) in to_stop {
5281 self.stop_local_language_server(id, cx).detach();
5282 }
5283 }
5284
5285 pub fn apply_code_action(
5286 &self,
5287 buffer_handle: Entity<Buffer>,
5288 mut action: CodeAction,
5289 push_to_history: bool,
5290 cx: &mut Context<Self>,
5291 ) -> Task<Result<ProjectTransaction>> {
5292 if let Some((upstream_client, project_id)) = self.upstream_client() {
5293 let request = proto::ApplyCodeAction {
5294 project_id,
5295 buffer_id: buffer_handle.read(cx).remote_id().into(),
5296 action: Some(Self::serialize_code_action(&action)),
5297 };
5298 let buffer_store = self.buffer_store();
5299 cx.spawn(async move |_, cx| {
5300 let response = upstream_client
5301 .request(request)
5302 .await?
5303 .transaction
5304 .context("missing transaction")?;
5305
5306 buffer_store
5307 .update(cx, |buffer_store, cx| {
5308 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5309 })
5310 .await
5311 })
5312 } else if self.mode.is_local() {
5313 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5314 let request_timeout = ProjectSettings::get_global(cx)
5315 .global_lsp_settings
5316 .get_request_timeout();
5317 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5318 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5319 }) else {
5320 return Task::ready(Ok(ProjectTransaction::default()));
5321 };
5322
5323 cx.spawn(async move |this, cx| {
5324 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5325 .await
5326 .context("resolving a code action")?;
5327 if let Some(edit) = action.lsp_action.edit()
5328 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5329 return LocalLspStore::deserialize_workspace_edit(
5330 this.upgrade().context("no app present")?,
5331 edit.clone(),
5332 push_to_history,
5333
5334 lang_server.clone(),
5335 cx,
5336 )
5337 .await;
5338 }
5339
5340 let Some(command) = action.lsp_action.command() else {
5341 return Ok(ProjectTransaction::default())
5342 };
5343
5344 let server_capabilities = lang_server.capabilities();
5345 let available_commands = server_capabilities
5346 .execute_command_provider
5347 .as_ref()
5348 .map(|options| options.commands.as_slice())
5349 .unwrap_or_default();
5350
5351 if !available_commands.contains(&command.command) {
5352 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5353 return Ok(ProjectTransaction::default())
5354 }
5355
5356 let request_timeout = cx.update(|app|
5357 ProjectSettings::get_global(app)
5358 .global_lsp_settings
5359 .get_request_timeout()
5360 );
5361
5362 this.update(cx, |this, _| {
5363 this.as_local_mut()
5364 .unwrap()
5365 .last_workspace_edits_by_language_server
5366 .remove(&lang_server.server_id());
5367 })?;
5368
5369 let _result = lang_server
5370 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5371 command: command.command.clone(),
5372 arguments: command.arguments.clone().unwrap_or_default(),
5373 ..lsp::ExecuteCommandParams::default()
5374 }, request_timeout)
5375 .await.into_response()
5376 .context("execute command")?;
5377
5378 return this.update(cx, |this, _| {
5379 this.as_local_mut()
5380 .unwrap()
5381 .last_workspace_edits_by_language_server
5382 .remove(&lang_server.server_id())
5383 .unwrap_or_default()
5384 });
5385 })
5386 } else {
5387 Task::ready(Err(anyhow!("no upstream client and not local")))
5388 }
5389 }
5390
5391 pub fn apply_code_action_kind(
5392 &mut self,
5393 buffers: HashSet<Entity<Buffer>>,
5394 kind: CodeActionKind,
5395 push_to_history: bool,
5396 cx: &mut Context<Self>,
5397 ) -> Task<anyhow::Result<ProjectTransaction>> {
5398 if self.as_local().is_some() {
5399 cx.spawn(async move |lsp_store, cx| {
5400 let buffers = buffers.into_iter().collect::<Vec<_>>();
5401 let result = LocalLspStore::execute_code_action_kind_locally(
5402 lsp_store.clone(),
5403 buffers,
5404 kind,
5405 push_to_history,
5406 cx,
5407 )
5408 .await;
5409 lsp_store.update(cx, |lsp_store, _| {
5410 lsp_store.update_last_formatting_failure(&result);
5411 })?;
5412 result
5413 })
5414 } else if let Some((client, project_id)) = self.upstream_client() {
5415 let buffer_store = self.buffer_store();
5416 cx.spawn(async move |lsp_store, cx| {
5417 let result = client
5418 .request(proto::ApplyCodeActionKind {
5419 project_id,
5420 kind: kind.as_str().to_owned(),
5421 buffer_ids: buffers
5422 .iter()
5423 .map(|buffer| {
5424 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5425 })
5426 .collect(),
5427 })
5428 .await
5429 .and_then(|result| result.transaction.context("missing transaction"));
5430 lsp_store.update(cx, |lsp_store, _| {
5431 lsp_store.update_last_formatting_failure(&result);
5432 })?;
5433
5434 let transaction_response = result?;
5435 buffer_store
5436 .update(cx, |buffer_store, cx| {
5437 buffer_store.deserialize_project_transaction(
5438 transaction_response,
5439 push_to_history,
5440 cx,
5441 )
5442 })
5443 .await
5444 })
5445 } else {
5446 Task::ready(Ok(ProjectTransaction::default()))
5447 }
5448 }
5449
5450 pub fn resolved_hint(
5451 &mut self,
5452 buffer_id: BufferId,
5453 id: InlayId,
5454 cx: &mut Context<Self>,
5455 ) -> Option<ResolvedHint> {
5456 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5457
5458 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5459 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5460 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5461 let (server_id, resolve_data) = match &hint.resolve_state {
5462 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5463 ResolveState::Resolving => {
5464 return Some(ResolvedHint::Resolving(
5465 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5466 ));
5467 }
5468 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5469 };
5470
5471 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5472 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5473 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5474 id,
5475 cx.spawn(async move |lsp_store, cx| {
5476 let resolved_hint = resolve_task.await;
5477 lsp_store
5478 .update(cx, |lsp_store, _| {
5479 if let Some(old_inlay_hint) = lsp_store
5480 .lsp_data
5481 .get_mut(&buffer_id)
5482 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5483 {
5484 match resolved_hint {
5485 Ok(resolved_hint) => {
5486 *old_inlay_hint = resolved_hint;
5487 }
5488 Err(e) => {
5489 old_inlay_hint.resolve_state =
5490 ResolveState::CanResolve(server_id, resolve_data);
5491 log::error!("Inlay hint resolve failed: {e:#}");
5492 }
5493 }
5494 }
5495 })
5496 .ok();
5497 })
5498 .shared(),
5499 );
5500 debug_assert!(
5501 previous_task.is_none(),
5502 "Did not change hint's resolve state after spawning its resolve"
5503 );
5504 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5505 None
5506 }
5507
5508 pub(crate) fn linked_edits(
5509 &mut self,
5510 buffer: &Entity<Buffer>,
5511 position: Anchor,
5512 cx: &mut Context<Self>,
5513 ) -> Task<Result<Vec<Range<Anchor>>>> {
5514 let snapshot = buffer.read(cx).snapshot();
5515 let scope = snapshot.language_scope_at(position);
5516 let Some(server_id) = self
5517 .as_local()
5518 .and_then(|local| {
5519 buffer.update(cx, |buffer, cx| {
5520 local
5521 .language_servers_for_buffer(buffer, cx)
5522 .filter(|(_, server)| {
5523 LinkedEditingRange::check_server_capabilities(server.capabilities())
5524 })
5525 .filter(|(adapter, _)| {
5526 scope
5527 .as_ref()
5528 .map(|scope| scope.language_allowed(&adapter.name))
5529 .unwrap_or(true)
5530 })
5531 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5532 .next()
5533 })
5534 })
5535 .or_else(|| {
5536 self.upstream_client()
5537 .is_some()
5538 .then_some(LanguageServerToQuery::FirstCapable)
5539 })
5540 .filter(|_| {
5541 maybe!({
5542 let language = buffer.read(cx).language_at(position)?;
5543 Some(
5544 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5545 .linked_edits,
5546 )
5547 }) == Some(true)
5548 })
5549 else {
5550 return Task::ready(Ok(Vec::new()));
5551 };
5552
5553 self.request_lsp(
5554 buffer.clone(),
5555 server_id,
5556 LinkedEditingRange { position },
5557 cx,
5558 )
5559 }
5560
5561 fn apply_on_type_formatting(
5562 &mut self,
5563 buffer: Entity<Buffer>,
5564 position: Anchor,
5565 trigger: String,
5566 cx: &mut Context<Self>,
5567 ) -> Task<Result<Option<Transaction>>> {
5568 if let Some((client, project_id)) = self.upstream_client() {
5569 if !self.check_if_capable_for_proto_request(
5570 &buffer,
5571 |capabilities| {
5572 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5573 },
5574 cx,
5575 ) {
5576 return Task::ready(Ok(None));
5577 }
5578 let request = proto::OnTypeFormatting {
5579 project_id,
5580 buffer_id: buffer.read(cx).remote_id().into(),
5581 position: Some(serialize_anchor(&position)),
5582 trigger,
5583 version: serialize_version(&buffer.read(cx).version()),
5584 };
5585 cx.background_spawn(async move {
5586 client
5587 .request(request)
5588 .await?
5589 .transaction
5590 .map(language::proto::deserialize_transaction)
5591 .transpose()
5592 })
5593 } else if let Some(local) = self.as_local_mut() {
5594 let buffer_id = buffer.read(cx).remote_id();
5595 local.buffers_being_formatted.insert(buffer_id);
5596 cx.spawn(async move |this, cx| {
5597 let _cleanup = defer({
5598 let this = this.clone();
5599 let mut cx = cx.clone();
5600 move || {
5601 this.update(&mut cx, |this, _| {
5602 if let Some(local) = this.as_local_mut() {
5603 local.buffers_being_formatted.remove(&buffer_id);
5604 }
5605 })
5606 .ok();
5607 }
5608 });
5609
5610 buffer
5611 .update(cx, |buffer, _| {
5612 buffer.wait_for_edits(Some(position.timestamp()))
5613 })
5614 .await?;
5615 this.update(cx, |this, cx| {
5616 let position = position.to_point_utf16(buffer.read(cx));
5617 this.on_type_format(buffer, position, trigger, false, cx)
5618 })?
5619 .await
5620 })
5621 } else {
5622 Task::ready(Err(anyhow!("No upstream client or local language server")))
5623 }
5624 }
5625
5626 pub fn on_type_format<T: ToPointUtf16>(
5627 &mut self,
5628 buffer: Entity<Buffer>,
5629 position: T,
5630 trigger: String,
5631 push_to_history: bool,
5632 cx: &mut Context<Self>,
5633 ) -> Task<Result<Option<Transaction>>> {
5634 let position = position.to_point_utf16(buffer.read(cx));
5635 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5636 }
5637
5638 fn on_type_format_impl(
5639 &mut self,
5640 buffer: Entity<Buffer>,
5641 position: PointUtf16,
5642 trigger: String,
5643 push_to_history: bool,
5644 cx: &mut Context<Self>,
5645 ) -> Task<Result<Option<Transaction>>> {
5646 let options = buffer.update(cx, |buffer, cx| {
5647 lsp_command::lsp_formatting_options(
5648 language_settings(
5649 buffer.language_at(position).map(|l| l.name()),
5650 buffer.file(),
5651 cx,
5652 )
5653 .as_ref(),
5654 )
5655 });
5656
5657 cx.spawn(async move |this, cx| {
5658 if let Some(waiter) =
5659 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5660 {
5661 waiter.await?;
5662 }
5663 cx.update(|cx| {
5664 this.update(cx, |this, cx| {
5665 this.request_lsp(
5666 buffer.clone(),
5667 LanguageServerToQuery::FirstCapable,
5668 OnTypeFormatting {
5669 position,
5670 trigger,
5671 options,
5672 push_to_history,
5673 },
5674 cx,
5675 )
5676 })
5677 })?
5678 .await
5679 })
5680 }
5681
5682 pub fn definitions(
5683 &mut self,
5684 buffer: &Entity<Buffer>,
5685 position: PointUtf16,
5686 cx: &mut Context<Self>,
5687 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5688 if let Some((upstream_client, project_id)) = self.upstream_client() {
5689 let request = GetDefinitions { position };
5690 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5691 return Task::ready(Ok(None));
5692 }
5693
5694 let request_timeout = ProjectSettings::get_global(cx)
5695 .global_lsp_settings
5696 .get_request_timeout();
5697
5698 let request_task = upstream_client.request_lsp(
5699 project_id,
5700 None,
5701 request_timeout,
5702 cx.background_executor().clone(),
5703 request.to_proto(project_id, buffer.read(cx)),
5704 );
5705 let buffer = buffer.clone();
5706 cx.spawn(async move |weak_lsp_store, cx| {
5707 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5708 return Ok(None);
5709 };
5710 let Some(responses) = request_task.await? else {
5711 return Ok(None);
5712 };
5713 let actions = join_all(responses.payload.into_iter().map(|response| {
5714 GetDefinitions { position }.response_from_proto(
5715 response.response,
5716 lsp_store.clone(),
5717 buffer.clone(),
5718 cx.clone(),
5719 )
5720 }))
5721 .await;
5722
5723 Ok(Some(
5724 actions
5725 .into_iter()
5726 .collect::<Result<Vec<Vec<_>>>>()?
5727 .into_iter()
5728 .flatten()
5729 .dedup()
5730 .collect(),
5731 ))
5732 })
5733 } else {
5734 let definitions_task = self.request_multiple_lsp_locally(
5735 buffer,
5736 Some(position),
5737 GetDefinitions { position },
5738 cx,
5739 );
5740 cx.background_spawn(async move {
5741 Ok(Some(
5742 definitions_task
5743 .await
5744 .into_iter()
5745 .flat_map(|(_, definitions)| definitions)
5746 .dedup()
5747 .collect(),
5748 ))
5749 })
5750 }
5751 }
5752
5753 pub fn declarations(
5754 &mut self,
5755 buffer: &Entity<Buffer>,
5756 position: PointUtf16,
5757 cx: &mut Context<Self>,
5758 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5759 if let Some((upstream_client, project_id)) = self.upstream_client() {
5760 let request = GetDeclarations { position };
5761 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5762 return Task::ready(Ok(None));
5763 }
5764 let request_timeout = ProjectSettings::get_global(cx)
5765 .global_lsp_settings
5766 .get_request_timeout();
5767 let request_task = upstream_client.request_lsp(
5768 project_id,
5769 None,
5770 request_timeout,
5771 cx.background_executor().clone(),
5772 request.to_proto(project_id, buffer.read(cx)),
5773 );
5774 let buffer = buffer.clone();
5775 cx.spawn(async move |weak_lsp_store, cx| {
5776 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5777 return Ok(None);
5778 };
5779 let Some(responses) = request_task.await? else {
5780 return Ok(None);
5781 };
5782 let actions = join_all(responses.payload.into_iter().map(|response| {
5783 GetDeclarations { position }.response_from_proto(
5784 response.response,
5785 lsp_store.clone(),
5786 buffer.clone(),
5787 cx.clone(),
5788 )
5789 }))
5790 .await;
5791
5792 Ok(Some(
5793 actions
5794 .into_iter()
5795 .collect::<Result<Vec<Vec<_>>>>()?
5796 .into_iter()
5797 .flatten()
5798 .dedup()
5799 .collect(),
5800 ))
5801 })
5802 } else {
5803 let declarations_task = self.request_multiple_lsp_locally(
5804 buffer,
5805 Some(position),
5806 GetDeclarations { position },
5807 cx,
5808 );
5809 cx.background_spawn(async move {
5810 Ok(Some(
5811 declarations_task
5812 .await
5813 .into_iter()
5814 .flat_map(|(_, declarations)| declarations)
5815 .dedup()
5816 .collect(),
5817 ))
5818 })
5819 }
5820 }
5821
5822 pub fn type_definitions(
5823 &mut self,
5824 buffer: &Entity<Buffer>,
5825 position: PointUtf16,
5826 cx: &mut Context<Self>,
5827 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5828 if let Some((upstream_client, project_id)) = self.upstream_client() {
5829 let request = GetTypeDefinitions { position };
5830 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5831 return Task::ready(Ok(None));
5832 }
5833 let request_timeout = ProjectSettings::get_global(cx)
5834 .global_lsp_settings
5835 .get_request_timeout();
5836 let request_task = upstream_client.request_lsp(
5837 project_id,
5838 None,
5839 request_timeout,
5840 cx.background_executor().clone(),
5841 request.to_proto(project_id, buffer.read(cx)),
5842 );
5843 let buffer = buffer.clone();
5844 cx.spawn(async move |weak_lsp_store, cx| {
5845 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5846 return Ok(None);
5847 };
5848 let Some(responses) = request_task.await? else {
5849 return Ok(None);
5850 };
5851 let actions = join_all(responses.payload.into_iter().map(|response| {
5852 GetTypeDefinitions { position }.response_from_proto(
5853 response.response,
5854 lsp_store.clone(),
5855 buffer.clone(),
5856 cx.clone(),
5857 )
5858 }))
5859 .await;
5860
5861 Ok(Some(
5862 actions
5863 .into_iter()
5864 .collect::<Result<Vec<Vec<_>>>>()?
5865 .into_iter()
5866 .flatten()
5867 .dedup()
5868 .collect(),
5869 ))
5870 })
5871 } else {
5872 let type_definitions_task = self.request_multiple_lsp_locally(
5873 buffer,
5874 Some(position),
5875 GetTypeDefinitions { position },
5876 cx,
5877 );
5878 cx.background_spawn(async move {
5879 Ok(Some(
5880 type_definitions_task
5881 .await
5882 .into_iter()
5883 .flat_map(|(_, type_definitions)| type_definitions)
5884 .dedup()
5885 .collect(),
5886 ))
5887 })
5888 }
5889 }
5890
5891 pub fn implementations(
5892 &mut self,
5893 buffer: &Entity<Buffer>,
5894 position: PointUtf16,
5895 cx: &mut Context<Self>,
5896 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5897 if let Some((upstream_client, project_id)) = self.upstream_client() {
5898 let request = GetImplementations { position };
5899 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5900 return Task::ready(Ok(None));
5901 }
5902
5903 let request_timeout = ProjectSettings::get_global(cx)
5904 .global_lsp_settings
5905 .get_request_timeout();
5906 let request_task = upstream_client.request_lsp(
5907 project_id,
5908 None,
5909 request_timeout,
5910 cx.background_executor().clone(),
5911 request.to_proto(project_id, buffer.read(cx)),
5912 );
5913 let buffer = buffer.clone();
5914 cx.spawn(async move |weak_lsp_store, cx| {
5915 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5916 return Ok(None);
5917 };
5918 let Some(responses) = request_task.await? else {
5919 return Ok(None);
5920 };
5921 let actions = join_all(responses.payload.into_iter().map(|response| {
5922 GetImplementations { position }.response_from_proto(
5923 response.response,
5924 lsp_store.clone(),
5925 buffer.clone(),
5926 cx.clone(),
5927 )
5928 }))
5929 .await;
5930
5931 Ok(Some(
5932 actions
5933 .into_iter()
5934 .collect::<Result<Vec<Vec<_>>>>()?
5935 .into_iter()
5936 .flatten()
5937 .dedup()
5938 .collect(),
5939 ))
5940 })
5941 } else {
5942 let implementations_task = self.request_multiple_lsp_locally(
5943 buffer,
5944 Some(position),
5945 GetImplementations { position },
5946 cx,
5947 );
5948 cx.background_spawn(async move {
5949 Ok(Some(
5950 implementations_task
5951 .await
5952 .into_iter()
5953 .flat_map(|(_, implementations)| implementations)
5954 .dedup()
5955 .collect(),
5956 ))
5957 })
5958 }
5959 }
5960
5961 pub fn references(
5962 &mut self,
5963 buffer: &Entity<Buffer>,
5964 position: PointUtf16,
5965 cx: &mut Context<Self>,
5966 ) -> Task<Result<Option<Vec<Location>>>> {
5967 if let Some((upstream_client, project_id)) = self.upstream_client() {
5968 let request = GetReferences { position };
5969 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5970 return Task::ready(Ok(None));
5971 }
5972
5973 let request_timeout = ProjectSettings::get_global(cx)
5974 .global_lsp_settings
5975 .get_request_timeout();
5976 let request_task = upstream_client.request_lsp(
5977 project_id,
5978 None,
5979 request_timeout,
5980 cx.background_executor().clone(),
5981 request.to_proto(project_id, buffer.read(cx)),
5982 );
5983 let buffer = buffer.clone();
5984 cx.spawn(async move |weak_lsp_store, cx| {
5985 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5986 return Ok(None);
5987 };
5988 let Some(responses) = request_task.await? else {
5989 return Ok(None);
5990 };
5991
5992 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5993 GetReferences { position }.response_from_proto(
5994 lsp_response.response,
5995 lsp_store.clone(),
5996 buffer.clone(),
5997 cx.clone(),
5998 )
5999 }))
6000 .await
6001 .into_iter()
6002 .collect::<Result<Vec<Vec<_>>>>()?
6003 .into_iter()
6004 .flatten()
6005 .dedup()
6006 .collect();
6007 Ok(Some(locations))
6008 })
6009 } else {
6010 let references_task = self.request_multiple_lsp_locally(
6011 buffer,
6012 Some(position),
6013 GetReferences { position },
6014 cx,
6015 );
6016 cx.background_spawn(async move {
6017 Ok(Some(
6018 references_task
6019 .await
6020 .into_iter()
6021 .flat_map(|(_, references)| references)
6022 .dedup()
6023 .collect(),
6024 ))
6025 })
6026 }
6027 }
6028
6029 pub fn code_actions(
6030 &mut self,
6031 buffer: &Entity<Buffer>,
6032 range: Range<Anchor>,
6033 kinds: Option<Vec<CodeActionKind>>,
6034 cx: &mut Context<Self>,
6035 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6036 if let Some((upstream_client, project_id)) = self.upstream_client() {
6037 let request = GetCodeActions {
6038 range: range.clone(),
6039 kinds: kinds.clone(),
6040 };
6041 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6042 return Task::ready(Ok(None));
6043 }
6044 let request_timeout = ProjectSettings::get_global(cx)
6045 .global_lsp_settings
6046 .get_request_timeout();
6047 let request_task = upstream_client.request_lsp(
6048 project_id,
6049 None,
6050 request_timeout,
6051 cx.background_executor().clone(),
6052 request.to_proto(project_id, buffer.read(cx)),
6053 );
6054 let buffer = buffer.clone();
6055 cx.spawn(async move |weak_lsp_store, cx| {
6056 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6057 return Ok(None);
6058 };
6059 let Some(responses) = request_task.await? else {
6060 return Ok(None);
6061 };
6062 let actions = join_all(responses.payload.into_iter().map(|response| {
6063 GetCodeActions {
6064 range: range.clone(),
6065 kinds: kinds.clone(),
6066 }
6067 .response_from_proto(
6068 response.response,
6069 lsp_store.clone(),
6070 buffer.clone(),
6071 cx.clone(),
6072 )
6073 }))
6074 .await;
6075
6076 Ok(Some(
6077 actions
6078 .into_iter()
6079 .collect::<Result<Vec<Vec<_>>>>()?
6080 .into_iter()
6081 .flatten()
6082 .collect(),
6083 ))
6084 })
6085 } else {
6086 let all_actions_task = self.request_multiple_lsp_locally(
6087 buffer,
6088 Some(range.start),
6089 GetCodeActions { range, kinds },
6090 cx,
6091 );
6092 cx.background_spawn(async move {
6093 Ok(Some(
6094 all_actions_task
6095 .await
6096 .into_iter()
6097 .flat_map(|(_, actions)| actions)
6098 .collect(),
6099 ))
6100 })
6101 }
6102 }
6103
6104 #[inline(never)]
6105 pub fn completions(
6106 &self,
6107 buffer: &Entity<Buffer>,
6108 position: PointUtf16,
6109 context: CompletionContext,
6110 cx: &mut Context<Self>,
6111 ) -> Task<Result<Vec<CompletionResponse>>> {
6112 let language_registry = self.languages.clone();
6113
6114 if let Some((upstream_client, project_id)) = self.upstream_client() {
6115 let snapshot = buffer.read(cx).snapshot();
6116 let offset = position.to_offset(&snapshot);
6117 let scope = snapshot.language_scope_at(offset);
6118 let capable_lsps = self.all_capable_for_proto_request(
6119 buffer,
6120 |server_name, capabilities| {
6121 capabilities.completion_provider.is_some()
6122 && scope
6123 .as_ref()
6124 .map(|scope| scope.language_allowed(server_name))
6125 .unwrap_or(true)
6126 },
6127 cx,
6128 );
6129 if capable_lsps.is_empty() {
6130 return Task::ready(Ok(Vec::new()));
6131 }
6132
6133 let language = buffer.read(cx).language().cloned();
6134
6135 let buffer = buffer.clone();
6136
6137 cx.spawn(async move |this, cx| {
6138 let requests = join_all(
6139 capable_lsps
6140 .into_iter()
6141 .map(|(id, server_name)| {
6142 let request = GetCompletions {
6143 position,
6144 context: context.clone(),
6145 server_id: Some(id),
6146 };
6147 let buffer = buffer.clone();
6148 let language = language.clone();
6149 let lsp_adapter = language.as_ref().and_then(|language| {
6150 let adapters = language_registry.lsp_adapters(&language.name());
6151 adapters
6152 .iter()
6153 .find(|adapter| adapter.name() == server_name)
6154 .or_else(|| adapters.first())
6155 .cloned()
6156 });
6157 let upstream_client = upstream_client.clone();
6158 let response = this
6159 .update(cx, |this, cx| {
6160 this.send_lsp_proto_request(
6161 buffer,
6162 upstream_client,
6163 project_id,
6164 request,
6165 cx,
6166 )
6167 })
6168 .log_err();
6169 async move {
6170 let response = response?.await.log_err()?;
6171
6172 let completions = populate_labels_for_completions(
6173 response.completions,
6174 language,
6175 lsp_adapter,
6176 )
6177 .await;
6178
6179 Some(CompletionResponse {
6180 completions,
6181 display_options: CompletionDisplayOptions::default(),
6182 is_incomplete: response.is_incomplete,
6183 })
6184 }
6185 })
6186 .collect::<Vec<_>>(),
6187 );
6188 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6189 })
6190 } else if let Some(local) = self.as_local() {
6191 let snapshot = buffer.read(cx).snapshot();
6192 let offset = position.to_offset(&snapshot);
6193 let scope = snapshot.language_scope_at(offset);
6194 let language = snapshot.language().cloned();
6195 let completion_settings = language_settings(
6196 language.as_ref().map(|language| language.name()),
6197 buffer.read(cx).file(),
6198 cx,
6199 )
6200 .completions
6201 .clone();
6202 if !completion_settings.lsp {
6203 return Task::ready(Ok(Vec::new()));
6204 }
6205
6206 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6207 local
6208 .language_servers_for_buffer(buffer, cx)
6209 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6210 .filter(|(adapter, _)| {
6211 scope
6212 .as_ref()
6213 .map(|scope| scope.language_allowed(&adapter.name))
6214 .unwrap_or(true)
6215 })
6216 .map(|(_, server)| server.server_id())
6217 .collect()
6218 });
6219
6220 let buffer = buffer.clone();
6221 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6222 let lsp_timeout = if lsp_timeout > 0 {
6223 Some(Duration::from_millis(lsp_timeout))
6224 } else {
6225 None
6226 };
6227 cx.spawn(async move |this, cx| {
6228 let mut tasks = Vec::with_capacity(server_ids.len());
6229 this.update(cx, |lsp_store, cx| {
6230 for server_id in server_ids {
6231 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6232 let lsp_timeout = lsp_timeout
6233 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6234 let mut timeout = cx.background_spawn(async move {
6235 match lsp_timeout {
6236 Some(lsp_timeout) => {
6237 lsp_timeout.await;
6238 true
6239 },
6240 None => false,
6241 }
6242 }).fuse();
6243 let mut lsp_request = lsp_store.request_lsp(
6244 buffer.clone(),
6245 LanguageServerToQuery::Other(server_id),
6246 GetCompletions {
6247 position,
6248 context: context.clone(),
6249 server_id: Some(server_id),
6250 },
6251 cx,
6252 ).fuse();
6253 let new_task = cx.background_spawn(async move {
6254 select_biased! {
6255 response = lsp_request => anyhow::Ok(Some(response?)),
6256 timeout_happened = timeout => {
6257 if timeout_happened {
6258 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6259 Ok(None)
6260 } else {
6261 let completions = lsp_request.await?;
6262 Ok(Some(completions))
6263 }
6264 },
6265 }
6266 });
6267 tasks.push((lsp_adapter, new_task));
6268 }
6269 })?;
6270
6271 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6272 let completion_response = task.await.ok()??;
6273 let completions = populate_labels_for_completions(
6274 completion_response.completions,
6275 language.clone(),
6276 lsp_adapter,
6277 )
6278 .await;
6279 Some(CompletionResponse {
6280 completions,
6281 display_options: CompletionDisplayOptions::default(),
6282 is_incomplete: completion_response.is_incomplete,
6283 })
6284 });
6285
6286 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6287
6288 Ok(responses.into_iter().flatten().collect())
6289 })
6290 } else {
6291 Task::ready(Err(anyhow!("No upstream client or local language server")))
6292 }
6293 }
6294
6295 pub fn resolve_completions(
6296 &self,
6297 buffer: Entity<Buffer>,
6298 completion_indices: Vec<usize>,
6299 completions: Rc<RefCell<Box<[Completion]>>>,
6300 cx: &mut Context<Self>,
6301 ) -> Task<Result<bool>> {
6302 let client = self.upstream_client();
6303 let buffer_id = buffer.read(cx).remote_id();
6304 let buffer_snapshot = buffer.read(cx).snapshot();
6305
6306 if !self.check_if_capable_for_proto_request(
6307 &buffer,
6308 GetCompletions::can_resolve_completions,
6309 cx,
6310 ) {
6311 return Task::ready(Ok(false));
6312 }
6313 cx.spawn(async move |lsp_store, cx| {
6314 let request_timeout = cx.update(|app| {
6315 ProjectSettings::get_global(app)
6316 .global_lsp_settings
6317 .get_request_timeout()
6318 });
6319
6320 let mut did_resolve = false;
6321 if let Some((client, project_id)) = client {
6322 for completion_index in completion_indices {
6323 let server_id = {
6324 let completion = &completions.borrow()[completion_index];
6325 completion.source.server_id()
6326 };
6327 if let Some(server_id) = server_id {
6328 if Self::resolve_completion_remote(
6329 project_id,
6330 server_id,
6331 buffer_id,
6332 completions.clone(),
6333 completion_index,
6334 client.clone(),
6335 )
6336 .await
6337 .log_err()
6338 .is_some()
6339 {
6340 did_resolve = true;
6341 }
6342 } else {
6343 resolve_word_completion(
6344 &buffer_snapshot,
6345 &mut completions.borrow_mut()[completion_index],
6346 );
6347 }
6348 }
6349 } else {
6350 for completion_index in completion_indices {
6351 let server_id = {
6352 let completion = &completions.borrow()[completion_index];
6353 completion.source.server_id()
6354 };
6355 if let Some(server_id) = server_id {
6356 let server_and_adapter = lsp_store
6357 .read_with(cx, |lsp_store, _| {
6358 let server = lsp_store.language_server_for_id(server_id)?;
6359 let adapter =
6360 lsp_store.language_server_adapter_for_id(server.server_id())?;
6361 Some((server, adapter))
6362 })
6363 .ok()
6364 .flatten();
6365 let Some((server, adapter)) = server_and_adapter else {
6366 continue;
6367 };
6368
6369 let resolved = Self::resolve_completion_local(
6370 server,
6371 completions.clone(),
6372 completion_index,
6373 request_timeout,
6374 )
6375 .await
6376 .log_err()
6377 .is_some();
6378 if resolved {
6379 Self::regenerate_completion_labels(
6380 adapter,
6381 &buffer_snapshot,
6382 completions.clone(),
6383 completion_index,
6384 )
6385 .await
6386 .log_err();
6387 did_resolve = true;
6388 }
6389 } else {
6390 resolve_word_completion(
6391 &buffer_snapshot,
6392 &mut completions.borrow_mut()[completion_index],
6393 );
6394 }
6395 }
6396 }
6397
6398 Ok(did_resolve)
6399 })
6400 }
6401
6402 async fn resolve_completion_local(
6403 server: Arc<lsp::LanguageServer>,
6404 completions: Rc<RefCell<Box<[Completion]>>>,
6405 completion_index: usize,
6406 request_timeout: Duration,
6407 ) -> Result<()> {
6408 let server_id = server.server_id();
6409 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6410 return Ok(());
6411 }
6412
6413 let request = {
6414 let completion = &completions.borrow()[completion_index];
6415 match &completion.source {
6416 CompletionSource::Lsp {
6417 lsp_completion,
6418 resolved,
6419 server_id: completion_server_id,
6420 ..
6421 } => {
6422 if *resolved {
6423 return Ok(());
6424 }
6425 anyhow::ensure!(
6426 server_id == *completion_server_id,
6427 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6428 );
6429 server.request::<lsp::request::ResolveCompletionItem>(
6430 *lsp_completion.clone(),
6431 request_timeout,
6432 )
6433 }
6434 CompletionSource::BufferWord { .. }
6435 | CompletionSource::Dap { .. }
6436 | CompletionSource::Custom => {
6437 return Ok(());
6438 }
6439 }
6440 };
6441 let resolved_completion = request
6442 .await
6443 .into_response()
6444 .context("resolve completion")?;
6445
6446 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6447 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6448
6449 let mut completions = completions.borrow_mut();
6450 let completion = &mut completions[completion_index];
6451 if let CompletionSource::Lsp {
6452 lsp_completion,
6453 resolved,
6454 server_id: completion_server_id,
6455 ..
6456 } = &mut completion.source
6457 {
6458 if *resolved {
6459 return Ok(());
6460 }
6461 anyhow::ensure!(
6462 server_id == *completion_server_id,
6463 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6464 );
6465 **lsp_completion = resolved_completion;
6466 *resolved = true;
6467 }
6468 Ok(())
6469 }
6470
6471 async fn regenerate_completion_labels(
6472 adapter: Arc<CachedLspAdapter>,
6473 snapshot: &BufferSnapshot,
6474 completions: Rc<RefCell<Box<[Completion]>>>,
6475 completion_index: usize,
6476 ) -> Result<()> {
6477 let completion_item = completions.borrow()[completion_index]
6478 .source
6479 .lsp_completion(true)
6480 .map(Cow::into_owned);
6481 if let Some(lsp_documentation) = completion_item
6482 .as_ref()
6483 .and_then(|completion_item| completion_item.documentation.clone())
6484 {
6485 let mut completions = completions.borrow_mut();
6486 let completion = &mut completions[completion_index];
6487 completion.documentation = Some(lsp_documentation.into());
6488 } else {
6489 let mut completions = completions.borrow_mut();
6490 let completion = &mut completions[completion_index];
6491 completion.documentation = Some(CompletionDocumentation::Undocumented);
6492 }
6493
6494 let mut new_label = match completion_item {
6495 Some(completion_item) => {
6496 // Some language servers always return `detail` lazily via resolve, regardless of
6497 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6498 // See: https://github.com/yioneko/vtsls/issues/213
6499 let language = snapshot.language();
6500 match language {
6501 Some(language) => {
6502 adapter
6503 .labels_for_completions(
6504 std::slice::from_ref(&completion_item),
6505 language,
6506 )
6507 .await?
6508 }
6509 None => Vec::new(),
6510 }
6511 .pop()
6512 .flatten()
6513 .unwrap_or_else(|| {
6514 CodeLabel::fallback_for_completion(
6515 &completion_item,
6516 language.map(|language| language.as_ref()),
6517 )
6518 })
6519 }
6520 None => CodeLabel::plain(
6521 completions.borrow()[completion_index].new_text.clone(),
6522 None,
6523 ),
6524 };
6525 ensure_uniform_list_compatible_label(&mut new_label);
6526
6527 let mut completions = completions.borrow_mut();
6528 let completion = &mut completions[completion_index];
6529 if completion.label.filter_text() == new_label.filter_text() {
6530 completion.label = new_label;
6531 } else {
6532 log::error!(
6533 "Resolved completion changed display label from {} to {}. \
6534 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6535 completion.label.text(),
6536 new_label.text(),
6537 completion.label.filter_text(),
6538 new_label.filter_text()
6539 );
6540 }
6541
6542 Ok(())
6543 }
6544
6545 async fn resolve_completion_remote(
6546 project_id: u64,
6547 server_id: LanguageServerId,
6548 buffer_id: BufferId,
6549 completions: Rc<RefCell<Box<[Completion]>>>,
6550 completion_index: usize,
6551 client: AnyProtoClient,
6552 ) -> Result<()> {
6553 let lsp_completion = {
6554 let completion = &completions.borrow()[completion_index];
6555 match &completion.source {
6556 CompletionSource::Lsp {
6557 lsp_completion,
6558 resolved,
6559 server_id: completion_server_id,
6560 ..
6561 } => {
6562 anyhow::ensure!(
6563 server_id == *completion_server_id,
6564 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6565 );
6566 if *resolved {
6567 return Ok(());
6568 }
6569 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6570 }
6571 CompletionSource::Custom
6572 | CompletionSource::Dap { .. }
6573 | CompletionSource::BufferWord { .. } => {
6574 return Ok(());
6575 }
6576 }
6577 };
6578 let request = proto::ResolveCompletionDocumentation {
6579 project_id,
6580 language_server_id: server_id.0 as u64,
6581 lsp_completion,
6582 buffer_id: buffer_id.into(),
6583 };
6584
6585 let response = client
6586 .request(request)
6587 .await
6588 .context("completion documentation resolve proto request")?;
6589 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6590
6591 let documentation = if response.documentation.is_empty() {
6592 CompletionDocumentation::Undocumented
6593 } else if response.documentation_is_markdown {
6594 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6595 } else if response.documentation.lines().count() <= 1 {
6596 CompletionDocumentation::SingleLine(response.documentation.into())
6597 } else {
6598 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6599 };
6600
6601 let mut completions = completions.borrow_mut();
6602 let completion = &mut completions[completion_index];
6603 completion.documentation = Some(documentation);
6604 if let CompletionSource::Lsp {
6605 insert_range,
6606 lsp_completion,
6607 resolved,
6608 server_id: completion_server_id,
6609 lsp_defaults: _,
6610 } = &mut completion.source
6611 {
6612 let completion_insert_range = response
6613 .old_insert_start
6614 .and_then(deserialize_anchor)
6615 .zip(response.old_insert_end.and_then(deserialize_anchor));
6616 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6617
6618 if *resolved {
6619 return Ok(());
6620 }
6621 anyhow::ensure!(
6622 server_id == *completion_server_id,
6623 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6624 );
6625 **lsp_completion = resolved_lsp_completion;
6626 *resolved = true;
6627 }
6628
6629 let replace_range = response
6630 .old_replace_start
6631 .and_then(deserialize_anchor)
6632 .zip(response.old_replace_end.and_then(deserialize_anchor));
6633 if let Some((old_replace_start, old_replace_end)) = replace_range
6634 && !response.new_text.is_empty()
6635 {
6636 completion.new_text = response.new_text;
6637 completion.replace_range = old_replace_start..old_replace_end;
6638 }
6639
6640 Ok(())
6641 }
6642
6643 pub fn apply_additional_edits_for_completion(
6644 &self,
6645 buffer_handle: Entity<Buffer>,
6646 completions: Rc<RefCell<Box<[Completion]>>>,
6647 completion_index: usize,
6648 push_to_history: bool,
6649 cx: &mut Context<Self>,
6650 ) -> Task<Result<Option<Transaction>>> {
6651 if let Some((client, project_id)) = self.upstream_client() {
6652 let buffer = buffer_handle.read(cx);
6653 let buffer_id = buffer.remote_id();
6654 cx.spawn(async move |_, cx| {
6655 let request = {
6656 let completion = completions.borrow()[completion_index].clone();
6657 proto::ApplyCompletionAdditionalEdits {
6658 project_id,
6659 buffer_id: buffer_id.into(),
6660 completion: Some(Self::serialize_completion(&CoreCompletion {
6661 replace_range: completion.replace_range,
6662 new_text: completion.new_text,
6663 source: completion.source,
6664 })),
6665 }
6666 };
6667
6668 let Some(transaction) = client.request(request).await?.transaction else {
6669 return Ok(None);
6670 };
6671
6672 let transaction = language::proto::deserialize_transaction(transaction)?;
6673 buffer_handle
6674 .update(cx, |buffer, _| {
6675 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6676 })
6677 .await?;
6678 if push_to_history {
6679 buffer_handle.update(cx, |buffer, _| {
6680 buffer.push_transaction(transaction.clone(), Instant::now());
6681 buffer.finalize_last_transaction();
6682 });
6683 }
6684 Ok(Some(transaction))
6685 })
6686 } else {
6687 let request_timeout = ProjectSettings::get_global(cx)
6688 .global_lsp_settings
6689 .get_request_timeout();
6690
6691 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6692 let completion = &completions.borrow()[completion_index];
6693 let server_id = completion.source.server_id()?;
6694 Some(
6695 self.language_server_for_local_buffer(buffer, server_id, cx)?
6696 .1
6697 .clone(),
6698 )
6699 }) else {
6700 return Task::ready(Ok(None));
6701 };
6702
6703 cx.spawn(async move |this, cx| {
6704 Self::resolve_completion_local(
6705 server.clone(),
6706 completions.clone(),
6707 completion_index,
6708 request_timeout,
6709 )
6710 .await
6711 .context("resolving completion")?;
6712 let completion = completions.borrow()[completion_index].clone();
6713 let additional_text_edits = completion
6714 .source
6715 .lsp_completion(true)
6716 .as_ref()
6717 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6718 if let Some(edits) = additional_text_edits {
6719 let edits = this
6720 .update(cx, |this, cx| {
6721 this.as_local_mut().unwrap().edits_from_lsp(
6722 &buffer_handle,
6723 edits,
6724 server.server_id(),
6725 None,
6726 cx,
6727 )
6728 })?
6729 .await?;
6730
6731 buffer_handle.update(cx, |buffer, cx| {
6732 buffer.finalize_last_transaction();
6733 buffer.start_transaction();
6734
6735 for (range, text) in edits {
6736 let primary = &completion.replace_range;
6737
6738 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6739 // and the primary completion is just an insertion (empty range), then this is likely
6740 // an auto-import scenario and should not be considered overlapping
6741 // https://github.com/zed-industries/zed/issues/26136
6742 let is_file_start_auto_import = {
6743 let snapshot = buffer.snapshot();
6744 let primary_start_point = primary.start.to_point(&snapshot);
6745 let range_start_point = range.start.to_point(&snapshot);
6746
6747 let result = primary_start_point.row == 0
6748 && primary_start_point.column == 0
6749 && range_start_point.row == 0
6750 && range_start_point.column == 0;
6751
6752 result
6753 };
6754
6755 let has_overlap = if is_file_start_auto_import {
6756 false
6757 } else {
6758 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6759 && primary.end.cmp(&range.start, buffer).is_ge();
6760 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6761 && range.end.cmp(&primary.end, buffer).is_ge();
6762 let result = start_within || end_within;
6763 result
6764 };
6765
6766 //Skip additional edits which overlap with the primary completion edit
6767 //https://github.com/zed-industries/zed/pull/1871
6768 if !has_overlap {
6769 buffer.edit([(range, text)], None, cx);
6770 }
6771 }
6772
6773 let transaction = if buffer.end_transaction(cx).is_some() {
6774 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6775 if !push_to_history {
6776 buffer.forget_transaction(transaction.id);
6777 }
6778 Some(transaction)
6779 } else {
6780 None
6781 };
6782 Ok(transaction)
6783 })
6784 } else {
6785 Ok(None)
6786 }
6787 })
6788 }
6789 }
6790
6791 pub fn pull_diagnostics(
6792 &mut self,
6793 buffer: Entity<Buffer>,
6794 cx: &mut Context<Self>,
6795 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6796 let buffer_id = buffer.read(cx).remote_id();
6797
6798 if let Some((client, upstream_project_id)) = self.upstream_client() {
6799 let mut suitable_capabilities = None;
6800 // Are we capable for proto request?
6801 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6802 &buffer,
6803 |capabilities| {
6804 if let Some(caps) = &capabilities.diagnostic_provider {
6805 suitable_capabilities = Some(caps.clone());
6806 true
6807 } else {
6808 false
6809 }
6810 },
6811 cx,
6812 );
6813 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6814 let Some(dynamic_caps) = suitable_capabilities else {
6815 return Task::ready(Ok(None));
6816 };
6817 assert!(any_server_has_diagnostics_provider);
6818
6819 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6820 let request = GetDocumentDiagnostics {
6821 previous_result_id: None,
6822 identifier,
6823 registration_id: None,
6824 };
6825 let request_timeout = ProjectSettings::get_global(cx)
6826 .global_lsp_settings
6827 .get_request_timeout();
6828 let request_task = client.request_lsp(
6829 upstream_project_id,
6830 None,
6831 request_timeout,
6832 cx.background_executor().clone(),
6833 request.to_proto(upstream_project_id, buffer.read(cx)),
6834 );
6835 cx.background_spawn(async move {
6836 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6837 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6838 // Do not attempt to further process the dummy responses here.
6839 let _response = request_task.await?;
6840 Ok(None)
6841 })
6842 } else {
6843 let servers = buffer.update(cx, |buffer, cx| {
6844 self.running_language_servers_for_local_buffer(buffer, cx)
6845 .map(|(_, server)| server.clone())
6846 .collect::<Vec<_>>()
6847 });
6848
6849 let pull_diagnostics = servers
6850 .into_iter()
6851 .flat_map(|server| {
6852 let result = maybe!({
6853 let local = self.as_local()?;
6854 let server_id = server.server_id();
6855 let providers_with_identifiers = local
6856 .language_server_dynamic_registrations
6857 .get(&server_id)
6858 .into_iter()
6859 .flat_map(|registrations| registrations.diagnostics.clone())
6860 .collect::<Vec<_>>();
6861 Some(
6862 providers_with_identifiers
6863 .into_iter()
6864 .map(|(registration_id, dynamic_caps)| {
6865 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6866 let registration_id = registration_id.map(SharedString::from);
6867 let result_id = self.result_id_for_buffer_pull(
6868 server_id,
6869 buffer_id,
6870 ®istration_id,
6871 cx,
6872 );
6873 self.request_lsp(
6874 buffer.clone(),
6875 LanguageServerToQuery::Other(server_id),
6876 GetDocumentDiagnostics {
6877 previous_result_id: result_id,
6878 registration_id,
6879 identifier,
6880 },
6881 cx,
6882 )
6883 })
6884 .collect::<Vec<_>>(),
6885 )
6886 });
6887
6888 result.unwrap_or_default()
6889 })
6890 .collect::<Vec<_>>();
6891
6892 cx.background_spawn(async move {
6893 let mut responses = Vec::new();
6894 for diagnostics in join_all(pull_diagnostics).await {
6895 responses.extend(diagnostics?);
6896 }
6897 Ok(Some(responses))
6898 })
6899 }
6900 }
6901
6902 pub fn applicable_inlay_chunks(
6903 &mut self,
6904 buffer: &Entity<Buffer>,
6905 ranges: &[Range<text::Anchor>],
6906 cx: &mut Context<Self>,
6907 ) -> Vec<Range<BufferRow>> {
6908 let buffer_snapshot = buffer.read(cx).snapshot();
6909 let ranges = ranges
6910 .iter()
6911 .map(|range| range.to_point(&buffer_snapshot))
6912 .collect::<Vec<_>>();
6913
6914 self.latest_lsp_data(buffer, cx)
6915 .inlay_hints
6916 .applicable_chunks(ranges.as_slice())
6917 .map(|chunk| chunk.row_range())
6918 .collect()
6919 }
6920
6921 pub fn invalidate_inlay_hints<'a>(
6922 &'a mut self,
6923 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6924 ) {
6925 for buffer_id in for_buffers {
6926 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6927 lsp_data.inlay_hints.clear();
6928 }
6929 }
6930 }
6931
6932 pub fn inlay_hints(
6933 &mut self,
6934 invalidate: InvalidationStrategy,
6935 buffer: Entity<Buffer>,
6936 ranges: Vec<Range<text::Anchor>>,
6937 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6938 cx: &mut Context<Self>,
6939 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6940 let next_hint_id = self.next_hint_id.clone();
6941 let lsp_data = self.latest_lsp_data(&buffer, cx);
6942 let query_version = lsp_data.buffer_version.clone();
6943 let mut lsp_refresh_requested = false;
6944 let for_server = if let InvalidationStrategy::RefreshRequested {
6945 server_id,
6946 request_id,
6947 } = invalidate
6948 {
6949 let invalidated = lsp_data
6950 .inlay_hints
6951 .invalidate_for_server_refresh(server_id, request_id);
6952 lsp_refresh_requested = invalidated;
6953 Some(server_id)
6954 } else {
6955 None
6956 };
6957 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6958 let known_chunks = known_chunks
6959 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6960 .map(|(_, known_chunks)| known_chunks)
6961 .unwrap_or_default();
6962
6963 let buffer_snapshot = buffer.read(cx).snapshot();
6964 let ranges = ranges
6965 .iter()
6966 .map(|range| range.to_point(&buffer_snapshot))
6967 .collect::<Vec<_>>();
6968
6969 let mut hint_fetch_tasks = Vec::new();
6970 let mut cached_inlay_hints = None;
6971 let mut ranges_to_query = None;
6972 let applicable_chunks = existing_inlay_hints
6973 .applicable_chunks(ranges.as_slice())
6974 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6975 .collect::<Vec<_>>();
6976 if applicable_chunks.is_empty() {
6977 return HashMap::default();
6978 }
6979
6980 for row_chunk in applicable_chunks {
6981 match (
6982 existing_inlay_hints
6983 .cached_hints(&row_chunk)
6984 .filter(|_| !lsp_refresh_requested)
6985 .cloned(),
6986 existing_inlay_hints
6987 .fetched_hints(&row_chunk)
6988 .as_ref()
6989 .filter(|_| !lsp_refresh_requested)
6990 .cloned(),
6991 ) {
6992 (None, None) => {
6993 let chunk_range = row_chunk.anchor_range();
6994 ranges_to_query
6995 .get_or_insert_with(Vec::new)
6996 .push((row_chunk, chunk_range));
6997 }
6998 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6999 (Some(cached_hints), None) => {
7000 for (server_id, cached_hints) in cached_hints {
7001 if for_server.is_none_or(|for_server| for_server == server_id) {
7002 cached_inlay_hints
7003 .get_or_insert_with(HashMap::default)
7004 .entry(row_chunk.row_range())
7005 .or_insert_with(HashMap::default)
7006 .entry(server_id)
7007 .or_insert_with(Vec::new)
7008 .extend(cached_hints);
7009 }
7010 }
7011 }
7012 (Some(cached_hints), Some(fetched_hints)) => {
7013 hint_fetch_tasks.push((row_chunk, fetched_hints));
7014 for (server_id, cached_hints) in cached_hints {
7015 if for_server.is_none_or(|for_server| for_server == server_id) {
7016 cached_inlay_hints
7017 .get_or_insert_with(HashMap::default)
7018 .entry(row_chunk.row_range())
7019 .or_insert_with(HashMap::default)
7020 .entry(server_id)
7021 .or_insert_with(Vec::new)
7022 .extend(cached_hints);
7023 }
7024 }
7025 }
7026 }
7027 }
7028
7029 if hint_fetch_tasks.is_empty()
7030 && ranges_to_query
7031 .as_ref()
7032 .is_none_or(|ranges| ranges.is_empty())
7033 && let Some(cached_inlay_hints) = cached_inlay_hints
7034 {
7035 cached_inlay_hints
7036 .into_iter()
7037 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7038 .collect()
7039 } else {
7040 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7041 // When a server refresh was requested, other servers' cached hints
7042 // are unaffected by the refresh and must be included in the result.
7043 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7044 // removes all visible hints but only adds back the requesting
7045 // server's new hints, permanently losing other servers' hints.
7046 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7047 lsp_data
7048 .inlay_hints
7049 .cached_hints(&chunk)
7050 .cloned()
7051 .unwrap_or_default()
7052 } else {
7053 HashMap::default()
7054 };
7055
7056 let next_hint_id = next_hint_id.clone();
7057 let buffer = buffer.clone();
7058 let query_version = query_version.clone();
7059 let new_inlay_hints = cx
7060 .spawn(async move |lsp_store, cx| {
7061 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7062 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7063 })?;
7064 new_fetch_task
7065 .await
7066 .and_then(|new_hints_by_server| {
7067 lsp_store.update(cx, |lsp_store, cx| {
7068 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7069 let update_cache = lsp_data.buffer_version == query_version;
7070 if new_hints_by_server.is_empty() {
7071 if update_cache {
7072 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7073 }
7074 other_servers_cached
7075 } else {
7076 let mut result = other_servers_cached;
7077 for (server_id, new_hints) in new_hints_by_server {
7078 let new_hints = new_hints
7079 .into_iter()
7080 .map(|new_hint| {
7081 (
7082 InlayId::Hint(next_hint_id.fetch_add(
7083 1,
7084 atomic::Ordering::AcqRel,
7085 )),
7086 new_hint,
7087 )
7088 })
7089 .collect::<Vec<_>>();
7090 if update_cache {
7091 lsp_data.inlay_hints.insert_new_hints(
7092 chunk,
7093 server_id,
7094 new_hints.clone(),
7095 );
7096 }
7097 result.insert(server_id, new_hints);
7098 }
7099 result
7100 }
7101 })
7102 })
7103 .map_err(Arc::new)
7104 })
7105 .shared();
7106
7107 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7108 *fetch_task = Some(new_inlay_hints.clone());
7109 hint_fetch_tasks.push((chunk, new_inlay_hints));
7110 }
7111
7112 cached_inlay_hints
7113 .unwrap_or_default()
7114 .into_iter()
7115 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7116 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7117 (
7118 chunk.row_range(),
7119 cx.spawn(async move |_, _| {
7120 hints_fetch.await.map_err(|e| {
7121 if e.error_code() != ErrorCode::Internal {
7122 anyhow!(e.error_code())
7123 } else {
7124 anyhow!("{e:#}")
7125 }
7126 })
7127 }),
7128 )
7129 }))
7130 .collect()
7131 }
7132 }
7133
7134 fn fetch_inlay_hints(
7135 &mut self,
7136 for_server: Option<LanguageServerId>,
7137 buffer: &Entity<Buffer>,
7138 range: Range<Anchor>,
7139 cx: &mut Context<Self>,
7140 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7141 let request = InlayHints {
7142 range: range.clone(),
7143 };
7144 if let Some((upstream_client, project_id)) = self.upstream_client() {
7145 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7146 return Task::ready(Ok(HashMap::default()));
7147 }
7148 let request_timeout = ProjectSettings::get_global(cx)
7149 .global_lsp_settings
7150 .get_request_timeout();
7151 let request_task = upstream_client.request_lsp(
7152 project_id,
7153 for_server.map(|id| id.to_proto()),
7154 request_timeout,
7155 cx.background_executor().clone(),
7156 request.to_proto(project_id, buffer.read(cx)),
7157 );
7158 let buffer = buffer.clone();
7159 cx.spawn(async move |weak_lsp_store, cx| {
7160 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7161 return Ok(HashMap::default());
7162 };
7163 let Some(responses) = request_task.await? else {
7164 return Ok(HashMap::default());
7165 };
7166
7167 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7168 let lsp_store = lsp_store.clone();
7169 let buffer = buffer.clone();
7170 let cx = cx.clone();
7171 let request = request.clone();
7172 async move {
7173 (
7174 LanguageServerId::from_proto(response.server_id),
7175 request
7176 .response_from_proto(response.response, lsp_store, buffer, cx)
7177 .await,
7178 )
7179 }
7180 }))
7181 .await;
7182
7183 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7184 let mut has_errors = false;
7185 let inlay_hints = inlay_hints
7186 .into_iter()
7187 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7188 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7189 Err(e) => {
7190 has_errors = true;
7191 log::error!("{e:#}");
7192 None
7193 }
7194 })
7195 .map(|(server_id, mut new_hints)| {
7196 new_hints.retain(|hint| {
7197 hint.position.is_valid(&buffer_snapshot)
7198 && range.start.is_valid(&buffer_snapshot)
7199 && range.end.is_valid(&buffer_snapshot)
7200 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7201 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7202 });
7203 (server_id, new_hints)
7204 })
7205 .collect::<HashMap<_, _>>();
7206 anyhow::ensure!(
7207 !has_errors || !inlay_hints.is_empty(),
7208 "Failed to fetch inlay hints"
7209 );
7210 Ok(inlay_hints)
7211 })
7212 } else {
7213 let inlay_hints_task = match for_server {
7214 Some(server_id) => {
7215 let server_task = self.request_lsp(
7216 buffer.clone(),
7217 LanguageServerToQuery::Other(server_id),
7218 request,
7219 cx,
7220 );
7221 cx.background_spawn(async move {
7222 let mut responses = Vec::new();
7223 match server_task.await {
7224 Ok(response) => responses.push((server_id, response)),
7225 // rust-analyzer likes to error with this when its still loading up
7226 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7227 Err(e) => log::error!(
7228 "Error handling response for inlay hints request: {e:#}"
7229 ),
7230 }
7231 responses
7232 })
7233 }
7234 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7235 };
7236 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7237 cx.background_spawn(async move {
7238 Ok(inlay_hints_task
7239 .await
7240 .into_iter()
7241 .map(|(server_id, mut new_hints)| {
7242 new_hints.retain(|hint| {
7243 hint.position.is_valid(&buffer_snapshot)
7244 && range.start.is_valid(&buffer_snapshot)
7245 && range.end.is_valid(&buffer_snapshot)
7246 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7247 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7248 });
7249 (server_id, new_hints)
7250 })
7251 .collect())
7252 })
7253 }
7254 }
7255
7256 fn diagnostic_registration_exists(
7257 &self,
7258 server_id: LanguageServerId,
7259 registration_id: &Option<SharedString>,
7260 ) -> bool {
7261 let Some(local) = self.as_local() else {
7262 return false;
7263 };
7264 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7265 else {
7266 return false;
7267 };
7268 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7269 registrations.diagnostics.contains_key(®istration_key)
7270 }
7271
7272 pub fn pull_diagnostics_for_buffer(
7273 &mut self,
7274 buffer: Entity<Buffer>,
7275 cx: &mut Context<Self>,
7276 ) -> Task<anyhow::Result<()>> {
7277 let diagnostics = self.pull_diagnostics(buffer, cx);
7278 cx.spawn(async move |lsp_store, cx| {
7279 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7280 return Ok(());
7281 };
7282 lsp_store.update(cx, |lsp_store, cx| {
7283 if lsp_store.as_local().is_none() {
7284 return;
7285 }
7286
7287 let mut unchanged_buffers = HashMap::default();
7288 let server_diagnostics_updates = diagnostics
7289 .into_iter()
7290 .filter_map(|diagnostics_set| match diagnostics_set {
7291 LspPullDiagnostics::Response {
7292 server_id,
7293 uri,
7294 diagnostics,
7295 registration_id,
7296 } => Some((server_id, uri, diagnostics, registration_id)),
7297 LspPullDiagnostics::Default => None,
7298 })
7299 .filter(|(server_id, _, _, registration_id)| {
7300 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7301 })
7302 .fold(
7303 HashMap::default(),
7304 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7305 let (result_id, diagnostics) = match diagnostics {
7306 PulledDiagnostics::Unchanged { result_id } => {
7307 unchanged_buffers
7308 .entry(new_registration_id.clone())
7309 .or_insert_with(HashSet::default)
7310 .insert(uri.clone());
7311 (Some(result_id), Vec::new())
7312 }
7313 PulledDiagnostics::Changed {
7314 result_id,
7315 diagnostics,
7316 } => (result_id, diagnostics),
7317 };
7318 let disk_based_sources = Cow::Owned(
7319 lsp_store
7320 .language_server_adapter_for_id(server_id)
7321 .as_ref()
7322 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7323 .unwrap_or(&[])
7324 .to_vec(),
7325 );
7326 acc.entry(server_id)
7327 .or_insert_with(HashMap::default)
7328 .entry(new_registration_id.clone())
7329 .or_insert_with(Vec::new)
7330 .push(DocumentDiagnosticsUpdate {
7331 server_id,
7332 diagnostics: lsp::PublishDiagnosticsParams {
7333 uri,
7334 diagnostics,
7335 version: None,
7336 },
7337 result_id: result_id.map(SharedString::new),
7338 disk_based_sources,
7339 registration_id: new_registration_id,
7340 });
7341 acc
7342 },
7343 );
7344
7345 for diagnostic_updates in server_diagnostics_updates.into_values() {
7346 for (registration_id, diagnostic_updates) in diagnostic_updates {
7347 lsp_store
7348 .merge_lsp_diagnostics(
7349 DiagnosticSourceKind::Pulled,
7350 diagnostic_updates,
7351 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7352 DiagnosticSourceKind::Pulled => {
7353 old_diagnostic.registration_id != registration_id
7354 || unchanged_buffers
7355 .get(&old_diagnostic.registration_id)
7356 .is_some_and(|unchanged_buffers| {
7357 unchanged_buffers.contains(&document_uri)
7358 })
7359 }
7360 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7361 true
7362 }
7363 },
7364 cx,
7365 )
7366 .log_err();
7367 }
7368 }
7369 })
7370 })
7371 }
7372
7373 pub fn signature_help<T: ToPointUtf16>(
7374 &mut self,
7375 buffer: &Entity<Buffer>,
7376 position: T,
7377 cx: &mut Context<Self>,
7378 ) -> Task<Option<Vec<SignatureHelp>>> {
7379 let position = position.to_point_utf16(buffer.read(cx));
7380
7381 if let Some((client, upstream_project_id)) = self.upstream_client() {
7382 let request = GetSignatureHelp { position };
7383 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7384 return Task::ready(None);
7385 }
7386 let request_timeout = ProjectSettings::get_global(cx)
7387 .global_lsp_settings
7388 .get_request_timeout();
7389 let request_task = client.request_lsp(
7390 upstream_project_id,
7391 None,
7392 request_timeout,
7393 cx.background_executor().clone(),
7394 request.to_proto(upstream_project_id, buffer.read(cx)),
7395 );
7396 let buffer = buffer.clone();
7397 cx.spawn(async move |weak_lsp_store, cx| {
7398 let lsp_store = weak_lsp_store.upgrade()?;
7399 let signatures = join_all(
7400 request_task
7401 .await
7402 .log_err()
7403 .flatten()
7404 .map(|response| response.payload)
7405 .unwrap_or_default()
7406 .into_iter()
7407 .map(|response| {
7408 let response = GetSignatureHelp { position }.response_from_proto(
7409 response.response,
7410 lsp_store.clone(),
7411 buffer.clone(),
7412 cx.clone(),
7413 );
7414 async move { response.await.log_err().flatten() }
7415 }),
7416 )
7417 .await
7418 .into_iter()
7419 .flatten()
7420 .collect();
7421 Some(signatures)
7422 })
7423 } else {
7424 let all_actions_task = self.request_multiple_lsp_locally(
7425 buffer,
7426 Some(position),
7427 GetSignatureHelp { position },
7428 cx,
7429 );
7430 cx.background_spawn(async move {
7431 Some(
7432 all_actions_task
7433 .await
7434 .into_iter()
7435 .flat_map(|(_, actions)| actions)
7436 .collect::<Vec<_>>(),
7437 )
7438 })
7439 }
7440 }
7441
7442 pub fn hover(
7443 &mut self,
7444 buffer: &Entity<Buffer>,
7445 position: PointUtf16,
7446 cx: &mut Context<Self>,
7447 ) -> Task<Option<Vec<Hover>>> {
7448 if let Some((client, upstream_project_id)) = self.upstream_client() {
7449 let request = GetHover { position };
7450 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7451 return Task::ready(None);
7452 }
7453 let request_timeout = ProjectSettings::get_global(cx)
7454 .global_lsp_settings
7455 .get_request_timeout();
7456 let request_task = client.request_lsp(
7457 upstream_project_id,
7458 None,
7459 request_timeout,
7460 cx.background_executor().clone(),
7461 request.to_proto(upstream_project_id, buffer.read(cx)),
7462 );
7463 let buffer = buffer.clone();
7464 cx.spawn(async move |weak_lsp_store, cx| {
7465 let lsp_store = weak_lsp_store.upgrade()?;
7466 let hovers = join_all(
7467 request_task
7468 .await
7469 .log_err()
7470 .flatten()
7471 .map(|response| response.payload)
7472 .unwrap_or_default()
7473 .into_iter()
7474 .map(|response| {
7475 let response = GetHover { position }.response_from_proto(
7476 response.response,
7477 lsp_store.clone(),
7478 buffer.clone(),
7479 cx.clone(),
7480 );
7481 async move {
7482 response
7483 .await
7484 .log_err()
7485 .flatten()
7486 .and_then(remove_empty_hover_blocks)
7487 }
7488 }),
7489 )
7490 .await
7491 .into_iter()
7492 .flatten()
7493 .collect();
7494 Some(hovers)
7495 })
7496 } else {
7497 let all_actions_task = self.request_multiple_lsp_locally(
7498 buffer,
7499 Some(position),
7500 GetHover { position },
7501 cx,
7502 );
7503 cx.background_spawn(async move {
7504 Some(
7505 all_actions_task
7506 .await
7507 .into_iter()
7508 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7509 .collect::<Vec<Hover>>(),
7510 )
7511 })
7512 }
7513 }
7514
7515 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7516 let language_registry = self.languages.clone();
7517
7518 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7519 let request = upstream_client.request(proto::GetProjectSymbols {
7520 project_id: *project_id,
7521 query: query.to_string(),
7522 });
7523 cx.foreground_executor().spawn(async move {
7524 let response = request.await?;
7525 let mut symbols = Vec::new();
7526 let core_symbols = response
7527 .symbols
7528 .into_iter()
7529 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7530 .collect::<Vec<_>>();
7531 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7532 .await;
7533 Ok(symbols)
7534 })
7535 } else if let Some(local) = self.as_local() {
7536 struct WorkspaceSymbolsResult {
7537 server_id: LanguageServerId,
7538 lsp_adapter: Arc<CachedLspAdapter>,
7539 worktree: WeakEntity<Worktree>,
7540 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7541 }
7542
7543 let mut requests = Vec::new();
7544 let mut requested_servers = BTreeSet::new();
7545 let request_timeout = ProjectSettings::get_global(cx)
7546 .global_lsp_settings
7547 .get_request_timeout();
7548
7549 for (seed, state) in local.language_server_ids.iter() {
7550 let Some(worktree_handle) = self
7551 .worktree_store
7552 .read(cx)
7553 .worktree_for_id(seed.worktree_id, cx)
7554 else {
7555 continue;
7556 };
7557
7558 let worktree = worktree_handle.read(cx);
7559 if !worktree.is_visible() {
7560 continue;
7561 }
7562
7563 if !requested_servers.insert(state.id) {
7564 continue;
7565 }
7566
7567 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7568 Some(LanguageServerState::Running {
7569 adapter, server, ..
7570 }) => (adapter.clone(), server),
7571
7572 _ => continue,
7573 };
7574
7575 let supports_workspace_symbol_request =
7576 match server.capabilities().workspace_symbol_provider {
7577 Some(OneOf::Left(supported)) => supported,
7578 Some(OneOf::Right(_)) => true,
7579 None => false,
7580 };
7581
7582 if !supports_workspace_symbol_request {
7583 continue;
7584 }
7585
7586 let worktree_handle = worktree_handle.clone();
7587 let server_id = server.server_id();
7588 requests.push(
7589 server
7590 .request::<lsp::request::WorkspaceSymbolRequest>(
7591 lsp::WorkspaceSymbolParams {
7592 query: query.to_string(),
7593 ..Default::default()
7594 },
7595 request_timeout,
7596 )
7597 .map(move |response| {
7598 let lsp_symbols = response
7599 .into_response()
7600 .context("workspace symbols request")
7601 .log_err()
7602 .flatten()
7603 .map(|symbol_response| match symbol_response {
7604 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7605 flat_responses
7606 .into_iter()
7607 .map(|lsp_symbol| {
7608 (
7609 lsp_symbol.name,
7610 lsp_symbol.kind,
7611 lsp_symbol.location,
7612 lsp_symbol.container_name,
7613 )
7614 })
7615 .collect::<Vec<_>>()
7616 }
7617 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7618 nested_responses
7619 .into_iter()
7620 .filter_map(|lsp_symbol| {
7621 let location = match lsp_symbol.location {
7622 OneOf::Left(location) => location,
7623 OneOf::Right(_) => {
7624 log::error!(
7625 "Unexpected: client capabilities \
7626 forbid symbol resolutions in \
7627 workspace.symbol.resolveSupport"
7628 );
7629 return None;
7630 }
7631 };
7632 Some((
7633 lsp_symbol.name,
7634 lsp_symbol.kind,
7635 location,
7636 lsp_symbol.container_name,
7637 ))
7638 })
7639 .collect::<Vec<_>>()
7640 }
7641 })
7642 .unwrap_or_default();
7643
7644 WorkspaceSymbolsResult {
7645 server_id,
7646 lsp_adapter,
7647 worktree: worktree_handle.downgrade(),
7648 lsp_symbols,
7649 }
7650 }),
7651 );
7652 }
7653
7654 cx.spawn(async move |this, cx| {
7655 let responses = futures::future::join_all(requests).await;
7656 let this = match this.upgrade() {
7657 Some(this) => this,
7658 None => return Ok(Vec::new()),
7659 };
7660
7661 let mut symbols = Vec::new();
7662 for result in responses {
7663 let core_symbols = this.update(cx, |this, cx| {
7664 result
7665 .lsp_symbols
7666 .into_iter()
7667 .filter_map(
7668 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7669 let abs_path = symbol_location.uri.to_file_path().ok()?;
7670 let source_worktree = result.worktree.upgrade()?;
7671 let source_worktree_id = source_worktree.read(cx).id();
7672
7673 let path = if let Some((tree, rel_path)) =
7674 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7675 {
7676 let worktree_id = tree.read(cx).id();
7677 SymbolLocation::InProject(ProjectPath {
7678 worktree_id,
7679 path: rel_path,
7680 })
7681 } else {
7682 SymbolLocation::OutsideProject {
7683 signature: this.symbol_signature(&abs_path),
7684 abs_path: abs_path.into(),
7685 }
7686 };
7687
7688 Some(CoreSymbol {
7689 source_language_server_id: result.server_id,
7690 language_server_name: result.lsp_adapter.name.clone(),
7691 source_worktree_id,
7692 path,
7693 kind: symbol_kind,
7694 name: collapse_newlines(&symbol_name, "↵ "),
7695 range: range_from_lsp(symbol_location.range),
7696 container_name: container_name
7697 .map(|c| collapse_newlines(&c, "↵ ")),
7698 })
7699 },
7700 )
7701 .collect::<Vec<_>>()
7702 });
7703
7704 populate_labels_for_symbols(
7705 core_symbols,
7706 &language_registry,
7707 Some(result.lsp_adapter),
7708 &mut symbols,
7709 )
7710 .await;
7711 }
7712
7713 Ok(symbols)
7714 })
7715 } else {
7716 Task::ready(Err(anyhow!("No upstream client or local language server")))
7717 }
7718 }
7719
7720 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7721 let mut summary = DiagnosticSummary::default();
7722 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7723 summary.error_count += path_summary.error_count;
7724 summary.warning_count += path_summary.warning_count;
7725 }
7726 summary
7727 }
7728
7729 /// Returns the diagnostic summary for a specific project path.
7730 pub fn diagnostic_summary_for_path(
7731 &self,
7732 project_path: &ProjectPath,
7733 _: &App,
7734 ) -> DiagnosticSummary {
7735 if let Some(summaries) = self
7736 .diagnostic_summaries
7737 .get(&project_path.worktree_id)
7738 .and_then(|map| map.get(&project_path.path))
7739 {
7740 let (error_count, warning_count) = summaries.iter().fold(
7741 (0, 0),
7742 |(error_count, warning_count), (_language_server_id, summary)| {
7743 (
7744 error_count + summary.error_count,
7745 warning_count + summary.warning_count,
7746 )
7747 },
7748 );
7749
7750 DiagnosticSummary {
7751 error_count,
7752 warning_count,
7753 }
7754 } else {
7755 DiagnosticSummary::default()
7756 }
7757 }
7758
7759 pub fn diagnostic_summaries<'a>(
7760 &'a self,
7761 include_ignored: bool,
7762 cx: &'a App,
7763 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7764 self.worktree_store
7765 .read(cx)
7766 .visible_worktrees(cx)
7767 .filter_map(|worktree| {
7768 let worktree = worktree.read(cx);
7769 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7770 })
7771 .flat_map(move |(worktree, summaries)| {
7772 let worktree_id = worktree.id();
7773 summaries
7774 .iter()
7775 .filter(move |(path, _)| {
7776 include_ignored
7777 || worktree
7778 .entry_for_path(path.as_ref())
7779 .is_some_and(|entry| !entry.is_ignored)
7780 })
7781 .flat_map(move |(path, summaries)| {
7782 summaries.iter().map(move |(server_id, summary)| {
7783 (
7784 ProjectPath {
7785 worktree_id,
7786 path: path.clone(),
7787 },
7788 *server_id,
7789 *summary,
7790 )
7791 })
7792 })
7793 })
7794 }
7795
7796 pub fn on_buffer_edited(
7797 &mut self,
7798 buffer: Entity<Buffer>,
7799 cx: &mut Context<Self>,
7800 ) -> Option<()> {
7801 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7802 Some(
7803 self.as_local()?
7804 .language_servers_for_buffer(buffer, cx)
7805 .map(|i| i.1.clone())
7806 .collect(),
7807 )
7808 })?;
7809
7810 let buffer = buffer.read(cx);
7811 let file = File::from_dyn(buffer.file())?;
7812 let abs_path = file.as_local()?.abs_path(cx);
7813 let uri = lsp::Uri::from_file_path(&abs_path)
7814 .ok()
7815 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7816 .log_err()?;
7817 let next_snapshot = buffer.text_snapshot();
7818 for language_server in language_servers {
7819 let language_server = language_server.clone();
7820
7821 let buffer_snapshots = self
7822 .as_local_mut()?
7823 .buffer_snapshots
7824 .get_mut(&buffer.remote_id())
7825 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7826 let previous_snapshot = buffer_snapshots.last()?;
7827
7828 let build_incremental_change = || {
7829 buffer
7830 .edits_since::<Dimensions<PointUtf16, usize>>(
7831 previous_snapshot.snapshot.version(),
7832 )
7833 .map(|edit| {
7834 let edit_start = edit.new.start.0;
7835 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7836 let new_text = next_snapshot
7837 .text_for_range(edit.new.start.1..edit.new.end.1)
7838 .collect();
7839 lsp::TextDocumentContentChangeEvent {
7840 range: Some(lsp::Range::new(
7841 point_to_lsp(edit_start),
7842 point_to_lsp(edit_end),
7843 )),
7844 range_length: None,
7845 text: new_text,
7846 }
7847 })
7848 .collect()
7849 };
7850
7851 let document_sync_kind = language_server
7852 .capabilities()
7853 .text_document_sync
7854 .as_ref()
7855 .and_then(|sync| match sync {
7856 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7857 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7858 });
7859
7860 let content_changes: Vec<_> = match document_sync_kind {
7861 Some(lsp::TextDocumentSyncKind::FULL) => {
7862 vec![lsp::TextDocumentContentChangeEvent {
7863 range: None,
7864 range_length: None,
7865 text: next_snapshot.text(),
7866 }]
7867 }
7868 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7869 _ => {
7870 #[cfg(any(test, feature = "test-support"))]
7871 {
7872 build_incremental_change()
7873 }
7874
7875 #[cfg(not(any(test, feature = "test-support")))]
7876 {
7877 continue;
7878 }
7879 }
7880 };
7881
7882 let next_version = previous_snapshot.version + 1;
7883 buffer_snapshots.push(LspBufferSnapshot {
7884 version: next_version,
7885 snapshot: next_snapshot.clone(),
7886 });
7887
7888 language_server
7889 .notify::<lsp::notification::DidChangeTextDocument>(
7890 lsp::DidChangeTextDocumentParams {
7891 text_document: lsp::VersionedTextDocumentIdentifier::new(
7892 uri.clone(),
7893 next_version,
7894 ),
7895 content_changes,
7896 },
7897 )
7898 .ok();
7899 self.pull_workspace_diagnostics(language_server.server_id());
7900 }
7901
7902 None
7903 }
7904
7905 pub fn on_buffer_saved(
7906 &mut self,
7907 buffer: Entity<Buffer>,
7908 cx: &mut Context<Self>,
7909 ) -> Option<()> {
7910 let file = File::from_dyn(buffer.read(cx).file())?;
7911 let worktree_id = file.worktree_id(cx);
7912 let abs_path = file.as_local()?.abs_path(cx);
7913 let text_document = lsp::TextDocumentIdentifier {
7914 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7915 };
7916 let local = self.as_local()?;
7917
7918 for server in local.language_servers_for_worktree(worktree_id) {
7919 if let Some(include_text) = include_text(server.as_ref()) {
7920 let text = if include_text {
7921 Some(buffer.read(cx).text())
7922 } else {
7923 None
7924 };
7925 server
7926 .notify::<lsp::notification::DidSaveTextDocument>(
7927 lsp::DidSaveTextDocumentParams {
7928 text_document: text_document.clone(),
7929 text,
7930 },
7931 )
7932 .ok();
7933 }
7934 }
7935
7936 let language_servers = buffer.update(cx, |buffer, cx| {
7937 local.language_server_ids_for_buffer(buffer, cx)
7938 });
7939 for language_server_id in language_servers {
7940 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7941 }
7942
7943 None
7944 }
7945
7946 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7947 maybe!(async move {
7948 let mut refreshed_servers = HashSet::default();
7949 let servers = lsp_store
7950 .update(cx, |lsp_store, cx| {
7951 let local = lsp_store.as_local()?;
7952
7953 let servers = local
7954 .language_server_ids
7955 .iter()
7956 .filter_map(|(seed, state)| {
7957 let worktree = lsp_store
7958 .worktree_store
7959 .read(cx)
7960 .worktree_for_id(seed.worktree_id, cx);
7961 let delegate: Arc<dyn LspAdapterDelegate> =
7962 worktree.map(|worktree| {
7963 LocalLspAdapterDelegate::new(
7964 local.languages.clone(),
7965 &local.environment,
7966 cx.weak_entity(),
7967 &worktree,
7968 local.http_client.clone(),
7969 local.fs.clone(),
7970 cx,
7971 )
7972 })?;
7973 let server_id = state.id;
7974
7975 let states = local.language_servers.get(&server_id)?;
7976
7977 match states {
7978 LanguageServerState::Starting { .. } => None,
7979 LanguageServerState::Running {
7980 adapter, server, ..
7981 } => {
7982 let adapter = adapter.clone();
7983 let server = server.clone();
7984 refreshed_servers.insert(server.name());
7985 let toolchain = seed.toolchain.clone();
7986 Some(cx.spawn(async move |_, cx| {
7987 let settings =
7988 LocalLspStore::workspace_configuration_for_adapter(
7989 adapter.adapter.clone(),
7990 &delegate,
7991 toolchain,
7992 None,
7993 cx,
7994 )
7995 .await
7996 .ok()?;
7997 server
7998 .notify::<lsp::notification::DidChangeConfiguration>(
7999 lsp::DidChangeConfigurationParams { settings },
8000 )
8001 .ok()?;
8002 Some(())
8003 }))
8004 }
8005 }
8006 })
8007 .collect::<Vec<_>>();
8008
8009 Some(servers)
8010 })
8011 .ok()
8012 .flatten()?;
8013
8014 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8015 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8016 // to stop and unregister its language server wrapper.
8017 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8018 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8019 let _: Vec<Option<()>> = join_all(servers).await;
8020
8021 Some(())
8022 })
8023 .await;
8024 }
8025
8026 fn maintain_workspace_config(
8027 external_refresh_requests: watch::Receiver<()>,
8028 cx: &mut Context<Self>,
8029 ) -> Task<Result<()>> {
8030 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8031 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8032
8033 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8034 *settings_changed_tx.borrow_mut() = ();
8035 });
8036
8037 let mut joint_future =
8038 futures::stream::select(settings_changed_rx, external_refresh_requests);
8039 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8040 // - 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).
8041 // - 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.
8042 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8043 // - 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,
8044 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8045 cx.spawn(async move |this, cx| {
8046 while let Some(()) = joint_future.next().await {
8047 this.update(cx, |this, cx| {
8048 this.refresh_server_tree(cx);
8049 })
8050 .ok();
8051
8052 Self::refresh_workspace_configurations(&this, cx).await;
8053 }
8054
8055 drop(settings_observation);
8056 anyhow::Ok(())
8057 })
8058 }
8059
8060 pub fn running_language_servers_for_local_buffer<'a>(
8061 &'a self,
8062 buffer: &Buffer,
8063 cx: &mut App,
8064 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8065 let local = self.as_local();
8066 let language_server_ids = local
8067 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8068 .unwrap_or_default();
8069
8070 language_server_ids
8071 .into_iter()
8072 .filter_map(
8073 move |server_id| match local?.language_servers.get(&server_id)? {
8074 LanguageServerState::Running {
8075 adapter, server, ..
8076 } => Some((adapter, server)),
8077 _ => None,
8078 },
8079 )
8080 }
8081
8082 pub fn language_servers_for_local_buffer(
8083 &self,
8084 buffer: &Buffer,
8085 cx: &mut App,
8086 ) -> Vec<LanguageServerId> {
8087 let local = self.as_local();
8088 local
8089 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8090 .unwrap_or_default()
8091 }
8092
8093 pub fn language_server_for_local_buffer<'a>(
8094 &'a self,
8095 buffer: &'a Buffer,
8096 server_id: LanguageServerId,
8097 cx: &'a mut App,
8098 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8099 self.as_local()?
8100 .language_servers_for_buffer(buffer, cx)
8101 .find(|(_, s)| s.server_id() == server_id)
8102 }
8103
8104 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8105 self.diagnostic_summaries.remove(&id_to_remove);
8106 if let Some(local) = self.as_local_mut() {
8107 let to_remove = local.remove_worktree(id_to_remove, cx);
8108 for server in to_remove {
8109 self.language_server_statuses.remove(&server);
8110 }
8111 }
8112 }
8113
8114 pub fn shared(
8115 &mut self,
8116 project_id: u64,
8117 downstream_client: AnyProtoClient,
8118 _: &mut Context<Self>,
8119 ) {
8120 self.downstream_client = Some((downstream_client.clone(), project_id));
8121
8122 for (server_id, status) in &self.language_server_statuses {
8123 if let Some(server) = self.language_server_for_id(*server_id) {
8124 downstream_client
8125 .send(proto::StartLanguageServer {
8126 project_id,
8127 server: Some(proto::LanguageServer {
8128 id: server_id.to_proto(),
8129 name: status.name.to_string(),
8130 worktree_id: status.worktree.map(|id| id.to_proto()),
8131 }),
8132 capabilities: serde_json::to_string(&server.capabilities())
8133 .expect("serializing server LSP capabilities"),
8134 })
8135 .log_err();
8136 }
8137 }
8138 }
8139
8140 pub fn disconnected_from_host(&mut self) {
8141 self.downstream_client.take();
8142 }
8143
8144 pub fn disconnected_from_ssh_remote(&mut self) {
8145 if let LspStoreMode::Remote(RemoteLspStore {
8146 upstream_client, ..
8147 }) = &mut self.mode
8148 {
8149 upstream_client.take();
8150 }
8151 }
8152
8153 pub(crate) fn set_language_server_statuses_from_proto(
8154 &mut self,
8155 project: WeakEntity<Project>,
8156 language_servers: Vec<proto::LanguageServer>,
8157 server_capabilities: Vec<String>,
8158 cx: &mut Context<Self>,
8159 ) {
8160 let lsp_logs = cx
8161 .try_global::<GlobalLogStore>()
8162 .map(|lsp_store| lsp_store.0.clone());
8163
8164 self.language_server_statuses = language_servers
8165 .into_iter()
8166 .zip(server_capabilities)
8167 .map(|(server, server_capabilities)| {
8168 let server_id = LanguageServerId(server.id as usize);
8169 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8170 self.lsp_server_capabilities
8171 .insert(server_id, server_capabilities);
8172 }
8173
8174 let name = LanguageServerName::from_proto(server.name);
8175 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8176
8177 if let Some(lsp_logs) = &lsp_logs {
8178 lsp_logs.update(cx, |lsp_logs, cx| {
8179 lsp_logs.add_language_server(
8180 // Only remote clients get their language servers set from proto
8181 LanguageServerKind::Remote {
8182 project: project.clone(),
8183 },
8184 server_id,
8185 Some(name.clone()),
8186 worktree,
8187 None,
8188 cx,
8189 );
8190 });
8191 }
8192
8193 (
8194 server_id,
8195 LanguageServerStatus {
8196 name,
8197 server_version: None,
8198 pending_work: Default::default(),
8199 has_pending_diagnostic_updates: false,
8200 progress_tokens: Default::default(),
8201 worktree,
8202 binary: None,
8203 configuration: None,
8204 workspace_folders: BTreeSet::new(),
8205 process_id: None,
8206 },
8207 )
8208 })
8209 .collect();
8210 }
8211
8212 #[cfg(feature = "test-support")]
8213 pub fn update_diagnostic_entries(
8214 &mut self,
8215 server_id: LanguageServerId,
8216 abs_path: PathBuf,
8217 result_id: Option<SharedString>,
8218 version: Option<i32>,
8219 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8220 cx: &mut Context<Self>,
8221 ) -> anyhow::Result<()> {
8222 self.merge_diagnostic_entries(
8223 vec![DocumentDiagnosticsUpdate {
8224 diagnostics: DocumentDiagnostics {
8225 diagnostics,
8226 document_abs_path: abs_path,
8227 version,
8228 },
8229 result_id,
8230 server_id,
8231 disk_based_sources: Cow::Borrowed(&[]),
8232 registration_id: None,
8233 }],
8234 |_, _, _| false,
8235 cx,
8236 )?;
8237 Ok(())
8238 }
8239
8240 pub fn merge_diagnostic_entries<'a>(
8241 &mut self,
8242 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8243 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8244 cx: &mut Context<Self>,
8245 ) -> anyhow::Result<()> {
8246 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8247 let mut updated_diagnostics_paths = HashMap::default();
8248 for mut update in diagnostic_updates {
8249 let abs_path = &update.diagnostics.document_abs_path;
8250 let server_id = update.server_id;
8251 let Some((worktree, relative_path)) =
8252 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8253 else {
8254 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8255 return Ok(());
8256 };
8257
8258 let worktree_id = worktree.read(cx).id();
8259 let project_path = ProjectPath {
8260 worktree_id,
8261 path: relative_path,
8262 };
8263
8264 let document_uri = lsp::Uri::from_file_path(abs_path)
8265 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8266 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8267 let snapshot = buffer_handle.read(cx).snapshot();
8268 let buffer = buffer_handle.read(cx);
8269 let reused_diagnostics = buffer
8270 .buffer_diagnostics(Some(server_id))
8271 .iter()
8272 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8273 .map(|v| {
8274 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8275 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8276 DiagnosticEntry {
8277 range: start..end,
8278 diagnostic: v.diagnostic.clone(),
8279 }
8280 })
8281 .collect::<Vec<_>>();
8282
8283 self.as_local_mut()
8284 .context("cannot merge diagnostics on a remote LspStore")?
8285 .update_buffer_diagnostics(
8286 &buffer_handle,
8287 server_id,
8288 Some(update.registration_id),
8289 update.result_id,
8290 update.diagnostics.version,
8291 update.diagnostics.diagnostics.clone(),
8292 reused_diagnostics.clone(),
8293 cx,
8294 )?;
8295
8296 update.diagnostics.diagnostics.extend(reused_diagnostics);
8297 } else if let Some(local) = self.as_local() {
8298 let reused_diagnostics = local
8299 .diagnostics
8300 .get(&worktree_id)
8301 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8302 .and_then(|diagnostics_by_server_id| {
8303 diagnostics_by_server_id
8304 .binary_search_by_key(&server_id, |e| e.0)
8305 .ok()
8306 .map(|ix| &diagnostics_by_server_id[ix].1)
8307 })
8308 .into_iter()
8309 .flatten()
8310 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8311
8312 update
8313 .diagnostics
8314 .diagnostics
8315 .extend(reused_diagnostics.cloned());
8316 }
8317
8318 let updated = worktree.update(cx, |worktree, cx| {
8319 self.update_worktree_diagnostics(
8320 worktree.id(),
8321 server_id,
8322 project_path.path.clone(),
8323 update.diagnostics.diagnostics,
8324 cx,
8325 )
8326 })?;
8327 match updated {
8328 ControlFlow::Continue(new_summary) => {
8329 if let Some((project_id, new_summary)) = new_summary {
8330 match &mut diagnostics_summary {
8331 Some(diagnostics_summary) => {
8332 diagnostics_summary
8333 .more_summaries
8334 .push(proto::DiagnosticSummary {
8335 path: project_path.path.as_ref().to_proto(),
8336 language_server_id: server_id.0 as u64,
8337 error_count: new_summary.error_count,
8338 warning_count: new_summary.warning_count,
8339 })
8340 }
8341 None => {
8342 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8343 project_id,
8344 worktree_id: worktree_id.to_proto(),
8345 summary: Some(proto::DiagnosticSummary {
8346 path: project_path.path.as_ref().to_proto(),
8347 language_server_id: server_id.0 as u64,
8348 error_count: new_summary.error_count,
8349 warning_count: new_summary.warning_count,
8350 }),
8351 more_summaries: Vec::new(),
8352 })
8353 }
8354 }
8355 }
8356 updated_diagnostics_paths
8357 .entry(server_id)
8358 .or_insert_with(Vec::new)
8359 .push(project_path);
8360 }
8361 ControlFlow::Break(()) => {}
8362 }
8363 }
8364
8365 if let Some((diagnostics_summary, (downstream_client, _))) =
8366 diagnostics_summary.zip(self.downstream_client.as_ref())
8367 {
8368 downstream_client.send(diagnostics_summary).log_err();
8369 }
8370 for (server_id, paths) in updated_diagnostics_paths {
8371 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8372 }
8373 Ok(())
8374 }
8375
8376 fn update_worktree_diagnostics(
8377 &mut self,
8378 worktree_id: WorktreeId,
8379 server_id: LanguageServerId,
8380 path_in_worktree: Arc<RelPath>,
8381 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8382 _: &mut Context<Worktree>,
8383 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8384 let local = match &mut self.mode {
8385 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8386 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8387 };
8388
8389 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8390 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8391 let summaries_by_server_id = summaries_for_tree
8392 .entry(path_in_worktree.clone())
8393 .or_default();
8394
8395 let old_summary = summaries_by_server_id
8396 .remove(&server_id)
8397 .unwrap_or_default();
8398
8399 let new_summary = DiagnosticSummary::new(&diagnostics);
8400 if diagnostics.is_empty() {
8401 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8402 {
8403 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8404 diagnostics_by_server_id.remove(ix);
8405 }
8406 if diagnostics_by_server_id.is_empty() {
8407 diagnostics_for_tree.remove(&path_in_worktree);
8408 }
8409 }
8410 } else {
8411 summaries_by_server_id.insert(server_id, new_summary);
8412 let diagnostics_by_server_id = diagnostics_for_tree
8413 .entry(path_in_worktree.clone())
8414 .or_default();
8415 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8416 Ok(ix) => {
8417 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8418 }
8419 Err(ix) => {
8420 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8421 }
8422 }
8423 }
8424
8425 if !old_summary.is_empty() || !new_summary.is_empty() {
8426 if let Some((_, project_id)) = &self.downstream_client {
8427 Ok(ControlFlow::Continue(Some((
8428 *project_id,
8429 proto::DiagnosticSummary {
8430 path: path_in_worktree.to_proto(),
8431 language_server_id: server_id.0 as u64,
8432 error_count: new_summary.error_count as u32,
8433 warning_count: new_summary.warning_count as u32,
8434 },
8435 ))))
8436 } else {
8437 Ok(ControlFlow::Continue(None))
8438 }
8439 } else {
8440 Ok(ControlFlow::Break(()))
8441 }
8442 }
8443
8444 pub fn open_buffer_for_symbol(
8445 &mut self,
8446 symbol: &Symbol,
8447 cx: &mut Context<Self>,
8448 ) -> Task<Result<Entity<Buffer>>> {
8449 if let Some((client, project_id)) = self.upstream_client() {
8450 let request = client.request(proto::OpenBufferForSymbol {
8451 project_id,
8452 symbol: Some(Self::serialize_symbol(symbol)),
8453 });
8454 cx.spawn(async move |this, cx| {
8455 let response = request.await?;
8456 let buffer_id = BufferId::new(response.buffer_id)?;
8457 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8458 .await
8459 })
8460 } else if let Some(local) = self.as_local() {
8461 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8462 seed.worktree_id == symbol.source_worktree_id
8463 && state.id == symbol.source_language_server_id
8464 && symbol.language_server_name == seed.name
8465 });
8466 if !is_valid {
8467 return Task::ready(Err(anyhow!(
8468 "language server for worktree and language not found"
8469 )));
8470 };
8471
8472 let symbol_abs_path = match &symbol.path {
8473 SymbolLocation::InProject(project_path) => self
8474 .worktree_store
8475 .read(cx)
8476 .absolutize(&project_path, cx)
8477 .context("no such worktree"),
8478 SymbolLocation::OutsideProject {
8479 abs_path,
8480 signature: _,
8481 } => Ok(abs_path.to_path_buf()),
8482 };
8483 let symbol_abs_path = match symbol_abs_path {
8484 Ok(abs_path) => abs_path,
8485 Err(err) => return Task::ready(Err(err)),
8486 };
8487 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8488 uri
8489 } else {
8490 return Task::ready(Err(anyhow!("invalid symbol path")));
8491 };
8492
8493 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8494 } else {
8495 Task::ready(Err(anyhow!("no upstream client or local store")))
8496 }
8497 }
8498
8499 pub(crate) fn open_local_buffer_via_lsp(
8500 &mut self,
8501 abs_path: lsp::Uri,
8502 language_server_id: LanguageServerId,
8503 cx: &mut Context<Self>,
8504 ) -> Task<Result<Entity<Buffer>>> {
8505 let path_style = self.worktree_store.read(cx).path_style();
8506 cx.spawn(async move |lsp_store, cx| {
8507 // Escape percent-encoded string.
8508 let current_scheme = abs_path.scheme().to_owned();
8509 // Uri is immutable, so we can't modify the scheme
8510
8511 let abs_path = abs_path
8512 .to_file_path_ext(path_style)
8513 .map_err(|()| anyhow!("can't convert URI to path"))?;
8514 let p = abs_path.clone();
8515 let yarn_worktree = lsp_store
8516 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8517 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8518 cx.spawn(async move |this, cx| {
8519 let t = this
8520 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8521 .ok()?;
8522 t.await
8523 })
8524 }),
8525 None => Task::ready(None),
8526 })?
8527 .await;
8528 let (worktree_root_target, known_relative_path) =
8529 if let Some((zip_root, relative_path)) = yarn_worktree {
8530 (zip_root, Some(relative_path))
8531 } else {
8532 (Arc::<Path>::from(abs_path.as_path()), None)
8533 };
8534 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8535 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8536 worktree_store.find_worktree(&worktree_root_target, cx)
8537 })
8538 })?;
8539 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8540 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8541 (result.0, relative_path, None)
8542 } else {
8543 let worktree = lsp_store
8544 .update(cx, |lsp_store, cx| {
8545 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8546 worktree_store.create_worktree(&worktree_root_target, false, cx)
8547 })
8548 })?
8549 .await?;
8550 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8551 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8552 lsp_store
8553 .update(cx, |lsp_store, cx| {
8554 if let Some(local) = lsp_store.as_local_mut() {
8555 local.register_language_server_for_invisible_worktree(
8556 &worktree,
8557 language_server_id,
8558 cx,
8559 )
8560 }
8561 match lsp_store.language_server_statuses.get(&language_server_id) {
8562 Some(status) => status.worktree,
8563 None => None,
8564 }
8565 })
8566 .ok()
8567 .flatten()
8568 .zip(Some(worktree_root.clone()))
8569 } else {
8570 None
8571 };
8572 let relative_path = if let Some(known_path) = known_relative_path {
8573 known_path
8574 } else {
8575 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8576 .into_arc()
8577 };
8578 (worktree, relative_path, source_ws)
8579 };
8580 let project_path = ProjectPath {
8581 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8582 path: relative_path,
8583 };
8584 let buffer = lsp_store
8585 .update(cx, |lsp_store, cx| {
8586 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8587 buffer_store.open_buffer(project_path, cx)
8588 })
8589 })?
8590 .await?;
8591 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8592 if let Some((source_ws, worktree_root)) = source_ws {
8593 buffer.update(cx, |buffer, cx| {
8594 let settings = WorktreeSettings::get(
8595 Some(
8596 (&ProjectPath {
8597 worktree_id: source_ws,
8598 path: Arc::from(RelPath::empty()),
8599 })
8600 .into(),
8601 ),
8602 cx,
8603 );
8604 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8605 if is_read_only {
8606 buffer.set_capability(Capability::ReadOnly, cx);
8607 }
8608 });
8609 }
8610 Ok(buffer)
8611 })
8612 }
8613
8614 fn local_lsp_servers_for_buffer(
8615 &self,
8616 buffer: &Entity<Buffer>,
8617 cx: &mut Context<Self>,
8618 ) -> Vec<LanguageServerId> {
8619 let Some(local) = self.as_local() else {
8620 return Vec::new();
8621 };
8622
8623 let snapshot = buffer.read(cx).snapshot();
8624
8625 buffer.update(cx, |buffer, cx| {
8626 local
8627 .language_servers_for_buffer(buffer, cx)
8628 .map(|(_, server)| server.server_id())
8629 .filter(|server_id| {
8630 self.as_local().is_none_or(|local| {
8631 local
8632 .buffers_opened_in_servers
8633 .get(&snapshot.remote_id())
8634 .is_some_and(|servers| servers.contains(server_id))
8635 })
8636 })
8637 .collect()
8638 })
8639 }
8640
8641 fn request_multiple_lsp_locally<P, R>(
8642 &mut self,
8643 buffer: &Entity<Buffer>,
8644 position: Option<P>,
8645 request: R,
8646 cx: &mut Context<Self>,
8647 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8648 where
8649 P: ToOffset,
8650 R: LspCommand + Clone,
8651 <R::LspRequest as lsp::request::Request>::Result: Send,
8652 <R::LspRequest as lsp::request::Request>::Params: Send,
8653 {
8654 let Some(local) = self.as_local() else {
8655 return Task::ready(Vec::new());
8656 };
8657
8658 let snapshot = buffer.read(cx).snapshot();
8659 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8660
8661 let server_ids = buffer.update(cx, |buffer, cx| {
8662 local
8663 .language_servers_for_buffer(buffer, cx)
8664 .filter(|(adapter, _)| {
8665 scope
8666 .as_ref()
8667 .map(|scope| scope.language_allowed(&adapter.name))
8668 .unwrap_or(true)
8669 })
8670 .map(|(_, server)| server.server_id())
8671 .filter(|server_id| {
8672 self.as_local().is_none_or(|local| {
8673 local
8674 .buffers_opened_in_servers
8675 .get(&snapshot.remote_id())
8676 .is_some_and(|servers| servers.contains(server_id))
8677 })
8678 })
8679 .collect::<Vec<_>>()
8680 });
8681
8682 let mut response_results = server_ids
8683 .into_iter()
8684 .map(|server_id| {
8685 let task = self.request_lsp(
8686 buffer.clone(),
8687 LanguageServerToQuery::Other(server_id),
8688 request.clone(),
8689 cx,
8690 );
8691 async move { (server_id, task.await) }
8692 })
8693 .collect::<FuturesUnordered<_>>();
8694
8695 cx.background_spawn(async move {
8696 let mut responses = Vec::with_capacity(response_results.len());
8697 while let Some((server_id, response_result)) = response_results.next().await {
8698 match response_result {
8699 Ok(response) => responses.push((server_id, response)),
8700 // rust-analyzer likes to error with this when its still loading up
8701 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8702 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8703 }
8704 }
8705 responses
8706 })
8707 }
8708
8709 async fn handle_lsp_get_completions(
8710 this: Entity<Self>,
8711 envelope: TypedEnvelope<proto::GetCompletions>,
8712 mut cx: AsyncApp,
8713 ) -> Result<proto::GetCompletionsResponse> {
8714 let sender_id = envelope.original_sender_id().unwrap_or_default();
8715
8716 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8717 let buffer_handle = this.update(&mut cx, |this, cx| {
8718 this.buffer_store.read(cx).get_existing(buffer_id)
8719 })?;
8720 let request = GetCompletions::from_proto(
8721 envelope.payload,
8722 this.clone(),
8723 buffer_handle.clone(),
8724 cx.clone(),
8725 )
8726 .await?;
8727
8728 let server_to_query = match request.server_id {
8729 Some(server_id) => LanguageServerToQuery::Other(server_id),
8730 None => LanguageServerToQuery::FirstCapable,
8731 };
8732
8733 let response = this
8734 .update(&mut cx, |this, cx| {
8735 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8736 })
8737 .await?;
8738 this.update(&mut cx, |this, cx| {
8739 Ok(GetCompletions::response_to_proto(
8740 response,
8741 this,
8742 sender_id,
8743 &buffer_handle.read(cx).version(),
8744 cx,
8745 ))
8746 })
8747 }
8748
8749 async fn handle_lsp_command<T: LspCommand>(
8750 this: Entity<Self>,
8751 envelope: TypedEnvelope<T::ProtoRequest>,
8752 mut cx: AsyncApp,
8753 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8754 where
8755 <T::LspRequest as lsp::request::Request>::Params: Send,
8756 <T::LspRequest as lsp::request::Request>::Result: Send,
8757 {
8758 let sender_id = envelope.original_sender_id().unwrap_or_default();
8759 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8760 let buffer_handle = this.update(&mut cx, |this, cx| {
8761 this.buffer_store.read(cx).get_existing(buffer_id)
8762 })?;
8763 let request = T::from_proto(
8764 envelope.payload,
8765 this.clone(),
8766 buffer_handle.clone(),
8767 cx.clone(),
8768 )
8769 .await?;
8770 let response = this
8771 .update(&mut cx, |this, cx| {
8772 this.request_lsp(
8773 buffer_handle.clone(),
8774 LanguageServerToQuery::FirstCapable,
8775 request,
8776 cx,
8777 )
8778 })
8779 .await?;
8780 this.update(&mut cx, |this, cx| {
8781 Ok(T::response_to_proto(
8782 response,
8783 this,
8784 sender_id,
8785 &buffer_handle.read(cx).version(),
8786 cx,
8787 ))
8788 })
8789 }
8790
8791 async fn handle_lsp_query(
8792 lsp_store: Entity<Self>,
8793 envelope: TypedEnvelope<proto::LspQuery>,
8794 mut cx: AsyncApp,
8795 ) -> Result<proto::Ack> {
8796 use proto::lsp_query::Request;
8797 let sender_id = envelope.original_sender_id().unwrap_or_default();
8798 let lsp_query = envelope.payload;
8799 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8800 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8801 match lsp_query.request.context("invalid LSP query request")? {
8802 Request::GetReferences(get_references) => {
8803 let position = get_references.position.clone().and_then(deserialize_anchor);
8804 Self::query_lsp_locally::<GetReferences>(
8805 lsp_store,
8806 server_id,
8807 sender_id,
8808 lsp_request_id,
8809 get_references,
8810 position,
8811 &mut cx,
8812 )
8813 .await?;
8814 }
8815 Request::GetDocumentColor(get_document_color) => {
8816 Self::query_lsp_locally::<GetDocumentColor>(
8817 lsp_store,
8818 server_id,
8819 sender_id,
8820 lsp_request_id,
8821 get_document_color,
8822 None,
8823 &mut cx,
8824 )
8825 .await?;
8826 }
8827 Request::GetFoldingRanges(get_folding_ranges) => {
8828 Self::query_lsp_locally::<GetFoldingRanges>(
8829 lsp_store,
8830 server_id,
8831 sender_id,
8832 lsp_request_id,
8833 get_folding_ranges,
8834 None,
8835 &mut cx,
8836 )
8837 .await?;
8838 }
8839 Request::GetDocumentSymbols(get_document_symbols) => {
8840 Self::query_lsp_locally::<GetDocumentSymbols>(
8841 lsp_store,
8842 server_id,
8843 sender_id,
8844 lsp_request_id,
8845 get_document_symbols,
8846 None,
8847 &mut cx,
8848 )
8849 .await?;
8850 }
8851 Request::GetHover(get_hover) => {
8852 let position = get_hover.position.clone().and_then(deserialize_anchor);
8853 Self::query_lsp_locally::<GetHover>(
8854 lsp_store,
8855 server_id,
8856 sender_id,
8857 lsp_request_id,
8858 get_hover,
8859 position,
8860 &mut cx,
8861 )
8862 .await?;
8863 }
8864 Request::GetCodeActions(get_code_actions) => {
8865 Self::query_lsp_locally::<GetCodeActions>(
8866 lsp_store,
8867 server_id,
8868 sender_id,
8869 lsp_request_id,
8870 get_code_actions,
8871 None,
8872 &mut cx,
8873 )
8874 .await?;
8875 }
8876 Request::GetSignatureHelp(get_signature_help) => {
8877 let position = get_signature_help
8878 .position
8879 .clone()
8880 .and_then(deserialize_anchor);
8881 Self::query_lsp_locally::<GetSignatureHelp>(
8882 lsp_store,
8883 server_id,
8884 sender_id,
8885 lsp_request_id,
8886 get_signature_help,
8887 position,
8888 &mut cx,
8889 )
8890 .await?;
8891 }
8892 Request::GetCodeLens(get_code_lens) => {
8893 Self::query_lsp_locally::<GetCodeLens>(
8894 lsp_store,
8895 server_id,
8896 sender_id,
8897 lsp_request_id,
8898 get_code_lens,
8899 None,
8900 &mut cx,
8901 )
8902 .await?;
8903 }
8904 Request::GetDefinition(get_definition) => {
8905 let position = get_definition.position.clone().and_then(deserialize_anchor);
8906 Self::query_lsp_locally::<GetDefinitions>(
8907 lsp_store,
8908 server_id,
8909 sender_id,
8910 lsp_request_id,
8911 get_definition,
8912 position,
8913 &mut cx,
8914 )
8915 .await?;
8916 }
8917 Request::GetDeclaration(get_declaration) => {
8918 let position = get_declaration
8919 .position
8920 .clone()
8921 .and_then(deserialize_anchor);
8922 Self::query_lsp_locally::<GetDeclarations>(
8923 lsp_store,
8924 server_id,
8925 sender_id,
8926 lsp_request_id,
8927 get_declaration,
8928 position,
8929 &mut cx,
8930 )
8931 .await?;
8932 }
8933 Request::GetTypeDefinition(get_type_definition) => {
8934 let position = get_type_definition
8935 .position
8936 .clone()
8937 .and_then(deserialize_anchor);
8938 Self::query_lsp_locally::<GetTypeDefinitions>(
8939 lsp_store,
8940 server_id,
8941 sender_id,
8942 lsp_request_id,
8943 get_type_definition,
8944 position,
8945 &mut cx,
8946 )
8947 .await?;
8948 }
8949 Request::GetImplementation(get_implementation) => {
8950 let position = get_implementation
8951 .position
8952 .clone()
8953 .and_then(deserialize_anchor);
8954 Self::query_lsp_locally::<GetImplementations>(
8955 lsp_store,
8956 server_id,
8957 sender_id,
8958 lsp_request_id,
8959 get_implementation,
8960 position,
8961 &mut cx,
8962 )
8963 .await?;
8964 }
8965 Request::InlayHints(inlay_hints) => {
8966 let query_start = inlay_hints
8967 .start
8968 .clone()
8969 .and_then(deserialize_anchor)
8970 .context("invalid inlay hints range start")?;
8971 let query_end = inlay_hints
8972 .end
8973 .clone()
8974 .and_then(deserialize_anchor)
8975 .context("invalid inlay hints range end")?;
8976 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8977 &lsp_store,
8978 server_id,
8979 lsp_request_id,
8980 &inlay_hints,
8981 query_start..query_end,
8982 &mut cx,
8983 )
8984 .await
8985 .context("preparing inlay hints request")?;
8986 Self::query_lsp_locally::<InlayHints>(
8987 lsp_store,
8988 server_id,
8989 sender_id,
8990 lsp_request_id,
8991 inlay_hints,
8992 None,
8993 &mut cx,
8994 )
8995 .await
8996 .context("querying for inlay hints")?
8997 }
8998 //////////////////////////////
8999 // Below are LSP queries that need to fetch more data,
9000 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9001 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9002 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9003 &lsp_store,
9004 &get_document_diagnostics,
9005 &mut cx,
9006 )
9007 .await?;
9008 lsp_store.update(&mut cx, |lsp_store, cx| {
9009 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9010 let key = LspKey {
9011 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9012 server_queried: server_id,
9013 };
9014 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9015 ) {
9016 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9017 lsp_requests.clear();
9018 };
9019 }
9020
9021 lsp_data.lsp_requests.entry(key).or_default().insert(
9022 lsp_request_id,
9023 cx.spawn(async move |lsp_store, cx| {
9024 let diagnostics_pull = lsp_store
9025 .update(cx, |lsp_store, cx| {
9026 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9027 })
9028 .ok();
9029 if let Some(diagnostics_pull) = diagnostics_pull {
9030 match diagnostics_pull.await {
9031 Ok(()) => {}
9032 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9033 };
9034 }
9035 }),
9036 );
9037 });
9038 }
9039 Request::SemanticTokens(semantic_tokens) => {
9040 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9041 &lsp_store,
9042 &semantic_tokens,
9043 &mut cx,
9044 )
9045 .await?;
9046 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9047 lsp_store.update(&mut cx, |lsp_store, cx| {
9048 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9049 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9050 let key = LspKey {
9051 request_type: TypeId::of::<SemanticTokensFull>(),
9052 server_queried: server_id,
9053 };
9054 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9055 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9056 lsp_requests.clear();
9057 };
9058 }
9059
9060 lsp_data.lsp_requests.entry(key).or_default().insert(
9061 lsp_request_id,
9062 cx.spawn(async move |lsp_store, cx| {
9063 let tokens_fetch = lsp_store
9064 .update(cx, |lsp_store, cx| {
9065 lsp_store
9066 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9067 })
9068 .ok();
9069 if let Some(tokens_fetch) = tokens_fetch {
9070 let new_tokens = tokens_fetch.await;
9071 if let Some(new_tokens) = new_tokens {
9072 lsp_store
9073 .update(cx, |lsp_store, cx| {
9074 let response = new_tokens
9075 .into_iter()
9076 .map(|(server_id, response)| {
9077 (
9078 server_id.to_proto(),
9079 SemanticTokensFull::response_to_proto(
9080 response,
9081 lsp_store,
9082 sender_id,
9083 &buffer_version,
9084 cx,
9085 ),
9086 )
9087 })
9088 .collect::<HashMap<_, _>>();
9089 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9090 project_id,
9091 lsp_request_id,
9092 response,
9093 ) {
9094 Ok(()) => {}
9095 Err(e) => {
9096 log::error!(
9097 "Failed to send semantic tokens LSP response: {e:#}",
9098 )
9099 }
9100 }
9101 })
9102 .ok();
9103 }
9104 }
9105 }),
9106 );
9107 }
9108 });
9109 }
9110 }
9111 Ok(proto::Ack {})
9112 }
9113
9114 async fn handle_lsp_query_response(
9115 lsp_store: Entity<Self>,
9116 envelope: TypedEnvelope<proto::LspQueryResponse>,
9117 cx: AsyncApp,
9118 ) -> Result<()> {
9119 lsp_store.read_with(&cx, |lsp_store, _| {
9120 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9121 upstream_client.handle_lsp_response(envelope.clone());
9122 }
9123 });
9124 Ok(())
9125 }
9126
9127 async fn handle_apply_code_action(
9128 this: Entity<Self>,
9129 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9130 mut cx: AsyncApp,
9131 ) -> Result<proto::ApplyCodeActionResponse> {
9132 let sender_id = envelope.original_sender_id().unwrap_or_default();
9133 let action =
9134 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9135 let apply_code_action = this.update(&mut cx, |this, cx| {
9136 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9137 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9138 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9139 })?;
9140
9141 let project_transaction = apply_code_action.await?;
9142 let project_transaction = this.update(&mut cx, |this, cx| {
9143 this.buffer_store.update(cx, |buffer_store, cx| {
9144 buffer_store.serialize_project_transaction_for_peer(
9145 project_transaction,
9146 sender_id,
9147 cx,
9148 )
9149 })
9150 });
9151 Ok(proto::ApplyCodeActionResponse {
9152 transaction: Some(project_transaction),
9153 })
9154 }
9155
9156 async fn handle_register_buffer_with_language_servers(
9157 this: Entity<Self>,
9158 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9159 mut cx: AsyncApp,
9160 ) -> Result<proto::Ack> {
9161 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9162 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9163 this.update(&mut cx, |this, cx| {
9164 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9165 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9166 project_id: upstream_project_id,
9167 buffer_id: buffer_id.to_proto(),
9168 only_servers: envelope.payload.only_servers,
9169 });
9170 }
9171
9172 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9173 anyhow::bail!("buffer is not open");
9174 };
9175
9176 let handle = this.register_buffer_with_language_servers(
9177 &buffer,
9178 envelope
9179 .payload
9180 .only_servers
9181 .into_iter()
9182 .filter_map(|selector| {
9183 Some(match selector.selector? {
9184 proto::language_server_selector::Selector::ServerId(server_id) => {
9185 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9186 }
9187 proto::language_server_selector::Selector::Name(name) => {
9188 LanguageServerSelector::Name(LanguageServerName(
9189 SharedString::from(name),
9190 ))
9191 }
9192 })
9193 })
9194 .collect(),
9195 false,
9196 cx,
9197 );
9198 // Pull diagnostics for the buffer even if it was already registered.
9199 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9200 // but it's unclear if we need it.
9201 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9202 .detach();
9203 this.buffer_store().update(cx, |buffer_store, _| {
9204 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9205 });
9206
9207 Ok(())
9208 })?;
9209 Ok(proto::Ack {})
9210 }
9211
9212 async fn handle_rename_project_entry(
9213 this: Entity<Self>,
9214 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9215 mut cx: AsyncApp,
9216 ) -> Result<proto::ProjectEntryResponse> {
9217 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9218 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9219 let new_path =
9220 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9221
9222 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9223 .update(&mut cx, |this, cx| {
9224 let (worktree, entry) = this
9225 .worktree_store
9226 .read(cx)
9227 .worktree_and_entry_for_id(entry_id, cx)?;
9228 let new_worktree = this
9229 .worktree_store
9230 .read(cx)
9231 .worktree_for_id(new_worktree_id, cx)?;
9232 Some((
9233 this.worktree_store.clone(),
9234 worktree,
9235 new_worktree,
9236 entry.clone(),
9237 ))
9238 })
9239 .context("worktree not found")?;
9240 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9241 (worktree.absolutize(&old_entry.path), worktree.id())
9242 });
9243 let new_abs_path =
9244 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9245
9246 let _transaction = Self::will_rename_entry(
9247 this.downgrade(),
9248 old_worktree_id,
9249 &old_abs_path,
9250 &new_abs_path,
9251 old_entry.is_dir(),
9252 cx.clone(),
9253 )
9254 .await;
9255 let response = WorktreeStore::handle_rename_project_entry(
9256 worktree_store,
9257 envelope.payload,
9258 cx.clone(),
9259 )
9260 .await;
9261 this.read_with(&cx, |this, _| {
9262 this.did_rename_entry(
9263 old_worktree_id,
9264 &old_abs_path,
9265 &new_abs_path,
9266 old_entry.is_dir(),
9267 );
9268 });
9269 response
9270 }
9271
9272 async fn handle_update_diagnostic_summary(
9273 this: Entity<Self>,
9274 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9275 mut cx: AsyncApp,
9276 ) -> Result<()> {
9277 this.update(&mut cx, |lsp_store, cx| {
9278 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9279 let mut updated_diagnostics_paths = HashMap::default();
9280 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9281 for message_summary in envelope
9282 .payload
9283 .summary
9284 .into_iter()
9285 .chain(envelope.payload.more_summaries)
9286 {
9287 let project_path = ProjectPath {
9288 worktree_id,
9289 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9290 };
9291 let path = project_path.path.clone();
9292 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9293 let summary = DiagnosticSummary {
9294 error_count: message_summary.error_count as usize,
9295 warning_count: message_summary.warning_count as usize,
9296 };
9297
9298 if summary.is_empty() {
9299 if let Some(worktree_summaries) =
9300 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9301 && let Some(summaries) = worktree_summaries.get_mut(&path)
9302 {
9303 summaries.remove(&server_id);
9304 if summaries.is_empty() {
9305 worktree_summaries.remove(&path);
9306 }
9307 }
9308 } else {
9309 lsp_store
9310 .diagnostic_summaries
9311 .entry(worktree_id)
9312 .or_default()
9313 .entry(path)
9314 .or_default()
9315 .insert(server_id, summary);
9316 }
9317
9318 if let Some((_, project_id)) = &lsp_store.downstream_client {
9319 match &mut diagnostics_summary {
9320 Some(diagnostics_summary) => {
9321 diagnostics_summary
9322 .more_summaries
9323 .push(proto::DiagnosticSummary {
9324 path: project_path.path.as_ref().to_proto(),
9325 language_server_id: server_id.0 as u64,
9326 error_count: summary.error_count as u32,
9327 warning_count: summary.warning_count as u32,
9328 })
9329 }
9330 None => {
9331 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9332 project_id: *project_id,
9333 worktree_id: worktree_id.to_proto(),
9334 summary: Some(proto::DiagnosticSummary {
9335 path: project_path.path.as_ref().to_proto(),
9336 language_server_id: server_id.0 as u64,
9337 error_count: summary.error_count as u32,
9338 warning_count: summary.warning_count as u32,
9339 }),
9340 more_summaries: Vec::new(),
9341 })
9342 }
9343 }
9344 }
9345 updated_diagnostics_paths
9346 .entry(server_id)
9347 .or_insert_with(Vec::new)
9348 .push(project_path);
9349 }
9350
9351 if let Some((diagnostics_summary, (downstream_client, _))) =
9352 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9353 {
9354 downstream_client.send(diagnostics_summary).log_err();
9355 }
9356 for (server_id, paths) in updated_diagnostics_paths {
9357 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9358 }
9359 Ok(())
9360 })
9361 }
9362
9363 async fn handle_start_language_server(
9364 lsp_store: Entity<Self>,
9365 envelope: TypedEnvelope<proto::StartLanguageServer>,
9366 mut cx: AsyncApp,
9367 ) -> Result<()> {
9368 let server = envelope.payload.server.context("invalid server")?;
9369 let server_capabilities =
9370 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9371 .with_context(|| {
9372 format!(
9373 "incorrect server capabilities {}",
9374 envelope.payload.capabilities
9375 )
9376 })?;
9377 lsp_store.update(&mut cx, |lsp_store, cx| {
9378 let server_id = LanguageServerId(server.id as usize);
9379 let server_name = LanguageServerName::from_proto(server.name.clone());
9380 lsp_store
9381 .lsp_server_capabilities
9382 .insert(server_id, server_capabilities);
9383 lsp_store.language_server_statuses.insert(
9384 server_id,
9385 LanguageServerStatus {
9386 name: server_name.clone(),
9387 server_version: None,
9388 pending_work: Default::default(),
9389 has_pending_diagnostic_updates: false,
9390 progress_tokens: Default::default(),
9391 worktree: server.worktree_id.map(WorktreeId::from_proto),
9392 binary: None,
9393 configuration: None,
9394 workspace_folders: BTreeSet::new(),
9395 process_id: None,
9396 },
9397 );
9398 cx.emit(LspStoreEvent::LanguageServerAdded(
9399 server_id,
9400 server_name,
9401 server.worktree_id.map(WorktreeId::from_proto),
9402 ));
9403 cx.notify();
9404 });
9405 Ok(())
9406 }
9407
9408 async fn handle_update_language_server(
9409 lsp_store: Entity<Self>,
9410 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9411 mut cx: AsyncApp,
9412 ) -> Result<()> {
9413 lsp_store.update(&mut cx, |lsp_store, cx| {
9414 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9415
9416 match envelope.payload.variant.context("invalid variant")? {
9417 proto::update_language_server::Variant::WorkStart(payload) => {
9418 lsp_store.on_lsp_work_start(
9419 language_server_id,
9420 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9421 .context("invalid progress token value")?,
9422 LanguageServerProgress {
9423 title: payload.title,
9424 is_disk_based_diagnostics_progress: false,
9425 is_cancellable: payload.is_cancellable.unwrap_or(false),
9426 message: payload.message,
9427 percentage: payload.percentage.map(|p| p as usize),
9428 last_update_at: cx.background_executor().now(),
9429 },
9430 cx,
9431 );
9432 }
9433 proto::update_language_server::Variant::WorkProgress(payload) => {
9434 lsp_store.on_lsp_work_progress(
9435 language_server_id,
9436 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9437 .context("invalid progress token value")?,
9438 LanguageServerProgress {
9439 title: None,
9440 is_disk_based_diagnostics_progress: false,
9441 is_cancellable: payload.is_cancellable.unwrap_or(false),
9442 message: payload.message,
9443 percentage: payload.percentage.map(|p| p as usize),
9444 last_update_at: cx.background_executor().now(),
9445 },
9446 cx,
9447 );
9448 }
9449
9450 proto::update_language_server::Variant::WorkEnd(payload) => {
9451 lsp_store.on_lsp_work_end(
9452 language_server_id,
9453 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9454 .context("invalid progress token value")?,
9455 cx,
9456 );
9457 }
9458
9459 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9460 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9461 }
9462
9463 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9464 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9465 }
9466
9467 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9468 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9469 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9470 cx.emit(LspStoreEvent::LanguageServerUpdate {
9471 language_server_id,
9472 name: envelope
9473 .payload
9474 .server_name
9475 .map(SharedString::new)
9476 .map(LanguageServerName),
9477 message: non_lsp,
9478 });
9479 }
9480 }
9481
9482 Ok(())
9483 })
9484 }
9485
9486 async fn handle_language_server_log(
9487 this: Entity<Self>,
9488 envelope: TypedEnvelope<proto::LanguageServerLog>,
9489 mut cx: AsyncApp,
9490 ) -> Result<()> {
9491 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9492 let log_type = envelope
9493 .payload
9494 .log_type
9495 .map(LanguageServerLogType::from_proto)
9496 .context("invalid language server log type")?;
9497
9498 let message = envelope.payload.message;
9499
9500 this.update(&mut cx, |_, cx| {
9501 cx.emit(LspStoreEvent::LanguageServerLog(
9502 language_server_id,
9503 log_type,
9504 message,
9505 ));
9506 });
9507 Ok(())
9508 }
9509
9510 async fn handle_lsp_ext_cancel_flycheck(
9511 lsp_store: Entity<Self>,
9512 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9513 cx: AsyncApp,
9514 ) -> Result<proto::Ack> {
9515 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9516 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9517 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9518 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9519 } else {
9520 None
9521 }
9522 });
9523 if let Some(task) = task {
9524 task.context("handling lsp ext cancel flycheck")?;
9525 }
9526
9527 Ok(proto::Ack {})
9528 }
9529
9530 async fn handle_lsp_ext_run_flycheck(
9531 lsp_store: Entity<Self>,
9532 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9533 mut cx: AsyncApp,
9534 ) -> Result<proto::Ack> {
9535 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9536 lsp_store.update(&mut cx, |lsp_store, cx| {
9537 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9538 let text_document = if envelope.payload.current_file_only {
9539 let buffer_id = envelope
9540 .payload
9541 .buffer_id
9542 .map(|id| BufferId::new(id))
9543 .transpose()?;
9544 buffer_id
9545 .and_then(|buffer_id| {
9546 lsp_store
9547 .buffer_store()
9548 .read(cx)
9549 .get(buffer_id)
9550 .and_then(|buffer| {
9551 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9552 })
9553 .map(|path| make_text_document_identifier(&path))
9554 })
9555 .transpose()?
9556 } else {
9557 None
9558 };
9559 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9560 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9561 )?;
9562 }
9563 anyhow::Ok(())
9564 })?;
9565
9566 Ok(proto::Ack {})
9567 }
9568
9569 async fn handle_lsp_ext_clear_flycheck(
9570 lsp_store: Entity<Self>,
9571 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9572 cx: AsyncApp,
9573 ) -> Result<proto::Ack> {
9574 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9575 lsp_store.read_with(&cx, |lsp_store, _| {
9576 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9577 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9578 } else {
9579 None
9580 }
9581 });
9582
9583 Ok(proto::Ack {})
9584 }
9585
9586 pub fn disk_based_diagnostics_started(
9587 &mut self,
9588 language_server_id: LanguageServerId,
9589 cx: &mut Context<Self>,
9590 ) {
9591 if let Some(language_server_status) =
9592 self.language_server_statuses.get_mut(&language_server_id)
9593 {
9594 language_server_status.has_pending_diagnostic_updates = true;
9595 }
9596
9597 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9598 cx.emit(LspStoreEvent::LanguageServerUpdate {
9599 language_server_id,
9600 name: self
9601 .language_server_adapter_for_id(language_server_id)
9602 .map(|adapter| adapter.name()),
9603 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9604 Default::default(),
9605 ),
9606 })
9607 }
9608
9609 pub fn disk_based_diagnostics_finished(
9610 &mut self,
9611 language_server_id: LanguageServerId,
9612 cx: &mut Context<Self>,
9613 ) {
9614 if let Some(language_server_status) =
9615 self.language_server_statuses.get_mut(&language_server_id)
9616 {
9617 language_server_status.has_pending_diagnostic_updates = false;
9618 }
9619
9620 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9621 cx.emit(LspStoreEvent::LanguageServerUpdate {
9622 language_server_id,
9623 name: self
9624 .language_server_adapter_for_id(language_server_id)
9625 .map(|adapter| adapter.name()),
9626 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9627 Default::default(),
9628 ),
9629 })
9630 }
9631
9632 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9633 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9634 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9635 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9636 // the language server might take some time to publish diagnostics.
9637 fn simulate_disk_based_diagnostics_events_if_needed(
9638 &mut self,
9639 language_server_id: LanguageServerId,
9640 cx: &mut Context<Self>,
9641 ) {
9642 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9643
9644 let Some(LanguageServerState::Running {
9645 simulate_disk_based_diagnostics_completion,
9646 adapter,
9647 ..
9648 }) = self
9649 .as_local_mut()
9650 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9651 else {
9652 return;
9653 };
9654
9655 if adapter.disk_based_diagnostics_progress_token.is_some() {
9656 return;
9657 }
9658
9659 let prev_task =
9660 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9661 cx.background_executor()
9662 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9663 .await;
9664
9665 this.update(cx, |this, cx| {
9666 this.disk_based_diagnostics_finished(language_server_id, cx);
9667
9668 if let Some(LanguageServerState::Running {
9669 simulate_disk_based_diagnostics_completion,
9670 ..
9671 }) = this.as_local_mut().and_then(|local_store| {
9672 local_store.language_servers.get_mut(&language_server_id)
9673 }) {
9674 *simulate_disk_based_diagnostics_completion = None;
9675 }
9676 })
9677 .ok();
9678 }));
9679
9680 if prev_task.is_none() {
9681 self.disk_based_diagnostics_started(language_server_id, cx);
9682 }
9683 }
9684
9685 pub fn language_server_statuses(
9686 &self,
9687 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9688 self.language_server_statuses
9689 .iter()
9690 .map(|(key, value)| (*key, value))
9691 }
9692
9693 pub(super) fn did_rename_entry(
9694 &self,
9695 worktree_id: WorktreeId,
9696 old_path: &Path,
9697 new_path: &Path,
9698 is_dir: bool,
9699 ) {
9700 maybe!({
9701 let local_store = self.as_local()?;
9702
9703 let old_uri = lsp::Uri::from_file_path(old_path)
9704 .ok()
9705 .map(|uri| uri.to_string())?;
9706 let new_uri = lsp::Uri::from_file_path(new_path)
9707 .ok()
9708 .map(|uri| uri.to_string())?;
9709
9710 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9711 let Some(filter) = local_store
9712 .language_server_paths_watched_for_rename
9713 .get(&language_server.server_id())
9714 else {
9715 continue;
9716 };
9717
9718 if filter.should_send_did_rename(&old_uri, is_dir) {
9719 language_server
9720 .notify::<DidRenameFiles>(RenameFilesParams {
9721 files: vec![FileRename {
9722 old_uri: old_uri.clone(),
9723 new_uri: new_uri.clone(),
9724 }],
9725 })
9726 .ok();
9727 }
9728 }
9729 Some(())
9730 });
9731 }
9732
9733 pub(super) fn will_rename_entry(
9734 this: WeakEntity<Self>,
9735 worktree_id: WorktreeId,
9736 old_path: &Path,
9737 new_path: &Path,
9738 is_dir: bool,
9739 cx: AsyncApp,
9740 ) -> Task<ProjectTransaction> {
9741 let old_uri = lsp::Uri::from_file_path(old_path)
9742 .ok()
9743 .map(|uri| uri.to_string());
9744 let new_uri = lsp::Uri::from_file_path(new_path)
9745 .ok()
9746 .map(|uri| uri.to_string());
9747 cx.spawn(async move |cx| {
9748 let mut tasks = vec![];
9749 this.update(cx, |this, cx| {
9750 let local_store = this.as_local()?;
9751 let old_uri = old_uri?;
9752 let new_uri = new_uri?;
9753 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9754 let Some(filter) = local_store
9755 .language_server_paths_watched_for_rename
9756 .get(&language_server.server_id())
9757 else {
9758 continue;
9759 };
9760
9761 if !filter.should_send_will_rename(&old_uri, is_dir) {
9762 continue;
9763 }
9764 let request_timeout = ProjectSettings::get_global(cx)
9765 .global_lsp_settings
9766 .get_request_timeout();
9767
9768 let apply_edit = cx.spawn({
9769 let old_uri = old_uri.clone();
9770 let new_uri = new_uri.clone();
9771 let language_server = language_server.clone();
9772 async move |this, cx| {
9773 let edit = language_server
9774 .request::<WillRenameFiles>(
9775 RenameFilesParams {
9776 files: vec![FileRename { old_uri, new_uri }],
9777 },
9778 request_timeout,
9779 )
9780 .await
9781 .into_response()
9782 .context("will rename files")
9783 .log_err()
9784 .flatten()?;
9785
9786 LocalLspStore::deserialize_workspace_edit(
9787 this.upgrade()?,
9788 edit,
9789 false,
9790 language_server.clone(),
9791 cx,
9792 )
9793 .await
9794 .ok()
9795 }
9796 });
9797 tasks.push(apply_edit);
9798 }
9799 Some(())
9800 })
9801 .ok()
9802 .flatten();
9803 let mut merged_transaction = ProjectTransaction::default();
9804 for task in tasks {
9805 // Await on tasks sequentially so that the order of application of edits is deterministic
9806 // (at least with regards to the order of registration of language servers)
9807 if let Some(transaction) = task.await {
9808 for (buffer, buffer_transaction) in transaction.0 {
9809 merged_transaction.0.insert(buffer, buffer_transaction);
9810 }
9811 }
9812 }
9813 merged_transaction
9814 })
9815 }
9816
9817 fn lsp_notify_abs_paths_changed(
9818 &mut self,
9819 server_id: LanguageServerId,
9820 changes: Vec<PathEvent>,
9821 ) {
9822 maybe!({
9823 let server = self.language_server_for_id(server_id)?;
9824 let changes = changes
9825 .into_iter()
9826 .filter_map(|event| {
9827 let typ = match event.kind? {
9828 PathEventKind::Created => lsp::FileChangeType::CREATED,
9829 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9830 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9831 };
9832 Some(lsp::FileEvent {
9833 uri: file_path_to_lsp_url(&event.path).log_err()?,
9834 typ,
9835 })
9836 })
9837 .collect::<Vec<_>>();
9838 if !changes.is_empty() {
9839 server
9840 .notify::<lsp::notification::DidChangeWatchedFiles>(
9841 lsp::DidChangeWatchedFilesParams { changes },
9842 )
9843 .ok();
9844 }
9845 Some(())
9846 });
9847 }
9848
9849 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9850 self.as_local()?.language_server_for_id(id)
9851 }
9852
9853 fn on_lsp_progress(
9854 &mut self,
9855 progress_params: lsp::ProgressParams,
9856 language_server_id: LanguageServerId,
9857 disk_based_diagnostics_progress_token: Option<String>,
9858 cx: &mut Context<Self>,
9859 ) {
9860 match progress_params.value {
9861 lsp::ProgressParamsValue::WorkDone(progress) => {
9862 self.handle_work_done_progress(
9863 progress,
9864 language_server_id,
9865 disk_based_diagnostics_progress_token,
9866 ProgressToken::from_lsp(progress_params.token),
9867 cx,
9868 );
9869 }
9870 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9871 let registration_id = match progress_params.token {
9872 lsp::NumberOrString::Number(_) => None,
9873 lsp::NumberOrString::String(token) => token
9874 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9875 .map(|(_, id)| id.to_owned()),
9876 };
9877 if let Some(LanguageServerState::Running {
9878 workspace_diagnostics_refresh_tasks,
9879 ..
9880 }) = self
9881 .as_local_mut()
9882 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9883 && let Some(workspace_diagnostics) =
9884 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9885 {
9886 workspace_diagnostics.progress_tx.try_send(()).ok();
9887 self.apply_workspace_diagnostic_report(
9888 language_server_id,
9889 report,
9890 registration_id.map(SharedString::from),
9891 cx,
9892 )
9893 }
9894 }
9895 }
9896 }
9897
9898 fn handle_work_done_progress(
9899 &mut self,
9900 progress: lsp::WorkDoneProgress,
9901 language_server_id: LanguageServerId,
9902 disk_based_diagnostics_progress_token: Option<String>,
9903 token: ProgressToken,
9904 cx: &mut Context<Self>,
9905 ) {
9906 let language_server_status =
9907 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9908 status
9909 } else {
9910 return;
9911 };
9912
9913 if !language_server_status.progress_tokens.contains(&token) {
9914 return;
9915 }
9916
9917 let is_disk_based_diagnostics_progress =
9918 if let (Some(disk_based_token), ProgressToken::String(token)) =
9919 (&disk_based_diagnostics_progress_token, &token)
9920 {
9921 token.starts_with(disk_based_token)
9922 } else {
9923 false
9924 };
9925
9926 match progress {
9927 lsp::WorkDoneProgress::Begin(report) => {
9928 if is_disk_based_diagnostics_progress {
9929 self.disk_based_diagnostics_started(language_server_id, cx);
9930 }
9931 self.on_lsp_work_start(
9932 language_server_id,
9933 token.clone(),
9934 LanguageServerProgress {
9935 title: Some(report.title),
9936 is_disk_based_diagnostics_progress,
9937 is_cancellable: report.cancellable.unwrap_or(false),
9938 message: report.message.clone(),
9939 percentage: report.percentage.map(|p| p as usize),
9940 last_update_at: cx.background_executor().now(),
9941 },
9942 cx,
9943 );
9944 }
9945 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9946 language_server_id,
9947 token,
9948 LanguageServerProgress {
9949 title: None,
9950 is_disk_based_diagnostics_progress,
9951 is_cancellable: report.cancellable.unwrap_or(false),
9952 message: report.message,
9953 percentage: report.percentage.map(|p| p as usize),
9954 last_update_at: cx.background_executor().now(),
9955 },
9956 cx,
9957 ),
9958 lsp::WorkDoneProgress::End(_) => {
9959 language_server_status.progress_tokens.remove(&token);
9960 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9961 if is_disk_based_diagnostics_progress {
9962 self.disk_based_diagnostics_finished(language_server_id, cx);
9963 }
9964 }
9965 }
9966 }
9967
9968 fn on_lsp_work_start(
9969 &mut self,
9970 language_server_id: LanguageServerId,
9971 token: ProgressToken,
9972 progress: LanguageServerProgress,
9973 cx: &mut Context<Self>,
9974 ) {
9975 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9976 status.pending_work.insert(token.clone(), progress.clone());
9977 cx.notify();
9978 }
9979 cx.emit(LspStoreEvent::LanguageServerUpdate {
9980 language_server_id,
9981 name: self
9982 .language_server_adapter_for_id(language_server_id)
9983 .map(|adapter| adapter.name()),
9984 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9985 token: Some(token.to_proto()),
9986 title: progress.title,
9987 message: progress.message,
9988 percentage: progress.percentage.map(|p| p as u32),
9989 is_cancellable: Some(progress.is_cancellable),
9990 }),
9991 })
9992 }
9993
9994 fn on_lsp_work_progress(
9995 &mut self,
9996 language_server_id: LanguageServerId,
9997 token: ProgressToken,
9998 progress: LanguageServerProgress,
9999 cx: &mut Context<Self>,
10000 ) {
10001 let mut did_update = false;
10002 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10003 match status.pending_work.entry(token.clone()) {
10004 btree_map::Entry::Vacant(entry) => {
10005 entry.insert(progress.clone());
10006 did_update = true;
10007 }
10008 btree_map::Entry::Occupied(mut entry) => {
10009 let entry = entry.get_mut();
10010 if (progress.last_update_at - entry.last_update_at)
10011 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10012 {
10013 entry.last_update_at = progress.last_update_at;
10014 if progress.message.is_some() {
10015 entry.message = progress.message.clone();
10016 }
10017 if progress.percentage.is_some() {
10018 entry.percentage = progress.percentage;
10019 }
10020 if progress.is_cancellable != entry.is_cancellable {
10021 entry.is_cancellable = progress.is_cancellable;
10022 }
10023 did_update = true;
10024 }
10025 }
10026 }
10027 }
10028
10029 if did_update {
10030 cx.emit(LspStoreEvent::LanguageServerUpdate {
10031 language_server_id,
10032 name: self
10033 .language_server_adapter_for_id(language_server_id)
10034 .map(|adapter| adapter.name()),
10035 message: proto::update_language_server::Variant::WorkProgress(
10036 proto::LspWorkProgress {
10037 token: Some(token.to_proto()),
10038 message: progress.message,
10039 percentage: progress.percentage.map(|p| p as u32),
10040 is_cancellable: Some(progress.is_cancellable),
10041 },
10042 ),
10043 })
10044 }
10045 }
10046
10047 fn on_lsp_work_end(
10048 &mut self,
10049 language_server_id: LanguageServerId,
10050 token: ProgressToken,
10051 cx: &mut Context<Self>,
10052 ) {
10053 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10054 if let Some(work) = status.pending_work.remove(&token)
10055 && !work.is_disk_based_diagnostics_progress
10056 {
10057 cx.emit(LspStoreEvent::RefreshInlayHints {
10058 server_id: language_server_id,
10059 request_id: None,
10060 });
10061 }
10062 cx.notify();
10063 }
10064
10065 cx.emit(LspStoreEvent::LanguageServerUpdate {
10066 language_server_id,
10067 name: self
10068 .language_server_adapter_for_id(language_server_id)
10069 .map(|adapter| adapter.name()),
10070 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10071 token: Some(token.to_proto()),
10072 }),
10073 })
10074 }
10075
10076 pub async fn handle_resolve_completion_documentation(
10077 this: Entity<Self>,
10078 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10079 mut cx: AsyncApp,
10080 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10081 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10082
10083 let completion = this
10084 .read_with(&cx, |this, cx| {
10085 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10086 let server = this
10087 .language_server_for_id(id)
10088 .with_context(|| format!("No language server {id}"))?;
10089
10090 let request_timeout = ProjectSettings::get_global(cx)
10091 .global_lsp_settings
10092 .get_request_timeout();
10093
10094 anyhow::Ok(cx.background_spawn(async move {
10095 let can_resolve = server
10096 .capabilities()
10097 .completion_provider
10098 .as_ref()
10099 .and_then(|options| options.resolve_provider)
10100 .unwrap_or(false);
10101 if can_resolve {
10102 server
10103 .request::<lsp::request::ResolveCompletionItem>(
10104 lsp_completion,
10105 request_timeout,
10106 )
10107 .await
10108 .into_response()
10109 .context("resolve completion item")
10110 } else {
10111 anyhow::Ok(lsp_completion)
10112 }
10113 }))
10114 })?
10115 .await?;
10116
10117 let mut documentation_is_markdown = false;
10118 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10119 let documentation = match completion.documentation {
10120 Some(lsp::Documentation::String(text)) => text,
10121
10122 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10123 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10124 value
10125 }
10126
10127 _ => String::new(),
10128 };
10129
10130 // If we have a new buffer_id, that means we're talking to a new client
10131 // and want to check for new text_edits in the completion too.
10132 let mut old_replace_start = None;
10133 let mut old_replace_end = None;
10134 let mut old_insert_start = None;
10135 let mut old_insert_end = None;
10136 let mut new_text = String::default();
10137 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10138 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10139 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10140 anyhow::Ok(buffer.read(cx).snapshot())
10141 })?;
10142
10143 if let Some(text_edit) = completion.text_edit.as_ref() {
10144 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10145
10146 if let Some(mut edit) = edit {
10147 LineEnding::normalize(&mut edit.new_text);
10148
10149 new_text = edit.new_text;
10150 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10151 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10152 if let Some(insert_range) = edit.insert_range {
10153 old_insert_start = Some(serialize_anchor(&insert_range.start));
10154 old_insert_end = Some(serialize_anchor(&insert_range.end));
10155 }
10156 }
10157 }
10158 }
10159
10160 Ok(proto::ResolveCompletionDocumentationResponse {
10161 documentation,
10162 documentation_is_markdown,
10163 old_replace_start,
10164 old_replace_end,
10165 new_text,
10166 lsp_completion,
10167 old_insert_start,
10168 old_insert_end,
10169 })
10170 }
10171
10172 async fn handle_on_type_formatting(
10173 this: Entity<Self>,
10174 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10175 mut cx: AsyncApp,
10176 ) -> Result<proto::OnTypeFormattingResponse> {
10177 let on_type_formatting = this.update(&mut cx, |this, cx| {
10178 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10179 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10180 let position = envelope
10181 .payload
10182 .position
10183 .and_then(deserialize_anchor)
10184 .context("invalid position")?;
10185 anyhow::Ok(this.apply_on_type_formatting(
10186 buffer,
10187 position,
10188 envelope.payload.trigger.clone(),
10189 cx,
10190 ))
10191 })?;
10192
10193 let transaction = on_type_formatting
10194 .await?
10195 .as_ref()
10196 .map(language::proto::serialize_transaction);
10197 Ok(proto::OnTypeFormattingResponse { transaction })
10198 }
10199
10200 async fn handle_pull_workspace_diagnostics(
10201 lsp_store: Entity<Self>,
10202 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10203 mut cx: AsyncApp,
10204 ) -> Result<proto::Ack> {
10205 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10206 lsp_store.update(&mut cx, |lsp_store, _| {
10207 lsp_store.pull_workspace_diagnostics(server_id);
10208 });
10209 Ok(proto::Ack {})
10210 }
10211
10212 async fn handle_open_buffer_for_symbol(
10213 this: Entity<Self>,
10214 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10215 mut cx: AsyncApp,
10216 ) -> Result<proto::OpenBufferForSymbolResponse> {
10217 let peer_id = envelope.original_sender_id().unwrap_or_default();
10218 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10219 let symbol = Self::deserialize_symbol(symbol)?;
10220 this.read_with(&cx, |this, _| {
10221 if let SymbolLocation::OutsideProject {
10222 abs_path,
10223 signature,
10224 } = &symbol.path
10225 {
10226 let new_signature = this.symbol_signature(&abs_path);
10227 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10228 }
10229 Ok(())
10230 })?;
10231 let buffer = this
10232 .update(&mut cx, |this, cx| {
10233 this.open_buffer_for_symbol(
10234 &Symbol {
10235 language_server_name: symbol.language_server_name,
10236 source_worktree_id: symbol.source_worktree_id,
10237 source_language_server_id: symbol.source_language_server_id,
10238 path: symbol.path,
10239 name: symbol.name,
10240 kind: symbol.kind,
10241 range: symbol.range,
10242 label: CodeLabel::default(),
10243 container_name: symbol.container_name,
10244 },
10245 cx,
10246 )
10247 })
10248 .await?;
10249
10250 this.update(&mut cx, |this, cx| {
10251 let is_private = buffer
10252 .read(cx)
10253 .file()
10254 .map(|f| f.is_private())
10255 .unwrap_or_default();
10256 if is_private {
10257 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10258 } else {
10259 this.buffer_store
10260 .update(cx, |buffer_store, cx| {
10261 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10262 })
10263 .detach_and_log_err(cx);
10264 let buffer_id = buffer.read(cx).remote_id().to_proto();
10265 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10266 }
10267 })
10268 }
10269
10270 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10271 let mut hasher = Sha256::new();
10272 hasher.update(abs_path.to_string_lossy().as_bytes());
10273 hasher.update(self.nonce.to_be_bytes());
10274 hasher.finalize().as_slice().try_into().unwrap()
10275 }
10276
10277 pub async fn handle_get_project_symbols(
10278 this: Entity<Self>,
10279 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10280 mut cx: AsyncApp,
10281 ) -> Result<proto::GetProjectSymbolsResponse> {
10282 let symbols = this
10283 .update(&mut cx, |this, cx| {
10284 this.symbols(&envelope.payload.query, cx)
10285 })
10286 .await?;
10287
10288 Ok(proto::GetProjectSymbolsResponse {
10289 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10290 })
10291 }
10292
10293 pub async fn handle_restart_language_servers(
10294 this: Entity<Self>,
10295 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10296 mut cx: AsyncApp,
10297 ) -> Result<proto::Ack> {
10298 this.update(&mut cx, |lsp_store, cx| {
10299 let buffers =
10300 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10301 lsp_store.restart_language_servers_for_buffers(
10302 buffers,
10303 envelope
10304 .payload
10305 .only_servers
10306 .into_iter()
10307 .filter_map(|selector| {
10308 Some(match selector.selector? {
10309 proto::language_server_selector::Selector::ServerId(server_id) => {
10310 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10311 }
10312 proto::language_server_selector::Selector::Name(name) => {
10313 LanguageServerSelector::Name(LanguageServerName(
10314 SharedString::from(name),
10315 ))
10316 }
10317 })
10318 })
10319 .collect(),
10320 cx,
10321 );
10322 });
10323
10324 Ok(proto::Ack {})
10325 }
10326
10327 pub async fn handle_stop_language_servers(
10328 lsp_store: Entity<Self>,
10329 envelope: TypedEnvelope<proto::StopLanguageServers>,
10330 mut cx: AsyncApp,
10331 ) -> Result<proto::Ack> {
10332 lsp_store.update(&mut cx, |lsp_store, cx| {
10333 if envelope.payload.all
10334 && envelope.payload.also_servers.is_empty()
10335 && envelope.payload.buffer_ids.is_empty()
10336 {
10337 lsp_store.stop_all_language_servers(cx);
10338 } else {
10339 let buffers =
10340 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10341 lsp_store
10342 .stop_language_servers_for_buffers(
10343 buffers,
10344 envelope
10345 .payload
10346 .also_servers
10347 .into_iter()
10348 .filter_map(|selector| {
10349 Some(match selector.selector? {
10350 proto::language_server_selector::Selector::ServerId(
10351 server_id,
10352 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10353 server_id,
10354 )),
10355 proto::language_server_selector::Selector::Name(name) => {
10356 LanguageServerSelector::Name(LanguageServerName(
10357 SharedString::from(name),
10358 ))
10359 }
10360 })
10361 })
10362 .collect(),
10363 cx,
10364 )
10365 .detach_and_log_err(cx);
10366 }
10367 });
10368
10369 Ok(proto::Ack {})
10370 }
10371
10372 pub async fn handle_cancel_language_server_work(
10373 lsp_store: Entity<Self>,
10374 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10375 mut cx: AsyncApp,
10376 ) -> Result<proto::Ack> {
10377 lsp_store.update(&mut cx, |lsp_store, cx| {
10378 if let Some(work) = envelope.payload.work {
10379 match work {
10380 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10381 let buffers =
10382 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10383 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10384 }
10385 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10386 let server_id = LanguageServerId::from_proto(work.language_server_id);
10387 let token = work
10388 .token
10389 .map(|token| {
10390 ProgressToken::from_proto(token)
10391 .context("invalid work progress token")
10392 })
10393 .transpose()?;
10394 lsp_store.cancel_language_server_work(server_id, token, cx);
10395 }
10396 }
10397 }
10398 anyhow::Ok(())
10399 })?;
10400
10401 Ok(proto::Ack {})
10402 }
10403
10404 fn buffer_ids_to_buffers(
10405 &mut self,
10406 buffer_ids: impl Iterator<Item = u64>,
10407 cx: &mut Context<Self>,
10408 ) -> Vec<Entity<Buffer>> {
10409 buffer_ids
10410 .into_iter()
10411 .flat_map(|buffer_id| {
10412 self.buffer_store
10413 .read(cx)
10414 .get(BufferId::new(buffer_id).log_err()?)
10415 })
10416 .collect::<Vec<_>>()
10417 }
10418
10419 async fn handle_apply_additional_edits_for_completion(
10420 this: Entity<Self>,
10421 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10422 mut cx: AsyncApp,
10423 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10424 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10425 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10426 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10427 let completion = Self::deserialize_completion(
10428 envelope.payload.completion.context("invalid completion")?,
10429 )?;
10430 anyhow::Ok((buffer, completion))
10431 })?;
10432
10433 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10434 this.apply_additional_edits_for_completion(
10435 buffer,
10436 Rc::new(RefCell::new(Box::new([Completion {
10437 replace_range: completion.replace_range,
10438 new_text: completion.new_text,
10439 source: completion.source,
10440 documentation: None,
10441 label: CodeLabel::default(),
10442 match_start: None,
10443 snippet_deduplication_key: None,
10444 insert_text_mode: None,
10445 icon_path: None,
10446 confirm: None,
10447 }]))),
10448 0,
10449 false,
10450 cx,
10451 )
10452 });
10453
10454 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10455 transaction: apply_additional_edits
10456 .await?
10457 .as_ref()
10458 .map(language::proto::serialize_transaction),
10459 })
10460 }
10461
10462 pub fn last_formatting_failure(&self) -> Option<&str> {
10463 self.last_formatting_failure.as_deref()
10464 }
10465
10466 pub fn reset_last_formatting_failure(&mut self) {
10467 self.last_formatting_failure = None;
10468 }
10469
10470 pub fn environment_for_buffer(
10471 &self,
10472 buffer: &Entity<Buffer>,
10473 cx: &mut Context<Self>,
10474 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10475 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10476 environment.update(cx, |env, cx| {
10477 env.buffer_environment(buffer, &self.worktree_store, cx)
10478 })
10479 } else {
10480 Task::ready(None).shared()
10481 }
10482 }
10483
10484 pub fn format(
10485 &mut self,
10486 buffers: HashSet<Entity<Buffer>>,
10487 target: LspFormatTarget,
10488 push_to_history: bool,
10489 trigger: FormatTrigger,
10490 cx: &mut Context<Self>,
10491 ) -> Task<anyhow::Result<ProjectTransaction>> {
10492 let logger = zlog::scoped!("format");
10493 if self.as_local().is_some() {
10494 zlog::trace!(logger => "Formatting locally");
10495 let logger = zlog::scoped!(logger => "local");
10496 let buffers = buffers
10497 .into_iter()
10498 .map(|buffer_handle| {
10499 let buffer = buffer_handle.read(cx);
10500 let buffer_abs_path = File::from_dyn(buffer.file())
10501 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10502
10503 (buffer_handle, buffer_abs_path, buffer.remote_id())
10504 })
10505 .collect::<Vec<_>>();
10506
10507 cx.spawn(async move |lsp_store, cx| {
10508 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10509
10510 for (handle, abs_path, id) in buffers {
10511 let env = lsp_store
10512 .update(cx, |lsp_store, cx| {
10513 lsp_store.environment_for_buffer(&handle, cx)
10514 })?
10515 .await;
10516
10517 let ranges = match &target {
10518 LspFormatTarget::Buffers => None,
10519 LspFormatTarget::Ranges(ranges) => {
10520 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10521 }
10522 };
10523
10524 formattable_buffers.push(FormattableBuffer {
10525 handle,
10526 abs_path,
10527 env,
10528 ranges,
10529 });
10530 }
10531 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10532
10533 let format_timer = zlog::time!(logger => "Formatting buffers");
10534 let result = LocalLspStore::format_locally(
10535 lsp_store.clone(),
10536 formattable_buffers,
10537 push_to_history,
10538 trigger,
10539 logger,
10540 cx,
10541 )
10542 .await;
10543 format_timer.end();
10544
10545 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10546
10547 lsp_store.update(cx, |lsp_store, _| {
10548 lsp_store.update_last_formatting_failure(&result);
10549 })?;
10550
10551 result
10552 })
10553 } else if let Some((client, project_id)) = self.upstream_client() {
10554 zlog::trace!(logger => "Formatting remotely");
10555 let logger = zlog::scoped!(logger => "remote");
10556
10557 let buffer_ranges = match &target {
10558 LspFormatTarget::Buffers => Vec::new(),
10559 LspFormatTarget::Ranges(ranges) => ranges
10560 .iter()
10561 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10562 buffer_id: buffer_id.to_proto(),
10563 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10564 })
10565 .collect(),
10566 };
10567
10568 let buffer_store = self.buffer_store();
10569 cx.spawn(async move |lsp_store, cx| {
10570 zlog::trace!(logger => "Sending remote format request");
10571 let request_timer = zlog::time!(logger => "remote format request");
10572 let result = client
10573 .request(proto::FormatBuffers {
10574 project_id,
10575 trigger: trigger as i32,
10576 buffer_ids: buffers
10577 .iter()
10578 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10579 .collect(),
10580 buffer_ranges,
10581 })
10582 .await
10583 .and_then(|result| result.transaction.context("missing transaction"));
10584 request_timer.end();
10585
10586 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10587
10588 lsp_store.update(cx, |lsp_store, _| {
10589 lsp_store.update_last_formatting_failure(&result);
10590 })?;
10591
10592 let transaction_response = result?;
10593 let _timer = zlog::time!(logger => "deserializing project transaction");
10594 buffer_store
10595 .update(cx, |buffer_store, cx| {
10596 buffer_store.deserialize_project_transaction(
10597 transaction_response,
10598 push_to_history,
10599 cx,
10600 )
10601 })
10602 .await
10603 })
10604 } else {
10605 zlog::trace!(logger => "Not formatting");
10606 Task::ready(Ok(ProjectTransaction::default()))
10607 }
10608 }
10609
10610 async fn handle_format_buffers(
10611 this: Entity<Self>,
10612 envelope: TypedEnvelope<proto::FormatBuffers>,
10613 mut cx: AsyncApp,
10614 ) -> Result<proto::FormatBuffersResponse> {
10615 let sender_id = envelope.original_sender_id().unwrap_or_default();
10616 let format = this.update(&mut cx, |this, cx| {
10617 let mut buffers = HashSet::default();
10618 for buffer_id in &envelope.payload.buffer_ids {
10619 let buffer_id = BufferId::new(*buffer_id)?;
10620 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10621 }
10622
10623 let target = if envelope.payload.buffer_ranges.is_empty() {
10624 LspFormatTarget::Buffers
10625 } else {
10626 let mut ranges_map = BTreeMap::new();
10627 for buffer_range in &envelope.payload.buffer_ranges {
10628 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10629 let ranges: Result<Vec<_>> = buffer_range
10630 .ranges
10631 .iter()
10632 .map(|range| {
10633 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10634 })
10635 .collect();
10636 ranges_map.insert(buffer_id, ranges?);
10637 }
10638 LspFormatTarget::Ranges(ranges_map)
10639 };
10640
10641 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10642 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10643 })?;
10644
10645 let project_transaction = format.await?;
10646 let project_transaction = this.update(&mut cx, |this, cx| {
10647 this.buffer_store.update(cx, |buffer_store, cx| {
10648 buffer_store.serialize_project_transaction_for_peer(
10649 project_transaction,
10650 sender_id,
10651 cx,
10652 )
10653 })
10654 });
10655 Ok(proto::FormatBuffersResponse {
10656 transaction: Some(project_transaction),
10657 })
10658 }
10659
10660 async fn handle_apply_code_action_kind(
10661 this: Entity<Self>,
10662 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10663 mut cx: AsyncApp,
10664 ) -> Result<proto::ApplyCodeActionKindResponse> {
10665 let sender_id = envelope.original_sender_id().unwrap_or_default();
10666 let format = this.update(&mut cx, |this, cx| {
10667 let mut buffers = HashSet::default();
10668 for buffer_id in &envelope.payload.buffer_ids {
10669 let buffer_id = BufferId::new(*buffer_id)?;
10670 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10671 }
10672 let kind = match envelope.payload.kind.as_str() {
10673 "" => CodeActionKind::EMPTY,
10674 "quickfix" => CodeActionKind::QUICKFIX,
10675 "refactor" => CodeActionKind::REFACTOR,
10676 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10677 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10678 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10679 "source" => CodeActionKind::SOURCE,
10680 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10681 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10682 _ => anyhow::bail!(
10683 "Invalid code action kind {}",
10684 envelope.payload.kind.as_str()
10685 ),
10686 };
10687 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10688 })?;
10689
10690 let project_transaction = format.await?;
10691 let project_transaction = this.update(&mut cx, |this, cx| {
10692 this.buffer_store.update(cx, |buffer_store, cx| {
10693 buffer_store.serialize_project_transaction_for_peer(
10694 project_transaction,
10695 sender_id,
10696 cx,
10697 )
10698 })
10699 });
10700 Ok(proto::ApplyCodeActionKindResponse {
10701 transaction: Some(project_transaction),
10702 })
10703 }
10704
10705 async fn shutdown_language_server(
10706 server_state: Option<LanguageServerState>,
10707 name: LanguageServerName,
10708 cx: &mut AsyncApp,
10709 ) {
10710 let server = match server_state {
10711 Some(LanguageServerState::Starting { startup, .. }) => {
10712 let mut timer = cx
10713 .background_executor()
10714 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10715 .fuse();
10716
10717 select! {
10718 server = startup.fuse() => server,
10719 () = timer => {
10720 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10721 None
10722 },
10723 }
10724 }
10725
10726 Some(LanguageServerState::Running { server, .. }) => Some(server),
10727
10728 None => None,
10729 };
10730
10731 let Some(server) = server else { return };
10732 if let Some(shutdown) = server.shutdown() {
10733 shutdown.await;
10734 }
10735 }
10736
10737 // Returns a list of all of the worktrees which no longer have a language server and the root path
10738 // for the stopped server
10739 fn stop_local_language_server(
10740 &mut self,
10741 server_id: LanguageServerId,
10742 cx: &mut Context<Self>,
10743 ) -> Task<()> {
10744 let local = match &mut self.mode {
10745 LspStoreMode::Local(local) => local,
10746 _ => {
10747 return Task::ready(());
10748 }
10749 };
10750
10751 // Remove this server ID from all entries in the given worktree.
10752 local
10753 .language_server_ids
10754 .retain(|_, state| state.id != server_id);
10755 self.buffer_store.update(cx, |buffer_store, cx| {
10756 for buffer in buffer_store.buffers() {
10757 buffer.update(cx, |buffer, cx| {
10758 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10759 buffer.set_completion_triggers(server_id, Default::default(), cx);
10760 });
10761 }
10762 });
10763
10764 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10765 summaries.retain(|path, summaries_by_server_id| {
10766 if summaries_by_server_id.remove(&server_id).is_some() {
10767 if let Some((client, project_id)) = self.downstream_client.clone() {
10768 client
10769 .send(proto::UpdateDiagnosticSummary {
10770 project_id,
10771 worktree_id: worktree_id.to_proto(),
10772 summary: Some(proto::DiagnosticSummary {
10773 path: path.as_ref().to_proto(),
10774 language_server_id: server_id.0 as u64,
10775 error_count: 0,
10776 warning_count: 0,
10777 }),
10778 more_summaries: Vec::new(),
10779 })
10780 .log_err();
10781 }
10782 !summaries_by_server_id.is_empty()
10783 } else {
10784 true
10785 }
10786 });
10787 }
10788
10789 let local = self.as_local_mut().unwrap();
10790 for diagnostics in local.diagnostics.values_mut() {
10791 diagnostics.retain(|_, diagnostics_by_server_id| {
10792 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10793 diagnostics_by_server_id.remove(ix);
10794 !diagnostics_by_server_id.is_empty()
10795 } else {
10796 true
10797 }
10798 });
10799 }
10800 local.language_server_watched_paths.remove(&server_id);
10801
10802 let server_state = local.language_servers.remove(&server_id);
10803 self.cleanup_lsp_data(server_id);
10804 let name = self
10805 .language_server_statuses
10806 .remove(&server_id)
10807 .map(|status| status.name)
10808 .or_else(|| {
10809 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10810 Some(adapter.name())
10811 } else {
10812 None
10813 }
10814 });
10815
10816 if let Some(name) = name {
10817 log::info!("stopping language server {name}");
10818 self.languages
10819 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10820 cx.notify();
10821
10822 return cx.spawn(async move |lsp_store, cx| {
10823 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10824 lsp_store
10825 .update(cx, |lsp_store, cx| {
10826 lsp_store
10827 .languages
10828 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10829 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10830 cx.notify();
10831 })
10832 .ok();
10833 });
10834 }
10835
10836 if server_state.is_some() {
10837 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10838 }
10839 Task::ready(())
10840 }
10841
10842 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10843 self.shutdown_all_language_servers(cx).detach();
10844 }
10845
10846 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10847 if let Some((client, project_id)) = self.upstream_client() {
10848 let request = client.request(proto::StopLanguageServers {
10849 project_id,
10850 buffer_ids: Vec::new(),
10851 also_servers: Vec::new(),
10852 all: true,
10853 });
10854 cx.background_spawn(async move {
10855 request.await.ok();
10856 })
10857 } else {
10858 let Some(local) = self.as_local_mut() else {
10859 return Task::ready(());
10860 };
10861 let language_servers_to_stop = local
10862 .language_server_ids
10863 .values()
10864 .map(|state| state.id)
10865 .collect();
10866 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10867 let tasks = language_servers_to_stop
10868 .into_iter()
10869 .map(|server| self.stop_local_language_server(server, cx))
10870 .collect::<Vec<_>>();
10871 cx.background_spawn(async move {
10872 futures::future::join_all(tasks).await;
10873 })
10874 }
10875 }
10876
10877 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10878 let buffers = self.buffer_store.read(cx).buffers().collect();
10879 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10880 }
10881
10882 pub fn restart_language_servers_for_buffers(
10883 &mut self,
10884 buffers: Vec<Entity<Buffer>>,
10885 only_restart_servers: HashSet<LanguageServerSelector>,
10886 cx: &mut Context<Self>,
10887 ) {
10888 if let Some((client, project_id)) = self.upstream_client() {
10889 let request = client.request(proto::RestartLanguageServers {
10890 project_id,
10891 buffer_ids: buffers
10892 .into_iter()
10893 .map(|b| b.read(cx).remote_id().to_proto())
10894 .collect(),
10895 only_servers: only_restart_servers
10896 .into_iter()
10897 .map(|selector| {
10898 let selector = match selector {
10899 LanguageServerSelector::Id(language_server_id) => {
10900 proto::language_server_selector::Selector::ServerId(
10901 language_server_id.to_proto(),
10902 )
10903 }
10904 LanguageServerSelector::Name(language_server_name) => {
10905 proto::language_server_selector::Selector::Name(
10906 language_server_name.to_string(),
10907 )
10908 }
10909 };
10910 proto::LanguageServerSelector {
10911 selector: Some(selector),
10912 }
10913 })
10914 .collect(),
10915 all: false,
10916 });
10917 cx.background_spawn(request).detach_and_log_err(cx);
10918 } else {
10919 let stop_task = if only_restart_servers.is_empty() {
10920 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10921 } else {
10922 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10923 };
10924 cx.spawn(async move |lsp_store, cx| {
10925 stop_task.await;
10926 lsp_store.update(cx, |lsp_store, cx| {
10927 for buffer in buffers {
10928 lsp_store.register_buffer_with_language_servers(
10929 &buffer,
10930 only_restart_servers.clone(),
10931 true,
10932 cx,
10933 );
10934 }
10935 })
10936 })
10937 .detach();
10938 }
10939 }
10940
10941 pub fn stop_language_servers_for_buffers(
10942 &mut self,
10943 buffers: Vec<Entity<Buffer>>,
10944 also_stop_servers: HashSet<LanguageServerSelector>,
10945 cx: &mut Context<Self>,
10946 ) -> Task<Result<()>> {
10947 if let Some((client, project_id)) = self.upstream_client() {
10948 let request = client.request(proto::StopLanguageServers {
10949 project_id,
10950 buffer_ids: buffers
10951 .into_iter()
10952 .map(|b| b.read(cx).remote_id().to_proto())
10953 .collect(),
10954 also_servers: also_stop_servers
10955 .into_iter()
10956 .map(|selector| {
10957 let selector = match selector {
10958 LanguageServerSelector::Id(language_server_id) => {
10959 proto::language_server_selector::Selector::ServerId(
10960 language_server_id.to_proto(),
10961 )
10962 }
10963 LanguageServerSelector::Name(language_server_name) => {
10964 proto::language_server_selector::Selector::Name(
10965 language_server_name.to_string(),
10966 )
10967 }
10968 };
10969 proto::LanguageServerSelector {
10970 selector: Some(selector),
10971 }
10972 })
10973 .collect(),
10974 all: false,
10975 });
10976 cx.background_spawn(async move {
10977 let _ = request.await?;
10978 Ok(())
10979 })
10980 } else {
10981 let task =
10982 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10983 cx.background_spawn(async move {
10984 task.await;
10985 Ok(())
10986 })
10987 }
10988 }
10989
10990 fn stop_local_language_servers_for_buffers(
10991 &mut self,
10992 buffers: &[Entity<Buffer>],
10993 also_stop_servers: HashSet<LanguageServerSelector>,
10994 cx: &mut Context<Self>,
10995 ) -> Task<()> {
10996 let Some(local) = self.as_local_mut() else {
10997 return Task::ready(());
10998 };
10999 let mut language_server_names_to_stop = BTreeSet::default();
11000 let mut language_servers_to_stop = also_stop_servers
11001 .into_iter()
11002 .flat_map(|selector| match selector {
11003 LanguageServerSelector::Id(id) => Some(id),
11004 LanguageServerSelector::Name(name) => {
11005 language_server_names_to_stop.insert(name);
11006 None
11007 }
11008 })
11009 .collect::<BTreeSet<_>>();
11010
11011 let mut covered_worktrees = HashSet::default();
11012 for buffer in buffers {
11013 buffer.update(cx, |buffer, cx| {
11014 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11015 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11016 && covered_worktrees.insert(worktree_id)
11017 {
11018 language_server_names_to_stop.retain(|name| {
11019 let old_ids_count = language_servers_to_stop.len();
11020 let all_language_servers_with_this_name = local
11021 .language_server_ids
11022 .iter()
11023 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11024 language_servers_to_stop.extend(all_language_servers_with_this_name);
11025 old_ids_count == language_servers_to_stop.len()
11026 });
11027 }
11028 });
11029 }
11030 for name in language_server_names_to_stop {
11031 language_servers_to_stop.extend(
11032 local
11033 .language_server_ids
11034 .iter()
11035 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11036 );
11037 }
11038
11039 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11040 let tasks = language_servers_to_stop
11041 .into_iter()
11042 .map(|server| self.stop_local_language_server(server, cx))
11043 .collect::<Vec<_>>();
11044
11045 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11046 }
11047
11048 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11049 let (worktree, relative_path) =
11050 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11051
11052 let project_path = ProjectPath {
11053 worktree_id: worktree.read(cx).id(),
11054 path: relative_path,
11055 };
11056
11057 Some(
11058 self.buffer_store()
11059 .read(cx)
11060 .get_by_path(&project_path)?
11061 .read(cx),
11062 )
11063 }
11064
11065 #[cfg(any(test, feature = "test-support"))]
11066 pub fn update_diagnostics(
11067 &mut self,
11068 server_id: LanguageServerId,
11069 diagnostics: lsp::PublishDiagnosticsParams,
11070 result_id: Option<SharedString>,
11071 source_kind: DiagnosticSourceKind,
11072 disk_based_sources: &[String],
11073 cx: &mut Context<Self>,
11074 ) -> Result<()> {
11075 self.merge_lsp_diagnostics(
11076 source_kind,
11077 vec![DocumentDiagnosticsUpdate {
11078 diagnostics,
11079 result_id,
11080 server_id,
11081 disk_based_sources: Cow::Borrowed(disk_based_sources),
11082 registration_id: None,
11083 }],
11084 |_, _, _| false,
11085 cx,
11086 )
11087 }
11088
11089 pub fn merge_lsp_diagnostics(
11090 &mut self,
11091 source_kind: DiagnosticSourceKind,
11092 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11093 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11094 cx: &mut Context<Self>,
11095 ) -> Result<()> {
11096 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11097 let updates = lsp_diagnostics
11098 .into_iter()
11099 .filter_map(|update| {
11100 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11101 Some(DocumentDiagnosticsUpdate {
11102 diagnostics: self.lsp_to_document_diagnostics(
11103 abs_path,
11104 source_kind,
11105 update.server_id,
11106 update.diagnostics,
11107 &update.disk_based_sources,
11108 update.registration_id.clone(),
11109 ),
11110 result_id: update.result_id,
11111 server_id: update.server_id,
11112 disk_based_sources: update.disk_based_sources,
11113 registration_id: update.registration_id,
11114 })
11115 })
11116 .collect();
11117 self.merge_diagnostic_entries(updates, merge, cx)?;
11118 Ok(())
11119 }
11120
11121 fn lsp_to_document_diagnostics(
11122 &mut self,
11123 document_abs_path: PathBuf,
11124 source_kind: DiagnosticSourceKind,
11125 server_id: LanguageServerId,
11126 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11127 disk_based_sources: &[String],
11128 registration_id: Option<SharedString>,
11129 ) -> DocumentDiagnostics {
11130 let mut diagnostics = Vec::default();
11131 let mut primary_diagnostic_group_ids = HashMap::default();
11132 let mut sources_by_group_id = HashMap::default();
11133 let mut supporting_diagnostics = HashMap::default();
11134
11135 let adapter = self.language_server_adapter_for_id(server_id);
11136
11137 // Ensure that primary diagnostics are always the most severe
11138 lsp_diagnostics
11139 .diagnostics
11140 .sort_by_key(|item| item.severity);
11141
11142 for diagnostic in &lsp_diagnostics.diagnostics {
11143 let source = diagnostic.source.as_ref();
11144 let range = range_from_lsp(diagnostic.range);
11145 let is_supporting = diagnostic
11146 .related_information
11147 .as_ref()
11148 .is_some_and(|infos| {
11149 infos.iter().any(|info| {
11150 primary_diagnostic_group_ids.contains_key(&(
11151 source,
11152 diagnostic.code.clone(),
11153 range_from_lsp(info.location.range),
11154 ))
11155 })
11156 });
11157
11158 let is_unnecessary = diagnostic
11159 .tags
11160 .as_ref()
11161 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11162
11163 let underline = self
11164 .language_server_adapter_for_id(server_id)
11165 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11166
11167 if is_supporting {
11168 supporting_diagnostics.insert(
11169 (source, diagnostic.code.clone(), range),
11170 (diagnostic.severity, is_unnecessary),
11171 );
11172 } else {
11173 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11174 let is_disk_based =
11175 source.is_some_and(|source| disk_based_sources.contains(source));
11176
11177 sources_by_group_id.insert(group_id, source);
11178 primary_diagnostic_group_ids
11179 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11180
11181 diagnostics.push(DiagnosticEntry {
11182 range,
11183 diagnostic: Diagnostic {
11184 source: diagnostic.source.clone(),
11185 source_kind,
11186 code: diagnostic.code.clone(),
11187 code_description: diagnostic
11188 .code_description
11189 .as_ref()
11190 .and_then(|d| d.href.clone()),
11191 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11192 markdown: adapter.as_ref().and_then(|adapter| {
11193 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11194 }),
11195 message: diagnostic.message.trim().to_string(),
11196 group_id,
11197 is_primary: true,
11198 is_disk_based,
11199 is_unnecessary,
11200 underline,
11201 data: diagnostic.data.clone(),
11202 registration_id: registration_id.clone(),
11203 },
11204 });
11205 if let Some(infos) = &diagnostic.related_information {
11206 for info in infos {
11207 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11208 let range = range_from_lsp(info.location.range);
11209 diagnostics.push(DiagnosticEntry {
11210 range,
11211 diagnostic: Diagnostic {
11212 source: diagnostic.source.clone(),
11213 source_kind,
11214 code: diagnostic.code.clone(),
11215 code_description: diagnostic
11216 .code_description
11217 .as_ref()
11218 .and_then(|d| d.href.clone()),
11219 severity: DiagnosticSeverity::INFORMATION,
11220 markdown: adapter.as_ref().and_then(|adapter| {
11221 adapter.diagnostic_message_to_markdown(&info.message)
11222 }),
11223 message: info.message.trim().to_string(),
11224 group_id,
11225 is_primary: false,
11226 is_disk_based,
11227 is_unnecessary: false,
11228 underline,
11229 data: diagnostic.data.clone(),
11230 registration_id: registration_id.clone(),
11231 },
11232 });
11233 }
11234 }
11235 }
11236 }
11237 }
11238
11239 for entry in &mut diagnostics {
11240 let diagnostic = &mut entry.diagnostic;
11241 if !diagnostic.is_primary {
11242 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11243 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11244 source,
11245 diagnostic.code.clone(),
11246 entry.range.clone(),
11247 )) {
11248 if let Some(severity) = severity {
11249 diagnostic.severity = severity;
11250 }
11251 diagnostic.is_unnecessary = is_unnecessary;
11252 }
11253 }
11254 }
11255
11256 DocumentDiagnostics {
11257 diagnostics,
11258 document_abs_path,
11259 version: lsp_diagnostics.version,
11260 }
11261 }
11262
11263 fn insert_newly_running_language_server(
11264 &mut self,
11265 adapter: Arc<CachedLspAdapter>,
11266 language_server: Arc<LanguageServer>,
11267 server_id: LanguageServerId,
11268 key: LanguageServerSeed,
11269 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11270 cx: &mut Context<Self>,
11271 ) {
11272 let Some(local) = self.as_local_mut() else {
11273 return;
11274 };
11275 // If the language server for this key doesn't match the server id, don't store the
11276 // server. Which will cause it to be dropped, killing the process
11277 if local
11278 .language_server_ids
11279 .get(&key)
11280 .map(|state| state.id != server_id)
11281 .unwrap_or(false)
11282 {
11283 return;
11284 }
11285
11286 // Update language_servers collection with Running variant of LanguageServerState
11287 // indicating that the server is up and running and ready
11288 let workspace_folders = workspace_folders.lock().clone();
11289 language_server.set_workspace_folders(workspace_folders);
11290
11291 let workspace_diagnostics_refresh_tasks = language_server
11292 .capabilities()
11293 .diagnostic_provider
11294 .and_then(|provider| {
11295 local
11296 .language_server_dynamic_registrations
11297 .entry(server_id)
11298 .or_default()
11299 .diagnostics
11300 .entry(None)
11301 .or_insert(provider.clone());
11302 let workspace_refresher =
11303 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11304
11305 Some((None, workspace_refresher))
11306 })
11307 .into_iter()
11308 .collect();
11309 local.language_servers.insert(
11310 server_id,
11311 LanguageServerState::Running {
11312 workspace_diagnostics_refresh_tasks,
11313 adapter: adapter.clone(),
11314 server: language_server.clone(),
11315 simulate_disk_based_diagnostics_completion: None,
11316 },
11317 );
11318 local
11319 .languages
11320 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11321 if let Some(file_ops_caps) = language_server
11322 .capabilities()
11323 .workspace
11324 .as_ref()
11325 .and_then(|ws| ws.file_operations.as_ref())
11326 {
11327 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11328 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11329 if did_rename_caps.or(will_rename_caps).is_some() {
11330 let watcher = RenamePathsWatchedForServer::default()
11331 .with_did_rename_patterns(did_rename_caps)
11332 .with_will_rename_patterns(will_rename_caps);
11333 local
11334 .language_server_paths_watched_for_rename
11335 .insert(server_id, watcher);
11336 }
11337 }
11338
11339 self.language_server_statuses.insert(
11340 server_id,
11341 LanguageServerStatus {
11342 name: language_server.name(),
11343 server_version: language_server.version(),
11344 pending_work: Default::default(),
11345 has_pending_diagnostic_updates: false,
11346 progress_tokens: Default::default(),
11347 worktree: Some(key.worktree_id),
11348 binary: Some(language_server.binary().clone()),
11349 configuration: Some(language_server.configuration().clone()),
11350 workspace_folders: language_server.workspace_folders(),
11351 process_id: language_server.process_id(),
11352 },
11353 );
11354
11355 cx.emit(LspStoreEvent::LanguageServerAdded(
11356 server_id,
11357 language_server.name(),
11358 Some(key.worktree_id),
11359 ));
11360
11361 let server_capabilities = language_server.capabilities();
11362 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11363 downstream_client
11364 .send(proto::StartLanguageServer {
11365 project_id: *project_id,
11366 server: Some(proto::LanguageServer {
11367 id: server_id.to_proto(),
11368 name: language_server.name().to_string(),
11369 worktree_id: Some(key.worktree_id.to_proto()),
11370 }),
11371 capabilities: serde_json::to_string(&server_capabilities)
11372 .expect("serializing server LSP capabilities"),
11373 })
11374 .log_err();
11375 }
11376 self.lsp_server_capabilities
11377 .insert(server_id, server_capabilities);
11378
11379 // Tell the language server about every open buffer in the worktree that matches the language.
11380 // Also check for buffers in worktrees that reused this server
11381 let mut worktrees_using_server = vec![key.worktree_id];
11382 if let Some(local) = self.as_local() {
11383 // Find all worktrees that have this server in their language server tree
11384 for (worktree_id, servers) in &local.lsp_tree.instances {
11385 if *worktree_id != key.worktree_id {
11386 for server_map in servers.roots.values() {
11387 if server_map
11388 .values()
11389 .any(|(node, _)| node.id() == Some(server_id))
11390 {
11391 worktrees_using_server.push(*worktree_id);
11392 }
11393 }
11394 }
11395 }
11396 }
11397
11398 let mut buffer_paths_registered = Vec::new();
11399 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11400 let mut lsp_adapters = HashMap::default();
11401 for buffer_handle in buffer_store.buffers() {
11402 let buffer = buffer_handle.read(cx);
11403 let file = match File::from_dyn(buffer.file()) {
11404 Some(file) => file,
11405 None => continue,
11406 };
11407 let language = match buffer.language() {
11408 Some(language) => language,
11409 None => continue,
11410 };
11411
11412 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11413 || !lsp_adapters
11414 .entry(language.name())
11415 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11416 .iter()
11417 .any(|a| a.name == key.name)
11418 {
11419 continue;
11420 }
11421 // didOpen
11422 let file = match file.as_local() {
11423 Some(file) => file,
11424 None => continue,
11425 };
11426
11427 let local = self.as_local_mut().unwrap();
11428
11429 let buffer_id = buffer.remote_id();
11430 if local.registered_buffers.contains_key(&buffer_id) {
11431 let abs_path = file.abs_path(cx);
11432 let uri = match lsp::Uri::from_file_path(&abs_path) {
11433 Ok(uri) => uri,
11434 Err(()) => {
11435 log::error!("failed to convert path to URI: {:?}", abs_path);
11436 continue;
11437 }
11438 };
11439
11440 let versions = local
11441 .buffer_snapshots
11442 .entry(buffer_id)
11443 .or_default()
11444 .entry(server_id)
11445 .and_modify(|_| {
11446 assert!(
11447 false,
11448 "There should not be an existing snapshot for a newly inserted buffer"
11449 )
11450 })
11451 .or_insert_with(|| {
11452 vec![LspBufferSnapshot {
11453 version: 0,
11454 snapshot: buffer.text_snapshot(),
11455 }]
11456 });
11457
11458 let snapshot = versions.last().unwrap();
11459 let version = snapshot.version;
11460 let initial_snapshot = &snapshot.snapshot;
11461 language_server.register_buffer(
11462 uri,
11463 adapter.language_id(&language.name()),
11464 version,
11465 initial_snapshot.text(),
11466 );
11467 buffer_paths_registered.push((buffer_id, abs_path));
11468 local
11469 .buffers_opened_in_servers
11470 .entry(buffer_id)
11471 .or_default()
11472 .insert(server_id);
11473 }
11474 buffer_handle.update(cx, |buffer, cx| {
11475 buffer.set_completion_triggers(
11476 server_id,
11477 language_server
11478 .capabilities()
11479 .completion_provider
11480 .as_ref()
11481 .and_then(|provider| {
11482 provider
11483 .trigger_characters
11484 .as_ref()
11485 .map(|characters| characters.iter().cloned().collect())
11486 })
11487 .unwrap_or_default(),
11488 cx,
11489 )
11490 });
11491 }
11492 });
11493
11494 for (buffer_id, abs_path) in buffer_paths_registered {
11495 cx.emit(LspStoreEvent::LanguageServerUpdate {
11496 language_server_id: server_id,
11497 name: Some(adapter.name()),
11498 message: proto::update_language_server::Variant::RegisteredForBuffer(
11499 proto::RegisteredForBuffer {
11500 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11501 buffer_id: buffer_id.to_proto(),
11502 },
11503 ),
11504 });
11505 }
11506
11507 cx.notify();
11508 }
11509
11510 pub fn language_servers_running_disk_based_diagnostics(
11511 &self,
11512 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11513 self.language_server_statuses
11514 .iter()
11515 .filter_map(|(id, status)| {
11516 if status.has_pending_diagnostic_updates {
11517 Some(*id)
11518 } else {
11519 None
11520 }
11521 })
11522 }
11523
11524 pub(crate) fn cancel_language_server_work_for_buffers(
11525 &mut self,
11526 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11527 cx: &mut Context<Self>,
11528 ) {
11529 if let Some((client, project_id)) = self.upstream_client() {
11530 let request = client.request(proto::CancelLanguageServerWork {
11531 project_id,
11532 work: Some(proto::cancel_language_server_work::Work::Buffers(
11533 proto::cancel_language_server_work::Buffers {
11534 buffer_ids: buffers
11535 .into_iter()
11536 .map(|b| b.read(cx).remote_id().to_proto())
11537 .collect(),
11538 },
11539 )),
11540 });
11541 cx.background_spawn(request).detach_and_log_err(cx);
11542 } else if let Some(local) = self.as_local() {
11543 let servers = buffers
11544 .into_iter()
11545 .flat_map(|buffer| {
11546 buffer.update(cx, |buffer, cx| {
11547 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11548 })
11549 })
11550 .collect::<HashSet<_>>();
11551 for server_id in servers {
11552 self.cancel_language_server_work(server_id, None, cx);
11553 }
11554 }
11555 }
11556
11557 pub(crate) fn cancel_language_server_work(
11558 &mut self,
11559 server_id: LanguageServerId,
11560 token_to_cancel: Option<ProgressToken>,
11561 cx: &mut Context<Self>,
11562 ) {
11563 if let Some(local) = self.as_local() {
11564 let status = self.language_server_statuses.get(&server_id);
11565 let server = local.language_servers.get(&server_id);
11566 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11567 {
11568 for (token, progress) in &status.pending_work {
11569 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11570 && token != token_to_cancel
11571 {
11572 continue;
11573 }
11574 if progress.is_cancellable {
11575 server
11576 .notify::<lsp::notification::WorkDoneProgressCancel>(
11577 WorkDoneProgressCancelParams {
11578 token: token.to_lsp(),
11579 },
11580 )
11581 .ok();
11582 }
11583 }
11584 }
11585 } else if let Some((client, project_id)) = self.upstream_client() {
11586 let request = client.request(proto::CancelLanguageServerWork {
11587 project_id,
11588 work: Some(
11589 proto::cancel_language_server_work::Work::LanguageServerWork(
11590 proto::cancel_language_server_work::LanguageServerWork {
11591 language_server_id: server_id.to_proto(),
11592 token: token_to_cancel.map(|token| token.to_proto()),
11593 },
11594 ),
11595 ),
11596 });
11597 cx.background_spawn(request).detach_and_log_err(cx);
11598 }
11599 }
11600
11601 fn register_supplementary_language_server(
11602 &mut self,
11603 id: LanguageServerId,
11604 name: LanguageServerName,
11605 server: Arc<LanguageServer>,
11606 cx: &mut Context<Self>,
11607 ) {
11608 if let Some(local) = self.as_local_mut() {
11609 local
11610 .supplementary_language_servers
11611 .insert(id, (name.clone(), server));
11612 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11613 }
11614 }
11615
11616 fn unregister_supplementary_language_server(
11617 &mut self,
11618 id: LanguageServerId,
11619 cx: &mut Context<Self>,
11620 ) {
11621 if let Some(local) = self.as_local_mut() {
11622 local.supplementary_language_servers.remove(&id);
11623 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11624 }
11625 }
11626
11627 pub(crate) fn supplementary_language_servers(
11628 &self,
11629 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11630 self.as_local().into_iter().flat_map(|local| {
11631 local
11632 .supplementary_language_servers
11633 .iter()
11634 .map(|(id, (name, _))| (*id, name.clone()))
11635 })
11636 }
11637
11638 pub fn language_server_adapter_for_id(
11639 &self,
11640 id: LanguageServerId,
11641 ) -> Option<Arc<CachedLspAdapter>> {
11642 self.as_local()
11643 .and_then(|local| local.language_servers.get(&id))
11644 .and_then(|language_server_state| match language_server_state {
11645 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11646 _ => None,
11647 })
11648 }
11649
11650 pub(super) fn update_local_worktree_language_servers(
11651 &mut self,
11652 worktree_handle: &Entity<Worktree>,
11653 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11654 cx: &mut Context<Self>,
11655 ) {
11656 if changes.is_empty() {
11657 return;
11658 }
11659
11660 let Some(local) = self.as_local() else { return };
11661
11662 local.prettier_store.update(cx, |prettier_store, cx| {
11663 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11664 });
11665
11666 let worktree_id = worktree_handle.read(cx).id();
11667 let mut language_server_ids = local
11668 .language_server_ids
11669 .iter()
11670 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11671 .collect::<Vec<_>>();
11672 language_server_ids.sort();
11673 language_server_ids.dedup();
11674
11675 // let abs_path = worktree_handle.read(cx).abs_path();
11676 for server_id in &language_server_ids {
11677 if let Some(LanguageServerState::Running { server, .. }) =
11678 local.language_servers.get(server_id)
11679 && let Some(watched_paths) = local
11680 .language_server_watched_paths
11681 .get(server_id)
11682 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11683 {
11684 let params = lsp::DidChangeWatchedFilesParams {
11685 changes: changes
11686 .iter()
11687 .filter_map(|(path, _, change)| {
11688 if !watched_paths.is_match(path.as_std_path()) {
11689 return None;
11690 }
11691 let typ = match change {
11692 PathChange::Loaded => return None,
11693 PathChange::Added => lsp::FileChangeType::CREATED,
11694 PathChange::Removed => lsp::FileChangeType::DELETED,
11695 PathChange::Updated => lsp::FileChangeType::CHANGED,
11696 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11697 };
11698 let uri = lsp::Uri::from_file_path(
11699 worktree_handle.read(cx).absolutize(&path),
11700 )
11701 .ok()?;
11702 Some(lsp::FileEvent { uri, typ })
11703 })
11704 .collect(),
11705 };
11706 if !params.changes.is_empty() {
11707 server
11708 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11709 .ok();
11710 }
11711 }
11712 }
11713 for (path, _, _) in changes {
11714 if let Some(file_name) = path.file_name()
11715 && local.watched_manifest_filenames.contains(file_name)
11716 {
11717 self.request_workspace_config_refresh();
11718 break;
11719 }
11720 }
11721 }
11722
11723 pub fn wait_for_remote_buffer(
11724 &mut self,
11725 id: BufferId,
11726 cx: &mut Context<Self>,
11727 ) -> Task<Result<Entity<Buffer>>> {
11728 self.buffer_store.update(cx, |buffer_store, cx| {
11729 buffer_store.wait_for_remote_buffer(id, cx)
11730 })
11731 }
11732
11733 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11734 let mut result = proto::Symbol {
11735 language_server_name: symbol.language_server_name.0.to_string(),
11736 source_worktree_id: symbol.source_worktree_id.to_proto(),
11737 language_server_id: symbol.source_language_server_id.to_proto(),
11738 name: symbol.name.clone(),
11739 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11740 start: Some(proto::PointUtf16 {
11741 row: symbol.range.start.0.row,
11742 column: symbol.range.start.0.column,
11743 }),
11744 end: Some(proto::PointUtf16 {
11745 row: symbol.range.end.0.row,
11746 column: symbol.range.end.0.column,
11747 }),
11748 worktree_id: Default::default(),
11749 path: Default::default(),
11750 signature: Default::default(),
11751 container_name: symbol.container_name.clone(),
11752 };
11753 match &symbol.path {
11754 SymbolLocation::InProject(path) => {
11755 result.worktree_id = path.worktree_id.to_proto();
11756 result.path = path.path.to_proto();
11757 }
11758 SymbolLocation::OutsideProject {
11759 abs_path,
11760 signature,
11761 } => {
11762 result.path = abs_path.to_string_lossy().into_owned();
11763 result.signature = signature.to_vec();
11764 }
11765 }
11766 result
11767 }
11768
11769 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11770 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11771 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11772 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11773
11774 let path = if serialized_symbol.signature.is_empty() {
11775 SymbolLocation::InProject(ProjectPath {
11776 worktree_id,
11777 path: RelPath::from_proto(&serialized_symbol.path)
11778 .context("invalid symbol path")?,
11779 })
11780 } else {
11781 SymbolLocation::OutsideProject {
11782 abs_path: Path::new(&serialized_symbol.path).into(),
11783 signature: serialized_symbol
11784 .signature
11785 .try_into()
11786 .map_err(|_| anyhow!("invalid signature"))?,
11787 }
11788 };
11789
11790 let start = serialized_symbol.start.context("invalid start")?;
11791 let end = serialized_symbol.end.context("invalid end")?;
11792 Ok(CoreSymbol {
11793 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11794 source_worktree_id,
11795 source_language_server_id: LanguageServerId::from_proto(
11796 serialized_symbol.language_server_id,
11797 ),
11798 path,
11799 name: serialized_symbol.name,
11800 range: Unclipped(PointUtf16::new(start.row, start.column))
11801 ..Unclipped(PointUtf16::new(end.row, end.column)),
11802 kind,
11803 container_name: serialized_symbol.container_name,
11804 })
11805 }
11806
11807 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11808 let mut serialized_completion = proto::Completion {
11809 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11810 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11811 new_text: completion.new_text.clone(),
11812 ..proto::Completion::default()
11813 };
11814 match &completion.source {
11815 CompletionSource::Lsp {
11816 insert_range,
11817 server_id,
11818 lsp_completion,
11819 lsp_defaults,
11820 resolved,
11821 } => {
11822 let (old_insert_start, old_insert_end) = insert_range
11823 .as_ref()
11824 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11825 .unzip();
11826
11827 serialized_completion.old_insert_start = old_insert_start;
11828 serialized_completion.old_insert_end = old_insert_end;
11829 serialized_completion.source = proto::completion::Source::Lsp as i32;
11830 serialized_completion.server_id = server_id.0 as u64;
11831 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11832 serialized_completion.lsp_defaults = lsp_defaults
11833 .as_deref()
11834 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11835 serialized_completion.resolved = *resolved;
11836 }
11837 CompletionSource::BufferWord {
11838 word_range,
11839 resolved,
11840 } => {
11841 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11842 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11843 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11844 serialized_completion.resolved = *resolved;
11845 }
11846 CompletionSource::Custom => {
11847 serialized_completion.source = proto::completion::Source::Custom as i32;
11848 serialized_completion.resolved = true;
11849 }
11850 CompletionSource::Dap { sort_text } => {
11851 serialized_completion.source = proto::completion::Source::Dap as i32;
11852 serialized_completion.sort_text = Some(sort_text.clone());
11853 }
11854 }
11855
11856 serialized_completion
11857 }
11858
11859 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11860 let old_replace_start = completion
11861 .old_replace_start
11862 .and_then(deserialize_anchor)
11863 .context("invalid old start")?;
11864 let old_replace_end = completion
11865 .old_replace_end
11866 .and_then(deserialize_anchor)
11867 .context("invalid old end")?;
11868 let insert_range = {
11869 match completion.old_insert_start.zip(completion.old_insert_end) {
11870 Some((start, end)) => {
11871 let start = deserialize_anchor(start).context("invalid insert old start")?;
11872 let end = deserialize_anchor(end).context("invalid insert old end")?;
11873 Some(start..end)
11874 }
11875 None => None,
11876 }
11877 };
11878 Ok(CoreCompletion {
11879 replace_range: old_replace_start..old_replace_end,
11880 new_text: completion.new_text,
11881 source: match proto::completion::Source::from_i32(completion.source) {
11882 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11883 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11884 insert_range,
11885 server_id: LanguageServerId::from_proto(completion.server_id),
11886 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11887 lsp_defaults: completion
11888 .lsp_defaults
11889 .as_deref()
11890 .map(serde_json::from_slice)
11891 .transpose()?,
11892 resolved: completion.resolved,
11893 },
11894 Some(proto::completion::Source::BufferWord) => {
11895 let word_range = completion
11896 .buffer_word_start
11897 .and_then(deserialize_anchor)
11898 .context("invalid buffer word start")?
11899 ..completion
11900 .buffer_word_end
11901 .and_then(deserialize_anchor)
11902 .context("invalid buffer word end")?;
11903 CompletionSource::BufferWord {
11904 word_range,
11905 resolved: completion.resolved,
11906 }
11907 }
11908 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11909 sort_text: completion
11910 .sort_text
11911 .context("expected sort text to exist")?,
11912 },
11913 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11914 },
11915 })
11916 }
11917
11918 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11919 let (kind, lsp_action) = match &action.lsp_action {
11920 LspAction::Action(code_action) => (
11921 proto::code_action::Kind::Action as i32,
11922 serde_json::to_vec(code_action).unwrap(),
11923 ),
11924 LspAction::Command(command) => (
11925 proto::code_action::Kind::Command as i32,
11926 serde_json::to_vec(command).unwrap(),
11927 ),
11928 LspAction::CodeLens(code_lens) => (
11929 proto::code_action::Kind::CodeLens as i32,
11930 serde_json::to_vec(code_lens).unwrap(),
11931 ),
11932 };
11933
11934 proto::CodeAction {
11935 server_id: action.server_id.0 as u64,
11936 start: Some(serialize_anchor(&action.range.start)),
11937 end: Some(serialize_anchor(&action.range.end)),
11938 lsp_action,
11939 kind,
11940 resolved: action.resolved,
11941 }
11942 }
11943
11944 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11945 let start = action
11946 .start
11947 .and_then(deserialize_anchor)
11948 .context("invalid start")?;
11949 let end = action
11950 .end
11951 .and_then(deserialize_anchor)
11952 .context("invalid end")?;
11953 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11954 Some(proto::code_action::Kind::Action) => {
11955 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11956 }
11957 Some(proto::code_action::Kind::Command) => {
11958 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11959 }
11960 Some(proto::code_action::Kind::CodeLens) => {
11961 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11962 }
11963 None => anyhow::bail!("Unknown action kind {}", action.kind),
11964 };
11965 Ok(CodeAction {
11966 server_id: LanguageServerId(action.server_id as usize),
11967 range: start..end,
11968 resolved: action.resolved,
11969 lsp_action,
11970 })
11971 }
11972
11973 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11974 match &formatting_result {
11975 Ok(_) => self.last_formatting_failure = None,
11976 Err(error) => {
11977 let error_string = format!("{error:#}");
11978 log::error!("Formatting failed: {error_string}");
11979 self.last_formatting_failure
11980 .replace(error_string.lines().join(" "));
11981 }
11982 }
11983 }
11984
11985 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11986 self.lsp_server_capabilities.remove(&for_server);
11987 self.semantic_token_config.remove_server_data(for_server);
11988 for lsp_data in self.lsp_data.values_mut() {
11989 lsp_data.remove_server_data(for_server);
11990 }
11991 if let Some(local) = self.as_local_mut() {
11992 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11993 local
11994 .workspace_pull_diagnostics_result_ids
11995 .remove(&for_server);
11996 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11997 buffer_servers.remove(&for_server);
11998 }
11999 }
12000 }
12001
12002 pub fn result_id_for_buffer_pull(
12003 &self,
12004 server_id: LanguageServerId,
12005 buffer_id: BufferId,
12006 registration_id: &Option<SharedString>,
12007 cx: &App,
12008 ) -> Option<SharedString> {
12009 let abs_path = self
12010 .buffer_store
12011 .read(cx)
12012 .get(buffer_id)
12013 .and_then(|b| File::from_dyn(b.read(cx).file()))
12014 .map(|f| f.abs_path(cx))?;
12015 self.as_local()?
12016 .buffer_pull_diagnostics_result_ids
12017 .get(&server_id)?
12018 .get(registration_id)?
12019 .get(&abs_path)?
12020 .clone()
12021 }
12022
12023 /// Gets all result_ids for a workspace diagnostics pull request.
12024 /// 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.
12025 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12026 pub fn result_ids_for_workspace_refresh(
12027 &self,
12028 server_id: LanguageServerId,
12029 registration_id: &Option<SharedString>,
12030 ) -> HashMap<PathBuf, SharedString> {
12031 let Some(local) = self.as_local() else {
12032 return HashMap::default();
12033 };
12034 local
12035 .workspace_pull_diagnostics_result_ids
12036 .get(&server_id)
12037 .into_iter()
12038 .filter_map(|diagnostics| diagnostics.get(registration_id))
12039 .flatten()
12040 .filter_map(|(abs_path, result_id)| {
12041 let result_id = local
12042 .buffer_pull_diagnostics_result_ids
12043 .get(&server_id)
12044 .and_then(|buffer_ids_result_ids| {
12045 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12046 })
12047 .cloned()
12048 .flatten()
12049 .or_else(|| result_id.clone())?;
12050 Some((abs_path.clone(), result_id))
12051 })
12052 .collect()
12053 }
12054
12055 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12056 if let Some(LanguageServerState::Running {
12057 workspace_diagnostics_refresh_tasks,
12058 ..
12059 }) = self
12060 .as_local_mut()
12061 .and_then(|local| local.language_servers.get_mut(&server_id))
12062 {
12063 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12064 diagnostics.refresh_tx.try_send(()).ok();
12065 }
12066 }
12067 }
12068
12069 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12070 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12071 /// which requires refreshing both workspace and document diagnostics.
12072 pub fn pull_document_diagnostics_for_server(
12073 &mut self,
12074 server_id: LanguageServerId,
12075 source_buffer_id: Option<BufferId>,
12076 cx: &mut Context<Self>,
12077 ) -> Shared<Task<()>> {
12078 let Some(local) = self.as_local_mut() else {
12079 return Task::ready(()).shared();
12080 };
12081 let mut buffers_to_refresh = HashSet::default();
12082 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12083 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12084 buffers_to_refresh.insert(*buffer_id);
12085 }
12086 }
12087
12088 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12089 }
12090
12091 pub fn pull_document_diagnostics_for_buffer_edit(
12092 &mut self,
12093 buffer_id: BufferId,
12094 cx: &mut Context<Self>,
12095 ) {
12096 let Some(local) = self.as_local_mut() else {
12097 return;
12098 };
12099 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12100 else {
12101 return;
12102 };
12103 for server_id in languages_servers {
12104 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12105 }
12106 }
12107
12108 fn apply_workspace_diagnostic_report(
12109 &mut self,
12110 server_id: LanguageServerId,
12111 report: lsp::WorkspaceDiagnosticReportResult,
12112 registration_id: Option<SharedString>,
12113 cx: &mut Context<Self>,
12114 ) {
12115 let mut workspace_diagnostics =
12116 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12117 report,
12118 server_id,
12119 registration_id,
12120 );
12121 workspace_diagnostics.retain(|d| match &d.diagnostics {
12122 LspPullDiagnostics::Response {
12123 server_id,
12124 registration_id,
12125 ..
12126 } => self.diagnostic_registration_exists(*server_id, registration_id),
12127 LspPullDiagnostics::Default => false,
12128 });
12129 let mut unchanged_buffers = HashMap::default();
12130 let workspace_diagnostics_updates = workspace_diagnostics
12131 .into_iter()
12132 .filter_map(
12133 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12134 LspPullDiagnostics::Response {
12135 server_id,
12136 uri,
12137 diagnostics,
12138 registration_id,
12139 } => Some((
12140 server_id,
12141 uri,
12142 diagnostics,
12143 workspace_diagnostics.version,
12144 registration_id,
12145 )),
12146 LspPullDiagnostics::Default => None,
12147 },
12148 )
12149 .fold(
12150 HashMap::default(),
12151 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12152 let (result_id, diagnostics) = match diagnostics {
12153 PulledDiagnostics::Unchanged { result_id } => {
12154 unchanged_buffers
12155 .entry(new_registration_id.clone())
12156 .or_insert_with(HashSet::default)
12157 .insert(uri.clone());
12158 (Some(result_id), Vec::new())
12159 }
12160 PulledDiagnostics::Changed {
12161 result_id,
12162 diagnostics,
12163 } => (result_id, diagnostics),
12164 };
12165 let disk_based_sources = Cow::Owned(
12166 self.language_server_adapter_for_id(server_id)
12167 .as_ref()
12168 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12169 .unwrap_or(&[])
12170 .to_vec(),
12171 );
12172
12173 let Some(abs_path) = uri.to_file_path().ok() else {
12174 return acc;
12175 };
12176 let Some((worktree, relative_path)) =
12177 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12178 else {
12179 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12180 return acc;
12181 };
12182 let worktree_id = worktree.read(cx).id();
12183 let project_path = ProjectPath {
12184 worktree_id,
12185 path: relative_path,
12186 };
12187 if let Some(local_lsp_store) = self.as_local_mut() {
12188 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12189 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12190 }
12191 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12192 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12193 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12194 acc.entry(server_id)
12195 .or_insert_with(HashMap::default)
12196 .entry(new_registration_id.clone())
12197 .or_insert_with(Vec::new)
12198 .push(DocumentDiagnosticsUpdate {
12199 server_id,
12200 diagnostics: lsp::PublishDiagnosticsParams {
12201 uri,
12202 diagnostics,
12203 version,
12204 },
12205 result_id: result_id.map(SharedString::new),
12206 disk_based_sources,
12207 registration_id: new_registration_id,
12208 });
12209 }
12210 acc
12211 },
12212 );
12213
12214 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12215 for (registration_id, diagnostic_updates) in diagnostic_updates {
12216 self.merge_lsp_diagnostics(
12217 DiagnosticSourceKind::Pulled,
12218 diagnostic_updates,
12219 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12220 DiagnosticSourceKind::Pulled => {
12221 old_diagnostic.registration_id != registration_id
12222 || unchanged_buffers
12223 .get(&old_diagnostic.registration_id)
12224 .is_some_and(|unchanged_buffers| {
12225 unchanged_buffers.contains(&document_uri)
12226 })
12227 }
12228 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12229 },
12230 cx,
12231 )
12232 .log_err();
12233 }
12234 }
12235 }
12236
12237 fn register_server_capabilities(
12238 &mut self,
12239 server_id: LanguageServerId,
12240 params: lsp::RegistrationParams,
12241 cx: &mut Context<Self>,
12242 ) -> anyhow::Result<()> {
12243 let server = self
12244 .language_server_for_id(server_id)
12245 .with_context(|| format!("no server {server_id} found"))?;
12246 for reg in params.registrations {
12247 match reg.method.as_str() {
12248 "workspace/didChangeWatchedFiles" => {
12249 if let Some(options) = reg.register_options {
12250 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12251 let caps = serde_json::from_value(options)?;
12252 local_lsp_store
12253 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12254 true
12255 } else {
12256 false
12257 };
12258 if notify {
12259 notify_server_capabilities_updated(&server, cx);
12260 }
12261 }
12262 }
12263 "workspace/didChangeConfiguration" => {
12264 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12265 }
12266 "workspace/didChangeWorkspaceFolders" => {
12267 // In this case register options is an empty object, we can ignore it
12268 let caps = lsp::WorkspaceFoldersServerCapabilities {
12269 supported: Some(true),
12270 change_notifications: Some(OneOf::Right(reg.id)),
12271 };
12272 server.update_capabilities(|capabilities| {
12273 capabilities
12274 .workspace
12275 .get_or_insert_default()
12276 .workspace_folders = Some(caps);
12277 });
12278 notify_server_capabilities_updated(&server, cx);
12279 }
12280 "workspace/symbol" => {
12281 let options = parse_register_capabilities(reg)?;
12282 server.update_capabilities(|capabilities| {
12283 capabilities.workspace_symbol_provider = Some(options);
12284 });
12285 notify_server_capabilities_updated(&server, cx);
12286 }
12287 "workspace/fileOperations" => {
12288 if let Some(options) = reg.register_options {
12289 let caps = serde_json::from_value(options)?;
12290 server.update_capabilities(|capabilities| {
12291 capabilities
12292 .workspace
12293 .get_or_insert_default()
12294 .file_operations = Some(caps);
12295 });
12296 notify_server_capabilities_updated(&server, cx);
12297 }
12298 }
12299 "workspace/executeCommand" => {
12300 if let Some(options) = reg.register_options {
12301 let options = serde_json::from_value(options)?;
12302 server.update_capabilities(|capabilities| {
12303 capabilities.execute_command_provider = Some(options);
12304 });
12305 notify_server_capabilities_updated(&server, cx);
12306 }
12307 }
12308 "textDocument/rangeFormatting" => {
12309 let options = parse_register_capabilities(reg)?;
12310 server.update_capabilities(|capabilities| {
12311 capabilities.document_range_formatting_provider = Some(options);
12312 });
12313 notify_server_capabilities_updated(&server, cx);
12314 }
12315 "textDocument/onTypeFormatting" => {
12316 if let Some(options) = reg
12317 .register_options
12318 .map(serde_json::from_value)
12319 .transpose()?
12320 {
12321 server.update_capabilities(|capabilities| {
12322 capabilities.document_on_type_formatting_provider = Some(options);
12323 });
12324 notify_server_capabilities_updated(&server, cx);
12325 }
12326 }
12327 "textDocument/formatting" => {
12328 let options = parse_register_capabilities(reg)?;
12329 server.update_capabilities(|capabilities| {
12330 capabilities.document_formatting_provider = Some(options);
12331 });
12332 notify_server_capabilities_updated(&server, cx);
12333 }
12334 "textDocument/rename" => {
12335 let options = parse_register_capabilities(reg)?;
12336 server.update_capabilities(|capabilities| {
12337 capabilities.rename_provider = Some(options);
12338 });
12339 notify_server_capabilities_updated(&server, cx);
12340 }
12341 "textDocument/inlayHint" => {
12342 let options = parse_register_capabilities(reg)?;
12343 server.update_capabilities(|capabilities| {
12344 capabilities.inlay_hint_provider = Some(options);
12345 });
12346 notify_server_capabilities_updated(&server, cx);
12347 }
12348 "textDocument/documentSymbol" => {
12349 let options = parse_register_capabilities(reg)?;
12350 server.update_capabilities(|capabilities| {
12351 capabilities.document_symbol_provider = Some(options);
12352 });
12353 notify_server_capabilities_updated(&server, cx);
12354 }
12355 "textDocument/codeAction" => {
12356 let options = parse_register_capabilities(reg)?;
12357 let provider = match options {
12358 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12359 OneOf::Right(caps) => caps,
12360 };
12361 server.update_capabilities(|capabilities| {
12362 capabilities.code_action_provider = Some(provider);
12363 });
12364 notify_server_capabilities_updated(&server, cx);
12365 }
12366 "textDocument/definition" => {
12367 let options = parse_register_capabilities(reg)?;
12368 server.update_capabilities(|capabilities| {
12369 capabilities.definition_provider = Some(options);
12370 });
12371 notify_server_capabilities_updated(&server, cx);
12372 }
12373 "textDocument/completion" => {
12374 if let Some(caps) = reg
12375 .register_options
12376 .map(serde_json::from_value::<CompletionOptions>)
12377 .transpose()?
12378 {
12379 server.update_capabilities(|capabilities| {
12380 capabilities.completion_provider = Some(caps.clone());
12381 });
12382
12383 if let Some(local) = self.as_local() {
12384 let mut buffers_with_language_server = Vec::new();
12385 for handle in self.buffer_store.read(cx).buffers() {
12386 let buffer_id = handle.read(cx).remote_id();
12387 if local
12388 .buffers_opened_in_servers
12389 .get(&buffer_id)
12390 .filter(|s| s.contains(&server_id))
12391 .is_some()
12392 {
12393 buffers_with_language_server.push(handle);
12394 }
12395 }
12396 let triggers = caps
12397 .trigger_characters
12398 .unwrap_or_default()
12399 .into_iter()
12400 .collect::<BTreeSet<_>>();
12401 for handle in buffers_with_language_server {
12402 let triggers = triggers.clone();
12403 let _ = handle.update(cx, move |buffer, cx| {
12404 buffer.set_completion_triggers(server_id, triggers, cx);
12405 });
12406 }
12407 }
12408 notify_server_capabilities_updated(&server, cx);
12409 }
12410 }
12411 "textDocument/hover" => {
12412 let options = parse_register_capabilities(reg)?;
12413 let provider = match options {
12414 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12415 OneOf::Right(caps) => caps,
12416 };
12417 server.update_capabilities(|capabilities| {
12418 capabilities.hover_provider = Some(provider);
12419 });
12420 notify_server_capabilities_updated(&server, cx);
12421 }
12422 "textDocument/signatureHelp" => {
12423 if let Some(caps) = reg
12424 .register_options
12425 .map(serde_json::from_value)
12426 .transpose()?
12427 {
12428 server.update_capabilities(|capabilities| {
12429 capabilities.signature_help_provider = Some(caps);
12430 });
12431 notify_server_capabilities_updated(&server, cx);
12432 }
12433 }
12434 "textDocument/didChange" => {
12435 if let Some(sync_kind) = reg
12436 .register_options
12437 .and_then(|opts| opts.get("syncKind").cloned())
12438 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12439 .transpose()?
12440 {
12441 server.update_capabilities(|capabilities| {
12442 let mut sync_options =
12443 Self::take_text_document_sync_options(capabilities);
12444 sync_options.change = Some(sync_kind);
12445 capabilities.text_document_sync =
12446 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12447 });
12448 notify_server_capabilities_updated(&server, cx);
12449 }
12450 }
12451 "textDocument/didSave" => {
12452 if let Some(include_text) = reg
12453 .register_options
12454 .map(|opts| {
12455 let transpose = opts
12456 .get("includeText")
12457 .cloned()
12458 .map(serde_json::from_value::<Option<bool>>)
12459 .transpose();
12460 match transpose {
12461 Ok(value) => Ok(value.flatten()),
12462 Err(e) => Err(e),
12463 }
12464 })
12465 .transpose()?
12466 {
12467 server.update_capabilities(|capabilities| {
12468 let mut sync_options =
12469 Self::take_text_document_sync_options(capabilities);
12470 sync_options.save =
12471 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12472 include_text,
12473 }));
12474 capabilities.text_document_sync =
12475 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12476 });
12477 notify_server_capabilities_updated(&server, cx);
12478 }
12479 }
12480 "textDocument/codeLens" => {
12481 if let Some(caps) = reg
12482 .register_options
12483 .map(serde_json::from_value)
12484 .transpose()?
12485 {
12486 server.update_capabilities(|capabilities| {
12487 capabilities.code_lens_provider = Some(caps);
12488 });
12489 notify_server_capabilities_updated(&server, cx);
12490 }
12491 }
12492 "textDocument/diagnostic" => {
12493 if let Some(caps) = reg
12494 .register_options
12495 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12496 .transpose()?
12497 {
12498 let local = self
12499 .as_local_mut()
12500 .context("Expected LSP Store to be local")?;
12501 let state = local
12502 .language_servers
12503 .get_mut(&server_id)
12504 .context("Could not obtain Language Servers state")?;
12505 local
12506 .language_server_dynamic_registrations
12507 .entry(server_id)
12508 .or_default()
12509 .diagnostics
12510 .insert(Some(reg.id.clone()), caps.clone());
12511
12512 let supports_workspace_diagnostics =
12513 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12514 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12515 diagnostic_options.workspace_diagnostics
12516 }
12517 DiagnosticServerCapabilities::RegistrationOptions(
12518 diagnostic_registration_options,
12519 ) => {
12520 diagnostic_registration_options
12521 .diagnostic_options
12522 .workspace_diagnostics
12523 }
12524 };
12525
12526 if supports_workspace_diagnostics(&caps) {
12527 if let LanguageServerState::Running {
12528 workspace_diagnostics_refresh_tasks,
12529 ..
12530 } = state
12531 && let Some(task) = lsp_workspace_diagnostics_refresh(
12532 Some(reg.id.clone()),
12533 caps.clone(),
12534 server.clone(),
12535 cx,
12536 )
12537 {
12538 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12539 }
12540 }
12541
12542 server.update_capabilities(|capabilities| {
12543 capabilities.diagnostic_provider = Some(caps);
12544 });
12545
12546 notify_server_capabilities_updated(&server, cx);
12547
12548 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12549 }
12550 }
12551 "textDocument/documentColor" => {
12552 let options = parse_register_capabilities(reg)?;
12553 let provider = match options {
12554 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12555 OneOf::Right(caps) => caps,
12556 };
12557 server.update_capabilities(|capabilities| {
12558 capabilities.color_provider = Some(provider);
12559 });
12560 notify_server_capabilities_updated(&server, cx);
12561 }
12562 "textDocument/foldingRange" => {
12563 let options = parse_register_capabilities(reg)?;
12564 let provider = match options {
12565 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12566 OneOf::Right(caps) => caps,
12567 };
12568 server.update_capabilities(|capabilities| {
12569 capabilities.folding_range_provider = Some(provider);
12570 });
12571 notify_server_capabilities_updated(&server, cx);
12572 }
12573 _ => log::warn!("unhandled capability registration: {reg:?}"),
12574 }
12575 }
12576
12577 Ok(())
12578 }
12579
12580 fn unregister_server_capabilities(
12581 &mut self,
12582 server_id: LanguageServerId,
12583 params: lsp::UnregistrationParams,
12584 cx: &mut Context<Self>,
12585 ) -> anyhow::Result<()> {
12586 let server = self
12587 .language_server_for_id(server_id)
12588 .with_context(|| format!("no server {server_id} found"))?;
12589 for unreg in params.unregisterations.iter() {
12590 match unreg.method.as_str() {
12591 "workspace/didChangeWatchedFiles" => {
12592 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12593 local_lsp_store
12594 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12595 true
12596 } else {
12597 false
12598 };
12599 if notify {
12600 notify_server_capabilities_updated(&server, cx);
12601 }
12602 }
12603 "workspace/didChangeConfiguration" => {
12604 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12605 }
12606 "workspace/didChangeWorkspaceFolders" => {
12607 server.update_capabilities(|capabilities| {
12608 capabilities
12609 .workspace
12610 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12611 workspace_folders: None,
12612 file_operations: None,
12613 })
12614 .workspace_folders = None;
12615 });
12616 notify_server_capabilities_updated(&server, cx);
12617 }
12618 "workspace/symbol" => {
12619 server.update_capabilities(|capabilities| {
12620 capabilities.workspace_symbol_provider = None
12621 });
12622 notify_server_capabilities_updated(&server, cx);
12623 }
12624 "workspace/fileOperations" => {
12625 server.update_capabilities(|capabilities| {
12626 capabilities
12627 .workspace
12628 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12629 workspace_folders: None,
12630 file_operations: None,
12631 })
12632 .file_operations = None;
12633 });
12634 notify_server_capabilities_updated(&server, cx);
12635 }
12636 "workspace/executeCommand" => {
12637 server.update_capabilities(|capabilities| {
12638 capabilities.execute_command_provider = None;
12639 });
12640 notify_server_capabilities_updated(&server, cx);
12641 }
12642 "textDocument/rangeFormatting" => {
12643 server.update_capabilities(|capabilities| {
12644 capabilities.document_range_formatting_provider = None
12645 });
12646 notify_server_capabilities_updated(&server, cx);
12647 }
12648 "textDocument/onTypeFormatting" => {
12649 server.update_capabilities(|capabilities| {
12650 capabilities.document_on_type_formatting_provider = None;
12651 });
12652 notify_server_capabilities_updated(&server, cx);
12653 }
12654 "textDocument/formatting" => {
12655 server.update_capabilities(|capabilities| {
12656 capabilities.document_formatting_provider = None;
12657 });
12658 notify_server_capabilities_updated(&server, cx);
12659 }
12660 "textDocument/rename" => {
12661 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12662 notify_server_capabilities_updated(&server, cx);
12663 }
12664 "textDocument/codeAction" => {
12665 server.update_capabilities(|capabilities| {
12666 capabilities.code_action_provider = None;
12667 });
12668 notify_server_capabilities_updated(&server, cx);
12669 }
12670 "textDocument/definition" => {
12671 server.update_capabilities(|capabilities| {
12672 capabilities.definition_provider = None;
12673 });
12674 notify_server_capabilities_updated(&server, cx);
12675 }
12676 "textDocument/completion" => {
12677 server.update_capabilities(|capabilities| {
12678 capabilities.completion_provider = None;
12679 });
12680 notify_server_capabilities_updated(&server, cx);
12681 }
12682 "textDocument/hover" => {
12683 server.update_capabilities(|capabilities| {
12684 capabilities.hover_provider = None;
12685 });
12686 notify_server_capabilities_updated(&server, cx);
12687 }
12688 "textDocument/signatureHelp" => {
12689 server.update_capabilities(|capabilities| {
12690 capabilities.signature_help_provider = None;
12691 });
12692 notify_server_capabilities_updated(&server, cx);
12693 }
12694 "textDocument/didChange" => {
12695 server.update_capabilities(|capabilities| {
12696 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12697 sync_options.change = None;
12698 capabilities.text_document_sync =
12699 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12700 });
12701 notify_server_capabilities_updated(&server, cx);
12702 }
12703 "textDocument/didSave" => {
12704 server.update_capabilities(|capabilities| {
12705 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12706 sync_options.save = None;
12707 capabilities.text_document_sync =
12708 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12709 });
12710 notify_server_capabilities_updated(&server, cx);
12711 }
12712 "textDocument/codeLens" => {
12713 server.update_capabilities(|capabilities| {
12714 capabilities.code_lens_provider = None;
12715 });
12716 notify_server_capabilities_updated(&server, cx);
12717 }
12718 "textDocument/diagnostic" => {
12719 let local = self
12720 .as_local_mut()
12721 .context("Expected LSP Store to be local")?;
12722
12723 let state = local
12724 .language_servers
12725 .get_mut(&server_id)
12726 .context("Could not obtain Language Servers state")?;
12727 let registrations = local
12728 .language_server_dynamic_registrations
12729 .get_mut(&server_id)
12730 .with_context(|| {
12731 format!("Expected dynamic registration to exist for server {server_id}")
12732 })?;
12733 registrations.diagnostics
12734 .remove(&Some(unreg.id.clone()))
12735 .with_context(|| format!(
12736 "Attempted to unregister non-existent diagnostic registration with ID {}",
12737 unreg.id)
12738 )?;
12739 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12740
12741 if let LanguageServerState::Running {
12742 workspace_diagnostics_refresh_tasks,
12743 ..
12744 } = state
12745 {
12746 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12747 }
12748
12749 self.clear_unregistered_diagnostics(
12750 server_id,
12751 SharedString::from(unreg.id.clone()),
12752 cx,
12753 )?;
12754
12755 if removed_last_diagnostic_provider {
12756 server.update_capabilities(|capabilities| {
12757 debug_assert!(capabilities.diagnostic_provider.is_some());
12758 capabilities.diagnostic_provider = None;
12759 });
12760 }
12761
12762 notify_server_capabilities_updated(&server, cx);
12763 }
12764 "textDocument/documentColor" => {
12765 server.update_capabilities(|capabilities| {
12766 capabilities.color_provider = None;
12767 });
12768 notify_server_capabilities_updated(&server, cx);
12769 }
12770 "textDocument/foldingRange" => {
12771 server.update_capabilities(|capabilities| {
12772 capabilities.folding_range_provider = None;
12773 });
12774 notify_server_capabilities_updated(&server, cx);
12775 }
12776 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12777 }
12778 }
12779
12780 Ok(())
12781 }
12782
12783 fn clear_unregistered_diagnostics(
12784 &mut self,
12785 server_id: LanguageServerId,
12786 cleared_registration_id: SharedString,
12787 cx: &mut Context<Self>,
12788 ) -> anyhow::Result<()> {
12789 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12790
12791 self.buffer_store.update(cx, |buffer_store, cx| {
12792 for buffer_handle in buffer_store.buffers() {
12793 let buffer = buffer_handle.read(cx);
12794 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12795 let Some(abs_path) = abs_path else {
12796 continue;
12797 };
12798 affected_abs_paths.insert(abs_path);
12799 }
12800 });
12801
12802 let local = self.as_local().context("Expected LSP Store to be local")?;
12803 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12804 let Some(worktree) = self
12805 .worktree_store
12806 .read(cx)
12807 .worktree_for_id(*worktree_id, cx)
12808 else {
12809 continue;
12810 };
12811
12812 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12813 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12814 let has_matching_registration =
12815 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12816 entry.diagnostic.registration_id.as_ref()
12817 == Some(&cleared_registration_id)
12818 });
12819 if has_matching_registration {
12820 let abs_path = worktree.read(cx).absolutize(rel_path);
12821 affected_abs_paths.insert(abs_path);
12822 }
12823 }
12824 }
12825 }
12826
12827 if affected_abs_paths.is_empty() {
12828 return Ok(());
12829 }
12830
12831 // Send a fake diagnostic update which clears the state for the registration ID
12832 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12833 affected_abs_paths
12834 .into_iter()
12835 .map(|abs_path| DocumentDiagnosticsUpdate {
12836 diagnostics: DocumentDiagnostics {
12837 diagnostics: Vec::new(),
12838 document_abs_path: abs_path,
12839 version: None,
12840 },
12841 result_id: None,
12842 registration_id: Some(cleared_registration_id.clone()),
12843 server_id,
12844 disk_based_sources: Cow::Borrowed(&[]),
12845 })
12846 .collect();
12847
12848 let merge_registration_id = cleared_registration_id.clone();
12849 self.merge_diagnostic_entries(
12850 clears,
12851 move |_, diagnostic, _| {
12852 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12853 diagnostic.registration_id != Some(merge_registration_id.clone())
12854 } else {
12855 true
12856 }
12857 },
12858 cx,
12859 )?;
12860
12861 Ok(())
12862 }
12863
12864 async fn deduplicate_range_based_lsp_requests<T>(
12865 lsp_store: &Entity<Self>,
12866 server_id: Option<LanguageServerId>,
12867 lsp_request_id: LspRequestId,
12868 proto_request: &T::ProtoRequest,
12869 range: Range<Anchor>,
12870 cx: &mut AsyncApp,
12871 ) -> Result<()>
12872 where
12873 T: LspCommand,
12874 T::ProtoRequest: proto::LspRequestMessage,
12875 {
12876 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12877 let version = deserialize_version(proto_request.buffer_version());
12878 let buffer = lsp_store.update(cx, |this, cx| {
12879 this.buffer_store.read(cx).get_existing(buffer_id)
12880 })?;
12881 buffer
12882 .update(cx, |buffer, _| buffer.wait_for_version(version))
12883 .await?;
12884 lsp_store.update(cx, |lsp_store, cx| {
12885 let buffer_snapshot = buffer.read(cx).snapshot();
12886 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12887 let chunks_queried_for = lsp_data
12888 .inlay_hints
12889 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12890 .collect::<Vec<_>>();
12891 match chunks_queried_for.as_slice() {
12892 &[chunk] => {
12893 let key = LspKey {
12894 request_type: TypeId::of::<T>(),
12895 server_queried: server_id,
12896 };
12897 let previous_request = lsp_data
12898 .chunk_lsp_requests
12899 .entry(key)
12900 .or_default()
12901 .insert(chunk, lsp_request_id);
12902 if let Some((previous_request, running_requests)) =
12903 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12904 {
12905 running_requests.remove(&previous_request);
12906 }
12907 }
12908 _ambiguous_chunks => {
12909 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12910 // there, a buffer version-based check will be performed and outdated requests discarded.
12911 }
12912 }
12913 anyhow::Ok(())
12914 })?;
12915
12916 Ok(())
12917 }
12918
12919 async fn query_lsp_locally<T>(
12920 lsp_store: Entity<Self>,
12921 for_server_id: Option<LanguageServerId>,
12922 sender_id: proto::PeerId,
12923 lsp_request_id: LspRequestId,
12924 proto_request: T::ProtoRequest,
12925 position: Option<Anchor>,
12926 cx: &mut AsyncApp,
12927 ) -> Result<()>
12928 where
12929 T: LspCommand + Clone,
12930 T::ProtoRequest: proto::LspRequestMessage,
12931 <T::ProtoRequest as proto::RequestMessage>::Response:
12932 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12933 {
12934 let (buffer_version, buffer) =
12935 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12936 let request =
12937 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12938 let key = LspKey {
12939 request_type: TypeId::of::<T>(),
12940 server_queried: for_server_id,
12941 };
12942 lsp_store.update(cx, |lsp_store, cx| {
12943 let request_task = match for_server_id {
12944 Some(server_id) => {
12945 let server_task = lsp_store.request_lsp(
12946 buffer.clone(),
12947 LanguageServerToQuery::Other(server_id),
12948 request.clone(),
12949 cx,
12950 );
12951 cx.background_spawn(async move {
12952 let mut responses = Vec::new();
12953 match server_task.await {
12954 Ok(response) => responses.push((server_id, response)),
12955 // rust-analyzer likes to error with this when its still loading up
12956 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12957 Err(e) => log::error!(
12958 "Error handling response for request {request:?}: {e:#}"
12959 ),
12960 }
12961 responses
12962 })
12963 }
12964 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12965 };
12966 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12967 if T::ProtoRequest::stop_previous_requests() {
12968 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12969 lsp_requests.clear();
12970 }
12971 }
12972 lsp_data.lsp_requests.entry(key).or_default().insert(
12973 lsp_request_id,
12974 cx.spawn(async move |lsp_store, cx| {
12975 let response = request_task.await;
12976 lsp_store
12977 .update(cx, |lsp_store, cx| {
12978 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12979 {
12980 let response = response
12981 .into_iter()
12982 .map(|(server_id, response)| {
12983 (
12984 server_id.to_proto(),
12985 T::response_to_proto(
12986 response,
12987 lsp_store,
12988 sender_id,
12989 &buffer_version,
12990 cx,
12991 )
12992 .into(),
12993 )
12994 })
12995 .collect::<HashMap<_, _>>();
12996 match client.send_lsp_response::<T::ProtoRequest>(
12997 project_id,
12998 lsp_request_id,
12999 response,
13000 ) {
13001 Ok(()) => {}
13002 Err(e) => {
13003 log::error!("Failed to send LSP response: {e:#}",)
13004 }
13005 }
13006 }
13007 })
13008 .ok();
13009 }),
13010 );
13011 });
13012 Ok(())
13013 }
13014
13015 async fn wait_for_buffer_version<T>(
13016 lsp_store: &Entity<Self>,
13017 proto_request: &T::ProtoRequest,
13018 cx: &mut AsyncApp,
13019 ) -> Result<(Global, Entity<Buffer>)>
13020 where
13021 T: LspCommand,
13022 T::ProtoRequest: proto::LspRequestMessage,
13023 {
13024 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13025 let version = deserialize_version(proto_request.buffer_version());
13026 let buffer = lsp_store.update(cx, |this, cx| {
13027 this.buffer_store.read(cx).get_existing(buffer_id)
13028 })?;
13029 buffer
13030 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13031 .await?;
13032 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13033 Ok((buffer_version, buffer))
13034 }
13035
13036 fn take_text_document_sync_options(
13037 capabilities: &mut lsp::ServerCapabilities,
13038 ) -> lsp::TextDocumentSyncOptions {
13039 match capabilities.text_document_sync.take() {
13040 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13041 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13042 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13043 sync_options.change = Some(sync_kind);
13044 sync_options
13045 }
13046 None => lsp::TextDocumentSyncOptions::default(),
13047 }
13048 }
13049
13050 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13051 self.downstream_client.clone()
13052 }
13053
13054 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13055 self.worktree_store.clone()
13056 }
13057
13058 /// Gets what's stored in the LSP data for the given buffer.
13059 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13060 self.lsp_data.get_mut(&buffer_id)
13061 }
13062
13063 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13064 /// new [`BufferLspData`] will be created to replace the previous state.
13065 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13066 let (buffer_id, buffer_version) =
13067 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13068 let lsp_data = self
13069 .lsp_data
13070 .entry(buffer_id)
13071 .or_insert_with(|| BufferLspData::new(buffer, cx));
13072 if buffer_version.changed_since(&lsp_data.buffer_version) {
13073 // To send delta requests for semantic tokens, the previous tokens
13074 // need to be kept between buffer changes.
13075 let semantic_tokens = lsp_data.semantic_tokens.take();
13076 *lsp_data = BufferLspData::new(buffer, cx);
13077 lsp_data.semantic_tokens = semantic_tokens;
13078 }
13079 lsp_data
13080 }
13081}
13082
13083// Registration with registerOptions as null, should fallback to true.
13084// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13085fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13086 reg: lsp::Registration,
13087) -> Result<OneOf<bool, T>> {
13088 Ok(match reg.register_options {
13089 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13090 None => OneOf::Left(true),
13091 })
13092}
13093
13094fn subscribe_to_binary_statuses(
13095 languages: &Arc<LanguageRegistry>,
13096 cx: &mut Context<'_, LspStore>,
13097) -> Task<()> {
13098 let mut server_statuses = languages.language_server_binary_statuses();
13099 cx.spawn(async move |lsp_store, cx| {
13100 while let Some((server_name, binary_status)) = server_statuses.next().await {
13101 if lsp_store
13102 .update(cx, |_, cx| {
13103 let mut message = None;
13104 let binary_status = match binary_status {
13105 BinaryStatus::None => proto::ServerBinaryStatus::None,
13106 BinaryStatus::CheckingForUpdate => {
13107 proto::ServerBinaryStatus::CheckingForUpdate
13108 }
13109 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13110 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13111 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13112 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13113 BinaryStatus::Failed { error } => {
13114 message = Some(error);
13115 proto::ServerBinaryStatus::Failed
13116 }
13117 };
13118 cx.emit(LspStoreEvent::LanguageServerUpdate {
13119 // Binary updates are about the binary that might not have any language server id at that point.
13120 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13121 language_server_id: LanguageServerId(0),
13122 name: Some(server_name),
13123 message: proto::update_language_server::Variant::StatusUpdate(
13124 proto::StatusUpdate {
13125 message,
13126 status: Some(proto::status_update::Status::Binary(
13127 binary_status as i32,
13128 )),
13129 },
13130 ),
13131 });
13132 })
13133 .is_err()
13134 {
13135 break;
13136 }
13137 }
13138 })
13139}
13140
13141fn lsp_workspace_diagnostics_refresh(
13142 registration_id: Option<String>,
13143 options: DiagnosticServerCapabilities,
13144 server: Arc<LanguageServer>,
13145 cx: &mut Context<'_, LspStore>,
13146) -> Option<WorkspaceRefreshTask> {
13147 let identifier = workspace_diagnostic_identifier(&options)?;
13148 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13149
13150 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13151 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13152 refresh_tx.try_send(()).ok();
13153
13154 let request_timeout = ProjectSettings::get_global(cx)
13155 .global_lsp_settings
13156 .get_request_timeout();
13157
13158 // 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.
13159 // This allows users to increase the duration if need be
13160 let timeout = if request_timeout != Duration::ZERO {
13161 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13162 } else {
13163 request_timeout
13164 };
13165
13166 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13167 let mut attempts = 0;
13168 let max_attempts = 50;
13169 let mut requests = 0;
13170
13171 loop {
13172 let Some(()) = refresh_rx.recv().await else {
13173 return;
13174 };
13175
13176 'request: loop {
13177 requests += 1;
13178 if attempts > max_attempts {
13179 log::error!(
13180 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13181 );
13182 return;
13183 }
13184 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13185 cx.background_executor()
13186 .timer(Duration::from_millis(backoff_millis))
13187 .await;
13188 attempts += 1;
13189
13190 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13191 lsp_store
13192 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13193 .into_iter()
13194 .filter_map(|(abs_path, result_id)| {
13195 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13196 Some(lsp::PreviousResultId {
13197 uri,
13198 value: result_id.to_string(),
13199 })
13200 })
13201 .collect()
13202 }) else {
13203 return;
13204 };
13205
13206 let token = if let Some(registration_id) = ®istration_id {
13207 format!(
13208 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13209 server.server_id(),
13210 )
13211 } else {
13212 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13213 };
13214
13215 progress_rx.try_recv().ok();
13216 let timer = server.request_timer(timeout).fuse();
13217 let progress = pin!(progress_rx.recv().fuse());
13218 let response_result = server
13219 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13220 lsp::WorkspaceDiagnosticParams {
13221 previous_result_ids,
13222 identifier: identifier.clone(),
13223 work_done_progress_params: Default::default(),
13224 partial_result_params: lsp::PartialResultParams {
13225 partial_result_token: Some(lsp::ProgressToken::String(token)),
13226 },
13227 },
13228 select(timer, progress).then(|either| match either {
13229 Either::Left((message, ..)) => ready(message).left_future(),
13230 Either::Right(..) => pending::<String>().right_future(),
13231 }),
13232 )
13233 .await;
13234
13235 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13236 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13237 match response_result {
13238 ConnectionResult::Timeout => {
13239 log::error!("Timeout during workspace diagnostics pull");
13240 continue 'request;
13241 }
13242 ConnectionResult::ConnectionReset => {
13243 log::error!("Server closed a workspace diagnostics pull request");
13244 continue 'request;
13245 }
13246 ConnectionResult::Result(Err(e)) => {
13247 log::error!("Error during workspace diagnostics pull: {e:#}");
13248 break 'request;
13249 }
13250 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13251 attempts = 0;
13252 if lsp_store
13253 .update(cx, |lsp_store, cx| {
13254 lsp_store.apply_workspace_diagnostic_report(
13255 server.server_id(),
13256 pulled_diagnostics,
13257 registration_id_shared.clone(),
13258 cx,
13259 )
13260 })
13261 .is_err()
13262 {
13263 return;
13264 }
13265 break 'request;
13266 }
13267 }
13268 }
13269 }
13270 });
13271
13272 Some(WorkspaceRefreshTask {
13273 refresh_tx,
13274 progress_tx,
13275 task: workspace_query_language_server,
13276 })
13277}
13278
13279fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13280 match &options {
13281 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13282 .identifier
13283 .as_deref()
13284 .map(SharedString::new),
13285 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13286 let diagnostic_options = ®istration_options.diagnostic_options;
13287 diagnostic_options
13288 .identifier
13289 .as_deref()
13290 .map(SharedString::new)
13291 }
13292 }
13293}
13294
13295fn workspace_diagnostic_identifier(
13296 options: &DiagnosticServerCapabilities,
13297) -> Option<Option<String>> {
13298 match &options {
13299 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13300 if !diagnostic_options.workspace_diagnostics {
13301 return None;
13302 }
13303 Some(diagnostic_options.identifier.clone())
13304 }
13305 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13306 let diagnostic_options = ®istration_options.diagnostic_options;
13307 if !diagnostic_options.workspace_diagnostics {
13308 return None;
13309 }
13310 Some(diagnostic_options.identifier.clone())
13311 }
13312 }
13313}
13314
13315fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13316 let CompletionSource::BufferWord {
13317 word_range,
13318 resolved,
13319 } = &mut completion.source
13320 else {
13321 return;
13322 };
13323 if *resolved {
13324 return;
13325 }
13326
13327 if completion.new_text
13328 != snapshot
13329 .text_for_range(word_range.clone())
13330 .collect::<String>()
13331 {
13332 return;
13333 }
13334
13335 let mut offset = 0;
13336 for chunk in snapshot.chunks(word_range.clone(), true) {
13337 let end_offset = offset + chunk.text.len();
13338 if let Some(highlight_id) = chunk.syntax_highlight_id {
13339 completion
13340 .label
13341 .runs
13342 .push((offset..end_offset, highlight_id));
13343 }
13344 offset = end_offset;
13345 }
13346 *resolved = true;
13347}
13348
13349impl EventEmitter<LspStoreEvent> for LspStore {}
13350
13351fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13352 hover
13353 .contents
13354 .retain(|hover_block| !hover_block.text.trim().is_empty());
13355 if hover.contents.is_empty() {
13356 None
13357 } else {
13358 Some(hover)
13359 }
13360}
13361
13362async fn populate_labels_for_completions(
13363 new_completions: Vec<CoreCompletion>,
13364 language: Option<Arc<Language>>,
13365 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13366) -> Vec<Completion> {
13367 let lsp_completions = new_completions
13368 .iter()
13369 .filter_map(|new_completion| {
13370 new_completion
13371 .source
13372 .lsp_completion(true)
13373 .map(|lsp_completion| lsp_completion.into_owned())
13374 })
13375 .collect::<Vec<_>>();
13376
13377 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13378 lsp_adapter
13379 .labels_for_completions(&lsp_completions, language)
13380 .await
13381 .log_err()
13382 .unwrap_or_default()
13383 } else {
13384 Vec::new()
13385 }
13386 .into_iter()
13387 .fuse();
13388
13389 let mut completions = Vec::new();
13390 for completion in new_completions {
13391 match completion.source.lsp_completion(true) {
13392 Some(lsp_completion) => {
13393 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13394
13395 let mut label = labels.next().flatten().unwrap_or_else(|| {
13396 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13397 });
13398 ensure_uniform_list_compatible_label(&mut label);
13399 completions.push(Completion {
13400 label,
13401 documentation,
13402 replace_range: completion.replace_range,
13403 new_text: completion.new_text,
13404 insert_text_mode: lsp_completion.insert_text_mode,
13405 source: completion.source,
13406 icon_path: None,
13407 confirm: None,
13408 match_start: None,
13409 snippet_deduplication_key: None,
13410 });
13411 }
13412 None => {
13413 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13414 ensure_uniform_list_compatible_label(&mut label);
13415 completions.push(Completion {
13416 label,
13417 documentation: None,
13418 replace_range: completion.replace_range,
13419 new_text: completion.new_text,
13420 source: completion.source,
13421 insert_text_mode: None,
13422 icon_path: None,
13423 confirm: None,
13424 match_start: None,
13425 snippet_deduplication_key: None,
13426 });
13427 }
13428 }
13429 }
13430 completions
13431}
13432
13433#[derive(Debug)]
13434pub enum LanguageServerToQuery {
13435 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13436 FirstCapable,
13437 /// Query a specific language server.
13438 Other(LanguageServerId),
13439}
13440
13441#[derive(Default)]
13442struct RenamePathsWatchedForServer {
13443 did_rename: Vec<RenameActionPredicate>,
13444 will_rename: Vec<RenameActionPredicate>,
13445}
13446
13447impl RenamePathsWatchedForServer {
13448 fn with_did_rename_patterns(
13449 mut self,
13450 did_rename: Option<&FileOperationRegistrationOptions>,
13451 ) -> Self {
13452 if let Some(did_rename) = did_rename {
13453 self.did_rename = did_rename
13454 .filters
13455 .iter()
13456 .filter_map(|filter| filter.try_into().log_err())
13457 .collect();
13458 }
13459 self
13460 }
13461 fn with_will_rename_patterns(
13462 mut self,
13463 will_rename: Option<&FileOperationRegistrationOptions>,
13464 ) -> Self {
13465 if let Some(will_rename) = will_rename {
13466 self.will_rename = will_rename
13467 .filters
13468 .iter()
13469 .filter_map(|filter| filter.try_into().log_err())
13470 .collect();
13471 }
13472 self
13473 }
13474
13475 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13476 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13477 }
13478 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13479 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13480 }
13481}
13482
13483impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13484 type Error = globset::Error;
13485 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13486 Ok(Self {
13487 kind: ops.pattern.matches.clone(),
13488 glob: GlobBuilder::new(&ops.pattern.glob)
13489 .case_insensitive(
13490 ops.pattern
13491 .options
13492 .as_ref()
13493 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13494 )
13495 .build()?
13496 .compile_matcher(),
13497 })
13498 }
13499}
13500struct RenameActionPredicate {
13501 glob: GlobMatcher,
13502 kind: Option<FileOperationPatternKind>,
13503}
13504
13505impl RenameActionPredicate {
13506 // Returns true if language server should be notified
13507 fn eval(&self, path: &str, is_dir: bool) -> bool {
13508 self.kind.as_ref().is_none_or(|kind| {
13509 let expected_kind = if is_dir {
13510 FileOperationPatternKind::Folder
13511 } else {
13512 FileOperationPatternKind::File
13513 };
13514 kind == &expected_kind
13515 }) && self.glob.is_match(path)
13516 }
13517}
13518
13519#[derive(Default)]
13520struct LanguageServerWatchedPaths {
13521 worktree_paths: HashMap<WorktreeId, GlobSet>,
13522 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13523}
13524
13525#[derive(Default)]
13526struct LanguageServerWatchedPathsBuilder {
13527 worktree_paths: HashMap<WorktreeId, GlobSet>,
13528 abs_paths: HashMap<Arc<Path>, GlobSet>,
13529}
13530
13531impl LanguageServerWatchedPathsBuilder {
13532 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13533 self.worktree_paths.insert(worktree_id, glob_set);
13534 }
13535 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13536 self.abs_paths.insert(path, glob_set);
13537 }
13538 fn build(
13539 self,
13540 fs: Arc<dyn Fs>,
13541 language_server_id: LanguageServerId,
13542 cx: &mut Context<LspStore>,
13543 ) -> LanguageServerWatchedPaths {
13544 let lsp_store = cx.weak_entity();
13545
13546 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13547 let abs_paths = self
13548 .abs_paths
13549 .into_iter()
13550 .map(|(abs_path, globset)| {
13551 let task = cx.spawn({
13552 let abs_path = abs_path.clone();
13553 let fs = fs.clone();
13554
13555 let lsp_store = lsp_store.clone();
13556 async move |_, cx| {
13557 maybe!(async move {
13558 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13559 while let Some(update) = push_updates.0.next().await {
13560 let action = lsp_store
13561 .update(cx, |this, _| {
13562 let Some(local) = this.as_local() else {
13563 return ControlFlow::Break(());
13564 };
13565 let Some(watcher) = local
13566 .language_server_watched_paths
13567 .get(&language_server_id)
13568 else {
13569 return ControlFlow::Break(());
13570 };
13571 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13572 "Watched abs path is not registered with a watcher",
13573 );
13574 let matching_entries = update
13575 .into_iter()
13576 .filter(|event| globs.is_match(&event.path))
13577 .collect::<Vec<_>>();
13578 this.lsp_notify_abs_paths_changed(
13579 language_server_id,
13580 matching_entries,
13581 );
13582 ControlFlow::Continue(())
13583 })
13584 .ok()?;
13585
13586 if action.is_break() {
13587 break;
13588 }
13589 }
13590 Some(())
13591 })
13592 .await;
13593 }
13594 });
13595 (abs_path, (globset, task))
13596 })
13597 .collect();
13598 LanguageServerWatchedPaths {
13599 worktree_paths: self.worktree_paths,
13600 abs_paths,
13601 }
13602 }
13603}
13604
13605struct LspBufferSnapshot {
13606 version: i32,
13607 snapshot: TextBufferSnapshot,
13608}
13609
13610/// A prompt requested by LSP server.
13611#[derive(Clone, Debug)]
13612pub struct LanguageServerPromptRequest {
13613 pub id: usize,
13614 pub level: PromptLevel,
13615 pub message: String,
13616 pub actions: Vec<MessageActionItem>,
13617 pub lsp_name: String,
13618 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13619}
13620
13621impl LanguageServerPromptRequest {
13622 pub fn new(
13623 level: PromptLevel,
13624 message: String,
13625 actions: Vec<MessageActionItem>,
13626 lsp_name: String,
13627 response_channel: smol::channel::Sender<MessageActionItem>,
13628 ) -> Self {
13629 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13630 LanguageServerPromptRequest {
13631 id,
13632 level,
13633 message,
13634 actions,
13635 lsp_name,
13636 response_channel,
13637 }
13638 }
13639 pub async fn respond(self, index: usize) -> Option<()> {
13640 if let Some(response) = self.actions.into_iter().nth(index) {
13641 self.response_channel.send(response).await.ok()
13642 } else {
13643 None
13644 }
13645 }
13646
13647 #[cfg(any(test, feature = "test-support"))]
13648 pub fn test(
13649 level: PromptLevel,
13650 message: String,
13651 actions: Vec<MessageActionItem>,
13652 lsp_name: String,
13653 ) -> Self {
13654 let (tx, _rx) = smol::channel::unbounded();
13655 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13656 }
13657}
13658impl PartialEq for LanguageServerPromptRequest {
13659 fn eq(&self, other: &Self) -> bool {
13660 self.message == other.message && self.actions == other.actions
13661 }
13662}
13663
13664#[derive(Clone, Debug, PartialEq)]
13665pub enum LanguageServerLogType {
13666 Log(MessageType),
13667 Trace { verbose_info: Option<String> },
13668 Rpc { received: bool },
13669}
13670
13671impl LanguageServerLogType {
13672 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13673 match self {
13674 Self::Log(log_type) => {
13675 use proto::log_message::LogLevel;
13676 let level = match *log_type {
13677 MessageType::ERROR => LogLevel::Error,
13678 MessageType::WARNING => LogLevel::Warning,
13679 MessageType::INFO => LogLevel::Info,
13680 MessageType::LOG => LogLevel::Log,
13681 other => {
13682 log::warn!("Unknown lsp log message type: {other:?}");
13683 LogLevel::Log
13684 }
13685 };
13686 proto::language_server_log::LogType::Log(proto::LogMessage {
13687 level: level as i32,
13688 })
13689 }
13690 Self::Trace { verbose_info } => {
13691 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13692 verbose_info: verbose_info.to_owned(),
13693 })
13694 }
13695 Self::Rpc { received } => {
13696 let kind = if *received {
13697 proto::rpc_message::Kind::Received
13698 } else {
13699 proto::rpc_message::Kind::Sent
13700 };
13701 let kind = kind as i32;
13702 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13703 }
13704 }
13705 }
13706
13707 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13708 use proto::log_message::LogLevel;
13709 use proto::rpc_message;
13710 match log_type {
13711 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13712 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13713 LogLevel::Error => MessageType::ERROR,
13714 LogLevel::Warning => MessageType::WARNING,
13715 LogLevel::Info => MessageType::INFO,
13716 LogLevel::Log => MessageType::LOG,
13717 },
13718 ),
13719 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13720 verbose_info: trace_message.verbose_info,
13721 },
13722 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13723 received: match rpc_message::Kind::from_i32(message.kind)
13724 .unwrap_or(rpc_message::Kind::Received)
13725 {
13726 rpc_message::Kind::Received => true,
13727 rpc_message::Kind::Sent => false,
13728 },
13729 },
13730 }
13731 }
13732}
13733
13734pub struct WorkspaceRefreshTask {
13735 refresh_tx: mpsc::Sender<()>,
13736 progress_tx: mpsc::Sender<()>,
13737 #[allow(dead_code)]
13738 task: Task<()>,
13739}
13740
13741pub enum LanguageServerState {
13742 Starting {
13743 startup: Task<Option<Arc<LanguageServer>>>,
13744 /// List of language servers that will be added to the workspace once it's initialization completes.
13745 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13746 },
13747
13748 Running {
13749 adapter: Arc<CachedLspAdapter>,
13750 server: Arc<LanguageServer>,
13751 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13752 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13753 },
13754}
13755
13756impl LanguageServerState {
13757 fn add_workspace_folder(&self, uri: Uri) {
13758 match self {
13759 LanguageServerState::Starting {
13760 pending_workspace_folders,
13761 ..
13762 } => {
13763 pending_workspace_folders.lock().insert(uri);
13764 }
13765 LanguageServerState::Running { server, .. } => {
13766 server.add_workspace_folder(uri);
13767 }
13768 }
13769 }
13770 fn _remove_workspace_folder(&self, uri: Uri) {
13771 match self {
13772 LanguageServerState::Starting {
13773 pending_workspace_folders,
13774 ..
13775 } => {
13776 pending_workspace_folders.lock().remove(&uri);
13777 }
13778 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13779 }
13780 }
13781}
13782
13783impl std::fmt::Debug for LanguageServerState {
13784 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13785 match self {
13786 LanguageServerState::Starting { .. } => {
13787 f.debug_struct("LanguageServerState::Starting").finish()
13788 }
13789 LanguageServerState::Running { .. } => {
13790 f.debug_struct("LanguageServerState::Running").finish()
13791 }
13792 }
13793 }
13794}
13795
13796#[derive(Clone, Debug, Serialize)]
13797pub struct LanguageServerProgress {
13798 pub is_disk_based_diagnostics_progress: bool,
13799 pub is_cancellable: bool,
13800 pub title: Option<String>,
13801 pub message: Option<String>,
13802 pub percentage: Option<usize>,
13803 #[serde(skip_serializing)]
13804 pub last_update_at: Instant,
13805}
13806
13807#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13808pub struct DiagnosticSummary {
13809 pub error_count: usize,
13810 pub warning_count: usize,
13811}
13812
13813impl DiagnosticSummary {
13814 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13815 let mut this = Self {
13816 error_count: 0,
13817 warning_count: 0,
13818 };
13819
13820 for entry in diagnostics {
13821 if entry.diagnostic.is_primary {
13822 match entry.diagnostic.severity {
13823 DiagnosticSeverity::ERROR => this.error_count += 1,
13824 DiagnosticSeverity::WARNING => this.warning_count += 1,
13825 _ => {}
13826 }
13827 }
13828 }
13829
13830 this
13831 }
13832
13833 pub fn is_empty(&self) -> bool {
13834 self.error_count == 0 && self.warning_count == 0
13835 }
13836
13837 pub fn to_proto(
13838 self,
13839 language_server_id: LanguageServerId,
13840 path: &RelPath,
13841 ) -> proto::DiagnosticSummary {
13842 proto::DiagnosticSummary {
13843 path: path.to_proto(),
13844 language_server_id: language_server_id.0 as u64,
13845 error_count: self.error_count as u32,
13846 warning_count: self.warning_count as u32,
13847 }
13848 }
13849}
13850
13851#[derive(Clone, Debug)]
13852pub enum CompletionDocumentation {
13853 /// There is no documentation for this completion.
13854 Undocumented,
13855 /// A single line of documentation.
13856 SingleLine(SharedString),
13857 /// Multiple lines of plain text documentation.
13858 MultiLinePlainText(SharedString),
13859 /// Markdown documentation.
13860 MultiLineMarkdown(SharedString),
13861 /// Both single line and multiple lines of plain text documentation.
13862 SingleLineAndMultiLinePlainText {
13863 single_line: SharedString,
13864 plain_text: Option<SharedString>,
13865 },
13866}
13867
13868impl CompletionDocumentation {
13869 #[cfg(any(test, feature = "test-support"))]
13870 pub fn text(&self) -> SharedString {
13871 match self {
13872 CompletionDocumentation::Undocumented => "".into(),
13873 CompletionDocumentation::SingleLine(s) => s.clone(),
13874 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13875 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13876 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13877 single_line.clone()
13878 }
13879 }
13880 }
13881}
13882
13883impl From<lsp::Documentation> for CompletionDocumentation {
13884 fn from(docs: lsp::Documentation) -> Self {
13885 match docs {
13886 lsp::Documentation::String(text) => {
13887 if text.lines().count() <= 1 {
13888 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13889 } else {
13890 CompletionDocumentation::MultiLinePlainText(text.into())
13891 }
13892 }
13893
13894 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13895 lsp::MarkupKind::PlainText => {
13896 if value.lines().count() <= 1 {
13897 CompletionDocumentation::SingleLine(value.into())
13898 } else {
13899 CompletionDocumentation::MultiLinePlainText(value.into())
13900 }
13901 }
13902
13903 lsp::MarkupKind::Markdown => {
13904 CompletionDocumentation::MultiLineMarkdown(value.into())
13905 }
13906 },
13907 }
13908 }
13909}
13910
13911pub enum ResolvedHint {
13912 Resolved(InlayHint),
13913 Resolving(Shared<Task<()>>),
13914}
13915
13916pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13917 glob.components()
13918 .take_while(|component| match component {
13919 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13920 _ => true,
13921 })
13922 .collect()
13923}
13924
13925pub struct SshLspAdapter {
13926 name: LanguageServerName,
13927 binary: LanguageServerBinary,
13928 initialization_options: Option<String>,
13929 code_action_kinds: Option<Vec<CodeActionKind>>,
13930}
13931
13932impl SshLspAdapter {
13933 pub fn new(
13934 name: LanguageServerName,
13935 binary: LanguageServerBinary,
13936 initialization_options: Option<String>,
13937 code_action_kinds: Option<String>,
13938 ) -> Self {
13939 Self {
13940 name,
13941 binary,
13942 initialization_options,
13943 code_action_kinds: code_action_kinds
13944 .as_ref()
13945 .and_then(|c| serde_json::from_str(c).ok()),
13946 }
13947 }
13948}
13949
13950impl LspInstaller for SshLspAdapter {
13951 type BinaryVersion = ();
13952 async fn check_if_user_installed(
13953 &self,
13954 _: &dyn LspAdapterDelegate,
13955 _: Option<Toolchain>,
13956 _: &AsyncApp,
13957 ) -> Option<LanguageServerBinary> {
13958 Some(self.binary.clone())
13959 }
13960
13961 async fn cached_server_binary(
13962 &self,
13963 _: PathBuf,
13964 _: &dyn LspAdapterDelegate,
13965 ) -> Option<LanguageServerBinary> {
13966 None
13967 }
13968
13969 async fn fetch_latest_server_version(
13970 &self,
13971 _: &dyn LspAdapterDelegate,
13972 _: bool,
13973 _: &mut AsyncApp,
13974 ) -> Result<()> {
13975 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13976 }
13977
13978 async fn fetch_server_binary(
13979 &self,
13980 _: (),
13981 _: PathBuf,
13982 _: &dyn LspAdapterDelegate,
13983 ) -> Result<LanguageServerBinary> {
13984 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13985 }
13986}
13987
13988#[async_trait(?Send)]
13989impl LspAdapter for SshLspAdapter {
13990 fn name(&self) -> LanguageServerName {
13991 self.name.clone()
13992 }
13993
13994 async fn initialization_options(
13995 self: Arc<Self>,
13996 _: &Arc<dyn LspAdapterDelegate>,
13997 _: &mut AsyncApp,
13998 ) -> Result<Option<serde_json::Value>> {
13999 let Some(options) = &self.initialization_options else {
14000 return Ok(None);
14001 };
14002 let result = serde_json::from_str(options)?;
14003 Ok(result)
14004 }
14005
14006 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14007 self.code_action_kinds.clone()
14008 }
14009}
14010
14011pub fn language_server_settings<'a>(
14012 delegate: &'a dyn LspAdapterDelegate,
14013 language: &LanguageServerName,
14014 cx: &'a App,
14015) -> Option<&'a LspSettings> {
14016 language_server_settings_for(
14017 SettingsLocation {
14018 worktree_id: delegate.worktree_id(),
14019 path: RelPath::empty(),
14020 },
14021 language,
14022 cx,
14023 )
14024}
14025
14026pub fn language_server_settings_for<'a>(
14027 location: SettingsLocation<'a>,
14028 language: &LanguageServerName,
14029 cx: &'a App,
14030) -> Option<&'a LspSettings> {
14031 ProjectSettings::get(Some(location), cx).lsp.get(language)
14032}
14033
14034pub struct LocalLspAdapterDelegate {
14035 lsp_store: WeakEntity<LspStore>,
14036 worktree: worktree::Snapshot,
14037 fs: Arc<dyn Fs>,
14038 http_client: Arc<dyn HttpClient>,
14039 language_registry: Arc<LanguageRegistry>,
14040 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14041}
14042
14043impl LocalLspAdapterDelegate {
14044 pub fn new(
14045 language_registry: Arc<LanguageRegistry>,
14046 environment: &Entity<ProjectEnvironment>,
14047 lsp_store: WeakEntity<LspStore>,
14048 worktree: &Entity<Worktree>,
14049 http_client: Arc<dyn HttpClient>,
14050 fs: Arc<dyn Fs>,
14051 cx: &mut App,
14052 ) -> Arc<Self> {
14053 let load_shell_env_task =
14054 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14055
14056 Arc::new(Self {
14057 lsp_store,
14058 worktree: worktree.read(cx).snapshot(),
14059 fs,
14060 http_client,
14061 language_registry,
14062 load_shell_env_task,
14063 })
14064 }
14065
14066 pub fn from_local_lsp(
14067 local: &LocalLspStore,
14068 worktree: &Entity<Worktree>,
14069 cx: &mut App,
14070 ) -> Arc<Self> {
14071 Self::new(
14072 local.languages.clone(),
14073 &local.environment,
14074 local.weak.clone(),
14075 worktree,
14076 local.http_client.clone(),
14077 local.fs.clone(),
14078 cx,
14079 )
14080 }
14081}
14082
14083#[async_trait]
14084impl LspAdapterDelegate for LocalLspAdapterDelegate {
14085 fn show_notification(&self, message: &str, cx: &mut App) {
14086 self.lsp_store
14087 .update(cx, |_, cx| {
14088 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14089 })
14090 .ok();
14091 }
14092
14093 fn http_client(&self) -> Arc<dyn HttpClient> {
14094 self.http_client.clone()
14095 }
14096
14097 fn worktree_id(&self) -> WorktreeId {
14098 self.worktree.id()
14099 }
14100
14101 fn worktree_root_path(&self) -> &Path {
14102 self.worktree.abs_path().as_ref()
14103 }
14104
14105 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14106 self.worktree.resolve_relative_path(path)
14107 }
14108
14109 async fn shell_env(&self) -> HashMap<String, String> {
14110 let task = self.load_shell_env_task.clone();
14111 task.await.unwrap_or_default()
14112 }
14113
14114 async fn npm_package_installed_version(
14115 &self,
14116 package_name: &str,
14117 ) -> Result<Option<(PathBuf, Version)>> {
14118 let local_package_directory = self.worktree_root_path();
14119 let node_modules_directory = local_package_directory.join("node_modules");
14120
14121 if let Some(version) =
14122 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14123 {
14124 return Ok(Some((node_modules_directory, version)));
14125 }
14126 let Some(npm) = self.which("npm".as_ref()).await else {
14127 log::warn!(
14128 "Failed to find npm executable for {:?}",
14129 local_package_directory
14130 );
14131 return Ok(None);
14132 };
14133
14134 let env = self.shell_env().await;
14135 let output = util::command::new_command(&npm)
14136 .args(["root", "-g"])
14137 .envs(env)
14138 .current_dir(local_package_directory)
14139 .output()
14140 .await?;
14141 let global_node_modules =
14142 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14143
14144 if let Some(version) =
14145 read_package_installed_version(global_node_modules.clone(), package_name).await?
14146 {
14147 return Ok(Some((global_node_modules, version)));
14148 }
14149 return Ok(None);
14150 }
14151
14152 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14153 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14154 if self.fs.is_file(&worktree_abs_path).await {
14155 worktree_abs_path.pop();
14156 }
14157
14158 let env = self.shell_env().await;
14159
14160 let shell_path = env.get("PATH").cloned();
14161
14162 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14163 }
14164
14165 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14166 let mut working_dir = self.worktree_root_path().to_path_buf();
14167 if self.fs.is_file(&working_dir).await {
14168 working_dir.pop();
14169 }
14170 let output = util::command::new_command(&command.path)
14171 .args(command.arguments)
14172 .envs(command.env.clone().unwrap_or_default())
14173 .current_dir(working_dir)
14174 .output()
14175 .await?;
14176
14177 anyhow::ensure!(
14178 output.status.success(),
14179 "{}, stdout: {:?}, stderr: {:?}",
14180 output.status,
14181 String::from_utf8_lossy(&output.stdout),
14182 String::from_utf8_lossy(&output.stderr)
14183 );
14184 Ok(())
14185 }
14186
14187 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14188 self.language_registry
14189 .update_lsp_binary_status(server_name, status);
14190 }
14191
14192 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14193 self.language_registry
14194 .all_lsp_adapters()
14195 .into_iter()
14196 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14197 .collect()
14198 }
14199
14200 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14201 let dir = self.language_registry.language_server_download_dir(name)?;
14202
14203 if !dir.exists() {
14204 smol::fs::create_dir_all(&dir)
14205 .await
14206 .context("failed to create container directory")
14207 .log_err()?;
14208 }
14209
14210 Some(dir)
14211 }
14212
14213 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14214 let entry = self
14215 .worktree
14216 .entry_for_path(path)
14217 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14218 let abs_path = self.worktree.absolutize(&entry.path);
14219 self.fs.load(&abs_path).await
14220 }
14221}
14222
14223async fn populate_labels_for_symbols(
14224 symbols: Vec<CoreSymbol>,
14225 language_registry: &Arc<LanguageRegistry>,
14226 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14227 output: &mut Vec<Symbol>,
14228) {
14229 #[allow(clippy::mutable_key_type)]
14230 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14231
14232 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14233 for symbol in symbols {
14234 let Some(file_name) = symbol.path.file_name() else {
14235 continue;
14236 };
14237 let language = language_registry
14238 .load_language_for_file_path(Path::new(file_name))
14239 .await
14240 .ok()
14241 .or_else(|| {
14242 unknown_paths.insert(file_name.into());
14243 None
14244 });
14245 symbols_by_language
14246 .entry(language)
14247 .or_default()
14248 .push(symbol);
14249 }
14250
14251 for unknown_path in unknown_paths {
14252 log::info!("no language found for symbol in file {unknown_path:?}");
14253 }
14254
14255 let mut label_params = Vec::new();
14256 for (language, mut symbols) in symbols_by_language {
14257 label_params.clear();
14258 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14259 name: mem::take(&mut symbol.name),
14260 kind: symbol.kind,
14261 container_name: symbol.container_name.take(),
14262 }));
14263
14264 let mut labels = Vec::new();
14265 if let Some(language) = language {
14266 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14267 language_registry
14268 .lsp_adapters(&language.name())
14269 .first()
14270 .cloned()
14271 });
14272 if let Some(lsp_adapter) = lsp_adapter {
14273 labels = lsp_adapter
14274 .labels_for_symbols(&label_params, &language)
14275 .await
14276 .log_err()
14277 .unwrap_or_default();
14278 }
14279 }
14280
14281 for (
14282 (
14283 symbol,
14284 language::Symbol {
14285 name,
14286 container_name,
14287 ..
14288 },
14289 ),
14290 label,
14291 ) in symbols
14292 .into_iter()
14293 .zip(label_params.drain(..))
14294 .zip(labels.into_iter().chain(iter::repeat(None)))
14295 {
14296 output.push(Symbol {
14297 language_server_name: symbol.language_server_name,
14298 source_worktree_id: symbol.source_worktree_id,
14299 source_language_server_id: symbol.source_language_server_id,
14300 path: symbol.path,
14301 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14302 name,
14303 kind: symbol.kind,
14304 range: symbol.range,
14305 container_name,
14306 });
14307 }
14308 }
14309}
14310
14311pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14312 text.lines()
14313 .map(|line| line.trim())
14314 .filter(|line| !line.is_empty())
14315 .join(separator)
14316}
14317
14318fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14319 match server.capabilities().text_document_sync.as_ref()? {
14320 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14321 // Server wants didSave but didn't specify includeText.
14322 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14323 // Server doesn't want didSave at all.
14324 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14325 // Server provided SaveOptions.
14326 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14327 Some(save_options.include_text.unwrap_or(false))
14328 }
14329 },
14330 // We do not have any save info. Kind affects didChange only.
14331 lsp::TextDocumentSyncCapability::Kind(_) => None,
14332 }
14333}
14334
14335/// Completion items are displayed in a `UniformList`.
14336/// Usually, those items are single-line strings, but in LSP responses,
14337/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14338/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14339/// 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,
14340/// breaking the completions menu presentation.
14341///
14342/// 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.
14343pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14344 let mut new_text = String::with_capacity(label.text.len());
14345 let mut offset_map = vec![0; label.text.len() + 1];
14346 let mut last_char_was_space = false;
14347 let mut new_idx = 0;
14348 let chars = label.text.char_indices().fuse();
14349 let mut newlines_removed = false;
14350
14351 for (idx, c) in chars {
14352 offset_map[idx] = new_idx;
14353
14354 match c {
14355 '\n' if last_char_was_space => {
14356 newlines_removed = true;
14357 }
14358 '\t' | ' ' if last_char_was_space => {}
14359 '\n' if !last_char_was_space => {
14360 new_text.push(' ');
14361 new_idx += 1;
14362 last_char_was_space = true;
14363 newlines_removed = true;
14364 }
14365 ' ' | '\t' => {
14366 new_text.push(' ');
14367 new_idx += 1;
14368 last_char_was_space = true;
14369 }
14370 _ => {
14371 new_text.push(c);
14372 new_idx += c.len_utf8();
14373 last_char_was_space = false;
14374 }
14375 }
14376 }
14377 offset_map[label.text.len()] = new_idx;
14378
14379 // Only modify the label if newlines were removed.
14380 if !newlines_removed {
14381 return;
14382 }
14383
14384 let last_index = new_idx;
14385 let mut run_ranges_errors = Vec::new();
14386 label.runs.retain_mut(|(range, _)| {
14387 match offset_map.get(range.start) {
14388 Some(&start) => range.start = start,
14389 None => {
14390 run_ranges_errors.push(range.clone());
14391 return false;
14392 }
14393 }
14394
14395 match offset_map.get(range.end) {
14396 Some(&end) => range.end = end,
14397 None => {
14398 run_ranges_errors.push(range.clone());
14399 range.end = last_index;
14400 }
14401 }
14402 true
14403 });
14404 if !run_ranges_errors.is_empty() {
14405 log::error!(
14406 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14407 label.text
14408 );
14409 }
14410
14411 let mut wrong_filter_range = None;
14412 if label.filter_range == (0..label.text.len()) {
14413 label.filter_range = 0..new_text.len();
14414 } else {
14415 let mut original_filter_range = Some(label.filter_range.clone());
14416 match offset_map.get(label.filter_range.start) {
14417 Some(&start) => label.filter_range.start = start,
14418 None => {
14419 wrong_filter_range = original_filter_range.take();
14420 label.filter_range.start = last_index;
14421 }
14422 }
14423
14424 match offset_map.get(label.filter_range.end) {
14425 Some(&end) => label.filter_range.end = end,
14426 None => {
14427 wrong_filter_range = original_filter_range.take();
14428 label.filter_range.end = last_index;
14429 }
14430 }
14431 }
14432 if let Some(wrong_filter_range) = wrong_filter_range {
14433 log::error!(
14434 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14435 label.text
14436 );
14437 }
14438
14439 label.text = new_text;
14440}