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 => {
1782 adapters_and_servers.first().map(|e| e.1.clone())
1783 }
1784 };
1785
1786 let Some(language_server) = language_server else {
1787 log::debug!(
1788 "No language server found to format buffer '{:?}'. Skipping",
1789 buffer_path_abs.as_path().to_string_lossy()
1790 );
1791 continue;
1792 };
1793
1794 zlog::trace!(
1795 logger =>
1796 "Formatting buffer '{:?}' using language server '{:?}'",
1797 buffer_path_abs.as_path().to_string_lossy(),
1798 language_server.name()
1799 );
1800
1801 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1802 zlog::trace!(logger => "formatting ranges");
1803 Self::format_ranges_via_lsp(
1804 &lsp_store,
1805 &buffer.handle,
1806 ranges,
1807 buffer_path_abs,
1808 &language_server,
1809 &settings,
1810 cx,
1811 )
1812 .await
1813 .context("Failed to format ranges via language server")?
1814 } else {
1815 zlog::trace!(logger => "formatting full");
1816 Self::format_via_lsp(
1817 &lsp_store,
1818 &buffer.handle,
1819 buffer_path_abs,
1820 &language_server,
1821 &settings,
1822 cx,
1823 )
1824 .await
1825 .context("failed to format via language server")?
1826 };
1827
1828 if edits.is_empty() {
1829 zlog::trace!(logger => "No changes");
1830 continue;
1831 }
1832 extend_formatting_transaction(
1833 buffer,
1834 formatting_transaction_id,
1835 cx,
1836 |buffer, cx| {
1837 buffer.edit(edits, None, cx);
1838 },
1839 )?;
1840 }
1841 Formatter::CodeAction(code_action_name) => {
1842 let logger = zlog::scoped!(logger => "code-actions");
1843 zlog::trace!(logger => "formatting");
1844 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1845
1846 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1847 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1848 continue;
1849 };
1850
1851 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1852 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1853
1854 let mut actions_and_servers = Vec::new();
1855
1856 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1857 let actions_result = Self::get_server_code_actions_from_action_kinds(
1858 &lsp_store,
1859 language_server.server_id(),
1860 vec![code_action_kind.clone()],
1861 &buffer.handle,
1862 cx,
1863 )
1864 .await
1865 .with_context(|| {
1866 format!(
1867 "Failed to resolve code action {:?} with language server {}",
1868 code_action_kind,
1869 language_server.name()
1870 )
1871 });
1872 let Ok(actions) = actions_result else {
1873 // note: it may be better to set result to the error and break formatters here
1874 // but for now we try to execute the actions that we can resolve and skip the rest
1875 zlog::error!(
1876 logger =>
1877 "Failed to resolve code action {:?} with language server {}",
1878 code_action_kind,
1879 language_server.name()
1880 );
1881 continue;
1882 };
1883 for action in actions {
1884 actions_and_servers.push((action, index));
1885 }
1886 }
1887
1888 if actions_and_servers.is_empty() {
1889 zlog::warn!(logger => "No code actions were resolved, continuing");
1890 continue;
1891 }
1892
1893 'actions: for (mut action, server_index) in actions_and_servers {
1894 let server = &adapters_and_servers[server_index].1;
1895
1896 let describe_code_action = |action: &CodeAction| {
1897 format!(
1898 "code action '{}' with title \"{}\" on server {}",
1899 action
1900 .lsp_action
1901 .action_kind()
1902 .unwrap_or("unknown".into())
1903 .as_str(),
1904 action.lsp_action.title(),
1905 server.name(),
1906 )
1907 };
1908
1909 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1910
1911 if let Err(err) =
1912 Self::try_resolve_code_action(server, &mut action, request_timeout)
1913 .await
1914 {
1915 zlog::error!(
1916 logger =>
1917 "Failed to resolve {}. Error: {}",
1918 describe_code_action(&action),
1919 err
1920 );
1921 continue;
1922 }
1923
1924 if let Some(edit) = action.lsp_action.edit().cloned() {
1925 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1926 // but filters out and logs warnings for code actions that require unreasonably
1927 // difficult handling on our part, such as:
1928 // - applying edits that call commands
1929 // which can result in arbitrary workspace edits being sent from the server that
1930 // have no way of being tied back to the command that initiated them (i.e. we
1931 // can't know which edits are part of the format request, or if the server is done sending
1932 // actions in response to the command)
1933 // - actions that create/delete/modify/rename files other than the one we are formatting
1934 // as we then would need to handle such changes correctly in the local history as well
1935 // as the remote history through the ProjectTransaction
1936 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1937 // Supporting these actions is not impossible, but not supported as of yet.
1938 if edit.changes.is_none() && edit.document_changes.is_none() {
1939 zlog::trace!(
1940 logger =>
1941 "No changes for code action. Skipping {}",
1942 describe_code_action(&action),
1943 );
1944 continue;
1945 }
1946
1947 let mut operations = Vec::new();
1948 if let Some(document_changes) = edit.document_changes {
1949 match document_changes {
1950 lsp::DocumentChanges::Edits(edits) => operations.extend(
1951 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1952 ),
1953 lsp::DocumentChanges::Operations(ops) => operations = ops,
1954 }
1955 } else if let Some(changes) = edit.changes {
1956 operations.extend(changes.into_iter().map(|(uri, edits)| {
1957 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1958 text_document:
1959 lsp::OptionalVersionedTextDocumentIdentifier {
1960 uri,
1961 version: None,
1962 },
1963 edits: edits.into_iter().map(Edit::Plain).collect(),
1964 })
1965 }));
1966 }
1967
1968 let mut edits = Vec::with_capacity(operations.len());
1969
1970 if operations.is_empty() {
1971 zlog::trace!(
1972 logger =>
1973 "No changes for code action. Skipping {}",
1974 describe_code_action(&action),
1975 );
1976 continue;
1977 }
1978 for operation in operations {
1979 let op = match operation {
1980 lsp::DocumentChangeOperation::Edit(op) => op,
1981 lsp::DocumentChangeOperation::Op(_) => {
1982 zlog::warn!(
1983 logger =>
1984 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1985 describe_code_action(&action),
1986 );
1987 continue 'actions;
1988 }
1989 };
1990 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1991 zlog::warn!(
1992 logger =>
1993 "Failed to convert URI '{:?}' to file path. Skipping {}",
1994 &op.text_document.uri,
1995 describe_code_action(&action),
1996 );
1997 continue 'actions;
1998 };
1999 if &file_path != buffer_path_abs {
2000 zlog::warn!(
2001 logger =>
2002 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2003 file_path,
2004 buffer_path_abs,
2005 describe_code_action(&action),
2006 );
2007 continue 'actions;
2008 }
2009
2010 let mut lsp_edits = Vec::new();
2011 for edit in op.edits {
2012 match edit {
2013 Edit::Plain(edit) => {
2014 if !lsp_edits.contains(&edit) {
2015 lsp_edits.push(edit);
2016 }
2017 }
2018 Edit::Annotated(edit) => {
2019 if !lsp_edits.contains(&edit.text_edit) {
2020 lsp_edits.push(edit.text_edit);
2021 }
2022 }
2023 Edit::Snippet(_) => {
2024 zlog::warn!(
2025 logger =>
2026 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2027 describe_code_action(&action),
2028 );
2029 continue 'actions;
2030 }
2031 }
2032 }
2033 let edits_result = lsp_store
2034 .update(cx, |lsp_store, cx| {
2035 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2036 &buffer.handle,
2037 lsp_edits,
2038 server.server_id(),
2039 op.text_document.version,
2040 cx,
2041 )
2042 })?
2043 .await;
2044 let Ok(resolved_edits) = edits_result else {
2045 zlog::warn!(
2046 logger =>
2047 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2048 buffer_path_abs.as_path(),
2049 describe_code_action(&action),
2050 );
2051 continue 'actions;
2052 };
2053 edits.extend(resolved_edits);
2054 }
2055
2056 if edits.is_empty() {
2057 zlog::warn!(logger => "No edits resolved from LSP");
2058 continue;
2059 }
2060
2061 extend_formatting_transaction(
2062 buffer,
2063 formatting_transaction_id,
2064 cx,
2065 |buffer, cx| {
2066 zlog::info!(
2067 "Applying edits {edits:?}. Content: {:?}",
2068 buffer.text()
2069 );
2070 buffer.edit(edits, None, cx);
2071 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2072 },
2073 )?;
2074 }
2075
2076 // bail early if command is invalid
2077 let Some(command) = action.lsp_action.command() else {
2078 continue;
2079 };
2080
2081 zlog::warn!(
2082 logger =>
2083 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2084 &command.command,
2085 );
2086
2087 let server_capabilities = server.capabilities();
2088 let available_commands = server_capabilities
2089 .execute_command_provider
2090 .as_ref()
2091 .map(|options| options.commands.as_slice())
2092 .unwrap_or_default();
2093 if !available_commands.contains(&command.command) {
2094 zlog::warn!(
2095 logger =>
2096 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2097 command.command,
2098 server.name(),
2099 );
2100 continue;
2101 }
2102
2103 // noop so we just ensure buffer hasn't been edited since resolving code actions
2104 extend_formatting_transaction(
2105 buffer,
2106 formatting_transaction_id,
2107 cx,
2108 |_, _| {},
2109 )?;
2110 zlog::info!(logger => "Executing command {}", &command.command);
2111
2112 lsp_store.update(cx, |this, _| {
2113 this.as_local_mut()
2114 .unwrap()
2115 .last_workspace_edits_by_language_server
2116 .remove(&server.server_id());
2117 })?;
2118
2119 let execute_command_result = server
2120 .request::<lsp::request::ExecuteCommand>(
2121 lsp::ExecuteCommandParams {
2122 command: command.command.clone(),
2123 arguments: command.arguments.clone().unwrap_or_default(),
2124 ..Default::default()
2125 },
2126 request_timeout,
2127 )
2128 .await
2129 .into_response();
2130
2131 if execute_command_result.is_err() {
2132 zlog::error!(
2133 logger =>
2134 "Failed to execute command '{}' as part of {}",
2135 &command.command,
2136 describe_code_action(&action),
2137 );
2138 continue 'actions;
2139 }
2140
2141 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2142 this.as_local_mut()
2143 .unwrap()
2144 .last_workspace_edits_by_language_server
2145 .remove(&server.server_id())
2146 .unwrap_or_default()
2147 })?;
2148
2149 if let Some(transaction) =
2150 project_transaction_command.0.remove(&buffer.handle)
2151 {
2152 zlog::trace!(
2153 logger =>
2154 "Successfully captured {} edits that resulted from command {}",
2155 transaction.edit_ids.len(),
2156 &command.command,
2157 );
2158 let transaction_id_project_transaction = transaction.id;
2159 buffer.handle.update(cx, |buffer, _| {
2160 // it may have been removed from history if push_to_history was
2161 // false in deserialize_workspace_edit. If so push it so we
2162 // can merge it with the format transaction
2163 // and pop the combined transaction off the history stack
2164 // later if push_to_history is false
2165 if buffer.get_transaction(transaction.id).is_none() {
2166 buffer.push_transaction(transaction, Instant::now());
2167 }
2168 buffer.merge_transactions(
2169 transaction_id_project_transaction,
2170 formatting_transaction_id,
2171 );
2172 });
2173 }
2174
2175 if project_transaction_command.0.is_empty() {
2176 continue;
2177 }
2178
2179 let mut extra_buffers = String::new();
2180 for buffer in project_transaction_command.0.keys() {
2181 buffer.read_with(cx, |b, cx| {
2182 let Some(path) = b.project_path(cx) else {
2183 return;
2184 };
2185
2186 if !extra_buffers.is_empty() {
2187 extra_buffers.push_str(", ");
2188 }
2189 extra_buffers.push_str(path.path.as_unix_str());
2190 });
2191 }
2192 zlog::warn!(
2193 logger =>
2194 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2195 &command.command,
2196 extra_buffers,
2197 );
2198 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2199 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2200 // add it so it's included, and merge it into the format transaction when its created later
2201 }
2202 }
2203 }
2204 }
2205
2206 Ok(())
2207 }
2208
2209 pub async fn format_ranges_via_lsp(
2210 this: &WeakEntity<LspStore>,
2211 buffer_handle: &Entity<Buffer>,
2212 ranges: &[Range<Anchor>],
2213 abs_path: &Path,
2214 language_server: &Arc<LanguageServer>,
2215 settings: &LanguageSettings,
2216 cx: &mut AsyncApp,
2217 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2218 let capabilities = &language_server.capabilities();
2219 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2220 if range_formatting_provider == Some(&OneOf::Left(false)) {
2221 anyhow::bail!(
2222 "{} language server does not support range formatting",
2223 language_server.name()
2224 );
2225 }
2226
2227 let uri = file_path_to_lsp_url(abs_path)?;
2228 let text_document = lsp::TextDocumentIdentifier::new(uri);
2229
2230 let request_timeout = cx.update(|app| {
2231 ProjectSettings::get_global(app)
2232 .global_lsp_settings
2233 .get_request_timeout()
2234 });
2235 let lsp_edits = {
2236 let mut lsp_ranges = Vec::new();
2237 this.update(cx, |_this, cx| {
2238 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2239 // not have been sent to the language server. This seems like a fairly systemic
2240 // issue, though, the resolution probably is not specific to formatting.
2241 //
2242 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2243 // LSP.
2244 let snapshot = buffer_handle.read(cx).snapshot();
2245 for range in ranges {
2246 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2247 }
2248 anyhow::Ok(())
2249 })??;
2250
2251 let mut edits = None;
2252 for range in lsp_ranges {
2253 if let Some(mut edit) = language_server
2254 .request::<lsp::request::RangeFormatting>(
2255 lsp::DocumentRangeFormattingParams {
2256 text_document: text_document.clone(),
2257 range,
2258 options: lsp_command::lsp_formatting_options(settings),
2259 work_done_progress_params: Default::default(),
2260 },
2261 request_timeout,
2262 )
2263 .await
2264 .into_response()?
2265 {
2266 edits.get_or_insert_with(Vec::new).append(&mut edit);
2267 }
2268 }
2269 edits
2270 };
2271
2272 if let Some(lsp_edits) = lsp_edits {
2273 this.update(cx, |this, cx| {
2274 this.as_local_mut().unwrap().edits_from_lsp(
2275 buffer_handle,
2276 lsp_edits,
2277 language_server.server_id(),
2278 None,
2279 cx,
2280 )
2281 })?
2282 .await
2283 } else {
2284 Ok(Vec::with_capacity(0))
2285 }
2286 }
2287
2288 async fn format_via_lsp(
2289 this: &WeakEntity<LspStore>,
2290 buffer: &Entity<Buffer>,
2291 abs_path: &Path,
2292 language_server: &Arc<LanguageServer>,
2293 settings: &LanguageSettings,
2294 cx: &mut AsyncApp,
2295 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2296 let logger = zlog::scoped!("lsp_format");
2297 zlog::debug!(logger => "Formatting via LSP");
2298
2299 let uri = file_path_to_lsp_url(abs_path)?;
2300 let text_document = lsp::TextDocumentIdentifier::new(uri);
2301 let capabilities = &language_server.capabilities();
2302
2303 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2304 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2305
2306 let request_timeout = cx.update(|app| {
2307 ProjectSettings::get_global(app)
2308 .global_lsp_settings
2309 .get_request_timeout()
2310 });
2311
2312 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2313 let _timer = zlog::time!(logger => "format-full");
2314 language_server
2315 .request::<lsp::request::Formatting>(
2316 lsp::DocumentFormattingParams {
2317 text_document,
2318 options: lsp_command::lsp_formatting_options(settings),
2319 work_done_progress_params: Default::default(),
2320 },
2321 request_timeout,
2322 )
2323 .await
2324 .into_response()?
2325 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2326 let _timer = zlog::time!(logger => "format-range");
2327 let buffer_start = lsp::Position::new(0, 0);
2328 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2329 language_server
2330 .request::<lsp::request::RangeFormatting>(
2331 lsp::DocumentRangeFormattingParams {
2332 text_document: text_document.clone(),
2333 range: lsp::Range::new(buffer_start, buffer_end),
2334 options: lsp_command::lsp_formatting_options(settings),
2335 work_done_progress_params: Default::default(),
2336 },
2337 request_timeout,
2338 )
2339 .await
2340 .into_response()?
2341 } else {
2342 None
2343 };
2344
2345 if let Some(lsp_edits) = lsp_edits {
2346 this.update(cx, |this, cx| {
2347 this.as_local_mut().unwrap().edits_from_lsp(
2348 buffer,
2349 lsp_edits,
2350 language_server.server_id(),
2351 None,
2352 cx,
2353 )
2354 })?
2355 .await
2356 } else {
2357 Ok(Vec::with_capacity(0))
2358 }
2359 }
2360
2361 async fn format_via_external_command(
2362 buffer: &FormattableBuffer,
2363 command: &str,
2364 arguments: Option<&[String]>,
2365 cx: &mut AsyncApp,
2366 ) -> Result<Option<Diff>> {
2367 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2368 let file = File::from_dyn(buffer.file())?;
2369 let worktree = file.worktree.read(cx);
2370 let mut worktree_path = worktree.abs_path().to_path_buf();
2371 if worktree.root_entry()?.is_file() {
2372 worktree_path.pop();
2373 }
2374 Some(worktree_path)
2375 });
2376
2377 use util::command::Stdio;
2378 let mut child = util::command::new_command(command);
2379
2380 if let Some(buffer_env) = buffer.env.as_ref() {
2381 child.envs(buffer_env);
2382 }
2383
2384 if let Some(working_dir_path) = working_dir_path {
2385 child.current_dir(working_dir_path);
2386 }
2387
2388 if let Some(arguments) = arguments {
2389 child.args(arguments.iter().map(|arg| {
2390 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2391 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2392 } else {
2393 arg.replace("{buffer_path}", "Untitled")
2394 }
2395 }));
2396 }
2397
2398 let mut child = child
2399 .stdin(Stdio::piped())
2400 .stdout(Stdio::piped())
2401 .stderr(Stdio::piped())
2402 .spawn()?;
2403
2404 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2405 let text = buffer
2406 .handle
2407 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2408 for chunk in text.chunks() {
2409 stdin.write_all(chunk.as_bytes()).await?;
2410 }
2411 stdin.flush().await?;
2412
2413 let output = child.output().await?;
2414 anyhow::ensure!(
2415 output.status.success(),
2416 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2417 output.status.code(),
2418 String::from_utf8_lossy(&output.stdout),
2419 String::from_utf8_lossy(&output.stderr),
2420 );
2421
2422 let stdout = String::from_utf8(output.stdout)?;
2423 Ok(Some(
2424 buffer
2425 .handle
2426 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2427 .await,
2428 ))
2429 }
2430
2431 async fn try_resolve_code_action(
2432 lang_server: &LanguageServer,
2433 action: &mut CodeAction,
2434 request_timeout: Duration,
2435 ) -> anyhow::Result<()> {
2436 match &mut action.lsp_action {
2437 LspAction::Action(lsp_action) => {
2438 if !action.resolved
2439 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2440 && lsp_action.data.is_some()
2441 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2442 {
2443 **lsp_action = lang_server
2444 .request::<lsp::request::CodeActionResolveRequest>(
2445 *lsp_action.clone(),
2446 request_timeout,
2447 )
2448 .await
2449 .into_response()?;
2450 }
2451 }
2452 LspAction::CodeLens(lens) => {
2453 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2454 *lens = lang_server
2455 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2456 .await
2457 .into_response()?;
2458 }
2459 }
2460 LspAction::Command(_) => {}
2461 }
2462
2463 action.resolved = true;
2464 anyhow::Ok(())
2465 }
2466
2467 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2468 let buffer = buffer_handle.read(cx);
2469
2470 let file = buffer.file().cloned();
2471
2472 let Some(file) = File::from_dyn(file.as_ref()) else {
2473 return;
2474 };
2475 if !file.is_local() {
2476 return;
2477 }
2478 let path = ProjectPath::from_file(file, cx);
2479 let worktree_id = file.worktree_id(cx);
2480 let language = buffer.language().cloned();
2481
2482 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2483 for (server_id, diagnostics) in
2484 diagnostics.get(file.path()).cloned().unwrap_or_default()
2485 {
2486 self.update_buffer_diagnostics(
2487 buffer_handle,
2488 server_id,
2489 None,
2490 None,
2491 None,
2492 Vec::new(),
2493 diagnostics,
2494 cx,
2495 )
2496 .log_err();
2497 }
2498 }
2499 let Some(language) = language else {
2500 return;
2501 };
2502 let Some(snapshot) = self
2503 .worktree_store
2504 .read(cx)
2505 .worktree_for_id(worktree_id, cx)
2506 .map(|worktree| worktree.read(cx).snapshot())
2507 else {
2508 return;
2509 };
2510 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2511
2512 for server_id in
2513 self.lsp_tree
2514 .get(path, language.name(), language.manifest(), &delegate, cx)
2515 {
2516 let server = self
2517 .language_servers
2518 .get(&server_id)
2519 .and_then(|server_state| {
2520 if let LanguageServerState::Running { server, .. } = server_state {
2521 Some(server.clone())
2522 } else {
2523 None
2524 }
2525 });
2526 let server = match server {
2527 Some(server) => server,
2528 None => continue,
2529 };
2530
2531 buffer_handle.update(cx, |buffer, cx| {
2532 buffer.set_completion_triggers(
2533 server.server_id(),
2534 server
2535 .capabilities()
2536 .completion_provider
2537 .as_ref()
2538 .and_then(|provider| {
2539 provider
2540 .trigger_characters
2541 .as_ref()
2542 .map(|characters| characters.iter().cloned().collect())
2543 })
2544 .unwrap_or_default(),
2545 cx,
2546 );
2547 });
2548 }
2549 }
2550
2551 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2552 buffer.update(cx, |buffer, cx| {
2553 let Some(language) = buffer.language() else {
2554 return;
2555 };
2556 let path = ProjectPath {
2557 worktree_id: old_file.worktree_id(cx),
2558 path: old_file.path.clone(),
2559 };
2560 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2561 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2562 buffer.set_completion_triggers(server_id, Default::default(), cx);
2563 }
2564 });
2565 }
2566
2567 fn update_buffer_diagnostics(
2568 &mut self,
2569 buffer: &Entity<Buffer>,
2570 server_id: LanguageServerId,
2571 registration_id: Option<Option<SharedString>>,
2572 result_id: Option<SharedString>,
2573 version: Option<i32>,
2574 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2575 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2576 cx: &mut Context<LspStore>,
2577 ) -> Result<()> {
2578 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2579 Ordering::Equal
2580 .then_with(|| b.is_primary.cmp(&a.is_primary))
2581 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2582 .then_with(|| a.severity.cmp(&b.severity))
2583 .then_with(|| a.message.cmp(&b.message))
2584 }
2585
2586 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2587 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2588 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2589
2590 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2591 Ordering::Equal
2592 .then_with(|| a.range.start.cmp(&b.range.start))
2593 .then_with(|| b.range.end.cmp(&a.range.end))
2594 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2595 });
2596
2597 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2598
2599 let edits_since_save = std::cell::LazyCell::new(|| {
2600 let saved_version = buffer.read(cx).saved_version();
2601 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2602 });
2603
2604 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2605
2606 for (new_diagnostic, entry) in diagnostics {
2607 let start;
2608 let end;
2609 if new_diagnostic && entry.diagnostic.is_disk_based {
2610 // Some diagnostics are based on files on disk instead of buffers'
2611 // current contents. Adjust these diagnostics' ranges to reflect
2612 // any unsaved edits.
2613 // Do not alter the reused ones though, as their coordinates were stored as anchors
2614 // and were properly adjusted on reuse.
2615 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2616 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2617 } else {
2618 start = entry.range.start;
2619 end = entry.range.end;
2620 }
2621
2622 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2623 ..snapshot.clip_point_utf16(end, Bias::Right);
2624
2625 // Expand empty ranges by one codepoint
2626 if range.start == range.end {
2627 // This will be go to the next boundary when being clipped
2628 range.end.column += 1;
2629 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2630 if range.start == range.end && range.end.column > 0 {
2631 range.start.column -= 1;
2632 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2633 }
2634 }
2635
2636 sanitized_diagnostics.push(DiagnosticEntry {
2637 range,
2638 diagnostic: entry.diagnostic,
2639 });
2640 }
2641 drop(edits_since_save);
2642
2643 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2644 buffer.update(cx, |buffer, cx| {
2645 if let Some(registration_id) = registration_id {
2646 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2647 self.buffer_pull_diagnostics_result_ids
2648 .entry(server_id)
2649 .or_default()
2650 .entry(registration_id)
2651 .or_default()
2652 .insert(abs_path, result_id);
2653 }
2654 }
2655
2656 buffer.update_diagnostics(server_id, set, cx)
2657 });
2658
2659 Ok(())
2660 }
2661
2662 fn register_language_server_for_invisible_worktree(
2663 &mut self,
2664 worktree: &Entity<Worktree>,
2665 language_server_id: LanguageServerId,
2666 cx: &mut App,
2667 ) {
2668 let worktree = worktree.read(cx);
2669 let worktree_id = worktree.id();
2670 debug_assert!(!worktree.is_visible());
2671 let Some(mut origin_seed) = self
2672 .language_server_ids
2673 .iter()
2674 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2675 else {
2676 return;
2677 };
2678 origin_seed.worktree_id = worktree_id;
2679 self.language_server_ids
2680 .entry(origin_seed)
2681 .or_insert_with(|| UnifiedLanguageServer {
2682 id: language_server_id,
2683 project_roots: Default::default(),
2684 });
2685 }
2686
2687 fn register_buffer_with_language_servers(
2688 &mut self,
2689 buffer_handle: &Entity<Buffer>,
2690 only_register_servers: HashSet<LanguageServerSelector>,
2691 cx: &mut Context<LspStore>,
2692 ) {
2693 let buffer = buffer_handle.read(cx);
2694 let buffer_id = buffer.remote_id();
2695
2696 let Some(file) = File::from_dyn(buffer.file()) else {
2697 return;
2698 };
2699 if !file.is_local() {
2700 return;
2701 }
2702
2703 let abs_path = file.abs_path(cx);
2704 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2705 return;
2706 };
2707 let initial_snapshot = buffer.text_snapshot();
2708 let worktree_id = file.worktree_id(cx);
2709
2710 let Some(language) = buffer.language().cloned() else {
2711 return;
2712 };
2713 let path: Arc<RelPath> = file
2714 .path()
2715 .parent()
2716 .map(Arc::from)
2717 .unwrap_or_else(|| file.path().clone());
2718 let Some(worktree) = self
2719 .worktree_store
2720 .read(cx)
2721 .worktree_for_id(worktree_id, cx)
2722 else {
2723 return;
2724 };
2725 let language_name = language.name();
2726 let (reused, delegate, servers) = self
2727 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2728 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2729 .unwrap_or_else(|| {
2730 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2731 let delegate: Arc<dyn ManifestDelegate> =
2732 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2733
2734 let servers = self
2735 .lsp_tree
2736 .walk(
2737 ProjectPath { worktree_id, path },
2738 language.name(),
2739 language.manifest(),
2740 &delegate,
2741 cx,
2742 )
2743 .collect::<Vec<_>>();
2744 (false, lsp_delegate, servers)
2745 });
2746 let servers_and_adapters = servers
2747 .into_iter()
2748 .filter_map(|server_node| {
2749 if reused && server_node.server_id().is_none() {
2750 return None;
2751 }
2752 if !only_register_servers.is_empty() {
2753 if let Some(server_id) = server_node.server_id()
2754 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2755 {
2756 return None;
2757 }
2758 if let Some(name) = server_node.name()
2759 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2760 {
2761 return None;
2762 }
2763 }
2764
2765 let server_id = server_node.server_id_or_init(|disposition| {
2766 let path = &disposition.path;
2767
2768 {
2769 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2770
2771 let server_id = self.get_or_insert_language_server(
2772 &worktree,
2773 delegate.clone(),
2774 disposition,
2775 &language_name,
2776 cx,
2777 );
2778
2779 if let Some(state) = self.language_servers.get(&server_id)
2780 && let Ok(uri) = uri
2781 {
2782 state.add_workspace_folder(uri);
2783 };
2784 server_id
2785 }
2786 })?;
2787 let server_state = self.language_servers.get(&server_id)?;
2788 if let LanguageServerState::Running {
2789 server, adapter, ..
2790 } = server_state
2791 {
2792 Some((server.clone(), adapter.clone()))
2793 } else {
2794 None
2795 }
2796 })
2797 .collect::<Vec<_>>();
2798 for (server, adapter) in servers_and_adapters {
2799 buffer_handle.update(cx, |buffer, cx| {
2800 buffer.set_completion_triggers(
2801 server.server_id(),
2802 server
2803 .capabilities()
2804 .completion_provider
2805 .as_ref()
2806 .and_then(|provider| {
2807 provider
2808 .trigger_characters
2809 .as_ref()
2810 .map(|characters| characters.iter().cloned().collect())
2811 })
2812 .unwrap_or_default(),
2813 cx,
2814 );
2815 });
2816
2817 let snapshot = LspBufferSnapshot {
2818 version: 0,
2819 snapshot: initial_snapshot.clone(),
2820 };
2821
2822 let mut registered = false;
2823 self.buffer_snapshots
2824 .entry(buffer_id)
2825 .or_default()
2826 .entry(server.server_id())
2827 .or_insert_with(|| {
2828 registered = true;
2829 server.register_buffer(
2830 uri.clone(),
2831 adapter.language_id(&language.name()),
2832 0,
2833 initial_snapshot.text(),
2834 );
2835
2836 vec![snapshot]
2837 });
2838
2839 self.buffers_opened_in_servers
2840 .entry(buffer_id)
2841 .or_default()
2842 .insert(server.server_id());
2843 if registered {
2844 cx.emit(LspStoreEvent::LanguageServerUpdate {
2845 language_server_id: server.server_id(),
2846 name: None,
2847 message: proto::update_language_server::Variant::RegisteredForBuffer(
2848 proto::RegisteredForBuffer {
2849 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2850 buffer_id: buffer_id.to_proto(),
2851 },
2852 ),
2853 });
2854 }
2855 }
2856 }
2857
2858 fn reuse_existing_language_server<'lang_name>(
2859 &self,
2860 server_tree: &LanguageServerTree,
2861 worktree: &Entity<Worktree>,
2862 language_name: &'lang_name LanguageName,
2863 cx: &mut App,
2864 ) -> Option<(
2865 Arc<LocalLspAdapterDelegate>,
2866 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2867 )> {
2868 if worktree.read(cx).is_visible() {
2869 return None;
2870 }
2871
2872 let worktree_store = self.worktree_store.read(cx);
2873 let servers = server_tree
2874 .instances
2875 .iter()
2876 .filter(|(worktree_id, _)| {
2877 worktree_store
2878 .worktree_for_id(**worktree_id, cx)
2879 .is_some_and(|worktree| worktree.read(cx).is_visible())
2880 })
2881 .flat_map(|(worktree_id, servers)| {
2882 servers
2883 .roots
2884 .iter()
2885 .flat_map(|(_, language_servers)| language_servers)
2886 .map(move |(_, (server_node, server_languages))| {
2887 (worktree_id, server_node, server_languages)
2888 })
2889 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2890 .map(|(worktree_id, server_node, _)| {
2891 (
2892 *worktree_id,
2893 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2894 )
2895 })
2896 })
2897 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2898 acc.entry(worktree_id)
2899 .or_insert_with(Vec::new)
2900 .push(server_node);
2901 acc
2902 })
2903 .into_values()
2904 .max_by_key(|servers| servers.len())?;
2905
2906 let worktree_id = worktree.read(cx).id();
2907 let apply = move |tree: &mut LanguageServerTree| {
2908 for server_node in &servers {
2909 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2910 }
2911 servers
2912 };
2913
2914 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2915 Some((delegate, apply))
2916 }
2917
2918 pub(crate) fn unregister_old_buffer_from_language_servers(
2919 &mut self,
2920 buffer: &Entity<Buffer>,
2921 old_file: &File,
2922 cx: &mut App,
2923 ) {
2924 let old_path = match old_file.as_local() {
2925 Some(local) => local.abs_path(cx),
2926 None => return,
2927 };
2928
2929 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2930 debug_panic!("{old_path:?} is not parseable as an URI");
2931 return;
2932 };
2933 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2934 }
2935
2936 pub(crate) fn unregister_buffer_from_language_servers(
2937 &mut self,
2938 buffer: &Entity<Buffer>,
2939 file_url: &lsp::Uri,
2940 cx: &mut App,
2941 ) {
2942 buffer.update(cx, |buffer, cx| {
2943 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2944
2945 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2946 if snapshots
2947 .as_mut()
2948 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2949 {
2950 language_server.unregister_buffer(file_url.clone());
2951 }
2952 }
2953 });
2954 }
2955
2956 fn buffer_snapshot_for_lsp_version(
2957 &mut self,
2958 buffer: &Entity<Buffer>,
2959 server_id: LanguageServerId,
2960 version: Option<i32>,
2961 cx: &App,
2962 ) -> Result<TextBufferSnapshot> {
2963 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2964
2965 if let Some(version) = version {
2966 let buffer_id = buffer.read(cx).remote_id();
2967 let snapshots = if let Some(snapshots) = self
2968 .buffer_snapshots
2969 .get_mut(&buffer_id)
2970 .and_then(|m| m.get_mut(&server_id))
2971 {
2972 snapshots
2973 } else if version == 0 {
2974 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2975 // We detect this case and treat it as if the version was `None`.
2976 return Ok(buffer.read(cx).text_snapshot());
2977 } else {
2978 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2979 };
2980
2981 let found_snapshot = snapshots
2982 .binary_search_by_key(&version, |e| e.version)
2983 .map(|ix| snapshots[ix].snapshot.clone())
2984 .map_err(|_| {
2985 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2986 })?;
2987
2988 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2989 Ok(found_snapshot)
2990 } else {
2991 Ok((buffer.read(cx)).text_snapshot())
2992 }
2993 }
2994
2995 async fn get_server_code_actions_from_action_kinds(
2996 lsp_store: &WeakEntity<LspStore>,
2997 language_server_id: LanguageServerId,
2998 code_action_kinds: Vec<lsp::CodeActionKind>,
2999 buffer: &Entity<Buffer>,
3000 cx: &mut AsyncApp,
3001 ) -> Result<Vec<CodeAction>> {
3002 let actions = lsp_store
3003 .update(cx, move |this, cx| {
3004 let request = GetCodeActions {
3005 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3006 kinds: Some(code_action_kinds),
3007 };
3008 let server = LanguageServerToQuery::Other(language_server_id);
3009 this.request_lsp(buffer.clone(), server, request, cx)
3010 })?
3011 .await?;
3012 Ok(actions)
3013 }
3014
3015 pub async fn execute_code_actions_on_server(
3016 lsp_store: &WeakEntity<LspStore>,
3017 language_server: &Arc<LanguageServer>,
3018 actions: Vec<CodeAction>,
3019 push_to_history: bool,
3020 project_transaction: &mut ProjectTransaction,
3021 cx: &mut AsyncApp,
3022 ) -> anyhow::Result<()> {
3023 let request_timeout = cx.update(|app| {
3024 ProjectSettings::get_global(app)
3025 .global_lsp_settings
3026 .get_request_timeout()
3027 });
3028
3029 for mut action in actions {
3030 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3031 .await
3032 .context("resolving a formatting code action")?;
3033
3034 if let Some(edit) = action.lsp_action.edit() {
3035 if edit.changes.is_none() && edit.document_changes.is_none() {
3036 continue;
3037 }
3038
3039 let new = Self::deserialize_workspace_edit(
3040 lsp_store.upgrade().context("project dropped")?,
3041 edit.clone(),
3042 push_to_history,
3043 language_server.clone(),
3044 cx,
3045 )
3046 .await?;
3047 project_transaction.0.extend(new.0);
3048 }
3049
3050 let Some(command) = action.lsp_action.command() else {
3051 continue;
3052 };
3053
3054 let server_capabilities = language_server.capabilities();
3055 let available_commands = server_capabilities
3056 .execute_command_provider
3057 .as_ref()
3058 .map(|options| options.commands.as_slice())
3059 .unwrap_or_default();
3060 if !available_commands.contains(&command.command) {
3061 log::warn!(
3062 "Cannot execute a command {} not listed in the language server capabilities",
3063 command.command
3064 );
3065 continue;
3066 }
3067
3068 lsp_store.update(cx, |lsp_store, _| {
3069 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3070 mode.last_workspace_edits_by_language_server
3071 .remove(&language_server.server_id());
3072 }
3073 })?;
3074
3075 language_server
3076 .request::<lsp::request::ExecuteCommand>(
3077 lsp::ExecuteCommandParams {
3078 command: command.command.clone(),
3079 arguments: command.arguments.clone().unwrap_or_default(),
3080 ..Default::default()
3081 },
3082 request_timeout,
3083 )
3084 .await
3085 .into_response()
3086 .context("execute command")?;
3087
3088 lsp_store.update(cx, |this, _| {
3089 if let LspStoreMode::Local(mode) = &mut this.mode {
3090 project_transaction.0.extend(
3091 mode.last_workspace_edits_by_language_server
3092 .remove(&language_server.server_id())
3093 .unwrap_or_default()
3094 .0,
3095 )
3096 }
3097 })?;
3098 }
3099 Ok(())
3100 }
3101
3102 pub async fn deserialize_text_edits(
3103 this: Entity<LspStore>,
3104 buffer_to_edit: Entity<Buffer>,
3105 edits: Vec<lsp::TextEdit>,
3106 push_to_history: bool,
3107 _: Arc<CachedLspAdapter>,
3108 language_server: Arc<LanguageServer>,
3109 cx: &mut AsyncApp,
3110 ) -> Result<Option<Transaction>> {
3111 let edits = this
3112 .update(cx, |this, cx| {
3113 this.as_local_mut().unwrap().edits_from_lsp(
3114 &buffer_to_edit,
3115 edits,
3116 language_server.server_id(),
3117 None,
3118 cx,
3119 )
3120 })
3121 .await?;
3122
3123 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3124 buffer.finalize_last_transaction();
3125 buffer.start_transaction();
3126 for (range, text) in edits {
3127 buffer.edit([(range, text)], None, cx);
3128 }
3129
3130 if buffer.end_transaction(cx).is_some() {
3131 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3132 if !push_to_history {
3133 buffer.forget_transaction(transaction.id);
3134 }
3135 Some(transaction)
3136 } else {
3137 None
3138 }
3139 });
3140
3141 Ok(transaction)
3142 }
3143
3144 #[allow(clippy::type_complexity)]
3145 pub fn edits_from_lsp(
3146 &mut self,
3147 buffer: &Entity<Buffer>,
3148 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3149 server_id: LanguageServerId,
3150 version: Option<i32>,
3151 cx: &mut Context<LspStore>,
3152 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3153 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3154 cx.background_spawn(async move {
3155 let snapshot = snapshot?;
3156 let mut lsp_edits = lsp_edits
3157 .into_iter()
3158 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3159 .collect::<Vec<_>>();
3160
3161 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3162
3163 let mut lsp_edits = lsp_edits.into_iter().peekable();
3164 let mut edits = Vec::new();
3165 while let Some((range, mut new_text)) = lsp_edits.next() {
3166 // Clip invalid ranges provided by the language server.
3167 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3168 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3169
3170 // Combine any LSP edits that are adjacent.
3171 //
3172 // Also, combine LSP edits that are separated from each other by only
3173 // a newline. This is important because for some code actions,
3174 // Rust-analyzer rewrites the entire buffer via a series of edits that
3175 // are separated by unchanged newline characters.
3176 //
3177 // In order for the diffing logic below to work properly, any edits that
3178 // cancel each other out must be combined into one.
3179 while let Some((next_range, next_text)) = lsp_edits.peek() {
3180 if next_range.start.0 > range.end {
3181 if next_range.start.0.row > range.end.row + 1
3182 || next_range.start.0.column > 0
3183 || snapshot.clip_point_utf16(
3184 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3185 Bias::Left,
3186 ) > range.end
3187 {
3188 break;
3189 }
3190 new_text.push('\n');
3191 }
3192 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3193 new_text.push_str(next_text);
3194 lsp_edits.next();
3195 }
3196
3197 // For multiline edits, perform a diff of the old and new text so that
3198 // we can identify the changes more precisely, preserving the locations
3199 // of any anchors positioned in the unchanged regions.
3200 if range.end.row > range.start.row {
3201 let offset = range.start.to_offset(&snapshot);
3202 let old_text = snapshot.text_for_range(range).collect::<String>();
3203 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3204 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3205 (
3206 snapshot.anchor_after(offset + range.start)
3207 ..snapshot.anchor_before(offset + range.end),
3208 replacement,
3209 )
3210 }));
3211 } else if range.end == range.start {
3212 let anchor = snapshot.anchor_after(range.start);
3213 edits.push((anchor..anchor, new_text.into()));
3214 } else {
3215 let edit_start = snapshot.anchor_after(range.start);
3216 let edit_end = snapshot.anchor_before(range.end);
3217 edits.push((edit_start..edit_end, new_text.into()));
3218 }
3219 }
3220
3221 Ok(edits)
3222 })
3223 }
3224
3225 pub(crate) async fn deserialize_workspace_edit(
3226 this: Entity<LspStore>,
3227 edit: lsp::WorkspaceEdit,
3228 push_to_history: bool,
3229 language_server: Arc<LanguageServer>,
3230 cx: &mut AsyncApp,
3231 ) -> Result<ProjectTransaction> {
3232 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3233
3234 let mut operations = Vec::new();
3235 if let Some(document_changes) = edit.document_changes {
3236 match document_changes {
3237 lsp::DocumentChanges::Edits(edits) => {
3238 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3239 }
3240 lsp::DocumentChanges::Operations(ops) => operations = ops,
3241 }
3242 } else if let Some(changes) = edit.changes {
3243 operations.extend(changes.into_iter().map(|(uri, edits)| {
3244 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3245 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3246 uri,
3247 version: None,
3248 },
3249 edits: edits.into_iter().map(Edit::Plain).collect(),
3250 })
3251 }));
3252 }
3253
3254 let mut project_transaction = ProjectTransaction::default();
3255 for operation in operations {
3256 match operation {
3257 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3258 let abs_path = op
3259 .uri
3260 .to_file_path()
3261 .map_err(|()| anyhow!("can't convert URI to path"))?;
3262
3263 if let Some(parent_path) = abs_path.parent() {
3264 fs.create_dir(parent_path).await?;
3265 }
3266 if abs_path.ends_with("/") {
3267 fs.create_dir(&abs_path).await?;
3268 } else {
3269 fs.create_file(
3270 &abs_path,
3271 op.options
3272 .map(|options| fs::CreateOptions {
3273 overwrite: options.overwrite.unwrap_or(false),
3274 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3275 })
3276 .unwrap_or_default(),
3277 )
3278 .await?;
3279 }
3280 }
3281
3282 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3283 let source_abs_path = op
3284 .old_uri
3285 .to_file_path()
3286 .map_err(|()| anyhow!("can't convert URI to path"))?;
3287 let target_abs_path = op
3288 .new_uri
3289 .to_file_path()
3290 .map_err(|()| anyhow!("can't convert URI to path"))?;
3291
3292 let options = fs::RenameOptions {
3293 overwrite: op
3294 .options
3295 .as_ref()
3296 .and_then(|options| options.overwrite)
3297 .unwrap_or(false),
3298 ignore_if_exists: op
3299 .options
3300 .as_ref()
3301 .and_then(|options| options.ignore_if_exists)
3302 .unwrap_or(false),
3303 create_parents: true,
3304 };
3305
3306 fs.rename(&source_abs_path, &target_abs_path, options)
3307 .await?;
3308 }
3309
3310 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3311 let abs_path = op
3312 .uri
3313 .to_file_path()
3314 .map_err(|()| anyhow!("can't convert URI to path"))?;
3315 let options = op
3316 .options
3317 .map(|options| fs::RemoveOptions {
3318 recursive: options.recursive.unwrap_or(false),
3319 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3320 })
3321 .unwrap_or_default();
3322 if abs_path.ends_with("/") {
3323 fs.remove_dir(&abs_path, options).await?;
3324 } else {
3325 fs.remove_file(&abs_path, options).await?;
3326 }
3327 }
3328
3329 lsp::DocumentChangeOperation::Edit(op) => {
3330 let buffer_to_edit = this
3331 .update(cx, |this, cx| {
3332 this.open_local_buffer_via_lsp(
3333 op.text_document.uri.clone(),
3334 language_server.server_id(),
3335 cx,
3336 )
3337 })
3338 .await?;
3339
3340 let edits = this
3341 .update(cx, |this, cx| {
3342 let path = buffer_to_edit.read(cx).project_path(cx);
3343 let active_entry = this.active_entry;
3344 let is_active_entry = path.is_some_and(|project_path| {
3345 this.worktree_store
3346 .read(cx)
3347 .entry_for_path(&project_path, cx)
3348 .is_some_and(|entry| Some(entry.id) == active_entry)
3349 });
3350 let local = this.as_local_mut().unwrap();
3351
3352 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3353 for edit in op.edits {
3354 match edit {
3355 Edit::Plain(edit) => {
3356 if !edits.contains(&edit) {
3357 edits.push(edit)
3358 }
3359 }
3360 Edit::Annotated(edit) => {
3361 if !edits.contains(&edit.text_edit) {
3362 edits.push(edit.text_edit)
3363 }
3364 }
3365 Edit::Snippet(edit) => {
3366 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3367 else {
3368 continue;
3369 };
3370
3371 if is_active_entry {
3372 snippet_edits.push((edit.range, snippet));
3373 } else {
3374 // Since this buffer is not focused, apply a normal edit.
3375 let new_edit = TextEdit {
3376 range: edit.range,
3377 new_text: snippet.text,
3378 };
3379 if !edits.contains(&new_edit) {
3380 edits.push(new_edit);
3381 }
3382 }
3383 }
3384 }
3385 }
3386 if !snippet_edits.is_empty() {
3387 let buffer_id = buffer_to_edit.read(cx).remote_id();
3388 let version = if let Some(buffer_version) = op.text_document.version
3389 {
3390 local
3391 .buffer_snapshot_for_lsp_version(
3392 &buffer_to_edit,
3393 language_server.server_id(),
3394 Some(buffer_version),
3395 cx,
3396 )
3397 .ok()
3398 .map(|snapshot| snapshot.version)
3399 } else {
3400 Some(buffer_to_edit.read(cx).saved_version().clone())
3401 };
3402
3403 let most_recent_edit =
3404 version.and_then(|version| version.most_recent());
3405 // Check if the edit that triggered that edit has been made by this participant.
3406
3407 if let Some(most_recent_edit) = most_recent_edit {
3408 cx.emit(LspStoreEvent::SnippetEdit {
3409 buffer_id,
3410 edits: snippet_edits,
3411 most_recent_edit,
3412 });
3413 }
3414 }
3415
3416 local.edits_from_lsp(
3417 &buffer_to_edit,
3418 edits,
3419 language_server.server_id(),
3420 op.text_document.version,
3421 cx,
3422 )
3423 })
3424 .await?;
3425
3426 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3427 buffer.finalize_last_transaction();
3428 buffer.start_transaction();
3429 for (range, text) in edits {
3430 buffer.edit([(range, text)], None, cx);
3431 }
3432
3433 buffer.end_transaction(cx).and_then(|transaction_id| {
3434 if push_to_history {
3435 buffer.finalize_last_transaction();
3436 buffer.get_transaction(transaction_id).cloned()
3437 } else {
3438 buffer.forget_transaction(transaction_id)
3439 }
3440 })
3441 });
3442 if let Some(transaction) = transaction {
3443 project_transaction.0.insert(buffer_to_edit, transaction);
3444 }
3445 }
3446 }
3447 }
3448
3449 Ok(project_transaction)
3450 }
3451
3452 async fn on_lsp_workspace_edit(
3453 this: WeakEntity<LspStore>,
3454 params: lsp::ApplyWorkspaceEditParams,
3455 server_id: LanguageServerId,
3456 cx: &mut AsyncApp,
3457 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3458 let this = this.upgrade().context("project project closed")?;
3459 let language_server = this
3460 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3461 .context("language server not found")?;
3462 let transaction = Self::deserialize_workspace_edit(
3463 this.clone(),
3464 params.edit,
3465 true,
3466 language_server.clone(),
3467 cx,
3468 )
3469 .await
3470 .log_err();
3471 this.update(cx, |this, cx| {
3472 if let Some(transaction) = transaction {
3473 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3474
3475 this.as_local_mut()
3476 .unwrap()
3477 .last_workspace_edits_by_language_server
3478 .insert(server_id, transaction);
3479 }
3480 });
3481 Ok(lsp::ApplyWorkspaceEditResponse {
3482 applied: true,
3483 failed_change: None,
3484 failure_reason: None,
3485 })
3486 }
3487
3488 fn remove_worktree(
3489 &mut self,
3490 id_to_remove: WorktreeId,
3491 cx: &mut Context<LspStore>,
3492 ) -> Vec<LanguageServerId> {
3493 self.restricted_worktrees_tasks.remove(&id_to_remove);
3494 self.diagnostics.remove(&id_to_remove);
3495 self.prettier_store.update(cx, |prettier_store, cx| {
3496 prettier_store.remove_worktree(id_to_remove, cx);
3497 });
3498
3499 let mut servers_to_remove = BTreeSet::default();
3500 let mut servers_to_preserve = HashSet::default();
3501 for (seed, state) in &self.language_server_ids {
3502 if seed.worktree_id == id_to_remove {
3503 servers_to_remove.insert(state.id);
3504 } else {
3505 servers_to_preserve.insert(state.id);
3506 }
3507 }
3508 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3509 self.language_server_ids
3510 .retain(|_, state| !servers_to_remove.contains(&state.id));
3511 for server_id_to_remove in &servers_to_remove {
3512 self.language_server_watched_paths
3513 .remove(server_id_to_remove);
3514 self.language_server_paths_watched_for_rename
3515 .remove(server_id_to_remove);
3516 self.last_workspace_edits_by_language_server
3517 .remove(server_id_to_remove);
3518 self.language_servers.remove(server_id_to_remove);
3519 self.buffer_pull_diagnostics_result_ids
3520 .remove(server_id_to_remove);
3521 self.workspace_pull_diagnostics_result_ids
3522 .remove(server_id_to_remove);
3523 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3524 buffer_servers.remove(server_id_to_remove);
3525 }
3526 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3527 }
3528 servers_to_remove.into_iter().collect()
3529 }
3530
3531 fn rebuild_watched_paths_inner<'a>(
3532 &'a self,
3533 language_server_id: LanguageServerId,
3534 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3535 cx: &mut Context<LspStore>,
3536 ) -> LanguageServerWatchedPathsBuilder {
3537 let worktrees = self
3538 .worktree_store
3539 .read(cx)
3540 .worktrees()
3541 .filter_map(|worktree| {
3542 self.language_servers_for_worktree(worktree.read(cx).id())
3543 .find(|server| server.server_id() == language_server_id)
3544 .map(|_| worktree)
3545 })
3546 .collect::<Vec<_>>();
3547
3548 let mut worktree_globs = HashMap::default();
3549 let mut abs_globs = HashMap::default();
3550 log::trace!(
3551 "Processing new watcher paths for language server with id {}",
3552 language_server_id
3553 );
3554
3555 for watcher in watchers {
3556 if let Some((worktree, literal_prefix, pattern)) =
3557 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3558 {
3559 worktree.update(cx, |worktree, _| {
3560 if let Some((tree, glob)) =
3561 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3562 {
3563 tree.add_path_prefix_to_scan(literal_prefix);
3564 worktree_globs
3565 .entry(tree.id())
3566 .or_insert_with(GlobSetBuilder::new)
3567 .add(glob);
3568 }
3569 });
3570 } else {
3571 let (path, pattern) = match &watcher.glob_pattern {
3572 lsp::GlobPattern::String(s) => {
3573 let watcher_path = SanitizedPath::new(s);
3574 let path = glob_literal_prefix(watcher_path.as_path());
3575 let pattern = watcher_path
3576 .as_path()
3577 .strip_prefix(&path)
3578 .map(|p| p.to_string_lossy().into_owned())
3579 .unwrap_or_else(|e| {
3580 debug_panic!(
3581 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3582 s,
3583 path.display(),
3584 e
3585 );
3586 watcher_path.as_path().to_string_lossy().into_owned()
3587 });
3588 (path, pattern)
3589 }
3590 lsp::GlobPattern::Relative(rp) => {
3591 let Ok(mut base_uri) = match &rp.base_uri {
3592 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3593 lsp::OneOf::Right(base_uri) => base_uri,
3594 }
3595 .to_file_path() else {
3596 continue;
3597 };
3598
3599 let path = glob_literal_prefix(Path::new(&rp.pattern));
3600 let pattern = Path::new(&rp.pattern)
3601 .strip_prefix(&path)
3602 .map(|p| p.to_string_lossy().into_owned())
3603 .unwrap_or_else(|e| {
3604 debug_panic!(
3605 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3606 rp.pattern,
3607 path.display(),
3608 e
3609 );
3610 rp.pattern.clone()
3611 });
3612 base_uri.push(path);
3613 (base_uri, pattern)
3614 }
3615 };
3616
3617 if let Some(glob) = Glob::new(&pattern).log_err() {
3618 if !path
3619 .components()
3620 .any(|c| matches!(c, path::Component::Normal(_)))
3621 {
3622 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3623 // rather than adding a new watcher for `/`.
3624 for worktree in &worktrees {
3625 worktree_globs
3626 .entry(worktree.read(cx).id())
3627 .or_insert_with(GlobSetBuilder::new)
3628 .add(glob.clone());
3629 }
3630 } else {
3631 abs_globs
3632 .entry(path.into())
3633 .or_insert_with(GlobSetBuilder::new)
3634 .add(glob);
3635 }
3636 }
3637 }
3638 }
3639
3640 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3641 for (worktree_id, builder) in worktree_globs {
3642 if let Ok(globset) = builder.build() {
3643 watch_builder.watch_worktree(worktree_id, globset);
3644 }
3645 }
3646 for (abs_path, builder) in abs_globs {
3647 if let Ok(globset) = builder.build() {
3648 watch_builder.watch_abs_path(abs_path, globset);
3649 }
3650 }
3651 watch_builder
3652 }
3653
3654 fn worktree_and_path_for_file_watcher(
3655 worktrees: &[Entity<Worktree>],
3656 watcher: &FileSystemWatcher,
3657 cx: &App,
3658 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3659 worktrees.iter().find_map(|worktree| {
3660 let tree = worktree.read(cx);
3661 let worktree_root_path = tree.abs_path();
3662 let path_style = tree.path_style();
3663 match &watcher.glob_pattern {
3664 lsp::GlobPattern::String(s) => {
3665 let watcher_path = SanitizedPath::new(s);
3666 let relative = watcher_path
3667 .as_path()
3668 .strip_prefix(&worktree_root_path)
3669 .ok()?;
3670 let literal_prefix = glob_literal_prefix(relative);
3671 Some((
3672 worktree.clone(),
3673 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3674 relative.to_string_lossy().into_owned(),
3675 ))
3676 }
3677 lsp::GlobPattern::Relative(rp) => {
3678 let base_uri = match &rp.base_uri {
3679 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3680 lsp::OneOf::Right(base_uri) => base_uri,
3681 }
3682 .to_file_path()
3683 .ok()?;
3684 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3685 let mut literal_prefix = relative.to_owned();
3686 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3687 Some((
3688 worktree.clone(),
3689 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3690 rp.pattern.clone(),
3691 ))
3692 }
3693 }
3694 })
3695 }
3696
3697 fn rebuild_watched_paths(
3698 &mut self,
3699 language_server_id: LanguageServerId,
3700 cx: &mut Context<LspStore>,
3701 ) {
3702 let Some(registrations) = self
3703 .language_server_dynamic_registrations
3704 .get(&language_server_id)
3705 else {
3706 return;
3707 };
3708
3709 let watch_builder = self.rebuild_watched_paths_inner(
3710 language_server_id,
3711 registrations.did_change_watched_files.values().flatten(),
3712 cx,
3713 );
3714 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3715 self.language_server_watched_paths
3716 .insert(language_server_id, watcher);
3717
3718 cx.notify();
3719 }
3720
3721 fn on_lsp_did_change_watched_files(
3722 &mut self,
3723 language_server_id: LanguageServerId,
3724 registration_id: &str,
3725 params: DidChangeWatchedFilesRegistrationOptions,
3726 cx: &mut Context<LspStore>,
3727 ) {
3728 let registrations = self
3729 .language_server_dynamic_registrations
3730 .entry(language_server_id)
3731 .or_default();
3732
3733 registrations
3734 .did_change_watched_files
3735 .insert(registration_id.to_string(), params.watchers);
3736
3737 self.rebuild_watched_paths(language_server_id, cx);
3738 }
3739
3740 fn on_lsp_unregister_did_change_watched_files(
3741 &mut self,
3742 language_server_id: LanguageServerId,
3743 registration_id: &str,
3744 cx: &mut Context<LspStore>,
3745 ) {
3746 let registrations = self
3747 .language_server_dynamic_registrations
3748 .entry(language_server_id)
3749 .or_default();
3750
3751 if registrations
3752 .did_change_watched_files
3753 .remove(registration_id)
3754 .is_some()
3755 {
3756 log::info!(
3757 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3758 language_server_id,
3759 registration_id
3760 );
3761 } else {
3762 log::warn!(
3763 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3764 language_server_id,
3765 registration_id
3766 );
3767 }
3768
3769 self.rebuild_watched_paths(language_server_id, cx);
3770 }
3771
3772 async fn initialization_options_for_adapter(
3773 adapter: Arc<dyn LspAdapter>,
3774 delegate: &Arc<dyn LspAdapterDelegate>,
3775 cx: &mut AsyncApp,
3776 ) -> Result<Option<serde_json::Value>> {
3777 let Some(mut initialization_config) =
3778 adapter.clone().initialization_options(delegate, cx).await?
3779 else {
3780 return Ok(None);
3781 };
3782
3783 for other_adapter in delegate.registered_lsp_adapters() {
3784 if other_adapter.name() == adapter.name() {
3785 continue;
3786 }
3787 if let Ok(Some(target_config)) = other_adapter
3788 .clone()
3789 .additional_initialization_options(adapter.name(), delegate)
3790 .await
3791 {
3792 merge_json_value_into(target_config.clone(), &mut initialization_config);
3793 }
3794 }
3795
3796 Ok(Some(initialization_config))
3797 }
3798
3799 async fn workspace_configuration_for_adapter(
3800 adapter: Arc<dyn LspAdapter>,
3801 delegate: &Arc<dyn LspAdapterDelegate>,
3802 toolchain: Option<Toolchain>,
3803 requested_uri: Option<Uri>,
3804 cx: &mut AsyncApp,
3805 ) -> Result<serde_json::Value> {
3806 let mut workspace_config = adapter
3807 .clone()
3808 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3809 .await?;
3810
3811 for other_adapter in delegate.registered_lsp_adapters() {
3812 if other_adapter.name() == adapter.name() {
3813 continue;
3814 }
3815 if let Ok(Some(target_config)) = other_adapter
3816 .clone()
3817 .additional_workspace_configuration(adapter.name(), delegate, cx)
3818 .await
3819 {
3820 merge_json_value_into(target_config.clone(), &mut workspace_config);
3821 }
3822 }
3823
3824 Ok(workspace_config)
3825 }
3826
3827 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3828 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3829 Some(server.clone())
3830 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3831 Some(Arc::clone(server))
3832 } else {
3833 None
3834 }
3835 }
3836}
3837
3838fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3839 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3840 cx.emit(LspStoreEvent::LanguageServerUpdate {
3841 language_server_id: server.server_id(),
3842 name: Some(server.name()),
3843 message: proto::update_language_server::Variant::MetadataUpdated(
3844 proto::ServerMetadataUpdated {
3845 capabilities: Some(capabilities),
3846 binary: Some(proto::LanguageServerBinaryInfo {
3847 path: server.binary().path.to_string_lossy().into_owned(),
3848 arguments: server
3849 .binary()
3850 .arguments
3851 .iter()
3852 .map(|arg| arg.to_string_lossy().into_owned())
3853 .collect(),
3854 }),
3855 configuration: serde_json::to_string(server.configuration()).ok(),
3856 workspace_folders: server
3857 .workspace_folders()
3858 .iter()
3859 .map(|uri| uri.to_string())
3860 .collect(),
3861 },
3862 ),
3863 });
3864 }
3865}
3866
3867#[derive(Debug)]
3868pub struct FormattableBuffer {
3869 handle: Entity<Buffer>,
3870 abs_path: Option<PathBuf>,
3871 env: Option<HashMap<String, String>>,
3872 ranges: Option<Vec<Range<Anchor>>>,
3873}
3874
3875pub struct RemoteLspStore {
3876 upstream_client: Option<AnyProtoClient>,
3877 upstream_project_id: u64,
3878}
3879
3880pub(crate) enum LspStoreMode {
3881 Local(LocalLspStore), // ssh host and collab host
3882 Remote(RemoteLspStore), // collab guest
3883}
3884
3885impl LspStoreMode {
3886 fn is_local(&self) -> bool {
3887 matches!(self, LspStoreMode::Local(_))
3888 }
3889}
3890
3891pub struct LspStore {
3892 mode: LspStoreMode,
3893 last_formatting_failure: Option<String>,
3894 downstream_client: Option<(AnyProtoClient, u64)>,
3895 nonce: u128,
3896 buffer_store: Entity<BufferStore>,
3897 worktree_store: Entity<WorktreeStore>,
3898 pub languages: Arc<LanguageRegistry>,
3899 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3900 active_entry: Option<ProjectEntryId>,
3901 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3902 _maintain_buffer_languages: Task<()>,
3903 diagnostic_summaries:
3904 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3905 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3906 semantic_token_config: SemanticTokenConfig,
3907 lsp_data: HashMap<BufferId, BufferLspData>,
3908 next_hint_id: Arc<AtomicUsize>,
3909}
3910
3911#[derive(Debug)]
3912pub struct BufferLspData {
3913 buffer_version: Global,
3914 document_colors: Option<DocumentColorData>,
3915 code_lens: Option<CodeLensData>,
3916 semantic_tokens: Option<SemanticTokensData>,
3917 folding_ranges: Option<FoldingRangeData>,
3918 document_symbols: Option<DocumentSymbolsData>,
3919 inlay_hints: BufferInlayHints,
3920 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3921 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3922}
3923
3924#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3925struct LspKey {
3926 request_type: TypeId,
3927 server_queried: Option<LanguageServerId>,
3928}
3929
3930impl BufferLspData {
3931 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3932 Self {
3933 buffer_version: buffer.read(cx).version(),
3934 document_colors: None,
3935 code_lens: None,
3936 semantic_tokens: None,
3937 folding_ranges: None,
3938 document_symbols: None,
3939 inlay_hints: BufferInlayHints::new(buffer, cx),
3940 lsp_requests: HashMap::default(),
3941 chunk_lsp_requests: HashMap::default(),
3942 }
3943 }
3944
3945 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3946 if let Some(document_colors) = &mut self.document_colors {
3947 document_colors.remove_server_data(for_server);
3948 }
3949
3950 if let Some(code_lens) = &mut self.code_lens {
3951 code_lens.remove_server_data(for_server);
3952 }
3953
3954 self.inlay_hints.remove_server_data(for_server);
3955
3956 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3957 semantic_tokens.raw_tokens.servers.remove(&for_server);
3958 semantic_tokens
3959 .latest_invalidation_requests
3960 .remove(&for_server);
3961 }
3962
3963 if let Some(folding_ranges) = &mut self.folding_ranges {
3964 folding_ranges.ranges.remove(&for_server);
3965 }
3966
3967 if let Some(document_symbols) = &mut self.document_symbols {
3968 document_symbols.remove_server_data(for_server);
3969 }
3970 }
3971
3972 #[cfg(any(test, feature = "test-support"))]
3973 pub fn inlay_hints(&self) -> &BufferInlayHints {
3974 &self.inlay_hints
3975 }
3976}
3977
3978#[derive(Debug)]
3979pub enum LspStoreEvent {
3980 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3981 LanguageServerRemoved(LanguageServerId),
3982 LanguageServerUpdate {
3983 language_server_id: LanguageServerId,
3984 name: Option<LanguageServerName>,
3985 message: proto::update_language_server::Variant,
3986 },
3987 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3988 LanguageServerPrompt(LanguageServerPromptRequest),
3989 LanguageDetected {
3990 buffer: Entity<Buffer>,
3991 new_language: Option<Arc<Language>>,
3992 },
3993 Notification(String),
3994 RefreshInlayHints {
3995 server_id: LanguageServerId,
3996 request_id: Option<usize>,
3997 },
3998 RefreshSemanticTokens {
3999 server_id: LanguageServerId,
4000 request_id: Option<usize>,
4001 },
4002 RefreshCodeLens,
4003 DiagnosticsUpdated {
4004 server_id: LanguageServerId,
4005 paths: Vec<ProjectPath>,
4006 },
4007 DiskBasedDiagnosticsStarted {
4008 language_server_id: LanguageServerId,
4009 },
4010 DiskBasedDiagnosticsFinished {
4011 language_server_id: LanguageServerId,
4012 },
4013 SnippetEdit {
4014 buffer_id: BufferId,
4015 edits: Vec<(lsp::Range, Snippet)>,
4016 most_recent_edit: clock::Lamport,
4017 },
4018 WorkspaceEditApplied(ProjectTransaction),
4019}
4020
4021#[derive(Clone, Debug, Serialize)]
4022pub struct LanguageServerStatus {
4023 pub name: LanguageServerName,
4024 pub server_version: Option<SharedString>,
4025 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4026 pub has_pending_diagnostic_updates: bool,
4027 pub progress_tokens: HashSet<ProgressToken>,
4028 pub worktree: Option<WorktreeId>,
4029 pub binary: Option<LanguageServerBinary>,
4030 pub configuration: Option<Value>,
4031 pub workspace_folders: BTreeSet<Uri>,
4032 pub process_id: Option<u32>,
4033}
4034
4035#[derive(Clone, Debug)]
4036struct CoreSymbol {
4037 pub language_server_name: LanguageServerName,
4038 pub source_worktree_id: WorktreeId,
4039 pub source_language_server_id: LanguageServerId,
4040 pub path: SymbolLocation,
4041 pub name: String,
4042 pub kind: lsp::SymbolKind,
4043 pub range: Range<Unclipped<PointUtf16>>,
4044 pub container_name: Option<String>,
4045}
4046
4047#[derive(Clone, Debug, PartialEq, Eq)]
4048pub enum SymbolLocation {
4049 InProject(ProjectPath),
4050 OutsideProject {
4051 abs_path: Arc<Path>,
4052 signature: [u8; 32],
4053 },
4054}
4055
4056impl SymbolLocation {
4057 fn file_name(&self) -> Option<&str> {
4058 match self {
4059 Self::InProject(path) => path.path.file_name(),
4060 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4061 }
4062 }
4063}
4064
4065impl LspStore {
4066 pub fn init(client: &AnyProtoClient) {
4067 client.add_entity_request_handler(Self::handle_lsp_query);
4068 client.add_entity_message_handler(Self::handle_lsp_query_response);
4069 client.add_entity_request_handler(Self::handle_restart_language_servers);
4070 client.add_entity_request_handler(Self::handle_stop_language_servers);
4071 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4072 client.add_entity_message_handler(Self::handle_start_language_server);
4073 client.add_entity_message_handler(Self::handle_update_language_server);
4074 client.add_entity_message_handler(Self::handle_language_server_log);
4075 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4076 client.add_entity_request_handler(Self::handle_format_buffers);
4077 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4078 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4079 client.add_entity_request_handler(Self::handle_apply_code_action);
4080 client.add_entity_request_handler(Self::handle_get_project_symbols);
4081 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4082 client.add_entity_request_handler(Self::handle_get_color_presentation);
4083 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4084 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4085 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4086 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4087 client.add_entity_request_handler(Self::handle_on_type_formatting);
4088 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4089 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4090 client.add_entity_request_handler(Self::handle_rename_project_entry);
4091 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4092 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4093 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4094 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4095 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4096 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4097 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4098
4099 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4100 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4101 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4102 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4103 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4104 client.add_entity_request_handler(
4105 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4106 );
4107 client.add_entity_request_handler(
4108 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4109 );
4110 client.add_entity_request_handler(
4111 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4112 );
4113 }
4114
4115 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4116 match &self.mode {
4117 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4118 _ => None,
4119 }
4120 }
4121
4122 pub fn as_local(&self) -> Option<&LocalLspStore> {
4123 match &self.mode {
4124 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4125 _ => None,
4126 }
4127 }
4128
4129 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4130 match &mut self.mode {
4131 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4132 _ => None,
4133 }
4134 }
4135
4136 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4137 match &self.mode {
4138 LspStoreMode::Remote(RemoteLspStore {
4139 upstream_client: Some(upstream_client),
4140 upstream_project_id,
4141 ..
4142 }) => Some((upstream_client.clone(), *upstream_project_id)),
4143
4144 LspStoreMode::Remote(RemoteLspStore {
4145 upstream_client: None,
4146 ..
4147 }) => None,
4148 LspStoreMode::Local(_) => None,
4149 }
4150 }
4151
4152 pub fn new_local(
4153 buffer_store: Entity<BufferStore>,
4154 worktree_store: Entity<WorktreeStore>,
4155 prettier_store: Entity<PrettierStore>,
4156 toolchain_store: Entity<LocalToolchainStore>,
4157 environment: Entity<ProjectEnvironment>,
4158 manifest_tree: Entity<ManifestTree>,
4159 languages: Arc<LanguageRegistry>,
4160 http_client: Arc<dyn HttpClient>,
4161 fs: Arc<dyn Fs>,
4162 cx: &mut Context<Self>,
4163 ) -> Self {
4164 let yarn = YarnPathStore::new(fs.clone(), cx);
4165 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4166 .detach();
4167 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4168 .detach();
4169 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4170 .detach();
4171 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4172 .detach();
4173 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4174 .detach();
4175 subscribe_to_binary_statuses(&languages, cx).detach();
4176
4177 let _maintain_workspace_config = {
4178 let (sender, receiver) = watch::channel();
4179 (Self::maintain_workspace_config(receiver, cx), sender)
4180 };
4181
4182 Self {
4183 mode: LspStoreMode::Local(LocalLspStore {
4184 weak: cx.weak_entity(),
4185 worktree_store: worktree_store.clone(),
4186
4187 supplementary_language_servers: Default::default(),
4188 languages: languages.clone(),
4189 language_server_ids: Default::default(),
4190 language_servers: Default::default(),
4191 last_workspace_edits_by_language_server: Default::default(),
4192 language_server_watched_paths: Default::default(),
4193 language_server_paths_watched_for_rename: Default::default(),
4194 language_server_dynamic_registrations: Default::default(),
4195 buffers_being_formatted: Default::default(),
4196 buffers_to_refresh_hash_set: HashSet::default(),
4197 buffers_to_refresh_queue: VecDeque::new(),
4198 _background_diagnostics_worker: Task::ready(()).shared(),
4199 buffer_snapshots: Default::default(),
4200 prettier_store,
4201 environment,
4202 http_client,
4203 fs,
4204 yarn,
4205 next_diagnostic_group_id: Default::default(),
4206 diagnostics: Default::default(),
4207 _subscription: cx.on_app_quit(|this, _| {
4208 this.as_local_mut()
4209 .unwrap()
4210 .shutdown_language_servers_on_quit()
4211 }),
4212 lsp_tree: LanguageServerTree::new(
4213 manifest_tree,
4214 languages.clone(),
4215 toolchain_store.clone(),
4216 ),
4217 toolchain_store,
4218 registered_buffers: HashMap::default(),
4219 buffers_opened_in_servers: HashMap::default(),
4220 buffer_pull_diagnostics_result_ids: HashMap::default(),
4221 workspace_pull_diagnostics_result_ids: HashMap::default(),
4222 restricted_worktrees_tasks: HashMap::default(),
4223 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4224 .manifest_file_names(),
4225 }),
4226 last_formatting_failure: None,
4227 downstream_client: None,
4228 buffer_store,
4229 worktree_store,
4230 languages: languages.clone(),
4231 language_server_statuses: Default::default(),
4232 nonce: StdRng::from_os_rng().random(),
4233 diagnostic_summaries: HashMap::default(),
4234 lsp_server_capabilities: HashMap::default(),
4235 semantic_token_config: SemanticTokenConfig::new(cx),
4236 lsp_data: HashMap::default(),
4237 next_hint_id: Arc::default(),
4238 active_entry: None,
4239 _maintain_workspace_config,
4240 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4241 }
4242 }
4243
4244 fn send_lsp_proto_request<R: LspCommand>(
4245 &self,
4246 buffer: Entity<Buffer>,
4247 client: AnyProtoClient,
4248 upstream_project_id: u64,
4249 request: R,
4250 cx: &mut Context<LspStore>,
4251 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4252 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4253 return Task::ready(Ok(R::Response::default()));
4254 }
4255 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4256 cx.spawn(async move |this, cx| {
4257 let response = client.request(message).await?;
4258 let this = this.upgrade().context("project dropped")?;
4259 request
4260 .response_from_proto(response, this, buffer, cx.clone())
4261 .await
4262 })
4263 }
4264
4265 pub(super) fn new_remote(
4266 buffer_store: Entity<BufferStore>,
4267 worktree_store: Entity<WorktreeStore>,
4268 languages: Arc<LanguageRegistry>,
4269 upstream_client: AnyProtoClient,
4270 project_id: u64,
4271 cx: &mut Context<Self>,
4272 ) -> Self {
4273 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4274 .detach();
4275 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4276 .detach();
4277 subscribe_to_binary_statuses(&languages, cx).detach();
4278 let _maintain_workspace_config = {
4279 let (sender, receiver) = watch::channel();
4280 (Self::maintain_workspace_config(receiver, cx), sender)
4281 };
4282 Self {
4283 mode: LspStoreMode::Remote(RemoteLspStore {
4284 upstream_client: Some(upstream_client),
4285 upstream_project_id: project_id,
4286 }),
4287 downstream_client: None,
4288 last_formatting_failure: None,
4289 buffer_store,
4290 worktree_store,
4291 languages: languages.clone(),
4292 language_server_statuses: Default::default(),
4293 nonce: StdRng::from_os_rng().random(),
4294 diagnostic_summaries: HashMap::default(),
4295 lsp_server_capabilities: HashMap::default(),
4296 semantic_token_config: SemanticTokenConfig::new(cx),
4297 next_hint_id: Arc::default(),
4298 lsp_data: HashMap::default(),
4299 active_entry: None,
4300
4301 _maintain_workspace_config,
4302 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4303 }
4304 }
4305
4306 fn on_buffer_store_event(
4307 &mut self,
4308 _: Entity<BufferStore>,
4309 event: &BufferStoreEvent,
4310 cx: &mut Context<Self>,
4311 ) {
4312 match event {
4313 BufferStoreEvent::BufferAdded(buffer) => {
4314 self.on_buffer_added(buffer, cx).log_err();
4315 }
4316 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4317 let buffer_id = buffer.read(cx).remote_id();
4318 if let Some(local) = self.as_local_mut()
4319 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4320 {
4321 local.reset_buffer(buffer, old_file, cx);
4322
4323 if local.registered_buffers.contains_key(&buffer_id) {
4324 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4325 }
4326 }
4327
4328 self.detect_language_for_buffer(buffer, cx);
4329 if let Some(local) = self.as_local_mut() {
4330 local.initialize_buffer(buffer, cx);
4331 if local.registered_buffers.contains_key(&buffer_id) {
4332 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4333 }
4334 }
4335 }
4336 _ => {}
4337 }
4338 }
4339
4340 fn on_worktree_store_event(
4341 &mut self,
4342 _: Entity<WorktreeStore>,
4343 event: &WorktreeStoreEvent,
4344 cx: &mut Context<Self>,
4345 ) {
4346 match event {
4347 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4348 if !worktree.read(cx).is_local() {
4349 return;
4350 }
4351 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4352 worktree::Event::UpdatedEntries(changes) => {
4353 this.update_local_worktree_language_servers(&worktree, changes, cx);
4354 }
4355 worktree::Event::UpdatedGitRepositories(_)
4356 | worktree::Event::DeletedEntry(_) => {}
4357 })
4358 .detach()
4359 }
4360 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4361 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4362 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4363 }
4364 WorktreeStoreEvent::WorktreeReleased(..)
4365 | WorktreeStoreEvent::WorktreeOrderChanged
4366 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4367 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4368 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4369 }
4370 }
4371
4372 fn on_prettier_store_event(
4373 &mut self,
4374 _: Entity<PrettierStore>,
4375 event: &PrettierStoreEvent,
4376 cx: &mut Context<Self>,
4377 ) {
4378 match event {
4379 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4380 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4381 }
4382 PrettierStoreEvent::LanguageServerAdded {
4383 new_server_id,
4384 name,
4385 prettier_server,
4386 } => {
4387 self.register_supplementary_language_server(
4388 *new_server_id,
4389 name.clone(),
4390 prettier_server.clone(),
4391 cx,
4392 );
4393 }
4394 }
4395 }
4396
4397 fn on_toolchain_store_event(
4398 &mut self,
4399 _: Entity<LocalToolchainStore>,
4400 event: &ToolchainStoreEvent,
4401 _: &mut Context<Self>,
4402 ) {
4403 if let ToolchainStoreEvent::ToolchainActivated = event {
4404 self.request_workspace_config_refresh()
4405 }
4406 }
4407
4408 fn request_workspace_config_refresh(&mut self) {
4409 *self._maintain_workspace_config.1.borrow_mut() = ();
4410 }
4411
4412 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4413 self.as_local().map(|local| local.prettier_store.clone())
4414 }
4415
4416 fn on_buffer_event(
4417 &mut self,
4418 buffer: Entity<Buffer>,
4419 event: &language::BufferEvent,
4420 cx: &mut Context<Self>,
4421 ) {
4422 match event {
4423 language::BufferEvent::Edited => {
4424 self.on_buffer_edited(buffer, cx);
4425 }
4426
4427 language::BufferEvent::Saved => {
4428 self.on_buffer_saved(buffer, cx);
4429 }
4430
4431 _ => {}
4432 }
4433 }
4434
4435 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4436 buffer
4437 .read(cx)
4438 .set_language_registry(self.languages.clone());
4439
4440 cx.subscribe(buffer, |this, buffer, event, cx| {
4441 this.on_buffer_event(buffer, event, cx);
4442 })
4443 .detach();
4444
4445 self.detect_language_for_buffer(buffer, cx);
4446 if let Some(local) = self.as_local_mut() {
4447 local.initialize_buffer(buffer, cx);
4448 }
4449
4450 Ok(())
4451 }
4452
4453 pub fn refresh_background_diagnostics_for_buffers(
4454 &mut self,
4455 buffers: HashSet<BufferId>,
4456 cx: &mut Context<Self>,
4457 ) -> Shared<Task<()>> {
4458 let Some(local) = self.as_local_mut() else {
4459 return Task::ready(()).shared();
4460 };
4461 for buffer in buffers {
4462 if local.buffers_to_refresh_hash_set.insert(buffer) {
4463 local.buffers_to_refresh_queue.push_back(buffer);
4464 if local.buffers_to_refresh_queue.len() == 1 {
4465 local._background_diagnostics_worker =
4466 Self::background_diagnostics_worker(cx).shared();
4467 }
4468 }
4469 }
4470
4471 local._background_diagnostics_worker.clone()
4472 }
4473
4474 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4475 let buffer_store = self.buffer_store.clone();
4476 let local = self.as_local_mut()?;
4477 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4478 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4479 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4480 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4481 }
4482 }
4483 None
4484 }
4485
4486 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4487 cx.spawn(async move |this, cx| {
4488 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4489 task.await.log_err();
4490 }
4491 })
4492 }
4493
4494 pub(crate) fn register_buffer_with_language_servers(
4495 &mut self,
4496 buffer: &Entity<Buffer>,
4497 only_register_servers: HashSet<LanguageServerSelector>,
4498 ignore_refcounts: bool,
4499 cx: &mut Context<Self>,
4500 ) -> OpenLspBufferHandle {
4501 let buffer_id = buffer.read(cx).remote_id();
4502 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4503 if let Some(local) = self.as_local_mut() {
4504 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4505 if !ignore_refcounts {
4506 *refcount += 1;
4507 }
4508
4509 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4510 // 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
4511 // 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
4512 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4513 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4514 return handle;
4515 };
4516 if !file.is_local() {
4517 return handle;
4518 }
4519
4520 if ignore_refcounts || *refcount == 1 {
4521 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4522 }
4523 if !ignore_refcounts {
4524 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4525 let refcount = {
4526 let local = lsp_store.as_local_mut().unwrap();
4527 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4528 debug_panic!("bad refcounting");
4529 return;
4530 };
4531
4532 *refcount -= 1;
4533 *refcount
4534 };
4535 if refcount == 0 {
4536 lsp_store.lsp_data.remove(&buffer_id);
4537 let local = lsp_store.as_local_mut().unwrap();
4538 local.registered_buffers.remove(&buffer_id);
4539
4540 local.buffers_opened_in_servers.remove(&buffer_id);
4541 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4542 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4543
4544 let buffer_abs_path = file.abs_path(cx);
4545 for (_, buffer_pull_diagnostics_result_ids) in
4546 &mut local.buffer_pull_diagnostics_result_ids
4547 {
4548 buffer_pull_diagnostics_result_ids.retain(
4549 |_, buffer_result_ids| {
4550 buffer_result_ids.remove(&buffer_abs_path);
4551 !buffer_result_ids.is_empty()
4552 },
4553 );
4554 }
4555
4556 let diagnostic_updates = local
4557 .language_servers
4558 .keys()
4559 .cloned()
4560 .map(|server_id| DocumentDiagnosticsUpdate {
4561 diagnostics: DocumentDiagnostics {
4562 document_abs_path: buffer_abs_path.clone(),
4563 version: None,
4564 diagnostics: Vec::new(),
4565 },
4566 result_id: None,
4567 registration_id: None,
4568 server_id,
4569 disk_based_sources: Cow::Borrowed(&[]),
4570 })
4571 .collect::<Vec<_>>();
4572
4573 lsp_store
4574 .merge_diagnostic_entries(
4575 diagnostic_updates,
4576 |_, diagnostic, _| {
4577 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4578 },
4579 cx,
4580 )
4581 .context("Clearing diagnostics for the closed buffer")
4582 .log_err();
4583 }
4584 }
4585 })
4586 .detach();
4587 }
4588 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4589 let buffer_id = buffer.read(cx).remote_id().to_proto();
4590 cx.background_spawn(async move {
4591 upstream_client
4592 .request(proto::RegisterBufferWithLanguageServers {
4593 project_id: upstream_project_id,
4594 buffer_id,
4595 only_servers: only_register_servers
4596 .into_iter()
4597 .map(|selector| {
4598 let selector = match selector {
4599 LanguageServerSelector::Id(language_server_id) => {
4600 proto::language_server_selector::Selector::ServerId(
4601 language_server_id.to_proto(),
4602 )
4603 }
4604 LanguageServerSelector::Name(language_server_name) => {
4605 proto::language_server_selector::Selector::Name(
4606 language_server_name.to_string(),
4607 )
4608 }
4609 };
4610 proto::LanguageServerSelector {
4611 selector: Some(selector),
4612 }
4613 })
4614 .collect(),
4615 })
4616 .await
4617 })
4618 .detach();
4619 } else {
4620 // Our remote connection got closed
4621 }
4622 handle
4623 }
4624
4625 fn maintain_buffer_languages(
4626 languages: Arc<LanguageRegistry>,
4627 cx: &mut Context<Self>,
4628 ) -> Task<()> {
4629 let mut subscription = languages.subscribe();
4630 let mut prev_reload_count = languages.reload_count();
4631 cx.spawn(async move |this, cx| {
4632 while let Some(()) = subscription.next().await {
4633 if let Some(this) = this.upgrade() {
4634 // If the language registry has been reloaded, then remove and
4635 // re-assign the languages on all open buffers.
4636 let reload_count = languages.reload_count();
4637 if reload_count > prev_reload_count {
4638 prev_reload_count = reload_count;
4639 this.update(cx, |this, cx| {
4640 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4641 for buffer in buffer_store.buffers() {
4642 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4643 {
4644 buffer.update(cx, |buffer, cx| {
4645 buffer.set_language_async(None, cx)
4646 });
4647 if let Some(local) = this.as_local_mut() {
4648 local.reset_buffer(&buffer, &f, cx);
4649
4650 if local
4651 .registered_buffers
4652 .contains_key(&buffer.read(cx).remote_id())
4653 && let Some(file_url) =
4654 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4655 {
4656 local.unregister_buffer_from_language_servers(
4657 &buffer, &file_url, cx,
4658 );
4659 }
4660 }
4661 }
4662 }
4663 });
4664 });
4665 }
4666
4667 this.update(cx, |this, cx| {
4668 let mut plain_text_buffers = Vec::new();
4669 let mut buffers_with_unknown_injections = Vec::new();
4670 for handle in this.buffer_store.read(cx).buffers() {
4671 let buffer = handle.read(cx);
4672 if buffer.language().is_none()
4673 || buffer.language() == Some(&*language::PLAIN_TEXT)
4674 {
4675 plain_text_buffers.push(handle);
4676 } else if buffer.contains_unknown_injections() {
4677 buffers_with_unknown_injections.push(handle);
4678 }
4679 }
4680
4681 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4682 // and reused later in the invisible worktrees.
4683 plain_text_buffers.sort_by_key(|buffer| {
4684 Reverse(
4685 File::from_dyn(buffer.read(cx).file())
4686 .map(|file| file.worktree.read(cx).is_visible()),
4687 )
4688 });
4689
4690 for buffer in plain_text_buffers {
4691 this.detect_language_for_buffer(&buffer, cx);
4692 if let Some(local) = this.as_local_mut() {
4693 local.initialize_buffer(&buffer, cx);
4694 if local
4695 .registered_buffers
4696 .contains_key(&buffer.read(cx).remote_id())
4697 {
4698 local.register_buffer_with_language_servers(
4699 &buffer,
4700 HashSet::default(),
4701 cx,
4702 );
4703 }
4704 }
4705 }
4706
4707 for buffer in buffers_with_unknown_injections {
4708 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4709 }
4710 });
4711 }
4712 }
4713 })
4714 }
4715
4716 fn detect_language_for_buffer(
4717 &mut self,
4718 buffer_handle: &Entity<Buffer>,
4719 cx: &mut Context<Self>,
4720 ) -> Option<language::AvailableLanguage> {
4721 // If the buffer has a language, set it and start the language server if we haven't already.
4722 let buffer = buffer_handle.read(cx);
4723 let file = buffer.file()?;
4724
4725 let content = buffer.as_rope();
4726 let available_language = self.languages.language_for_file(file, Some(content), cx);
4727 if let Some(available_language) = &available_language {
4728 if let Some(Ok(Ok(new_language))) = self
4729 .languages
4730 .load_language(available_language)
4731 .now_or_never()
4732 {
4733 self.set_language_for_buffer(buffer_handle, new_language, cx);
4734 }
4735 } else {
4736 cx.emit(LspStoreEvent::LanguageDetected {
4737 buffer: buffer_handle.clone(),
4738 new_language: None,
4739 });
4740 }
4741
4742 available_language
4743 }
4744
4745 pub(crate) fn set_language_for_buffer(
4746 &mut self,
4747 buffer_entity: &Entity<Buffer>,
4748 new_language: Arc<Language>,
4749 cx: &mut Context<Self>,
4750 ) {
4751 let buffer = buffer_entity.read(cx);
4752 let buffer_file = buffer.file().cloned();
4753 let buffer_id = buffer.remote_id();
4754 if let Some(local_store) = self.as_local_mut()
4755 && local_store.registered_buffers.contains_key(&buffer_id)
4756 && let Some(abs_path) =
4757 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4758 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4759 {
4760 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4761 }
4762 buffer_entity.update(cx, |buffer, cx| {
4763 if buffer
4764 .language()
4765 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4766 {
4767 buffer.set_language_async(Some(new_language.clone()), cx);
4768 }
4769 });
4770
4771 let settings =
4772 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4773 let buffer_file = File::from_dyn(buffer_file.as_ref());
4774
4775 let worktree_id = if let Some(file) = buffer_file {
4776 let worktree = file.worktree.clone();
4777
4778 if let Some(local) = self.as_local_mut()
4779 && local.registered_buffers.contains_key(&buffer_id)
4780 {
4781 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4782 }
4783 Some(worktree.read(cx).id())
4784 } else {
4785 None
4786 };
4787
4788 if settings.prettier.allowed
4789 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4790 {
4791 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4792 if let Some(prettier_store) = prettier_store {
4793 prettier_store.update(cx, |prettier_store, cx| {
4794 prettier_store.install_default_prettier(
4795 worktree_id,
4796 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4797 cx,
4798 )
4799 })
4800 }
4801 }
4802
4803 cx.emit(LspStoreEvent::LanguageDetected {
4804 buffer: buffer_entity.clone(),
4805 new_language: Some(new_language),
4806 })
4807 }
4808
4809 pub fn buffer_store(&self) -> Entity<BufferStore> {
4810 self.buffer_store.clone()
4811 }
4812
4813 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4814 self.active_entry = active_entry;
4815 }
4816
4817 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4818 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4819 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4820 {
4821 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4822 summaries
4823 .iter()
4824 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4825 });
4826 if let Some(summary) = summaries.next() {
4827 client
4828 .send(proto::UpdateDiagnosticSummary {
4829 project_id: downstream_project_id,
4830 worktree_id: worktree.id().to_proto(),
4831 summary: Some(summary),
4832 more_summaries: summaries.collect(),
4833 })
4834 .log_err();
4835 }
4836 }
4837 }
4838
4839 fn is_capable_for_proto_request<R>(
4840 &self,
4841 buffer: &Entity<Buffer>,
4842 request: &R,
4843 cx: &App,
4844 ) -> bool
4845 where
4846 R: LspCommand,
4847 {
4848 self.check_if_capable_for_proto_request(
4849 buffer,
4850 |capabilities| {
4851 request.check_capabilities(AdapterServerCapabilities {
4852 server_capabilities: capabilities.clone(),
4853 code_action_kinds: None,
4854 })
4855 },
4856 cx,
4857 )
4858 }
4859
4860 fn check_if_capable_for_proto_request<F>(
4861 &self,
4862 buffer: &Entity<Buffer>,
4863 check: F,
4864 cx: &App,
4865 ) -> bool
4866 where
4867 F: FnMut(&lsp::ServerCapabilities) -> bool,
4868 {
4869 let Some(language) = buffer.read(cx).language().cloned() else {
4870 return false;
4871 };
4872 let registered_language_servers = self
4873 .languages
4874 .lsp_adapters(&language.name())
4875 .into_iter()
4876 .map(|lsp_adapter| lsp_adapter.name())
4877 .collect::<HashSet<_>>();
4878 self.language_server_statuses
4879 .iter()
4880 .filter_map(|(server_id, server_status)| {
4881 // Include servers that are either registered for this language OR
4882 // available to be loaded (for SSH remote mode where adapters like
4883 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4884 // but only loaded on the server side)
4885 let is_relevant = registered_language_servers.contains(&server_status.name)
4886 || self.languages.is_lsp_adapter_available(&server_status.name);
4887 is_relevant.then_some(server_id)
4888 })
4889 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4890 .any(check)
4891 }
4892
4893 fn all_capable_for_proto_request<F>(
4894 &self,
4895 buffer: &Entity<Buffer>,
4896 mut check: F,
4897 cx: &App,
4898 ) -> Vec<lsp::LanguageServerId>
4899 where
4900 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4901 {
4902 let Some(language) = buffer.read(cx).language().cloned() else {
4903 return Vec::default();
4904 };
4905 let registered_language_servers = self
4906 .languages
4907 .lsp_adapters(&language.name())
4908 .into_iter()
4909 .map(|lsp_adapter| lsp_adapter.name())
4910 .collect::<HashSet<_>>();
4911 self.language_server_statuses
4912 .iter()
4913 .filter_map(|(server_id, server_status)| {
4914 // Include servers that are either registered for this language OR
4915 // available to be loaded (for SSH remote mode where adapters like
4916 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4917 // but only loaded on the server side)
4918 let is_relevant = registered_language_servers.contains(&server_status.name)
4919 || self.languages.is_lsp_adapter_available(&server_status.name);
4920 is_relevant.then_some((server_id, &server_status.name))
4921 })
4922 .filter_map(|(server_id, server_name)| {
4923 self.lsp_server_capabilities
4924 .get(server_id)
4925 .map(|c| (server_id, server_name, c))
4926 })
4927 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4928 .map(|(server_id, _, _)| *server_id)
4929 .collect()
4930 }
4931
4932 pub fn request_lsp<R>(
4933 &mut self,
4934 buffer: Entity<Buffer>,
4935 server: LanguageServerToQuery,
4936 request: R,
4937 cx: &mut Context<Self>,
4938 ) -> Task<Result<R::Response>>
4939 where
4940 R: LspCommand,
4941 <R::LspRequest as lsp::request::Request>::Result: Send,
4942 <R::LspRequest as lsp::request::Request>::Params: Send,
4943 {
4944 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4945 return self.send_lsp_proto_request(
4946 buffer,
4947 upstream_client,
4948 upstream_project_id,
4949 request,
4950 cx,
4951 );
4952 }
4953
4954 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4955 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4956 local
4957 .language_servers_for_buffer(buffer, cx)
4958 .find(|(_, server)| {
4959 request.check_capabilities(server.adapter_server_capabilities())
4960 })
4961 .map(|(_, server)| server.clone())
4962 }),
4963 LanguageServerToQuery::Other(id) => self
4964 .language_server_for_local_buffer(buffer, id, cx)
4965 .and_then(|(_, server)| {
4966 request
4967 .check_capabilities(server.adapter_server_capabilities())
4968 .then(|| Arc::clone(server))
4969 }),
4970 }) else {
4971 return Task::ready(Ok(Default::default()));
4972 };
4973
4974 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4975
4976 let Some(file) = file else {
4977 return Task::ready(Ok(Default::default()));
4978 };
4979
4980 let lsp_params = match request.to_lsp_params_or_response(
4981 &file.abs_path(cx),
4982 buffer.read(cx),
4983 &language_server,
4984 cx,
4985 ) {
4986 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4987 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4988 Err(err) => {
4989 let message = format!(
4990 "{} via {} failed: {}",
4991 request.display_name(),
4992 language_server.name(),
4993 err
4994 );
4995 // rust-analyzer likes to error with this when its still loading up
4996 if !message.ends_with("content modified") {
4997 log::warn!("{message}");
4998 }
4999 return Task::ready(Err(anyhow!(message)));
5000 }
5001 };
5002
5003 let status = request.status();
5004 let request_timeout = ProjectSettings::get_global(cx)
5005 .global_lsp_settings
5006 .get_request_timeout();
5007
5008 cx.spawn(async move |this, cx| {
5009 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5010
5011 let id = lsp_request.id();
5012 let _cleanup = if status.is_some() {
5013 cx.update(|cx| {
5014 this.update(cx, |this, cx| {
5015 this.on_lsp_work_start(
5016 language_server.server_id(),
5017 ProgressToken::Number(id),
5018 LanguageServerProgress {
5019 is_disk_based_diagnostics_progress: false,
5020 is_cancellable: false,
5021 title: None,
5022 message: status.clone(),
5023 percentage: None,
5024 last_update_at: cx.background_executor().now(),
5025 },
5026 cx,
5027 );
5028 })
5029 })
5030 .log_err();
5031
5032 Some(defer(|| {
5033 cx.update(|cx| {
5034 this.update(cx, |this, cx| {
5035 this.on_lsp_work_end(
5036 language_server.server_id(),
5037 ProgressToken::Number(id),
5038 cx,
5039 );
5040 })
5041 })
5042 .log_err();
5043 }))
5044 } else {
5045 None
5046 };
5047
5048 let result = lsp_request.await.into_response();
5049
5050 let response = result.map_err(|err| {
5051 let message = format!(
5052 "{} via {} failed: {}",
5053 request.display_name(),
5054 language_server.name(),
5055 err
5056 );
5057 // rust-analyzer likes to error with this when its still loading up
5058 if !message.ends_with("content modified") {
5059 log::warn!("{message}");
5060 }
5061 anyhow::anyhow!(message)
5062 })?;
5063
5064 request
5065 .response_from_lsp(
5066 response,
5067 this.upgrade().context("no app context")?,
5068 buffer,
5069 language_server.server_id(),
5070 cx.clone(),
5071 )
5072 .await
5073 })
5074 }
5075
5076 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5077 let mut language_formatters_to_check = Vec::new();
5078 for buffer in self.buffer_store.read(cx).buffers() {
5079 let buffer = buffer.read(cx);
5080 let buffer_file = File::from_dyn(buffer.file());
5081 let buffer_language = buffer.language();
5082 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5083 if buffer_language.is_some() {
5084 language_formatters_to_check.push((
5085 buffer_file.map(|f| f.worktree_id(cx)),
5086 settings.into_owned(),
5087 ));
5088 }
5089 }
5090
5091 self.request_workspace_config_refresh();
5092
5093 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5094 prettier_store.update(cx, |prettier_store, cx| {
5095 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5096 })
5097 }
5098
5099 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5100 .global_lsp_settings
5101 .semantic_token_rules
5102 .clone();
5103 self.semantic_token_config
5104 .update_rules(new_semantic_token_rules);
5105 // Always clear cached stylizers so that changes to language-specific
5106 // semantic token rules (e.g. from extension install/uninstall) are
5107 // picked up. Stylizers are recreated lazily, so this is cheap.
5108 self.semantic_token_config.clear_stylizers();
5109
5110 let new_global_semantic_tokens_mode =
5111 all_language_settings(None, cx).defaults.semantic_tokens;
5112 if self
5113 .semantic_token_config
5114 .update_global_mode(new_global_semantic_tokens_mode)
5115 {
5116 self.restart_all_language_servers(cx);
5117 }
5118
5119 cx.notify();
5120 }
5121
5122 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5123 let buffer_store = self.buffer_store.clone();
5124 let Some(local) = self.as_local_mut() else {
5125 return;
5126 };
5127 let mut adapters = BTreeMap::default();
5128 let get_adapter = {
5129 let languages = local.languages.clone();
5130 let environment = local.environment.clone();
5131 let weak = local.weak.clone();
5132 let worktree_store = local.worktree_store.clone();
5133 let http_client = local.http_client.clone();
5134 let fs = local.fs.clone();
5135 move |worktree_id, cx: &mut App| {
5136 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5137 Some(LocalLspAdapterDelegate::new(
5138 languages.clone(),
5139 &environment,
5140 weak.clone(),
5141 &worktree,
5142 http_client.clone(),
5143 fs.clone(),
5144 cx,
5145 ))
5146 }
5147 };
5148
5149 let mut messages_to_report = Vec::new();
5150 let (new_tree, to_stop) = {
5151 let mut rebase = local.lsp_tree.rebase();
5152 let buffers = buffer_store
5153 .read(cx)
5154 .buffers()
5155 .filter_map(|buffer| {
5156 let raw_buffer = buffer.read(cx);
5157 if !local
5158 .registered_buffers
5159 .contains_key(&raw_buffer.remote_id())
5160 {
5161 return None;
5162 }
5163 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5164 let language = raw_buffer.language().cloned()?;
5165 Some((file, language, raw_buffer.remote_id()))
5166 })
5167 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5168 for (file, language, buffer_id) in buffers {
5169 let worktree_id = file.worktree_id(cx);
5170 let Some(worktree) = local
5171 .worktree_store
5172 .read(cx)
5173 .worktree_for_id(worktree_id, cx)
5174 else {
5175 continue;
5176 };
5177
5178 if let Some((_, apply)) = local.reuse_existing_language_server(
5179 rebase.server_tree(),
5180 &worktree,
5181 &language.name(),
5182 cx,
5183 ) {
5184 (apply)(rebase.server_tree());
5185 } else if let Some(lsp_delegate) = adapters
5186 .entry(worktree_id)
5187 .or_insert_with(|| get_adapter(worktree_id, cx))
5188 .clone()
5189 {
5190 let delegate =
5191 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5192 let path = file
5193 .path()
5194 .parent()
5195 .map(Arc::from)
5196 .unwrap_or_else(|| file.path().clone());
5197 let worktree_path = ProjectPath { worktree_id, path };
5198 let abs_path = file.abs_path(cx);
5199 let nodes = rebase
5200 .walk(
5201 worktree_path,
5202 language.name(),
5203 language.manifest(),
5204 delegate.clone(),
5205 cx,
5206 )
5207 .collect::<Vec<_>>();
5208 for node in nodes {
5209 let server_id = node.server_id_or_init(|disposition| {
5210 let path = &disposition.path;
5211 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5212 let key = LanguageServerSeed {
5213 worktree_id,
5214 name: disposition.server_name.clone(),
5215 settings: LanguageServerSeedSettings {
5216 binary: disposition.settings.binary.clone(),
5217 initialization_options: disposition
5218 .settings
5219 .initialization_options
5220 .clone(),
5221 },
5222 toolchain: local.toolchain_store.read(cx).active_toolchain(
5223 path.worktree_id,
5224 &path.path,
5225 language.name(),
5226 ),
5227 };
5228 local.language_server_ids.remove(&key);
5229
5230 let server_id = local.get_or_insert_language_server(
5231 &worktree,
5232 lsp_delegate.clone(),
5233 disposition,
5234 &language.name(),
5235 cx,
5236 );
5237 if let Some(state) = local.language_servers.get(&server_id)
5238 && let Ok(uri) = uri
5239 {
5240 state.add_workspace_folder(uri);
5241 };
5242 server_id
5243 });
5244
5245 if let Some(language_server_id) = server_id {
5246 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5247 language_server_id,
5248 name: node.name(),
5249 message:
5250 proto::update_language_server::Variant::RegisteredForBuffer(
5251 proto::RegisteredForBuffer {
5252 buffer_abs_path: abs_path
5253 .to_string_lossy()
5254 .into_owned(),
5255 buffer_id: buffer_id.to_proto(),
5256 },
5257 ),
5258 });
5259 }
5260 }
5261 } else {
5262 continue;
5263 }
5264 }
5265 rebase.finish()
5266 };
5267 for message in messages_to_report {
5268 cx.emit(message);
5269 }
5270 local.lsp_tree = new_tree;
5271 for (id, _) in to_stop {
5272 self.stop_local_language_server(id, cx).detach();
5273 }
5274 }
5275
5276 pub fn apply_code_action(
5277 &self,
5278 buffer_handle: Entity<Buffer>,
5279 mut action: CodeAction,
5280 push_to_history: bool,
5281 cx: &mut Context<Self>,
5282 ) -> Task<Result<ProjectTransaction>> {
5283 if let Some((upstream_client, project_id)) = self.upstream_client() {
5284 let request = proto::ApplyCodeAction {
5285 project_id,
5286 buffer_id: buffer_handle.read(cx).remote_id().into(),
5287 action: Some(Self::serialize_code_action(&action)),
5288 };
5289 let buffer_store = self.buffer_store();
5290 cx.spawn(async move |_, cx| {
5291 let response = upstream_client
5292 .request(request)
5293 .await?
5294 .transaction
5295 .context("missing transaction")?;
5296
5297 buffer_store
5298 .update(cx, |buffer_store, cx| {
5299 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5300 })
5301 .await
5302 })
5303 } else if self.mode.is_local() {
5304 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5305 let request_timeout = ProjectSettings::get_global(cx)
5306 .global_lsp_settings
5307 .get_request_timeout();
5308 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5309 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5310 }) else {
5311 return Task::ready(Ok(ProjectTransaction::default()));
5312 };
5313
5314 cx.spawn(async move |this, cx| {
5315 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5316 .await
5317 .context("resolving a code action")?;
5318 if let Some(edit) = action.lsp_action.edit()
5319 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5320 return LocalLspStore::deserialize_workspace_edit(
5321 this.upgrade().context("no app present")?,
5322 edit.clone(),
5323 push_to_history,
5324
5325 lang_server.clone(),
5326 cx,
5327 )
5328 .await;
5329 }
5330
5331 let Some(command) = action.lsp_action.command() else {
5332 return Ok(ProjectTransaction::default())
5333 };
5334
5335 let server_capabilities = lang_server.capabilities();
5336 let available_commands = server_capabilities
5337 .execute_command_provider
5338 .as_ref()
5339 .map(|options| options.commands.as_slice())
5340 .unwrap_or_default();
5341
5342 if !available_commands.contains(&command.command) {
5343 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5344 return Ok(ProjectTransaction::default())
5345 }
5346
5347 let request_timeout = cx.update(|app|
5348 ProjectSettings::get_global(app)
5349 .global_lsp_settings
5350 .get_request_timeout()
5351 );
5352
5353 this.update(cx, |this, _| {
5354 this.as_local_mut()
5355 .unwrap()
5356 .last_workspace_edits_by_language_server
5357 .remove(&lang_server.server_id());
5358 })?;
5359
5360 let _result = lang_server
5361 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5362 command: command.command.clone(),
5363 arguments: command.arguments.clone().unwrap_or_default(),
5364 ..lsp::ExecuteCommandParams::default()
5365 }, request_timeout)
5366 .await.into_response()
5367 .context("execute command")?;
5368
5369 return this.update(cx, |this, _| {
5370 this.as_local_mut()
5371 .unwrap()
5372 .last_workspace_edits_by_language_server
5373 .remove(&lang_server.server_id())
5374 .unwrap_or_default()
5375 });
5376 })
5377 } else {
5378 Task::ready(Err(anyhow!("no upstream client and not local")))
5379 }
5380 }
5381
5382 pub fn apply_code_action_kind(
5383 &mut self,
5384 buffers: HashSet<Entity<Buffer>>,
5385 kind: CodeActionKind,
5386 push_to_history: bool,
5387 cx: &mut Context<Self>,
5388 ) -> Task<anyhow::Result<ProjectTransaction>> {
5389 if self.as_local().is_some() {
5390 cx.spawn(async move |lsp_store, cx| {
5391 let buffers = buffers.into_iter().collect::<Vec<_>>();
5392 let result = LocalLspStore::execute_code_action_kind_locally(
5393 lsp_store.clone(),
5394 buffers,
5395 kind,
5396 push_to_history,
5397 cx,
5398 )
5399 .await;
5400 lsp_store.update(cx, |lsp_store, _| {
5401 lsp_store.update_last_formatting_failure(&result);
5402 })?;
5403 result
5404 })
5405 } else if let Some((client, project_id)) = self.upstream_client() {
5406 let buffer_store = self.buffer_store();
5407 cx.spawn(async move |lsp_store, cx| {
5408 let result = client
5409 .request(proto::ApplyCodeActionKind {
5410 project_id,
5411 kind: kind.as_str().to_owned(),
5412 buffer_ids: buffers
5413 .iter()
5414 .map(|buffer| {
5415 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5416 })
5417 .collect(),
5418 })
5419 .await
5420 .and_then(|result| result.transaction.context("missing transaction"));
5421 lsp_store.update(cx, |lsp_store, _| {
5422 lsp_store.update_last_formatting_failure(&result);
5423 })?;
5424
5425 let transaction_response = result?;
5426 buffer_store
5427 .update(cx, |buffer_store, cx| {
5428 buffer_store.deserialize_project_transaction(
5429 transaction_response,
5430 push_to_history,
5431 cx,
5432 )
5433 })
5434 .await
5435 })
5436 } else {
5437 Task::ready(Ok(ProjectTransaction::default()))
5438 }
5439 }
5440
5441 pub fn resolved_hint(
5442 &mut self,
5443 buffer_id: BufferId,
5444 id: InlayId,
5445 cx: &mut Context<Self>,
5446 ) -> Option<ResolvedHint> {
5447 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5448
5449 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5450 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5451 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5452 let (server_id, resolve_data) = match &hint.resolve_state {
5453 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5454 ResolveState::Resolving => {
5455 return Some(ResolvedHint::Resolving(
5456 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5457 ));
5458 }
5459 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5460 };
5461
5462 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5463 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5464 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5465 id,
5466 cx.spawn(async move |lsp_store, cx| {
5467 let resolved_hint = resolve_task.await;
5468 lsp_store
5469 .update(cx, |lsp_store, _| {
5470 if let Some(old_inlay_hint) = lsp_store
5471 .lsp_data
5472 .get_mut(&buffer_id)
5473 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5474 {
5475 match resolved_hint {
5476 Ok(resolved_hint) => {
5477 *old_inlay_hint = resolved_hint;
5478 }
5479 Err(e) => {
5480 old_inlay_hint.resolve_state =
5481 ResolveState::CanResolve(server_id, resolve_data);
5482 log::error!("Inlay hint resolve failed: {e:#}");
5483 }
5484 }
5485 }
5486 })
5487 .ok();
5488 })
5489 .shared(),
5490 );
5491 debug_assert!(
5492 previous_task.is_none(),
5493 "Did not change hint's resolve state after spawning its resolve"
5494 );
5495 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5496 None
5497 }
5498
5499 pub(crate) fn linked_edits(
5500 &mut self,
5501 buffer: &Entity<Buffer>,
5502 position: Anchor,
5503 cx: &mut Context<Self>,
5504 ) -> Task<Result<Vec<Range<Anchor>>>> {
5505 let snapshot = buffer.read(cx).snapshot();
5506 let scope = snapshot.language_scope_at(position);
5507 let Some(server_id) = self
5508 .as_local()
5509 .and_then(|local| {
5510 buffer.update(cx, |buffer, cx| {
5511 local
5512 .language_servers_for_buffer(buffer, cx)
5513 .filter(|(_, server)| {
5514 LinkedEditingRange::check_server_capabilities(server.capabilities())
5515 })
5516 .filter(|(adapter, _)| {
5517 scope
5518 .as_ref()
5519 .map(|scope| scope.language_allowed(&adapter.name))
5520 .unwrap_or(true)
5521 })
5522 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5523 .next()
5524 })
5525 })
5526 .or_else(|| {
5527 self.upstream_client()
5528 .is_some()
5529 .then_some(LanguageServerToQuery::FirstCapable)
5530 })
5531 .filter(|_| {
5532 maybe!({
5533 let language = buffer.read(cx).language_at(position)?;
5534 Some(
5535 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5536 .linked_edits,
5537 )
5538 }) == Some(true)
5539 })
5540 else {
5541 return Task::ready(Ok(Vec::new()));
5542 };
5543
5544 self.request_lsp(
5545 buffer.clone(),
5546 server_id,
5547 LinkedEditingRange { position },
5548 cx,
5549 )
5550 }
5551
5552 fn apply_on_type_formatting(
5553 &mut self,
5554 buffer: Entity<Buffer>,
5555 position: Anchor,
5556 trigger: String,
5557 cx: &mut Context<Self>,
5558 ) -> Task<Result<Option<Transaction>>> {
5559 if let Some((client, project_id)) = self.upstream_client() {
5560 if !self.check_if_capable_for_proto_request(
5561 &buffer,
5562 |capabilities| {
5563 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5564 },
5565 cx,
5566 ) {
5567 return Task::ready(Ok(None));
5568 }
5569 let request = proto::OnTypeFormatting {
5570 project_id,
5571 buffer_id: buffer.read(cx).remote_id().into(),
5572 position: Some(serialize_anchor(&position)),
5573 trigger,
5574 version: serialize_version(&buffer.read(cx).version()),
5575 };
5576 cx.background_spawn(async move {
5577 client
5578 .request(request)
5579 .await?
5580 .transaction
5581 .map(language::proto::deserialize_transaction)
5582 .transpose()
5583 })
5584 } else if let Some(local) = self.as_local_mut() {
5585 let buffer_id = buffer.read(cx).remote_id();
5586 local.buffers_being_formatted.insert(buffer_id);
5587 cx.spawn(async move |this, cx| {
5588 let _cleanup = defer({
5589 let this = this.clone();
5590 let mut cx = cx.clone();
5591 move || {
5592 this.update(&mut cx, |this, _| {
5593 if let Some(local) = this.as_local_mut() {
5594 local.buffers_being_formatted.remove(&buffer_id);
5595 }
5596 })
5597 .ok();
5598 }
5599 });
5600
5601 buffer
5602 .update(cx, |buffer, _| {
5603 buffer.wait_for_edits(Some(position.timestamp()))
5604 })
5605 .await?;
5606 this.update(cx, |this, cx| {
5607 let position = position.to_point_utf16(buffer.read(cx));
5608 this.on_type_format(buffer, position, trigger, false, cx)
5609 })?
5610 .await
5611 })
5612 } else {
5613 Task::ready(Err(anyhow!("No upstream client or local language server")))
5614 }
5615 }
5616
5617 pub fn on_type_format<T: ToPointUtf16>(
5618 &mut self,
5619 buffer: Entity<Buffer>,
5620 position: T,
5621 trigger: String,
5622 push_to_history: bool,
5623 cx: &mut Context<Self>,
5624 ) -> Task<Result<Option<Transaction>>> {
5625 let position = position.to_point_utf16(buffer.read(cx));
5626 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5627 }
5628
5629 fn on_type_format_impl(
5630 &mut self,
5631 buffer: Entity<Buffer>,
5632 position: PointUtf16,
5633 trigger: String,
5634 push_to_history: bool,
5635 cx: &mut Context<Self>,
5636 ) -> Task<Result<Option<Transaction>>> {
5637 let options = buffer.update(cx, |buffer, cx| {
5638 lsp_command::lsp_formatting_options(
5639 language_settings(
5640 buffer.language_at(position).map(|l| l.name()),
5641 buffer.file(),
5642 cx,
5643 )
5644 .as_ref(),
5645 )
5646 });
5647
5648 cx.spawn(async move |this, cx| {
5649 if let Some(waiter) =
5650 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5651 {
5652 waiter.await?;
5653 }
5654 cx.update(|cx| {
5655 this.update(cx, |this, cx| {
5656 this.request_lsp(
5657 buffer.clone(),
5658 LanguageServerToQuery::FirstCapable,
5659 OnTypeFormatting {
5660 position,
5661 trigger,
5662 options,
5663 push_to_history,
5664 },
5665 cx,
5666 )
5667 })
5668 })?
5669 .await
5670 })
5671 }
5672
5673 pub fn definitions(
5674 &mut self,
5675 buffer: &Entity<Buffer>,
5676 position: PointUtf16,
5677 cx: &mut Context<Self>,
5678 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5679 if let Some((upstream_client, project_id)) = self.upstream_client() {
5680 let request = GetDefinitions { position };
5681 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5682 return Task::ready(Ok(None));
5683 }
5684
5685 let request_timeout = ProjectSettings::get_global(cx)
5686 .global_lsp_settings
5687 .get_request_timeout();
5688
5689 let request_task = upstream_client.request_lsp(
5690 project_id,
5691 None,
5692 request_timeout,
5693 cx.background_executor().clone(),
5694 request.to_proto(project_id, buffer.read(cx)),
5695 );
5696 let buffer = buffer.clone();
5697 cx.spawn(async move |weak_lsp_store, cx| {
5698 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5699 return Ok(None);
5700 };
5701 let Some(responses) = request_task.await? else {
5702 return Ok(None);
5703 };
5704 let actions = join_all(responses.payload.into_iter().map(|response| {
5705 GetDefinitions { position }.response_from_proto(
5706 response.response,
5707 lsp_store.clone(),
5708 buffer.clone(),
5709 cx.clone(),
5710 )
5711 }))
5712 .await;
5713
5714 Ok(Some(
5715 actions
5716 .into_iter()
5717 .collect::<Result<Vec<Vec<_>>>>()?
5718 .into_iter()
5719 .flatten()
5720 .dedup()
5721 .collect(),
5722 ))
5723 })
5724 } else {
5725 let definitions_task = self.request_multiple_lsp_locally(
5726 buffer,
5727 Some(position),
5728 GetDefinitions { position },
5729 cx,
5730 );
5731 cx.background_spawn(async move {
5732 Ok(Some(
5733 definitions_task
5734 .await
5735 .into_iter()
5736 .flat_map(|(_, definitions)| definitions)
5737 .dedup()
5738 .collect(),
5739 ))
5740 })
5741 }
5742 }
5743
5744 pub fn declarations(
5745 &mut self,
5746 buffer: &Entity<Buffer>,
5747 position: PointUtf16,
5748 cx: &mut Context<Self>,
5749 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5750 if let Some((upstream_client, project_id)) = self.upstream_client() {
5751 let request = GetDeclarations { position };
5752 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5753 return Task::ready(Ok(None));
5754 }
5755 let request_timeout = ProjectSettings::get_global(cx)
5756 .global_lsp_settings
5757 .get_request_timeout();
5758 let request_task = upstream_client.request_lsp(
5759 project_id,
5760 None,
5761 request_timeout,
5762 cx.background_executor().clone(),
5763 request.to_proto(project_id, buffer.read(cx)),
5764 );
5765 let buffer = buffer.clone();
5766 cx.spawn(async move |weak_lsp_store, cx| {
5767 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5768 return Ok(None);
5769 };
5770 let Some(responses) = request_task.await? else {
5771 return Ok(None);
5772 };
5773 let actions = join_all(responses.payload.into_iter().map(|response| {
5774 GetDeclarations { position }.response_from_proto(
5775 response.response,
5776 lsp_store.clone(),
5777 buffer.clone(),
5778 cx.clone(),
5779 )
5780 }))
5781 .await;
5782
5783 Ok(Some(
5784 actions
5785 .into_iter()
5786 .collect::<Result<Vec<Vec<_>>>>()?
5787 .into_iter()
5788 .flatten()
5789 .dedup()
5790 .collect(),
5791 ))
5792 })
5793 } else {
5794 let declarations_task = self.request_multiple_lsp_locally(
5795 buffer,
5796 Some(position),
5797 GetDeclarations { position },
5798 cx,
5799 );
5800 cx.background_spawn(async move {
5801 Ok(Some(
5802 declarations_task
5803 .await
5804 .into_iter()
5805 .flat_map(|(_, declarations)| declarations)
5806 .dedup()
5807 .collect(),
5808 ))
5809 })
5810 }
5811 }
5812
5813 pub fn type_definitions(
5814 &mut self,
5815 buffer: &Entity<Buffer>,
5816 position: PointUtf16,
5817 cx: &mut Context<Self>,
5818 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5819 if let Some((upstream_client, project_id)) = self.upstream_client() {
5820 let request = GetTypeDefinitions { position };
5821 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5822 return Task::ready(Ok(None));
5823 }
5824 let request_timeout = ProjectSettings::get_global(cx)
5825 .global_lsp_settings
5826 .get_request_timeout();
5827 let request_task = upstream_client.request_lsp(
5828 project_id,
5829 None,
5830 request_timeout,
5831 cx.background_executor().clone(),
5832 request.to_proto(project_id, buffer.read(cx)),
5833 );
5834 let buffer = buffer.clone();
5835 cx.spawn(async move |weak_lsp_store, cx| {
5836 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5837 return Ok(None);
5838 };
5839 let Some(responses) = request_task.await? else {
5840 return Ok(None);
5841 };
5842 let actions = join_all(responses.payload.into_iter().map(|response| {
5843 GetTypeDefinitions { position }.response_from_proto(
5844 response.response,
5845 lsp_store.clone(),
5846 buffer.clone(),
5847 cx.clone(),
5848 )
5849 }))
5850 .await;
5851
5852 Ok(Some(
5853 actions
5854 .into_iter()
5855 .collect::<Result<Vec<Vec<_>>>>()?
5856 .into_iter()
5857 .flatten()
5858 .dedup()
5859 .collect(),
5860 ))
5861 })
5862 } else {
5863 let type_definitions_task = self.request_multiple_lsp_locally(
5864 buffer,
5865 Some(position),
5866 GetTypeDefinitions { position },
5867 cx,
5868 );
5869 cx.background_spawn(async move {
5870 Ok(Some(
5871 type_definitions_task
5872 .await
5873 .into_iter()
5874 .flat_map(|(_, type_definitions)| type_definitions)
5875 .dedup()
5876 .collect(),
5877 ))
5878 })
5879 }
5880 }
5881
5882 pub fn implementations(
5883 &mut self,
5884 buffer: &Entity<Buffer>,
5885 position: PointUtf16,
5886 cx: &mut Context<Self>,
5887 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5888 if let Some((upstream_client, project_id)) = self.upstream_client() {
5889 let request = GetImplementations { position };
5890 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5891 return Task::ready(Ok(None));
5892 }
5893
5894 let request_timeout = ProjectSettings::get_global(cx)
5895 .global_lsp_settings
5896 .get_request_timeout();
5897 let request_task = upstream_client.request_lsp(
5898 project_id,
5899 None,
5900 request_timeout,
5901 cx.background_executor().clone(),
5902 request.to_proto(project_id, buffer.read(cx)),
5903 );
5904 let buffer = buffer.clone();
5905 cx.spawn(async move |weak_lsp_store, cx| {
5906 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5907 return Ok(None);
5908 };
5909 let Some(responses) = request_task.await? else {
5910 return Ok(None);
5911 };
5912 let actions = join_all(responses.payload.into_iter().map(|response| {
5913 GetImplementations { position }.response_from_proto(
5914 response.response,
5915 lsp_store.clone(),
5916 buffer.clone(),
5917 cx.clone(),
5918 )
5919 }))
5920 .await;
5921
5922 Ok(Some(
5923 actions
5924 .into_iter()
5925 .collect::<Result<Vec<Vec<_>>>>()?
5926 .into_iter()
5927 .flatten()
5928 .dedup()
5929 .collect(),
5930 ))
5931 })
5932 } else {
5933 let implementations_task = self.request_multiple_lsp_locally(
5934 buffer,
5935 Some(position),
5936 GetImplementations { position },
5937 cx,
5938 );
5939 cx.background_spawn(async move {
5940 Ok(Some(
5941 implementations_task
5942 .await
5943 .into_iter()
5944 .flat_map(|(_, implementations)| implementations)
5945 .dedup()
5946 .collect(),
5947 ))
5948 })
5949 }
5950 }
5951
5952 pub fn references(
5953 &mut self,
5954 buffer: &Entity<Buffer>,
5955 position: PointUtf16,
5956 cx: &mut Context<Self>,
5957 ) -> Task<Result<Option<Vec<Location>>>> {
5958 if let Some((upstream_client, project_id)) = self.upstream_client() {
5959 let request = GetReferences { position };
5960 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5961 return Task::ready(Ok(None));
5962 }
5963
5964 let request_timeout = ProjectSettings::get_global(cx)
5965 .global_lsp_settings
5966 .get_request_timeout();
5967 let request_task = upstream_client.request_lsp(
5968 project_id,
5969 None,
5970 request_timeout,
5971 cx.background_executor().clone(),
5972 request.to_proto(project_id, buffer.read(cx)),
5973 );
5974 let buffer = buffer.clone();
5975 cx.spawn(async move |weak_lsp_store, cx| {
5976 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5977 return Ok(None);
5978 };
5979 let Some(responses) = request_task.await? else {
5980 return Ok(None);
5981 };
5982
5983 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5984 GetReferences { position }.response_from_proto(
5985 lsp_response.response,
5986 lsp_store.clone(),
5987 buffer.clone(),
5988 cx.clone(),
5989 )
5990 }))
5991 .await
5992 .into_iter()
5993 .collect::<Result<Vec<Vec<_>>>>()?
5994 .into_iter()
5995 .flatten()
5996 .dedup()
5997 .collect();
5998 Ok(Some(locations))
5999 })
6000 } else {
6001 let references_task = self.request_multiple_lsp_locally(
6002 buffer,
6003 Some(position),
6004 GetReferences { position },
6005 cx,
6006 );
6007 cx.background_spawn(async move {
6008 Ok(Some(
6009 references_task
6010 .await
6011 .into_iter()
6012 .flat_map(|(_, references)| references)
6013 .dedup()
6014 .collect(),
6015 ))
6016 })
6017 }
6018 }
6019
6020 pub fn code_actions(
6021 &mut self,
6022 buffer: &Entity<Buffer>,
6023 range: Range<Anchor>,
6024 kinds: Option<Vec<CodeActionKind>>,
6025 cx: &mut Context<Self>,
6026 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6027 if let Some((upstream_client, project_id)) = self.upstream_client() {
6028 let request = GetCodeActions {
6029 range: range.clone(),
6030 kinds: kinds.clone(),
6031 };
6032 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6033 return Task::ready(Ok(None));
6034 }
6035 let request_timeout = ProjectSettings::get_global(cx)
6036 .global_lsp_settings
6037 .get_request_timeout();
6038 let request_task = upstream_client.request_lsp(
6039 project_id,
6040 None,
6041 request_timeout,
6042 cx.background_executor().clone(),
6043 request.to_proto(project_id, buffer.read(cx)),
6044 );
6045 let buffer = buffer.clone();
6046 cx.spawn(async move |weak_lsp_store, cx| {
6047 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6048 return Ok(None);
6049 };
6050 let Some(responses) = request_task.await? else {
6051 return Ok(None);
6052 };
6053 let actions = join_all(responses.payload.into_iter().map(|response| {
6054 GetCodeActions {
6055 range: range.clone(),
6056 kinds: kinds.clone(),
6057 }
6058 .response_from_proto(
6059 response.response,
6060 lsp_store.clone(),
6061 buffer.clone(),
6062 cx.clone(),
6063 )
6064 }))
6065 .await;
6066
6067 Ok(Some(
6068 actions
6069 .into_iter()
6070 .collect::<Result<Vec<Vec<_>>>>()?
6071 .into_iter()
6072 .flatten()
6073 .collect(),
6074 ))
6075 })
6076 } else {
6077 let all_actions_task = self.request_multiple_lsp_locally(
6078 buffer,
6079 Some(range.start),
6080 GetCodeActions { range, kinds },
6081 cx,
6082 );
6083 cx.background_spawn(async move {
6084 Ok(Some(
6085 all_actions_task
6086 .await
6087 .into_iter()
6088 .flat_map(|(_, actions)| actions)
6089 .collect(),
6090 ))
6091 })
6092 }
6093 }
6094
6095 #[inline(never)]
6096 pub fn completions(
6097 &self,
6098 buffer: &Entity<Buffer>,
6099 position: PointUtf16,
6100 context: CompletionContext,
6101 cx: &mut Context<Self>,
6102 ) -> Task<Result<Vec<CompletionResponse>>> {
6103 let language_registry = self.languages.clone();
6104
6105 if let Some((upstream_client, project_id)) = self.upstream_client() {
6106 let snapshot = buffer.read(cx).snapshot();
6107 let offset = position.to_offset(&snapshot);
6108 let scope = snapshot.language_scope_at(offset);
6109 let capable_lsps = self.all_capable_for_proto_request(
6110 buffer,
6111 |server_name, capabilities| {
6112 capabilities.completion_provider.is_some()
6113 && scope
6114 .as_ref()
6115 .map(|scope| scope.language_allowed(server_name))
6116 .unwrap_or(true)
6117 },
6118 cx,
6119 );
6120 if capable_lsps.is_empty() {
6121 return Task::ready(Ok(Vec::new()));
6122 }
6123
6124 let language = buffer.read(cx).language().cloned();
6125
6126 // In the future, we should provide project guests with the names of LSP adapters,
6127 // so that they can use the correct LSP adapter when computing labels. For now,
6128 // guests just use the first LSP adapter associated with the buffer's language.
6129 let lsp_adapter = language.as_ref().and_then(|language| {
6130 language_registry
6131 .lsp_adapters(&language.name())
6132 .first()
6133 .cloned()
6134 });
6135
6136 let buffer = buffer.clone();
6137
6138 cx.spawn(async move |this, cx| {
6139 let requests = join_all(
6140 capable_lsps
6141 .into_iter()
6142 .map(|id| {
6143 let request = GetCompletions {
6144 position,
6145 context: context.clone(),
6146 server_id: Some(id),
6147 };
6148 let buffer = buffer.clone();
6149 let language = language.clone();
6150 let lsp_adapter = lsp_adapter.clone();
6151 let upstream_client = upstream_client.clone();
6152 let response = this
6153 .update(cx, |this, cx| {
6154 this.send_lsp_proto_request(
6155 buffer,
6156 upstream_client,
6157 project_id,
6158 request,
6159 cx,
6160 )
6161 })
6162 .log_err();
6163 async move {
6164 let response = response?.await.log_err()?;
6165
6166 let completions = populate_labels_for_completions(
6167 response.completions,
6168 language,
6169 lsp_adapter,
6170 )
6171 .await;
6172
6173 Some(CompletionResponse {
6174 completions,
6175 display_options: CompletionDisplayOptions::default(),
6176 is_incomplete: response.is_incomplete,
6177 })
6178 }
6179 })
6180 .collect::<Vec<_>>(),
6181 );
6182 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6183 })
6184 } else if let Some(local) = self.as_local() {
6185 let snapshot = buffer.read(cx).snapshot();
6186 let offset = position.to_offset(&snapshot);
6187 let scope = snapshot.language_scope_at(offset);
6188 let language = snapshot.language().cloned();
6189 let completion_settings = language_settings(
6190 language.as_ref().map(|language| language.name()),
6191 buffer.read(cx).file(),
6192 cx,
6193 )
6194 .completions
6195 .clone();
6196 if !completion_settings.lsp {
6197 return Task::ready(Ok(Vec::new()));
6198 }
6199
6200 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6201 local
6202 .language_servers_for_buffer(buffer, cx)
6203 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6204 .filter(|(adapter, _)| {
6205 scope
6206 .as_ref()
6207 .map(|scope| scope.language_allowed(&adapter.name))
6208 .unwrap_or(true)
6209 })
6210 .map(|(_, server)| server.server_id())
6211 .collect()
6212 });
6213
6214 let buffer = buffer.clone();
6215 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6216 let lsp_timeout = if lsp_timeout > 0 {
6217 Some(Duration::from_millis(lsp_timeout))
6218 } else {
6219 None
6220 };
6221 cx.spawn(async move |this, cx| {
6222 let mut tasks = Vec::with_capacity(server_ids.len());
6223 this.update(cx, |lsp_store, cx| {
6224 for server_id in server_ids {
6225 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6226 let lsp_timeout = lsp_timeout
6227 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6228 let mut timeout = cx.background_spawn(async move {
6229 match lsp_timeout {
6230 Some(lsp_timeout) => {
6231 lsp_timeout.await;
6232 true
6233 },
6234 None => false,
6235 }
6236 }).fuse();
6237 let mut lsp_request = lsp_store.request_lsp(
6238 buffer.clone(),
6239 LanguageServerToQuery::Other(server_id),
6240 GetCompletions {
6241 position,
6242 context: context.clone(),
6243 server_id: Some(server_id),
6244 },
6245 cx,
6246 ).fuse();
6247 let new_task = cx.background_spawn(async move {
6248 select_biased! {
6249 response = lsp_request => anyhow::Ok(Some(response?)),
6250 timeout_happened = timeout => {
6251 if timeout_happened {
6252 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6253 Ok(None)
6254 } else {
6255 let completions = lsp_request.await?;
6256 Ok(Some(completions))
6257 }
6258 },
6259 }
6260 });
6261 tasks.push((lsp_adapter, new_task));
6262 }
6263 })?;
6264
6265 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6266 let completion_response = task.await.ok()??;
6267 let completions = populate_labels_for_completions(
6268 completion_response.completions,
6269 language.clone(),
6270 lsp_adapter,
6271 )
6272 .await;
6273 Some(CompletionResponse {
6274 completions,
6275 display_options: CompletionDisplayOptions::default(),
6276 is_incomplete: completion_response.is_incomplete,
6277 })
6278 });
6279
6280 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6281
6282 Ok(responses.into_iter().flatten().collect())
6283 })
6284 } else {
6285 Task::ready(Err(anyhow!("No upstream client or local language server")))
6286 }
6287 }
6288
6289 pub fn resolve_completions(
6290 &self,
6291 buffer: Entity<Buffer>,
6292 completion_indices: Vec<usize>,
6293 completions: Rc<RefCell<Box<[Completion]>>>,
6294 cx: &mut Context<Self>,
6295 ) -> Task<Result<bool>> {
6296 let client = self.upstream_client();
6297 let buffer_id = buffer.read(cx).remote_id();
6298 let buffer_snapshot = buffer.read(cx).snapshot();
6299
6300 if !self.check_if_capable_for_proto_request(
6301 &buffer,
6302 GetCompletions::can_resolve_completions,
6303 cx,
6304 ) {
6305 return Task::ready(Ok(false));
6306 }
6307 cx.spawn(async move |lsp_store, cx| {
6308 let request_timeout = cx.update(|app| {
6309 ProjectSettings::get_global(app)
6310 .global_lsp_settings
6311 .get_request_timeout()
6312 });
6313
6314 let mut did_resolve = false;
6315 if let Some((client, project_id)) = client {
6316 for completion_index in completion_indices {
6317 let server_id = {
6318 let completion = &completions.borrow()[completion_index];
6319 completion.source.server_id()
6320 };
6321 if let Some(server_id) = server_id {
6322 if Self::resolve_completion_remote(
6323 project_id,
6324 server_id,
6325 buffer_id,
6326 completions.clone(),
6327 completion_index,
6328 client.clone(),
6329 )
6330 .await
6331 .log_err()
6332 .is_some()
6333 {
6334 did_resolve = true;
6335 }
6336 } else {
6337 resolve_word_completion(
6338 &buffer_snapshot,
6339 &mut completions.borrow_mut()[completion_index],
6340 );
6341 }
6342 }
6343 } else {
6344 for completion_index in completion_indices {
6345 let server_id = {
6346 let completion = &completions.borrow()[completion_index];
6347 completion.source.server_id()
6348 };
6349 if let Some(server_id) = server_id {
6350 let server_and_adapter = lsp_store
6351 .read_with(cx, |lsp_store, _| {
6352 let server = lsp_store.language_server_for_id(server_id)?;
6353 let adapter =
6354 lsp_store.language_server_adapter_for_id(server.server_id())?;
6355 Some((server, adapter))
6356 })
6357 .ok()
6358 .flatten();
6359 let Some((server, adapter)) = server_and_adapter else {
6360 continue;
6361 };
6362
6363 let resolved = Self::resolve_completion_local(
6364 server,
6365 completions.clone(),
6366 completion_index,
6367 request_timeout,
6368 )
6369 .await
6370 .log_err()
6371 .is_some();
6372 if resolved {
6373 Self::regenerate_completion_labels(
6374 adapter,
6375 &buffer_snapshot,
6376 completions.clone(),
6377 completion_index,
6378 )
6379 .await
6380 .log_err();
6381 did_resolve = true;
6382 }
6383 } else {
6384 resolve_word_completion(
6385 &buffer_snapshot,
6386 &mut completions.borrow_mut()[completion_index],
6387 );
6388 }
6389 }
6390 }
6391
6392 Ok(did_resolve)
6393 })
6394 }
6395
6396 async fn resolve_completion_local(
6397 server: Arc<lsp::LanguageServer>,
6398 completions: Rc<RefCell<Box<[Completion]>>>,
6399 completion_index: usize,
6400 request_timeout: Duration,
6401 ) -> Result<()> {
6402 let server_id = server.server_id();
6403 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6404 return Ok(());
6405 }
6406
6407 let request = {
6408 let completion = &completions.borrow()[completion_index];
6409 match &completion.source {
6410 CompletionSource::Lsp {
6411 lsp_completion,
6412 resolved,
6413 server_id: completion_server_id,
6414 ..
6415 } => {
6416 if *resolved {
6417 return Ok(());
6418 }
6419 anyhow::ensure!(
6420 server_id == *completion_server_id,
6421 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6422 );
6423 server.request::<lsp::request::ResolveCompletionItem>(
6424 *lsp_completion.clone(),
6425 request_timeout,
6426 )
6427 }
6428 CompletionSource::BufferWord { .. }
6429 | CompletionSource::Dap { .. }
6430 | CompletionSource::Custom => {
6431 return Ok(());
6432 }
6433 }
6434 };
6435 let resolved_completion = request
6436 .await
6437 .into_response()
6438 .context("resolve completion")?;
6439
6440 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6441 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6442
6443 let mut completions = completions.borrow_mut();
6444 let completion = &mut completions[completion_index];
6445 if let CompletionSource::Lsp {
6446 lsp_completion,
6447 resolved,
6448 server_id: completion_server_id,
6449 ..
6450 } = &mut completion.source
6451 {
6452 if *resolved {
6453 return Ok(());
6454 }
6455 anyhow::ensure!(
6456 server_id == *completion_server_id,
6457 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6458 );
6459 **lsp_completion = resolved_completion;
6460 *resolved = true;
6461 }
6462 Ok(())
6463 }
6464
6465 async fn regenerate_completion_labels(
6466 adapter: Arc<CachedLspAdapter>,
6467 snapshot: &BufferSnapshot,
6468 completions: Rc<RefCell<Box<[Completion]>>>,
6469 completion_index: usize,
6470 ) -> Result<()> {
6471 let completion_item = completions.borrow()[completion_index]
6472 .source
6473 .lsp_completion(true)
6474 .map(Cow::into_owned);
6475 if let Some(lsp_documentation) = completion_item
6476 .as_ref()
6477 .and_then(|completion_item| completion_item.documentation.clone())
6478 {
6479 let mut completions = completions.borrow_mut();
6480 let completion = &mut completions[completion_index];
6481 completion.documentation = Some(lsp_documentation.into());
6482 } else {
6483 let mut completions = completions.borrow_mut();
6484 let completion = &mut completions[completion_index];
6485 completion.documentation = Some(CompletionDocumentation::Undocumented);
6486 }
6487
6488 let mut new_label = match completion_item {
6489 Some(completion_item) => {
6490 // Some language servers always return `detail` lazily via resolve, regardless of
6491 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6492 // See: https://github.com/yioneko/vtsls/issues/213
6493 let language = snapshot.language();
6494 match language {
6495 Some(language) => {
6496 adapter
6497 .labels_for_completions(
6498 std::slice::from_ref(&completion_item),
6499 language,
6500 )
6501 .await?
6502 }
6503 None => Vec::new(),
6504 }
6505 .pop()
6506 .flatten()
6507 .unwrap_or_else(|| {
6508 CodeLabel::fallback_for_completion(
6509 &completion_item,
6510 language.map(|language| language.as_ref()),
6511 )
6512 })
6513 }
6514 None => CodeLabel::plain(
6515 completions.borrow()[completion_index].new_text.clone(),
6516 None,
6517 ),
6518 };
6519 ensure_uniform_list_compatible_label(&mut new_label);
6520
6521 let mut completions = completions.borrow_mut();
6522 let completion = &mut completions[completion_index];
6523 if completion.label.filter_text() == new_label.filter_text() {
6524 completion.label = new_label;
6525 } else {
6526 log::error!(
6527 "Resolved completion changed display label from {} to {}. \
6528 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6529 completion.label.text(),
6530 new_label.text(),
6531 completion.label.filter_text(),
6532 new_label.filter_text()
6533 );
6534 }
6535
6536 Ok(())
6537 }
6538
6539 async fn resolve_completion_remote(
6540 project_id: u64,
6541 server_id: LanguageServerId,
6542 buffer_id: BufferId,
6543 completions: Rc<RefCell<Box<[Completion]>>>,
6544 completion_index: usize,
6545 client: AnyProtoClient,
6546 ) -> Result<()> {
6547 let lsp_completion = {
6548 let completion = &completions.borrow()[completion_index];
6549 match &completion.source {
6550 CompletionSource::Lsp {
6551 lsp_completion,
6552 resolved,
6553 server_id: completion_server_id,
6554 ..
6555 } => {
6556 anyhow::ensure!(
6557 server_id == *completion_server_id,
6558 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6559 );
6560 if *resolved {
6561 return Ok(());
6562 }
6563 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6564 }
6565 CompletionSource::Custom
6566 | CompletionSource::Dap { .. }
6567 | CompletionSource::BufferWord { .. } => {
6568 return Ok(());
6569 }
6570 }
6571 };
6572 let request = proto::ResolveCompletionDocumentation {
6573 project_id,
6574 language_server_id: server_id.0 as u64,
6575 lsp_completion,
6576 buffer_id: buffer_id.into(),
6577 };
6578
6579 let response = client
6580 .request(request)
6581 .await
6582 .context("completion documentation resolve proto request")?;
6583 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6584
6585 let documentation = if response.documentation.is_empty() {
6586 CompletionDocumentation::Undocumented
6587 } else if response.documentation_is_markdown {
6588 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6589 } else if response.documentation.lines().count() <= 1 {
6590 CompletionDocumentation::SingleLine(response.documentation.into())
6591 } else {
6592 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6593 };
6594
6595 let mut completions = completions.borrow_mut();
6596 let completion = &mut completions[completion_index];
6597 completion.documentation = Some(documentation);
6598 if let CompletionSource::Lsp {
6599 insert_range,
6600 lsp_completion,
6601 resolved,
6602 server_id: completion_server_id,
6603 lsp_defaults: _,
6604 } = &mut completion.source
6605 {
6606 let completion_insert_range = response
6607 .old_insert_start
6608 .and_then(deserialize_anchor)
6609 .zip(response.old_insert_end.and_then(deserialize_anchor));
6610 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6611
6612 if *resolved {
6613 return Ok(());
6614 }
6615 anyhow::ensure!(
6616 server_id == *completion_server_id,
6617 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6618 );
6619 **lsp_completion = resolved_lsp_completion;
6620 *resolved = true;
6621 }
6622
6623 let replace_range = response
6624 .old_replace_start
6625 .and_then(deserialize_anchor)
6626 .zip(response.old_replace_end.and_then(deserialize_anchor));
6627 if let Some((old_replace_start, old_replace_end)) = replace_range
6628 && !response.new_text.is_empty()
6629 {
6630 completion.new_text = response.new_text;
6631 completion.replace_range = old_replace_start..old_replace_end;
6632 }
6633
6634 Ok(())
6635 }
6636
6637 pub fn apply_additional_edits_for_completion(
6638 &self,
6639 buffer_handle: Entity<Buffer>,
6640 completions: Rc<RefCell<Box<[Completion]>>>,
6641 completion_index: usize,
6642 push_to_history: bool,
6643 cx: &mut Context<Self>,
6644 ) -> Task<Result<Option<Transaction>>> {
6645 if let Some((client, project_id)) = self.upstream_client() {
6646 let buffer = buffer_handle.read(cx);
6647 let buffer_id = buffer.remote_id();
6648 cx.spawn(async move |_, cx| {
6649 let request = {
6650 let completion = completions.borrow()[completion_index].clone();
6651 proto::ApplyCompletionAdditionalEdits {
6652 project_id,
6653 buffer_id: buffer_id.into(),
6654 completion: Some(Self::serialize_completion(&CoreCompletion {
6655 replace_range: completion.replace_range,
6656 new_text: completion.new_text,
6657 source: completion.source,
6658 })),
6659 }
6660 };
6661
6662 let Some(transaction) = client.request(request).await?.transaction else {
6663 return Ok(None);
6664 };
6665
6666 let transaction = language::proto::deserialize_transaction(transaction)?;
6667 buffer_handle
6668 .update(cx, |buffer, _| {
6669 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6670 })
6671 .await?;
6672 if push_to_history {
6673 buffer_handle.update(cx, |buffer, _| {
6674 buffer.push_transaction(transaction.clone(), Instant::now());
6675 buffer.finalize_last_transaction();
6676 });
6677 }
6678 Ok(Some(transaction))
6679 })
6680 } else {
6681 let request_timeout = ProjectSettings::get_global(cx)
6682 .global_lsp_settings
6683 .get_request_timeout();
6684
6685 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6686 let completion = &completions.borrow()[completion_index];
6687 let server_id = completion.source.server_id()?;
6688 Some(
6689 self.language_server_for_local_buffer(buffer, server_id, cx)?
6690 .1
6691 .clone(),
6692 )
6693 }) else {
6694 return Task::ready(Ok(None));
6695 };
6696
6697 cx.spawn(async move |this, cx| {
6698 Self::resolve_completion_local(
6699 server.clone(),
6700 completions.clone(),
6701 completion_index,
6702 request_timeout,
6703 )
6704 .await
6705 .context("resolving completion")?;
6706 let completion = completions.borrow()[completion_index].clone();
6707 let additional_text_edits = completion
6708 .source
6709 .lsp_completion(true)
6710 .as_ref()
6711 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6712 if let Some(edits) = additional_text_edits {
6713 let edits = this
6714 .update(cx, |this, cx| {
6715 this.as_local_mut().unwrap().edits_from_lsp(
6716 &buffer_handle,
6717 edits,
6718 server.server_id(),
6719 None,
6720 cx,
6721 )
6722 })?
6723 .await?;
6724
6725 buffer_handle.update(cx, |buffer, cx| {
6726 buffer.finalize_last_transaction();
6727 buffer.start_transaction();
6728
6729 for (range, text) in edits {
6730 let primary = &completion.replace_range;
6731
6732 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6733 // and the primary completion is just an insertion (empty range), then this is likely
6734 // an auto-import scenario and should not be considered overlapping
6735 // https://github.com/zed-industries/zed/issues/26136
6736 let is_file_start_auto_import = {
6737 let snapshot = buffer.snapshot();
6738 let primary_start_point = primary.start.to_point(&snapshot);
6739 let range_start_point = range.start.to_point(&snapshot);
6740
6741 let result = primary_start_point.row == 0
6742 && primary_start_point.column == 0
6743 && range_start_point.row == 0
6744 && range_start_point.column == 0;
6745
6746 result
6747 };
6748
6749 let has_overlap = if is_file_start_auto_import {
6750 false
6751 } else {
6752 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6753 && primary.end.cmp(&range.start, buffer).is_ge();
6754 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6755 && range.end.cmp(&primary.end, buffer).is_ge();
6756 let result = start_within || end_within;
6757 result
6758 };
6759
6760 //Skip additional edits which overlap with the primary completion edit
6761 //https://github.com/zed-industries/zed/pull/1871
6762 if !has_overlap {
6763 buffer.edit([(range, text)], None, cx);
6764 }
6765 }
6766
6767 let transaction = if buffer.end_transaction(cx).is_some() {
6768 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6769 if !push_to_history {
6770 buffer.forget_transaction(transaction.id);
6771 }
6772 Some(transaction)
6773 } else {
6774 None
6775 };
6776 Ok(transaction)
6777 })
6778 } else {
6779 Ok(None)
6780 }
6781 })
6782 }
6783 }
6784
6785 pub fn pull_diagnostics(
6786 &mut self,
6787 buffer: Entity<Buffer>,
6788 cx: &mut Context<Self>,
6789 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6790 let buffer_id = buffer.read(cx).remote_id();
6791
6792 if let Some((client, upstream_project_id)) = self.upstream_client() {
6793 let mut suitable_capabilities = None;
6794 // Are we capable for proto request?
6795 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6796 &buffer,
6797 |capabilities| {
6798 if let Some(caps) = &capabilities.diagnostic_provider {
6799 suitable_capabilities = Some(caps.clone());
6800 true
6801 } else {
6802 false
6803 }
6804 },
6805 cx,
6806 );
6807 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6808 let Some(dynamic_caps) = suitable_capabilities else {
6809 return Task::ready(Ok(None));
6810 };
6811 assert!(any_server_has_diagnostics_provider);
6812
6813 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6814 let request = GetDocumentDiagnostics {
6815 previous_result_id: None,
6816 identifier,
6817 registration_id: None,
6818 };
6819 let request_timeout = ProjectSettings::get_global(cx)
6820 .global_lsp_settings
6821 .get_request_timeout();
6822 let request_task = client.request_lsp(
6823 upstream_project_id,
6824 None,
6825 request_timeout,
6826 cx.background_executor().clone(),
6827 request.to_proto(upstream_project_id, buffer.read(cx)),
6828 );
6829 cx.background_spawn(async move {
6830 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6831 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6832 // Do not attempt to further process the dummy responses here.
6833 let _response = request_task.await?;
6834 Ok(None)
6835 })
6836 } else {
6837 let servers = buffer.update(cx, |buffer, cx| {
6838 self.running_language_servers_for_local_buffer(buffer, cx)
6839 .map(|(_, server)| server.clone())
6840 .collect::<Vec<_>>()
6841 });
6842
6843 let pull_diagnostics = servers
6844 .into_iter()
6845 .flat_map(|server| {
6846 let result = maybe!({
6847 let local = self.as_local()?;
6848 let server_id = server.server_id();
6849 let providers_with_identifiers = local
6850 .language_server_dynamic_registrations
6851 .get(&server_id)
6852 .into_iter()
6853 .flat_map(|registrations| registrations.diagnostics.clone())
6854 .collect::<Vec<_>>();
6855 Some(
6856 providers_with_identifiers
6857 .into_iter()
6858 .map(|(registration_id, dynamic_caps)| {
6859 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6860 let registration_id = registration_id.map(SharedString::from);
6861 let result_id = self.result_id_for_buffer_pull(
6862 server_id,
6863 buffer_id,
6864 ®istration_id,
6865 cx,
6866 );
6867 self.request_lsp(
6868 buffer.clone(),
6869 LanguageServerToQuery::Other(server_id),
6870 GetDocumentDiagnostics {
6871 previous_result_id: result_id,
6872 registration_id,
6873 identifier,
6874 },
6875 cx,
6876 )
6877 })
6878 .collect::<Vec<_>>(),
6879 )
6880 });
6881
6882 result.unwrap_or_default()
6883 })
6884 .collect::<Vec<_>>();
6885
6886 cx.background_spawn(async move {
6887 let mut responses = Vec::new();
6888 for diagnostics in join_all(pull_diagnostics).await {
6889 responses.extend(diagnostics?);
6890 }
6891 Ok(Some(responses))
6892 })
6893 }
6894 }
6895
6896 pub fn applicable_inlay_chunks(
6897 &mut self,
6898 buffer: &Entity<Buffer>,
6899 ranges: &[Range<text::Anchor>],
6900 cx: &mut Context<Self>,
6901 ) -> Vec<Range<BufferRow>> {
6902 let buffer_snapshot = buffer.read(cx).snapshot();
6903 let ranges = ranges
6904 .iter()
6905 .map(|range| range.to_point(&buffer_snapshot))
6906 .collect::<Vec<_>>();
6907
6908 self.latest_lsp_data(buffer, cx)
6909 .inlay_hints
6910 .applicable_chunks(ranges.as_slice())
6911 .map(|chunk| chunk.row_range())
6912 .collect()
6913 }
6914
6915 pub fn invalidate_inlay_hints<'a>(
6916 &'a mut self,
6917 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6918 ) {
6919 for buffer_id in for_buffers {
6920 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6921 lsp_data.inlay_hints.clear();
6922 }
6923 }
6924 }
6925
6926 pub fn inlay_hints(
6927 &mut self,
6928 invalidate: InvalidationStrategy,
6929 buffer: Entity<Buffer>,
6930 ranges: Vec<Range<text::Anchor>>,
6931 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6932 cx: &mut Context<Self>,
6933 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6934 let next_hint_id = self.next_hint_id.clone();
6935 let lsp_data = self.latest_lsp_data(&buffer, cx);
6936 let query_version = lsp_data.buffer_version.clone();
6937 let mut lsp_refresh_requested = false;
6938 let for_server = if let InvalidationStrategy::RefreshRequested {
6939 server_id,
6940 request_id,
6941 } = invalidate
6942 {
6943 let invalidated = lsp_data
6944 .inlay_hints
6945 .invalidate_for_server_refresh(server_id, request_id);
6946 lsp_refresh_requested = invalidated;
6947 Some(server_id)
6948 } else {
6949 None
6950 };
6951 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6952 let known_chunks = known_chunks
6953 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6954 .map(|(_, known_chunks)| known_chunks)
6955 .unwrap_or_default();
6956
6957 let buffer_snapshot = buffer.read(cx).snapshot();
6958 let ranges = ranges
6959 .iter()
6960 .map(|range| range.to_point(&buffer_snapshot))
6961 .collect::<Vec<_>>();
6962
6963 let mut hint_fetch_tasks = Vec::new();
6964 let mut cached_inlay_hints = None;
6965 let mut ranges_to_query = None;
6966 let applicable_chunks = existing_inlay_hints
6967 .applicable_chunks(ranges.as_slice())
6968 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6969 .collect::<Vec<_>>();
6970 if applicable_chunks.is_empty() {
6971 return HashMap::default();
6972 }
6973
6974 for row_chunk in applicable_chunks {
6975 match (
6976 existing_inlay_hints
6977 .cached_hints(&row_chunk)
6978 .filter(|_| !lsp_refresh_requested)
6979 .cloned(),
6980 existing_inlay_hints
6981 .fetched_hints(&row_chunk)
6982 .as_ref()
6983 .filter(|_| !lsp_refresh_requested)
6984 .cloned(),
6985 ) {
6986 (None, None) => {
6987 let chunk_range = row_chunk.anchor_range();
6988 ranges_to_query
6989 .get_or_insert_with(Vec::new)
6990 .push((row_chunk, chunk_range));
6991 }
6992 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6993 (Some(cached_hints), None) => {
6994 for (server_id, cached_hints) in cached_hints {
6995 if for_server.is_none_or(|for_server| for_server == server_id) {
6996 cached_inlay_hints
6997 .get_or_insert_with(HashMap::default)
6998 .entry(row_chunk.row_range())
6999 .or_insert_with(HashMap::default)
7000 .entry(server_id)
7001 .or_insert_with(Vec::new)
7002 .extend(cached_hints);
7003 }
7004 }
7005 }
7006 (Some(cached_hints), Some(fetched_hints)) => {
7007 hint_fetch_tasks.push((row_chunk, fetched_hints));
7008 for (server_id, cached_hints) in cached_hints {
7009 if for_server.is_none_or(|for_server| for_server == server_id) {
7010 cached_inlay_hints
7011 .get_or_insert_with(HashMap::default)
7012 .entry(row_chunk.row_range())
7013 .or_insert_with(HashMap::default)
7014 .entry(server_id)
7015 .or_insert_with(Vec::new)
7016 .extend(cached_hints);
7017 }
7018 }
7019 }
7020 }
7021 }
7022
7023 if hint_fetch_tasks.is_empty()
7024 && ranges_to_query
7025 .as_ref()
7026 .is_none_or(|ranges| ranges.is_empty())
7027 && let Some(cached_inlay_hints) = cached_inlay_hints
7028 {
7029 cached_inlay_hints
7030 .into_iter()
7031 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7032 .collect()
7033 } else {
7034 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7035 // When a server refresh was requested, other servers' cached hints
7036 // are unaffected by the refresh and must be included in the result.
7037 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7038 // removes all visible hints but only adds back the requesting
7039 // server's new hints, permanently losing other servers' hints.
7040 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7041 lsp_data
7042 .inlay_hints
7043 .cached_hints(&chunk)
7044 .cloned()
7045 .unwrap_or_default()
7046 } else {
7047 HashMap::default()
7048 };
7049
7050 let next_hint_id = next_hint_id.clone();
7051 let buffer = buffer.clone();
7052 let query_version = query_version.clone();
7053 let new_inlay_hints = cx
7054 .spawn(async move |lsp_store, cx| {
7055 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7056 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7057 })?;
7058 new_fetch_task
7059 .await
7060 .and_then(|new_hints_by_server| {
7061 lsp_store.update(cx, |lsp_store, cx| {
7062 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7063 let update_cache = lsp_data.buffer_version == query_version;
7064 if new_hints_by_server.is_empty() {
7065 if update_cache {
7066 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7067 }
7068 other_servers_cached
7069 } else {
7070 let mut result = other_servers_cached;
7071 for (server_id, new_hints) in new_hints_by_server {
7072 let new_hints = new_hints
7073 .into_iter()
7074 .map(|new_hint| {
7075 (
7076 InlayId::Hint(next_hint_id.fetch_add(
7077 1,
7078 atomic::Ordering::AcqRel,
7079 )),
7080 new_hint,
7081 )
7082 })
7083 .collect::<Vec<_>>();
7084 if update_cache {
7085 lsp_data.inlay_hints.insert_new_hints(
7086 chunk,
7087 server_id,
7088 new_hints.clone(),
7089 );
7090 }
7091 result.insert(server_id, new_hints);
7092 }
7093 result
7094 }
7095 })
7096 })
7097 .map_err(Arc::new)
7098 })
7099 .shared();
7100
7101 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7102 *fetch_task = Some(new_inlay_hints.clone());
7103 hint_fetch_tasks.push((chunk, new_inlay_hints));
7104 }
7105
7106 cached_inlay_hints
7107 .unwrap_or_default()
7108 .into_iter()
7109 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7110 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7111 (
7112 chunk.row_range(),
7113 cx.spawn(async move |_, _| {
7114 hints_fetch.await.map_err(|e| {
7115 if e.error_code() != ErrorCode::Internal {
7116 anyhow!(e.error_code())
7117 } else {
7118 anyhow!("{e:#}")
7119 }
7120 })
7121 }),
7122 )
7123 }))
7124 .collect()
7125 }
7126 }
7127
7128 fn fetch_inlay_hints(
7129 &mut self,
7130 for_server: Option<LanguageServerId>,
7131 buffer: &Entity<Buffer>,
7132 range: Range<Anchor>,
7133 cx: &mut Context<Self>,
7134 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7135 let request = InlayHints {
7136 range: range.clone(),
7137 };
7138 if let Some((upstream_client, project_id)) = self.upstream_client() {
7139 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7140 return Task::ready(Ok(HashMap::default()));
7141 }
7142 let request_timeout = ProjectSettings::get_global(cx)
7143 .global_lsp_settings
7144 .get_request_timeout();
7145 let request_task = upstream_client.request_lsp(
7146 project_id,
7147 for_server.map(|id| id.to_proto()),
7148 request_timeout,
7149 cx.background_executor().clone(),
7150 request.to_proto(project_id, buffer.read(cx)),
7151 );
7152 let buffer = buffer.clone();
7153 cx.spawn(async move |weak_lsp_store, cx| {
7154 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7155 return Ok(HashMap::default());
7156 };
7157 let Some(responses) = request_task.await? else {
7158 return Ok(HashMap::default());
7159 };
7160
7161 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7162 let lsp_store = lsp_store.clone();
7163 let buffer = buffer.clone();
7164 let cx = cx.clone();
7165 let request = request.clone();
7166 async move {
7167 (
7168 LanguageServerId::from_proto(response.server_id),
7169 request
7170 .response_from_proto(response.response, lsp_store, buffer, cx)
7171 .await,
7172 )
7173 }
7174 }))
7175 .await;
7176
7177 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7178 let mut has_errors = false;
7179 let inlay_hints = inlay_hints
7180 .into_iter()
7181 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7182 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7183 Err(e) => {
7184 has_errors = true;
7185 log::error!("{e:#}");
7186 None
7187 }
7188 })
7189 .map(|(server_id, mut new_hints)| {
7190 new_hints.retain(|hint| {
7191 hint.position.is_valid(&buffer_snapshot)
7192 && range.start.is_valid(&buffer_snapshot)
7193 && range.end.is_valid(&buffer_snapshot)
7194 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7195 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7196 });
7197 (server_id, new_hints)
7198 })
7199 .collect::<HashMap<_, _>>();
7200 anyhow::ensure!(
7201 !has_errors || !inlay_hints.is_empty(),
7202 "Failed to fetch inlay hints"
7203 );
7204 Ok(inlay_hints)
7205 })
7206 } else {
7207 let inlay_hints_task = match for_server {
7208 Some(server_id) => {
7209 let server_task = self.request_lsp(
7210 buffer.clone(),
7211 LanguageServerToQuery::Other(server_id),
7212 request,
7213 cx,
7214 );
7215 cx.background_spawn(async move {
7216 let mut responses = Vec::new();
7217 match server_task.await {
7218 Ok(response) => responses.push((server_id, response)),
7219 // rust-analyzer likes to error with this when its still loading up
7220 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7221 Err(e) => log::error!(
7222 "Error handling response for inlay hints request: {e:#}"
7223 ),
7224 }
7225 responses
7226 })
7227 }
7228 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7229 };
7230 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7231 cx.background_spawn(async move {
7232 Ok(inlay_hints_task
7233 .await
7234 .into_iter()
7235 .map(|(server_id, mut new_hints)| {
7236 new_hints.retain(|hint| {
7237 hint.position.is_valid(&buffer_snapshot)
7238 && range.start.is_valid(&buffer_snapshot)
7239 && range.end.is_valid(&buffer_snapshot)
7240 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7241 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7242 });
7243 (server_id, new_hints)
7244 })
7245 .collect())
7246 })
7247 }
7248 }
7249
7250 fn diagnostic_registration_exists(
7251 &self,
7252 server_id: LanguageServerId,
7253 registration_id: &Option<SharedString>,
7254 ) -> bool {
7255 let Some(local) = self.as_local() else {
7256 return false;
7257 };
7258 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7259 else {
7260 return false;
7261 };
7262 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7263 registrations.diagnostics.contains_key(®istration_key)
7264 }
7265
7266 pub fn pull_diagnostics_for_buffer(
7267 &mut self,
7268 buffer: Entity<Buffer>,
7269 cx: &mut Context<Self>,
7270 ) -> Task<anyhow::Result<()>> {
7271 let diagnostics = self.pull_diagnostics(buffer, cx);
7272 cx.spawn(async move |lsp_store, cx| {
7273 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7274 return Ok(());
7275 };
7276 lsp_store.update(cx, |lsp_store, cx| {
7277 if lsp_store.as_local().is_none() {
7278 return;
7279 }
7280
7281 let mut unchanged_buffers = HashMap::default();
7282 let server_diagnostics_updates = diagnostics
7283 .into_iter()
7284 .filter_map(|diagnostics_set| match diagnostics_set {
7285 LspPullDiagnostics::Response {
7286 server_id,
7287 uri,
7288 diagnostics,
7289 registration_id,
7290 } => Some((server_id, uri, diagnostics, registration_id)),
7291 LspPullDiagnostics::Default => None,
7292 })
7293 .filter(|(server_id, _, _, registration_id)| {
7294 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7295 })
7296 .fold(
7297 HashMap::default(),
7298 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7299 let (result_id, diagnostics) = match diagnostics {
7300 PulledDiagnostics::Unchanged { result_id } => {
7301 unchanged_buffers
7302 .entry(new_registration_id.clone())
7303 .or_insert_with(HashSet::default)
7304 .insert(uri.clone());
7305 (Some(result_id), Vec::new())
7306 }
7307 PulledDiagnostics::Changed {
7308 result_id,
7309 diagnostics,
7310 } => (result_id, diagnostics),
7311 };
7312 let disk_based_sources = Cow::Owned(
7313 lsp_store
7314 .language_server_adapter_for_id(server_id)
7315 .as_ref()
7316 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7317 .unwrap_or(&[])
7318 .to_vec(),
7319 );
7320 acc.entry(server_id)
7321 .or_insert_with(HashMap::default)
7322 .entry(new_registration_id.clone())
7323 .or_insert_with(Vec::new)
7324 .push(DocumentDiagnosticsUpdate {
7325 server_id,
7326 diagnostics: lsp::PublishDiagnosticsParams {
7327 uri,
7328 diagnostics,
7329 version: None,
7330 },
7331 result_id: result_id.map(SharedString::new),
7332 disk_based_sources,
7333 registration_id: new_registration_id,
7334 });
7335 acc
7336 },
7337 );
7338
7339 for diagnostic_updates in server_diagnostics_updates.into_values() {
7340 for (registration_id, diagnostic_updates) in diagnostic_updates {
7341 lsp_store
7342 .merge_lsp_diagnostics(
7343 DiagnosticSourceKind::Pulled,
7344 diagnostic_updates,
7345 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7346 DiagnosticSourceKind::Pulled => {
7347 old_diagnostic.registration_id != registration_id
7348 || unchanged_buffers
7349 .get(&old_diagnostic.registration_id)
7350 .is_some_and(|unchanged_buffers| {
7351 unchanged_buffers.contains(&document_uri)
7352 })
7353 }
7354 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7355 true
7356 }
7357 },
7358 cx,
7359 )
7360 .log_err();
7361 }
7362 }
7363 })
7364 })
7365 }
7366
7367 pub fn signature_help<T: ToPointUtf16>(
7368 &mut self,
7369 buffer: &Entity<Buffer>,
7370 position: T,
7371 cx: &mut Context<Self>,
7372 ) -> Task<Option<Vec<SignatureHelp>>> {
7373 let position = position.to_point_utf16(buffer.read(cx));
7374
7375 if let Some((client, upstream_project_id)) = self.upstream_client() {
7376 let request = GetSignatureHelp { position };
7377 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7378 return Task::ready(None);
7379 }
7380 let request_timeout = ProjectSettings::get_global(cx)
7381 .global_lsp_settings
7382 .get_request_timeout();
7383 let request_task = client.request_lsp(
7384 upstream_project_id,
7385 None,
7386 request_timeout,
7387 cx.background_executor().clone(),
7388 request.to_proto(upstream_project_id, buffer.read(cx)),
7389 );
7390 let buffer = buffer.clone();
7391 cx.spawn(async move |weak_lsp_store, cx| {
7392 let lsp_store = weak_lsp_store.upgrade()?;
7393 let signatures = join_all(
7394 request_task
7395 .await
7396 .log_err()
7397 .flatten()
7398 .map(|response| response.payload)
7399 .unwrap_or_default()
7400 .into_iter()
7401 .map(|response| {
7402 let response = GetSignatureHelp { position }.response_from_proto(
7403 response.response,
7404 lsp_store.clone(),
7405 buffer.clone(),
7406 cx.clone(),
7407 );
7408 async move { response.await.log_err().flatten() }
7409 }),
7410 )
7411 .await
7412 .into_iter()
7413 .flatten()
7414 .collect();
7415 Some(signatures)
7416 })
7417 } else {
7418 let all_actions_task = self.request_multiple_lsp_locally(
7419 buffer,
7420 Some(position),
7421 GetSignatureHelp { position },
7422 cx,
7423 );
7424 cx.background_spawn(async move {
7425 Some(
7426 all_actions_task
7427 .await
7428 .into_iter()
7429 .flat_map(|(_, actions)| actions)
7430 .collect::<Vec<_>>(),
7431 )
7432 })
7433 }
7434 }
7435
7436 pub fn hover(
7437 &mut self,
7438 buffer: &Entity<Buffer>,
7439 position: PointUtf16,
7440 cx: &mut Context<Self>,
7441 ) -> Task<Option<Vec<Hover>>> {
7442 if let Some((client, upstream_project_id)) = self.upstream_client() {
7443 let request = GetHover { position };
7444 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7445 return Task::ready(None);
7446 }
7447 let request_timeout = ProjectSettings::get_global(cx)
7448 .global_lsp_settings
7449 .get_request_timeout();
7450 let request_task = client.request_lsp(
7451 upstream_project_id,
7452 None,
7453 request_timeout,
7454 cx.background_executor().clone(),
7455 request.to_proto(upstream_project_id, buffer.read(cx)),
7456 );
7457 let buffer = buffer.clone();
7458 cx.spawn(async move |weak_lsp_store, cx| {
7459 let lsp_store = weak_lsp_store.upgrade()?;
7460 let hovers = join_all(
7461 request_task
7462 .await
7463 .log_err()
7464 .flatten()
7465 .map(|response| response.payload)
7466 .unwrap_or_default()
7467 .into_iter()
7468 .map(|response| {
7469 let response = GetHover { position }.response_from_proto(
7470 response.response,
7471 lsp_store.clone(),
7472 buffer.clone(),
7473 cx.clone(),
7474 );
7475 async move {
7476 response
7477 .await
7478 .log_err()
7479 .flatten()
7480 .and_then(remove_empty_hover_blocks)
7481 }
7482 }),
7483 )
7484 .await
7485 .into_iter()
7486 .flatten()
7487 .collect();
7488 Some(hovers)
7489 })
7490 } else {
7491 let all_actions_task = self.request_multiple_lsp_locally(
7492 buffer,
7493 Some(position),
7494 GetHover { position },
7495 cx,
7496 );
7497 cx.background_spawn(async move {
7498 Some(
7499 all_actions_task
7500 .await
7501 .into_iter()
7502 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7503 .collect::<Vec<Hover>>(),
7504 )
7505 })
7506 }
7507 }
7508
7509 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7510 let language_registry = self.languages.clone();
7511
7512 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7513 let request = upstream_client.request(proto::GetProjectSymbols {
7514 project_id: *project_id,
7515 query: query.to_string(),
7516 });
7517 cx.foreground_executor().spawn(async move {
7518 let response = request.await?;
7519 let mut symbols = Vec::new();
7520 let core_symbols = response
7521 .symbols
7522 .into_iter()
7523 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7524 .collect::<Vec<_>>();
7525 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7526 .await;
7527 Ok(symbols)
7528 })
7529 } else if let Some(local) = self.as_local() {
7530 struct WorkspaceSymbolsResult {
7531 server_id: LanguageServerId,
7532 lsp_adapter: Arc<CachedLspAdapter>,
7533 worktree: WeakEntity<Worktree>,
7534 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7535 }
7536
7537 let mut requests = Vec::new();
7538 let mut requested_servers = BTreeSet::new();
7539 let request_timeout = ProjectSettings::get_global(cx)
7540 .global_lsp_settings
7541 .get_request_timeout();
7542
7543 for (seed, state) in local.language_server_ids.iter() {
7544 let Some(worktree_handle) = self
7545 .worktree_store
7546 .read(cx)
7547 .worktree_for_id(seed.worktree_id, cx)
7548 else {
7549 continue;
7550 };
7551
7552 let worktree = worktree_handle.read(cx);
7553 if !worktree.is_visible() {
7554 continue;
7555 }
7556
7557 if !requested_servers.insert(state.id) {
7558 continue;
7559 }
7560
7561 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7562 Some(LanguageServerState::Running {
7563 adapter, server, ..
7564 }) => (adapter.clone(), server),
7565
7566 _ => continue,
7567 };
7568
7569 let supports_workspace_symbol_request =
7570 match server.capabilities().workspace_symbol_provider {
7571 Some(OneOf::Left(supported)) => supported,
7572 Some(OneOf::Right(_)) => true,
7573 None => false,
7574 };
7575
7576 if !supports_workspace_symbol_request {
7577 continue;
7578 }
7579
7580 let worktree_handle = worktree_handle.clone();
7581 let server_id = server.server_id();
7582 requests.push(
7583 server
7584 .request::<lsp::request::WorkspaceSymbolRequest>(
7585 lsp::WorkspaceSymbolParams {
7586 query: query.to_string(),
7587 ..Default::default()
7588 },
7589 request_timeout,
7590 )
7591 .map(move |response| {
7592 let lsp_symbols = response
7593 .into_response()
7594 .context("workspace symbols request")
7595 .log_err()
7596 .flatten()
7597 .map(|symbol_response| match symbol_response {
7598 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7599 flat_responses
7600 .into_iter()
7601 .map(|lsp_symbol| {
7602 (
7603 lsp_symbol.name,
7604 lsp_symbol.kind,
7605 lsp_symbol.location,
7606 lsp_symbol.container_name,
7607 )
7608 })
7609 .collect::<Vec<_>>()
7610 }
7611 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7612 nested_responses
7613 .into_iter()
7614 .filter_map(|lsp_symbol| {
7615 let location = match lsp_symbol.location {
7616 OneOf::Left(location) => location,
7617 OneOf::Right(_) => {
7618 log::error!(
7619 "Unexpected: client capabilities \
7620 forbid symbol resolutions in \
7621 workspace.symbol.resolveSupport"
7622 );
7623 return None;
7624 }
7625 };
7626 Some((
7627 lsp_symbol.name,
7628 lsp_symbol.kind,
7629 location,
7630 lsp_symbol.container_name,
7631 ))
7632 })
7633 .collect::<Vec<_>>()
7634 }
7635 })
7636 .unwrap_or_default();
7637
7638 WorkspaceSymbolsResult {
7639 server_id,
7640 lsp_adapter,
7641 worktree: worktree_handle.downgrade(),
7642 lsp_symbols,
7643 }
7644 }),
7645 );
7646 }
7647
7648 cx.spawn(async move |this, cx| {
7649 let responses = futures::future::join_all(requests).await;
7650 let this = match this.upgrade() {
7651 Some(this) => this,
7652 None => return Ok(Vec::new()),
7653 };
7654
7655 let mut symbols = Vec::new();
7656 for result in responses {
7657 let core_symbols = this.update(cx, |this, cx| {
7658 result
7659 .lsp_symbols
7660 .into_iter()
7661 .filter_map(
7662 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7663 let abs_path = symbol_location.uri.to_file_path().ok()?;
7664 let source_worktree = result.worktree.upgrade()?;
7665 let source_worktree_id = source_worktree.read(cx).id();
7666
7667 let path = if let Some((tree, rel_path)) =
7668 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7669 {
7670 let worktree_id = tree.read(cx).id();
7671 SymbolLocation::InProject(ProjectPath {
7672 worktree_id,
7673 path: rel_path,
7674 })
7675 } else {
7676 SymbolLocation::OutsideProject {
7677 signature: this.symbol_signature(&abs_path),
7678 abs_path: abs_path.into(),
7679 }
7680 };
7681
7682 Some(CoreSymbol {
7683 source_language_server_id: result.server_id,
7684 language_server_name: result.lsp_adapter.name.clone(),
7685 source_worktree_id,
7686 path,
7687 kind: symbol_kind,
7688 name: collapse_newlines(&symbol_name, "↵ "),
7689 range: range_from_lsp(symbol_location.range),
7690 container_name: container_name
7691 .map(|c| collapse_newlines(&c, "↵ ")),
7692 })
7693 },
7694 )
7695 .collect::<Vec<_>>()
7696 });
7697
7698 populate_labels_for_symbols(
7699 core_symbols,
7700 &language_registry,
7701 Some(result.lsp_adapter),
7702 &mut symbols,
7703 )
7704 .await;
7705 }
7706
7707 Ok(symbols)
7708 })
7709 } else {
7710 Task::ready(Err(anyhow!("No upstream client or local language server")))
7711 }
7712 }
7713
7714 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7715 let mut summary = DiagnosticSummary::default();
7716 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7717 summary.error_count += path_summary.error_count;
7718 summary.warning_count += path_summary.warning_count;
7719 }
7720 summary
7721 }
7722
7723 /// Returns the diagnostic summary for a specific project path.
7724 pub fn diagnostic_summary_for_path(
7725 &self,
7726 project_path: &ProjectPath,
7727 _: &App,
7728 ) -> DiagnosticSummary {
7729 if let Some(summaries) = self
7730 .diagnostic_summaries
7731 .get(&project_path.worktree_id)
7732 .and_then(|map| map.get(&project_path.path))
7733 {
7734 let (error_count, warning_count) = summaries.iter().fold(
7735 (0, 0),
7736 |(error_count, warning_count), (_language_server_id, summary)| {
7737 (
7738 error_count + summary.error_count,
7739 warning_count + summary.warning_count,
7740 )
7741 },
7742 );
7743
7744 DiagnosticSummary {
7745 error_count,
7746 warning_count,
7747 }
7748 } else {
7749 DiagnosticSummary::default()
7750 }
7751 }
7752
7753 pub fn diagnostic_summaries<'a>(
7754 &'a self,
7755 include_ignored: bool,
7756 cx: &'a App,
7757 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7758 self.worktree_store
7759 .read(cx)
7760 .visible_worktrees(cx)
7761 .filter_map(|worktree| {
7762 let worktree = worktree.read(cx);
7763 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7764 })
7765 .flat_map(move |(worktree, summaries)| {
7766 let worktree_id = worktree.id();
7767 summaries
7768 .iter()
7769 .filter(move |(path, _)| {
7770 include_ignored
7771 || worktree
7772 .entry_for_path(path.as_ref())
7773 .is_some_and(|entry| !entry.is_ignored)
7774 })
7775 .flat_map(move |(path, summaries)| {
7776 summaries.iter().map(move |(server_id, summary)| {
7777 (
7778 ProjectPath {
7779 worktree_id,
7780 path: path.clone(),
7781 },
7782 *server_id,
7783 *summary,
7784 )
7785 })
7786 })
7787 })
7788 }
7789
7790 pub fn on_buffer_edited(
7791 &mut self,
7792 buffer: Entity<Buffer>,
7793 cx: &mut Context<Self>,
7794 ) -> Option<()> {
7795 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7796 Some(
7797 self.as_local()?
7798 .language_servers_for_buffer(buffer, cx)
7799 .map(|i| i.1.clone())
7800 .collect(),
7801 )
7802 })?;
7803
7804 let buffer = buffer.read(cx);
7805 let file = File::from_dyn(buffer.file())?;
7806 let abs_path = file.as_local()?.abs_path(cx);
7807 let uri = lsp::Uri::from_file_path(&abs_path)
7808 .ok()
7809 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7810 .log_err()?;
7811 let next_snapshot = buffer.text_snapshot();
7812 for language_server in language_servers {
7813 let language_server = language_server.clone();
7814
7815 let buffer_snapshots = self
7816 .as_local_mut()?
7817 .buffer_snapshots
7818 .get_mut(&buffer.remote_id())
7819 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7820 let previous_snapshot = buffer_snapshots.last()?;
7821
7822 let build_incremental_change = || {
7823 buffer
7824 .edits_since::<Dimensions<PointUtf16, usize>>(
7825 previous_snapshot.snapshot.version(),
7826 )
7827 .map(|edit| {
7828 let edit_start = edit.new.start.0;
7829 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7830 let new_text = next_snapshot
7831 .text_for_range(edit.new.start.1..edit.new.end.1)
7832 .collect();
7833 lsp::TextDocumentContentChangeEvent {
7834 range: Some(lsp::Range::new(
7835 point_to_lsp(edit_start),
7836 point_to_lsp(edit_end),
7837 )),
7838 range_length: None,
7839 text: new_text,
7840 }
7841 })
7842 .collect()
7843 };
7844
7845 let document_sync_kind = language_server
7846 .capabilities()
7847 .text_document_sync
7848 .as_ref()
7849 .and_then(|sync| match sync {
7850 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7851 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7852 });
7853
7854 let content_changes: Vec<_> = match document_sync_kind {
7855 Some(lsp::TextDocumentSyncKind::FULL) => {
7856 vec![lsp::TextDocumentContentChangeEvent {
7857 range: None,
7858 range_length: None,
7859 text: next_snapshot.text(),
7860 }]
7861 }
7862 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7863 _ => {
7864 #[cfg(any(test, feature = "test-support"))]
7865 {
7866 build_incremental_change()
7867 }
7868
7869 #[cfg(not(any(test, feature = "test-support")))]
7870 {
7871 continue;
7872 }
7873 }
7874 };
7875
7876 let next_version = previous_snapshot.version + 1;
7877 buffer_snapshots.push(LspBufferSnapshot {
7878 version: next_version,
7879 snapshot: next_snapshot.clone(),
7880 });
7881
7882 language_server
7883 .notify::<lsp::notification::DidChangeTextDocument>(
7884 lsp::DidChangeTextDocumentParams {
7885 text_document: lsp::VersionedTextDocumentIdentifier::new(
7886 uri.clone(),
7887 next_version,
7888 ),
7889 content_changes,
7890 },
7891 )
7892 .ok();
7893 self.pull_workspace_diagnostics(language_server.server_id());
7894 }
7895
7896 None
7897 }
7898
7899 pub fn on_buffer_saved(
7900 &mut self,
7901 buffer: Entity<Buffer>,
7902 cx: &mut Context<Self>,
7903 ) -> Option<()> {
7904 let file = File::from_dyn(buffer.read(cx).file())?;
7905 let worktree_id = file.worktree_id(cx);
7906 let abs_path = file.as_local()?.abs_path(cx);
7907 let text_document = lsp::TextDocumentIdentifier {
7908 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7909 };
7910 let local = self.as_local()?;
7911
7912 for server in local.language_servers_for_worktree(worktree_id) {
7913 if let Some(include_text) = include_text(server.as_ref()) {
7914 let text = if include_text {
7915 Some(buffer.read(cx).text())
7916 } else {
7917 None
7918 };
7919 server
7920 .notify::<lsp::notification::DidSaveTextDocument>(
7921 lsp::DidSaveTextDocumentParams {
7922 text_document: text_document.clone(),
7923 text,
7924 },
7925 )
7926 .ok();
7927 }
7928 }
7929
7930 let language_servers = buffer.update(cx, |buffer, cx| {
7931 local.language_server_ids_for_buffer(buffer, cx)
7932 });
7933 for language_server_id in language_servers {
7934 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7935 }
7936
7937 None
7938 }
7939
7940 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7941 maybe!(async move {
7942 let mut refreshed_servers = HashSet::default();
7943 let servers = lsp_store
7944 .update(cx, |lsp_store, cx| {
7945 let local = lsp_store.as_local()?;
7946
7947 let servers = local
7948 .language_server_ids
7949 .iter()
7950 .filter_map(|(seed, state)| {
7951 let worktree = lsp_store
7952 .worktree_store
7953 .read(cx)
7954 .worktree_for_id(seed.worktree_id, cx);
7955 let delegate: Arc<dyn LspAdapterDelegate> =
7956 worktree.map(|worktree| {
7957 LocalLspAdapterDelegate::new(
7958 local.languages.clone(),
7959 &local.environment,
7960 cx.weak_entity(),
7961 &worktree,
7962 local.http_client.clone(),
7963 local.fs.clone(),
7964 cx,
7965 )
7966 })?;
7967 let server_id = state.id;
7968
7969 let states = local.language_servers.get(&server_id)?;
7970
7971 match states {
7972 LanguageServerState::Starting { .. } => None,
7973 LanguageServerState::Running {
7974 adapter, server, ..
7975 } => {
7976 let adapter = adapter.clone();
7977 let server = server.clone();
7978 refreshed_servers.insert(server.name());
7979 let toolchain = seed.toolchain.clone();
7980 Some(cx.spawn(async move |_, cx| {
7981 let settings =
7982 LocalLspStore::workspace_configuration_for_adapter(
7983 adapter.adapter.clone(),
7984 &delegate,
7985 toolchain,
7986 None,
7987 cx,
7988 )
7989 .await
7990 .ok()?;
7991 server
7992 .notify::<lsp::notification::DidChangeConfiguration>(
7993 lsp::DidChangeConfigurationParams { settings },
7994 )
7995 .ok()?;
7996 Some(())
7997 }))
7998 }
7999 }
8000 })
8001 .collect::<Vec<_>>();
8002
8003 Some(servers)
8004 })
8005 .ok()
8006 .flatten()?;
8007
8008 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8009 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8010 // to stop and unregister its language server wrapper.
8011 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8012 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8013 let _: Vec<Option<()>> = join_all(servers).await;
8014
8015 Some(())
8016 })
8017 .await;
8018 }
8019
8020 fn maintain_workspace_config(
8021 external_refresh_requests: watch::Receiver<()>,
8022 cx: &mut Context<Self>,
8023 ) -> Task<Result<()>> {
8024 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8025 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8026
8027 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8028 *settings_changed_tx.borrow_mut() = ();
8029 });
8030
8031 let mut joint_future =
8032 futures::stream::select(settings_changed_rx, external_refresh_requests);
8033 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8034 // - 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).
8035 // - 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.
8036 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8037 // - 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,
8038 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8039 cx.spawn(async move |this, cx| {
8040 while let Some(()) = joint_future.next().await {
8041 this.update(cx, |this, cx| {
8042 this.refresh_server_tree(cx);
8043 })
8044 .ok();
8045
8046 Self::refresh_workspace_configurations(&this, cx).await;
8047 }
8048
8049 drop(settings_observation);
8050 anyhow::Ok(())
8051 })
8052 }
8053
8054 pub fn running_language_servers_for_local_buffer<'a>(
8055 &'a self,
8056 buffer: &Buffer,
8057 cx: &mut App,
8058 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8059 let local = self.as_local();
8060 let language_server_ids = local
8061 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8062 .unwrap_or_default();
8063
8064 language_server_ids
8065 .into_iter()
8066 .filter_map(
8067 move |server_id| match local?.language_servers.get(&server_id)? {
8068 LanguageServerState::Running {
8069 adapter, server, ..
8070 } => Some((adapter, server)),
8071 _ => None,
8072 },
8073 )
8074 }
8075
8076 pub fn language_servers_for_local_buffer(
8077 &self,
8078 buffer: &Buffer,
8079 cx: &mut App,
8080 ) -> Vec<LanguageServerId> {
8081 let local = self.as_local();
8082 local
8083 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8084 .unwrap_or_default()
8085 }
8086
8087 pub fn language_server_for_local_buffer<'a>(
8088 &'a self,
8089 buffer: &'a Buffer,
8090 server_id: LanguageServerId,
8091 cx: &'a mut App,
8092 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8093 self.as_local()?
8094 .language_servers_for_buffer(buffer, cx)
8095 .find(|(_, s)| s.server_id() == server_id)
8096 }
8097
8098 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8099 self.diagnostic_summaries.remove(&id_to_remove);
8100 if let Some(local) = self.as_local_mut() {
8101 let to_remove = local.remove_worktree(id_to_remove, cx);
8102 for server in to_remove {
8103 self.language_server_statuses.remove(&server);
8104 }
8105 }
8106 }
8107
8108 pub fn shared(
8109 &mut self,
8110 project_id: u64,
8111 downstream_client: AnyProtoClient,
8112 _: &mut Context<Self>,
8113 ) {
8114 self.downstream_client = Some((downstream_client.clone(), project_id));
8115
8116 for (server_id, status) in &self.language_server_statuses {
8117 if let Some(server) = self.language_server_for_id(*server_id) {
8118 downstream_client
8119 .send(proto::StartLanguageServer {
8120 project_id,
8121 server: Some(proto::LanguageServer {
8122 id: server_id.to_proto(),
8123 name: status.name.to_string(),
8124 worktree_id: status.worktree.map(|id| id.to_proto()),
8125 }),
8126 capabilities: serde_json::to_string(&server.capabilities())
8127 .expect("serializing server LSP capabilities"),
8128 })
8129 .log_err();
8130 }
8131 }
8132 }
8133
8134 pub fn disconnected_from_host(&mut self) {
8135 self.downstream_client.take();
8136 }
8137
8138 pub fn disconnected_from_ssh_remote(&mut self) {
8139 if let LspStoreMode::Remote(RemoteLspStore {
8140 upstream_client, ..
8141 }) = &mut self.mode
8142 {
8143 upstream_client.take();
8144 }
8145 }
8146
8147 pub(crate) fn set_language_server_statuses_from_proto(
8148 &mut self,
8149 project: WeakEntity<Project>,
8150 language_servers: Vec<proto::LanguageServer>,
8151 server_capabilities: Vec<String>,
8152 cx: &mut Context<Self>,
8153 ) {
8154 let lsp_logs = cx
8155 .try_global::<GlobalLogStore>()
8156 .map(|lsp_store| lsp_store.0.clone());
8157
8158 self.language_server_statuses = language_servers
8159 .into_iter()
8160 .zip(server_capabilities)
8161 .map(|(server, server_capabilities)| {
8162 let server_id = LanguageServerId(server.id as usize);
8163 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8164 self.lsp_server_capabilities
8165 .insert(server_id, server_capabilities);
8166 }
8167
8168 let name = LanguageServerName::from_proto(server.name);
8169 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8170
8171 if let Some(lsp_logs) = &lsp_logs {
8172 lsp_logs.update(cx, |lsp_logs, cx| {
8173 lsp_logs.add_language_server(
8174 // Only remote clients get their language servers set from proto
8175 LanguageServerKind::Remote {
8176 project: project.clone(),
8177 },
8178 server_id,
8179 Some(name.clone()),
8180 worktree,
8181 None,
8182 cx,
8183 );
8184 });
8185 }
8186
8187 (
8188 server_id,
8189 LanguageServerStatus {
8190 name,
8191 server_version: None,
8192 pending_work: Default::default(),
8193 has_pending_diagnostic_updates: false,
8194 progress_tokens: Default::default(),
8195 worktree,
8196 binary: None,
8197 configuration: None,
8198 workspace_folders: BTreeSet::new(),
8199 process_id: None,
8200 },
8201 )
8202 })
8203 .collect();
8204 }
8205
8206 #[cfg(feature = "test-support")]
8207 pub fn update_diagnostic_entries(
8208 &mut self,
8209 server_id: LanguageServerId,
8210 abs_path: PathBuf,
8211 result_id: Option<SharedString>,
8212 version: Option<i32>,
8213 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8214 cx: &mut Context<Self>,
8215 ) -> anyhow::Result<()> {
8216 self.merge_diagnostic_entries(
8217 vec![DocumentDiagnosticsUpdate {
8218 diagnostics: DocumentDiagnostics {
8219 diagnostics,
8220 document_abs_path: abs_path,
8221 version,
8222 },
8223 result_id,
8224 server_id,
8225 disk_based_sources: Cow::Borrowed(&[]),
8226 registration_id: None,
8227 }],
8228 |_, _, _| false,
8229 cx,
8230 )?;
8231 Ok(())
8232 }
8233
8234 pub fn merge_diagnostic_entries<'a>(
8235 &mut self,
8236 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8237 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8238 cx: &mut Context<Self>,
8239 ) -> anyhow::Result<()> {
8240 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8241 let mut updated_diagnostics_paths = HashMap::default();
8242 for mut update in diagnostic_updates {
8243 let abs_path = &update.diagnostics.document_abs_path;
8244 let server_id = update.server_id;
8245 let Some((worktree, relative_path)) =
8246 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8247 else {
8248 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8249 return Ok(());
8250 };
8251
8252 let worktree_id = worktree.read(cx).id();
8253 let project_path = ProjectPath {
8254 worktree_id,
8255 path: relative_path,
8256 };
8257
8258 let document_uri = lsp::Uri::from_file_path(abs_path)
8259 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8260 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8261 let snapshot = buffer_handle.read(cx).snapshot();
8262 let buffer = buffer_handle.read(cx);
8263 let reused_diagnostics = buffer
8264 .buffer_diagnostics(Some(server_id))
8265 .iter()
8266 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8267 .map(|v| {
8268 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8269 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8270 DiagnosticEntry {
8271 range: start..end,
8272 diagnostic: v.diagnostic.clone(),
8273 }
8274 })
8275 .collect::<Vec<_>>();
8276
8277 self.as_local_mut()
8278 .context("cannot merge diagnostics on a remote LspStore")?
8279 .update_buffer_diagnostics(
8280 &buffer_handle,
8281 server_id,
8282 Some(update.registration_id),
8283 update.result_id,
8284 update.diagnostics.version,
8285 update.diagnostics.diagnostics.clone(),
8286 reused_diagnostics.clone(),
8287 cx,
8288 )?;
8289
8290 update.diagnostics.diagnostics.extend(reused_diagnostics);
8291 } else if let Some(local) = self.as_local() {
8292 let reused_diagnostics = local
8293 .diagnostics
8294 .get(&worktree_id)
8295 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8296 .and_then(|diagnostics_by_server_id| {
8297 diagnostics_by_server_id
8298 .binary_search_by_key(&server_id, |e| e.0)
8299 .ok()
8300 .map(|ix| &diagnostics_by_server_id[ix].1)
8301 })
8302 .into_iter()
8303 .flatten()
8304 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8305
8306 update
8307 .diagnostics
8308 .diagnostics
8309 .extend(reused_diagnostics.cloned());
8310 }
8311
8312 let updated = worktree.update(cx, |worktree, cx| {
8313 self.update_worktree_diagnostics(
8314 worktree.id(),
8315 server_id,
8316 project_path.path.clone(),
8317 update.diagnostics.diagnostics,
8318 cx,
8319 )
8320 })?;
8321 match updated {
8322 ControlFlow::Continue(new_summary) => {
8323 if let Some((project_id, new_summary)) = new_summary {
8324 match &mut diagnostics_summary {
8325 Some(diagnostics_summary) => {
8326 diagnostics_summary
8327 .more_summaries
8328 .push(proto::DiagnosticSummary {
8329 path: project_path.path.as_ref().to_proto(),
8330 language_server_id: server_id.0 as u64,
8331 error_count: new_summary.error_count,
8332 warning_count: new_summary.warning_count,
8333 })
8334 }
8335 None => {
8336 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8337 project_id,
8338 worktree_id: worktree_id.to_proto(),
8339 summary: Some(proto::DiagnosticSummary {
8340 path: project_path.path.as_ref().to_proto(),
8341 language_server_id: server_id.0 as u64,
8342 error_count: new_summary.error_count,
8343 warning_count: new_summary.warning_count,
8344 }),
8345 more_summaries: Vec::new(),
8346 })
8347 }
8348 }
8349 }
8350 updated_diagnostics_paths
8351 .entry(server_id)
8352 .or_insert_with(Vec::new)
8353 .push(project_path);
8354 }
8355 ControlFlow::Break(()) => {}
8356 }
8357 }
8358
8359 if let Some((diagnostics_summary, (downstream_client, _))) =
8360 diagnostics_summary.zip(self.downstream_client.as_ref())
8361 {
8362 downstream_client.send(diagnostics_summary).log_err();
8363 }
8364 for (server_id, paths) in updated_diagnostics_paths {
8365 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8366 }
8367 Ok(())
8368 }
8369
8370 fn update_worktree_diagnostics(
8371 &mut self,
8372 worktree_id: WorktreeId,
8373 server_id: LanguageServerId,
8374 path_in_worktree: Arc<RelPath>,
8375 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8376 _: &mut Context<Worktree>,
8377 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8378 let local = match &mut self.mode {
8379 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8380 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8381 };
8382
8383 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8384 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8385 let summaries_by_server_id = summaries_for_tree
8386 .entry(path_in_worktree.clone())
8387 .or_default();
8388
8389 let old_summary = summaries_by_server_id
8390 .remove(&server_id)
8391 .unwrap_or_default();
8392
8393 let new_summary = DiagnosticSummary::new(&diagnostics);
8394 if diagnostics.is_empty() {
8395 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8396 {
8397 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8398 diagnostics_by_server_id.remove(ix);
8399 }
8400 if diagnostics_by_server_id.is_empty() {
8401 diagnostics_for_tree.remove(&path_in_worktree);
8402 }
8403 }
8404 } else {
8405 summaries_by_server_id.insert(server_id, new_summary);
8406 let diagnostics_by_server_id = diagnostics_for_tree
8407 .entry(path_in_worktree.clone())
8408 .or_default();
8409 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8410 Ok(ix) => {
8411 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8412 }
8413 Err(ix) => {
8414 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8415 }
8416 }
8417 }
8418
8419 if !old_summary.is_empty() || !new_summary.is_empty() {
8420 if let Some((_, project_id)) = &self.downstream_client {
8421 Ok(ControlFlow::Continue(Some((
8422 *project_id,
8423 proto::DiagnosticSummary {
8424 path: path_in_worktree.to_proto(),
8425 language_server_id: server_id.0 as u64,
8426 error_count: new_summary.error_count as u32,
8427 warning_count: new_summary.warning_count as u32,
8428 },
8429 ))))
8430 } else {
8431 Ok(ControlFlow::Continue(None))
8432 }
8433 } else {
8434 Ok(ControlFlow::Break(()))
8435 }
8436 }
8437
8438 pub fn open_buffer_for_symbol(
8439 &mut self,
8440 symbol: &Symbol,
8441 cx: &mut Context<Self>,
8442 ) -> Task<Result<Entity<Buffer>>> {
8443 if let Some((client, project_id)) = self.upstream_client() {
8444 let request = client.request(proto::OpenBufferForSymbol {
8445 project_id,
8446 symbol: Some(Self::serialize_symbol(symbol)),
8447 });
8448 cx.spawn(async move |this, cx| {
8449 let response = request.await?;
8450 let buffer_id = BufferId::new(response.buffer_id)?;
8451 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8452 .await
8453 })
8454 } else if let Some(local) = self.as_local() {
8455 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8456 seed.worktree_id == symbol.source_worktree_id
8457 && state.id == symbol.source_language_server_id
8458 && symbol.language_server_name == seed.name
8459 });
8460 if !is_valid {
8461 return Task::ready(Err(anyhow!(
8462 "language server for worktree and language not found"
8463 )));
8464 };
8465
8466 let symbol_abs_path = match &symbol.path {
8467 SymbolLocation::InProject(project_path) => self
8468 .worktree_store
8469 .read(cx)
8470 .absolutize(&project_path, cx)
8471 .context("no such worktree"),
8472 SymbolLocation::OutsideProject {
8473 abs_path,
8474 signature: _,
8475 } => Ok(abs_path.to_path_buf()),
8476 };
8477 let symbol_abs_path = match symbol_abs_path {
8478 Ok(abs_path) => abs_path,
8479 Err(err) => return Task::ready(Err(err)),
8480 };
8481 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8482 uri
8483 } else {
8484 return Task::ready(Err(anyhow!("invalid symbol path")));
8485 };
8486
8487 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8488 } else {
8489 Task::ready(Err(anyhow!("no upstream client or local store")))
8490 }
8491 }
8492
8493 pub(crate) fn open_local_buffer_via_lsp(
8494 &mut self,
8495 abs_path: lsp::Uri,
8496 language_server_id: LanguageServerId,
8497 cx: &mut Context<Self>,
8498 ) -> Task<Result<Entity<Buffer>>> {
8499 let path_style = self.worktree_store.read(cx).path_style();
8500 cx.spawn(async move |lsp_store, cx| {
8501 // Escape percent-encoded string.
8502 let current_scheme = abs_path.scheme().to_owned();
8503 // Uri is immutable, so we can't modify the scheme
8504
8505 let abs_path = abs_path
8506 .to_file_path_ext(path_style)
8507 .map_err(|()| anyhow!("can't convert URI to path"))?;
8508 let p = abs_path.clone();
8509 let yarn_worktree = lsp_store
8510 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8511 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8512 cx.spawn(async move |this, cx| {
8513 let t = this
8514 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8515 .ok()?;
8516 t.await
8517 })
8518 }),
8519 None => Task::ready(None),
8520 })?
8521 .await;
8522 let (worktree_root_target, known_relative_path) =
8523 if let Some((zip_root, relative_path)) = yarn_worktree {
8524 (zip_root, Some(relative_path))
8525 } else {
8526 (Arc::<Path>::from(abs_path.as_path()), None)
8527 };
8528 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8529 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8530 worktree_store.find_worktree(&worktree_root_target, cx)
8531 })
8532 })?;
8533 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8534 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8535 (result.0, relative_path, None)
8536 } else {
8537 let worktree = lsp_store
8538 .update(cx, |lsp_store, cx| {
8539 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8540 worktree_store.create_worktree(&worktree_root_target, false, cx)
8541 })
8542 })?
8543 .await?;
8544 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8545 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8546 lsp_store
8547 .update(cx, |lsp_store, cx| {
8548 if let Some(local) = lsp_store.as_local_mut() {
8549 local.register_language_server_for_invisible_worktree(
8550 &worktree,
8551 language_server_id,
8552 cx,
8553 )
8554 }
8555 match lsp_store.language_server_statuses.get(&language_server_id) {
8556 Some(status) => status.worktree,
8557 None => None,
8558 }
8559 })
8560 .ok()
8561 .flatten()
8562 .zip(Some(worktree_root.clone()))
8563 } else {
8564 None
8565 };
8566 let relative_path = if let Some(known_path) = known_relative_path {
8567 known_path
8568 } else {
8569 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8570 .into_arc()
8571 };
8572 (worktree, relative_path, source_ws)
8573 };
8574 let project_path = ProjectPath {
8575 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8576 path: relative_path,
8577 };
8578 let buffer = lsp_store
8579 .update(cx, |lsp_store, cx| {
8580 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8581 buffer_store.open_buffer(project_path, cx)
8582 })
8583 })?
8584 .await?;
8585 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8586 if let Some((source_ws, worktree_root)) = source_ws {
8587 buffer.update(cx, |buffer, cx| {
8588 let settings = WorktreeSettings::get(
8589 Some(
8590 (&ProjectPath {
8591 worktree_id: source_ws,
8592 path: Arc::from(RelPath::empty()),
8593 })
8594 .into(),
8595 ),
8596 cx,
8597 );
8598 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8599 if is_read_only {
8600 buffer.set_capability(Capability::ReadOnly, cx);
8601 }
8602 });
8603 }
8604 Ok(buffer)
8605 })
8606 }
8607
8608 fn local_lsp_servers_for_buffer(
8609 &self,
8610 buffer: &Entity<Buffer>,
8611 cx: &mut Context<Self>,
8612 ) -> Vec<LanguageServerId> {
8613 let Some(local) = self.as_local() else {
8614 return Vec::new();
8615 };
8616
8617 let snapshot = buffer.read(cx).snapshot();
8618
8619 buffer.update(cx, |buffer, cx| {
8620 local
8621 .language_servers_for_buffer(buffer, cx)
8622 .map(|(_, server)| server.server_id())
8623 .filter(|server_id| {
8624 self.as_local().is_none_or(|local| {
8625 local
8626 .buffers_opened_in_servers
8627 .get(&snapshot.remote_id())
8628 .is_some_and(|servers| servers.contains(server_id))
8629 })
8630 })
8631 .collect()
8632 })
8633 }
8634
8635 fn request_multiple_lsp_locally<P, R>(
8636 &mut self,
8637 buffer: &Entity<Buffer>,
8638 position: Option<P>,
8639 request: R,
8640 cx: &mut Context<Self>,
8641 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8642 where
8643 P: ToOffset,
8644 R: LspCommand + Clone,
8645 <R::LspRequest as lsp::request::Request>::Result: Send,
8646 <R::LspRequest as lsp::request::Request>::Params: Send,
8647 {
8648 let Some(local) = self.as_local() else {
8649 return Task::ready(Vec::new());
8650 };
8651
8652 let snapshot = buffer.read(cx).snapshot();
8653 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8654
8655 let server_ids = buffer.update(cx, |buffer, cx| {
8656 local
8657 .language_servers_for_buffer(buffer, cx)
8658 .filter(|(adapter, _)| {
8659 scope
8660 .as_ref()
8661 .map(|scope| scope.language_allowed(&adapter.name))
8662 .unwrap_or(true)
8663 })
8664 .map(|(_, server)| server.server_id())
8665 .filter(|server_id| {
8666 self.as_local().is_none_or(|local| {
8667 local
8668 .buffers_opened_in_servers
8669 .get(&snapshot.remote_id())
8670 .is_some_and(|servers| servers.contains(server_id))
8671 })
8672 })
8673 .collect::<Vec<_>>()
8674 });
8675
8676 let mut response_results = server_ids
8677 .into_iter()
8678 .map(|server_id| {
8679 let task = self.request_lsp(
8680 buffer.clone(),
8681 LanguageServerToQuery::Other(server_id),
8682 request.clone(),
8683 cx,
8684 );
8685 async move { (server_id, task.await) }
8686 })
8687 .collect::<FuturesUnordered<_>>();
8688
8689 cx.background_spawn(async move {
8690 let mut responses = Vec::with_capacity(response_results.len());
8691 while let Some((server_id, response_result)) = response_results.next().await {
8692 match response_result {
8693 Ok(response) => responses.push((server_id, response)),
8694 // rust-analyzer likes to error with this when its still loading up
8695 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8696 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8697 }
8698 }
8699 responses
8700 })
8701 }
8702
8703 async fn handle_lsp_get_completions(
8704 this: Entity<Self>,
8705 envelope: TypedEnvelope<proto::GetCompletions>,
8706 mut cx: AsyncApp,
8707 ) -> Result<proto::GetCompletionsResponse> {
8708 let sender_id = envelope.original_sender_id().unwrap_or_default();
8709
8710 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8711 let buffer_handle = this.update(&mut cx, |this, cx| {
8712 this.buffer_store.read(cx).get_existing(buffer_id)
8713 })?;
8714 let request = GetCompletions::from_proto(
8715 envelope.payload,
8716 this.clone(),
8717 buffer_handle.clone(),
8718 cx.clone(),
8719 )
8720 .await?;
8721
8722 let server_to_query = match request.server_id {
8723 Some(server_id) => LanguageServerToQuery::Other(server_id),
8724 None => LanguageServerToQuery::FirstCapable,
8725 };
8726
8727 let response = this
8728 .update(&mut cx, |this, cx| {
8729 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8730 })
8731 .await?;
8732 this.update(&mut cx, |this, cx| {
8733 Ok(GetCompletions::response_to_proto(
8734 response,
8735 this,
8736 sender_id,
8737 &buffer_handle.read(cx).version(),
8738 cx,
8739 ))
8740 })
8741 }
8742
8743 async fn handle_lsp_command<T: LspCommand>(
8744 this: Entity<Self>,
8745 envelope: TypedEnvelope<T::ProtoRequest>,
8746 mut cx: AsyncApp,
8747 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8748 where
8749 <T::LspRequest as lsp::request::Request>::Params: Send,
8750 <T::LspRequest as lsp::request::Request>::Result: Send,
8751 {
8752 let sender_id = envelope.original_sender_id().unwrap_or_default();
8753 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8754 let buffer_handle = this.update(&mut cx, |this, cx| {
8755 this.buffer_store.read(cx).get_existing(buffer_id)
8756 })?;
8757 let request = T::from_proto(
8758 envelope.payload,
8759 this.clone(),
8760 buffer_handle.clone(),
8761 cx.clone(),
8762 )
8763 .await?;
8764 let response = this
8765 .update(&mut cx, |this, cx| {
8766 this.request_lsp(
8767 buffer_handle.clone(),
8768 LanguageServerToQuery::FirstCapable,
8769 request,
8770 cx,
8771 )
8772 })
8773 .await?;
8774 this.update(&mut cx, |this, cx| {
8775 Ok(T::response_to_proto(
8776 response,
8777 this,
8778 sender_id,
8779 &buffer_handle.read(cx).version(),
8780 cx,
8781 ))
8782 })
8783 }
8784
8785 async fn handle_lsp_query(
8786 lsp_store: Entity<Self>,
8787 envelope: TypedEnvelope<proto::LspQuery>,
8788 mut cx: AsyncApp,
8789 ) -> Result<proto::Ack> {
8790 use proto::lsp_query::Request;
8791 let sender_id = envelope.original_sender_id().unwrap_or_default();
8792 let lsp_query = envelope.payload;
8793 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8794 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8795 match lsp_query.request.context("invalid LSP query request")? {
8796 Request::GetReferences(get_references) => {
8797 let position = get_references.position.clone().and_then(deserialize_anchor);
8798 Self::query_lsp_locally::<GetReferences>(
8799 lsp_store,
8800 server_id,
8801 sender_id,
8802 lsp_request_id,
8803 get_references,
8804 position,
8805 &mut cx,
8806 )
8807 .await?;
8808 }
8809 Request::GetDocumentColor(get_document_color) => {
8810 Self::query_lsp_locally::<GetDocumentColor>(
8811 lsp_store,
8812 server_id,
8813 sender_id,
8814 lsp_request_id,
8815 get_document_color,
8816 None,
8817 &mut cx,
8818 )
8819 .await?;
8820 }
8821 Request::GetFoldingRanges(get_folding_ranges) => {
8822 Self::query_lsp_locally::<GetFoldingRanges>(
8823 lsp_store,
8824 server_id,
8825 sender_id,
8826 lsp_request_id,
8827 get_folding_ranges,
8828 None,
8829 &mut cx,
8830 )
8831 .await?;
8832 }
8833 Request::GetDocumentSymbols(get_document_symbols) => {
8834 Self::query_lsp_locally::<GetDocumentSymbols>(
8835 lsp_store,
8836 server_id,
8837 sender_id,
8838 lsp_request_id,
8839 get_document_symbols,
8840 None,
8841 &mut cx,
8842 )
8843 .await?;
8844 }
8845 Request::GetHover(get_hover) => {
8846 let position = get_hover.position.clone().and_then(deserialize_anchor);
8847 Self::query_lsp_locally::<GetHover>(
8848 lsp_store,
8849 server_id,
8850 sender_id,
8851 lsp_request_id,
8852 get_hover,
8853 position,
8854 &mut cx,
8855 )
8856 .await?;
8857 }
8858 Request::GetCodeActions(get_code_actions) => {
8859 Self::query_lsp_locally::<GetCodeActions>(
8860 lsp_store,
8861 server_id,
8862 sender_id,
8863 lsp_request_id,
8864 get_code_actions,
8865 None,
8866 &mut cx,
8867 )
8868 .await?;
8869 }
8870 Request::GetSignatureHelp(get_signature_help) => {
8871 let position = get_signature_help
8872 .position
8873 .clone()
8874 .and_then(deserialize_anchor);
8875 Self::query_lsp_locally::<GetSignatureHelp>(
8876 lsp_store,
8877 server_id,
8878 sender_id,
8879 lsp_request_id,
8880 get_signature_help,
8881 position,
8882 &mut cx,
8883 )
8884 .await?;
8885 }
8886 Request::GetCodeLens(get_code_lens) => {
8887 Self::query_lsp_locally::<GetCodeLens>(
8888 lsp_store,
8889 server_id,
8890 sender_id,
8891 lsp_request_id,
8892 get_code_lens,
8893 None,
8894 &mut cx,
8895 )
8896 .await?;
8897 }
8898 Request::GetDefinition(get_definition) => {
8899 let position = get_definition.position.clone().and_then(deserialize_anchor);
8900 Self::query_lsp_locally::<GetDefinitions>(
8901 lsp_store,
8902 server_id,
8903 sender_id,
8904 lsp_request_id,
8905 get_definition,
8906 position,
8907 &mut cx,
8908 )
8909 .await?;
8910 }
8911 Request::GetDeclaration(get_declaration) => {
8912 let position = get_declaration
8913 .position
8914 .clone()
8915 .and_then(deserialize_anchor);
8916 Self::query_lsp_locally::<GetDeclarations>(
8917 lsp_store,
8918 server_id,
8919 sender_id,
8920 lsp_request_id,
8921 get_declaration,
8922 position,
8923 &mut cx,
8924 )
8925 .await?;
8926 }
8927 Request::GetTypeDefinition(get_type_definition) => {
8928 let position = get_type_definition
8929 .position
8930 .clone()
8931 .and_then(deserialize_anchor);
8932 Self::query_lsp_locally::<GetTypeDefinitions>(
8933 lsp_store,
8934 server_id,
8935 sender_id,
8936 lsp_request_id,
8937 get_type_definition,
8938 position,
8939 &mut cx,
8940 )
8941 .await?;
8942 }
8943 Request::GetImplementation(get_implementation) => {
8944 let position = get_implementation
8945 .position
8946 .clone()
8947 .and_then(deserialize_anchor);
8948 Self::query_lsp_locally::<GetImplementations>(
8949 lsp_store,
8950 server_id,
8951 sender_id,
8952 lsp_request_id,
8953 get_implementation,
8954 position,
8955 &mut cx,
8956 )
8957 .await?;
8958 }
8959 Request::InlayHints(inlay_hints) => {
8960 let query_start = inlay_hints
8961 .start
8962 .clone()
8963 .and_then(deserialize_anchor)
8964 .context("invalid inlay hints range start")?;
8965 let query_end = inlay_hints
8966 .end
8967 .clone()
8968 .and_then(deserialize_anchor)
8969 .context("invalid inlay hints range end")?;
8970 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8971 &lsp_store,
8972 server_id,
8973 lsp_request_id,
8974 &inlay_hints,
8975 query_start..query_end,
8976 &mut cx,
8977 )
8978 .await
8979 .context("preparing inlay hints request")?;
8980 Self::query_lsp_locally::<InlayHints>(
8981 lsp_store,
8982 server_id,
8983 sender_id,
8984 lsp_request_id,
8985 inlay_hints,
8986 None,
8987 &mut cx,
8988 )
8989 .await
8990 .context("querying for inlay hints")?
8991 }
8992 //////////////////////////////
8993 // Below are LSP queries that need to fetch more data,
8994 // hence cannot just proxy the request to language server with `query_lsp_locally`.
8995 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8996 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
8997 &lsp_store,
8998 &get_document_diagnostics,
8999 &mut cx,
9000 )
9001 .await?;
9002 lsp_store.update(&mut cx, |lsp_store, cx| {
9003 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9004 let key = LspKey {
9005 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9006 server_queried: server_id,
9007 };
9008 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9009 ) {
9010 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9011 lsp_requests.clear();
9012 };
9013 }
9014
9015 lsp_data.lsp_requests.entry(key).or_default().insert(
9016 lsp_request_id,
9017 cx.spawn(async move |lsp_store, cx| {
9018 let diagnostics_pull = lsp_store
9019 .update(cx, |lsp_store, cx| {
9020 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9021 })
9022 .ok();
9023 if let Some(diagnostics_pull) = diagnostics_pull {
9024 match diagnostics_pull.await {
9025 Ok(()) => {}
9026 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9027 };
9028 }
9029 }),
9030 );
9031 });
9032 }
9033 Request::SemanticTokens(semantic_tokens) => {
9034 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9035 &lsp_store,
9036 &semantic_tokens,
9037 &mut cx,
9038 )
9039 .await?;
9040 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9041 lsp_store.update(&mut cx, |lsp_store, cx| {
9042 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9043 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9044 let key = LspKey {
9045 request_type: TypeId::of::<SemanticTokensFull>(),
9046 server_queried: server_id,
9047 };
9048 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9049 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9050 lsp_requests.clear();
9051 };
9052 }
9053
9054 lsp_data.lsp_requests.entry(key).or_default().insert(
9055 lsp_request_id,
9056 cx.spawn(async move |lsp_store, cx| {
9057 let tokens_fetch = lsp_store
9058 .update(cx, |lsp_store, cx| {
9059 lsp_store
9060 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9061 })
9062 .ok();
9063 if let Some(tokens_fetch) = tokens_fetch {
9064 let new_tokens = tokens_fetch.await;
9065 if let Some(new_tokens) = new_tokens {
9066 lsp_store
9067 .update(cx, |lsp_store, cx| {
9068 let response = new_tokens
9069 .into_iter()
9070 .map(|(server_id, response)| {
9071 (
9072 server_id.to_proto(),
9073 SemanticTokensFull::response_to_proto(
9074 response,
9075 lsp_store,
9076 sender_id,
9077 &buffer_version,
9078 cx,
9079 ),
9080 )
9081 })
9082 .collect::<HashMap<_, _>>();
9083 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9084 project_id,
9085 lsp_request_id,
9086 response,
9087 ) {
9088 Ok(()) => {}
9089 Err(e) => {
9090 log::error!(
9091 "Failed to send semantic tokens LSP response: {e:#}",
9092 )
9093 }
9094 }
9095 })
9096 .ok();
9097 }
9098 }
9099 }),
9100 );
9101 }
9102 });
9103 }
9104 }
9105 Ok(proto::Ack {})
9106 }
9107
9108 async fn handle_lsp_query_response(
9109 lsp_store: Entity<Self>,
9110 envelope: TypedEnvelope<proto::LspQueryResponse>,
9111 cx: AsyncApp,
9112 ) -> Result<()> {
9113 lsp_store.read_with(&cx, |lsp_store, _| {
9114 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9115 upstream_client.handle_lsp_response(envelope.clone());
9116 }
9117 });
9118 Ok(())
9119 }
9120
9121 async fn handle_apply_code_action(
9122 this: Entity<Self>,
9123 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9124 mut cx: AsyncApp,
9125 ) -> Result<proto::ApplyCodeActionResponse> {
9126 let sender_id = envelope.original_sender_id().unwrap_or_default();
9127 let action =
9128 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9129 let apply_code_action = this.update(&mut cx, |this, cx| {
9130 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9131 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9132 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9133 })?;
9134
9135 let project_transaction = apply_code_action.await?;
9136 let project_transaction = this.update(&mut cx, |this, cx| {
9137 this.buffer_store.update(cx, |buffer_store, cx| {
9138 buffer_store.serialize_project_transaction_for_peer(
9139 project_transaction,
9140 sender_id,
9141 cx,
9142 )
9143 })
9144 });
9145 Ok(proto::ApplyCodeActionResponse {
9146 transaction: Some(project_transaction),
9147 })
9148 }
9149
9150 async fn handle_register_buffer_with_language_servers(
9151 this: Entity<Self>,
9152 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9153 mut cx: AsyncApp,
9154 ) -> Result<proto::Ack> {
9155 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9156 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9157 this.update(&mut cx, |this, cx| {
9158 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9159 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9160 project_id: upstream_project_id,
9161 buffer_id: buffer_id.to_proto(),
9162 only_servers: envelope.payload.only_servers,
9163 });
9164 }
9165
9166 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9167 anyhow::bail!("buffer is not open");
9168 };
9169
9170 let handle = this.register_buffer_with_language_servers(
9171 &buffer,
9172 envelope
9173 .payload
9174 .only_servers
9175 .into_iter()
9176 .filter_map(|selector| {
9177 Some(match selector.selector? {
9178 proto::language_server_selector::Selector::ServerId(server_id) => {
9179 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9180 }
9181 proto::language_server_selector::Selector::Name(name) => {
9182 LanguageServerSelector::Name(LanguageServerName(
9183 SharedString::from(name),
9184 ))
9185 }
9186 })
9187 })
9188 .collect(),
9189 false,
9190 cx,
9191 );
9192 // Pull diagnostics for the buffer even if it was already registered.
9193 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9194 // but it's unclear if we need it.
9195 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9196 .detach();
9197 this.buffer_store().update(cx, |buffer_store, _| {
9198 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9199 });
9200
9201 Ok(())
9202 })?;
9203 Ok(proto::Ack {})
9204 }
9205
9206 async fn handle_rename_project_entry(
9207 this: Entity<Self>,
9208 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9209 mut cx: AsyncApp,
9210 ) -> Result<proto::ProjectEntryResponse> {
9211 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9212 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9213 let new_path =
9214 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9215
9216 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9217 .update(&mut cx, |this, cx| {
9218 let (worktree, entry) = this
9219 .worktree_store
9220 .read(cx)
9221 .worktree_and_entry_for_id(entry_id, cx)?;
9222 let new_worktree = this
9223 .worktree_store
9224 .read(cx)
9225 .worktree_for_id(new_worktree_id, cx)?;
9226 Some((
9227 this.worktree_store.clone(),
9228 worktree,
9229 new_worktree,
9230 entry.clone(),
9231 ))
9232 })
9233 .context("worktree not found")?;
9234 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9235 (worktree.absolutize(&old_entry.path), worktree.id())
9236 });
9237 let new_abs_path =
9238 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9239
9240 let _transaction = Self::will_rename_entry(
9241 this.downgrade(),
9242 old_worktree_id,
9243 &old_abs_path,
9244 &new_abs_path,
9245 old_entry.is_dir(),
9246 cx.clone(),
9247 )
9248 .await;
9249 let response = WorktreeStore::handle_rename_project_entry(
9250 worktree_store,
9251 envelope.payload,
9252 cx.clone(),
9253 )
9254 .await;
9255 this.read_with(&cx, |this, _| {
9256 this.did_rename_entry(
9257 old_worktree_id,
9258 &old_abs_path,
9259 &new_abs_path,
9260 old_entry.is_dir(),
9261 );
9262 });
9263 response
9264 }
9265
9266 async fn handle_update_diagnostic_summary(
9267 this: Entity<Self>,
9268 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9269 mut cx: AsyncApp,
9270 ) -> Result<()> {
9271 this.update(&mut cx, |lsp_store, cx| {
9272 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9273 let mut updated_diagnostics_paths = HashMap::default();
9274 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9275 for message_summary in envelope
9276 .payload
9277 .summary
9278 .into_iter()
9279 .chain(envelope.payload.more_summaries)
9280 {
9281 let project_path = ProjectPath {
9282 worktree_id,
9283 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9284 };
9285 let path = project_path.path.clone();
9286 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9287 let summary = DiagnosticSummary {
9288 error_count: message_summary.error_count as usize,
9289 warning_count: message_summary.warning_count as usize,
9290 };
9291
9292 if summary.is_empty() {
9293 if let Some(worktree_summaries) =
9294 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9295 && let Some(summaries) = worktree_summaries.get_mut(&path)
9296 {
9297 summaries.remove(&server_id);
9298 if summaries.is_empty() {
9299 worktree_summaries.remove(&path);
9300 }
9301 }
9302 } else {
9303 lsp_store
9304 .diagnostic_summaries
9305 .entry(worktree_id)
9306 .or_default()
9307 .entry(path)
9308 .or_default()
9309 .insert(server_id, summary);
9310 }
9311
9312 if let Some((_, project_id)) = &lsp_store.downstream_client {
9313 match &mut diagnostics_summary {
9314 Some(diagnostics_summary) => {
9315 diagnostics_summary
9316 .more_summaries
9317 .push(proto::DiagnosticSummary {
9318 path: project_path.path.as_ref().to_proto(),
9319 language_server_id: server_id.0 as u64,
9320 error_count: summary.error_count as u32,
9321 warning_count: summary.warning_count as u32,
9322 })
9323 }
9324 None => {
9325 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9326 project_id: *project_id,
9327 worktree_id: worktree_id.to_proto(),
9328 summary: Some(proto::DiagnosticSummary {
9329 path: project_path.path.as_ref().to_proto(),
9330 language_server_id: server_id.0 as u64,
9331 error_count: summary.error_count as u32,
9332 warning_count: summary.warning_count as u32,
9333 }),
9334 more_summaries: Vec::new(),
9335 })
9336 }
9337 }
9338 }
9339 updated_diagnostics_paths
9340 .entry(server_id)
9341 .or_insert_with(Vec::new)
9342 .push(project_path);
9343 }
9344
9345 if let Some((diagnostics_summary, (downstream_client, _))) =
9346 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9347 {
9348 downstream_client.send(diagnostics_summary).log_err();
9349 }
9350 for (server_id, paths) in updated_diagnostics_paths {
9351 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9352 }
9353 Ok(())
9354 })
9355 }
9356
9357 async fn handle_start_language_server(
9358 lsp_store: Entity<Self>,
9359 envelope: TypedEnvelope<proto::StartLanguageServer>,
9360 mut cx: AsyncApp,
9361 ) -> Result<()> {
9362 let server = envelope.payload.server.context("invalid server")?;
9363 let server_capabilities =
9364 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9365 .with_context(|| {
9366 format!(
9367 "incorrect server capabilities {}",
9368 envelope.payload.capabilities
9369 )
9370 })?;
9371 lsp_store.update(&mut cx, |lsp_store, cx| {
9372 let server_id = LanguageServerId(server.id as usize);
9373 let server_name = LanguageServerName::from_proto(server.name.clone());
9374 lsp_store
9375 .lsp_server_capabilities
9376 .insert(server_id, server_capabilities);
9377 lsp_store.language_server_statuses.insert(
9378 server_id,
9379 LanguageServerStatus {
9380 name: server_name.clone(),
9381 server_version: None,
9382 pending_work: Default::default(),
9383 has_pending_diagnostic_updates: false,
9384 progress_tokens: Default::default(),
9385 worktree: server.worktree_id.map(WorktreeId::from_proto),
9386 binary: None,
9387 configuration: None,
9388 workspace_folders: BTreeSet::new(),
9389 process_id: None,
9390 },
9391 );
9392 cx.emit(LspStoreEvent::LanguageServerAdded(
9393 server_id,
9394 server_name,
9395 server.worktree_id.map(WorktreeId::from_proto),
9396 ));
9397 cx.notify();
9398 });
9399 Ok(())
9400 }
9401
9402 async fn handle_update_language_server(
9403 lsp_store: Entity<Self>,
9404 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9405 mut cx: AsyncApp,
9406 ) -> Result<()> {
9407 lsp_store.update(&mut cx, |lsp_store, cx| {
9408 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9409
9410 match envelope.payload.variant.context("invalid variant")? {
9411 proto::update_language_server::Variant::WorkStart(payload) => {
9412 lsp_store.on_lsp_work_start(
9413 language_server_id,
9414 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9415 .context("invalid progress token value")?,
9416 LanguageServerProgress {
9417 title: payload.title,
9418 is_disk_based_diagnostics_progress: false,
9419 is_cancellable: payload.is_cancellable.unwrap_or(false),
9420 message: payload.message,
9421 percentage: payload.percentage.map(|p| p as usize),
9422 last_update_at: cx.background_executor().now(),
9423 },
9424 cx,
9425 );
9426 }
9427 proto::update_language_server::Variant::WorkProgress(payload) => {
9428 lsp_store.on_lsp_work_progress(
9429 language_server_id,
9430 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9431 .context("invalid progress token value")?,
9432 LanguageServerProgress {
9433 title: None,
9434 is_disk_based_diagnostics_progress: false,
9435 is_cancellable: payload.is_cancellable.unwrap_or(false),
9436 message: payload.message,
9437 percentage: payload.percentage.map(|p| p as usize),
9438 last_update_at: cx.background_executor().now(),
9439 },
9440 cx,
9441 );
9442 }
9443
9444 proto::update_language_server::Variant::WorkEnd(payload) => {
9445 lsp_store.on_lsp_work_end(
9446 language_server_id,
9447 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9448 .context("invalid progress token value")?,
9449 cx,
9450 );
9451 }
9452
9453 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9454 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9455 }
9456
9457 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9458 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9459 }
9460
9461 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9462 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9463 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9464 cx.emit(LspStoreEvent::LanguageServerUpdate {
9465 language_server_id,
9466 name: envelope
9467 .payload
9468 .server_name
9469 .map(SharedString::new)
9470 .map(LanguageServerName),
9471 message: non_lsp,
9472 });
9473 }
9474 }
9475
9476 Ok(())
9477 })
9478 }
9479
9480 async fn handle_language_server_log(
9481 this: Entity<Self>,
9482 envelope: TypedEnvelope<proto::LanguageServerLog>,
9483 mut cx: AsyncApp,
9484 ) -> Result<()> {
9485 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9486 let log_type = envelope
9487 .payload
9488 .log_type
9489 .map(LanguageServerLogType::from_proto)
9490 .context("invalid language server log type")?;
9491
9492 let message = envelope.payload.message;
9493
9494 this.update(&mut cx, |_, cx| {
9495 cx.emit(LspStoreEvent::LanguageServerLog(
9496 language_server_id,
9497 log_type,
9498 message,
9499 ));
9500 });
9501 Ok(())
9502 }
9503
9504 async fn handle_lsp_ext_cancel_flycheck(
9505 lsp_store: Entity<Self>,
9506 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9507 cx: AsyncApp,
9508 ) -> Result<proto::Ack> {
9509 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9510 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9511 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9512 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9513 } else {
9514 None
9515 }
9516 });
9517 if let Some(task) = task {
9518 task.context("handling lsp ext cancel flycheck")?;
9519 }
9520
9521 Ok(proto::Ack {})
9522 }
9523
9524 async fn handle_lsp_ext_run_flycheck(
9525 lsp_store: Entity<Self>,
9526 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9527 mut cx: AsyncApp,
9528 ) -> Result<proto::Ack> {
9529 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9530 lsp_store.update(&mut cx, |lsp_store, cx| {
9531 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9532 let text_document = if envelope.payload.current_file_only {
9533 let buffer_id = envelope
9534 .payload
9535 .buffer_id
9536 .map(|id| BufferId::new(id))
9537 .transpose()?;
9538 buffer_id
9539 .and_then(|buffer_id| {
9540 lsp_store
9541 .buffer_store()
9542 .read(cx)
9543 .get(buffer_id)
9544 .and_then(|buffer| {
9545 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9546 })
9547 .map(|path| make_text_document_identifier(&path))
9548 })
9549 .transpose()?
9550 } else {
9551 None
9552 };
9553 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9554 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9555 )?;
9556 }
9557 anyhow::Ok(())
9558 })?;
9559
9560 Ok(proto::Ack {})
9561 }
9562
9563 async fn handle_lsp_ext_clear_flycheck(
9564 lsp_store: Entity<Self>,
9565 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9566 cx: AsyncApp,
9567 ) -> Result<proto::Ack> {
9568 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9569 lsp_store.read_with(&cx, |lsp_store, _| {
9570 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9571 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9572 } else {
9573 None
9574 }
9575 });
9576
9577 Ok(proto::Ack {})
9578 }
9579
9580 pub fn disk_based_diagnostics_started(
9581 &mut self,
9582 language_server_id: LanguageServerId,
9583 cx: &mut Context<Self>,
9584 ) {
9585 if let Some(language_server_status) =
9586 self.language_server_statuses.get_mut(&language_server_id)
9587 {
9588 language_server_status.has_pending_diagnostic_updates = true;
9589 }
9590
9591 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9592 cx.emit(LspStoreEvent::LanguageServerUpdate {
9593 language_server_id,
9594 name: self
9595 .language_server_adapter_for_id(language_server_id)
9596 .map(|adapter| adapter.name()),
9597 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9598 Default::default(),
9599 ),
9600 })
9601 }
9602
9603 pub fn disk_based_diagnostics_finished(
9604 &mut self,
9605 language_server_id: LanguageServerId,
9606 cx: &mut Context<Self>,
9607 ) {
9608 if let Some(language_server_status) =
9609 self.language_server_statuses.get_mut(&language_server_id)
9610 {
9611 language_server_status.has_pending_diagnostic_updates = false;
9612 }
9613
9614 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9615 cx.emit(LspStoreEvent::LanguageServerUpdate {
9616 language_server_id,
9617 name: self
9618 .language_server_adapter_for_id(language_server_id)
9619 .map(|adapter| adapter.name()),
9620 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9621 Default::default(),
9622 ),
9623 })
9624 }
9625
9626 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9627 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9628 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9629 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9630 // the language server might take some time to publish diagnostics.
9631 fn simulate_disk_based_diagnostics_events_if_needed(
9632 &mut self,
9633 language_server_id: LanguageServerId,
9634 cx: &mut Context<Self>,
9635 ) {
9636 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9637
9638 let Some(LanguageServerState::Running {
9639 simulate_disk_based_diagnostics_completion,
9640 adapter,
9641 ..
9642 }) = self
9643 .as_local_mut()
9644 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9645 else {
9646 return;
9647 };
9648
9649 if adapter.disk_based_diagnostics_progress_token.is_some() {
9650 return;
9651 }
9652
9653 let prev_task =
9654 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9655 cx.background_executor()
9656 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9657 .await;
9658
9659 this.update(cx, |this, cx| {
9660 this.disk_based_diagnostics_finished(language_server_id, cx);
9661
9662 if let Some(LanguageServerState::Running {
9663 simulate_disk_based_diagnostics_completion,
9664 ..
9665 }) = this.as_local_mut().and_then(|local_store| {
9666 local_store.language_servers.get_mut(&language_server_id)
9667 }) {
9668 *simulate_disk_based_diagnostics_completion = None;
9669 }
9670 })
9671 .ok();
9672 }));
9673
9674 if prev_task.is_none() {
9675 self.disk_based_diagnostics_started(language_server_id, cx);
9676 }
9677 }
9678
9679 pub fn language_server_statuses(
9680 &self,
9681 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9682 self.language_server_statuses
9683 .iter()
9684 .map(|(key, value)| (*key, value))
9685 }
9686
9687 pub(super) fn did_rename_entry(
9688 &self,
9689 worktree_id: WorktreeId,
9690 old_path: &Path,
9691 new_path: &Path,
9692 is_dir: bool,
9693 ) {
9694 maybe!({
9695 let local_store = self.as_local()?;
9696
9697 let old_uri = lsp::Uri::from_file_path(old_path)
9698 .ok()
9699 .map(|uri| uri.to_string())?;
9700 let new_uri = lsp::Uri::from_file_path(new_path)
9701 .ok()
9702 .map(|uri| uri.to_string())?;
9703
9704 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9705 let Some(filter) = local_store
9706 .language_server_paths_watched_for_rename
9707 .get(&language_server.server_id())
9708 else {
9709 continue;
9710 };
9711
9712 if filter.should_send_did_rename(&old_uri, is_dir) {
9713 language_server
9714 .notify::<DidRenameFiles>(RenameFilesParams {
9715 files: vec![FileRename {
9716 old_uri: old_uri.clone(),
9717 new_uri: new_uri.clone(),
9718 }],
9719 })
9720 .ok();
9721 }
9722 }
9723 Some(())
9724 });
9725 }
9726
9727 pub(super) fn will_rename_entry(
9728 this: WeakEntity<Self>,
9729 worktree_id: WorktreeId,
9730 old_path: &Path,
9731 new_path: &Path,
9732 is_dir: bool,
9733 cx: AsyncApp,
9734 ) -> Task<ProjectTransaction> {
9735 let old_uri = lsp::Uri::from_file_path(old_path)
9736 .ok()
9737 .map(|uri| uri.to_string());
9738 let new_uri = lsp::Uri::from_file_path(new_path)
9739 .ok()
9740 .map(|uri| uri.to_string());
9741 cx.spawn(async move |cx| {
9742 let mut tasks = vec![];
9743 this.update(cx, |this, cx| {
9744 let local_store = this.as_local()?;
9745 let old_uri = old_uri?;
9746 let new_uri = new_uri?;
9747 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9748 let Some(filter) = local_store
9749 .language_server_paths_watched_for_rename
9750 .get(&language_server.server_id())
9751 else {
9752 continue;
9753 };
9754
9755 if !filter.should_send_will_rename(&old_uri, is_dir) {
9756 continue;
9757 }
9758 let request_timeout = ProjectSettings::get_global(cx)
9759 .global_lsp_settings
9760 .get_request_timeout();
9761
9762 let apply_edit = cx.spawn({
9763 let old_uri = old_uri.clone();
9764 let new_uri = new_uri.clone();
9765 let language_server = language_server.clone();
9766 async move |this, cx| {
9767 let edit = language_server
9768 .request::<WillRenameFiles>(
9769 RenameFilesParams {
9770 files: vec![FileRename { old_uri, new_uri }],
9771 },
9772 request_timeout,
9773 )
9774 .await
9775 .into_response()
9776 .context("will rename files")
9777 .log_err()
9778 .flatten()?;
9779
9780 LocalLspStore::deserialize_workspace_edit(
9781 this.upgrade()?,
9782 edit,
9783 false,
9784 language_server.clone(),
9785 cx,
9786 )
9787 .await
9788 .ok()
9789 }
9790 });
9791 tasks.push(apply_edit);
9792 }
9793 Some(())
9794 })
9795 .ok()
9796 .flatten();
9797 let mut merged_transaction = ProjectTransaction::default();
9798 for task in tasks {
9799 // Await on tasks sequentially so that the order of application of edits is deterministic
9800 // (at least with regards to the order of registration of language servers)
9801 if let Some(transaction) = task.await {
9802 for (buffer, buffer_transaction) in transaction.0 {
9803 merged_transaction.0.insert(buffer, buffer_transaction);
9804 }
9805 }
9806 }
9807 merged_transaction
9808 })
9809 }
9810
9811 fn lsp_notify_abs_paths_changed(
9812 &mut self,
9813 server_id: LanguageServerId,
9814 changes: Vec<PathEvent>,
9815 ) {
9816 maybe!({
9817 let server = self.language_server_for_id(server_id)?;
9818 let changes = changes
9819 .into_iter()
9820 .filter_map(|event| {
9821 let typ = match event.kind? {
9822 PathEventKind::Created => lsp::FileChangeType::CREATED,
9823 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9824 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9825 };
9826 Some(lsp::FileEvent {
9827 uri: file_path_to_lsp_url(&event.path).log_err()?,
9828 typ,
9829 })
9830 })
9831 .collect::<Vec<_>>();
9832 if !changes.is_empty() {
9833 server
9834 .notify::<lsp::notification::DidChangeWatchedFiles>(
9835 lsp::DidChangeWatchedFilesParams { changes },
9836 )
9837 .ok();
9838 }
9839 Some(())
9840 });
9841 }
9842
9843 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9844 self.as_local()?.language_server_for_id(id)
9845 }
9846
9847 fn on_lsp_progress(
9848 &mut self,
9849 progress_params: lsp::ProgressParams,
9850 language_server_id: LanguageServerId,
9851 disk_based_diagnostics_progress_token: Option<String>,
9852 cx: &mut Context<Self>,
9853 ) {
9854 match progress_params.value {
9855 lsp::ProgressParamsValue::WorkDone(progress) => {
9856 self.handle_work_done_progress(
9857 progress,
9858 language_server_id,
9859 disk_based_diagnostics_progress_token,
9860 ProgressToken::from_lsp(progress_params.token),
9861 cx,
9862 );
9863 }
9864 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9865 let registration_id = match progress_params.token {
9866 lsp::NumberOrString::Number(_) => None,
9867 lsp::NumberOrString::String(token) => token
9868 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9869 .map(|(_, id)| id.to_owned()),
9870 };
9871 if let Some(LanguageServerState::Running {
9872 workspace_diagnostics_refresh_tasks,
9873 ..
9874 }) = self
9875 .as_local_mut()
9876 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9877 && let Some(workspace_diagnostics) =
9878 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9879 {
9880 workspace_diagnostics.progress_tx.try_send(()).ok();
9881 self.apply_workspace_diagnostic_report(
9882 language_server_id,
9883 report,
9884 registration_id.map(SharedString::from),
9885 cx,
9886 )
9887 }
9888 }
9889 }
9890 }
9891
9892 fn handle_work_done_progress(
9893 &mut self,
9894 progress: lsp::WorkDoneProgress,
9895 language_server_id: LanguageServerId,
9896 disk_based_diagnostics_progress_token: Option<String>,
9897 token: ProgressToken,
9898 cx: &mut Context<Self>,
9899 ) {
9900 let language_server_status =
9901 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9902 status
9903 } else {
9904 return;
9905 };
9906
9907 if !language_server_status.progress_tokens.contains(&token) {
9908 return;
9909 }
9910
9911 let is_disk_based_diagnostics_progress =
9912 if let (Some(disk_based_token), ProgressToken::String(token)) =
9913 (&disk_based_diagnostics_progress_token, &token)
9914 {
9915 token.starts_with(disk_based_token)
9916 } else {
9917 false
9918 };
9919
9920 match progress {
9921 lsp::WorkDoneProgress::Begin(report) => {
9922 if is_disk_based_diagnostics_progress {
9923 self.disk_based_diagnostics_started(language_server_id, cx);
9924 }
9925 self.on_lsp_work_start(
9926 language_server_id,
9927 token.clone(),
9928 LanguageServerProgress {
9929 title: Some(report.title),
9930 is_disk_based_diagnostics_progress,
9931 is_cancellable: report.cancellable.unwrap_or(false),
9932 message: report.message.clone(),
9933 percentage: report.percentage.map(|p| p as usize),
9934 last_update_at: cx.background_executor().now(),
9935 },
9936 cx,
9937 );
9938 }
9939 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9940 language_server_id,
9941 token,
9942 LanguageServerProgress {
9943 title: None,
9944 is_disk_based_diagnostics_progress,
9945 is_cancellable: report.cancellable.unwrap_or(false),
9946 message: report.message,
9947 percentage: report.percentage.map(|p| p as usize),
9948 last_update_at: cx.background_executor().now(),
9949 },
9950 cx,
9951 ),
9952 lsp::WorkDoneProgress::End(_) => {
9953 language_server_status.progress_tokens.remove(&token);
9954 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9955 if is_disk_based_diagnostics_progress {
9956 self.disk_based_diagnostics_finished(language_server_id, cx);
9957 }
9958 }
9959 }
9960 }
9961
9962 fn on_lsp_work_start(
9963 &mut self,
9964 language_server_id: LanguageServerId,
9965 token: ProgressToken,
9966 progress: LanguageServerProgress,
9967 cx: &mut Context<Self>,
9968 ) {
9969 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9970 status.pending_work.insert(token.clone(), progress.clone());
9971 cx.notify();
9972 }
9973 cx.emit(LspStoreEvent::LanguageServerUpdate {
9974 language_server_id,
9975 name: self
9976 .language_server_adapter_for_id(language_server_id)
9977 .map(|adapter| adapter.name()),
9978 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9979 token: Some(token.to_proto()),
9980 title: progress.title,
9981 message: progress.message,
9982 percentage: progress.percentage.map(|p| p as u32),
9983 is_cancellable: Some(progress.is_cancellable),
9984 }),
9985 })
9986 }
9987
9988 fn on_lsp_work_progress(
9989 &mut self,
9990 language_server_id: LanguageServerId,
9991 token: ProgressToken,
9992 progress: LanguageServerProgress,
9993 cx: &mut Context<Self>,
9994 ) {
9995 let mut did_update = false;
9996 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9997 match status.pending_work.entry(token.clone()) {
9998 btree_map::Entry::Vacant(entry) => {
9999 entry.insert(progress.clone());
10000 did_update = true;
10001 }
10002 btree_map::Entry::Occupied(mut entry) => {
10003 let entry = entry.get_mut();
10004 if (progress.last_update_at - entry.last_update_at)
10005 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10006 {
10007 entry.last_update_at = progress.last_update_at;
10008 if progress.message.is_some() {
10009 entry.message = progress.message.clone();
10010 }
10011 if progress.percentage.is_some() {
10012 entry.percentage = progress.percentage;
10013 }
10014 if progress.is_cancellable != entry.is_cancellable {
10015 entry.is_cancellable = progress.is_cancellable;
10016 }
10017 did_update = true;
10018 }
10019 }
10020 }
10021 }
10022
10023 if did_update {
10024 cx.emit(LspStoreEvent::LanguageServerUpdate {
10025 language_server_id,
10026 name: self
10027 .language_server_adapter_for_id(language_server_id)
10028 .map(|adapter| adapter.name()),
10029 message: proto::update_language_server::Variant::WorkProgress(
10030 proto::LspWorkProgress {
10031 token: Some(token.to_proto()),
10032 message: progress.message,
10033 percentage: progress.percentage.map(|p| p as u32),
10034 is_cancellable: Some(progress.is_cancellable),
10035 },
10036 ),
10037 })
10038 }
10039 }
10040
10041 fn on_lsp_work_end(
10042 &mut self,
10043 language_server_id: LanguageServerId,
10044 token: ProgressToken,
10045 cx: &mut Context<Self>,
10046 ) {
10047 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10048 if let Some(work) = status.pending_work.remove(&token)
10049 && !work.is_disk_based_diagnostics_progress
10050 {
10051 cx.emit(LspStoreEvent::RefreshInlayHints {
10052 server_id: language_server_id,
10053 request_id: None,
10054 });
10055 }
10056 cx.notify();
10057 }
10058
10059 cx.emit(LspStoreEvent::LanguageServerUpdate {
10060 language_server_id,
10061 name: self
10062 .language_server_adapter_for_id(language_server_id)
10063 .map(|adapter| adapter.name()),
10064 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10065 token: Some(token.to_proto()),
10066 }),
10067 })
10068 }
10069
10070 pub async fn handle_resolve_completion_documentation(
10071 this: Entity<Self>,
10072 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10073 mut cx: AsyncApp,
10074 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10075 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10076
10077 let completion = this
10078 .read_with(&cx, |this, cx| {
10079 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10080 let server = this
10081 .language_server_for_id(id)
10082 .with_context(|| format!("No language server {id}"))?;
10083
10084 let request_timeout = ProjectSettings::get_global(cx)
10085 .global_lsp_settings
10086 .get_request_timeout();
10087
10088 anyhow::Ok(cx.background_spawn(async move {
10089 let can_resolve = server
10090 .capabilities()
10091 .completion_provider
10092 .as_ref()
10093 .and_then(|options| options.resolve_provider)
10094 .unwrap_or(false);
10095 if can_resolve {
10096 server
10097 .request::<lsp::request::ResolveCompletionItem>(
10098 lsp_completion,
10099 request_timeout,
10100 )
10101 .await
10102 .into_response()
10103 .context("resolve completion item")
10104 } else {
10105 anyhow::Ok(lsp_completion)
10106 }
10107 }))
10108 })?
10109 .await?;
10110
10111 let mut documentation_is_markdown = false;
10112 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10113 let documentation = match completion.documentation {
10114 Some(lsp::Documentation::String(text)) => text,
10115
10116 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10117 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10118 value
10119 }
10120
10121 _ => String::new(),
10122 };
10123
10124 // If we have a new buffer_id, that means we're talking to a new client
10125 // and want to check for new text_edits in the completion too.
10126 let mut old_replace_start = None;
10127 let mut old_replace_end = None;
10128 let mut old_insert_start = None;
10129 let mut old_insert_end = None;
10130 let mut new_text = String::default();
10131 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10132 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10133 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10134 anyhow::Ok(buffer.read(cx).snapshot())
10135 })?;
10136
10137 if let Some(text_edit) = completion.text_edit.as_ref() {
10138 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10139
10140 if let Some(mut edit) = edit {
10141 LineEnding::normalize(&mut edit.new_text);
10142
10143 new_text = edit.new_text;
10144 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10145 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10146 if let Some(insert_range) = edit.insert_range {
10147 old_insert_start = Some(serialize_anchor(&insert_range.start));
10148 old_insert_end = Some(serialize_anchor(&insert_range.end));
10149 }
10150 }
10151 }
10152 }
10153
10154 Ok(proto::ResolveCompletionDocumentationResponse {
10155 documentation,
10156 documentation_is_markdown,
10157 old_replace_start,
10158 old_replace_end,
10159 new_text,
10160 lsp_completion,
10161 old_insert_start,
10162 old_insert_end,
10163 })
10164 }
10165
10166 async fn handle_on_type_formatting(
10167 this: Entity<Self>,
10168 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10169 mut cx: AsyncApp,
10170 ) -> Result<proto::OnTypeFormattingResponse> {
10171 let on_type_formatting = this.update(&mut cx, |this, cx| {
10172 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10173 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10174 let position = envelope
10175 .payload
10176 .position
10177 .and_then(deserialize_anchor)
10178 .context("invalid position")?;
10179 anyhow::Ok(this.apply_on_type_formatting(
10180 buffer,
10181 position,
10182 envelope.payload.trigger.clone(),
10183 cx,
10184 ))
10185 })?;
10186
10187 let transaction = on_type_formatting
10188 .await?
10189 .as_ref()
10190 .map(language::proto::serialize_transaction);
10191 Ok(proto::OnTypeFormattingResponse { transaction })
10192 }
10193
10194 async fn handle_pull_workspace_diagnostics(
10195 lsp_store: Entity<Self>,
10196 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10197 mut cx: AsyncApp,
10198 ) -> Result<proto::Ack> {
10199 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10200 lsp_store.update(&mut cx, |lsp_store, _| {
10201 lsp_store.pull_workspace_diagnostics(server_id);
10202 });
10203 Ok(proto::Ack {})
10204 }
10205
10206 async fn handle_open_buffer_for_symbol(
10207 this: Entity<Self>,
10208 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10209 mut cx: AsyncApp,
10210 ) -> Result<proto::OpenBufferForSymbolResponse> {
10211 let peer_id = envelope.original_sender_id().unwrap_or_default();
10212 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10213 let symbol = Self::deserialize_symbol(symbol)?;
10214 this.read_with(&cx, |this, _| {
10215 if let SymbolLocation::OutsideProject {
10216 abs_path,
10217 signature,
10218 } = &symbol.path
10219 {
10220 let new_signature = this.symbol_signature(&abs_path);
10221 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10222 }
10223 Ok(())
10224 })?;
10225 let buffer = this
10226 .update(&mut cx, |this, cx| {
10227 this.open_buffer_for_symbol(
10228 &Symbol {
10229 language_server_name: symbol.language_server_name,
10230 source_worktree_id: symbol.source_worktree_id,
10231 source_language_server_id: symbol.source_language_server_id,
10232 path: symbol.path,
10233 name: symbol.name,
10234 kind: symbol.kind,
10235 range: symbol.range,
10236 label: CodeLabel::default(),
10237 container_name: symbol.container_name,
10238 },
10239 cx,
10240 )
10241 })
10242 .await?;
10243
10244 this.update(&mut cx, |this, cx| {
10245 let is_private = buffer
10246 .read(cx)
10247 .file()
10248 .map(|f| f.is_private())
10249 .unwrap_or_default();
10250 if is_private {
10251 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10252 } else {
10253 this.buffer_store
10254 .update(cx, |buffer_store, cx| {
10255 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10256 })
10257 .detach_and_log_err(cx);
10258 let buffer_id = buffer.read(cx).remote_id().to_proto();
10259 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10260 }
10261 })
10262 }
10263
10264 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10265 let mut hasher = Sha256::new();
10266 hasher.update(abs_path.to_string_lossy().as_bytes());
10267 hasher.update(self.nonce.to_be_bytes());
10268 hasher.finalize().as_slice().try_into().unwrap()
10269 }
10270
10271 pub async fn handle_get_project_symbols(
10272 this: Entity<Self>,
10273 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10274 mut cx: AsyncApp,
10275 ) -> Result<proto::GetProjectSymbolsResponse> {
10276 let symbols = this
10277 .update(&mut cx, |this, cx| {
10278 this.symbols(&envelope.payload.query, cx)
10279 })
10280 .await?;
10281
10282 Ok(proto::GetProjectSymbolsResponse {
10283 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10284 })
10285 }
10286
10287 pub async fn handle_restart_language_servers(
10288 this: Entity<Self>,
10289 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10290 mut cx: AsyncApp,
10291 ) -> Result<proto::Ack> {
10292 this.update(&mut cx, |lsp_store, cx| {
10293 let buffers =
10294 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10295 lsp_store.restart_language_servers_for_buffers(
10296 buffers,
10297 envelope
10298 .payload
10299 .only_servers
10300 .into_iter()
10301 .filter_map(|selector| {
10302 Some(match selector.selector? {
10303 proto::language_server_selector::Selector::ServerId(server_id) => {
10304 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10305 }
10306 proto::language_server_selector::Selector::Name(name) => {
10307 LanguageServerSelector::Name(LanguageServerName(
10308 SharedString::from(name),
10309 ))
10310 }
10311 })
10312 })
10313 .collect(),
10314 cx,
10315 );
10316 });
10317
10318 Ok(proto::Ack {})
10319 }
10320
10321 pub async fn handle_stop_language_servers(
10322 lsp_store: Entity<Self>,
10323 envelope: TypedEnvelope<proto::StopLanguageServers>,
10324 mut cx: AsyncApp,
10325 ) -> Result<proto::Ack> {
10326 lsp_store.update(&mut cx, |lsp_store, cx| {
10327 if envelope.payload.all
10328 && envelope.payload.also_servers.is_empty()
10329 && envelope.payload.buffer_ids.is_empty()
10330 {
10331 lsp_store.stop_all_language_servers(cx);
10332 } else {
10333 let buffers =
10334 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10335 lsp_store
10336 .stop_language_servers_for_buffers(
10337 buffers,
10338 envelope
10339 .payload
10340 .also_servers
10341 .into_iter()
10342 .filter_map(|selector| {
10343 Some(match selector.selector? {
10344 proto::language_server_selector::Selector::ServerId(
10345 server_id,
10346 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10347 server_id,
10348 )),
10349 proto::language_server_selector::Selector::Name(name) => {
10350 LanguageServerSelector::Name(LanguageServerName(
10351 SharedString::from(name),
10352 ))
10353 }
10354 })
10355 })
10356 .collect(),
10357 cx,
10358 )
10359 .detach_and_log_err(cx);
10360 }
10361 });
10362
10363 Ok(proto::Ack {})
10364 }
10365
10366 pub async fn handle_cancel_language_server_work(
10367 lsp_store: Entity<Self>,
10368 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10369 mut cx: AsyncApp,
10370 ) -> Result<proto::Ack> {
10371 lsp_store.update(&mut cx, |lsp_store, cx| {
10372 if let Some(work) = envelope.payload.work {
10373 match work {
10374 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10375 let buffers =
10376 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10377 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10378 }
10379 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10380 let server_id = LanguageServerId::from_proto(work.language_server_id);
10381 let token = work
10382 .token
10383 .map(|token| {
10384 ProgressToken::from_proto(token)
10385 .context("invalid work progress token")
10386 })
10387 .transpose()?;
10388 lsp_store.cancel_language_server_work(server_id, token, cx);
10389 }
10390 }
10391 }
10392 anyhow::Ok(())
10393 })?;
10394
10395 Ok(proto::Ack {})
10396 }
10397
10398 fn buffer_ids_to_buffers(
10399 &mut self,
10400 buffer_ids: impl Iterator<Item = u64>,
10401 cx: &mut Context<Self>,
10402 ) -> Vec<Entity<Buffer>> {
10403 buffer_ids
10404 .into_iter()
10405 .flat_map(|buffer_id| {
10406 self.buffer_store
10407 .read(cx)
10408 .get(BufferId::new(buffer_id).log_err()?)
10409 })
10410 .collect::<Vec<_>>()
10411 }
10412
10413 async fn handle_apply_additional_edits_for_completion(
10414 this: Entity<Self>,
10415 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10416 mut cx: AsyncApp,
10417 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10418 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10419 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10420 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10421 let completion = Self::deserialize_completion(
10422 envelope.payload.completion.context("invalid completion")?,
10423 )?;
10424 anyhow::Ok((buffer, completion))
10425 })?;
10426
10427 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10428 this.apply_additional_edits_for_completion(
10429 buffer,
10430 Rc::new(RefCell::new(Box::new([Completion {
10431 replace_range: completion.replace_range,
10432 new_text: completion.new_text,
10433 source: completion.source,
10434 documentation: None,
10435 label: CodeLabel::default(),
10436 match_start: None,
10437 snippet_deduplication_key: None,
10438 insert_text_mode: None,
10439 icon_path: None,
10440 confirm: None,
10441 }]))),
10442 0,
10443 false,
10444 cx,
10445 )
10446 });
10447
10448 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10449 transaction: apply_additional_edits
10450 .await?
10451 .as_ref()
10452 .map(language::proto::serialize_transaction),
10453 })
10454 }
10455
10456 pub fn last_formatting_failure(&self) -> Option<&str> {
10457 self.last_formatting_failure.as_deref()
10458 }
10459
10460 pub fn reset_last_formatting_failure(&mut self) {
10461 self.last_formatting_failure = None;
10462 }
10463
10464 pub fn environment_for_buffer(
10465 &self,
10466 buffer: &Entity<Buffer>,
10467 cx: &mut Context<Self>,
10468 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10469 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10470 environment.update(cx, |env, cx| {
10471 env.buffer_environment(buffer, &self.worktree_store, cx)
10472 })
10473 } else {
10474 Task::ready(None).shared()
10475 }
10476 }
10477
10478 pub fn format(
10479 &mut self,
10480 buffers: HashSet<Entity<Buffer>>,
10481 target: LspFormatTarget,
10482 push_to_history: bool,
10483 trigger: FormatTrigger,
10484 cx: &mut Context<Self>,
10485 ) -> Task<anyhow::Result<ProjectTransaction>> {
10486 let logger = zlog::scoped!("format");
10487 if self.as_local().is_some() {
10488 zlog::trace!(logger => "Formatting locally");
10489 let logger = zlog::scoped!(logger => "local");
10490 let buffers = buffers
10491 .into_iter()
10492 .map(|buffer_handle| {
10493 let buffer = buffer_handle.read(cx);
10494 let buffer_abs_path = File::from_dyn(buffer.file())
10495 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10496
10497 (buffer_handle, buffer_abs_path, buffer.remote_id())
10498 })
10499 .collect::<Vec<_>>();
10500
10501 cx.spawn(async move |lsp_store, cx| {
10502 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10503
10504 for (handle, abs_path, id) in buffers {
10505 let env = lsp_store
10506 .update(cx, |lsp_store, cx| {
10507 lsp_store.environment_for_buffer(&handle, cx)
10508 })?
10509 .await;
10510
10511 let ranges = match &target {
10512 LspFormatTarget::Buffers => None,
10513 LspFormatTarget::Ranges(ranges) => {
10514 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10515 }
10516 };
10517
10518 formattable_buffers.push(FormattableBuffer {
10519 handle,
10520 abs_path,
10521 env,
10522 ranges,
10523 });
10524 }
10525 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10526
10527 let format_timer = zlog::time!(logger => "Formatting buffers");
10528 let result = LocalLspStore::format_locally(
10529 lsp_store.clone(),
10530 formattable_buffers,
10531 push_to_history,
10532 trigger,
10533 logger,
10534 cx,
10535 )
10536 .await;
10537 format_timer.end();
10538
10539 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10540
10541 lsp_store.update(cx, |lsp_store, _| {
10542 lsp_store.update_last_formatting_failure(&result);
10543 })?;
10544
10545 result
10546 })
10547 } else if let Some((client, project_id)) = self.upstream_client() {
10548 zlog::trace!(logger => "Formatting remotely");
10549 let logger = zlog::scoped!(logger => "remote");
10550
10551 let buffer_ranges = match &target {
10552 LspFormatTarget::Buffers => Vec::new(),
10553 LspFormatTarget::Ranges(ranges) => ranges
10554 .iter()
10555 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10556 buffer_id: buffer_id.to_proto(),
10557 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10558 })
10559 .collect(),
10560 };
10561
10562 let buffer_store = self.buffer_store();
10563 cx.spawn(async move |lsp_store, cx| {
10564 zlog::trace!(logger => "Sending remote format request");
10565 let request_timer = zlog::time!(logger => "remote format request");
10566 let result = client
10567 .request(proto::FormatBuffers {
10568 project_id,
10569 trigger: trigger as i32,
10570 buffer_ids: buffers
10571 .iter()
10572 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10573 .collect(),
10574 buffer_ranges,
10575 })
10576 .await
10577 .and_then(|result| result.transaction.context("missing transaction"));
10578 request_timer.end();
10579
10580 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10581
10582 lsp_store.update(cx, |lsp_store, _| {
10583 lsp_store.update_last_formatting_failure(&result);
10584 })?;
10585
10586 let transaction_response = result?;
10587 let _timer = zlog::time!(logger => "deserializing project transaction");
10588 buffer_store
10589 .update(cx, |buffer_store, cx| {
10590 buffer_store.deserialize_project_transaction(
10591 transaction_response,
10592 push_to_history,
10593 cx,
10594 )
10595 })
10596 .await
10597 })
10598 } else {
10599 zlog::trace!(logger => "Not formatting");
10600 Task::ready(Ok(ProjectTransaction::default()))
10601 }
10602 }
10603
10604 async fn handle_format_buffers(
10605 this: Entity<Self>,
10606 envelope: TypedEnvelope<proto::FormatBuffers>,
10607 mut cx: AsyncApp,
10608 ) -> Result<proto::FormatBuffersResponse> {
10609 let sender_id = envelope.original_sender_id().unwrap_or_default();
10610 let format = this.update(&mut cx, |this, cx| {
10611 let mut buffers = HashSet::default();
10612 for buffer_id in &envelope.payload.buffer_ids {
10613 let buffer_id = BufferId::new(*buffer_id)?;
10614 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10615 }
10616
10617 let target = if envelope.payload.buffer_ranges.is_empty() {
10618 LspFormatTarget::Buffers
10619 } else {
10620 let mut ranges_map = BTreeMap::new();
10621 for buffer_range in &envelope.payload.buffer_ranges {
10622 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10623 let ranges: Result<Vec<_>> = buffer_range
10624 .ranges
10625 .iter()
10626 .map(|range| {
10627 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10628 })
10629 .collect();
10630 ranges_map.insert(buffer_id, ranges?);
10631 }
10632 LspFormatTarget::Ranges(ranges_map)
10633 };
10634
10635 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10636 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10637 })?;
10638
10639 let project_transaction = format.await?;
10640 let project_transaction = this.update(&mut cx, |this, cx| {
10641 this.buffer_store.update(cx, |buffer_store, cx| {
10642 buffer_store.serialize_project_transaction_for_peer(
10643 project_transaction,
10644 sender_id,
10645 cx,
10646 )
10647 })
10648 });
10649 Ok(proto::FormatBuffersResponse {
10650 transaction: Some(project_transaction),
10651 })
10652 }
10653
10654 async fn handle_apply_code_action_kind(
10655 this: Entity<Self>,
10656 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10657 mut cx: AsyncApp,
10658 ) -> Result<proto::ApplyCodeActionKindResponse> {
10659 let sender_id = envelope.original_sender_id().unwrap_or_default();
10660 let format = this.update(&mut cx, |this, cx| {
10661 let mut buffers = HashSet::default();
10662 for buffer_id in &envelope.payload.buffer_ids {
10663 let buffer_id = BufferId::new(*buffer_id)?;
10664 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10665 }
10666 let kind = match envelope.payload.kind.as_str() {
10667 "" => CodeActionKind::EMPTY,
10668 "quickfix" => CodeActionKind::QUICKFIX,
10669 "refactor" => CodeActionKind::REFACTOR,
10670 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10671 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10672 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10673 "source" => CodeActionKind::SOURCE,
10674 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10675 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10676 _ => anyhow::bail!(
10677 "Invalid code action kind {}",
10678 envelope.payload.kind.as_str()
10679 ),
10680 };
10681 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10682 })?;
10683
10684 let project_transaction = format.await?;
10685 let project_transaction = this.update(&mut cx, |this, cx| {
10686 this.buffer_store.update(cx, |buffer_store, cx| {
10687 buffer_store.serialize_project_transaction_for_peer(
10688 project_transaction,
10689 sender_id,
10690 cx,
10691 )
10692 })
10693 });
10694 Ok(proto::ApplyCodeActionKindResponse {
10695 transaction: Some(project_transaction),
10696 })
10697 }
10698
10699 async fn shutdown_language_server(
10700 server_state: Option<LanguageServerState>,
10701 name: LanguageServerName,
10702 cx: &mut AsyncApp,
10703 ) {
10704 let server = match server_state {
10705 Some(LanguageServerState::Starting { startup, .. }) => {
10706 let mut timer = cx
10707 .background_executor()
10708 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10709 .fuse();
10710
10711 select! {
10712 server = startup.fuse() => server,
10713 () = timer => {
10714 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10715 None
10716 },
10717 }
10718 }
10719
10720 Some(LanguageServerState::Running { server, .. }) => Some(server),
10721
10722 None => None,
10723 };
10724
10725 let Some(server) = server else { return };
10726 if let Some(shutdown) = server.shutdown() {
10727 shutdown.await;
10728 }
10729 }
10730
10731 // Returns a list of all of the worktrees which no longer have a language server and the root path
10732 // for the stopped server
10733 fn stop_local_language_server(
10734 &mut self,
10735 server_id: LanguageServerId,
10736 cx: &mut Context<Self>,
10737 ) -> Task<()> {
10738 let local = match &mut self.mode {
10739 LspStoreMode::Local(local) => local,
10740 _ => {
10741 return Task::ready(());
10742 }
10743 };
10744
10745 // Remove this server ID from all entries in the given worktree.
10746 local
10747 .language_server_ids
10748 .retain(|_, state| state.id != server_id);
10749 self.buffer_store.update(cx, |buffer_store, cx| {
10750 for buffer in buffer_store.buffers() {
10751 buffer.update(cx, |buffer, cx| {
10752 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10753 buffer.set_completion_triggers(server_id, Default::default(), cx);
10754 });
10755 }
10756 });
10757
10758 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10759 summaries.retain(|path, summaries_by_server_id| {
10760 if summaries_by_server_id.remove(&server_id).is_some() {
10761 if let Some((client, project_id)) = self.downstream_client.clone() {
10762 client
10763 .send(proto::UpdateDiagnosticSummary {
10764 project_id,
10765 worktree_id: worktree_id.to_proto(),
10766 summary: Some(proto::DiagnosticSummary {
10767 path: path.as_ref().to_proto(),
10768 language_server_id: server_id.0 as u64,
10769 error_count: 0,
10770 warning_count: 0,
10771 }),
10772 more_summaries: Vec::new(),
10773 })
10774 .log_err();
10775 }
10776 !summaries_by_server_id.is_empty()
10777 } else {
10778 true
10779 }
10780 });
10781 }
10782
10783 let local = self.as_local_mut().unwrap();
10784 for diagnostics in local.diagnostics.values_mut() {
10785 diagnostics.retain(|_, diagnostics_by_server_id| {
10786 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10787 diagnostics_by_server_id.remove(ix);
10788 !diagnostics_by_server_id.is_empty()
10789 } else {
10790 true
10791 }
10792 });
10793 }
10794 local.language_server_watched_paths.remove(&server_id);
10795
10796 let server_state = local.language_servers.remove(&server_id);
10797 self.cleanup_lsp_data(server_id);
10798 let name = self
10799 .language_server_statuses
10800 .remove(&server_id)
10801 .map(|status| status.name)
10802 .or_else(|| {
10803 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10804 Some(adapter.name())
10805 } else {
10806 None
10807 }
10808 });
10809
10810 if let Some(name) = name {
10811 log::info!("stopping language server {name}");
10812 self.languages
10813 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10814 cx.notify();
10815
10816 return cx.spawn(async move |lsp_store, cx| {
10817 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10818 lsp_store
10819 .update(cx, |lsp_store, cx| {
10820 lsp_store
10821 .languages
10822 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10823 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10824 cx.notify();
10825 })
10826 .ok();
10827 });
10828 }
10829
10830 if server_state.is_some() {
10831 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10832 }
10833 Task::ready(())
10834 }
10835
10836 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10837 self.shutdown_all_language_servers(cx).detach();
10838 }
10839
10840 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10841 if let Some((client, project_id)) = self.upstream_client() {
10842 let request = client.request(proto::StopLanguageServers {
10843 project_id,
10844 buffer_ids: Vec::new(),
10845 also_servers: Vec::new(),
10846 all: true,
10847 });
10848 cx.background_spawn(async move {
10849 request.await.ok();
10850 })
10851 } else {
10852 let Some(local) = self.as_local_mut() else {
10853 return Task::ready(());
10854 };
10855 let language_servers_to_stop = local
10856 .language_server_ids
10857 .values()
10858 .map(|state| state.id)
10859 .collect();
10860 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10861 let tasks = language_servers_to_stop
10862 .into_iter()
10863 .map(|server| self.stop_local_language_server(server, cx))
10864 .collect::<Vec<_>>();
10865 cx.background_spawn(async move {
10866 futures::future::join_all(tasks).await;
10867 })
10868 }
10869 }
10870
10871 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10872 let buffers = self.buffer_store.read(cx).buffers().collect();
10873 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10874 }
10875
10876 pub fn restart_language_servers_for_buffers(
10877 &mut self,
10878 buffers: Vec<Entity<Buffer>>,
10879 only_restart_servers: HashSet<LanguageServerSelector>,
10880 cx: &mut Context<Self>,
10881 ) {
10882 if let Some((client, project_id)) = self.upstream_client() {
10883 let request = client.request(proto::RestartLanguageServers {
10884 project_id,
10885 buffer_ids: buffers
10886 .into_iter()
10887 .map(|b| b.read(cx).remote_id().to_proto())
10888 .collect(),
10889 only_servers: only_restart_servers
10890 .into_iter()
10891 .map(|selector| {
10892 let selector = match selector {
10893 LanguageServerSelector::Id(language_server_id) => {
10894 proto::language_server_selector::Selector::ServerId(
10895 language_server_id.to_proto(),
10896 )
10897 }
10898 LanguageServerSelector::Name(language_server_name) => {
10899 proto::language_server_selector::Selector::Name(
10900 language_server_name.to_string(),
10901 )
10902 }
10903 };
10904 proto::LanguageServerSelector {
10905 selector: Some(selector),
10906 }
10907 })
10908 .collect(),
10909 all: false,
10910 });
10911 cx.background_spawn(request).detach_and_log_err(cx);
10912 } else {
10913 let stop_task = if only_restart_servers.is_empty() {
10914 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10915 } else {
10916 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10917 };
10918 cx.spawn(async move |lsp_store, cx| {
10919 stop_task.await;
10920 lsp_store.update(cx, |lsp_store, cx| {
10921 for buffer in buffers {
10922 lsp_store.register_buffer_with_language_servers(
10923 &buffer,
10924 only_restart_servers.clone(),
10925 true,
10926 cx,
10927 );
10928 }
10929 })
10930 })
10931 .detach();
10932 }
10933 }
10934
10935 pub fn stop_language_servers_for_buffers(
10936 &mut self,
10937 buffers: Vec<Entity<Buffer>>,
10938 also_stop_servers: HashSet<LanguageServerSelector>,
10939 cx: &mut Context<Self>,
10940 ) -> Task<Result<()>> {
10941 if let Some((client, project_id)) = self.upstream_client() {
10942 let request = client.request(proto::StopLanguageServers {
10943 project_id,
10944 buffer_ids: buffers
10945 .into_iter()
10946 .map(|b| b.read(cx).remote_id().to_proto())
10947 .collect(),
10948 also_servers: also_stop_servers
10949 .into_iter()
10950 .map(|selector| {
10951 let selector = match selector {
10952 LanguageServerSelector::Id(language_server_id) => {
10953 proto::language_server_selector::Selector::ServerId(
10954 language_server_id.to_proto(),
10955 )
10956 }
10957 LanguageServerSelector::Name(language_server_name) => {
10958 proto::language_server_selector::Selector::Name(
10959 language_server_name.to_string(),
10960 )
10961 }
10962 };
10963 proto::LanguageServerSelector {
10964 selector: Some(selector),
10965 }
10966 })
10967 .collect(),
10968 all: false,
10969 });
10970 cx.background_spawn(async move {
10971 let _ = request.await?;
10972 Ok(())
10973 })
10974 } else {
10975 let task =
10976 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10977 cx.background_spawn(async move {
10978 task.await;
10979 Ok(())
10980 })
10981 }
10982 }
10983
10984 fn stop_local_language_servers_for_buffers(
10985 &mut self,
10986 buffers: &[Entity<Buffer>],
10987 also_stop_servers: HashSet<LanguageServerSelector>,
10988 cx: &mut Context<Self>,
10989 ) -> Task<()> {
10990 let Some(local) = self.as_local_mut() else {
10991 return Task::ready(());
10992 };
10993 let mut language_server_names_to_stop = BTreeSet::default();
10994 let mut language_servers_to_stop = also_stop_servers
10995 .into_iter()
10996 .flat_map(|selector| match selector {
10997 LanguageServerSelector::Id(id) => Some(id),
10998 LanguageServerSelector::Name(name) => {
10999 language_server_names_to_stop.insert(name);
11000 None
11001 }
11002 })
11003 .collect::<BTreeSet<_>>();
11004
11005 let mut covered_worktrees = HashSet::default();
11006 for buffer in buffers {
11007 buffer.update(cx, |buffer, cx| {
11008 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11009 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11010 && covered_worktrees.insert(worktree_id)
11011 {
11012 language_server_names_to_stop.retain(|name| {
11013 let old_ids_count = language_servers_to_stop.len();
11014 let all_language_servers_with_this_name = local
11015 .language_server_ids
11016 .iter()
11017 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11018 language_servers_to_stop.extend(all_language_servers_with_this_name);
11019 old_ids_count == language_servers_to_stop.len()
11020 });
11021 }
11022 });
11023 }
11024 for name in language_server_names_to_stop {
11025 language_servers_to_stop.extend(
11026 local
11027 .language_server_ids
11028 .iter()
11029 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11030 );
11031 }
11032
11033 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11034 let tasks = language_servers_to_stop
11035 .into_iter()
11036 .map(|server| self.stop_local_language_server(server, cx))
11037 .collect::<Vec<_>>();
11038
11039 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11040 }
11041
11042 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11043 let (worktree, relative_path) =
11044 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11045
11046 let project_path = ProjectPath {
11047 worktree_id: worktree.read(cx).id(),
11048 path: relative_path,
11049 };
11050
11051 Some(
11052 self.buffer_store()
11053 .read(cx)
11054 .get_by_path(&project_path)?
11055 .read(cx),
11056 )
11057 }
11058
11059 #[cfg(any(test, feature = "test-support"))]
11060 pub fn update_diagnostics(
11061 &mut self,
11062 server_id: LanguageServerId,
11063 diagnostics: lsp::PublishDiagnosticsParams,
11064 result_id: Option<SharedString>,
11065 source_kind: DiagnosticSourceKind,
11066 disk_based_sources: &[String],
11067 cx: &mut Context<Self>,
11068 ) -> Result<()> {
11069 self.merge_lsp_diagnostics(
11070 source_kind,
11071 vec![DocumentDiagnosticsUpdate {
11072 diagnostics,
11073 result_id,
11074 server_id,
11075 disk_based_sources: Cow::Borrowed(disk_based_sources),
11076 registration_id: None,
11077 }],
11078 |_, _, _| false,
11079 cx,
11080 )
11081 }
11082
11083 pub fn merge_lsp_diagnostics(
11084 &mut self,
11085 source_kind: DiagnosticSourceKind,
11086 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11087 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11088 cx: &mut Context<Self>,
11089 ) -> Result<()> {
11090 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11091 let updates = lsp_diagnostics
11092 .into_iter()
11093 .filter_map(|update| {
11094 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11095 Some(DocumentDiagnosticsUpdate {
11096 diagnostics: self.lsp_to_document_diagnostics(
11097 abs_path,
11098 source_kind,
11099 update.server_id,
11100 update.diagnostics,
11101 &update.disk_based_sources,
11102 update.registration_id.clone(),
11103 ),
11104 result_id: update.result_id,
11105 server_id: update.server_id,
11106 disk_based_sources: update.disk_based_sources,
11107 registration_id: update.registration_id,
11108 })
11109 })
11110 .collect();
11111 self.merge_diagnostic_entries(updates, merge, cx)?;
11112 Ok(())
11113 }
11114
11115 fn lsp_to_document_diagnostics(
11116 &mut self,
11117 document_abs_path: PathBuf,
11118 source_kind: DiagnosticSourceKind,
11119 server_id: LanguageServerId,
11120 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11121 disk_based_sources: &[String],
11122 registration_id: Option<SharedString>,
11123 ) -> DocumentDiagnostics {
11124 let mut diagnostics = Vec::default();
11125 let mut primary_diagnostic_group_ids = HashMap::default();
11126 let mut sources_by_group_id = HashMap::default();
11127 let mut supporting_diagnostics = HashMap::default();
11128
11129 let adapter = self.language_server_adapter_for_id(server_id);
11130
11131 // Ensure that primary diagnostics are always the most severe
11132 lsp_diagnostics
11133 .diagnostics
11134 .sort_by_key(|item| item.severity);
11135
11136 for diagnostic in &lsp_diagnostics.diagnostics {
11137 let source = diagnostic.source.as_ref();
11138 let range = range_from_lsp(diagnostic.range);
11139 let is_supporting = diagnostic
11140 .related_information
11141 .as_ref()
11142 .is_some_and(|infos| {
11143 infos.iter().any(|info| {
11144 primary_diagnostic_group_ids.contains_key(&(
11145 source,
11146 diagnostic.code.clone(),
11147 range_from_lsp(info.location.range),
11148 ))
11149 })
11150 });
11151
11152 let is_unnecessary = diagnostic
11153 .tags
11154 .as_ref()
11155 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11156
11157 let underline = self
11158 .language_server_adapter_for_id(server_id)
11159 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11160
11161 if is_supporting {
11162 supporting_diagnostics.insert(
11163 (source, diagnostic.code.clone(), range),
11164 (diagnostic.severity, is_unnecessary),
11165 );
11166 } else {
11167 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11168 let is_disk_based =
11169 source.is_some_and(|source| disk_based_sources.contains(source));
11170
11171 sources_by_group_id.insert(group_id, source);
11172 primary_diagnostic_group_ids
11173 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11174
11175 diagnostics.push(DiagnosticEntry {
11176 range,
11177 diagnostic: Diagnostic {
11178 source: diagnostic.source.clone(),
11179 source_kind,
11180 code: diagnostic.code.clone(),
11181 code_description: diagnostic
11182 .code_description
11183 .as_ref()
11184 .and_then(|d| d.href.clone()),
11185 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11186 markdown: adapter.as_ref().and_then(|adapter| {
11187 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11188 }),
11189 message: diagnostic.message.trim().to_string(),
11190 group_id,
11191 is_primary: true,
11192 is_disk_based,
11193 is_unnecessary,
11194 underline,
11195 data: diagnostic.data.clone(),
11196 registration_id: registration_id.clone(),
11197 },
11198 });
11199 if let Some(infos) = &diagnostic.related_information {
11200 for info in infos {
11201 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11202 let range = range_from_lsp(info.location.range);
11203 diagnostics.push(DiagnosticEntry {
11204 range,
11205 diagnostic: Diagnostic {
11206 source: diagnostic.source.clone(),
11207 source_kind,
11208 code: diagnostic.code.clone(),
11209 code_description: diagnostic
11210 .code_description
11211 .as_ref()
11212 .and_then(|d| d.href.clone()),
11213 severity: DiagnosticSeverity::INFORMATION,
11214 markdown: adapter.as_ref().and_then(|adapter| {
11215 adapter.diagnostic_message_to_markdown(&info.message)
11216 }),
11217 message: info.message.trim().to_string(),
11218 group_id,
11219 is_primary: false,
11220 is_disk_based,
11221 is_unnecessary: false,
11222 underline,
11223 data: diagnostic.data.clone(),
11224 registration_id: registration_id.clone(),
11225 },
11226 });
11227 }
11228 }
11229 }
11230 }
11231 }
11232
11233 for entry in &mut diagnostics {
11234 let diagnostic = &mut entry.diagnostic;
11235 if !diagnostic.is_primary {
11236 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11237 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11238 source,
11239 diagnostic.code.clone(),
11240 entry.range.clone(),
11241 )) {
11242 if let Some(severity) = severity {
11243 diagnostic.severity = severity;
11244 }
11245 diagnostic.is_unnecessary = is_unnecessary;
11246 }
11247 }
11248 }
11249
11250 DocumentDiagnostics {
11251 diagnostics,
11252 document_abs_path,
11253 version: lsp_diagnostics.version,
11254 }
11255 }
11256
11257 fn insert_newly_running_language_server(
11258 &mut self,
11259 adapter: Arc<CachedLspAdapter>,
11260 language_server: Arc<LanguageServer>,
11261 server_id: LanguageServerId,
11262 key: LanguageServerSeed,
11263 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11264 cx: &mut Context<Self>,
11265 ) {
11266 let Some(local) = self.as_local_mut() else {
11267 return;
11268 };
11269 // If the language server for this key doesn't match the server id, don't store the
11270 // server. Which will cause it to be dropped, killing the process
11271 if local
11272 .language_server_ids
11273 .get(&key)
11274 .map(|state| state.id != server_id)
11275 .unwrap_or(false)
11276 {
11277 return;
11278 }
11279
11280 // Update language_servers collection with Running variant of LanguageServerState
11281 // indicating that the server is up and running and ready
11282 let workspace_folders = workspace_folders.lock().clone();
11283 language_server.set_workspace_folders(workspace_folders);
11284
11285 let workspace_diagnostics_refresh_tasks = language_server
11286 .capabilities()
11287 .diagnostic_provider
11288 .and_then(|provider| {
11289 local
11290 .language_server_dynamic_registrations
11291 .entry(server_id)
11292 .or_default()
11293 .diagnostics
11294 .entry(None)
11295 .or_insert(provider.clone());
11296 let workspace_refresher =
11297 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11298
11299 Some((None, workspace_refresher))
11300 })
11301 .into_iter()
11302 .collect();
11303 local.language_servers.insert(
11304 server_id,
11305 LanguageServerState::Running {
11306 workspace_diagnostics_refresh_tasks,
11307 adapter: adapter.clone(),
11308 server: language_server.clone(),
11309 simulate_disk_based_diagnostics_completion: None,
11310 },
11311 );
11312 local
11313 .languages
11314 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11315 if let Some(file_ops_caps) = language_server
11316 .capabilities()
11317 .workspace
11318 .as_ref()
11319 .and_then(|ws| ws.file_operations.as_ref())
11320 {
11321 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11322 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11323 if did_rename_caps.or(will_rename_caps).is_some() {
11324 let watcher = RenamePathsWatchedForServer::default()
11325 .with_did_rename_patterns(did_rename_caps)
11326 .with_will_rename_patterns(will_rename_caps);
11327 local
11328 .language_server_paths_watched_for_rename
11329 .insert(server_id, watcher);
11330 }
11331 }
11332
11333 self.language_server_statuses.insert(
11334 server_id,
11335 LanguageServerStatus {
11336 name: language_server.name(),
11337 server_version: language_server.version(),
11338 pending_work: Default::default(),
11339 has_pending_diagnostic_updates: false,
11340 progress_tokens: Default::default(),
11341 worktree: Some(key.worktree_id),
11342 binary: Some(language_server.binary().clone()),
11343 configuration: Some(language_server.configuration().clone()),
11344 workspace_folders: language_server.workspace_folders(),
11345 process_id: language_server.process_id(),
11346 },
11347 );
11348
11349 cx.emit(LspStoreEvent::LanguageServerAdded(
11350 server_id,
11351 language_server.name(),
11352 Some(key.worktree_id),
11353 ));
11354
11355 let server_capabilities = language_server.capabilities();
11356 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11357 downstream_client
11358 .send(proto::StartLanguageServer {
11359 project_id: *project_id,
11360 server: Some(proto::LanguageServer {
11361 id: server_id.to_proto(),
11362 name: language_server.name().to_string(),
11363 worktree_id: Some(key.worktree_id.to_proto()),
11364 }),
11365 capabilities: serde_json::to_string(&server_capabilities)
11366 .expect("serializing server LSP capabilities"),
11367 })
11368 .log_err();
11369 }
11370 self.lsp_server_capabilities
11371 .insert(server_id, server_capabilities);
11372
11373 // Tell the language server about every open buffer in the worktree that matches the language.
11374 // Also check for buffers in worktrees that reused this server
11375 let mut worktrees_using_server = vec![key.worktree_id];
11376 if let Some(local) = self.as_local() {
11377 // Find all worktrees that have this server in their language server tree
11378 for (worktree_id, servers) in &local.lsp_tree.instances {
11379 if *worktree_id != key.worktree_id {
11380 for server_map in servers.roots.values() {
11381 if server_map
11382 .values()
11383 .any(|(node, _)| node.id() == Some(server_id))
11384 {
11385 worktrees_using_server.push(*worktree_id);
11386 }
11387 }
11388 }
11389 }
11390 }
11391
11392 let mut buffer_paths_registered = Vec::new();
11393 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11394 let mut lsp_adapters = HashMap::default();
11395 for buffer_handle in buffer_store.buffers() {
11396 let buffer = buffer_handle.read(cx);
11397 let file = match File::from_dyn(buffer.file()) {
11398 Some(file) => file,
11399 None => continue,
11400 };
11401 let language = match buffer.language() {
11402 Some(language) => language,
11403 None => continue,
11404 };
11405
11406 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11407 || !lsp_adapters
11408 .entry(language.name())
11409 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11410 .iter()
11411 .any(|a| a.name == key.name)
11412 {
11413 continue;
11414 }
11415 // didOpen
11416 let file = match file.as_local() {
11417 Some(file) => file,
11418 None => continue,
11419 };
11420
11421 let local = self.as_local_mut().unwrap();
11422
11423 let buffer_id = buffer.remote_id();
11424 if local.registered_buffers.contains_key(&buffer_id) {
11425 let abs_path = file.abs_path(cx);
11426 let uri = match lsp::Uri::from_file_path(&abs_path) {
11427 Ok(uri) => uri,
11428 Err(()) => {
11429 log::error!("failed to convert path to URI: {:?}", abs_path);
11430 continue;
11431 }
11432 };
11433
11434 let versions = local
11435 .buffer_snapshots
11436 .entry(buffer_id)
11437 .or_default()
11438 .entry(server_id)
11439 .and_modify(|_| {
11440 assert!(
11441 false,
11442 "There should not be an existing snapshot for a newly inserted buffer"
11443 )
11444 })
11445 .or_insert_with(|| {
11446 vec![LspBufferSnapshot {
11447 version: 0,
11448 snapshot: buffer.text_snapshot(),
11449 }]
11450 });
11451
11452 let snapshot = versions.last().unwrap();
11453 let version = snapshot.version;
11454 let initial_snapshot = &snapshot.snapshot;
11455 language_server.register_buffer(
11456 uri,
11457 adapter.language_id(&language.name()),
11458 version,
11459 initial_snapshot.text(),
11460 );
11461 buffer_paths_registered.push((buffer_id, abs_path));
11462 local
11463 .buffers_opened_in_servers
11464 .entry(buffer_id)
11465 .or_default()
11466 .insert(server_id);
11467 }
11468 buffer_handle.update(cx, |buffer, cx| {
11469 buffer.set_completion_triggers(
11470 server_id,
11471 language_server
11472 .capabilities()
11473 .completion_provider
11474 .as_ref()
11475 .and_then(|provider| {
11476 provider
11477 .trigger_characters
11478 .as_ref()
11479 .map(|characters| characters.iter().cloned().collect())
11480 })
11481 .unwrap_or_default(),
11482 cx,
11483 )
11484 });
11485 }
11486 });
11487
11488 for (buffer_id, abs_path) in buffer_paths_registered {
11489 cx.emit(LspStoreEvent::LanguageServerUpdate {
11490 language_server_id: server_id,
11491 name: Some(adapter.name()),
11492 message: proto::update_language_server::Variant::RegisteredForBuffer(
11493 proto::RegisteredForBuffer {
11494 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11495 buffer_id: buffer_id.to_proto(),
11496 },
11497 ),
11498 });
11499 }
11500
11501 cx.notify();
11502 }
11503
11504 pub fn language_servers_running_disk_based_diagnostics(
11505 &self,
11506 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11507 self.language_server_statuses
11508 .iter()
11509 .filter_map(|(id, status)| {
11510 if status.has_pending_diagnostic_updates {
11511 Some(*id)
11512 } else {
11513 None
11514 }
11515 })
11516 }
11517
11518 pub(crate) fn cancel_language_server_work_for_buffers(
11519 &mut self,
11520 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11521 cx: &mut Context<Self>,
11522 ) {
11523 if let Some((client, project_id)) = self.upstream_client() {
11524 let request = client.request(proto::CancelLanguageServerWork {
11525 project_id,
11526 work: Some(proto::cancel_language_server_work::Work::Buffers(
11527 proto::cancel_language_server_work::Buffers {
11528 buffer_ids: buffers
11529 .into_iter()
11530 .map(|b| b.read(cx).remote_id().to_proto())
11531 .collect(),
11532 },
11533 )),
11534 });
11535 cx.background_spawn(request).detach_and_log_err(cx);
11536 } else if let Some(local) = self.as_local() {
11537 let servers = buffers
11538 .into_iter()
11539 .flat_map(|buffer| {
11540 buffer.update(cx, |buffer, cx| {
11541 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11542 })
11543 })
11544 .collect::<HashSet<_>>();
11545 for server_id in servers {
11546 self.cancel_language_server_work(server_id, None, cx);
11547 }
11548 }
11549 }
11550
11551 pub(crate) fn cancel_language_server_work(
11552 &mut self,
11553 server_id: LanguageServerId,
11554 token_to_cancel: Option<ProgressToken>,
11555 cx: &mut Context<Self>,
11556 ) {
11557 if let Some(local) = self.as_local() {
11558 let status = self.language_server_statuses.get(&server_id);
11559 let server = local.language_servers.get(&server_id);
11560 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11561 {
11562 for (token, progress) in &status.pending_work {
11563 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11564 && token != token_to_cancel
11565 {
11566 continue;
11567 }
11568 if progress.is_cancellable {
11569 server
11570 .notify::<lsp::notification::WorkDoneProgressCancel>(
11571 WorkDoneProgressCancelParams {
11572 token: token.to_lsp(),
11573 },
11574 )
11575 .ok();
11576 }
11577 }
11578 }
11579 } else if let Some((client, project_id)) = self.upstream_client() {
11580 let request = client.request(proto::CancelLanguageServerWork {
11581 project_id,
11582 work: Some(
11583 proto::cancel_language_server_work::Work::LanguageServerWork(
11584 proto::cancel_language_server_work::LanguageServerWork {
11585 language_server_id: server_id.to_proto(),
11586 token: token_to_cancel.map(|token| token.to_proto()),
11587 },
11588 ),
11589 ),
11590 });
11591 cx.background_spawn(request).detach_and_log_err(cx);
11592 }
11593 }
11594
11595 fn register_supplementary_language_server(
11596 &mut self,
11597 id: LanguageServerId,
11598 name: LanguageServerName,
11599 server: Arc<LanguageServer>,
11600 cx: &mut Context<Self>,
11601 ) {
11602 if let Some(local) = self.as_local_mut() {
11603 local
11604 .supplementary_language_servers
11605 .insert(id, (name.clone(), server));
11606 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11607 }
11608 }
11609
11610 fn unregister_supplementary_language_server(
11611 &mut self,
11612 id: LanguageServerId,
11613 cx: &mut Context<Self>,
11614 ) {
11615 if let Some(local) = self.as_local_mut() {
11616 local.supplementary_language_servers.remove(&id);
11617 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11618 }
11619 }
11620
11621 pub(crate) fn supplementary_language_servers(
11622 &self,
11623 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11624 self.as_local().into_iter().flat_map(|local| {
11625 local
11626 .supplementary_language_servers
11627 .iter()
11628 .map(|(id, (name, _))| (*id, name.clone()))
11629 })
11630 }
11631
11632 pub fn language_server_adapter_for_id(
11633 &self,
11634 id: LanguageServerId,
11635 ) -> Option<Arc<CachedLspAdapter>> {
11636 self.as_local()
11637 .and_then(|local| local.language_servers.get(&id))
11638 .and_then(|language_server_state| match language_server_state {
11639 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11640 _ => None,
11641 })
11642 }
11643
11644 pub(super) fn update_local_worktree_language_servers(
11645 &mut self,
11646 worktree_handle: &Entity<Worktree>,
11647 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11648 cx: &mut Context<Self>,
11649 ) {
11650 if changes.is_empty() {
11651 return;
11652 }
11653
11654 let Some(local) = self.as_local() else { return };
11655
11656 local.prettier_store.update(cx, |prettier_store, cx| {
11657 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11658 });
11659
11660 let worktree_id = worktree_handle.read(cx).id();
11661 let mut language_server_ids = local
11662 .language_server_ids
11663 .iter()
11664 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11665 .collect::<Vec<_>>();
11666 language_server_ids.sort();
11667 language_server_ids.dedup();
11668
11669 // let abs_path = worktree_handle.read(cx).abs_path();
11670 for server_id in &language_server_ids {
11671 if let Some(LanguageServerState::Running { server, .. }) =
11672 local.language_servers.get(server_id)
11673 && let Some(watched_paths) = local
11674 .language_server_watched_paths
11675 .get(server_id)
11676 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11677 {
11678 let params = lsp::DidChangeWatchedFilesParams {
11679 changes: changes
11680 .iter()
11681 .filter_map(|(path, _, change)| {
11682 if !watched_paths.is_match(path.as_std_path()) {
11683 return None;
11684 }
11685 let typ = match change {
11686 PathChange::Loaded => return None,
11687 PathChange::Added => lsp::FileChangeType::CREATED,
11688 PathChange::Removed => lsp::FileChangeType::DELETED,
11689 PathChange::Updated => lsp::FileChangeType::CHANGED,
11690 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11691 };
11692 let uri = lsp::Uri::from_file_path(
11693 worktree_handle.read(cx).absolutize(&path),
11694 )
11695 .ok()?;
11696 Some(lsp::FileEvent { uri, typ })
11697 })
11698 .collect(),
11699 };
11700 if !params.changes.is_empty() {
11701 server
11702 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11703 .ok();
11704 }
11705 }
11706 }
11707 for (path, _, _) in changes {
11708 if let Some(file_name) = path.file_name()
11709 && local.watched_manifest_filenames.contains(file_name)
11710 {
11711 self.request_workspace_config_refresh();
11712 break;
11713 }
11714 }
11715 }
11716
11717 pub fn wait_for_remote_buffer(
11718 &mut self,
11719 id: BufferId,
11720 cx: &mut Context<Self>,
11721 ) -> Task<Result<Entity<Buffer>>> {
11722 self.buffer_store.update(cx, |buffer_store, cx| {
11723 buffer_store.wait_for_remote_buffer(id, cx)
11724 })
11725 }
11726
11727 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11728 let mut result = proto::Symbol {
11729 language_server_name: symbol.language_server_name.0.to_string(),
11730 source_worktree_id: symbol.source_worktree_id.to_proto(),
11731 language_server_id: symbol.source_language_server_id.to_proto(),
11732 name: symbol.name.clone(),
11733 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11734 start: Some(proto::PointUtf16 {
11735 row: symbol.range.start.0.row,
11736 column: symbol.range.start.0.column,
11737 }),
11738 end: Some(proto::PointUtf16 {
11739 row: symbol.range.end.0.row,
11740 column: symbol.range.end.0.column,
11741 }),
11742 worktree_id: Default::default(),
11743 path: Default::default(),
11744 signature: Default::default(),
11745 container_name: symbol.container_name.clone(),
11746 };
11747 match &symbol.path {
11748 SymbolLocation::InProject(path) => {
11749 result.worktree_id = path.worktree_id.to_proto();
11750 result.path = path.path.to_proto();
11751 }
11752 SymbolLocation::OutsideProject {
11753 abs_path,
11754 signature,
11755 } => {
11756 result.path = abs_path.to_string_lossy().into_owned();
11757 result.signature = signature.to_vec();
11758 }
11759 }
11760 result
11761 }
11762
11763 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11764 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11765 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11766 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11767
11768 let path = if serialized_symbol.signature.is_empty() {
11769 SymbolLocation::InProject(ProjectPath {
11770 worktree_id,
11771 path: RelPath::from_proto(&serialized_symbol.path)
11772 .context("invalid symbol path")?,
11773 })
11774 } else {
11775 SymbolLocation::OutsideProject {
11776 abs_path: Path::new(&serialized_symbol.path).into(),
11777 signature: serialized_symbol
11778 .signature
11779 .try_into()
11780 .map_err(|_| anyhow!("invalid signature"))?,
11781 }
11782 };
11783
11784 let start = serialized_symbol.start.context("invalid start")?;
11785 let end = serialized_symbol.end.context("invalid end")?;
11786 Ok(CoreSymbol {
11787 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11788 source_worktree_id,
11789 source_language_server_id: LanguageServerId::from_proto(
11790 serialized_symbol.language_server_id,
11791 ),
11792 path,
11793 name: serialized_symbol.name,
11794 range: Unclipped(PointUtf16::new(start.row, start.column))
11795 ..Unclipped(PointUtf16::new(end.row, end.column)),
11796 kind,
11797 container_name: serialized_symbol.container_name,
11798 })
11799 }
11800
11801 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11802 let mut serialized_completion = proto::Completion {
11803 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11804 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11805 new_text: completion.new_text.clone(),
11806 ..proto::Completion::default()
11807 };
11808 match &completion.source {
11809 CompletionSource::Lsp {
11810 insert_range,
11811 server_id,
11812 lsp_completion,
11813 lsp_defaults,
11814 resolved,
11815 } => {
11816 let (old_insert_start, old_insert_end) = insert_range
11817 .as_ref()
11818 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11819 .unzip();
11820
11821 serialized_completion.old_insert_start = old_insert_start;
11822 serialized_completion.old_insert_end = old_insert_end;
11823 serialized_completion.source = proto::completion::Source::Lsp as i32;
11824 serialized_completion.server_id = server_id.0 as u64;
11825 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11826 serialized_completion.lsp_defaults = lsp_defaults
11827 .as_deref()
11828 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11829 serialized_completion.resolved = *resolved;
11830 }
11831 CompletionSource::BufferWord {
11832 word_range,
11833 resolved,
11834 } => {
11835 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11836 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11837 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11838 serialized_completion.resolved = *resolved;
11839 }
11840 CompletionSource::Custom => {
11841 serialized_completion.source = proto::completion::Source::Custom as i32;
11842 serialized_completion.resolved = true;
11843 }
11844 CompletionSource::Dap { sort_text } => {
11845 serialized_completion.source = proto::completion::Source::Dap as i32;
11846 serialized_completion.sort_text = Some(sort_text.clone());
11847 }
11848 }
11849
11850 serialized_completion
11851 }
11852
11853 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11854 let old_replace_start = completion
11855 .old_replace_start
11856 .and_then(deserialize_anchor)
11857 .context("invalid old start")?;
11858 let old_replace_end = completion
11859 .old_replace_end
11860 .and_then(deserialize_anchor)
11861 .context("invalid old end")?;
11862 let insert_range = {
11863 match completion.old_insert_start.zip(completion.old_insert_end) {
11864 Some((start, end)) => {
11865 let start = deserialize_anchor(start).context("invalid insert old start")?;
11866 let end = deserialize_anchor(end).context("invalid insert old end")?;
11867 Some(start..end)
11868 }
11869 None => None,
11870 }
11871 };
11872 Ok(CoreCompletion {
11873 replace_range: old_replace_start..old_replace_end,
11874 new_text: completion.new_text,
11875 source: match proto::completion::Source::from_i32(completion.source) {
11876 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11877 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11878 insert_range,
11879 server_id: LanguageServerId::from_proto(completion.server_id),
11880 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11881 lsp_defaults: completion
11882 .lsp_defaults
11883 .as_deref()
11884 .map(serde_json::from_slice)
11885 .transpose()?,
11886 resolved: completion.resolved,
11887 },
11888 Some(proto::completion::Source::BufferWord) => {
11889 let word_range = completion
11890 .buffer_word_start
11891 .and_then(deserialize_anchor)
11892 .context("invalid buffer word start")?
11893 ..completion
11894 .buffer_word_end
11895 .and_then(deserialize_anchor)
11896 .context("invalid buffer word end")?;
11897 CompletionSource::BufferWord {
11898 word_range,
11899 resolved: completion.resolved,
11900 }
11901 }
11902 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11903 sort_text: completion
11904 .sort_text
11905 .context("expected sort text to exist")?,
11906 },
11907 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11908 },
11909 })
11910 }
11911
11912 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11913 let (kind, lsp_action) = match &action.lsp_action {
11914 LspAction::Action(code_action) => (
11915 proto::code_action::Kind::Action as i32,
11916 serde_json::to_vec(code_action).unwrap(),
11917 ),
11918 LspAction::Command(command) => (
11919 proto::code_action::Kind::Command as i32,
11920 serde_json::to_vec(command).unwrap(),
11921 ),
11922 LspAction::CodeLens(code_lens) => (
11923 proto::code_action::Kind::CodeLens as i32,
11924 serde_json::to_vec(code_lens).unwrap(),
11925 ),
11926 };
11927
11928 proto::CodeAction {
11929 server_id: action.server_id.0 as u64,
11930 start: Some(serialize_anchor(&action.range.start)),
11931 end: Some(serialize_anchor(&action.range.end)),
11932 lsp_action,
11933 kind,
11934 resolved: action.resolved,
11935 }
11936 }
11937
11938 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11939 let start = action
11940 .start
11941 .and_then(deserialize_anchor)
11942 .context("invalid start")?;
11943 let end = action
11944 .end
11945 .and_then(deserialize_anchor)
11946 .context("invalid end")?;
11947 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11948 Some(proto::code_action::Kind::Action) => {
11949 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11950 }
11951 Some(proto::code_action::Kind::Command) => {
11952 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11953 }
11954 Some(proto::code_action::Kind::CodeLens) => {
11955 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11956 }
11957 None => anyhow::bail!("Unknown action kind {}", action.kind),
11958 };
11959 Ok(CodeAction {
11960 server_id: LanguageServerId(action.server_id as usize),
11961 range: start..end,
11962 resolved: action.resolved,
11963 lsp_action,
11964 })
11965 }
11966
11967 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11968 match &formatting_result {
11969 Ok(_) => self.last_formatting_failure = None,
11970 Err(error) => {
11971 let error_string = format!("{error:#}");
11972 log::error!("Formatting failed: {error_string}");
11973 self.last_formatting_failure
11974 .replace(error_string.lines().join(" "));
11975 }
11976 }
11977 }
11978
11979 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11980 self.lsp_server_capabilities.remove(&for_server);
11981 self.semantic_token_config.remove_server_data(for_server);
11982 for lsp_data in self.lsp_data.values_mut() {
11983 lsp_data.remove_server_data(for_server);
11984 }
11985 if let Some(local) = self.as_local_mut() {
11986 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11987 local
11988 .workspace_pull_diagnostics_result_ids
11989 .remove(&for_server);
11990 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11991 buffer_servers.remove(&for_server);
11992 }
11993 }
11994 }
11995
11996 pub fn result_id_for_buffer_pull(
11997 &self,
11998 server_id: LanguageServerId,
11999 buffer_id: BufferId,
12000 registration_id: &Option<SharedString>,
12001 cx: &App,
12002 ) -> Option<SharedString> {
12003 let abs_path = self
12004 .buffer_store
12005 .read(cx)
12006 .get(buffer_id)
12007 .and_then(|b| File::from_dyn(b.read(cx).file()))
12008 .map(|f| f.abs_path(cx))?;
12009 self.as_local()?
12010 .buffer_pull_diagnostics_result_ids
12011 .get(&server_id)?
12012 .get(registration_id)?
12013 .get(&abs_path)?
12014 .clone()
12015 }
12016
12017 /// Gets all result_ids for a workspace diagnostics pull request.
12018 /// 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.
12019 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12020 pub fn result_ids_for_workspace_refresh(
12021 &self,
12022 server_id: LanguageServerId,
12023 registration_id: &Option<SharedString>,
12024 ) -> HashMap<PathBuf, SharedString> {
12025 let Some(local) = self.as_local() else {
12026 return HashMap::default();
12027 };
12028 local
12029 .workspace_pull_diagnostics_result_ids
12030 .get(&server_id)
12031 .into_iter()
12032 .filter_map(|diagnostics| diagnostics.get(registration_id))
12033 .flatten()
12034 .filter_map(|(abs_path, result_id)| {
12035 let result_id = local
12036 .buffer_pull_diagnostics_result_ids
12037 .get(&server_id)
12038 .and_then(|buffer_ids_result_ids| {
12039 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12040 })
12041 .cloned()
12042 .flatten()
12043 .or_else(|| result_id.clone())?;
12044 Some((abs_path.clone(), result_id))
12045 })
12046 .collect()
12047 }
12048
12049 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12050 if let Some(LanguageServerState::Running {
12051 workspace_diagnostics_refresh_tasks,
12052 ..
12053 }) = self
12054 .as_local_mut()
12055 .and_then(|local| local.language_servers.get_mut(&server_id))
12056 {
12057 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12058 diagnostics.refresh_tx.try_send(()).ok();
12059 }
12060 }
12061 }
12062
12063 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12064 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12065 /// which requires refreshing both workspace and document diagnostics.
12066 pub fn pull_document_diagnostics_for_server(
12067 &mut self,
12068 server_id: LanguageServerId,
12069 source_buffer_id: Option<BufferId>,
12070 cx: &mut Context<Self>,
12071 ) -> Shared<Task<()>> {
12072 let Some(local) = self.as_local_mut() else {
12073 return Task::ready(()).shared();
12074 };
12075 let mut buffers_to_refresh = HashSet::default();
12076 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12077 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12078 buffers_to_refresh.insert(*buffer_id);
12079 }
12080 }
12081
12082 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12083 }
12084
12085 pub fn pull_document_diagnostics_for_buffer_edit(
12086 &mut self,
12087 buffer_id: BufferId,
12088 cx: &mut Context<Self>,
12089 ) {
12090 let Some(local) = self.as_local_mut() else {
12091 return;
12092 };
12093 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12094 else {
12095 return;
12096 };
12097 for server_id in languages_servers {
12098 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12099 }
12100 }
12101
12102 fn apply_workspace_diagnostic_report(
12103 &mut self,
12104 server_id: LanguageServerId,
12105 report: lsp::WorkspaceDiagnosticReportResult,
12106 registration_id: Option<SharedString>,
12107 cx: &mut Context<Self>,
12108 ) {
12109 let mut workspace_diagnostics =
12110 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12111 report,
12112 server_id,
12113 registration_id,
12114 );
12115 workspace_diagnostics.retain(|d| match &d.diagnostics {
12116 LspPullDiagnostics::Response {
12117 server_id,
12118 registration_id,
12119 ..
12120 } => self.diagnostic_registration_exists(*server_id, registration_id),
12121 LspPullDiagnostics::Default => false,
12122 });
12123 let mut unchanged_buffers = HashMap::default();
12124 let workspace_diagnostics_updates = workspace_diagnostics
12125 .into_iter()
12126 .filter_map(
12127 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12128 LspPullDiagnostics::Response {
12129 server_id,
12130 uri,
12131 diagnostics,
12132 registration_id,
12133 } => Some((
12134 server_id,
12135 uri,
12136 diagnostics,
12137 workspace_diagnostics.version,
12138 registration_id,
12139 )),
12140 LspPullDiagnostics::Default => None,
12141 },
12142 )
12143 .fold(
12144 HashMap::default(),
12145 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12146 let (result_id, diagnostics) = match diagnostics {
12147 PulledDiagnostics::Unchanged { result_id } => {
12148 unchanged_buffers
12149 .entry(new_registration_id.clone())
12150 .or_insert_with(HashSet::default)
12151 .insert(uri.clone());
12152 (Some(result_id), Vec::new())
12153 }
12154 PulledDiagnostics::Changed {
12155 result_id,
12156 diagnostics,
12157 } => (result_id, diagnostics),
12158 };
12159 let disk_based_sources = Cow::Owned(
12160 self.language_server_adapter_for_id(server_id)
12161 .as_ref()
12162 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12163 .unwrap_or(&[])
12164 .to_vec(),
12165 );
12166
12167 let Some(abs_path) = uri.to_file_path().ok() else {
12168 return acc;
12169 };
12170 let Some((worktree, relative_path)) =
12171 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12172 else {
12173 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12174 return acc;
12175 };
12176 let worktree_id = worktree.read(cx).id();
12177 let project_path = ProjectPath {
12178 worktree_id,
12179 path: relative_path,
12180 };
12181 if let Some(local_lsp_store) = self.as_local_mut() {
12182 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12183 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12184 }
12185 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12186 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12187 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12188 acc.entry(server_id)
12189 .or_insert_with(HashMap::default)
12190 .entry(new_registration_id.clone())
12191 .or_insert_with(Vec::new)
12192 .push(DocumentDiagnosticsUpdate {
12193 server_id,
12194 diagnostics: lsp::PublishDiagnosticsParams {
12195 uri,
12196 diagnostics,
12197 version,
12198 },
12199 result_id: result_id.map(SharedString::new),
12200 disk_based_sources,
12201 registration_id: new_registration_id,
12202 });
12203 }
12204 acc
12205 },
12206 );
12207
12208 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12209 for (registration_id, diagnostic_updates) in diagnostic_updates {
12210 self.merge_lsp_diagnostics(
12211 DiagnosticSourceKind::Pulled,
12212 diagnostic_updates,
12213 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12214 DiagnosticSourceKind::Pulled => {
12215 old_diagnostic.registration_id != registration_id
12216 || unchanged_buffers
12217 .get(&old_diagnostic.registration_id)
12218 .is_some_and(|unchanged_buffers| {
12219 unchanged_buffers.contains(&document_uri)
12220 })
12221 }
12222 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12223 },
12224 cx,
12225 )
12226 .log_err();
12227 }
12228 }
12229 }
12230
12231 fn register_server_capabilities(
12232 &mut self,
12233 server_id: LanguageServerId,
12234 params: lsp::RegistrationParams,
12235 cx: &mut Context<Self>,
12236 ) -> anyhow::Result<()> {
12237 let server = self
12238 .language_server_for_id(server_id)
12239 .with_context(|| format!("no server {server_id} found"))?;
12240 for reg in params.registrations {
12241 match reg.method.as_str() {
12242 "workspace/didChangeWatchedFiles" => {
12243 if let Some(options) = reg.register_options {
12244 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12245 let caps = serde_json::from_value(options)?;
12246 local_lsp_store
12247 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12248 true
12249 } else {
12250 false
12251 };
12252 if notify {
12253 notify_server_capabilities_updated(&server, cx);
12254 }
12255 }
12256 }
12257 "workspace/didChangeConfiguration" => {
12258 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12259 }
12260 "workspace/didChangeWorkspaceFolders" => {
12261 // In this case register options is an empty object, we can ignore it
12262 let caps = lsp::WorkspaceFoldersServerCapabilities {
12263 supported: Some(true),
12264 change_notifications: Some(OneOf::Right(reg.id)),
12265 };
12266 server.update_capabilities(|capabilities| {
12267 capabilities
12268 .workspace
12269 .get_or_insert_default()
12270 .workspace_folders = Some(caps);
12271 });
12272 notify_server_capabilities_updated(&server, cx);
12273 }
12274 "workspace/symbol" => {
12275 let options = parse_register_capabilities(reg)?;
12276 server.update_capabilities(|capabilities| {
12277 capabilities.workspace_symbol_provider = Some(options);
12278 });
12279 notify_server_capabilities_updated(&server, cx);
12280 }
12281 "workspace/fileOperations" => {
12282 if let Some(options) = reg.register_options {
12283 let caps = serde_json::from_value(options)?;
12284 server.update_capabilities(|capabilities| {
12285 capabilities
12286 .workspace
12287 .get_or_insert_default()
12288 .file_operations = Some(caps);
12289 });
12290 notify_server_capabilities_updated(&server, cx);
12291 }
12292 }
12293 "workspace/executeCommand" => {
12294 if let Some(options) = reg.register_options {
12295 let options = serde_json::from_value(options)?;
12296 server.update_capabilities(|capabilities| {
12297 capabilities.execute_command_provider = Some(options);
12298 });
12299 notify_server_capabilities_updated(&server, cx);
12300 }
12301 }
12302 "textDocument/rangeFormatting" => {
12303 let options = parse_register_capabilities(reg)?;
12304 server.update_capabilities(|capabilities| {
12305 capabilities.document_range_formatting_provider = Some(options);
12306 });
12307 notify_server_capabilities_updated(&server, cx);
12308 }
12309 "textDocument/onTypeFormatting" => {
12310 if let Some(options) = reg
12311 .register_options
12312 .map(serde_json::from_value)
12313 .transpose()?
12314 {
12315 server.update_capabilities(|capabilities| {
12316 capabilities.document_on_type_formatting_provider = Some(options);
12317 });
12318 notify_server_capabilities_updated(&server, cx);
12319 }
12320 }
12321 "textDocument/formatting" => {
12322 let options = parse_register_capabilities(reg)?;
12323 server.update_capabilities(|capabilities| {
12324 capabilities.document_formatting_provider = Some(options);
12325 });
12326 notify_server_capabilities_updated(&server, cx);
12327 }
12328 "textDocument/rename" => {
12329 let options = parse_register_capabilities(reg)?;
12330 server.update_capabilities(|capabilities| {
12331 capabilities.rename_provider = Some(options);
12332 });
12333 notify_server_capabilities_updated(&server, cx);
12334 }
12335 "textDocument/inlayHint" => {
12336 let options = parse_register_capabilities(reg)?;
12337 server.update_capabilities(|capabilities| {
12338 capabilities.inlay_hint_provider = Some(options);
12339 });
12340 notify_server_capabilities_updated(&server, cx);
12341 }
12342 "textDocument/documentSymbol" => {
12343 let options = parse_register_capabilities(reg)?;
12344 server.update_capabilities(|capabilities| {
12345 capabilities.document_symbol_provider = Some(options);
12346 });
12347 notify_server_capabilities_updated(&server, cx);
12348 }
12349 "textDocument/codeAction" => {
12350 let options = parse_register_capabilities(reg)?;
12351 let provider = match options {
12352 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12353 OneOf::Right(caps) => caps,
12354 };
12355 server.update_capabilities(|capabilities| {
12356 capabilities.code_action_provider = Some(provider);
12357 });
12358 notify_server_capabilities_updated(&server, cx);
12359 }
12360 "textDocument/definition" => {
12361 let options = parse_register_capabilities(reg)?;
12362 server.update_capabilities(|capabilities| {
12363 capabilities.definition_provider = Some(options);
12364 });
12365 notify_server_capabilities_updated(&server, cx);
12366 }
12367 "textDocument/completion" => {
12368 if let Some(caps) = reg
12369 .register_options
12370 .map(serde_json::from_value::<CompletionOptions>)
12371 .transpose()?
12372 {
12373 server.update_capabilities(|capabilities| {
12374 capabilities.completion_provider = Some(caps.clone());
12375 });
12376
12377 if let Some(local) = self.as_local() {
12378 let mut buffers_with_language_server = Vec::new();
12379 for handle in self.buffer_store.read(cx).buffers() {
12380 let buffer_id = handle.read(cx).remote_id();
12381 if local
12382 .buffers_opened_in_servers
12383 .get(&buffer_id)
12384 .filter(|s| s.contains(&server_id))
12385 .is_some()
12386 {
12387 buffers_with_language_server.push(handle);
12388 }
12389 }
12390 let triggers = caps
12391 .trigger_characters
12392 .unwrap_or_default()
12393 .into_iter()
12394 .collect::<BTreeSet<_>>();
12395 for handle in buffers_with_language_server {
12396 let triggers = triggers.clone();
12397 let _ = handle.update(cx, move |buffer, cx| {
12398 buffer.set_completion_triggers(server_id, triggers, cx);
12399 });
12400 }
12401 }
12402 notify_server_capabilities_updated(&server, cx);
12403 }
12404 }
12405 "textDocument/hover" => {
12406 let options = parse_register_capabilities(reg)?;
12407 let provider = match options {
12408 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12409 OneOf::Right(caps) => caps,
12410 };
12411 server.update_capabilities(|capabilities| {
12412 capabilities.hover_provider = Some(provider);
12413 });
12414 notify_server_capabilities_updated(&server, cx);
12415 }
12416 "textDocument/signatureHelp" => {
12417 if let Some(caps) = reg
12418 .register_options
12419 .map(serde_json::from_value)
12420 .transpose()?
12421 {
12422 server.update_capabilities(|capabilities| {
12423 capabilities.signature_help_provider = Some(caps);
12424 });
12425 notify_server_capabilities_updated(&server, cx);
12426 }
12427 }
12428 "textDocument/didChange" => {
12429 if let Some(sync_kind) = reg
12430 .register_options
12431 .and_then(|opts| opts.get("syncKind").cloned())
12432 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12433 .transpose()?
12434 {
12435 server.update_capabilities(|capabilities| {
12436 let mut sync_options =
12437 Self::take_text_document_sync_options(capabilities);
12438 sync_options.change = Some(sync_kind);
12439 capabilities.text_document_sync =
12440 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12441 });
12442 notify_server_capabilities_updated(&server, cx);
12443 }
12444 }
12445 "textDocument/didSave" => {
12446 if let Some(include_text) = reg
12447 .register_options
12448 .map(|opts| {
12449 let transpose = opts
12450 .get("includeText")
12451 .cloned()
12452 .map(serde_json::from_value::<Option<bool>>)
12453 .transpose();
12454 match transpose {
12455 Ok(value) => Ok(value.flatten()),
12456 Err(e) => Err(e),
12457 }
12458 })
12459 .transpose()?
12460 {
12461 server.update_capabilities(|capabilities| {
12462 let mut sync_options =
12463 Self::take_text_document_sync_options(capabilities);
12464 sync_options.save =
12465 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12466 include_text,
12467 }));
12468 capabilities.text_document_sync =
12469 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12470 });
12471 notify_server_capabilities_updated(&server, cx);
12472 }
12473 }
12474 "textDocument/codeLens" => {
12475 if let Some(caps) = reg
12476 .register_options
12477 .map(serde_json::from_value)
12478 .transpose()?
12479 {
12480 server.update_capabilities(|capabilities| {
12481 capabilities.code_lens_provider = Some(caps);
12482 });
12483 notify_server_capabilities_updated(&server, cx);
12484 }
12485 }
12486 "textDocument/diagnostic" => {
12487 if let Some(caps) = reg
12488 .register_options
12489 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12490 .transpose()?
12491 {
12492 let local = self
12493 .as_local_mut()
12494 .context("Expected LSP Store to be local")?;
12495 let state = local
12496 .language_servers
12497 .get_mut(&server_id)
12498 .context("Could not obtain Language Servers state")?;
12499 local
12500 .language_server_dynamic_registrations
12501 .entry(server_id)
12502 .or_default()
12503 .diagnostics
12504 .insert(Some(reg.id.clone()), caps.clone());
12505
12506 let supports_workspace_diagnostics =
12507 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12508 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12509 diagnostic_options.workspace_diagnostics
12510 }
12511 DiagnosticServerCapabilities::RegistrationOptions(
12512 diagnostic_registration_options,
12513 ) => {
12514 diagnostic_registration_options
12515 .diagnostic_options
12516 .workspace_diagnostics
12517 }
12518 };
12519
12520 if supports_workspace_diagnostics(&caps) {
12521 if let LanguageServerState::Running {
12522 workspace_diagnostics_refresh_tasks,
12523 ..
12524 } = state
12525 && let Some(task) = lsp_workspace_diagnostics_refresh(
12526 Some(reg.id.clone()),
12527 caps.clone(),
12528 server.clone(),
12529 cx,
12530 )
12531 {
12532 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12533 }
12534 }
12535
12536 server.update_capabilities(|capabilities| {
12537 capabilities.diagnostic_provider = Some(caps);
12538 });
12539
12540 notify_server_capabilities_updated(&server, cx);
12541
12542 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12543 }
12544 }
12545 "textDocument/documentColor" => {
12546 let options = parse_register_capabilities(reg)?;
12547 let provider = match options {
12548 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12549 OneOf::Right(caps) => caps,
12550 };
12551 server.update_capabilities(|capabilities| {
12552 capabilities.color_provider = Some(provider);
12553 });
12554 notify_server_capabilities_updated(&server, cx);
12555 }
12556 "textDocument/foldingRange" => {
12557 let options = parse_register_capabilities(reg)?;
12558 let provider = match options {
12559 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12560 OneOf::Right(caps) => caps,
12561 };
12562 server.update_capabilities(|capabilities| {
12563 capabilities.folding_range_provider = Some(provider);
12564 });
12565 notify_server_capabilities_updated(&server, cx);
12566 }
12567 _ => log::warn!("unhandled capability registration: {reg:?}"),
12568 }
12569 }
12570
12571 Ok(())
12572 }
12573
12574 fn unregister_server_capabilities(
12575 &mut self,
12576 server_id: LanguageServerId,
12577 params: lsp::UnregistrationParams,
12578 cx: &mut Context<Self>,
12579 ) -> anyhow::Result<()> {
12580 let server = self
12581 .language_server_for_id(server_id)
12582 .with_context(|| format!("no server {server_id} found"))?;
12583 for unreg in params.unregisterations.iter() {
12584 match unreg.method.as_str() {
12585 "workspace/didChangeWatchedFiles" => {
12586 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12587 local_lsp_store
12588 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12589 true
12590 } else {
12591 false
12592 };
12593 if notify {
12594 notify_server_capabilities_updated(&server, cx);
12595 }
12596 }
12597 "workspace/didChangeConfiguration" => {
12598 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12599 }
12600 "workspace/didChangeWorkspaceFolders" => {
12601 server.update_capabilities(|capabilities| {
12602 capabilities
12603 .workspace
12604 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12605 workspace_folders: None,
12606 file_operations: None,
12607 })
12608 .workspace_folders = None;
12609 });
12610 notify_server_capabilities_updated(&server, cx);
12611 }
12612 "workspace/symbol" => {
12613 server.update_capabilities(|capabilities| {
12614 capabilities.workspace_symbol_provider = None
12615 });
12616 notify_server_capabilities_updated(&server, cx);
12617 }
12618 "workspace/fileOperations" => {
12619 server.update_capabilities(|capabilities| {
12620 capabilities
12621 .workspace
12622 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12623 workspace_folders: None,
12624 file_operations: None,
12625 })
12626 .file_operations = None;
12627 });
12628 notify_server_capabilities_updated(&server, cx);
12629 }
12630 "workspace/executeCommand" => {
12631 server.update_capabilities(|capabilities| {
12632 capabilities.execute_command_provider = None;
12633 });
12634 notify_server_capabilities_updated(&server, cx);
12635 }
12636 "textDocument/rangeFormatting" => {
12637 server.update_capabilities(|capabilities| {
12638 capabilities.document_range_formatting_provider = None
12639 });
12640 notify_server_capabilities_updated(&server, cx);
12641 }
12642 "textDocument/onTypeFormatting" => {
12643 server.update_capabilities(|capabilities| {
12644 capabilities.document_on_type_formatting_provider = None;
12645 });
12646 notify_server_capabilities_updated(&server, cx);
12647 }
12648 "textDocument/formatting" => {
12649 server.update_capabilities(|capabilities| {
12650 capabilities.document_formatting_provider = None;
12651 });
12652 notify_server_capabilities_updated(&server, cx);
12653 }
12654 "textDocument/rename" => {
12655 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12656 notify_server_capabilities_updated(&server, cx);
12657 }
12658 "textDocument/codeAction" => {
12659 server.update_capabilities(|capabilities| {
12660 capabilities.code_action_provider = None;
12661 });
12662 notify_server_capabilities_updated(&server, cx);
12663 }
12664 "textDocument/definition" => {
12665 server.update_capabilities(|capabilities| {
12666 capabilities.definition_provider = None;
12667 });
12668 notify_server_capabilities_updated(&server, cx);
12669 }
12670 "textDocument/completion" => {
12671 server.update_capabilities(|capabilities| {
12672 capabilities.completion_provider = None;
12673 });
12674 notify_server_capabilities_updated(&server, cx);
12675 }
12676 "textDocument/hover" => {
12677 server.update_capabilities(|capabilities| {
12678 capabilities.hover_provider = None;
12679 });
12680 notify_server_capabilities_updated(&server, cx);
12681 }
12682 "textDocument/signatureHelp" => {
12683 server.update_capabilities(|capabilities| {
12684 capabilities.signature_help_provider = None;
12685 });
12686 notify_server_capabilities_updated(&server, cx);
12687 }
12688 "textDocument/didChange" => {
12689 server.update_capabilities(|capabilities| {
12690 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12691 sync_options.change = None;
12692 capabilities.text_document_sync =
12693 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12694 });
12695 notify_server_capabilities_updated(&server, cx);
12696 }
12697 "textDocument/didSave" => {
12698 server.update_capabilities(|capabilities| {
12699 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12700 sync_options.save = None;
12701 capabilities.text_document_sync =
12702 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12703 });
12704 notify_server_capabilities_updated(&server, cx);
12705 }
12706 "textDocument/codeLens" => {
12707 server.update_capabilities(|capabilities| {
12708 capabilities.code_lens_provider = None;
12709 });
12710 notify_server_capabilities_updated(&server, cx);
12711 }
12712 "textDocument/diagnostic" => {
12713 let local = self
12714 .as_local_mut()
12715 .context("Expected LSP Store to be local")?;
12716
12717 let state = local
12718 .language_servers
12719 .get_mut(&server_id)
12720 .context("Could not obtain Language Servers state")?;
12721 let registrations = local
12722 .language_server_dynamic_registrations
12723 .get_mut(&server_id)
12724 .with_context(|| {
12725 format!("Expected dynamic registration to exist for server {server_id}")
12726 })?;
12727 registrations.diagnostics
12728 .remove(&Some(unreg.id.clone()))
12729 .with_context(|| format!(
12730 "Attempted to unregister non-existent diagnostic registration with ID {}",
12731 unreg.id)
12732 )?;
12733 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12734
12735 if let LanguageServerState::Running {
12736 workspace_diagnostics_refresh_tasks,
12737 ..
12738 } = state
12739 {
12740 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12741 }
12742
12743 self.clear_unregistered_diagnostics(
12744 server_id,
12745 SharedString::from(unreg.id.clone()),
12746 cx,
12747 )?;
12748
12749 if removed_last_diagnostic_provider {
12750 server.update_capabilities(|capabilities| {
12751 debug_assert!(capabilities.diagnostic_provider.is_some());
12752 capabilities.diagnostic_provider = None;
12753 });
12754 }
12755
12756 notify_server_capabilities_updated(&server, cx);
12757 }
12758 "textDocument/documentColor" => {
12759 server.update_capabilities(|capabilities| {
12760 capabilities.color_provider = None;
12761 });
12762 notify_server_capabilities_updated(&server, cx);
12763 }
12764 "textDocument/foldingRange" => {
12765 server.update_capabilities(|capabilities| {
12766 capabilities.folding_range_provider = None;
12767 });
12768 notify_server_capabilities_updated(&server, cx);
12769 }
12770 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12771 }
12772 }
12773
12774 Ok(())
12775 }
12776
12777 fn clear_unregistered_diagnostics(
12778 &mut self,
12779 server_id: LanguageServerId,
12780 cleared_registration_id: SharedString,
12781 cx: &mut Context<Self>,
12782 ) -> anyhow::Result<()> {
12783 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12784
12785 self.buffer_store.update(cx, |buffer_store, cx| {
12786 for buffer_handle in buffer_store.buffers() {
12787 let buffer = buffer_handle.read(cx);
12788 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12789 let Some(abs_path) = abs_path else {
12790 continue;
12791 };
12792 affected_abs_paths.insert(abs_path);
12793 }
12794 });
12795
12796 let local = self.as_local().context("Expected LSP Store to be local")?;
12797 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12798 let Some(worktree) = self
12799 .worktree_store
12800 .read(cx)
12801 .worktree_for_id(*worktree_id, cx)
12802 else {
12803 continue;
12804 };
12805
12806 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12807 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12808 let has_matching_registration =
12809 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12810 entry.diagnostic.registration_id.as_ref()
12811 == Some(&cleared_registration_id)
12812 });
12813 if has_matching_registration {
12814 let abs_path = worktree.read(cx).absolutize(rel_path);
12815 affected_abs_paths.insert(abs_path);
12816 }
12817 }
12818 }
12819 }
12820
12821 if affected_abs_paths.is_empty() {
12822 return Ok(());
12823 }
12824
12825 // Send a fake diagnostic update which clears the state for the registration ID
12826 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12827 affected_abs_paths
12828 .into_iter()
12829 .map(|abs_path| DocumentDiagnosticsUpdate {
12830 diagnostics: DocumentDiagnostics {
12831 diagnostics: Vec::new(),
12832 document_abs_path: abs_path,
12833 version: None,
12834 },
12835 result_id: None,
12836 registration_id: Some(cleared_registration_id.clone()),
12837 server_id,
12838 disk_based_sources: Cow::Borrowed(&[]),
12839 })
12840 .collect();
12841
12842 let merge_registration_id = cleared_registration_id.clone();
12843 self.merge_diagnostic_entries(
12844 clears,
12845 move |_, diagnostic, _| {
12846 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12847 diagnostic.registration_id != Some(merge_registration_id.clone())
12848 } else {
12849 true
12850 }
12851 },
12852 cx,
12853 )?;
12854
12855 Ok(())
12856 }
12857
12858 async fn deduplicate_range_based_lsp_requests<T>(
12859 lsp_store: &Entity<Self>,
12860 server_id: Option<LanguageServerId>,
12861 lsp_request_id: LspRequestId,
12862 proto_request: &T::ProtoRequest,
12863 range: Range<Anchor>,
12864 cx: &mut AsyncApp,
12865 ) -> Result<()>
12866 where
12867 T: LspCommand,
12868 T::ProtoRequest: proto::LspRequestMessage,
12869 {
12870 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12871 let version = deserialize_version(proto_request.buffer_version());
12872 let buffer = lsp_store.update(cx, |this, cx| {
12873 this.buffer_store.read(cx).get_existing(buffer_id)
12874 })?;
12875 buffer
12876 .update(cx, |buffer, _| buffer.wait_for_version(version))
12877 .await?;
12878 lsp_store.update(cx, |lsp_store, cx| {
12879 let buffer_snapshot = buffer.read(cx).snapshot();
12880 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12881 let chunks_queried_for = lsp_data
12882 .inlay_hints
12883 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12884 .collect::<Vec<_>>();
12885 match chunks_queried_for.as_slice() {
12886 &[chunk] => {
12887 let key = LspKey {
12888 request_type: TypeId::of::<T>(),
12889 server_queried: server_id,
12890 };
12891 let previous_request = lsp_data
12892 .chunk_lsp_requests
12893 .entry(key)
12894 .or_default()
12895 .insert(chunk, lsp_request_id);
12896 if let Some((previous_request, running_requests)) =
12897 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12898 {
12899 running_requests.remove(&previous_request);
12900 }
12901 }
12902 _ambiguous_chunks => {
12903 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12904 // there, a buffer version-based check will be performed and outdated requests discarded.
12905 }
12906 }
12907 anyhow::Ok(())
12908 })?;
12909
12910 Ok(())
12911 }
12912
12913 async fn query_lsp_locally<T>(
12914 lsp_store: Entity<Self>,
12915 for_server_id: Option<LanguageServerId>,
12916 sender_id: proto::PeerId,
12917 lsp_request_id: LspRequestId,
12918 proto_request: T::ProtoRequest,
12919 position: Option<Anchor>,
12920 cx: &mut AsyncApp,
12921 ) -> Result<()>
12922 where
12923 T: LspCommand + Clone,
12924 T::ProtoRequest: proto::LspRequestMessage,
12925 <T::ProtoRequest as proto::RequestMessage>::Response:
12926 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12927 {
12928 let (buffer_version, buffer) =
12929 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12930 let request =
12931 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12932 let key = LspKey {
12933 request_type: TypeId::of::<T>(),
12934 server_queried: for_server_id,
12935 };
12936 lsp_store.update(cx, |lsp_store, cx| {
12937 let request_task = match for_server_id {
12938 Some(server_id) => {
12939 let server_task = lsp_store.request_lsp(
12940 buffer.clone(),
12941 LanguageServerToQuery::Other(server_id),
12942 request.clone(),
12943 cx,
12944 );
12945 cx.background_spawn(async move {
12946 let mut responses = Vec::new();
12947 match server_task.await {
12948 Ok(response) => responses.push((server_id, response)),
12949 // rust-analyzer likes to error with this when its still loading up
12950 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12951 Err(e) => log::error!(
12952 "Error handling response for request {request:?}: {e:#}"
12953 ),
12954 }
12955 responses
12956 })
12957 }
12958 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12959 };
12960 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12961 if T::ProtoRequest::stop_previous_requests() {
12962 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12963 lsp_requests.clear();
12964 }
12965 }
12966 lsp_data.lsp_requests.entry(key).or_default().insert(
12967 lsp_request_id,
12968 cx.spawn(async move |lsp_store, cx| {
12969 let response = request_task.await;
12970 lsp_store
12971 .update(cx, |lsp_store, cx| {
12972 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12973 {
12974 let response = response
12975 .into_iter()
12976 .map(|(server_id, response)| {
12977 (
12978 server_id.to_proto(),
12979 T::response_to_proto(
12980 response,
12981 lsp_store,
12982 sender_id,
12983 &buffer_version,
12984 cx,
12985 )
12986 .into(),
12987 )
12988 })
12989 .collect::<HashMap<_, _>>();
12990 match client.send_lsp_response::<T::ProtoRequest>(
12991 project_id,
12992 lsp_request_id,
12993 response,
12994 ) {
12995 Ok(()) => {}
12996 Err(e) => {
12997 log::error!("Failed to send LSP response: {e:#}",)
12998 }
12999 }
13000 }
13001 })
13002 .ok();
13003 }),
13004 );
13005 });
13006 Ok(())
13007 }
13008
13009 async fn wait_for_buffer_version<T>(
13010 lsp_store: &Entity<Self>,
13011 proto_request: &T::ProtoRequest,
13012 cx: &mut AsyncApp,
13013 ) -> Result<(Global, Entity<Buffer>)>
13014 where
13015 T: LspCommand,
13016 T::ProtoRequest: proto::LspRequestMessage,
13017 {
13018 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13019 let version = deserialize_version(proto_request.buffer_version());
13020 let buffer = lsp_store.update(cx, |this, cx| {
13021 this.buffer_store.read(cx).get_existing(buffer_id)
13022 })?;
13023 buffer
13024 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13025 .await?;
13026 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13027 Ok((buffer_version, buffer))
13028 }
13029
13030 fn take_text_document_sync_options(
13031 capabilities: &mut lsp::ServerCapabilities,
13032 ) -> lsp::TextDocumentSyncOptions {
13033 match capabilities.text_document_sync.take() {
13034 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13035 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13036 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13037 sync_options.change = Some(sync_kind);
13038 sync_options
13039 }
13040 None => lsp::TextDocumentSyncOptions::default(),
13041 }
13042 }
13043
13044 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13045 self.downstream_client.clone()
13046 }
13047
13048 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13049 self.worktree_store.clone()
13050 }
13051
13052 /// Gets what's stored in the LSP data for the given buffer.
13053 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13054 self.lsp_data.get_mut(&buffer_id)
13055 }
13056
13057 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13058 /// new [`BufferLspData`] will be created to replace the previous state.
13059 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13060 let (buffer_id, buffer_version) =
13061 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13062 let lsp_data = self
13063 .lsp_data
13064 .entry(buffer_id)
13065 .or_insert_with(|| BufferLspData::new(buffer, cx));
13066 if buffer_version.changed_since(&lsp_data.buffer_version) {
13067 // To send delta requests for semantic tokens, the previous tokens
13068 // need to be kept between buffer changes.
13069 let semantic_tokens = lsp_data.semantic_tokens.take();
13070 *lsp_data = BufferLspData::new(buffer, cx);
13071 lsp_data.semantic_tokens = semantic_tokens;
13072 }
13073 lsp_data
13074 }
13075}
13076
13077// Registration with registerOptions as null, should fallback to true.
13078// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13079fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13080 reg: lsp::Registration,
13081) -> Result<OneOf<bool, T>> {
13082 Ok(match reg.register_options {
13083 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13084 None => OneOf::Left(true),
13085 })
13086}
13087
13088fn subscribe_to_binary_statuses(
13089 languages: &Arc<LanguageRegistry>,
13090 cx: &mut Context<'_, LspStore>,
13091) -> Task<()> {
13092 let mut server_statuses = languages.language_server_binary_statuses();
13093 cx.spawn(async move |lsp_store, cx| {
13094 while let Some((server_name, binary_status)) = server_statuses.next().await {
13095 if lsp_store
13096 .update(cx, |_, cx| {
13097 let mut message = None;
13098 let binary_status = match binary_status {
13099 BinaryStatus::None => proto::ServerBinaryStatus::None,
13100 BinaryStatus::CheckingForUpdate => {
13101 proto::ServerBinaryStatus::CheckingForUpdate
13102 }
13103 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13104 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13105 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13106 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13107 BinaryStatus::Failed { error } => {
13108 message = Some(error);
13109 proto::ServerBinaryStatus::Failed
13110 }
13111 };
13112 cx.emit(LspStoreEvent::LanguageServerUpdate {
13113 // Binary updates are about the binary that might not have any language server id at that point.
13114 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13115 language_server_id: LanguageServerId(0),
13116 name: Some(server_name),
13117 message: proto::update_language_server::Variant::StatusUpdate(
13118 proto::StatusUpdate {
13119 message,
13120 status: Some(proto::status_update::Status::Binary(
13121 binary_status as i32,
13122 )),
13123 },
13124 ),
13125 });
13126 })
13127 .is_err()
13128 {
13129 break;
13130 }
13131 }
13132 })
13133}
13134
13135fn lsp_workspace_diagnostics_refresh(
13136 registration_id: Option<String>,
13137 options: DiagnosticServerCapabilities,
13138 server: Arc<LanguageServer>,
13139 cx: &mut Context<'_, LspStore>,
13140) -> Option<WorkspaceRefreshTask> {
13141 let identifier = workspace_diagnostic_identifier(&options)?;
13142 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13143
13144 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13145 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13146 refresh_tx.try_send(()).ok();
13147
13148 let request_timeout = ProjectSettings::get_global(cx)
13149 .global_lsp_settings
13150 .get_request_timeout();
13151
13152 // 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.
13153 // This allows users to increase the duration if need be
13154 let timeout = if request_timeout != Duration::ZERO {
13155 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13156 } else {
13157 request_timeout
13158 };
13159
13160 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13161 let mut attempts = 0;
13162 let max_attempts = 50;
13163 let mut requests = 0;
13164
13165 loop {
13166 let Some(()) = refresh_rx.recv().await else {
13167 return;
13168 };
13169
13170 'request: loop {
13171 requests += 1;
13172 if attempts > max_attempts {
13173 log::error!(
13174 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13175 );
13176 return;
13177 }
13178 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13179 cx.background_executor()
13180 .timer(Duration::from_millis(backoff_millis))
13181 .await;
13182 attempts += 1;
13183
13184 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13185 lsp_store
13186 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13187 .into_iter()
13188 .filter_map(|(abs_path, result_id)| {
13189 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13190 Some(lsp::PreviousResultId {
13191 uri,
13192 value: result_id.to_string(),
13193 })
13194 })
13195 .collect()
13196 }) else {
13197 return;
13198 };
13199
13200 let token = if let Some(registration_id) = ®istration_id {
13201 format!(
13202 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13203 server.server_id(),
13204 )
13205 } else {
13206 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13207 };
13208
13209 progress_rx.try_recv().ok();
13210 let timer = server.request_timer(timeout).fuse();
13211 let progress = pin!(progress_rx.recv().fuse());
13212 let response_result = server
13213 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13214 lsp::WorkspaceDiagnosticParams {
13215 previous_result_ids,
13216 identifier: identifier.clone(),
13217 work_done_progress_params: Default::default(),
13218 partial_result_params: lsp::PartialResultParams {
13219 partial_result_token: Some(lsp::ProgressToken::String(token)),
13220 },
13221 },
13222 select(timer, progress).then(|either| match either {
13223 Either::Left((message, ..)) => ready(message).left_future(),
13224 Either::Right(..) => pending::<String>().right_future(),
13225 }),
13226 )
13227 .await;
13228
13229 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13230 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13231 match response_result {
13232 ConnectionResult::Timeout => {
13233 log::error!("Timeout during workspace diagnostics pull");
13234 continue 'request;
13235 }
13236 ConnectionResult::ConnectionReset => {
13237 log::error!("Server closed a workspace diagnostics pull request");
13238 continue 'request;
13239 }
13240 ConnectionResult::Result(Err(e)) => {
13241 log::error!("Error during workspace diagnostics pull: {e:#}");
13242 break 'request;
13243 }
13244 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13245 attempts = 0;
13246 if lsp_store
13247 .update(cx, |lsp_store, cx| {
13248 lsp_store.apply_workspace_diagnostic_report(
13249 server.server_id(),
13250 pulled_diagnostics,
13251 registration_id_shared.clone(),
13252 cx,
13253 )
13254 })
13255 .is_err()
13256 {
13257 return;
13258 }
13259 break 'request;
13260 }
13261 }
13262 }
13263 }
13264 });
13265
13266 Some(WorkspaceRefreshTask {
13267 refresh_tx,
13268 progress_tx,
13269 task: workspace_query_language_server,
13270 })
13271}
13272
13273fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13274 match &options {
13275 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13276 .identifier
13277 .as_deref()
13278 .map(SharedString::new),
13279 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13280 let diagnostic_options = ®istration_options.diagnostic_options;
13281 diagnostic_options
13282 .identifier
13283 .as_deref()
13284 .map(SharedString::new)
13285 }
13286 }
13287}
13288
13289fn workspace_diagnostic_identifier(
13290 options: &DiagnosticServerCapabilities,
13291) -> Option<Option<String>> {
13292 match &options {
13293 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13294 if !diagnostic_options.workspace_diagnostics {
13295 return None;
13296 }
13297 Some(diagnostic_options.identifier.clone())
13298 }
13299 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13300 let diagnostic_options = ®istration_options.diagnostic_options;
13301 if !diagnostic_options.workspace_diagnostics {
13302 return None;
13303 }
13304 Some(diagnostic_options.identifier.clone())
13305 }
13306 }
13307}
13308
13309fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13310 let CompletionSource::BufferWord {
13311 word_range,
13312 resolved,
13313 } = &mut completion.source
13314 else {
13315 return;
13316 };
13317 if *resolved {
13318 return;
13319 }
13320
13321 if completion.new_text
13322 != snapshot
13323 .text_for_range(word_range.clone())
13324 .collect::<String>()
13325 {
13326 return;
13327 }
13328
13329 let mut offset = 0;
13330 for chunk in snapshot.chunks(word_range.clone(), true) {
13331 let end_offset = offset + chunk.text.len();
13332 if let Some(highlight_id) = chunk.syntax_highlight_id {
13333 completion
13334 .label
13335 .runs
13336 .push((offset..end_offset, highlight_id));
13337 }
13338 offset = end_offset;
13339 }
13340 *resolved = true;
13341}
13342
13343impl EventEmitter<LspStoreEvent> for LspStore {}
13344
13345fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13346 hover
13347 .contents
13348 .retain(|hover_block| !hover_block.text.trim().is_empty());
13349 if hover.contents.is_empty() {
13350 None
13351 } else {
13352 Some(hover)
13353 }
13354}
13355
13356async fn populate_labels_for_completions(
13357 new_completions: Vec<CoreCompletion>,
13358 language: Option<Arc<Language>>,
13359 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13360) -> Vec<Completion> {
13361 let lsp_completions = new_completions
13362 .iter()
13363 .filter_map(|new_completion| {
13364 new_completion
13365 .source
13366 .lsp_completion(true)
13367 .map(|lsp_completion| lsp_completion.into_owned())
13368 })
13369 .collect::<Vec<_>>();
13370
13371 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13372 lsp_adapter
13373 .labels_for_completions(&lsp_completions, language)
13374 .await
13375 .log_err()
13376 .unwrap_or_default()
13377 } else {
13378 Vec::new()
13379 }
13380 .into_iter()
13381 .fuse();
13382
13383 let mut completions = Vec::new();
13384 for completion in new_completions {
13385 match completion.source.lsp_completion(true) {
13386 Some(lsp_completion) => {
13387 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13388
13389 let mut label = labels.next().flatten().unwrap_or_else(|| {
13390 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13391 });
13392 ensure_uniform_list_compatible_label(&mut label);
13393 completions.push(Completion {
13394 label,
13395 documentation,
13396 replace_range: completion.replace_range,
13397 new_text: completion.new_text,
13398 insert_text_mode: lsp_completion.insert_text_mode,
13399 source: completion.source,
13400 icon_path: None,
13401 confirm: None,
13402 match_start: None,
13403 snippet_deduplication_key: None,
13404 });
13405 }
13406 None => {
13407 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13408 ensure_uniform_list_compatible_label(&mut label);
13409 completions.push(Completion {
13410 label,
13411 documentation: None,
13412 replace_range: completion.replace_range,
13413 new_text: completion.new_text,
13414 source: completion.source,
13415 insert_text_mode: None,
13416 icon_path: None,
13417 confirm: None,
13418 match_start: None,
13419 snippet_deduplication_key: None,
13420 });
13421 }
13422 }
13423 }
13424 completions
13425}
13426
13427#[derive(Debug)]
13428pub enum LanguageServerToQuery {
13429 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13430 FirstCapable,
13431 /// Query a specific language server.
13432 Other(LanguageServerId),
13433}
13434
13435#[derive(Default)]
13436struct RenamePathsWatchedForServer {
13437 did_rename: Vec<RenameActionPredicate>,
13438 will_rename: Vec<RenameActionPredicate>,
13439}
13440
13441impl RenamePathsWatchedForServer {
13442 fn with_did_rename_patterns(
13443 mut self,
13444 did_rename: Option<&FileOperationRegistrationOptions>,
13445 ) -> Self {
13446 if let Some(did_rename) = did_rename {
13447 self.did_rename = did_rename
13448 .filters
13449 .iter()
13450 .filter_map(|filter| filter.try_into().log_err())
13451 .collect();
13452 }
13453 self
13454 }
13455 fn with_will_rename_patterns(
13456 mut self,
13457 will_rename: Option<&FileOperationRegistrationOptions>,
13458 ) -> Self {
13459 if let Some(will_rename) = will_rename {
13460 self.will_rename = will_rename
13461 .filters
13462 .iter()
13463 .filter_map(|filter| filter.try_into().log_err())
13464 .collect();
13465 }
13466 self
13467 }
13468
13469 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13470 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13471 }
13472 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13473 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13474 }
13475}
13476
13477impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13478 type Error = globset::Error;
13479 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13480 Ok(Self {
13481 kind: ops.pattern.matches.clone(),
13482 glob: GlobBuilder::new(&ops.pattern.glob)
13483 .case_insensitive(
13484 ops.pattern
13485 .options
13486 .as_ref()
13487 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13488 )
13489 .build()?
13490 .compile_matcher(),
13491 })
13492 }
13493}
13494struct RenameActionPredicate {
13495 glob: GlobMatcher,
13496 kind: Option<FileOperationPatternKind>,
13497}
13498
13499impl RenameActionPredicate {
13500 // Returns true if language server should be notified
13501 fn eval(&self, path: &str, is_dir: bool) -> bool {
13502 self.kind.as_ref().is_none_or(|kind| {
13503 let expected_kind = if is_dir {
13504 FileOperationPatternKind::Folder
13505 } else {
13506 FileOperationPatternKind::File
13507 };
13508 kind == &expected_kind
13509 }) && self.glob.is_match(path)
13510 }
13511}
13512
13513#[derive(Default)]
13514struct LanguageServerWatchedPaths {
13515 worktree_paths: HashMap<WorktreeId, GlobSet>,
13516 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13517}
13518
13519#[derive(Default)]
13520struct LanguageServerWatchedPathsBuilder {
13521 worktree_paths: HashMap<WorktreeId, GlobSet>,
13522 abs_paths: HashMap<Arc<Path>, GlobSet>,
13523}
13524
13525impl LanguageServerWatchedPathsBuilder {
13526 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13527 self.worktree_paths.insert(worktree_id, glob_set);
13528 }
13529 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13530 self.abs_paths.insert(path, glob_set);
13531 }
13532 fn build(
13533 self,
13534 fs: Arc<dyn Fs>,
13535 language_server_id: LanguageServerId,
13536 cx: &mut Context<LspStore>,
13537 ) -> LanguageServerWatchedPaths {
13538 let lsp_store = cx.weak_entity();
13539
13540 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13541 let abs_paths = self
13542 .abs_paths
13543 .into_iter()
13544 .map(|(abs_path, globset)| {
13545 let task = cx.spawn({
13546 let abs_path = abs_path.clone();
13547 let fs = fs.clone();
13548
13549 let lsp_store = lsp_store.clone();
13550 async move |_, cx| {
13551 maybe!(async move {
13552 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13553 while let Some(update) = push_updates.0.next().await {
13554 let action = lsp_store
13555 .update(cx, |this, _| {
13556 let Some(local) = this.as_local() else {
13557 return ControlFlow::Break(());
13558 };
13559 let Some(watcher) = local
13560 .language_server_watched_paths
13561 .get(&language_server_id)
13562 else {
13563 return ControlFlow::Break(());
13564 };
13565 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13566 "Watched abs path is not registered with a watcher",
13567 );
13568 let matching_entries = update
13569 .into_iter()
13570 .filter(|event| globs.is_match(&event.path))
13571 .collect::<Vec<_>>();
13572 this.lsp_notify_abs_paths_changed(
13573 language_server_id,
13574 matching_entries,
13575 );
13576 ControlFlow::Continue(())
13577 })
13578 .ok()?;
13579
13580 if action.is_break() {
13581 break;
13582 }
13583 }
13584 Some(())
13585 })
13586 .await;
13587 }
13588 });
13589 (abs_path, (globset, task))
13590 })
13591 .collect();
13592 LanguageServerWatchedPaths {
13593 worktree_paths: self.worktree_paths,
13594 abs_paths,
13595 }
13596 }
13597}
13598
13599struct LspBufferSnapshot {
13600 version: i32,
13601 snapshot: TextBufferSnapshot,
13602}
13603
13604/// A prompt requested by LSP server.
13605#[derive(Clone, Debug)]
13606pub struct LanguageServerPromptRequest {
13607 pub id: usize,
13608 pub level: PromptLevel,
13609 pub message: String,
13610 pub actions: Vec<MessageActionItem>,
13611 pub lsp_name: String,
13612 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13613}
13614
13615impl LanguageServerPromptRequest {
13616 pub fn new(
13617 level: PromptLevel,
13618 message: String,
13619 actions: Vec<MessageActionItem>,
13620 lsp_name: String,
13621 response_channel: smol::channel::Sender<MessageActionItem>,
13622 ) -> Self {
13623 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13624 LanguageServerPromptRequest {
13625 id,
13626 level,
13627 message,
13628 actions,
13629 lsp_name,
13630 response_channel,
13631 }
13632 }
13633 pub async fn respond(self, index: usize) -> Option<()> {
13634 if let Some(response) = self.actions.into_iter().nth(index) {
13635 self.response_channel.send(response).await.ok()
13636 } else {
13637 None
13638 }
13639 }
13640
13641 #[cfg(any(test, feature = "test-support"))]
13642 pub fn test(
13643 level: PromptLevel,
13644 message: String,
13645 actions: Vec<MessageActionItem>,
13646 lsp_name: String,
13647 ) -> Self {
13648 let (tx, _rx) = smol::channel::unbounded();
13649 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13650 }
13651}
13652impl PartialEq for LanguageServerPromptRequest {
13653 fn eq(&self, other: &Self) -> bool {
13654 self.message == other.message && self.actions == other.actions
13655 }
13656}
13657
13658#[derive(Clone, Debug, PartialEq)]
13659pub enum LanguageServerLogType {
13660 Log(MessageType),
13661 Trace { verbose_info: Option<String> },
13662 Rpc { received: bool },
13663}
13664
13665impl LanguageServerLogType {
13666 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13667 match self {
13668 Self::Log(log_type) => {
13669 use proto::log_message::LogLevel;
13670 let level = match *log_type {
13671 MessageType::ERROR => LogLevel::Error,
13672 MessageType::WARNING => LogLevel::Warning,
13673 MessageType::INFO => LogLevel::Info,
13674 MessageType::LOG => LogLevel::Log,
13675 other => {
13676 log::warn!("Unknown lsp log message type: {other:?}");
13677 LogLevel::Log
13678 }
13679 };
13680 proto::language_server_log::LogType::Log(proto::LogMessage {
13681 level: level as i32,
13682 })
13683 }
13684 Self::Trace { verbose_info } => {
13685 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13686 verbose_info: verbose_info.to_owned(),
13687 })
13688 }
13689 Self::Rpc { received } => {
13690 let kind = if *received {
13691 proto::rpc_message::Kind::Received
13692 } else {
13693 proto::rpc_message::Kind::Sent
13694 };
13695 let kind = kind as i32;
13696 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13697 }
13698 }
13699 }
13700
13701 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13702 use proto::log_message::LogLevel;
13703 use proto::rpc_message;
13704 match log_type {
13705 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13706 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13707 LogLevel::Error => MessageType::ERROR,
13708 LogLevel::Warning => MessageType::WARNING,
13709 LogLevel::Info => MessageType::INFO,
13710 LogLevel::Log => MessageType::LOG,
13711 },
13712 ),
13713 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13714 verbose_info: trace_message.verbose_info,
13715 },
13716 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13717 received: match rpc_message::Kind::from_i32(message.kind)
13718 .unwrap_or(rpc_message::Kind::Received)
13719 {
13720 rpc_message::Kind::Received => true,
13721 rpc_message::Kind::Sent => false,
13722 },
13723 },
13724 }
13725 }
13726}
13727
13728pub struct WorkspaceRefreshTask {
13729 refresh_tx: mpsc::Sender<()>,
13730 progress_tx: mpsc::Sender<()>,
13731 #[allow(dead_code)]
13732 task: Task<()>,
13733}
13734
13735pub enum LanguageServerState {
13736 Starting {
13737 startup: Task<Option<Arc<LanguageServer>>>,
13738 /// List of language servers that will be added to the workspace once it's initialization completes.
13739 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13740 },
13741
13742 Running {
13743 adapter: Arc<CachedLspAdapter>,
13744 server: Arc<LanguageServer>,
13745 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13746 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13747 },
13748}
13749
13750impl LanguageServerState {
13751 fn add_workspace_folder(&self, uri: Uri) {
13752 match self {
13753 LanguageServerState::Starting {
13754 pending_workspace_folders,
13755 ..
13756 } => {
13757 pending_workspace_folders.lock().insert(uri);
13758 }
13759 LanguageServerState::Running { server, .. } => {
13760 server.add_workspace_folder(uri);
13761 }
13762 }
13763 }
13764 fn _remove_workspace_folder(&self, uri: Uri) {
13765 match self {
13766 LanguageServerState::Starting {
13767 pending_workspace_folders,
13768 ..
13769 } => {
13770 pending_workspace_folders.lock().remove(&uri);
13771 }
13772 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13773 }
13774 }
13775}
13776
13777impl std::fmt::Debug for LanguageServerState {
13778 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13779 match self {
13780 LanguageServerState::Starting { .. } => {
13781 f.debug_struct("LanguageServerState::Starting").finish()
13782 }
13783 LanguageServerState::Running { .. } => {
13784 f.debug_struct("LanguageServerState::Running").finish()
13785 }
13786 }
13787 }
13788}
13789
13790#[derive(Clone, Debug, Serialize)]
13791pub struct LanguageServerProgress {
13792 pub is_disk_based_diagnostics_progress: bool,
13793 pub is_cancellable: bool,
13794 pub title: Option<String>,
13795 pub message: Option<String>,
13796 pub percentage: Option<usize>,
13797 #[serde(skip_serializing)]
13798 pub last_update_at: Instant,
13799}
13800
13801#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13802pub struct DiagnosticSummary {
13803 pub error_count: usize,
13804 pub warning_count: usize,
13805}
13806
13807impl DiagnosticSummary {
13808 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13809 let mut this = Self {
13810 error_count: 0,
13811 warning_count: 0,
13812 };
13813
13814 for entry in diagnostics {
13815 if entry.diagnostic.is_primary {
13816 match entry.diagnostic.severity {
13817 DiagnosticSeverity::ERROR => this.error_count += 1,
13818 DiagnosticSeverity::WARNING => this.warning_count += 1,
13819 _ => {}
13820 }
13821 }
13822 }
13823
13824 this
13825 }
13826
13827 pub fn is_empty(&self) -> bool {
13828 self.error_count == 0 && self.warning_count == 0
13829 }
13830
13831 pub fn to_proto(
13832 self,
13833 language_server_id: LanguageServerId,
13834 path: &RelPath,
13835 ) -> proto::DiagnosticSummary {
13836 proto::DiagnosticSummary {
13837 path: path.to_proto(),
13838 language_server_id: language_server_id.0 as u64,
13839 error_count: self.error_count as u32,
13840 warning_count: self.warning_count as u32,
13841 }
13842 }
13843}
13844
13845#[derive(Clone, Debug)]
13846pub enum CompletionDocumentation {
13847 /// There is no documentation for this completion.
13848 Undocumented,
13849 /// A single line of documentation.
13850 SingleLine(SharedString),
13851 /// Multiple lines of plain text documentation.
13852 MultiLinePlainText(SharedString),
13853 /// Markdown documentation.
13854 MultiLineMarkdown(SharedString),
13855 /// Both single line and multiple lines of plain text documentation.
13856 SingleLineAndMultiLinePlainText {
13857 single_line: SharedString,
13858 plain_text: Option<SharedString>,
13859 },
13860}
13861
13862impl CompletionDocumentation {
13863 #[cfg(any(test, feature = "test-support"))]
13864 pub fn text(&self) -> SharedString {
13865 match self {
13866 CompletionDocumentation::Undocumented => "".into(),
13867 CompletionDocumentation::SingleLine(s) => s.clone(),
13868 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13869 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13870 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13871 single_line.clone()
13872 }
13873 }
13874 }
13875}
13876
13877impl From<lsp::Documentation> for CompletionDocumentation {
13878 fn from(docs: lsp::Documentation) -> Self {
13879 match docs {
13880 lsp::Documentation::String(text) => {
13881 if text.lines().count() <= 1 {
13882 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13883 } else {
13884 CompletionDocumentation::MultiLinePlainText(text.into())
13885 }
13886 }
13887
13888 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13889 lsp::MarkupKind::PlainText => {
13890 if value.lines().count() <= 1 {
13891 CompletionDocumentation::SingleLine(value.into())
13892 } else {
13893 CompletionDocumentation::MultiLinePlainText(value.into())
13894 }
13895 }
13896
13897 lsp::MarkupKind::Markdown => {
13898 CompletionDocumentation::MultiLineMarkdown(value.into())
13899 }
13900 },
13901 }
13902 }
13903}
13904
13905pub enum ResolvedHint {
13906 Resolved(InlayHint),
13907 Resolving(Shared<Task<()>>),
13908}
13909
13910pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13911 glob.components()
13912 .take_while(|component| match component {
13913 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13914 _ => true,
13915 })
13916 .collect()
13917}
13918
13919pub struct SshLspAdapter {
13920 name: LanguageServerName,
13921 binary: LanguageServerBinary,
13922 initialization_options: Option<String>,
13923 code_action_kinds: Option<Vec<CodeActionKind>>,
13924}
13925
13926impl SshLspAdapter {
13927 pub fn new(
13928 name: LanguageServerName,
13929 binary: LanguageServerBinary,
13930 initialization_options: Option<String>,
13931 code_action_kinds: Option<String>,
13932 ) -> Self {
13933 Self {
13934 name,
13935 binary,
13936 initialization_options,
13937 code_action_kinds: code_action_kinds
13938 .as_ref()
13939 .and_then(|c| serde_json::from_str(c).ok()),
13940 }
13941 }
13942}
13943
13944impl LspInstaller for SshLspAdapter {
13945 type BinaryVersion = ();
13946 async fn check_if_user_installed(
13947 &self,
13948 _: &dyn LspAdapterDelegate,
13949 _: Option<Toolchain>,
13950 _: &AsyncApp,
13951 ) -> Option<LanguageServerBinary> {
13952 Some(self.binary.clone())
13953 }
13954
13955 async fn cached_server_binary(
13956 &self,
13957 _: PathBuf,
13958 _: &dyn LspAdapterDelegate,
13959 ) -> Option<LanguageServerBinary> {
13960 None
13961 }
13962
13963 async fn fetch_latest_server_version(
13964 &self,
13965 _: &dyn LspAdapterDelegate,
13966 _: bool,
13967 _: &mut AsyncApp,
13968 ) -> Result<()> {
13969 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13970 }
13971
13972 async fn fetch_server_binary(
13973 &self,
13974 _: (),
13975 _: PathBuf,
13976 _: &dyn LspAdapterDelegate,
13977 ) -> Result<LanguageServerBinary> {
13978 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13979 }
13980}
13981
13982#[async_trait(?Send)]
13983impl LspAdapter for SshLspAdapter {
13984 fn name(&self) -> LanguageServerName {
13985 self.name.clone()
13986 }
13987
13988 async fn initialization_options(
13989 self: Arc<Self>,
13990 _: &Arc<dyn LspAdapterDelegate>,
13991 _: &mut AsyncApp,
13992 ) -> Result<Option<serde_json::Value>> {
13993 let Some(options) = &self.initialization_options else {
13994 return Ok(None);
13995 };
13996 let result = serde_json::from_str(options)?;
13997 Ok(result)
13998 }
13999
14000 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14001 self.code_action_kinds.clone()
14002 }
14003}
14004
14005pub fn language_server_settings<'a>(
14006 delegate: &'a dyn LspAdapterDelegate,
14007 language: &LanguageServerName,
14008 cx: &'a App,
14009) -> Option<&'a LspSettings> {
14010 language_server_settings_for(
14011 SettingsLocation {
14012 worktree_id: delegate.worktree_id(),
14013 path: RelPath::empty(),
14014 },
14015 language,
14016 cx,
14017 )
14018}
14019
14020pub fn language_server_settings_for<'a>(
14021 location: SettingsLocation<'a>,
14022 language: &LanguageServerName,
14023 cx: &'a App,
14024) -> Option<&'a LspSettings> {
14025 ProjectSettings::get(Some(location), cx).lsp.get(language)
14026}
14027
14028pub struct LocalLspAdapterDelegate {
14029 lsp_store: WeakEntity<LspStore>,
14030 worktree: worktree::Snapshot,
14031 fs: Arc<dyn Fs>,
14032 http_client: Arc<dyn HttpClient>,
14033 language_registry: Arc<LanguageRegistry>,
14034 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14035}
14036
14037impl LocalLspAdapterDelegate {
14038 pub fn new(
14039 language_registry: Arc<LanguageRegistry>,
14040 environment: &Entity<ProjectEnvironment>,
14041 lsp_store: WeakEntity<LspStore>,
14042 worktree: &Entity<Worktree>,
14043 http_client: Arc<dyn HttpClient>,
14044 fs: Arc<dyn Fs>,
14045 cx: &mut App,
14046 ) -> Arc<Self> {
14047 let load_shell_env_task =
14048 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14049
14050 Arc::new(Self {
14051 lsp_store,
14052 worktree: worktree.read(cx).snapshot(),
14053 fs,
14054 http_client,
14055 language_registry,
14056 load_shell_env_task,
14057 })
14058 }
14059
14060 pub fn from_local_lsp(
14061 local: &LocalLspStore,
14062 worktree: &Entity<Worktree>,
14063 cx: &mut App,
14064 ) -> Arc<Self> {
14065 Self::new(
14066 local.languages.clone(),
14067 &local.environment,
14068 local.weak.clone(),
14069 worktree,
14070 local.http_client.clone(),
14071 local.fs.clone(),
14072 cx,
14073 )
14074 }
14075}
14076
14077#[async_trait]
14078impl LspAdapterDelegate for LocalLspAdapterDelegate {
14079 fn show_notification(&self, message: &str, cx: &mut App) {
14080 self.lsp_store
14081 .update(cx, |_, cx| {
14082 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14083 })
14084 .ok();
14085 }
14086
14087 fn http_client(&self) -> Arc<dyn HttpClient> {
14088 self.http_client.clone()
14089 }
14090
14091 fn worktree_id(&self) -> WorktreeId {
14092 self.worktree.id()
14093 }
14094
14095 fn worktree_root_path(&self) -> &Path {
14096 self.worktree.abs_path().as_ref()
14097 }
14098
14099 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14100 self.worktree.resolve_relative_path(path)
14101 }
14102
14103 async fn shell_env(&self) -> HashMap<String, String> {
14104 let task = self.load_shell_env_task.clone();
14105 task.await.unwrap_or_default()
14106 }
14107
14108 async fn npm_package_installed_version(
14109 &self,
14110 package_name: &str,
14111 ) -> Result<Option<(PathBuf, Version)>> {
14112 let local_package_directory = self.worktree_root_path();
14113 let node_modules_directory = local_package_directory.join("node_modules");
14114
14115 if let Some(version) =
14116 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14117 {
14118 return Ok(Some((node_modules_directory, version)));
14119 }
14120 let Some(npm) = self.which("npm".as_ref()).await else {
14121 log::warn!(
14122 "Failed to find npm executable for {:?}",
14123 local_package_directory
14124 );
14125 return Ok(None);
14126 };
14127
14128 let env = self.shell_env().await;
14129 let output = util::command::new_command(&npm)
14130 .args(["root", "-g"])
14131 .envs(env)
14132 .current_dir(local_package_directory)
14133 .output()
14134 .await?;
14135 let global_node_modules =
14136 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14137
14138 if let Some(version) =
14139 read_package_installed_version(global_node_modules.clone(), package_name).await?
14140 {
14141 return Ok(Some((global_node_modules, version)));
14142 }
14143 return Ok(None);
14144 }
14145
14146 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14147 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14148 if self.fs.is_file(&worktree_abs_path).await {
14149 worktree_abs_path.pop();
14150 }
14151
14152 let env = self.shell_env().await;
14153
14154 let shell_path = env.get("PATH").cloned();
14155
14156 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14157 }
14158
14159 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14160 let mut working_dir = self.worktree_root_path().to_path_buf();
14161 if self.fs.is_file(&working_dir).await {
14162 working_dir.pop();
14163 }
14164 let output = util::command::new_command(&command.path)
14165 .args(command.arguments)
14166 .envs(command.env.clone().unwrap_or_default())
14167 .current_dir(working_dir)
14168 .output()
14169 .await?;
14170
14171 anyhow::ensure!(
14172 output.status.success(),
14173 "{}, stdout: {:?}, stderr: {:?}",
14174 output.status,
14175 String::from_utf8_lossy(&output.stdout),
14176 String::from_utf8_lossy(&output.stderr)
14177 );
14178 Ok(())
14179 }
14180
14181 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14182 self.language_registry
14183 .update_lsp_binary_status(server_name, status);
14184 }
14185
14186 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14187 self.language_registry
14188 .all_lsp_adapters()
14189 .into_iter()
14190 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14191 .collect()
14192 }
14193
14194 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14195 let dir = self.language_registry.language_server_download_dir(name)?;
14196
14197 if !dir.exists() {
14198 smol::fs::create_dir_all(&dir)
14199 .await
14200 .context("failed to create container directory")
14201 .log_err()?;
14202 }
14203
14204 Some(dir)
14205 }
14206
14207 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14208 let entry = self
14209 .worktree
14210 .entry_for_path(path)
14211 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14212 let abs_path = self.worktree.absolutize(&entry.path);
14213 self.fs.load(&abs_path).await
14214 }
14215}
14216
14217async fn populate_labels_for_symbols(
14218 symbols: Vec<CoreSymbol>,
14219 language_registry: &Arc<LanguageRegistry>,
14220 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14221 output: &mut Vec<Symbol>,
14222) {
14223 #[allow(clippy::mutable_key_type)]
14224 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14225
14226 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14227 for symbol in symbols {
14228 let Some(file_name) = symbol.path.file_name() else {
14229 continue;
14230 };
14231 let language = language_registry
14232 .load_language_for_file_path(Path::new(file_name))
14233 .await
14234 .ok()
14235 .or_else(|| {
14236 unknown_paths.insert(file_name.into());
14237 None
14238 });
14239 symbols_by_language
14240 .entry(language)
14241 .or_default()
14242 .push(symbol);
14243 }
14244
14245 for unknown_path in unknown_paths {
14246 log::info!("no language found for symbol in file {unknown_path:?}");
14247 }
14248
14249 let mut label_params = Vec::new();
14250 for (language, mut symbols) in symbols_by_language {
14251 label_params.clear();
14252 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14253 name: mem::take(&mut symbol.name),
14254 kind: symbol.kind,
14255 container_name: symbol.container_name.take(),
14256 }));
14257
14258 let mut labels = Vec::new();
14259 if let Some(language) = language {
14260 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14261 language_registry
14262 .lsp_adapters(&language.name())
14263 .first()
14264 .cloned()
14265 });
14266 if let Some(lsp_adapter) = lsp_adapter {
14267 labels = lsp_adapter
14268 .labels_for_symbols(&label_params, &language)
14269 .await
14270 .log_err()
14271 .unwrap_or_default();
14272 }
14273 }
14274
14275 for (
14276 (
14277 symbol,
14278 language::Symbol {
14279 name,
14280 container_name,
14281 ..
14282 },
14283 ),
14284 label,
14285 ) in symbols
14286 .into_iter()
14287 .zip(label_params.drain(..))
14288 .zip(labels.into_iter().chain(iter::repeat(None)))
14289 {
14290 output.push(Symbol {
14291 language_server_name: symbol.language_server_name,
14292 source_worktree_id: symbol.source_worktree_id,
14293 source_language_server_id: symbol.source_language_server_id,
14294 path: symbol.path,
14295 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14296 name,
14297 kind: symbol.kind,
14298 range: symbol.range,
14299 container_name,
14300 });
14301 }
14302 }
14303}
14304
14305pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14306 text.lines()
14307 .map(|line| line.trim())
14308 .filter(|line| !line.is_empty())
14309 .join(separator)
14310}
14311
14312fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14313 match server.capabilities().text_document_sync.as_ref()? {
14314 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14315 // Server wants didSave but didn't specify includeText.
14316 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14317 // Server doesn't want didSave at all.
14318 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14319 // Server provided SaveOptions.
14320 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14321 Some(save_options.include_text.unwrap_or(false))
14322 }
14323 },
14324 // We do not have any save info. Kind affects didChange only.
14325 lsp::TextDocumentSyncCapability::Kind(_) => None,
14326 }
14327}
14328
14329/// Completion items are displayed in a `UniformList`.
14330/// Usually, those items are single-line strings, but in LSP responses,
14331/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14332/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14333/// 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,
14334/// breaking the completions menu presentation.
14335///
14336/// 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.
14337pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14338 let mut new_text = String::with_capacity(label.text.len());
14339 let mut offset_map = vec![0; label.text.len() + 1];
14340 let mut last_char_was_space = false;
14341 let mut new_idx = 0;
14342 let chars = label.text.char_indices().fuse();
14343 let mut newlines_removed = false;
14344
14345 for (idx, c) in chars {
14346 offset_map[idx] = new_idx;
14347
14348 match c {
14349 '\n' if last_char_was_space => {
14350 newlines_removed = true;
14351 }
14352 '\t' | ' ' if last_char_was_space => {}
14353 '\n' if !last_char_was_space => {
14354 new_text.push(' ');
14355 new_idx += 1;
14356 last_char_was_space = true;
14357 newlines_removed = true;
14358 }
14359 ' ' | '\t' => {
14360 new_text.push(' ');
14361 new_idx += 1;
14362 last_char_was_space = true;
14363 }
14364 _ => {
14365 new_text.push(c);
14366 new_idx += c.len_utf8();
14367 last_char_was_space = false;
14368 }
14369 }
14370 }
14371 offset_map[label.text.len()] = new_idx;
14372
14373 // Only modify the label if newlines were removed.
14374 if !newlines_removed {
14375 return;
14376 }
14377
14378 let last_index = new_idx;
14379 let mut run_ranges_errors = Vec::new();
14380 label.runs.retain_mut(|(range, _)| {
14381 match offset_map.get(range.start) {
14382 Some(&start) => range.start = start,
14383 None => {
14384 run_ranges_errors.push(range.clone());
14385 return false;
14386 }
14387 }
14388
14389 match offset_map.get(range.end) {
14390 Some(&end) => range.end = end,
14391 None => {
14392 run_ranges_errors.push(range.clone());
14393 range.end = last_index;
14394 }
14395 }
14396 true
14397 });
14398 if !run_ranges_errors.is_empty() {
14399 log::error!(
14400 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14401 label.text
14402 );
14403 }
14404
14405 let mut wrong_filter_range = None;
14406 if label.filter_range == (0..label.text.len()) {
14407 label.filter_range = 0..new_text.len();
14408 } else {
14409 let mut original_filter_range = Some(label.filter_range.clone());
14410 match offset_map.get(label.filter_range.start) {
14411 Some(&start) => label.filter_range.start = start,
14412 None => {
14413 wrong_filter_range = original_filter_range.take();
14414 label.filter_range.start = last_index;
14415 }
14416 }
14417
14418 match offset_map.get(label.filter_range.end) {
14419 Some(&end) => label.filter_range.end = end,
14420 None => {
14421 wrong_filter_range = original_filter_range.take();
14422 label.filter_range.end = last_index;
14423 }
14424 }
14425 }
14426 if let Some(wrong_filter_range) = wrong_filter_range {
14427 log::error!(
14428 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14429 label.text
14430 );
14431 }
14432
14433 label.text = new_text;
14434}