1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
77 Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 language_settings,
81 },
82 point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153pub use semantic_tokens::{
154 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
155};
156
157pub use worktree::{
158 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
159 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
160};
161
162const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
163pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
164const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
165const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
166static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
167
168#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
169pub enum ProgressToken {
170 Number(i32),
171 String(SharedString),
172}
173
174impl std::fmt::Display for ProgressToken {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Number(number) => write!(f, "{number}"),
178 Self::String(string) => write!(f, "{string}"),
179 }
180 }
181}
182
183impl ProgressToken {
184 fn from_lsp(value: lsp::NumberOrString) -> Self {
185 match value {
186 lsp::NumberOrString::Number(number) => Self::Number(number),
187 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
188 }
189 }
190
191 fn to_lsp(&self) -> lsp::NumberOrString {
192 match self {
193 Self::Number(number) => lsp::NumberOrString::Number(*number),
194 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
195 }
196 }
197
198 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
199 Some(match value.value? {
200 proto::progress_token::Value::Number(number) => Self::Number(number),
201 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
202 })
203 }
204
205 fn to_proto(&self) -> proto::ProgressToken {
206 proto::ProgressToken {
207 value: Some(match self {
208 Self::Number(number) => proto::progress_token::Value::Number(*number),
209 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
210 }),
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum FormatTrigger {
217 Save,
218 Manual,
219}
220
221pub enum LspFormatTarget {
222 Buffers,
223 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
228
229struct OpenLspBuffer(Entity<Buffer>);
230
231impl FormatTrigger {
232 fn from_proto(value: i32) -> FormatTrigger {
233 match value {
234 0 => FormatTrigger::Save,
235 1 => FormatTrigger::Manual,
236 _ => FormatTrigger::Save,
237 }
238 }
239}
240
241#[derive(Clone)]
242struct UnifiedLanguageServer {
243 id: LanguageServerId,
244 project_roots: HashSet<Arc<RelPath>>,
245}
246
247/// Settings that affect language server identity.
248///
249/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
250/// updated via `workspace/didChangeConfiguration` without restarting the server.
251#[derive(Clone, Debug, Hash, PartialEq, Eq)]
252struct LanguageServerSeedSettings {
253 binary: Option<BinarySettings>,
254 initialization_options: Option<serde_json::Value>,
255}
256
257#[derive(Clone, Debug, Hash, PartialEq, Eq)]
258struct LanguageServerSeed {
259 worktree_id: WorktreeId,
260 name: LanguageServerName,
261 toolchain: Option<Toolchain>,
262 settings: LanguageServerSeedSettings,
263}
264
265#[derive(Debug)]
266pub struct DocumentDiagnosticsUpdate<'a, D> {
267 pub diagnostics: D,
268 pub result_id: Option<SharedString>,
269 pub registration_id: Option<SharedString>,
270 pub server_id: LanguageServerId,
271 pub disk_based_sources: Cow<'a, [String]>,
272}
273
274pub struct DocumentDiagnostics {
275 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 document_abs_path: PathBuf,
277 version: Option<i32>,
278}
279
280#[derive(Default, Debug)]
281struct DynamicRegistrations {
282 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
283 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
284}
285
286pub struct LocalLspStore {
287 weak: WeakEntity<LspStore>,
288 pub worktree_store: Entity<WorktreeStore>,
289 toolchain_store: Entity<LocalToolchainStore>,
290 http_client: Arc<dyn HttpClient>,
291 environment: Entity<ProjectEnvironment>,
292 fs: Arc<dyn Fs>,
293 languages: Arc<LanguageRegistry>,
294 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
295 yarn: Entity<YarnPathStore>,
296 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
297 buffers_being_formatted: HashSet<BufferId>,
298 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
299 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
300 watched_manifest_filenames: HashSet<ManifestName>,
301 language_server_paths_watched_for_rename:
302 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
303 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
304 supplementary_language_servers:
305 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
306 prettier_store: Entity<PrettierStore>,
307 next_diagnostic_group_id: usize,
308 diagnostics: HashMap<
309 WorktreeId,
310 HashMap<
311 Arc<RelPath>,
312 Vec<(
313 LanguageServerId,
314 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
315 )>,
316 >,
317 >,
318 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
319 _subscription: gpui::Subscription,
320 lsp_tree: LanguageServerTree,
321 registered_buffers: HashMap<BufferId, usize>,
322 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
323 buffer_pull_diagnostics_result_ids: HashMap<
324 LanguageServerId,
325 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
326 >,
327 workspace_pull_diagnostics_result_ids: HashMap<
328 LanguageServerId,
329 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
330 >,
331 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
332
333 buffers_to_refresh_hash_set: HashSet<BufferId>,
334 buffers_to_refresh_queue: VecDeque<BufferId>,
335 _background_diagnostics_worker: Shared<Task<()>>,
336}
337
338impl LocalLspStore {
339 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
340 pub fn running_language_server_for_id(
341 &self,
342 id: LanguageServerId,
343 ) -> Option<&Arc<LanguageServer>> {
344 let language_server_state = self.language_servers.get(&id)?;
345
346 match language_server_state {
347 LanguageServerState::Running { server, .. } => Some(server),
348 LanguageServerState::Starting { .. } => None,
349 }
350 }
351
352 fn get_or_insert_language_server(
353 &mut self,
354 worktree_handle: &Entity<Worktree>,
355 delegate: Arc<LocalLspAdapterDelegate>,
356 disposition: &Arc<LaunchDisposition>,
357 language_name: &LanguageName,
358 cx: &mut App,
359 ) -> LanguageServerId {
360 let key = LanguageServerSeed {
361 worktree_id: worktree_handle.read(cx).id(),
362 name: disposition.server_name.clone(),
363 settings: LanguageServerSeedSettings {
364 binary: disposition.settings.binary.clone(),
365 initialization_options: disposition.settings.initialization_options.clone(),
366 },
367 toolchain: disposition.toolchain.clone(),
368 };
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 state.id
372 } else {
373 let adapter = self
374 .languages
375 .lsp_adapters(language_name)
376 .into_iter()
377 .find(|adapter| adapter.name() == disposition.server_name)
378 .expect("To find LSP adapter");
379 let new_language_server_id = self.start_language_server(
380 worktree_handle,
381 delegate,
382 adapter,
383 disposition.settings.clone(),
384 key.clone(),
385 language_name.clone(),
386 cx,
387 );
388 if let Some(state) = self.language_server_ids.get_mut(&key) {
389 state.project_roots.insert(disposition.path.path.clone());
390 } else {
391 debug_assert!(
392 false,
393 "Expected `start_language_server` to ensure that `key` exists in a map"
394 );
395 }
396 new_language_server_id
397 }
398 }
399
400 fn start_language_server(
401 &mut self,
402 worktree_handle: &Entity<Worktree>,
403 delegate: Arc<LocalLspAdapterDelegate>,
404 adapter: Arc<CachedLspAdapter>,
405 settings: Arc<LspSettings>,
406 key: LanguageServerSeed,
407 language_name: LanguageName,
408 cx: &mut App,
409 ) -> LanguageServerId {
410 let worktree = worktree_handle.read(cx);
411
412 let worktree_id = worktree.id();
413 let worktree_abs_path = worktree.abs_path();
414 let toolchain = key.toolchain.clone();
415 let override_options = settings.initialization_options.clone();
416
417 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
418
419 let server_id = self.languages.next_language_server_id();
420 log::trace!(
421 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
422 adapter.name.0
423 );
424
425 let wait_until_worktree_trust =
426 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
427 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
428 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
429 });
430 if can_trust {
431 self.restricted_worktrees_tasks.remove(&worktree_id);
432 None
433 } else {
434 match self.restricted_worktrees_tasks.entry(worktree_id) {
435 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
436 hash_map::Entry::Vacant(v) => {
437 let (mut tx, rx) = watch::channel::<bool>();
438 let lsp_store = self.weak.clone();
439 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
440 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
441 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
442 tx.blocking_send(true).ok();
443 lsp_store
444 .update(cx, |lsp_store, _| {
445 if let Some(local_lsp_store) =
446 lsp_store.as_local_mut()
447 {
448 local_lsp_store
449 .restricted_worktrees_tasks
450 .remove(&worktree_id);
451 }
452 })
453 .ok();
454 }
455 }
456 });
457 v.insert((subscription, rx.clone()));
458 Some(rx)
459 }
460 }
461 }
462 });
463 let update_binary_status = wait_until_worktree_trust.is_none();
464
465 let binary = self.get_language_server_binary(
466 worktree_abs_path.clone(),
467 adapter.clone(),
468 settings,
469 toolchain.clone(),
470 delegate.clone(),
471 true,
472 wait_until_worktree_trust,
473 cx,
474 );
475 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
476
477 let pending_server = cx.spawn({
478 let adapter = adapter.clone();
479 let server_name = adapter.name.clone();
480 let stderr_capture = stderr_capture.clone();
481 #[cfg(any(test, feature = "test-support"))]
482 let lsp_store = self.weak.clone();
483 let pending_workspace_folders = pending_workspace_folders.clone();
484 async move |cx| {
485 let binary = binary.await?;
486 #[cfg(any(test, feature = "test-support"))]
487 if let Some(server) = lsp_store
488 .update(&mut cx.clone(), |this, cx| {
489 this.languages.create_fake_language_server(
490 server_id,
491 &server_name,
492 binary.clone(),
493 &mut cx.to_async(),
494 )
495 })
496 .ok()
497 .flatten()
498 {
499 return Ok(server);
500 }
501
502 let code_action_kinds = adapter.code_action_kinds();
503 lsp::LanguageServer::new(
504 stderr_capture,
505 server_id,
506 server_name,
507 binary,
508 &worktree_abs_path,
509 code_action_kinds,
510 Some(pending_workspace_folders),
511 cx,
512 )
513 }
514 });
515
516 let startup = {
517 let server_name = adapter.name.0.clone();
518 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
519 let key = key.clone();
520 let adapter = adapter.clone();
521 let lsp_store = self.weak.clone();
522 let pending_workspace_folders = pending_workspace_folders.clone();
523 let pull_diagnostics = ProjectSettings::get_global(cx)
524 .diagnostics
525 .lsp_pull_diagnostics
526 .enabled;
527 let settings_location = SettingsLocation {
528 worktree_id,
529 path: RelPath::empty(),
530 };
531 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
532 .language(Some(settings_location), Some(&language_name), cx)
533 .semantic_tokens
534 .use_tree_sitter();
535 cx.spawn(async move |cx| {
536 let result = async {
537 let language_server = pending_server.await?;
538
539 let workspace_config = Self::workspace_configuration_for_adapter(
540 adapter.adapter.clone(),
541 &delegate,
542 toolchain,
543 None,
544 cx,
545 )
546 .await?;
547
548 let mut initialization_options = Self::initialization_options_for_adapter(
549 adapter.adapter.clone(),
550 &delegate,
551 cx,
552 )
553 .await?;
554
555 match (&mut initialization_options, override_options) {
556 (Some(initialization_options), Some(override_options)) => {
557 merge_json_value_into(override_options, initialization_options);
558 }
559 (None, override_options) => initialization_options = override_options,
560 _ => {}
561 }
562
563 let initialization_params = cx.update(|cx| {
564 let mut params = language_server.default_initialize_params(
565 pull_diagnostics,
566 augments_syntax_tokens,
567 cx,
568 );
569 params.initialization_options = initialization_options;
570 adapter.adapter.prepare_initialize_params(params, cx)
571 })?;
572
573 Self::setup_lsp_messages(
574 lsp_store.clone(),
575 &language_server,
576 delegate.clone(),
577 adapter.clone(),
578 );
579
580 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
581 settings: workspace_config,
582 };
583 let language_server = cx
584 .update(|cx| {
585 let request_timeout = ProjectSettings::get_global(cx)
586 .global_lsp_settings
587 .get_request_timeout();
588
589 language_server.initialize(
590 initialization_params,
591 Arc::new(did_change_configuration_params.clone()),
592 request_timeout,
593 cx,
594 )
595 })
596 .await
597 .inspect_err(|_| {
598 if let Some(lsp_store) = lsp_store.upgrade() {
599 lsp_store.update(cx, |lsp_store, cx| {
600 lsp_store.cleanup_lsp_data(server_id);
601 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
602 });
603 }
604 })?;
605
606 language_server.notify::<lsp::notification::DidChangeConfiguration>(
607 did_change_configuration_params,
608 )?;
609
610 anyhow::Ok(language_server)
611 }
612 .await;
613
614 match result {
615 Ok(server) => {
616 lsp_store
617 .update(cx, |lsp_store, cx| {
618 lsp_store.insert_newly_running_language_server(
619 adapter,
620 server.clone(),
621 server_id,
622 key,
623 pending_workspace_folders,
624 cx,
625 );
626 })
627 .ok();
628 stderr_capture.lock().take();
629 Some(server)
630 }
631
632 Err(err) => {
633 let log = stderr_capture.lock().take().unwrap_or_default();
634 delegate.update_status(
635 adapter.name(),
636 BinaryStatus::Failed {
637 error: if log.is_empty() {
638 format!("{err:#}")
639 } else {
640 format!("{err:#}\n-- stderr --\n{log}")
641 },
642 },
643 );
644 log::error!(
645 "Failed to start language server {server_name:?}: {}",
646 redact_command(&format!("{err:?}"))
647 );
648 if !log.is_empty() {
649 log::error!("server stderr: {}", redact_command(&log));
650 }
651 None
652 }
653 }
654 })
655 };
656 let state = LanguageServerState::Starting {
657 startup,
658 pending_workspace_folders,
659 };
660
661 if update_binary_status {
662 self.languages
663 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
664 }
665
666 self.language_servers.insert(server_id, state);
667 self.language_server_ids
668 .entry(key)
669 .or_insert(UnifiedLanguageServer {
670 id: server_id,
671 project_roots: Default::default(),
672 });
673 server_id
674 }
675
676 fn get_language_server_binary(
677 &self,
678 worktree_abs_path: Arc<Path>,
679 adapter: Arc<CachedLspAdapter>,
680 settings: Arc<LspSettings>,
681 toolchain: Option<Toolchain>,
682 delegate: Arc<dyn LspAdapterDelegate>,
683 allow_binary_download: bool,
684 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
685 cx: &mut App,
686 ) -> Task<Result<LanguageServerBinary>> {
687 if let Some(settings) = &settings.binary
688 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
689 {
690 let settings = settings.clone();
691 let languages = self.languages.clone();
692 return cx.background_spawn(async move {
693 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
694 let already_trusted = *wait_until_worktree_trust.borrow();
695 if !already_trusted {
696 log::info!(
697 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
698 adapter.name(),
699 );
700 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
701 if worktree_trusted {
702 break;
703 }
704 }
705 log::info!(
706 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
707 adapter.name(),
708 );
709 }
710 languages
711 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
712 }
713 let mut env = delegate.shell_env().await;
714 env.extend(settings.env.unwrap_or_default());
715
716 Ok(LanguageServerBinary {
717 path: delegate.resolve_relative_path(path),
718 env: Some(env),
719 arguments: settings
720 .arguments
721 .unwrap_or_default()
722 .iter()
723 .map(Into::into)
724 .collect(),
725 })
726 });
727 }
728 let lsp_binary_options = LanguageServerBinaryOptions {
729 allow_path_lookup: !settings
730 .binary
731 .as_ref()
732 .and_then(|b| b.ignore_system_version)
733 .unwrap_or_default(),
734 allow_binary_download,
735 pre_release: settings
736 .fetch
737 .as_ref()
738 .and_then(|f| f.pre_release)
739 .unwrap_or(false),
740 };
741
742 cx.spawn(async move |cx| {
743 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
744 let already_trusted = *wait_until_worktree_trust.borrow();
745 if !already_trusted {
746 log::info!(
747 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
748 adapter.name(),
749 );
750 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
751 if worktree_trusted {
752 break;
753 }
754 }
755 log::info!(
756 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
757 adapter.name(),
758 );
759 }
760 }
761
762 let (existing_binary, maybe_download_binary) = adapter
763 .clone()
764 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
765 .await
766 .await;
767
768 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
769
770 let mut binary = match (existing_binary, maybe_download_binary) {
771 (binary, None) => binary?,
772 (Err(_), Some(downloader)) => downloader.await?,
773 (Ok(existing_binary), Some(downloader)) => {
774 let mut download_timeout = cx
775 .background_executor()
776 .timer(SERVER_DOWNLOAD_TIMEOUT)
777 .fuse();
778 let mut downloader = downloader.fuse();
779 futures::select! {
780 _ = download_timeout => {
781 // Return existing binary and kick the existing work to the background.
782 cx.spawn(async move |_| downloader.await).detach();
783 Ok(existing_binary)
784 },
785 downloaded_or_existing_binary = downloader => {
786 // If download fails, this results in the existing binary.
787 downloaded_or_existing_binary
788 }
789 }?
790 }
791 };
792 let mut shell_env = delegate.shell_env().await;
793
794 shell_env.extend(binary.env.unwrap_or_default());
795
796 if let Some(settings) = settings.binary.as_ref() {
797 if let Some(arguments) = &settings.arguments {
798 binary.arguments = arguments.iter().map(Into::into).collect();
799 }
800 if let Some(env) = &settings.env {
801 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
802 }
803 }
804
805 binary.env = Some(shell_env);
806 Ok(binary)
807 })
808 }
809
810 fn setup_lsp_messages(
811 lsp_store: WeakEntity<LspStore>,
812 language_server: &LanguageServer,
813 delegate: Arc<dyn LspAdapterDelegate>,
814 adapter: Arc<CachedLspAdapter>,
815 ) {
816 let name = language_server.name();
817 let server_id = language_server.server_id();
818 language_server
819 .on_notification::<lsp::notification::PublishDiagnostics, _>({
820 let adapter = adapter.clone();
821 let this = lsp_store.clone();
822 move |mut params, cx| {
823 let adapter = adapter.clone();
824 if let Some(this) = this.upgrade() {
825 this.update(cx, |this, cx| {
826 {
827 let buffer = params
828 .uri
829 .to_file_path()
830 .map(|file_path| this.get_buffer(&file_path, cx))
831 .ok()
832 .flatten();
833 adapter.process_diagnostics(&mut params, server_id, buffer);
834 }
835
836 this.merge_lsp_diagnostics(
837 DiagnosticSourceKind::Pushed,
838 vec![DocumentDiagnosticsUpdate {
839 server_id,
840 diagnostics: params,
841 result_id: None,
842 disk_based_sources: Cow::Borrowed(
843 &adapter.disk_based_diagnostic_sources,
844 ),
845 registration_id: None,
846 }],
847 |_, diagnostic, cx| match diagnostic.source_kind {
848 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
849 adapter.retain_old_diagnostic(diagnostic, cx)
850 }
851 DiagnosticSourceKind::Pulled => true,
852 },
853 cx,
854 )
855 .log_err();
856 });
857 }
858 }
859 })
860 .detach();
861 language_server
862 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
863 let adapter = adapter.adapter.clone();
864 let delegate = delegate.clone();
865 let this = lsp_store.clone();
866 move |params, cx| {
867 let adapter = adapter.clone();
868 let delegate = delegate.clone();
869 let this = this.clone();
870 let mut cx = cx.clone();
871 async move {
872 let toolchain_for_id = this
873 .update(&mut cx, |this, _| {
874 this.as_local()?.language_server_ids.iter().find_map(
875 |(seed, value)| {
876 (value.id == server_id).then(|| seed.toolchain.clone())
877 },
878 )
879 })?
880 .context("Expected the LSP store to be in a local mode")?;
881
882 let mut scope_uri_to_workspace_config = BTreeMap::new();
883 for item in ¶ms.items {
884 let scope_uri = item.scope_uri.clone();
885 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
886 scope_uri_to_workspace_config.entry(scope_uri.clone())
887 else {
888 // We've already queried workspace configuration of this URI.
889 continue;
890 };
891 let workspace_config = Self::workspace_configuration_for_adapter(
892 adapter.clone(),
893 &delegate,
894 toolchain_for_id.clone(),
895 scope_uri,
896 &mut cx,
897 )
898 .await?;
899 new_scope_uri.insert(workspace_config);
900 }
901
902 Ok(params
903 .items
904 .into_iter()
905 .filter_map(|item| {
906 let workspace_config =
907 scope_uri_to_workspace_config.get(&item.scope_uri)?;
908 if let Some(section) = &item.section {
909 Some(
910 workspace_config
911 .get(section)
912 .cloned()
913 .unwrap_or(serde_json::Value::Null),
914 )
915 } else {
916 Some(workspace_config.clone())
917 }
918 })
919 .collect())
920 }
921 }
922 })
923 .detach();
924
925 language_server
926 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
927 let this = lsp_store.clone();
928 move |_, cx| {
929 let this = this.clone();
930 let cx = cx.clone();
931 async move {
932 let Some(server) =
933 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
934 else {
935 return Ok(None);
936 };
937 let root = server.workspace_folders();
938 Ok(Some(
939 root.into_iter()
940 .map(|uri| WorkspaceFolder {
941 uri,
942 name: Default::default(),
943 })
944 .collect(),
945 ))
946 }
947 }
948 })
949 .detach();
950 // Even though we don't have handling for these requests, respond to them to
951 // avoid stalling any language server like `gopls` which waits for a response
952 // to these requests when initializing.
953 language_server
954 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
955 let this = lsp_store.clone();
956 move |params, cx| {
957 let this = this.clone();
958 let mut cx = cx.clone();
959 async move {
960 this.update(&mut cx, |this, _| {
961 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
962 {
963 status
964 .progress_tokens
965 .insert(ProgressToken::from_lsp(params.token));
966 }
967 })?;
968
969 Ok(())
970 }
971 }
972 })
973 .detach();
974
975 language_server
976 .on_request::<lsp::request::RegisterCapability, _, _>({
977 let lsp_store = lsp_store.clone();
978 move |params, cx| {
979 let lsp_store = lsp_store.clone();
980 let mut cx = cx.clone();
981 async move {
982 lsp_store
983 .update(&mut cx, |lsp_store, cx| {
984 if lsp_store.as_local().is_some() {
985 match lsp_store
986 .register_server_capabilities(server_id, params, cx)
987 {
988 Ok(()) => {}
989 Err(e) => {
990 log::error!(
991 "Failed to register server capabilities: {e:#}"
992 );
993 }
994 };
995 }
996 })
997 .ok();
998 Ok(())
999 }
1000 }
1001 })
1002 .detach();
1003
1004 language_server
1005 .on_request::<lsp::request::UnregisterCapability, _, _>({
1006 let lsp_store = lsp_store.clone();
1007 move |params, cx| {
1008 let lsp_store = lsp_store.clone();
1009 let mut cx = cx.clone();
1010 async move {
1011 lsp_store
1012 .update(&mut cx, |lsp_store, cx| {
1013 if lsp_store.as_local().is_some() {
1014 match lsp_store
1015 .unregister_server_capabilities(server_id, params, cx)
1016 {
1017 Ok(()) => {}
1018 Err(e) => {
1019 log::error!(
1020 "Failed to unregister server capabilities: {e:#}"
1021 );
1022 }
1023 }
1024 }
1025 })
1026 .ok();
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1035 let this = lsp_store.clone();
1036 move |params, cx| {
1037 let mut cx = cx.clone();
1038 let this = this.clone();
1039 async move {
1040 LocalLspStore::on_lsp_workspace_edit(
1041 this.clone(),
1042 params,
1043 server_id,
1044 &mut cx,
1045 )
1046 .await
1047 }
1048 }
1049 })
1050 .detach();
1051
1052 language_server
1053 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1054 let lsp_store = lsp_store.clone();
1055 let request_id = Arc::new(AtomicUsize::new(0));
1056 move |(), cx| {
1057 let lsp_store = lsp_store.clone();
1058 let request_id = request_id.clone();
1059 let mut cx = cx.clone();
1060 async move {
1061 lsp_store
1062 .update(&mut cx, |lsp_store, cx| {
1063 let request_id =
1064 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1065 cx.emit(LspStoreEvent::RefreshInlayHints {
1066 server_id,
1067 request_id,
1068 });
1069 lsp_store
1070 .downstream_client
1071 .as_ref()
1072 .map(|(client, project_id)| {
1073 client.send(proto::RefreshInlayHints {
1074 project_id: *project_id,
1075 server_id: server_id.to_proto(),
1076 request_id: request_id.map(|id| id as u64),
1077 })
1078 })
1079 })?
1080 .transpose()?;
1081 Ok(())
1082 }
1083 }
1084 })
1085 .detach();
1086
1087 language_server
1088 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1089 let this = lsp_store.clone();
1090 move |(), cx| {
1091 let this = this.clone();
1092 let mut cx = cx.clone();
1093 async move {
1094 this.update(&mut cx, |this, cx| {
1095 cx.emit(LspStoreEvent::RefreshCodeLens);
1096 this.downstream_client.as_ref().map(|(client, project_id)| {
1097 client.send(proto::RefreshCodeLens {
1098 project_id: *project_id,
1099 })
1100 })
1101 })?
1102 .transpose()?;
1103 Ok(())
1104 }
1105 }
1106 })
1107 .detach();
1108
1109 language_server
1110 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1111 let lsp_store = lsp_store.clone();
1112 let request_id = Arc::new(AtomicUsize::new(0));
1113 move |(), cx| {
1114 let lsp_store = lsp_store.clone();
1115 let request_id = request_id.clone();
1116 let mut cx = cx.clone();
1117 async move {
1118 lsp_store
1119 .update(&mut cx, |lsp_store, cx| {
1120 let request_id =
1121 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1122 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1123 server_id,
1124 request_id,
1125 });
1126 lsp_store
1127 .downstream_client
1128 .as_ref()
1129 .map(|(client, project_id)| {
1130 client.send(proto::RefreshSemanticTokens {
1131 project_id: *project_id,
1132 server_id: server_id.to_proto(),
1133 request_id: request_id.map(|id| id as u64),
1134 })
1135 })
1136 })?
1137 .transpose()?;
1138 Ok(())
1139 }
1140 }
1141 })
1142 .detach();
1143
1144 language_server
1145 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1146 let this = lsp_store.clone();
1147 move |(), cx| {
1148 let this = this.clone();
1149 let mut cx = cx.clone();
1150 async move {
1151 this.update(&mut cx, |lsp_store, cx| {
1152 lsp_store.pull_workspace_diagnostics(server_id);
1153 lsp_store
1154 .downstream_client
1155 .as_ref()
1156 .map(|(client, project_id)| {
1157 client.send(proto::PullWorkspaceDiagnostics {
1158 project_id: *project_id,
1159 server_id: server_id.to_proto(),
1160 })
1161 })
1162 .transpose()?;
1163 anyhow::Ok(
1164 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1165 )
1166 })??
1167 .await;
1168 Ok(())
1169 }
1170 }
1171 })
1172 .detach();
1173
1174 language_server
1175 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1176 let this = lsp_store.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 move |params, cx| {
1180 let this = this.clone();
1181 let name = name.to_string();
1182 let adapter = adapter.clone();
1183 let mut cx = cx.clone();
1184 async move {
1185 let actions = params.actions.unwrap_or_default();
1186 let message = params.message.clone();
1187 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1188 let level = match params.typ {
1189 lsp::MessageType::ERROR => PromptLevel::Critical,
1190 lsp::MessageType::WARNING => PromptLevel::Warning,
1191 _ => PromptLevel::Info,
1192 };
1193 let request = LanguageServerPromptRequest::new(
1194 level,
1195 params.message,
1196 actions,
1197 name.clone(),
1198 tx,
1199 );
1200
1201 let did_update = this
1202 .update(&mut cx, |_, cx| {
1203 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1204 })
1205 .is_ok();
1206 if did_update {
1207 let response = rx.recv().await.ok();
1208 if let Some(ref selected_action) = response {
1209 let context = language::PromptResponseContext {
1210 message,
1211 selected_action: selected_action.clone(),
1212 };
1213 adapter.process_prompt_response(&context, &mut cx)
1214 }
1215
1216 Ok(response)
1217 } else {
1218 Ok(None)
1219 }
1220 }
1221 }
1222 })
1223 .detach();
1224 language_server
1225 .on_notification::<lsp::notification::ShowMessage, _>({
1226 let this = lsp_store.clone();
1227 let name = name.to_string();
1228 move |params, cx| {
1229 let this = this.clone();
1230 let name = name.to_string();
1231 let mut cx = cx.clone();
1232
1233 let (tx, _) = smol::channel::bounded(1);
1234 let level = match params.typ {
1235 lsp::MessageType::ERROR => PromptLevel::Critical,
1236 lsp::MessageType::WARNING => PromptLevel::Warning,
1237 _ => PromptLevel::Info,
1238 };
1239 let request =
1240 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1241
1242 let _ = this.update(&mut cx, |_, cx| {
1243 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1244 });
1245 }
1246 })
1247 .detach();
1248
1249 let disk_based_diagnostics_progress_token =
1250 adapter.disk_based_diagnostics_progress_token.clone();
1251
1252 language_server
1253 .on_notification::<lsp::notification::Progress, _>({
1254 let this = lsp_store.clone();
1255 move |params, cx| {
1256 if let Some(this) = this.upgrade() {
1257 this.update(cx, |this, cx| {
1258 this.on_lsp_progress(
1259 params,
1260 server_id,
1261 disk_based_diagnostics_progress_token.clone(),
1262 cx,
1263 );
1264 });
1265 }
1266 }
1267 })
1268 .detach();
1269
1270 language_server
1271 .on_notification::<lsp::notification::LogMessage, _>({
1272 let this = lsp_store.clone();
1273 move |params, cx| {
1274 if let Some(this) = this.upgrade() {
1275 this.update(cx, |_, cx| {
1276 cx.emit(LspStoreEvent::LanguageServerLog(
1277 server_id,
1278 LanguageServerLogType::Log(params.typ),
1279 params.message,
1280 ));
1281 });
1282 }
1283 }
1284 })
1285 .detach();
1286
1287 language_server
1288 .on_notification::<lsp::notification::LogTrace, _>({
1289 let this = lsp_store.clone();
1290 move |params, cx| {
1291 let mut cx = cx.clone();
1292 if let Some(this) = this.upgrade() {
1293 this.update(&mut cx, |_, cx| {
1294 cx.emit(LspStoreEvent::LanguageServerLog(
1295 server_id,
1296 LanguageServerLogType::Trace {
1297 verbose_info: params.verbose,
1298 },
1299 params.message,
1300 ));
1301 });
1302 }
1303 }
1304 })
1305 .detach();
1306
1307 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1309 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1310 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1311 }
1312
1313 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1314 let shutdown_futures = self
1315 .language_servers
1316 .drain()
1317 .map(|(_, server_state)| Self::shutdown_server(server_state))
1318 .collect::<Vec<_>>();
1319
1320 async move {
1321 join_all(shutdown_futures).await;
1322 }
1323 }
1324
1325 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1326 match server_state {
1327 LanguageServerState::Running { server, .. } => {
1328 if let Some(shutdown) = server.shutdown() {
1329 shutdown.await;
1330 }
1331 }
1332 LanguageServerState::Starting { startup, .. } => {
1333 if let Some(server) = startup.await
1334 && let Some(shutdown) = server.shutdown()
1335 {
1336 shutdown.await;
1337 }
1338 }
1339 }
1340 Ok(())
1341 }
1342
1343 fn language_servers_for_worktree(
1344 &self,
1345 worktree_id: WorktreeId,
1346 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1347 self.language_server_ids
1348 .iter()
1349 .filter_map(move |(seed, state)| {
1350 if seed.worktree_id != worktree_id {
1351 return None;
1352 }
1353
1354 if let Some(LanguageServerState::Running { server, .. }) =
1355 self.language_servers.get(&state.id)
1356 {
1357 Some(server)
1358 } else {
1359 None
1360 }
1361 })
1362 }
1363
1364 fn language_server_ids_for_project_path(
1365 &self,
1366 project_path: ProjectPath,
1367 language: &Language,
1368 cx: &mut App,
1369 ) -> Vec<LanguageServerId> {
1370 let Some(worktree) = self
1371 .worktree_store
1372 .read(cx)
1373 .worktree_for_id(project_path.worktree_id, cx)
1374 else {
1375 return Vec::new();
1376 };
1377 let delegate: Arc<dyn ManifestDelegate> =
1378 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1379
1380 self.lsp_tree
1381 .get(
1382 project_path,
1383 language.name(),
1384 language.manifest(),
1385 &delegate,
1386 cx,
1387 )
1388 .collect::<Vec<_>>()
1389 }
1390
1391 fn language_server_ids_for_buffer(
1392 &self,
1393 buffer: &Buffer,
1394 cx: &mut App,
1395 ) -> Vec<LanguageServerId> {
1396 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1397 let worktree_id = file.worktree_id(cx);
1398
1399 let path: Arc<RelPath> = file
1400 .path()
1401 .parent()
1402 .map(Arc::from)
1403 .unwrap_or_else(|| file.path().clone());
1404 let worktree_path = ProjectPath { worktree_id, path };
1405 self.language_server_ids_for_project_path(worktree_path, language, cx)
1406 } else {
1407 Vec::new()
1408 }
1409 }
1410
1411 fn language_servers_for_buffer<'a>(
1412 &'a self,
1413 buffer: &'a Buffer,
1414 cx: &'a mut App,
1415 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1416 self.language_server_ids_for_buffer(buffer, cx)
1417 .into_iter()
1418 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1419 LanguageServerState::Running {
1420 adapter, server, ..
1421 } => Some((adapter, server)),
1422 _ => None,
1423 })
1424 }
1425
1426 async fn execute_code_action_kind_locally(
1427 lsp_store: WeakEntity<LspStore>,
1428 mut buffers: Vec<Entity<Buffer>>,
1429 kind: CodeActionKind,
1430 push_to_history: bool,
1431 cx: &mut AsyncApp,
1432 ) -> anyhow::Result<ProjectTransaction> {
1433 // Do not allow multiple concurrent code actions requests for the
1434 // same buffer.
1435 lsp_store.update(cx, |this, cx| {
1436 let this = this.as_local_mut().unwrap();
1437 buffers.retain(|buffer| {
1438 this.buffers_being_formatted
1439 .insert(buffer.read(cx).remote_id())
1440 });
1441 })?;
1442 let _cleanup = defer({
1443 let this = lsp_store.clone();
1444 let mut cx = cx.clone();
1445 let buffers = &buffers;
1446 move || {
1447 this.update(&mut cx, |this, cx| {
1448 let this = this.as_local_mut().unwrap();
1449 for buffer in buffers {
1450 this.buffers_being_formatted
1451 .remove(&buffer.read(cx).remote_id());
1452 }
1453 })
1454 .ok();
1455 }
1456 });
1457 let mut project_transaction = ProjectTransaction::default();
1458
1459 for buffer in &buffers {
1460 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1461 buffer.update(cx, |buffer, cx| {
1462 lsp_store
1463 .as_local()
1464 .unwrap()
1465 .language_servers_for_buffer(buffer, cx)
1466 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1467 .collect::<Vec<_>>()
1468 })
1469 })?;
1470 for (_, language_server) in adapters_and_servers.iter() {
1471 let actions = Self::get_server_code_actions_from_action_kinds(
1472 &lsp_store,
1473 language_server.server_id(),
1474 vec![kind.clone()],
1475 buffer,
1476 cx,
1477 )
1478 .await?;
1479 Self::execute_code_actions_on_server(
1480 &lsp_store,
1481 language_server,
1482 actions,
1483 push_to_history,
1484 &mut project_transaction,
1485 cx,
1486 )
1487 .await?;
1488 }
1489 }
1490 Ok(project_transaction)
1491 }
1492
1493 async fn format_locally(
1494 lsp_store: WeakEntity<LspStore>,
1495 mut buffers: Vec<FormattableBuffer>,
1496 push_to_history: bool,
1497 trigger: FormatTrigger,
1498 logger: zlog::Logger,
1499 cx: &mut AsyncApp,
1500 ) -> anyhow::Result<ProjectTransaction> {
1501 // Do not allow multiple concurrent formatting requests for the
1502 // same buffer.
1503 lsp_store.update(cx, |this, cx| {
1504 let this = this.as_local_mut().unwrap();
1505 buffers.retain(|buffer| {
1506 this.buffers_being_formatted
1507 .insert(buffer.handle.read(cx).remote_id())
1508 });
1509 })?;
1510
1511 let _cleanup = defer({
1512 let this = lsp_store.clone();
1513 let mut cx = cx.clone();
1514 let buffers = &buffers;
1515 move || {
1516 this.update(&mut cx, |this, cx| {
1517 let this = this.as_local_mut().unwrap();
1518 for buffer in buffers {
1519 this.buffers_being_formatted
1520 .remove(&buffer.handle.read(cx).remote_id());
1521 }
1522 })
1523 .ok();
1524 }
1525 });
1526
1527 let mut project_transaction = ProjectTransaction::default();
1528
1529 for buffer in &buffers {
1530 zlog::debug!(
1531 logger =>
1532 "formatting buffer '{:?}'",
1533 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1534 );
1535 // Create an empty transaction to hold all of the formatting edits.
1536 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1537 // ensure no transactions created while formatting are
1538 // grouped with the previous transaction in the history
1539 // based on the transaction group interval
1540 buffer.finalize_last_transaction();
1541 buffer
1542 .start_transaction()
1543 .context("transaction already open")?;
1544 buffer.end_transaction(cx);
1545 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1546 buffer.finalize_last_transaction();
1547 anyhow::Ok(transaction_id)
1548 })?;
1549
1550 let result = Self::format_buffer_locally(
1551 lsp_store.clone(),
1552 buffer,
1553 formatting_transaction_id,
1554 trigger,
1555 logger,
1556 cx,
1557 )
1558 .await;
1559
1560 buffer.handle.update(cx, |buffer, cx| {
1561 let Some(formatting_transaction) =
1562 buffer.get_transaction(formatting_transaction_id).cloned()
1563 else {
1564 zlog::warn!(logger => "no formatting transaction");
1565 return;
1566 };
1567 if formatting_transaction.edit_ids.is_empty() {
1568 zlog::debug!(logger => "no changes made while formatting");
1569 buffer.forget_transaction(formatting_transaction_id);
1570 return;
1571 }
1572 if !push_to_history {
1573 zlog::trace!(logger => "forgetting format transaction");
1574 buffer.forget_transaction(formatting_transaction.id);
1575 }
1576 project_transaction
1577 .0
1578 .insert(cx.entity(), formatting_transaction);
1579 });
1580
1581 result?;
1582 }
1583
1584 Ok(project_transaction)
1585 }
1586
1587 async fn format_buffer_locally(
1588 lsp_store: WeakEntity<LspStore>,
1589 buffer: &FormattableBuffer,
1590 formatting_transaction_id: clock::Lamport,
1591 trigger: FormatTrigger,
1592 logger: zlog::Logger,
1593 cx: &mut AsyncApp,
1594 ) -> Result<()> {
1595 let (adapters_and_servers, settings, request_timeout) =
1596 lsp_store.update(cx, |lsp_store, cx| {
1597 buffer.handle.update(cx, |buffer, cx| {
1598 let adapters_and_servers = lsp_store
1599 .as_local()
1600 .unwrap()
1601 .language_servers_for_buffer(buffer, cx)
1602 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1603 .collect::<Vec<_>>();
1604 let settings =
1605 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1606 .into_owned();
1607 let request_timeout = ProjectSettings::get_global(cx)
1608 .global_lsp_settings
1609 .get_request_timeout();
1610 (adapters_and_servers, settings, request_timeout)
1611 })
1612 })?;
1613
1614 /// Apply edits to the buffer that will become part of the formatting transaction.
1615 /// Fails if the buffer has been edited since the start of that transaction.
1616 fn extend_formatting_transaction(
1617 buffer: &FormattableBuffer,
1618 formatting_transaction_id: text::TransactionId,
1619 cx: &mut AsyncApp,
1620 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1621 ) -> anyhow::Result<()> {
1622 buffer.handle.update(cx, |buffer, cx| {
1623 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1624 if last_transaction_id != Some(formatting_transaction_id) {
1625 anyhow::bail!("Buffer edited while formatting. Aborting")
1626 }
1627 buffer.start_transaction();
1628 operation(buffer, cx);
1629 if let Some(transaction_id) = buffer.end_transaction(cx) {
1630 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1631 }
1632 Ok(())
1633 })
1634 }
1635
1636 // handle whitespace formatting
1637 if settings.remove_trailing_whitespace_on_save {
1638 zlog::trace!(logger => "removing trailing whitespace");
1639 let diff = buffer
1640 .handle
1641 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1642 .await;
1643 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1644 buffer.apply_diff(diff, cx);
1645 })?;
1646 }
1647
1648 if settings.ensure_final_newline_on_save {
1649 zlog::trace!(logger => "ensuring final newline");
1650 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1651 buffer.ensure_final_newline(cx);
1652 })?;
1653 }
1654
1655 // Formatter for `code_actions_on_format` that runs before
1656 // the rest of the formatters
1657 let mut code_actions_on_format_formatters = None;
1658 let should_run_code_actions_on_format = !matches!(
1659 (trigger, &settings.format_on_save),
1660 (FormatTrigger::Save, &FormatOnSave::Off)
1661 );
1662 if should_run_code_actions_on_format {
1663 let have_code_actions_to_run_on_format = settings
1664 .code_actions_on_format
1665 .values()
1666 .any(|enabled| *enabled);
1667 if have_code_actions_to_run_on_format {
1668 zlog::trace!(logger => "going to run code actions on format");
1669 code_actions_on_format_formatters = Some(
1670 settings
1671 .code_actions_on_format
1672 .iter()
1673 .filter_map(|(action, enabled)| enabled.then_some(action))
1674 .cloned()
1675 .map(Formatter::CodeAction)
1676 .collect::<Vec<_>>(),
1677 );
1678 }
1679 }
1680
1681 let formatters = match (trigger, &settings.format_on_save) {
1682 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1683 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1684 settings.formatter.as_ref()
1685 }
1686 };
1687
1688 let formatters = code_actions_on_format_formatters
1689 .iter()
1690 .flatten()
1691 .chain(formatters);
1692
1693 for formatter in formatters {
1694 let formatter = if formatter == &Formatter::Auto {
1695 if settings.prettier.allowed {
1696 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1697 &Formatter::Prettier
1698 } else {
1699 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1700 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1701 }
1702 } else {
1703 formatter
1704 };
1705 match formatter {
1706 Formatter::Auto => unreachable!("Auto resolved above"),
1707 Formatter::Prettier => {
1708 let logger = zlog::scoped!(logger => "prettier");
1709 zlog::trace!(logger => "formatting");
1710 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1711
1712 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1713 lsp_store.prettier_store().unwrap().downgrade()
1714 })?;
1715 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1716 .await
1717 .transpose()?;
1718 let Some(diff) = diff else {
1719 zlog::trace!(logger => "No changes");
1720 continue;
1721 };
1722
1723 extend_formatting_transaction(
1724 buffer,
1725 formatting_transaction_id,
1726 cx,
1727 |buffer, cx| {
1728 buffer.apply_diff(diff, cx);
1729 },
1730 )?;
1731 }
1732 Formatter::External { command, arguments } => {
1733 let logger = zlog::scoped!(logger => "command");
1734 zlog::trace!(logger => "formatting");
1735 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1736
1737 let diff = Self::format_via_external_command(
1738 buffer,
1739 &command,
1740 arguments.as_deref(),
1741 cx,
1742 )
1743 .await
1744 .with_context(|| {
1745 format!("Failed to format buffer via external command: {}", command)
1746 })?;
1747 let Some(diff) = diff else {
1748 zlog::trace!(logger => "No changes");
1749 continue;
1750 };
1751
1752 extend_formatting_transaction(
1753 buffer,
1754 formatting_transaction_id,
1755 cx,
1756 |buffer, cx| {
1757 buffer.apply_diff(diff, cx);
1758 },
1759 )?;
1760 }
1761 Formatter::LanguageServer(specifier) => {
1762 let logger = zlog::scoped!(logger => "language-server");
1763 zlog::trace!(logger => "formatting");
1764 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1765
1766 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1767 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1768 continue;
1769 };
1770
1771 let language_server = match specifier {
1772 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1773 adapters_and_servers.iter().find_map(|(adapter, server)| {
1774 if adapter.name.0.as_ref() == name {
1775 Some(server.clone())
1776 } else {
1777 None
1778 }
1779 })
1780 }
1781 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1782 .iter()
1783 .find(|(_, server)| Self::server_supports_formatting(server))
1784 .map(|(_, server)| server.clone()),
1785 };
1786
1787 let Some(language_server) = language_server else {
1788 log::debug!(
1789 "No language server found to format buffer '{:?}'. Skipping",
1790 buffer_path_abs.as_path().to_string_lossy()
1791 );
1792 continue;
1793 };
1794
1795 zlog::trace!(
1796 logger =>
1797 "Formatting buffer '{:?}' using language server '{:?}'",
1798 buffer_path_abs.as_path().to_string_lossy(),
1799 language_server.name()
1800 );
1801
1802 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1803 zlog::trace!(logger => "formatting ranges");
1804 Self::format_ranges_via_lsp(
1805 &lsp_store,
1806 &buffer.handle,
1807 ranges,
1808 buffer_path_abs,
1809 &language_server,
1810 &settings,
1811 cx,
1812 )
1813 .await
1814 .context("Failed to format ranges via language server")?
1815 } else {
1816 zlog::trace!(logger => "formatting full");
1817 Self::format_via_lsp(
1818 &lsp_store,
1819 &buffer.handle,
1820 buffer_path_abs,
1821 &language_server,
1822 &settings,
1823 cx,
1824 )
1825 .await
1826 .context("failed to format via language server")?
1827 };
1828
1829 if edits.is_empty() {
1830 zlog::trace!(logger => "No changes");
1831 continue;
1832 }
1833 extend_formatting_transaction(
1834 buffer,
1835 formatting_transaction_id,
1836 cx,
1837 |buffer, cx| {
1838 buffer.edit(edits, None, cx);
1839 },
1840 )?;
1841 }
1842 Formatter::CodeAction(code_action_name) => {
1843 let logger = zlog::scoped!(logger => "code-actions");
1844 zlog::trace!(logger => "formatting");
1845 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1846
1847 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1848 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1849 continue;
1850 };
1851
1852 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1853 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1854
1855 let mut actions_and_servers = Vec::new();
1856
1857 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1858 let actions_result = Self::get_server_code_actions_from_action_kinds(
1859 &lsp_store,
1860 language_server.server_id(),
1861 vec![code_action_kind.clone()],
1862 &buffer.handle,
1863 cx,
1864 )
1865 .await
1866 .with_context(|| {
1867 format!(
1868 "Failed to resolve code action {:?} with language server {}",
1869 code_action_kind,
1870 language_server.name()
1871 )
1872 });
1873 let Ok(actions) = actions_result else {
1874 // note: it may be better to set result to the error and break formatters here
1875 // but for now we try to execute the actions that we can resolve and skip the rest
1876 zlog::error!(
1877 logger =>
1878 "Failed to resolve code action {:?} with language server {}",
1879 code_action_kind,
1880 language_server.name()
1881 );
1882 continue;
1883 };
1884 for action in actions {
1885 actions_and_servers.push((action, index));
1886 }
1887 }
1888
1889 if actions_and_servers.is_empty() {
1890 zlog::warn!(logger => "No code actions were resolved, continuing");
1891 continue;
1892 }
1893
1894 'actions: for (mut action, server_index) in actions_and_servers {
1895 let server = &adapters_and_servers[server_index].1;
1896
1897 let describe_code_action = |action: &CodeAction| {
1898 format!(
1899 "code action '{}' with title \"{}\" on server {}",
1900 action
1901 .lsp_action
1902 .action_kind()
1903 .unwrap_or("unknown".into())
1904 .as_str(),
1905 action.lsp_action.title(),
1906 server.name(),
1907 )
1908 };
1909
1910 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1911
1912 if let Err(err) =
1913 Self::try_resolve_code_action(server, &mut action, request_timeout)
1914 .await
1915 {
1916 zlog::error!(
1917 logger =>
1918 "Failed to resolve {}. Error: {}",
1919 describe_code_action(&action),
1920 err
1921 );
1922 continue;
1923 }
1924
1925 if let Some(edit) = action.lsp_action.edit().cloned() {
1926 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1927 // but filters out and logs warnings for code actions that require unreasonably
1928 // difficult handling on our part, such as:
1929 // - applying edits that call commands
1930 // which can result in arbitrary workspace edits being sent from the server that
1931 // have no way of being tied back to the command that initiated them (i.e. we
1932 // can't know which edits are part of the format request, or if the server is done sending
1933 // actions in response to the command)
1934 // - actions that create/delete/modify/rename files other than the one we are formatting
1935 // as we then would need to handle such changes correctly in the local history as well
1936 // as the remote history through the ProjectTransaction
1937 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1938 // Supporting these actions is not impossible, but not supported as of yet.
1939 if edit.changes.is_none() && edit.document_changes.is_none() {
1940 zlog::trace!(
1941 logger =>
1942 "No changes for code action. Skipping {}",
1943 describe_code_action(&action),
1944 );
1945 continue;
1946 }
1947
1948 let mut operations = Vec::new();
1949 if let Some(document_changes) = edit.document_changes {
1950 match document_changes {
1951 lsp::DocumentChanges::Edits(edits) => operations.extend(
1952 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1953 ),
1954 lsp::DocumentChanges::Operations(ops) => operations = ops,
1955 }
1956 } else if let Some(changes) = edit.changes {
1957 operations.extend(changes.into_iter().map(|(uri, edits)| {
1958 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1959 text_document:
1960 lsp::OptionalVersionedTextDocumentIdentifier {
1961 uri,
1962 version: None,
1963 },
1964 edits: edits.into_iter().map(Edit::Plain).collect(),
1965 })
1966 }));
1967 }
1968
1969 let mut edits = Vec::with_capacity(operations.len());
1970
1971 if operations.is_empty() {
1972 zlog::trace!(
1973 logger =>
1974 "No changes for code action. Skipping {}",
1975 describe_code_action(&action),
1976 );
1977 continue;
1978 }
1979 for operation in operations {
1980 let op = match operation {
1981 lsp::DocumentChangeOperation::Edit(op) => op,
1982 lsp::DocumentChangeOperation::Op(_) => {
1983 zlog::warn!(
1984 logger =>
1985 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1986 describe_code_action(&action),
1987 );
1988 continue 'actions;
1989 }
1990 };
1991 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1992 zlog::warn!(
1993 logger =>
1994 "Failed to convert URI '{:?}' to file path. Skipping {}",
1995 &op.text_document.uri,
1996 describe_code_action(&action),
1997 );
1998 continue 'actions;
1999 };
2000 if &file_path != buffer_path_abs {
2001 zlog::warn!(
2002 logger =>
2003 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2004 file_path,
2005 buffer_path_abs,
2006 describe_code_action(&action),
2007 );
2008 continue 'actions;
2009 }
2010
2011 let mut lsp_edits = Vec::new();
2012 for edit in op.edits {
2013 match edit {
2014 Edit::Plain(edit) => {
2015 if !lsp_edits.contains(&edit) {
2016 lsp_edits.push(edit);
2017 }
2018 }
2019 Edit::Annotated(edit) => {
2020 if !lsp_edits.contains(&edit.text_edit) {
2021 lsp_edits.push(edit.text_edit);
2022 }
2023 }
2024 Edit::Snippet(_) => {
2025 zlog::warn!(
2026 logger =>
2027 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2028 describe_code_action(&action),
2029 );
2030 continue 'actions;
2031 }
2032 }
2033 }
2034 let edits_result = lsp_store
2035 .update(cx, |lsp_store, cx| {
2036 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2037 &buffer.handle,
2038 lsp_edits,
2039 server.server_id(),
2040 op.text_document.version,
2041 cx,
2042 )
2043 })?
2044 .await;
2045 let Ok(resolved_edits) = edits_result else {
2046 zlog::warn!(
2047 logger =>
2048 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2049 buffer_path_abs.as_path(),
2050 describe_code_action(&action),
2051 );
2052 continue 'actions;
2053 };
2054 edits.extend(resolved_edits);
2055 }
2056
2057 if edits.is_empty() {
2058 zlog::warn!(logger => "No edits resolved from LSP");
2059 continue;
2060 }
2061
2062 extend_formatting_transaction(
2063 buffer,
2064 formatting_transaction_id,
2065 cx,
2066 |buffer, cx| {
2067 zlog::info!(
2068 "Applying edits {edits:?}. Content: {:?}",
2069 buffer.text()
2070 );
2071 buffer.edit(edits, None, cx);
2072 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2073 },
2074 )?;
2075 }
2076
2077 // bail early if command is invalid
2078 let Some(command) = action.lsp_action.command() else {
2079 continue;
2080 };
2081
2082 zlog::warn!(
2083 logger =>
2084 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2085 &command.command,
2086 );
2087
2088 let server_capabilities = server.capabilities();
2089 let available_commands = server_capabilities
2090 .execute_command_provider
2091 .as_ref()
2092 .map(|options| options.commands.as_slice())
2093 .unwrap_or_default();
2094 if !available_commands.contains(&command.command) {
2095 zlog::warn!(
2096 logger =>
2097 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2098 command.command,
2099 server.name(),
2100 );
2101 continue;
2102 }
2103
2104 // noop so we just ensure buffer hasn't been edited since resolving code actions
2105 extend_formatting_transaction(
2106 buffer,
2107 formatting_transaction_id,
2108 cx,
2109 |_, _| {},
2110 )?;
2111 zlog::info!(logger => "Executing command {}", &command.command);
2112
2113 lsp_store.update(cx, |this, _| {
2114 this.as_local_mut()
2115 .unwrap()
2116 .last_workspace_edits_by_language_server
2117 .remove(&server.server_id());
2118 })?;
2119
2120 let execute_command_result = server
2121 .request::<lsp::request::ExecuteCommand>(
2122 lsp::ExecuteCommandParams {
2123 command: command.command.clone(),
2124 arguments: command.arguments.clone().unwrap_or_default(),
2125 ..Default::default()
2126 },
2127 request_timeout,
2128 )
2129 .await
2130 .into_response();
2131
2132 if execute_command_result.is_err() {
2133 zlog::error!(
2134 logger =>
2135 "Failed to execute command '{}' as part of {}",
2136 &command.command,
2137 describe_code_action(&action),
2138 );
2139 continue 'actions;
2140 }
2141
2142 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2143 this.as_local_mut()
2144 .unwrap()
2145 .last_workspace_edits_by_language_server
2146 .remove(&server.server_id())
2147 .unwrap_or_default()
2148 })?;
2149
2150 if let Some(transaction) =
2151 project_transaction_command.0.remove(&buffer.handle)
2152 {
2153 zlog::trace!(
2154 logger =>
2155 "Successfully captured {} edits that resulted from command {}",
2156 transaction.edit_ids.len(),
2157 &command.command,
2158 );
2159 let transaction_id_project_transaction = transaction.id;
2160 buffer.handle.update(cx, |buffer, _| {
2161 // it may have been removed from history if push_to_history was
2162 // false in deserialize_workspace_edit. If so push it so we
2163 // can merge it with the format transaction
2164 // and pop the combined transaction off the history stack
2165 // later if push_to_history is false
2166 if buffer.get_transaction(transaction.id).is_none() {
2167 buffer.push_transaction(transaction, Instant::now());
2168 }
2169 buffer.merge_transactions(
2170 transaction_id_project_transaction,
2171 formatting_transaction_id,
2172 );
2173 });
2174 }
2175
2176 if project_transaction_command.0.is_empty() {
2177 continue;
2178 }
2179
2180 let mut extra_buffers = String::new();
2181 for buffer in project_transaction_command.0.keys() {
2182 buffer.read_with(cx, |b, cx| {
2183 let Some(path) = b.project_path(cx) else {
2184 return;
2185 };
2186
2187 if !extra_buffers.is_empty() {
2188 extra_buffers.push_str(", ");
2189 }
2190 extra_buffers.push_str(path.path.as_unix_str());
2191 });
2192 }
2193 zlog::warn!(
2194 logger =>
2195 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2196 &command.command,
2197 extra_buffers,
2198 );
2199 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2200 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2201 // add it so it's included, and merge it into the format transaction when its created later
2202 }
2203 }
2204 }
2205 }
2206
2207 Ok(())
2208 }
2209
2210 pub async fn format_ranges_via_lsp(
2211 this: &WeakEntity<LspStore>,
2212 buffer_handle: &Entity<Buffer>,
2213 ranges: &[Range<Anchor>],
2214 abs_path: &Path,
2215 language_server: &Arc<LanguageServer>,
2216 settings: &LanguageSettings,
2217 cx: &mut AsyncApp,
2218 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2219 let capabilities = &language_server.capabilities();
2220 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2221 if range_formatting_provider == Some(&OneOf::Left(false)) {
2222 anyhow::bail!(
2223 "{} language server does not support range formatting",
2224 language_server.name()
2225 );
2226 }
2227
2228 let uri = file_path_to_lsp_url(abs_path)?;
2229 let text_document = lsp::TextDocumentIdentifier::new(uri);
2230
2231 let request_timeout = cx.update(|app| {
2232 ProjectSettings::get_global(app)
2233 .global_lsp_settings
2234 .get_request_timeout()
2235 });
2236 let lsp_edits = {
2237 let mut lsp_ranges = Vec::new();
2238 this.update(cx, |_this, cx| {
2239 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2240 // not have been sent to the language server. This seems like a fairly systemic
2241 // issue, though, the resolution probably is not specific to formatting.
2242 //
2243 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2244 // LSP.
2245 let snapshot = buffer_handle.read(cx).snapshot();
2246 for range in ranges {
2247 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2248 }
2249 anyhow::Ok(())
2250 })??;
2251
2252 let mut edits = None;
2253 for range in lsp_ranges {
2254 if let Some(mut edit) = language_server
2255 .request::<lsp::request::RangeFormatting>(
2256 lsp::DocumentRangeFormattingParams {
2257 text_document: text_document.clone(),
2258 range,
2259 options: lsp_command::lsp_formatting_options(settings),
2260 work_done_progress_params: Default::default(),
2261 },
2262 request_timeout,
2263 )
2264 .await
2265 .into_response()?
2266 {
2267 edits.get_or_insert_with(Vec::new).append(&mut edit);
2268 }
2269 }
2270 edits
2271 };
2272
2273 if let Some(lsp_edits) = lsp_edits {
2274 this.update(cx, |this, cx| {
2275 this.as_local_mut().unwrap().edits_from_lsp(
2276 buffer_handle,
2277 lsp_edits,
2278 language_server.server_id(),
2279 None,
2280 cx,
2281 )
2282 })?
2283 .await
2284 } else {
2285 Ok(Vec::with_capacity(0))
2286 }
2287 }
2288
2289 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2290 let capabilities = server.capabilities();
2291 let formatting = capabilities.document_formatting_provider.as_ref();
2292 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2293 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2294 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2295 }
2296
2297 async fn format_via_lsp(
2298 this: &WeakEntity<LspStore>,
2299 buffer: &Entity<Buffer>,
2300 abs_path: &Path,
2301 language_server: &Arc<LanguageServer>,
2302 settings: &LanguageSettings,
2303 cx: &mut AsyncApp,
2304 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2305 let logger = zlog::scoped!("lsp_format");
2306 zlog::debug!(logger => "Formatting via LSP");
2307
2308 let uri = file_path_to_lsp_url(abs_path)?;
2309 let text_document = lsp::TextDocumentIdentifier::new(uri);
2310 let capabilities = &language_server.capabilities();
2311
2312 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2313 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2314
2315 let request_timeout = cx.update(|app| {
2316 ProjectSettings::get_global(app)
2317 .global_lsp_settings
2318 .get_request_timeout()
2319 });
2320
2321 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2322 let _timer = zlog::time!(logger => "format-full");
2323 language_server
2324 .request::<lsp::request::Formatting>(
2325 lsp::DocumentFormattingParams {
2326 text_document,
2327 options: lsp_command::lsp_formatting_options(settings),
2328 work_done_progress_params: Default::default(),
2329 },
2330 request_timeout,
2331 )
2332 .await
2333 .into_response()?
2334 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2335 let _timer = zlog::time!(logger => "format-range");
2336 let buffer_start = lsp::Position::new(0, 0);
2337 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2338 language_server
2339 .request::<lsp::request::RangeFormatting>(
2340 lsp::DocumentRangeFormattingParams {
2341 text_document: text_document.clone(),
2342 range: lsp::Range::new(buffer_start, buffer_end),
2343 options: lsp_command::lsp_formatting_options(settings),
2344 work_done_progress_params: Default::default(),
2345 },
2346 request_timeout,
2347 )
2348 .await
2349 .into_response()?
2350 } else {
2351 None
2352 };
2353
2354 if let Some(lsp_edits) = lsp_edits {
2355 this.update(cx, |this, cx| {
2356 this.as_local_mut().unwrap().edits_from_lsp(
2357 buffer,
2358 lsp_edits,
2359 language_server.server_id(),
2360 None,
2361 cx,
2362 )
2363 })?
2364 .await
2365 } else {
2366 Ok(Vec::with_capacity(0))
2367 }
2368 }
2369
2370 async fn format_via_external_command(
2371 buffer: &FormattableBuffer,
2372 command: &str,
2373 arguments: Option<&[String]>,
2374 cx: &mut AsyncApp,
2375 ) -> Result<Option<Diff>> {
2376 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2377 let file = File::from_dyn(buffer.file())?;
2378 let worktree = file.worktree.read(cx);
2379 let mut worktree_path = worktree.abs_path().to_path_buf();
2380 if worktree.root_entry()?.is_file() {
2381 worktree_path.pop();
2382 }
2383 Some(worktree_path)
2384 });
2385
2386 use util::command::Stdio;
2387 let mut child = util::command::new_command(command);
2388
2389 if let Some(buffer_env) = buffer.env.as_ref() {
2390 child.envs(buffer_env);
2391 }
2392
2393 if let Some(working_dir_path) = working_dir_path {
2394 child.current_dir(working_dir_path);
2395 }
2396
2397 if let Some(arguments) = arguments {
2398 child.args(arguments.iter().map(|arg| {
2399 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2400 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2401 } else {
2402 arg.replace("{buffer_path}", "Untitled")
2403 }
2404 }));
2405 }
2406
2407 let mut child = child
2408 .stdin(Stdio::piped())
2409 .stdout(Stdio::piped())
2410 .stderr(Stdio::piped())
2411 .spawn()?;
2412
2413 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2414 let text = buffer
2415 .handle
2416 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2417 for chunk in text.chunks() {
2418 stdin.write_all(chunk.as_bytes()).await?;
2419 }
2420 stdin.flush().await?;
2421
2422 let output = child.output().await?;
2423 anyhow::ensure!(
2424 output.status.success(),
2425 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2426 output.status.code(),
2427 String::from_utf8_lossy(&output.stdout),
2428 String::from_utf8_lossy(&output.stderr),
2429 );
2430
2431 let stdout = String::from_utf8(output.stdout)?;
2432 Ok(Some(
2433 buffer
2434 .handle
2435 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2436 .await,
2437 ))
2438 }
2439
2440 async fn try_resolve_code_action(
2441 lang_server: &LanguageServer,
2442 action: &mut CodeAction,
2443 request_timeout: Duration,
2444 ) -> anyhow::Result<()> {
2445 match &mut action.lsp_action {
2446 LspAction::Action(lsp_action) => {
2447 if !action.resolved
2448 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2449 && lsp_action.data.is_some()
2450 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2451 {
2452 **lsp_action = lang_server
2453 .request::<lsp::request::CodeActionResolveRequest>(
2454 *lsp_action.clone(),
2455 request_timeout,
2456 )
2457 .await
2458 .into_response()?;
2459 }
2460 }
2461 LspAction::CodeLens(lens) => {
2462 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2463 *lens = lang_server
2464 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2465 .await
2466 .into_response()?;
2467 }
2468 }
2469 LspAction::Command(_) => {}
2470 }
2471
2472 action.resolved = true;
2473 anyhow::Ok(())
2474 }
2475
2476 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2477 let buffer = buffer_handle.read(cx);
2478
2479 let file = buffer.file().cloned();
2480
2481 let Some(file) = File::from_dyn(file.as_ref()) else {
2482 return;
2483 };
2484 if !file.is_local() {
2485 return;
2486 }
2487 let path = ProjectPath::from_file(file, cx);
2488 let worktree_id = file.worktree_id(cx);
2489 let language = buffer.language().cloned();
2490
2491 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2492 for (server_id, diagnostics) in
2493 diagnostics.get(file.path()).cloned().unwrap_or_default()
2494 {
2495 self.update_buffer_diagnostics(
2496 buffer_handle,
2497 server_id,
2498 None,
2499 None,
2500 None,
2501 Vec::new(),
2502 diagnostics,
2503 cx,
2504 )
2505 .log_err();
2506 }
2507 }
2508 let Some(language) = language else {
2509 return;
2510 };
2511 let Some(snapshot) = self
2512 .worktree_store
2513 .read(cx)
2514 .worktree_for_id(worktree_id, cx)
2515 .map(|worktree| worktree.read(cx).snapshot())
2516 else {
2517 return;
2518 };
2519 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2520
2521 for server_id in
2522 self.lsp_tree
2523 .get(path, language.name(), language.manifest(), &delegate, cx)
2524 {
2525 let server = self
2526 .language_servers
2527 .get(&server_id)
2528 .and_then(|server_state| {
2529 if let LanguageServerState::Running { server, .. } = server_state {
2530 Some(server.clone())
2531 } else {
2532 None
2533 }
2534 });
2535 let server = match server {
2536 Some(server) => server,
2537 None => continue,
2538 };
2539
2540 buffer_handle.update(cx, |buffer, cx| {
2541 buffer.set_completion_triggers(
2542 server.server_id(),
2543 server
2544 .capabilities()
2545 .completion_provider
2546 .as_ref()
2547 .and_then(|provider| {
2548 provider
2549 .trigger_characters
2550 .as_ref()
2551 .map(|characters| characters.iter().cloned().collect())
2552 })
2553 .unwrap_or_default(),
2554 cx,
2555 );
2556 });
2557 }
2558 }
2559
2560 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2561 buffer.update(cx, |buffer, cx| {
2562 let Some(language) = buffer.language() else {
2563 return;
2564 };
2565 let path = ProjectPath {
2566 worktree_id: old_file.worktree_id(cx),
2567 path: old_file.path.clone(),
2568 };
2569 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2570 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2571 buffer.set_completion_triggers(server_id, Default::default(), cx);
2572 }
2573 });
2574 }
2575
2576 fn update_buffer_diagnostics(
2577 &mut self,
2578 buffer: &Entity<Buffer>,
2579 server_id: LanguageServerId,
2580 registration_id: Option<Option<SharedString>>,
2581 result_id: Option<SharedString>,
2582 version: Option<i32>,
2583 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2584 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2585 cx: &mut Context<LspStore>,
2586 ) -> Result<()> {
2587 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2588 Ordering::Equal
2589 .then_with(|| b.is_primary.cmp(&a.is_primary))
2590 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2591 .then_with(|| a.severity.cmp(&b.severity))
2592 .then_with(|| a.message.cmp(&b.message))
2593 }
2594
2595 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2596 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2597 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2598
2599 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2600 Ordering::Equal
2601 .then_with(|| a.range.start.cmp(&b.range.start))
2602 .then_with(|| b.range.end.cmp(&a.range.end))
2603 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2604 });
2605
2606 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2607
2608 let edits_since_save = std::cell::LazyCell::new(|| {
2609 let saved_version = buffer.read(cx).saved_version();
2610 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2611 });
2612
2613 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2614
2615 for (new_diagnostic, entry) in diagnostics {
2616 let start;
2617 let end;
2618 if new_diagnostic && entry.diagnostic.is_disk_based {
2619 // Some diagnostics are based on files on disk instead of buffers'
2620 // current contents. Adjust these diagnostics' ranges to reflect
2621 // any unsaved edits.
2622 // Do not alter the reused ones though, as their coordinates were stored as anchors
2623 // and were properly adjusted on reuse.
2624 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2625 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2626 } else {
2627 start = entry.range.start;
2628 end = entry.range.end;
2629 }
2630
2631 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2632 ..snapshot.clip_point_utf16(end, Bias::Right);
2633
2634 // Expand empty ranges by one codepoint
2635 if range.start == range.end {
2636 // This will be go to the next boundary when being clipped
2637 range.end.column += 1;
2638 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2639 if range.start == range.end && range.end.column > 0 {
2640 range.start.column -= 1;
2641 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2642 }
2643 }
2644
2645 sanitized_diagnostics.push(DiagnosticEntry {
2646 range,
2647 diagnostic: entry.diagnostic,
2648 });
2649 }
2650 drop(edits_since_save);
2651
2652 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2653 buffer.update(cx, |buffer, cx| {
2654 if let Some(registration_id) = registration_id {
2655 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2656 self.buffer_pull_diagnostics_result_ids
2657 .entry(server_id)
2658 .or_default()
2659 .entry(registration_id)
2660 .or_default()
2661 .insert(abs_path, result_id);
2662 }
2663 }
2664
2665 buffer.update_diagnostics(server_id, set, cx)
2666 });
2667
2668 Ok(())
2669 }
2670
2671 fn register_language_server_for_invisible_worktree(
2672 &mut self,
2673 worktree: &Entity<Worktree>,
2674 language_server_id: LanguageServerId,
2675 cx: &mut App,
2676 ) {
2677 let worktree = worktree.read(cx);
2678 let worktree_id = worktree.id();
2679 debug_assert!(!worktree.is_visible());
2680 let Some(mut origin_seed) = self
2681 .language_server_ids
2682 .iter()
2683 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2684 else {
2685 return;
2686 };
2687 origin_seed.worktree_id = worktree_id;
2688 self.language_server_ids
2689 .entry(origin_seed)
2690 .or_insert_with(|| UnifiedLanguageServer {
2691 id: language_server_id,
2692 project_roots: Default::default(),
2693 });
2694 }
2695
2696 fn register_buffer_with_language_servers(
2697 &mut self,
2698 buffer_handle: &Entity<Buffer>,
2699 only_register_servers: HashSet<LanguageServerSelector>,
2700 cx: &mut Context<LspStore>,
2701 ) {
2702 let buffer = buffer_handle.read(cx);
2703 let buffer_id = buffer.remote_id();
2704
2705 let Some(file) = File::from_dyn(buffer.file()) else {
2706 return;
2707 };
2708 if !file.is_local() {
2709 return;
2710 }
2711
2712 let abs_path = file.abs_path(cx);
2713 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2714 return;
2715 };
2716 let initial_snapshot = buffer.text_snapshot();
2717 let worktree_id = file.worktree_id(cx);
2718
2719 let Some(language) = buffer.language().cloned() else {
2720 return;
2721 };
2722 let path: Arc<RelPath> = file
2723 .path()
2724 .parent()
2725 .map(Arc::from)
2726 .unwrap_or_else(|| file.path().clone());
2727 let Some(worktree) = self
2728 .worktree_store
2729 .read(cx)
2730 .worktree_for_id(worktree_id, cx)
2731 else {
2732 return;
2733 };
2734 let language_name = language.name();
2735 let (reused, delegate, servers) = self
2736 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2737 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2738 .unwrap_or_else(|| {
2739 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2740 let delegate: Arc<dyn ManifestDelegate> =
2741 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2742
2743 let servers = self
2744 .lsp_tree
2745 .walk(
2746 ProjectPath { worktree_id, path },
2747 language.name(),
2748 language.manifest(),
2749 &delegate,
2750 cx,
2751 )
2752 .collect::<Vec<_>>();
2753 (false, lsp_delegate, servers)
2754 });
2755 let servers_and_adapters = servers
2756 .into_iter()
2757 .filter_map(|server_node| {
2758 if reused && server_node.server_id().is_none() {
2759 return None;
2760 }
2761 if !only_register_servers.is_empty() {
2762 if let Some(server_id) = server_node.server_id()
2763 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2764 {
2765 return None;
2766 }
2767 if let Some(name) = server_node.name()
2768 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2769 {
2770 return None;
2771 }
2772 }
2773
2774 let server_id = server_node.server_id_or_init(|disposition| {
2775 let path = &disposition.path;
2776
2777 {
2778 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2779
2780 let server_id = self.get_or_insert_language_server(
2781 &worktree,
2782 delegate.clone(),
2783 disposition,
2784 &language_name,
2785 cx,
2786 );
2787
2788 if let Some(state) = self.language_servers.get(&server_id)
2789 && let Ok(uri) = uri
2790 {
2791 state.add_workspace_folder(uri);
2792 };
2793 server_id
2794 }
2795 })?;
2796 let server_state = self.language_servers.get(&server_id)?;
2797 if let LanguageServerState::Running {
2798 server, adapter, ..
2799 } = server_state
2800 {
2801 Some((server.clone(), adapter.clone()))
2802 } else {
2803 None
2804 }
2805 })
2806 .collect::<Vec<_>>();
2807 for (server, adapter) in servers_and_adapters {
2808 buffer_handle.update(cx, |buffer, cx| {
2809 buffer.set_completion_triggers(
2810 server.server_id(),
2811 server
2812 .capabilities()
2813 .completion_provider
2814 .as_ref()
2815 .and_then(|provider| {
2816 provider
2817 .trigger_characters
2818 .as_ref()
2819 .map(|characters| characters.iter().cloned().collect())
2820 })
2821 .unwrap_or_default(),
2822 cx,
2823 );
2824 });
2825
2826 let snapshot = LspBufferSnapshot {
2827 version: 0,
2828 snapshot: initial_snapshot.clone(),
2829 };
2830
2831 let mut registered = false;
2832 self.buffer_snapshots
2833 .entry(buffer_id)
2834 .or_default()
2835 .entry(server.server_id())
2836 .or_insert_with(|| {
2837 registered = true;
2838 server.register_buffer(
2839 uri.clone(),
2840 adapter.language_id(&language.name()),
2841 0,
2842 initial_snapshot.text(),
2843 );
2844
2845 vec![snapshot]
2846 });
2847
2848 self.buffers_opened_in_servers
2849 .entry(buffer_id)
2850 .or_default()
2851 .insert(server.server_id());
2852 if registered {
2853 cx.emit(LspStoreEvent::LanguageServerUpdate {
2854 language_server_id: server.server_id(),
2855 name: None,
2856 message: proto::update_language_server::Variant::RegisteredForBuffer(
2857 proto::RegisteredForBuffer {
2858 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2859 buffer_id: buffer_id.to_proto(),
2860 },
2861 ),
2862 });
2863 }
2864 }
2865 }
2866
2867 fn reuse_existing_language_server<'lang_name>(
2868 &self,
2869 server_tree: &LanguageServerTree,
2870 worktree: &Entity<Worktree>,
2871 language_name: &'lang_name LanguageName,
2872 cx: &mut App,
2873 ) -> Option<(
2874 Arc<LocalLspAdapterDelegate>,
2875 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2876 )> {
2877 if worktree.read(cx).is_visible() {
2878 return None;
2879 }
2880
2881 let worktree_store = self.worktree_store.read(cx);
2882 let servers = server_tree
2883 .instances
2884 .iter()
2885 .filter(|(worktree_id, _)| {
2886 worktree_store
2887 .worktree_for_id(**worktree_id, cx)
2888 .is_some_and(|worktree| worktree.read(cx).is_visible())
2889 })
2890 .flat_map(|(worktree_id, servers)| {
2891 servers
2892 .roots
2893 .iter()
2894 .flat_map(|(_, language_servers)| language_servers)
2895 .map(move |(_, (server_node, server_languages))| {
2896 (worktree_id, server_node, server_languages)
2897 })
2898 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2899 .map(|(worktree_id, server_node, _)| {
2900 (
2901 *worktree_id,
2902 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2903 )
2904 })
2905 })
2906 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2907 acc.entry(worktree_id)
2908 .or_insert_with(Vec::new)
2909 .push(server_node);
2910 acc
2911 })
2912 .into_values()
2913 .max_by_key(|servers| servers.len())?;
2914
2915 let worktree_id = worktree.read(cx).id();
2916 let apply = move |tree: &mut LanguageServerTree| {
2917 for server_node in &servers {
2918 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2919 }
2920 servers
2921 };
2922
2923 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2924 Some((delegate, apply))
2925 }
2926
2927 pub(crate) fn unregister_old_buffer_from_language_servers(
2928 &mut self,
2929 buffer: &Entity<Buffer>,
2930 old_file: &File,
2931 cx: &mut App,
2932 ) {
2933 let old_path = match old_file.as_local() {
2934 Some(local) => local.abs_path(cx),
2935 None => return,
2936 };
2937
2938 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2939 debug_panic!("{old_path:?} is not parseable as an URI");
2940 return;
2941 };
2942 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2943 }
2944
2945 pub(crate) fn unregister_buffer_from_language_servers(
2946 &mut self,
2947 buffer: &Entity<Buffer>,
2948 file_url: &lsp::Uri,
2949 cx: &mut App,
2950 ) {
2951 buffer.update(cx, |buffer, cx| {
2952 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2953
2954 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2955 if snapshots
2956 .as_mut()
2957 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2958 {
2959 language_server.unregister_buffer(file_url.clone());
2960 }
2961 }
2962 });
2963 }
2964
2965 fn buffer_snapshot_for_lsp_version(
2966 &mut self,
2967 buffer: &Entity<Buffer>,
2968 server_id: LanguageServerId,
2969 version: Option<i32>,
2970 cx: &App,
2971 ) -> Result<TextBufferSnapshot> {
2972 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2973
2974 if let Some(version) = version {
2975 let buffer_id = buffer.read(cx).remote_id();
2976 let snapshots = if let Some(snapshots) = self
2977 .buffer_snapshots
2978 .get_mut(&buffer_id)
2979 .and_then(|m| m.get_mut(&server_id))
2980 {
2981 snapshots
2982 } else if version == 0 {
2983 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2984 // We detect this case and treat it as if the version was `None`.
2985 return Ok(buffer.read(cx).text_snapshot());
2986 } else {
2987 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2988 };
2989
2990 let found_snapshot = snapshots
2991 .binary_search_by_key(&version, |e| e.version)
2992 .map(|ix| snapshots[ix].snapshot.clone())
2993 .map_err(|_| {
2994 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2995 })?;
2996
2997 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2998 Ok(found_snapshot)
2999 } else {
3000 Ok((buffer.read(cx)).text_snapshot())
3001 }
3002 }
3003
3004 async fn get_server_code_actions_from_action_kinds(
3005 lsp_store: &WeakEntity<LspStore>,
3006 language_server_id: LanguageServerId,
3007 code_action_kinds: Vec<lsp::CodeActionKind>,
3008 buffer: &Entity<Buffer>,
3009 cx: &mut AsyncApp,
3010 ) -> Result<Vec<CodeAction>> {
3011 let actions = lsp_store
3012 .update(cx, move |this, cx| {
3013 let request = GetCodeActions {
3014 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3015 kinds: Some(code_action_kinds),
3016 };
3017 let server = LanguageServerToQuery::Other(language_server_id);
3018 this.request_lsp(buffer.clone(), server, request, cx)
3019 })?
3020 .await?;
3021 Ok(actions)
3022 }
3023
3024 pub async fn execute_code_actions_on_server(
3025 lsp_store: &WeakEntity<LspStore>,
3026 language_server: &Arc<LanguageServer>,
3027 actions: Vec<CodeAction>,
3028 push_to_history: bool,
3029 project_transaction: &mut ProjectTransaction,
3030 cx: &mut AsyncApp,
3031 ) -> anyhow::Result<()> {
3032 let request_timeout = cx.update(|app| {
3033 ProjectSettings::get_global(app)
3034 .global_lsp_settings
3035 .get_request_timeout()
3036 });
3037
3038 for mut action in actions {
3039 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3040 .await
3041 .context("resolving a formatting code action")?;
3042
3043 if let Some(edit) = action.lsp_action.edit() {
3044 if edit.changes.is_none() && edit.document_changes.is_none() {
3045 continue;
3046 }
3047
3048 let new = Self::deserialize_workspace_edit(
3049 lsp_store.upgrade().context("project dropped")?,
3050 edit.clone(),
3051 push_to_history,
3052 language_server.clone(),
3053 cx,
3054 )
3055 .await?;
3056 project_transaction.0.extend(new.0);
3057 }
3058
3059 let Some(command) = action.lsp_action.command() else {
3060 continue;
3061 };
3062
3063 let server_capabilities = language_server.capabilities();
3064 let available_commands = server_capabilities
3065 .execute_command_provider
3066 .as_ref()
3067 .map(|options| options.commands.as_slice())
3068 .unwrap_or_default();
3069 if !available_commands.contains(&command.command) {
3070 log::warn!(
3071 "Cannot execute a command {} not listed in the language server capabilities",
3072 command.command
3073 );
3074 continue;
3075 }
3076
3077 lsp_store.update(cx, |lsp_store, _| {
3078 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3079 mode.last_workspace_edits_by_language_server
3080 .remove(&language_server.server_id());
3081 }
3082 })?;
3083
3084 language_server
3085 .request::<lsp::request::ExecuteCommand>(
3086 lsp::ExecuteCommandParams {
3087 command: command.command.clone(),
3088 arguments: command.arguments.clone().unwrap_or_default(),
3089 ..Default::default()
3090 },
3091 request_timeout,
3092 )
3093 .await
3094 .into_response()
3095 .context("execute command")?;
3096
3097 lsp_store.update(cx, |this, _| {
3098 if let LspStoreMode::Local(mode) = &mut this.mode {
3099 project_transaction.0.extend(
3100 mode.last_workspace_edits_by_language_server
3101 .remove(&language_server.server_id())
3102 .unwrap_or_default()
3103 .0,
3104 )
3105 }
3106 })?;
3107 }
3108 Ok(())
3109 }
3110
3111 pub async fn deserialize_text_edits(
3112 this: Entity<LspStore>,
3113 buffer_to_edit: Entity<Buffer>,
3114 edits: Vec<lsp::TextEdit>,
3115 push_to_history: bool,
3116 _: Arc<CachedLspAdapter>,
3117 language_server: Arc<LanguageServer>,
3118 cx: &mut AsyncApp,
3119 ) -> Result<Option<Transaction>> {
3120 let edits = this
3121 .update(cx, |this, cx| {
3122 this.as_local_mut().unwrap().edits_from_lsp(
3123 &buffer_to_edit,
3124 edits,
3125 language_server.server_id(),
3126 None,
3127 cx,
3128 )
3129 })
3130 .await?;
3131
3132 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3133 buffer.finalize_last_transaction();
3134 buffer.start_transaction();
3135 for (range, text) in edits {
3136 buffer.edit([(range, text)], None, cx);
3137 }
3138
3139 if buffer.end_transaction(cx).is_some() {
3140 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3141 if !push_to_history {
3142 buffer.forget_transaction(transaction.id);
3143 }
3144 Some(transaction)
3145 } else {
3146 None
3147 }
3148 });
3149
3150 Ok(transaction)
3151 }
3152
3153 #[allow(clippy::type_complexity)]
3154 pub fn edits_from_lsp(
3155 &mut self,
3156 buffer: &Entity<Buffer>,
3157 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3158 server_id: LanguageServerId,
3159 version: Option<i32>,
3160 cx: &mut Context<LspStore>,
3161 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3162 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3163 cx.background_spawn(async move {
3164 let snapshot = snapshot?;
3165 let mut lsp_edits = lsp_edits
3166 .into_iter()
3167 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3168 .collect::<Vec<_>>();
3169
3170 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3171
3172 let mut lsp_edits = lsp_edits.into_iter().peekable();
3173 let mut edits = Vec::new();
3174 while let Some((range, mut new_text)) = lsp_edits.next() {
3175 // Clip invalid ranges provided by the language server.
3176 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3177 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3178
3179 // Combine any LSP edits that are adjacent.
3180 //
3181 // Also, combine LSP edits that are separated from each other by only
3182 // a newline. This is important because for some code actions,
3183 // Rust-analyzer rewrites the entire buffer via a series of edits that
3184 // are separated by unchanged newline characters.
3185 //
3186 // In order for the diffing logic below to work properly, any edits that
3187 // cancel each other out must be combined into one.
3188 while let Some((next_range, next_text)) = lsp_edits.peek() {
3189 if next_range.start.0 > range.end {
3190 if next_range.start.0.row > range.end.row + 1
3191 || next_range.start.0.column > 0
3192 || snapshot.clip_point_utf16(
3193 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3194 Bias::Left,
3195 ) > range.end
3196 {
3197 break;
3198 }
3199 new_text.push('\n');
3200 }
3201 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3202 new_text.push_str(next_text);
3203 lsp_edits.next();
3204 }
3205
3206 // For multiline edits, perform a diff of the old and new text so that
3207 // we can identify the changes more precisely, preserving the locations
3208 // of any anchors positioned in the unchanged regions.
3209 if range.end.row > range.start.row {
3210 let offset = range.start.to_offset(&snapshot);
3211 let old_text = snapshot.text_for_range(range).collect::<String>();
3212 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3213 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3214 (
3215 snapshot.anchor_after(offset + range.start)
3216 ..snapshot.anchor_before(offset + range.end),
3217 replacement,
3218 )
3219 }));
3220 } else if range.end == range.start {
3221 let anchor = snapshot.anchor_after(range.start);
3222 edits.push((anchor..anchor, new_text.into()));
3223 } else {
3224 let edit_start = snapshot.anchor_after(range.start);
3225 let edit_end = snapshot.anchor_before(range.end);
3226 edits.push((edit_start..edit_end, new_text.into()));
3227 }
3228 }
3229
3230 Ok(edits)
3231 })
3232 }
3233
3234 pub(crate) async fn deserialize_workspace_edit(
3235 this: Entity<LspStore>,
3236 edit: lsp::WorkspaceEdit,
3237 push_to_history: bool,
3238 language_server: Arc<LanguageServer>,
3239 cx: &mut AsyncApp,
3240 ) -> Result<ProjectTransaction> {
3241 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3242
3243 let mut operations = Vec::new();
3244 if let Some(document_changes) = edit.document_changes {
3245 match document_changes {
3246 lsp::DocumentChanges::Edits(edits) => {
3247 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3248 }
3249 lsp::DocumentChanges::Operations(ops) => operations = ops,
3250 }
3251 } else if let Some(changes) = edit.changes {
3252 operations.extend(changes.into_iter().map(|(uri, edits)| {
3253 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3254 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3255 uri,
3256 version: None,
3257 },
3258 edits: edits.into_iter().map(Edit::Plain).collect(),
3259 })
3260 }));
3261 }
3262
3263 let mut project_transaction = ProjectTransaction::default();
3264 for operation in operations {
3265 match operation {
3266 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3267 let abs_path = op
3268 .uri
3269 .to_file_path()
3270 .map_err(|()| anyhow!("can't convert URI to path"))?;
3271
3272 if let Some(parent_path) = abs_path.parent() {
3273 fs.create_dir(parent_path).await?;
3274 }
3275 if abs_path.ends_with("/") {
3276 fs.create_dir(&abs_path).await?;
3277 } else {
3278 fs.create_file(
3279 &abs_path,
3280 op.options
3281 .map(|options| fs::CreateOptions {
3282 overwrite: options.overwrite.unwrap_or(false),
3283 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3284 })
3285 .unwrap_or_default(),
3286 )
3287 .await?;
3288 }
3289 }
3290
3291 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3292 let source_abs_path = op
3293 .old_uri
3294 .to_file_path()
3295 .map_err(|()| anyhow!("can't convert URI to path"))?;
3296 let target_abs_path = op
3297 .new_uri
3298 .to_file_path()
3299 .map_err(|()| anyhow!("can't convert URI to path"))?;
3300
3301 let options = fs::RenameOptions {
3302 overwrite: op
3303 .options
3304 .as_ref()
3305 .and_then(|options| options.overwrite)
3306 .unwrap_or(false),
3307 ignore_if_exists: op
3308 .options
3309 .as_ref()
3310 .and_then(|options| options.ignore_if_exists)
3311 .unwrap_or(false),
3312 create_parents: true,
3313 };
3314
3315 fs.rename(&source_abs_path, &target_abs_path, options)
3316 .await?;
3317 }
3318
3319 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3320 let abs_path = op
3321 .uri
3322 .to_file_path()
3323 .map_err(|()| anyhow!("can't convert URI to path"))?;
3324 let options = op
3325 .options
3326 .map(|options| fs::RemoveOptions {
3327 recursive: options.recursive.unwrap_or(false),
3328 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3329 })
3330 .unwrap_or_default();
3331 if abs_path.ends_with("/") {
3332 fs.remove_dir(&abs_path, options).await?;
3333 } else {
3334 fs.remove_file(&abs_path, options).await?;
3335 }
3336 }
3337
3338 lsp::DocumentChangeOperation::Edit(op) => {
3339 let buffer_to_edit = this
3340 .update(cx, |this, cx| {
3341 this.open_local_buffer_via_lsp(
3342 op.text_document.uri.clone(),
3343 language_server.server_id(),
3344 cx,
3345 )
3346 })
3347 .await?;
3348
3349 let edits = this
3350 .update(cx, |this, cx| {
3351 let path = buffer_to_edit.read(cx).project_path(cx);
3352 let active_entry = this.active_entry;
3353 let is_active_entry = path.is_some_and(|project_path| {
3354 this.worktree_store
3355 .read(cx)
3356 .entry_for_path(&project_path, cx)
3357 .is_some_and(|entry| Some(entry.id) == active_entry)
3358 });
3359 let local = this.as_local_mut().unwrap();
3360
3361 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3362 for edit in op.edits {
3363 match edit {
3364 Edit::Plain(edit) => {
3365 if !edits.contains(&edit) {
3366 edits.push(edit)
3367 }
3368 }
3369 Edit::Annotated(edit) => {
3370 if !edits.contains(&edit.text_edit) {
3371 edits.push(edit.text_edit)
3372 }
3373 }
3374 Edit::Snippet(edit) => {
3375 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3376 else {
3377 continue;
3378 };
3379
3380 if is_active_entry {
3381 snippet_edits.push((edit.range, snippet));
3382 } else {
3383 // Since this buffer is not focused, apply a normal edit.
3384 let new_edit = TextEdit {
3385 range: edit.range,
3386 new_text: snippet.text,
3387 };
3388 if !edits.contains(&new_edit) {
3389 edits.push(new_edit);
3390 }
3391 }
3392 }
3393 }
3394 }
3395 if !snippet_edits.is_empty() {
3396 let buffer_id = buffer_to_edit.read(cx).remote_id();
3397 let version = if let Some(buffer_version) = op.text_document.version
3398 {
3399 local
3400 .buffer_snapshot_for_lsp_version(
3401 &buffer_to_edit,
3402 language_server.server_id(),
3403 Some(buffer_version),
3404 cx,
3405 )
3406 .ok()
3407 .map(|snapshot| snapshot.version)
3408 } else {
3409 Some(buffer_to_edit.read(cx).saved_version().clone())
3410 };
3411
3412 let most_recent_edit =
3413 version.and_then(|version| version.most_recent());
3414 // Check if the edit that triggered that edit has been made by this participant.
3415
3416 if let Some(most_recent_edit) = most_recent_edit {
3417 cx.emit(LspStoreEvent::SnippetEdit {
3418 buffer_id,
3419 edits: snippet_edits,
3420 most_recent_edit,
3421 });
3422 }
3423 }
3424
3425 local.edits_from_lsp(
3426 &buffer_to_edit,
3427 edits,
3428 language_server.server_id(),
3429 op.text_document.version,
3430 cx,
3431 )
3432 })
3433 .await?;
3434
3435 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3436 buffer.finalize_last_transaction();
3437 buffer.start_transaction();
3438 for (range, text) in edits {
3439 buffer.edit([(range, text)], None, cx);
3440 }
3441
3442 buffer.end_transaction(cx).and_then(|transaction_id| {
3443 if push_to_history {
3444 buffer.finalize_last_transaction();
3445 buffer.get_transaction(transaction_id).cloned()
3446 } else {
3447 buffer.forget_transaction(transaction_id)
3448 }
3449 })
3450 });
3451 if let Some(transaction) = transaction {
3452 project_transaction.0.insert(buffer_to_edit, transaction);
3453 }
3454 }
3455 }
3456 }
3457
3458 Ok(project_transaction)
3459 }
3460
3461 async fn on_lsp_workspace_edit(
3462 this: WeakEntity<LspStore>,
3463 params: lsp::ApplyWorkspaceEditParams,
3464 server_id: LanguageServerId,
3465 cx: &mut AsyncApp,
3466 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3467 let this = this.upgrade().context("project project closed")?;
3468 let language_server = this
3469 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3470 .context("language server not found")?;
3471 let transaction = Self::deserialize_workspace_edit(
3472 this.clone(),
3473 params.edit,
3474 true,
3475 language_server.clone(),
3476 cx,
3477 )
3478 .await
3479 .log_err();
3480 this.update(cx, |this, cx| {
3481 if let Some(transaction) = transaction {
3482 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3483
3484 this.as_local_mut()
3485 .unwrap()
3486 .last_workspace_edits_by_language_server
3487 .insert(server_id, transaction);
3488 }
3489 });
3490 Ok(lsp::ApplyWorkspaceEditResponse {
3491 applied: true,
3492 failed_change: None,
3493 failure_reason: None,
3494 })
3495 }
3496
3497 fn remove_worktree(
3498 &mut self,
3499 id_to_remove: WorktreeId,
3500 cx: &mut Context<LspStore>,
3501 ) -> Vec<LanguageServerId> {
3502 self.restricted_worktrees_tasks.remove(&id_to_remove);
3503 self.diagnostics.remove(&id_to_remove);
3504 self.prettier_store.update(cx, |prettier_store, cx| {
3505 prettier_store.remove_worktree(id_to_remove, cx);
3506 });
3507
3508 let mut servers_to_remove = BTreeSet::default();
3509 let mut servers_to_preserve = HashSet::default();
3510 for (seed, state) in &self.language_server_ids {
3511 if seed.worktree_id == id_to_remove {
3512 servers_to_remove.insert(state.id);
3513 } else {
3514 servers_to_preserve.insert(state.id);
3515 }
3516 }
3517 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3518 self.language_server_ids
3519 .retain(|_, state| !servers_to_remove.contains(&state.id));
3520 for server_id_to_remove in &servers_to_remove {
3521 self.language_server_watched_paths
3522 .remove(server_id_to_remove);
3523 self.language_server_paths_watched_for_rename
3524 .remove(server_id_to_remove);
3525 self.last_workspace_edits_by_language_server
3526 .remove(server_id_to_remove);
3527 self.language_servers.remove(server_id_to_remove);
3528 self.buffer_pull_diagnostics_result_ids
3529 .remove(server_id_to_remove);
3530 self.workspace_pull_diagnostics_result_ids
3531 .remove(server_id_to_remove);
3532 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3533 buffer_servers.remove(server_id_to_remove);
3534 }
3535 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3536 }
3537 servers_to_remove.into_iter().collect()
3538 }
3539
3540 fn rebuild_watched_paths_inner<'a>(
3541 &'a self,
3542 language_server_id: LanguageServerId,
3543 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3544 cx: &mut Context<LspStore>,
3545 ) -> LanguageServerWatchedPathsBuilder {
3546 let worktrees = self
3547 .worktree_store
3548 .read(cx)
3549 .worktrees()
3550 .filter_map(|worktree| {
3551 self.language_servers_for_worktree(worktree.read(cx).id())
3552 .find(|server| server.server_id() == language_server_id)
3553 .map(|_| worktree)
3554 })
3555 .collect::<Vec<_>>();
3556
3557 let mut worktree_globs = HashMap::default();
3558 let mut abs_globs = HashMap::default();
3559 log::trace!(
3560 "Processing new watcher paths for language server with id {}",
3561 language_server_id
3562 );
3563
3564 for watcher in watchers {
3565 if let Some((worktree, literal_prefix, pattern)) =
3566 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3567 {
3568 worktree.update(cx, |worktree, _| {
3569 if let Some((tree, glob)) =
3570 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3571 {
3572 tree.add_path_prefix_to_scan(literal_prefix);
3573 worktree_globs
3574 .entry(tree.id())
3575 .or_insert_with(GlobSetBuilder::new)
3576 .add(glob);
3577 }
3578 });
3579 } else {
3580 let (path, pattern) = match &watcher.glob_pattern {
3581 lsp::GlobPattern::String(s) => {
3582 let watcher_path = SanitizedPath::new(s);
3583 let path = glob_literal_prefix(watcher_path.as_path());
3584 let pattern = watcher_path
3585 .as_path()
3586 .strip_prefix(&path)
3587 .map(|p| p.to_string_lossy().into_owned())
3588 .unwrap_or_else(|e| {
3589 debug_panic!(
3590 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3591 s,
3592 path.display(),
3593 e
3594 );
3595 watcher_path.as_path().to_string_lossy().into_owned()
3596 });
3597 (path, pattern)
3598 }
3599 lsp::GlobPattern::Relative(rp) => {
3600 let Ok(mut base_uri) = match &rp.base_uri {
3601 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3602 lsp::OneOf::Right(base_uri) => base_uri,
3603 }
3604 .to_file_path() else {
3605 continue;
3606 };
3607
3608 let path = glob_literal_prefix(Path::new(&rp.pattern));
3609 let pattern = Path::new(&rp.pattern)
3610 .strip_prefix(&path)
3611 .map(|p| p.to_string_lossy().into_owned())
3612 .unwrap_or_else(|e| {
3613 debug_panic!(
3614 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3615 rp.pattern,
3616 path.display(),
3617 e
3618 );
3619 rp.pattern.clone()
3620 });
3621 base_uri.push(path);
3622 (base_uri, pattern)
3623 }
3624 };
3625
3626 if let Some(glob) = Glob::new(&pattern).log_err() {
3627 if !path
3628 .components()
3629 .any(|c| matches!(c, path::Component::Normal(_)))
3630 {
3631 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3632 // rather than adding a new watcher for `/`.
3633 for worktree in &worktrees {
3634 worktree_globs
3635 .entry(worktree.read(cx).id())
3636 .or_insert_with(GlobSetBuilder::new)
3637 .add(glob.clone());
3638 }
3639 } else {
3640 abs_globs
3641 .entry(path.into())
3642 .or_insert_with(GlobSetBuilder::new)
3643 .add(glob);
3644 }
3645 }
3646 }
3647 }
3648
3649 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3650 for (worktree_id, builder) in worktree_globs {
3651 if let Ok(globset) = builder.build() {
3652 watch_builder.watch_worktree(worktree_id, globset);
3653 }
3654 }
3655 for (abs_path, builder) in abs_globs {
3656 if let Ok(globset) = builder.build() {
3657 watch_builder.watch_abs_path(abs_path, globset);
3658 }
3659 }
3660 watch_builder
3661 }
3662
3663 fn worktree_and_path_for_file_watcher(
3664 worktrees: &[Entity<Worktree>],
3665 watcher: &FileSystemWatcher,
3666 cx: &App,
3667 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3668 worktrees.iter().find_map(|worktree| {
3669 let tree = worktree.read(cx);
3670 let worktree_root_path = tree.abs_path();
3671 let path_style = tree.path_style();
3672 match &watcher.glob_pattern {
3673 lsp::GlobPattern::String(s) => {
3674 let watcher_path = SanitizedPath::new(s);
3675 let relative = watcher_path
3676 .as_path()
3677 .strip_prefix(&worktree_root_path)
3678 .ok()?;
3679 let literal_prefix = glob_literal_prefix(relative);
3680 Some((
3681 worktree.clone(),
3682 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3683 relative.to_string_lossy().into_owned(),
3684 ))
3685 }
3686 lsp::GlobPattern::Relative(rp) => {
3687 let base_uri = match &rp.base_uri {
3688 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3689 lsp::OneOf::Right(base_uri) => base_uri,
3690 }
3691 .to_file_path()
3692 .ok()?;
3693 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3694 let mut literal_prefix = relative.to_owned();
3695 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3696 Some((
3697 worktree.clone(),
3698 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3699 rp.pattern.clone(),
3700 ))
3701 }
3702 }
3703 })
3704 }
3705
3706 fn rebuild_watched_paths(
3707 &mut self,
3708 language_server_id: LanguageServerId,
3709 cx: &mut Context<LspStore>,
3710 ) {
3711 let Some(registrations) = self
3712 .language_server_dynamic_registrations
3713 .get(&language_server_id)
3714 else {
3715 return;
3716 };
3717
3718 let watch_builder = self.rebuild_watched_paths_inner(
3719 language_server_id,
3720 registrations.did_change_watched_files.values().flatten(),
3721 cx,
3722 );
3723 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3724 self.language_server_watched_paths
3725 .insert(language_server_id, watcher);
3726
3727 cx.notify();
3728 }
3729
3730 fn on_lsp_did_change_watched_files(
3731 &mut self,
3732 language_server_id: LanguageServerId,
3733 registration_id: &str,
3734 params: DidChangeWatchedFilesRegistrationOptions,
3735 cx: &mut Context<LspStore>,
3736 ) {
3737 let registrations = self
3738 .language_server_dynamic_registrations
3739 .entry(language_server_id)
3740 .or_default();
3741
3742 registrations
3743 .did_change_watched_files
3744 .insert(registration_id.to_string(), params.watchers);
3745
3746 self.rebuild_watched_paths(language_server_id, cx);
3747 }
3748
3749 fn on_lsp_unregister_did_change_watched_files(
3750 &mut self,
3751 language_server_id: LanguageServerId,
3752 registration_id: &str,
3753 cx: &mut Context<LspStore>,
3754 ) {
3755 let registrations = self
3756 .language_server_dynamic_registrations
3757 .entry(language_server_id)
3758 .or_default();
3759
3760 if registrations
3761 .did_change_watched_files
3762 .remove(registration_id)
3763 .is_some()
3764 {
3765 log::info!(
3766 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3767 language_server_id,
3768 registration_id
3769 );
3770 } else {
3771 log::warn!(
3772 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3773 language_server_id,
3774 registration_id
3775 );
3776 }
3777
3778 self.rebuild_watched_paths(language_server_id, cx);
3779 }
3780
3781 async fn initialization_options_for_adapter(
3782 adapter: Arc<dyn LspAdapter>,
3783 delegate: &Arc<dyn LspAdapterDelegate>,
3784 cx: &mut AsyncApp,
3785 ) -> Result<Option<serde_json::Value>> {
3786 let Some(mut initialization_config) =
3787 adapter.clone().initialization_options(delegate, cx).await?
3788 else {
3789 return Ok(None);
3790 };
3791
3792 for other_adapter in delegate.registered_lsp_adapters() {
3793 if other_adapter.name() == adapter.name() {
3794 continue;
3795 }
3796 if let Ok(Some(target_config)) = other_adapter
3797 .clone()
3798 .additional_initialization_options(adapter.name(), delegate)
3799 .await
3800 {
3801 merge_json_value_into(target_config.clone(), &mut initialization_config);
3802 }
3803 }
3804
3805 Ok(Some(initialization_config))
3806 }
3807
3808 async fn workspace_configuration_for_adapter(
3809 adapter: Arc<dyn LspAdapter>,
3810 delegate: &Arc<dyn LspAdapterDelegate>,
3811 toolchain: Option<Toolchain>,
3812 requested_uri: Option<Uri>,
3813 cx: &mut AsyncApp,
3814 ) -> Result<serde_json::Value> {
3815 let mut workspace_config = adapter
3816 .clone()
3817 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3818 .await?;
3819
3820 for other_adapter in delegate.registered_lsp_adapters() {
3821 if other_adapter.name() == adapter.name() {
3822 continue;
3823 }
3824 if let Ok(Some(target_config)) = other_adapter
3825 .clone()
3826 .additional_workspace_configuration(adapter.name(), delegate, cx)
3827 .await
3828 {
3829 merge_json_value_into(target_config.clone(), &mut workspace_config);
3830 }
3831 }
3832
3833 Ok(workspace_config)
3834 }
3835
3836 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3837 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3838 Some(server.clone())
3839 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3840 Some(Arc::clone(server))
3841 } else {
3842 None
3843 }
3844 }
3845}
3846
3847fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3848 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3849 cx.emit(LspStoreEvent::LanguageServerUpdate {
3850 language_server_id: server.server_id(),
3851 name: Some(server.name()),
3852 message: proto::update_language_server::Variant::MetadataUpdated(
3853 proto::ServerMetadataUpdated {
3854 capabilities: Some(capabilities),
3855 binary: Some(proto::LanguageServerBinaryInfo {
3856 path: server.binary().path.to_string_lossy().into_owned(),
3857 arguments: server
3858 .binary()
3859 .arguments
3860 .iter()
3861 .map(|arg| arg.to_string_lossy().into_owned())
3862 .collect(),
3863 }),
3864 configuration: serde_json::to_string(server.configuration()).ok(),
3865 workspace_folders: server
3866 .workspace_folders()
3867 .iter()
3868 .map(|uri| uri.to_string())
3869 .collect(),
3870 },
3871 ),
3872 });
3873 }
3874}
3875
3876#[derive(Debug)]
3877pub struct FormattableBuffer {
3878 handle: Entity<Buffer>,
3879 abs_path: Option<PathBuf>,
3880 env: Option<HashMap<String, String>>,
3881 ranges: Option<Vec<Range<Anchor>>>,
3882}
3883
3884pub struct RemoteLspStore {
3885 upstream_client: Option<AnyProtoClient>,
3886 upstream_project_id: u64,
3887}
3888
3889pub(crate) enum LspStoreMode {
3890 Local(LocalLspStore), // ssh host and collab host
3891 Remote(RemoteLspStore), // collab guest
3892}
3893
3894impl LspStoreMode {
3895 fn is_local(&self) -> bool {
3896 matches!(self, LspStoreMode::Local(_))
3897 }
3898}
3899
3900pub struct LspStore {
3901 mode: LspStoreMode,
3902 last_formatting_failure: Option<String>,
3903 downstream_client: Option<(AnyProtoClient, u64)>,
3904 nonce: u128,
3905 buffer_store: Entity<BufferStore>,
3906 worktree_store: Entity<WorktreeStore>,
3907 pub languages: Arc<LanguageRegistry>,
3908 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3909 active_entry: Option<ProjectEntryId>,
3910 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3911 _maintain_buffer_languages: Task<()>,
3912 diagnostic_summaries:
3913 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3914 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3915 semantic_token_config: SemanticTokenConfig,
3916 lsp_data: HashMap<BufferId, BufferLspData>,
3917 next_hint_id: Arc<AtomicUsize>,
3918}
3919
3920#[derive(Debug)]
3921pub struct BufferLspData {
3922 buffer_version: Global,
3923 document_colors: Option<DocumentColorData>,
3924 code_lens: Option<CodeLensData>,
3925 semantic_tokens: Option<SemanticTokensData>,
3926 folding_ranges: Option<FoldingRangeData>,
3927 document_symbols: Option<DocumentSymbolsData>,
3928 inlay_hints: BufferInlayHints,
3929 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3930 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3931}
3932
3933#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3934struct LspKey {
3935 request_type: TypeId,
3936 server_queried: Option<LanguageServerId>,
3937}
3938
3939impl BufferLspData {
3940 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3941 Self {
3942 buffer_version: buffer.read(cx).version(),
3943 document_colors: None,
3944 code_lens: None,
3945 semantic_tokens: None,
3946 folding_ranges: None,
3947 document_symbols: None,
3948 inlay_hints: BufferInlayHints::new(buffer, cx),
3949 lsp_requests: HashMap::default(),
3950 chunk_lsp_requests: HashMap::default(),
3951 }
3952 }
3953
3954 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3955 if let Some(document_colors) = &mut self.document_colors {
3956 document_colors.remove_server_data(for_server);
3957 }
3958
3959 if let Some(code_lens) = &mut self.code_lens {
3960 code_lens.remove_server_data(for_server);
3961 }
3962
3963 self.inlay_hints.remove_server_data(for_server);
3964
3965 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3966 semantic_tokens.remove_server_data(for_server);
3967 }
3968
3969 if let Some(folding_ranges) = &mut self.folding_ranges {
3970 folding_ranges.ranges.remove(&for_server);
3971 }
3972
3973 if let Some(document_symbols) = &mut self.document_symbols {
3974 document_symbols.remove_server_data(for_server);
3975 }
3976 }
3977
3978 #[cfg(any(test, feature = "test-support"))]
3979 pub fn inlay_hints(&self) -> &BufferInlayHints {
3980 &self.inlay_hints
3981 }
3982}
3983
3984#[derive(Debug)]
3985pub enum LspStoreEvent {
3986 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3987 LanguageServerRemoved(LanguageServerId),
3988 LanguageServerUpdate {
3989 language_server_id: LanguageServerId,
3990 name: Option<LanguageServerName>,
3991 message: proto::update_language_server::Variant,
3992 },
3993 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3994 LanguageServerPrompt(LanguageServerPromptRequest),
3995 LanguageDetected {
3996 buffer: Entity<Buffer>,
3997 new_language: Option<Arc<Language>>,
3998 },
3999 Notification(String),
4000 RefreshInlayHints {
4001 server_id: LanguageServerId,
4002 request_id: Option<usize>,
4003 },
4004 RefreshSemanticTokens {
4005 server_id: LanguageServerId,
4006 request_id: Option<usize>,
4007 },
4008 RefreshCodeLens,
4009 DiagnosticsUpdated {
4010 server_id: LanguageServerId,
4011 paths: Vec<ProjectPath>,
4012 },
4013 DiskBasedDiagnosticsStarted {
4014 language_server_id: LanguageServerId,
4015 },
4016 DiskBasedDiagnosticsFinished {
4017 language_server_id: LanguageServerId,
4018 },
4019 SnippetEdit {
4020 buffer_id: BufferId,
4021 edits: Vec<(lsp::Range, Snippet)>,
4022 most_recent_edit: clock::Lamport,
4023 },
4024 WorkspaceEditApplied(ProjectTransaction),
4025}
4026
4027#[derive(Clone, Debug, Serialize)]
4028pub struct LanguageServerStatus {
4029 pub name: LanguageServerName,
4030 pub server_version: Option<SharedString>,
4031 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4032 pub has_pending_diagnostic_updates: bool,
4033 pub progress_tokens: HashSet<ProgressToken>,
4034 pub worktree: Option<WorktreeId>,
4035 pub binary: Option<LanguageServerBinary>,
4036 pub configuration: Option<Value>,
4037 pub workspace_folders: BTreeSet<Uri>,
4038 pub process_id: Option<u32>,
4039}
4040
4041#[derive(Clone, Debug)]
4042struct CoreSymbol {
4043 pub language_server_name: LanguageServerName,
4044 pub source_worktree_id: WorktreeId,
4045 pub source_language_server_id: LanguageServerId,
4046 pub path: SymbolLocation,
4047 pub name: String,
4048 pub kind: lsp::SymbolKind,
4049 pub range: Range<Unclipped<PointUtf16>>,
4050 pub container_name: Option<String>,
4051}
4052
4053#[derive(Clone, Debug, PartialEq, Eq)]
4054pub enum SymbolLocation {
4055 InProject(ProjectPath),
4056 OutsideProject {
4057 abs_path: Arc<Path>,
4058 signature: [u8; 32],
4059 },
4060}
4061
4062impl SymbolLocation {
4063 fn file_name(&self) -> Option<&str> {
4064 match self {
4065 Self::InProject(path) => path.path.file_name(),
4066 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4067 }
4068 }
4069}
4070
4071impl LspStore {
4072 pub fn init(client: &AnyProtoClient) {
4073 client.add_entity_request_handler(Self::handle_lsp_query);
4074 client.add_entity_message_handler(Self::handle_lsp_query_response);
4075 client.add_entity_request_handler(Self::handle_restart_language_servers);
4076 client.add_entity_request_handler(Self::handle_stop_language_servers);
4077 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4078 client.add_entity_message_handler(Self::handle_start_language_server);
4079 client.add_entity_message_handler(Self::handle_update_language_server);
4080 client.add_entity_message_handler(Self::handle_language_server_log);
4081 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4082 client.add_entity_request_handler(Self::handle_format_buffers);
4083 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4084 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4085 client.add_entity_request_handler(Self::handle_apply_code_action);
4086 client.add_entity_request_handler(Self::handle_get_project_symbols);
4087 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4088 client.add_entity_request_handler(Self::handle_get_color_presentation);
4089 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4090 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4091 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4092 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4093 client.add_entity_request_handler(Self::handle_on_type_formatting);
4094 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4095 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4096 client.add_entity_request_handler(Self::handle_rename_project_entry);
4097 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4098 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4099 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4100 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4101 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4102 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4103 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4104
4105 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4106 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4107 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4108 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4109 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4110 client.add_entity_request_handler(
4111 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4112 );
4113 client.add_entity_request_handler(
4114 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4115 );
4116 client.add_entity_request_handler(
4117 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4118 );
4119 }
4120
4121 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4122 match &self.mode {
4123 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4124 _ => None,
4125 }
4126 }
4127
4128 pub fn as_local(&self) -> Option<&LocalLspStore> {
4129 match &self.mode {
4130 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4131 _ => None,
4132 }
4133 }
4134
4135 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4136 match &mut self.mode {
4137 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4138 _ => None,
4139 }
4140 }
4141
4142 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4143 match &self.mode {
4144 LspStoreMode::Remote(RemoteLspStore {
4145 upstream_client: Some(upstream_client),
4146 upstream_project_id,
4147 ..
4148 }) => Some((upstream_client.clone(), *upstream_project_id)),
4149
4150 LspStoreMode::Remote(RemoteLspStore {
4151 upstream_client: None,
4152 ..
4153 }) => None,
4154 LspStoreMode::Local(_) => None,
4155 }
4156 }
4157
4158 pub fn new_local(
4159 buffer_store: Entity<BufferStore>,
4160 worktree_store: Entity<WorktreeStore>,
4161 prettier_store: Entity<PrettierStore>,
4162 toolchain_store: Entity<LocalToolchainStore>,
4163 environment: Entity<ProjectEnvironment>,
4164 manifest_tree: Entity<ManifestTree>,
4165 languages: Arc<LanguageRegistry>,
4166 http_client: Arc<dyn HttpClient>,
4167 fs: Arc<dyn Fs>,
4168 cx: &mut Context<Self>,
4169 ) -> Self {
4170 let yarn = YarnPathStore::new(fs.clone(), cx);
4171 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4172 .detach();
4173 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4174 .detach();
4175 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4176 .detach();
4177 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4178 .detach();
4179 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4180 .detach();
4181 subscribe_to_binary_statuses(&languages, cx).detach();
4182
4183 let _maintain_workspace_config = {
4184 let (sender, receiver) = watch::channel();
4185 (Self::maintain_workspace_config(receiver, cx), sender)
4186 };
4187
4188 Self {
4189 mode: LspStoreMode::Local(LocalLspStore {
4190 weak: cx.weak_entity(),
4191 worktree_store: worktree_store.clone(),
4192
4193 supplementary_language_servers: Default::default(),
4194 languages: languages.clone(),
4195 language_server_ids: Default::default(),
4196 language_servers: Default::default(),
4197 last_workspace_edits_by_language_server: Default::default(),
4198 language_server_watched_paths: Default::default(),
4199 language_server_paths_watched_for_rename: Default::default(),
4200 language_server_dynamic_registrations: Default::default(),
4201 buffers_being_formatted: Default::default(),
4202 buffers_to_refresh_hash_set: HashSet::default(),
4203 buffers_to_refresh_queue: VecDeque::new(),
4204 _background_diagnostics_worker: Task::ready(()).shared(),
4205 buffer_snapshots: Default::default(),
4206 prettier_store,
4207 environment,
4208 http_client,
4209 fs,
4210 yarn,
4211 next_diagnostic_group_id: Default::default(),
4212 diagnostics: Default::default(),
4213 _subscription: cx.on_app_quit(|this, _| {
4214 this.as_local_mut()
4215 .unwrap()
4216 .shutdown_language_servers_on_quit()
4217 }),
4218 lsp_tree: LanguageServerTree::new(
4219 manifest_tree,
4220 languages.clone(),
4221 toolchain_store.clone(),
4222 ),
4223 toolchain_store,
4224 registered_buffers: HashMap::default(),
4225 buffers_opened_in_servers: HashMap::default(),
4226 buffer_pull_diagnostics_result_ids: HashMap::default(),
4227 workspace_pull_diagnostics_result_ids: HashMap::default(),
4228 restricted_worktrees_tasks: HashMap::default(),
4229 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4230 .manifest_file_names(),
4231 }),
4232 last_formatting_failure: None,
4233 downstream_client: None,
4234 buffer_store,
4235 worktree_store,
4236 languages: languages.clone(),
4237 language_server_statuses: Default::default(),
4238 nonce: StdRng::from_os_rng().random(),
4239 diagnostic_summaries: HashMap::default(),
4240 lsp_server_capabilities: HashMap::default(),
4241 semantic_token_config: SemanticTokenConfig::new(cx),
4242 lsp_data: HashMap::default(),
4243 next_hint_id: Arc::default(),
4244 active_entry: None,
4245 _maintain_workspace_config,
4246 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4247 }
4248 }
4249
4250 fn send_lsp_proto_request<R: LspCommand>(
4251 &self,
4252 buffer: Entity<Buffer>,
4253 client: AnyProtoClient,
4254 upstream_project_id: u64,
4255 request: R,
4256 cx: &mut Context<LspStore>,
4257 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4258 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4259 return Task::ready(Ok(R::Response::default()));
4260 }
4261 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4262 cx.spawn(async move |this, cx| {
4263 let response = client.request(message).await?;
4264 let this = this.upgrade().context("project dropped")?;
4265 request
4266 .response_from_proto(response, this, buffer, cx.clone())
4267 .await
4268 })
4269 }
4270
4271 pub(super) fn new_remote(
4272 buffer_store: Entity<BufferStore>,
4273 worktree_store: Entity<WorktreeStore>,
4274 languages: Arc<LanguageRegistry>,
4275 upstream_client: AnyProtoClient,
4276 project_id: u64,
4277 cx: &mut Context<Self>,
4278 ) -> Self {
4279 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4280 .detach();
4281 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4282 .detach();
4283 subscribe_to_binary_statuses(&languages, cx).detach();
4284 let _maintain_workspace_config = {
4285 let (sender, receiver) = watch::channel();
4286 (Self::maintain_workspace_config(receiver, cx), sender)
4287 };
4288 Self {
4289 mode: LspStoreMode::Remote(RemoteLspStore {
4290 upstream_client: Some(upstream_client),
4291 upstream_project_id: project_id,
4292 }),
4293 downstream_client: None,
4294 last_formatting_failure: None,
4295 buffer_store,
4296 worktree_store,
4297 languages: languages.clone(),
4298 language_server_statuses: Default::default(),
4299 nonce: StdRng::from_os_rng().random(),
4300 diagnostic_summaries: HashMap::default(),
4301 lsp_server_capabilities: HashMap::default(),
4302 semantic_token_config: SemanticTokenConfig::new(cx),
4303 next_hint_id: Arc::default(),
4304 lsp_data: HashMap::default(),
4305 active_entry: None,
4306
4307 _maintain_workspace_config,
4308 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4309 }
4310 }
4311
4312 fn on_buffer_store_event(
4313 &mut self,
4314 _: Entity<BufferStore>,
4315 event: &BufferStoreEvent,
4316 cx: &mut Context<Self>,
4317 ) {
4318 match event {
4319 BufferStoreEvent::BufferAdded(buffer) => {
4320 self.on_buffer_added(buffer, cx).log_err();
4321 }
4322 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4323 let buffer_id = buffer.read(cx).remote_id();
4324 if let Some(local) = self.as_local_mut()
4325 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4326 {
4327 local.reset_buffer(buffer, old_file, cx);
4328
4329 if local.registered_buffers.contains_key(&buffer_id) {
4330 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4331 }
4332 }
4333
4334 self.detect_language_for_buffer(buffer, cx);
4335 if let Some(local) = self.as_local_mut() {
4336 local.initialize_buffer(buffer, cx);
4337 if local.registered_buffers.contains_key(&buffer_id) {
4338 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4339 }
4340 }
4341 }
4342 _ => {}
4343 }
4344 }
4345
4346 fn on_worktree_store_event(
4347 &mut self,
4348 _: Entity<WorktreeStore>,
4349 event: &WorktreeStoreEvent,
4350 cx: &mut Context<Self>,
4351 ) {
4352 match event {
4353 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4354 if !worktree.read(cx).is_local() {
4355 return;
4356 }
4357 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4358 worktree::Event::UpdatedEntries(changes) => {
4359 this.update_local_worktree_language_servers(&worktree, changes, cx);
4360 }
4361 worktree::Event::UpdatedGitRepositories(_)
4362 | worktree::Event::DeletedEntry(_) => {}
4363 })
4364 .detach()
4365 }
4366 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4367 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4368 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4369 }
4370 WorktreeStoreEvent::WorktreeReleased(..)
4371 | WorktreeStoreEvent::WorktreeOrderChanged
4372 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4373 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4374 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4375 }
4376 }
4377
4378 fn on_prettier_store_event(
4379 &mut self,
4380 _: Entity<PrettierStore>,
4381 event: &PrettierStoreEvent,
4382 cx: &mut Context<Self>,
4383 ) {
4384 match event {
4385 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4386 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4387 }
4388 PrettierStoreEvent::LanguageServerAdded {
4389 new_server_id,
4390 name,
4391 prettier_server,
4392 } => {
4393 self.register_supplementary_language_server(
4394 *new_server_id,
4395 name.clone(),
4396 prettier_server.clone(),
4397 cx,
4398 );
4399 }
4400 }
4401 }
4402
4403 fn on_toolchain_store_event(
4404 &mut self,
4405 _: Entity<LocalToolchainStore>,
4406 event: &ToolchainStoreEvent,
4407 _: &mut Context<Self>,
4408 ) {
4409 if let ToolchainStoreEvent::ToolchainActivated = event {
4410 self.request_workspace_config_refresh()
4411 }
4412 }
4413
4414 fn request_workspace_config_refresh(&mut self) {
4415 *self._maintain_workspace_config.1.borrow_mut() = ();
4416 }
4417
4418 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4419 self.as_local().map(|local| local.prettier_store.clone())
4420 }
4421
4422 fn on_buffer_event(
4423 &mut self,
4424 buffer: Entity<Buffer>,
4425 event: &language::BufferEvent,
4426 cx: &mut Context<Self>,
4427 ) {
4428 match event {
4429 language::BufferEvent::Edited { .. } => {
4430 self.on_buffer_edited(buffer, cx);
4431 }
4432
4433 language::BufferEvent::Saved => {
4434 self.on_buffer_saved(buffer, cx);
4435 }
4436
4437 _ => {}
4438 }
4439 }
4440
4441 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4442 buffer
4443 .read(cx)
4444 .set_language_registry(self.languages.clone());
4445
4446 cx.subscribe(buffer, |this, buffer, event, cx| {
4447 this.on_buffer_event(buffer, event, cx);
4448 })
4449 .detach();
4450
4451 self.detect_language_for_buffer(buffer, cx);
4452 if let Some(local) = self.as_local_mut() {
4453 local.initialize_buffer(buffer, cx);
4454 }
4455
4456 Ok(())
4457 }
4458
4459 pub fn refresh_background_diagnostics_for_buffers(
4460 &mut self,
4461 buffers: HashSet<BufferId>,
4462 cx: &mut Context<Self>,
4463 ) -> Shared<Task<()>> {
4464 let Some(local) = self.as_local_mut() else {
4465 return Task::ready(()).shared();
4466 };
4467 for buffer in buffers {
4468 if local.buffers_to_refresh_hash_set.insert(buffer) {
4469 local.buffers_to_refresh_queue.push_back(buffer);
4470 if local.buffers_to_refresh_queue.len() == 1 {
4471 local._background_diagnostics_worker =
4472 Self::background_diagnostics_worker(cx).shared();
4473 }
4474 }
4475 }
4476
4477 local._background_diagnostics_worker.clone()
4478 }
4479
4480 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4481 let buffer_store = self.buffer_store.clone();
4482 let local = self.as_local_mut()?;
4483 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4484 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4485 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4486 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4487 }
4488 }
4489 None
4490 }
4491
4492 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4493 cx.spawn(async move |this, cx| {
4494 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4495 task.await.log_err();
4496 }
4497 })
4498 }
4499
4500 pub(crate) fn register_buffer_with_language_servers(
4501 &mut self,
4502 buffer: &Entity<Buffer>,
4503 only_register_servers: HashSet<LanguageServerSelector>,
4504 ignore_refcounts: bool,
4505 cx: &mut Context<Self>,
4506 ) -> OpenLspBufferHandle {
4507 let buffer_id = buffer.read(cx).remote_id();
4508 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4509 if let Some(local) = self.as_local_mut() {
4510 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4511 if !ignore_refcounts {
4512 *refcount += 1;
4513 }
4514
4515 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4516 // 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
4517 // 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
4518 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4519 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4520 return handle;
4521 };
4522 if !file.is_local() {
4523 return handle;
4524 }
4525
4526 if ignore_refcounts || *refcount == 1 {
4527 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4528 }
4529 if !ignore_refcounts {
4530 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4531 let refcount = {
4532 let local = lsp_store.as_local_mut().unwrap();
4533 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4534 debug_panic!("bad refcounting");
4535 return;
4536 };
4537
4538 *refcount -= 1;
4539 *refcount
4540 };
4541 if refcount == 0 {
4542 lsp_store.lsp_data.remove(&buffer_id);
4543 let local = lsp_store.as_local_mut().unwrap();
4544 local.registered_buffers.remove(&buffer_id);
4545
4546 local.buffers_opened_in_servers.remove(&buffer_id);
4547 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4548 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4549
4550 let buffer_abs_path = file.abs_path(cx);
4551 for (_, buffer_pull_diagnostics_result_ids) in
4552 &mut local.buffer_pull_diagnostics_result_ids
4553 {
4554 buffer_pull_diagnostics_result_ids.retain(
4555 |_, buffer_result_ids| {
4556 buffer_result_ids.remove(&buffer_abs_path);
4557 !buffer_result_ids.is_empty()
4558 },
4559 );
4560 }
4561
4562 let diagnostic_updates = local
4563 .language_servers
4564 .keys()
4565 .cloned()
4566 .map(|server_id| DocumentDiagnosticsUpdate {
4567 diagnostics: DocumentDiagnostics {
4568 document_abs_path: buffer_abs_path.clone(),
4569 version: None,
4570 diagnostics: Vec::new(),
4571 },
4572 result_id: None,
4573 registration_id: None,
4574 server_id,
4575 disk_based_sources: Cow::Borrowed(&[]),
4576 })
4577 .collect::<Vec<_>>();
4578
4579 lsp_store
4580 .merge_diagnostic_entries(
4581 diagnostic_updates,
4582 |_, diagnostic, _| {
4583 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4584 },
4585 cx,
4586 )
4587 .context("Clearing diagnostics for the closed buffer")
4588 .log_err();
4589 }
4590 }
4591 })
4592 .detach();
4593 }
4594 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4595 let buffer_id = buffer.read(cx).remote_id().to_proto();
4596 cx.background_spawn(async move {
4597 upstream_client
4598 .request(proto::RegisterBufferWithLanguageServers {
4599 project_id: upstream_project_id,
4600 buffer_id,
4601 only_servers: only_register_servers
4602 .into_iter()
4603 .map(|selector| {
4604 let selector = match selector {
4605 LanguageServerSelector::Id(language_server_id) => {
4606 proto::language_server_selector::Selector::ServerId(
4607 language_server_id.to_proto(),
4608 )
4609 }
4610 LanguageServerSelector::Name(language_server_name) => {
4611 proto::language_server_selector::Selector::Name(
4612 language_server_name.to_string(),
4613 )
4614 }
4615 };
4616 proto::LanguageServerSelector {
4617 selector: Some(selector),
4618 }
4619 })
4620 .collect(),
4621 })
4622 .await
4623 })
4624 .detach();
4625 } else {
4626 // Our remote connection got closed
4627 }
4628 handle
4629 }
4630
4631 fn maintain_buffer_languages(
4632 languages: Arc<LanguageRegistry>,
4633 cx: &mut Context<Self>,
4634 ) -> Task<()> {
4635 let mut subscription = languages.subscribe();
4636 let mut prev_reload_count = languages.reload_count();
4637 cx.spawn(async move |this, cx| {
4638 while let Some(()) = subscription.next().await {
4639 if let Some(this) = this.upgrade() {
4640 // If the language registry has been reloaded, then remove and
4641 // re-assign the languages on all open buffers.
4642 let reload_count = languages.reload_count();
4643 if reload_count > prev_reload_count {
4644 prev_reload_count = reload_count;
4645 this.update(cx, |this, cx| {
4646 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4647 for buffer in buffer_store.buffers() {
4648 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4649 {
4650 buffer.update(cx, |buffer, cx| {
4651 buffer.set_language_async(None, cx)
4652 });
4653 if let Some(local) = this.as_local_mut() {
4654 local.reset_buffer(&buffer, &f, cx);
4655
4656 if local
4657 .registered_buffers
4658 .contains_key(&buffer.read(cx).remote_id())
4659 && let Some(file_url) =
4660 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4661 {
4662 local.unregister_buffer_from_language_servers(
4663 &buffer, &file_url, cx,
4664 );
4665 }
4666 }
4667 }
4668 }
4669 });
4670 });
4671 }
4672
4673 this.update(cx, |this, cx| {
4674 let mut plain_text_buffers = Vec::new();
4675 let mut buffers_with_unknown_injections = Vec::new();
4676 for handle in this.buffer_store.read(cx).buffers() {
4677 let buffer = handle.read(cx);
4678 if buffer.language().is_none()
4679 || buffer.language() == Some(&*language::PLAIN_TEXT)
4680 {
4681 plain_text_buffers.push(handle);
4682 } else if buffer.contains_unknown_injections() {
4683 buffers_with_unknown_injections.push(handle);
4684 }
4685 }
4686
4687 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4688 // and reused later in the invisible worktrees.
4689 plain_text_buffers.sort_by_key(|buffer| {
4690 Reverse(
4691 File::from_dyn(buffer.read(cx).file())
4692 .map(|file| file.worktree.read(cx).is_visible()),
4693 )
4694 });
4695
4696 for buffer in plain_text_buffers {
4697 this.detect_language_for_buffer(&buffer, cx);
4698 if let Some(local) = this.as_local_mut() {
4699 local.initialize_buffer(&buffer, cx);
4700 if local
4701 .registered_buffers
4702 .contains_key(&buffer.read(cx).remote_id())
4703 {
4704 local.register_buffer_with_language_servers(
4705 &buffer,
4706 HashSet::default(),
4707 cx,
4708 );
4709 }
4710 }
4711 }
4712
4713 for buffer in buffers_with_unknown_injections {
4714 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4715 }
4716 });
4717 }
4718 }
4719 })
4720 }
4721
4722 fn detect_language_for_buffer(
4723 &mut self,
4724 buffer_handle: &Entity<Buffer>,
4725 cx: &mut Context<Self>,
4726 ) -> Option<language::AvailableLanguage> {
4727 // If the buffer has a language, set it and start the language server if we haven't already.
4728 let buffer = buffer_handle.read(cx);
4729 let file = buffer.file()?;
4730
4731 let content = buffer.as_rope();
4732 let available_language = self.languages.language_for_file(file, Some(content), cx);
4733 if let Some(available_language) = &available_language {
4734 if let Some(Ok(Ok(new_language))) = self
4735 .languages
4736 .load_language(available_language)
4737 .now_or_never()
4738 {
4739 self.set_language_for_buffer(buffer_handle, new_language, cx);
4740 }
4741 } else {
4742 cx.emit(LspStoreEvent::LanguageDetected {
4743 buffer: buffer_handle.clone(),
4744 new_language: None,
4745 });
4746 }
4747
4748 available_language
4749 }
4750
4751 pub(crate) fn set_language_for_buffer(
4752 &mut self,
4753 buffer_entity: &Entity<Buffer>,
4754 new_language: Arc<Language>,
4755 cx: &mut Context<Self>,
4756 ) {
4757 let buffer = buffer_entity.read(cx);
4758 let buffer_file = buffer.file().cloned();
4759 let buffer_id = buffer.remote_id();
4760 if let Some(local_store) = self.as_local_mut()
4761 && local_store.registered_buffers.contains_key(&buffer_id)
4762 && let Some(abs_path) =
4763 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4764 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4765 {
4766 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4767 }
4768 buffer_entity.update(cx, |buffer, cx| {
4769 if buffer
4770 .language()
4771 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4772 {
4773 buffer.set_language_async(Some(new_language.clone()), cx);
4774 }
4775 });
4776
4777 let settings =
4778 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4779 let buffer_file = File::from_dyn(buffer_file.as_ref());
4780
4781 let worktree_id = if let Some(file) = buffer_file {
4782 let worktree = file.worktree.clone();
4783
4784 if let Some(local) = self.as_local_mut()
4785 && local.registered_buffers.contains_key(&buffer_id)
4786 {
4787 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4788 }
4789 Some(worktree.read(cx).id())
4790 } else {
4791 None
4792 };
4793
4794 if settings.prettier.allowed
4795 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4796 {
4797 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4798 if let Some(prettier_store) = prettier_store {
4799 prettier_store.update(cx, |prettier_store, cx| {
4800 prettier_store.install_default_prettier(
4801 worktree_id,
4802 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4803 cx,
4804 )
4805 })
4806 }
4807 }
4808
4809 cx.emit(LspStoreEvent::LanguageDetected {
4810 buffer: buffer_entity.clone(),
4811 new_language: Some(new_language),
4812 })
4813 }
4814
4815 pub fn buffer_store(&self) -> Entity<BufferStore> {
4816 self.buffer_store.clone()
4817 }
4818
4819 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4820 self.active_entry = active_entry;
4821 }
4822
4823 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4824 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4825 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4826 {
4827 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4828 summaries
4829 .iter()
4830 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4831 });
4832 if let Some(summary) = summaries.next() {
4833 client
4834 .send(proto::UpdateDiagnosticSummary {
4835 project_id: downstream_project_id,
4836 worktree_id: worktree.id().to_proto(),
4837 summary: Some(summary),
4838 more_summaries: summaries.collect(),
4839 })
4840 .log_err();
4841 }
4842 }
4843 }
4844
4845 fn is_capable_for_proto_request<R>(
4846 &self,
4847 buffer: &Entity<Buffer>,
4848 request: &R,
4849 cx: &App,
4850 ) -> bool
4851 where
4852 R: LspCommand,
4853 {
4854 self.check_if_capable_for_proto_request(
4855 buffer,
4856 |capabilities| {
4857 request.check_capabilities(AdapterServerCapabilities {
4858 server_capabilities: capabilities.clone(),
4859 code_action_kinds: None,
4860 })
4861 },
4862 cx,
4863 )
4864 }
4865
4866 fn check_if_capable_for_proto_request<F>(
4867 &self,
4868 buffer: &Entity<Buffer>,
4869 check: F,
4870 cx: &App,
4871 ) -> bool
4872 where
4873 F: FnMut(&lsp::ServerCapabilities) -> bool,
4874 {
4875 let Some(language) = buffer.read(cx).language().cloned() else {
4876 return false;
4877 };
4878 let registered_language_servers = self
4879 .languages
4880 .lsp_adapters(&language.name())
4881 .into_iter()
4882 .map(|lsp_adapter| lsp_adapter.name())
4883 .collect::<HashSet<_>>();
4884 self.language_server_statuses
4885 .iter()
4886 .filter_map(|(server_id, server_status)| {
4887 // Include servers that are either registered for this language OR
4888 // available to be loaded (for SSH remote mode where adapters like
4889 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4890 // but only loaded on the server side)
4891 let is_relevant = registered_language_servers.contains(&server_status.name)
4892 || self.languages.is_lsp_adapter_available(&server_status.name);
4893 is_relevant.then_some(server_id)
4894 })
4895 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4896 .any(check)
4897 }
4898
4899 fn all_capable_for_proto_request<F>(
4900 &self,
4901 buffer: &Entity<Buffer>,
4902 mut check: F,
4903 cx: &App,
4904 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4905 where
4906 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4907 {
4908 let Some(language) = buffer.read(cx).language().cloned() else {
4909 return Vec::default();
4910 };
4911 let registered_language_servers = self
4912 .languages
4913 .lsp_adapters(&language.name())
4914 .into_iter()
4915 .map(|lsp_adapter| lsp_adapter.name())
4916 .collect::<HashSet<_>>();
4917 self.language_server_statuses
4918 .iter()
4919 .filter_map(|(server_id, server_status)| {
4920 // Include servers that are either registered for this language OR
4921 // available to be loaded (for SSH remote mode where adapters like
4922 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4923 // but only loaded on the server side)
4924 let is_relevant = registered_language_servers.contains(&server_status.name)
4925 || self.languages.is_lsp_adapter_available(&server_status.name);
4926 is_relevant.then_some((server_id, &server_status.name))
4927 })
4928 .filter_map(|(server_id, server_name)| {
4929 self.lsp_server_capabilities
4930 .get(server_id)
4931 .map(|c| (server_id, server_name, c))
4932 })
4933 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4934 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
4935 .collect()
4936 }
4937
4938 pub fn request_lsp<R>(
4939 &mut self,
4940 buffer: Entity<Buffer>,
4941 server: LanguageServerToQuery,
4942 request: R,
4943 cx: &mut Context<Self>,
4944 ) -> Task<Result<R::Response>>
4945 where
4946 R: LspCommand,
4947 <R::LspRequest as lsp::request::Request>::Result: Send,
4948 <R::LspRequest as lsp::request::Request>::Params: Send,
4949 {
4950 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4951 return self.send_lsp_proto_request(
4952 buffer,
4953 upstream_client,
4954 upstream_project_id,
4955 request,
4956 cx,
4957 );
4958 }
4959
4960 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4961 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4962 local
4963 .language_servers_for_buffer(buffer, cx)
4964 .find(|(_, server)| {
4965 request.check_capabilities(server.adapter_server_capabilities())
4966 })
4967 .map(|(_, server)| server.clone())
4968 }),
4969 LanguageServerToQuery::Other(id) => self
4970 .language_server_for_local_buffer(buffer, id, cx)
4971 .and_then(|(_, server)| {
4972 request
4973 .check_capabilities(server.adapter_server_capabilities())
4974 .then(|| Arc::clone(server))
4975 }),
4976 }) else {
4977 return Task::ready(Ok(Default::default()));
4978 };
4979
4980 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4981
4982 let Some(file) = file else {
4983 return Task::ready(Ok(Default::default()));
4984 };
4985
4986 let lsp_params = match request.to_lsp_params_or_response(
4987 &file.abs_path(cx),
4988 buffer.read(cx),
4989 &language_server,
4990 cx,
4991 ) {
4992 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4993 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4994 Err(err) => {
4995 let message = format!(
4996 "{} via {} failed: {}",
4997 request.display_name(),
4998 language_server.name(),
4999 err
5000 );
5001 // rust-analyzer likes to error with this when its still loading up
5002 if !message.ends_with("content modified") {
5003 log::warn!("{message}");
5004 }
5005 return Task::ready(Err(anyhow!(message)));
5006 }
5007 };
5008
5009 let status = request.status();
5010 let request_timeout = ProjectSettings::get_global(cx)
5011 .global_lsp_settings
5012 .get_request_timeout();
5013
5014 cx.spawn(async move |this, cx| {
5015 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5016
5017 let id = lsp_request.id();
5018 let _cleanup = if status.is_some() {
5019 cx.update(|cx| {
5020 this.update(cx, |this, cx| {
5021 this.on_lsp_work_start(
5022 language_server.server_id(),
5023 ProgressToken::Number(id),
5024 LanguageServerProgress {
5025 is_disk_based_diagnostics_progress: false,
5026 is_cancellable: false,
5027 title: None,
5028 message: status.clone(),
5029 percentage: None,
5030 last_update_at: cx.background_executor().now(),
5031 },
5032 cx,
5033 );
5034 })
5035 })
5036 .log_err();
5037
5038 Some(defer(|| {
5039 cx.update(|cx| {
5040 this.update(cx, |this, cx| {
5041 this.on_lsp_work_end(
5042 language_server.server_id(),
5043 ProgressToken::Number(id),
5044 cx,
5045 );
5046 })
5047 })
5048 .log_err();
5049 }))
5050 } else {
5051 None
5052 };
5053
5054 let result = lsp_request.await.into_response();
5055
5056 let response = result.map_err(|err| {
5057 let message = format!(
5058 "{} via {} failed: {}",
5059 request.display_name(),
5060 language_server.name(),
5061 err
5062 );
5063 // rust-analyzer likes to error with this when its still loading up
5064 if !message.ends_with("content modified") {
5065 log::warn!("{message}");
5066 }
5067 anyhow::anyhow!(message)
5068 })?;
5069
5070 request
5071 .response_from_lsp(
5072 response,
5073 this.upgrade().context("no app context")?,
5074 buffer,
5075 language_server.server_id(),
5076 cx.clone(),
5077 )
5078 .await
5079 })
5080 }
5081
5082 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5083 let mut language_formatters_to_check = Vec::new();
5084 for buffer in self.buffer_store.read(cx).buffers() {
5085 let buffer = buffer.read(cx);
5086 let buffer_file = File::from_dyn(buffer.file());
5087 let buffer_language = buffer.language();
5088 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5089 if buffer_language.is_some() {
5090 language_formatters_to_check.push((
5091 buffer_file.map(|f| f.worktree_id(cx)),
5092 settings.into_owned(),
5093 ));
5094 }
5095 }
5096
5097 self.request_workspace_config_refresh();
5098
5099 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5100 prettier_store.update(cx, |prettier_store, cx| {
5101 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5102 })
5103 }
5104
5105 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5106 .global_lsp_settings
5107 .semantic_token_rules
5108 .clone();
5109 self.semantic_token_config
5110 .update_rules(new_semantic_token_rules);
5111 // Always clear cached stylizers so that changes to language-specific
5112 // semantic token rules (e.g. from extension install/uninstall) are
5113 // picked up. Stylizers are recreated lazily, so this is cheap.
5114 self.semantic_token_config.clear_stylizers();
5115
5116 let new_global_semantic_tokens_mode =
5117 all_language_settings(None, cx).defaults.semantic_tokens;
5118 if self
5119 .semantic_token_config
5120 .update_global_mode(new_global_semantic_tokens_mode)
5121 {
5122 self.restart_all_language_servers(cx);
5123 }
5124
5125 cx.notify();
5126 }
5127
5128 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5129 let buffer_store = self.buffer_store.clone();
5130 let Some(local) = self.as_local_mut() else {
5131 return;
5132 };
5133 let mut adapters = BTreeMap::default();
5134 let get_adapter = {
5135 let languages = local.languages.clone();
5136 let environment = local.environment.clone();
5137 let weak = local.weak.clone();
5138 let worktree_store = local.worktree_store.clone();
5139 let http_client = local.http_client.clone();
5140 let fs = local.fs.clone();
5141 move |worktree_id, cx: &mut App| {
5142 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5143 Some(LocalLspAdapterDelegate::new(
5144 languages.clone(),
5145 &environment,
5146 weak.clone(),
5147 &worktree,
5148 http_client.clone(),
5149 fs.clone(),
5150 cx,
5151 ))
5152 }
5153 };
5154
5155 let mut messages_to_report = Vec::new();
5156 let (new_tree, to_stop) = {
5157 let mut rebase = local.lsp_tree.rebase();
5158 let buffers = buffer_store
5159 .read(cx)
5160 .buffers()
5161 .filter_map(|buffer| {
5162 let raw_buffer = buffer.read(cx);
5163 if !local
5164 .registered_buffers
5165 .contains_key(&raw_buffer.remote_id())
5166 {
5167 return None;
5168 }
5169 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5170 let language = raw_buffer.language().cloned()?;
5171 Some((file, language, raw_buffer.remote_id()))
5172 })
5173 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5174 for (file, language, buffer_id) in buffers {
5175 let worktree_id = file.worktree_id(cx);
5176 let Some(worktree) = local
5177 .worktree_store
5178 .read(cx)
5179 .worktree_for_id(worktree_id, cx)
5180 else {
5181 continue;
5182 };
5183
5184 if let Some((_, apply)) = local.reuse_existing_language_server(
5185 rebase.server_tree(),
5186 &worktree,
5187 &language.name(),
5188 cx,
5189 ) {
5190 (apply)(rebase.server_tree());
5191 } else if let Some(lsp_delegate) = adapters
5192 .entry(worktree_id)
5193 .or_insert_with(|| get_adapter(worktree_id, cx))
5194 .clone()
5195 {
5196 let delegate =
5197 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5198 let path = file
5199 .path()
5200 .parent()
5201 .map(Arc::from)
5202 .unwrap_or_else(|| file.path().clone());
5203 let worktree_path = ProjectPath { worktree_id, path };
5204 let abs_path = file.abs_path(cx);
5205 let nodes = rebase
5206 .walk(
5207 worktree_path,
5208 language.name(),
5209 language.manifest(),
5210 delegate.clone(),
5211 cx,
5212 )
5213 .collect::<Vec<_>>();
5214 for node in nodes {
5215 let server_id = node.server_id_or_init(|disposition| {
5216 let path = &disposition.path;
5217 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5218 let key = LanguageServerSeed {
5219 worktree_id,
5220 name: disposition.server_name.clone(),
5221 settings: LanguageServerSeedSettings {
5222 binary: disposition.settings.binary.clone(),
5223 initialization_options: disposition
5224 .settings
5225 .initialization_options
5226 .clone(),
5227 },
5228 toolchain: local.toolchain_store.read(cx).active_toolchain(
5229 path.worktree_id,
5230 &path.path,
5231 language.name(),
5232 ),
5233 };
5234 local.language_server_ids.remove(&key);
5235
5236 let server_id = local.get_or_insert_language_server(
5237 &worktree,
5238 lsp_delegate.clone(),
5239 disposition,
5240 &language.name(),
5241 cx,
5242 );
5243 if let Some(state) = local.language_servers.get(&server_id)
5244 && let Ok(uri) = uri
5245 {
5246 state.add_workspace_folder(uri);
5247 };
5248 server_id
5249 });
5250
5251 if let Some(language_server_id) = server_id {
5252 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5253 language_server_id,
5254 name: node.name(),
5255 message:
5256 proto::update_language_server::Variant::RegisteredForBuffer(
5257 proto::RegisteredForBuffer {
5258 buffer_abs_path: abs_path
5259 .to_string_lossy()
5260 .into_owned(),
5261 buffer_id: buffer_id.to_proto(),
5262 },
5263 ),
5264 });
5265 }
5266 }
5267 } else {
5268 continue;
5269 }
5270 }
5271 rebase.finish()
5272 };
5273 for message in messages_to_report {
5274 cx.emit(message);
5275 }
5276 local.lsp_tree = new_tree;
5277 for (id, _) in to_stop {
5278 self.stop_local_language_server(id, cx).detach();
5279 }
5280 }
5281
5282 pub fn apply_code_action(
5283 &self,
5284 buffer_handle: Entity<Buffer>,
5285 mut action: CodeAction,
5286 push_to_history: bool,
5287 cx: &mut Context<Self>,
5288 ) -> Task<Result<ProjectTransaction>> {
5289 if let Some((upstream_client, project_id)) = self.upstream_client() {
5290 let request = proto::ApplyCodeAction {
5291 project_id,
5292 buffer_id: buffer_handle.read(cx).remote_id().into(),
5293 action: Some(Self::serialize_code_action(&action)),
5294 };
5295 let buffer_store = self.buffer_store();
5296 cx.spawn(async move |_, cx| {
5297 let response = upstream_client
5298 .request(request)
5299 .await?
5300 .transaction
5301 .context("missing transaction")?;
5302
5303 buffer_store
5304 .update(cx, |buffer_store, cx| {
5305 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5306 })
5307 .await
5308 })
5309 } else if self.mode.is_local() {
5310 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5311 let request_timeout = ProjectSettings::get_global(cx)
5312 .global_lsp_settings
5313 .get_request_timeout();
5314 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5315 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5316 }) else {
5317 return Task::ready(Ok(ProjectTransaction::default()));
5318 };
5319
5320 cx.spawn(async move |this, cx| {
5321 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5322 .await
5323 .context("resolving a code action")?;
5324 if let Some(edit) = action.lsp_action.edit()
5325 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5326 return LocalLspStore::deserialize_workspace_edit(
5327 this.upgrade().context("no app present")?,
5328 edit.clone(),
5329 push_to_history,
5330
5331 lang_server.clone(),
5332 cx,
5333 )
5334 .await;
5335 }
5336
5337 let Some(command) = action.lsp_action.command() else {
5338 return Ok(ProjectTransaction::default())
5339 };
5340
5341 let server_capabilities = lang_server.capabilities();
5342 let available_commands = server_capabilities
5343 .execute_command_provider
5344 .as_ref()
5345 .map(|options| options.commands.as_slice())
5346 .unwrap_or_default();
5347
5348 if !available_commands.contains(&command.command) {
5349 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5350 return Ok(ProjectTransaction::default())
5351 }
5352
5353 let request_timeout = cx.update(|app|
5354 ProjectSettings::get_global(app)
5355 .global_lsp_settings
5356 .get_request_timeout()
5357 );
5358
5359 this.update(cx, |this, _| {
5360 this.as_local_mut()
5361 .unwrap()
5362 .last_workspace_edits_by_language_server
5363 .remove(&lang_server.server_id());
5364 })?;
5365
5366 let _result = lang_server
5367 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5368 command: command.command.clone(),
5369 arguments: command.arguments.clone().unwrap_or_default(),
5370 ..lsp::ExecuteCommandParams::default()
5371 }, request_timeout)
5372 .await.into_response()
5373 .context("execute command")?;
5374
5375 return this.update(cx, |this, _| {
5376 this.as_local_mut()
5377 .unwrap()
5378 .last_workspace_edits_by_language_server
5379 .remove(&lang_server.server_id())
5380 .unwrap_or_default()
5381 });
5382 })
5383 } else {
5384 Task::ready(Err(anyhow!("no upstream client and not local")))
5385 }
5386 }
5387
5388 pub fn apply_code_action_kind(
5389 &mut self,
5390 buffers: HashSet<Entity<Buffer>>,
5391 kind: CodeActionKind,
5392 push_to_history: bool,
5393 cx: &mut Context<Self>,
5394 ) -> Task<anyhow::Result<ProjectTransaction>> {
5395 if self.as_local().is_some() {
5396 cx.spawn(async move |lsp_store, cx| {
5397 let buffers = buffers.into_iter().collect::<Vec<_>>();
5398 let result = LocalLspStore::execute_code_action_kind_locally(
5399 lsp_store.clone(),
5400 buffers,
5401 kind,
5402 push_to_history,
5403 cx,
5404 )
5405 .await;
5406 lsp_store.update(cx, |lsp_store, _| {
5407 lsp_store.update_last_formatting_failure(&result);
5408 })?;
5409 result
5410 })
5411 } else if let Some((client, project_id)) = self.upstream_client() {
5412 let buffer_store = self.buffer_store();
5413 cx.spawn(async move |lsp_store, cx| {
5414 let result = client
5415 .request(proto::ApplyCodeActionKind {
5416 project_id,
5417 kind: kind.as_str().to_owned(),
5418 buffer_ids: buffers
5419 .iter()
5420 .map(|buffer| {
5421 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5422 })
5423 .collect(),
5424 })
5425 .await
5426 .and_then(|result| result.transaction.context("missing transaction"));
5427 lsp_store.update(cx, |lsp_store, _| {
5428 lsp_store.update_last_formatting_failure(&result);
5429 })?;
5430
5431 let transaction_response = result?;
5432 buffer_store
5433 .update(cx, |buffer_store, cx| {
5434 buffer_store.deserialize_project_transaction(
5435 transaction_response,
5436 push_to_history,
5437 cx,
5438 )
5439 })
5440 .await
5441 })
5442 } else {
5443 Task::ready(Ok(ProjectTransaction::default()))
5444 }
5445 }
5446
5447 pub fn resolved_hint(
5448 &mut self,
5449 buffer_id: BufferId,
5450 id: InlayId,
5451 cx: &mut Context<Self>,
5452 ) -> Option<ResolvedHint> {
5453 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5454
5455 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5456 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5457 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5458 let (server_id, resolve_data) = match &hint.resolve_state {
5459 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5460 ResolveState::Resolving => {
5461 return Some(ResolvedHint::Resolving(
5462 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5463 ));
5464 }
5465 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5466 };
5467
5468 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5469 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5470 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5471 id,
5472 cx.spawn(async move |lsp_store, cx| {
5473 let resolved_hint = resolve_task.await;
5474 lsp_store
5475 .update(cx, |lsp_store, _| {
5476 if let Some(old_inlay_hint) = lsp_store
5477 .lsp_data
5478 .get_mut(&buffer_id)
5479 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5480 {
5481 match resolved_hint {
5482 Ok(resolved_hint) => {
5483 *old_inlay_hint = resolved_hint;
5484 }
5485 Err(e) => {
5486 old_inlay_hint.resolve_state =
5487 ResolveState::CanResolve(server_id, resolve_data);
5488 log::error!("Inlay hint resolve failed: {e:#}");
5489 }
5490 }
5491 }
5492 })
5493 .ok();
5494 })
5495 .shared(),
5496 );
5497 debug_assert!(
5498 previous_task.is_none(),
5499 "Did not change hint's resolve state after spawning its resolve"
5500 );
5501 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5502 None
5503 }
5504
5505 pub(crate) fn linked_edits(
5506 &mut self,
5507 buffer: &Entity<Buffer>,
5508 position: Anchor,
5509 cx: &mut Context<Self>,
5510 ) -> Task<Result<Vec<Range<Anchor>>>> {
5511 let snapshot = buffer.read(cx).snapshot();
5512 let scope = snapshot.language_scope_at(position);
5513 let Some(server_id) = self
5514 .as_local()
5515 .and_then(|local| {
5516 buffer.update(cx, |buffer, cx| {
5517 local
5518 .language_servers_for_buffer(buffer, cx)
5519 .filter(|(_, server)| {
5520 LinkedEditingRange::check_server_capabilities(server.capabilities())
5521 })
5522 .filter(|(adapter, _)| {
5523 scope
5524 .as_ref()
5525 .map(|scope| scope.language_allowed(&adapter.name))
5526 .unwrap_or(true)
5527 })
5528 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5529 .next()
5530 })
5531 })
5532 .or_else(|| {
5533 self.upstream_client()
5534 .is_some()
5535 .then_some(LanguageServerToQuery::FirstCapable)
5536 })
5537 .filter(|_| {
5538 maybe!({
5539 let language = buffer.read(cx).language_at(position)?;
5540 Some(
5541 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5542 .linked_edits,
5543 )
5544 }) == Some(true)
5545 })
5546 else {
5547 return Task::ready(Ok(Vec::new()));
5548 };
5549
5550 self.request_lsp(
5551 buffer.clone(),
5552 server_id,
5553 LinkedEditingRange { position },
5554 cx,
5555 )
5556 }
5557
5558 fn apply_on_type_formatting(
5559 &mut self,
5560 buffer: Entity<Buffer>,
5561 position: Anchor,
5562 trigger: String,
5563 cx: &mut Context<Self>,
5564 ) -> Task<Result<Option<Transaction>>> {
5565 if let Some((client, project_id)) = self.upstream_client() {
5566 if !self.check_if_capable_for_proto_request(
5567 &buffer,
5568 |capabilities| {
5569 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5570 },
5571 cx,
5572 ) {
5573 return Task::ready(Ok(None));
5574 }
5575 let request = proto::OnTypeFormatting {
5576 project_id,
5577 buffer_id: buffer.read(cx).remote_id().into(),
5578 position: Some(serialize_anchor(&position)),
5579 trigger,
5580 version: serialize_version(&buffer.read(cx).version()),
5581 };
5582 cx.background_spawn(async move {
5583 client
5584 .request(request)
5585 .await?
5586 .transaction
5587 .map(language::proto::deserialize_transaction)
5588 .transpose()
5589 })
5590 } else if let Some(local) = self.as_local_mut() {
5591 let buffer_id = buffer.read(cx).remote_id();
5592 local.buffers_being_formatted.insert(buffer_id);
5593 cx.spawn(async move |this, cx| {
5594 let _cleanup = defer({
5595 let this = this.clone();
5596 let mut cx = cx.clone();
5597 move || {
5598 this.update(&mut cx, |this, _| {
5599 if let Some(local) = this.as_local_mut() {
5600 local.buffers_being_formatted.remove(&buffer_id);
5601 }
5602 })
5603 .ok();
5604 }
5605 });
5606
5607 buffer
5608 .update(cx, |buffer, _| {
5609 buffer.wait_for_edits(Some(position.timestamp()))
5610 })
5611 .await?;
5612 this.update(cx, |this, cx| {
5613 let position = position.to_point_utf16(buffer.read(cx));
5614 this.on_type_format(buffer, position, trigger, false, cx)
5615 })?
5616 .await
5617 })
5618 } else {
5619 Task::ready(Err(anyhow!("No upstream client or local language server")))
5620 }
5621 }
5622
5623 pub fn on_type_format<T: ToPointUtf16>(
5624 &mut self,
5625 buffer: Entity<Buffer>,
5626 position: T,
5627 trigger: String,
5628 push_to_history: bool,
5629 cx: &mut Context<Self>,
5630 ) -> Task<Result<Option<Transaction>>> {
5631 let position = position.to_point_utf16(buffer.read(cx));
5632 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5633 }
5634
5635 fn on_type_format_impl(
5636 &mut self,
5637 buffer: Entity<Buffer>,
5638 position: PointUtf16,
5639 trigger: String,
5640 push_to_history: bool,
5641 cx: &mut Context<Self>,
5642 ) -> Task<Result<Option<Transaction>>> {
5643 let options = buffer.update(cx, |buffer, cx| {
5644 lsp_command::lsp_formatting_options(
5645 language_settings(
5646 buffer.language_at(position).map(|l| l.name()),
5647 buffer.file(),
5648 cx,
5649 )
5650 .as_ref(),
5651 )
5652 });
5653
5654 cx.spawn(async move |this, cx| {
5655 if let Some(waiter) =
5656 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5657 {
5658 waiter.await?;
5659 }
5660 cx.update(|cx| {
5661 this.update(cx, |this, cx| {
5662 this.request_lsp(
5663 buffer.clone(),
5664 LanguageServerToQuery::FirstCapable,
5665 OnTypeFormatting {
5666 position,
5667 trigger,
5668 options,
5669 push_to_history,
5670 },
5671 cx,
5672 )
5673 })
5674 })?
5675 .await
5676 })
5677 }
5678
5679 pub fn definitions(
5680 &mut self,
5681 buffer: &Entity<Buffer>,
5682 position: PointUtf16,
5683 cx: &mut Context<Self>,
5684 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5685 if let Some((upstream_client, project_id)) = self.upstream_client() {
5686 let request = GetDefinitions { position };
5687 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5688 return Task::ready(Ok(None));
5689 }
5690
5691 let request_timeout = ProjectSettings::get_global(cx)
5692 .global_lsp_settings
5693 .get_request_timeout();
5694
5695 let request_task = upstream_client.request_lsp(
5696 project_id,
5697 None,
5698 request_timeout,
5699 cx.background_executor().clone(),
5700 request.to_proto(project_id, buffer.read(cx)),
5701 );
5702 let buffer = buffer.clone();
5703 cx.spawn(async move |weak_lsp_store, cx| {
5704 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5705 return Ok(None);
5706 };
5707 let Some(responses) = request_task.await? else {
5708 return Ok(None);
5709 };
5710 let actions = join_all(responses.payload.into_iter().map(|response| {
5711 GetDefinitions { position }.response_from_proto(
5712 response.response,
5713 lsp_store.clone(),
5714 buffer.clone(),
5715 cx.clone(),
5716 )
5717 }))
5718 .await;
5719
5720 Ok(Some(
5721 actions
5722 .into_iter()
5723 .collect::<Result<Vec<Vec<_>>>>()?
5724 .into_iter()
5725 .flatten()
5726 .dedup()
5727 .collect(),
5728 ))
5729 })
5730 } else {
5731 let definitions_task = self.request_multiple_lsp_locally(
5732 buffer,
5733 Some(position),
5734 GetDefinitions { position },
5735 cx,
5736 );
5737 cx.background_spawn(async move {
5738 Ok(Some(
5739 definitions_task
5740 .await
5741 .into_iter()
5742 .flat_map(|(_, definitions)| definitions)
5743 .dedup()
5744 .collect(),
5745 ))
5746 })
5747 }
5748 }
5749
5750 pub fn declarations(
5751 &mut self,
5752 buffer: &Entity<Buffer>,
5753 position: PointUtf16,
5754 cx: &mut Context<Self>,
5755 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5756 if let Some((upstream_client, project_id)) = self.upstream_client() {
5757 let request = GetDeclarations { position };
5758 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5759 return Task::ready(Ok(None));
5760 }
5761 let request_timeout = ProjectSettings::get_global(cx)
5762 .global_lsp_settings
5763 .get_request_timeout();
5764 let request_task = upstream_client.request_lsp(
5765 project_id,
5766 None,
5767 request_timeout,
5768 cx.background_executor().clone(),
5769 request.to_proto(project_id, buffer.read(cx)),
5770 );
5771 let buffer = buffer.clone();
5772 cx.spawn(async move |weak_lsp_store, cx| {
5773 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5774 return Ok(None);
5775 };
5776 let Some(responses) = request_task.await? else {
5777 return Ok(None);
5778 };
5779 let actions = join_all(responses.payload.into_iter().map(|response| {
5780 GetDeclarations { position }.response_from_proto(
5781 response.response,
5782 lsp_store.clone(),
5783 buffer.clone(),
5784 cx.clone(),
5785 )
5786 }))
5787 .await;
5788
5789 Ok(Some(
5790 actions
5791 .into_iter()
5792 .collect::<Result<Vec<Vec<_>>>>()?
5793 .into_iter()
5794 .flatten()
5795 .dedup()
5796 .collect(),
5797 ))
5798 })
5799 } else {
5800 let declarations_task = self.request_multiple_lsp_locally(
5801 buffer,
5802 Some(position),
5803 GetDeclarations { position },
5804 cx,
5805 );
5806 cx.background_spawn(async move {
5807 Ok(Some(
5808 declarations_task
5809 .await
5810 .into_iter()
5811 .flat_map(|(_, declarations)| declarations)
5812 .dedup()
5813 .collect(),
5814 ))
5815 })
5816 }
5817 }
5818
5819 pub fn type_definitions(
5820 &mut self,
5821 buffer: &Entity<Buffer>,
5822 position: PointUtf16,
5823 cx: &mut Context<Self>,
5824 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5825 if let Some((upstream_client, project_id)) = self.upstream_client() {
5826 let request = GetTypeDefinitions { position };
5827 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5828 return Task::ready(Ok(None));
5829 }
5830 let request_timeout = ProjectSettings::get_global(cx)
5831 .global_lsp_settings
5832 .get_request_timeout();
5833 let request_task = upstream_client.request_lsp(
5834 project_id,
5835 None,
5836 request_timeout,
5837 cx.background_executor().clone(),
5838 request.to_proto(project_id, buffer.read(cx)),
5839 );
5840 let buffer = buffer.clone();
5841 cx.spawn(async move |weak_lsp_store, cx| {
5842 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5843 return Ok(None);
5844 };
5845 let Some(responses) = request_task.await? else {
5846 return Ok(None);
5847 };
5848 let actions = join_all(responses.payload.into_iter().map(|response| {
5849 GetTypeDefinitions { position }.response_from_proto(
5850 response.response,
5851 lsp_store.clone(),
5852 buffer.clone(),
5853 cx.clone(),
5854 )
5855 }))
5856 .await;
5857
5858 Ok(Some(
5859 actions
5860 .into_iter()
5861 .collect::<Result<Vec<Vec<_>>>>()?
5862 .into_iter()
5863 .flatten()
5864 .dedup()
5865 .collect(),
5866 ))
5867 })
5868 } else {
5869 let type_definitions_task = self.request_multiple_lsp_locally(
5870 buffer,
5871 Some(position),
5872 GetTypeDefinitions { position },
5873 cx,
5874 );
5875 cx.background_spawn(async move {
5876 Ok(Some(
5877 type_definitions_task
5878 .await
5879 .into_iter()
5880 .flat_map(|(_, type_definitions)| type_definitions)
5881 .dedup()
5882 .collect(),
5883 ))
5884 })
5885 }
5886 }
5887
5888 pub fn implementations(
5889 &mut self,
5890 buffer: &Entity<Buffer>,
5891 position: PointUtf16,
5892 cx: &mut Context<Self>,
5893 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5894 if let Some((upstream_client, project_id)) = self.upstream_client() {
5895 let request = GetImplementations { position };
5896 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5897 return Task::ready(Ok(None));
5898 }
5899
5900 let request_timeout = ProjectSettings::get_global(cx)
5901 .global_lsp_settings
5902 .get_request_timeout();
5903 let request_task = upstream_client.request_lsp(
5904 project_id,
5905 None,
5906 request_timeout,
5907 cx.background_executor().clone(),
5908 request.to_proto(project_id, buffer.read(cx)),
5909 );
5910 let buffer = buffer.clone();
5911 cx.spawn(async move |weak_lsp_store, cx| {
5912 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5913 return Ok(None);
5914 };
5915 let Some(responses) = request_task.await? else {
5916 return Ok(None);
5917 };
5918 let actions = join_all(responses.payload.into_iter().map(|response| {
5919 GetImplementations { position }.response_from_proto(
5920 response.response,
5921 lsp_store.clone(),
5922 buffer.clone(),
5923 cx.clone(),
5924 )
5925 }))
5926 .await;
5927
5928 Ok(Some(
5929 actions
5930 .into_iter()
5931 .collect::<Result<Vec<Vec<_>>>>()?
5932 .into_iter()
5933 .flatten()
5934 .dedup()
5935 .collect(),
5936 ))
5937 })
5938 } else {
5939 let implementations_task = self.request_multiple_lsp_locally(
5940 buffer,
5941 Some(position),
5942 GetImplementations { position },
5943 cx,
5944 );
5945 cx.background_spawn(async move {
5946 Ok(Some(
5947 implementations_task
5948 .await
5949 .into_iter()
5950 .flat_map(|(_, implementations)| implementations)
5951 .dedup()
5952 .collect(),
5953 ))
5954 })
5955 }
5956 }
5957
5958 pub fn references(
5959 &mut self,
5960 buffer: &Entity<Buffer>,
5961 position: PointUtf16,
5962 cx: &mut Context<Self>,
5963 ) -> Task<Result<Option<Vec<Location>>>> {
5964 if let Some((upstream_client, project_id)) = self.upstream_client() {
5965 let request = GetReferences { position };
5966 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5967 return Task::ready(Ok(None));
5968 }
5969
5970 let request_timeout = ProjectSettings::get_global(cx)
5971 .global_lsp_settings
5972 .get_request_timeout();
5973 let request_task = upstream_client.request_lsp(
5974 project_id,
5975 None,
5976 request_timeout,
5977 cx.background_executor().clone(),
5978 request.to_proto(project_id, buffer.read(cx)),
5979 );
5980 let buffer = buffer.clone();
5981 cx.spawn(async move |weak_lsp_store, cx| {
5982 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5983 return Ok(None);
5984 };
5985 let Some(responses) = request_task.await? else {
5986 return Ok(None);
5987 };
5988
5989 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5990 GetReferences { position }.response_from_proto(
5991 lsp_response.response,
5992 lsp_store.clone(),
5993 buffer.clone(),
5994 cx.clone(),
5995 )
5996 }))
5997 .await
5998 .into_iter()
5999 .collect::<Result<Vec<Vec<_>>>>()?
6000 .into_iter()
6001 .flatten()
6002 .dedup()
6003 .collect();
6004 Ok(Some(locations))
6005 })
6006 } else {
6007 let references_task = self.request_multiple_lsp_locally(
6008 buffer,
6009 Some(position),
6010 GetReferences { position },
6011 cx,
6012 );
6013 cx.background_spawn(async move {
6014 Ok(Some(
6015 references_task
6016 .await
6017 .into_iter()
6018 .flat_map(|(_, references)| references)
6019 .dedup()
6020 .collect(),
6021 ))
6022 })
6023 }
6024 }
6025
6026 pub fn code_actions(
6027 &mut self,
6028 buffer: &Entity<Buffer>,
6029 range: Range<Anchor>,
6030 kinds: Option<Vec<CodeActionKind>>,
6031 cx: &mut Context<Self>,
6032 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6033 if let Some((upstream_client, project_id)) = self.upstream_client() {
6034 let request = GetCodeActions {
6035 range: range.clone(),
6036 kinds: kinds.clone(),
6037 };
6038 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6039 return Task::ready(Ok(None));
6040 }
6041 let request_timeout = ProjectSettings::get_global(cx)
6042 .global_lsp_settings
6043 .get_request_timeout();
6044 let request_task = upstream_client.request_lsp(
6045 project_id,
6046 None,
6047 request_timeout,
6048 cx.background_executor().clone(),
6049 request.to_proto(project_id, buffer.read(cx)),
6050 );
6051 let buffer = buffer.clone();
6052 cx.spawn(async move |weak_lsp_store, cx| {
6053 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6054 return Ok(None);
6055 };
6056 let Some(responses) = request_task.await? else {
6057 return Ok(None);
6058 };
6059 let actions = join_all(responses.payload.into_iter().map(|response| {
6060 GetCodeActions {
6061 range: range.clone(),
6062 kinds: kinds.clone(),
6063 }
6064 .response_from_proto(
6065 response.response,
6066 lsp_store.clone(),
6067 buffer.clone(),
6068 cx.clone(),
6069 )
6070 }))
6071 .await;
6072
6073 Ok(Some(
6074 actions
6075 .into_iter()
6076 .collect::<Result<Vec<Vec<_>>>>()?
6077 .into_iter()
6078 .flatten()
6079 .collect(),
6080 ))
6081 })
6082 } else {
6083 let all_actions_task = self.request_multiple_lsp_locally(
6084 buffer,
6085 Some(range.start),
6086 GetCodeActions { range, kinds },
6087 cx,
6088 );
6089 cx.background_spawn(async move {
6090 Ok(Some(
6091 all_actions_task
6092 .await
6093 .into_iter()
6094 .flat_map(|(_, actions)| actions)
6095 .collect(),
6096 ))
6097 })
6098 }
6099 }
6100
6101 #[inline(never)]
6102 pub fn completions(
6103 &self,
6104 buffer: &Entity<Buffer>,
6105 position: PointUtf16,
6106 context: CompletionContext,
6107 cx: &mut Context<Self>,
6108 ) -> Task<Result<Vec<CompletionResponse>>> {
6109 let language_registry = self.languages.clone();
6110
6111 if let Some((upstream_client, project_id)) = self.upstream_client() {
6112 let snapshot = buffer.read(cx).snapshot();
6113 let offset = position.to_offset(&snapshot);
6114 let scope = snapshot.language_scope_at(offset);
6115 let capable_lsps = self.all_capable_for_proto_request(
6116 buffer,
6117 |server_name, capabilities| {
6118 capabilities.completion_provider.is_some()
6119 && scope
6120 .as_ref()
6121 .map(|scope| scope.language_allowed(server_name))
6122 .unwrap_or(true)
6123 },
6124 cx,
6125 );
6126 if capable_lsps.is_empty() {
6127 return Task::ready(Ok(Vec::new()));
6128 }
6129
6130 let language = buffer.read(cx).language().cloned();
6131
6132 let buffer = buffer.clone();
6133
6134 cx.spawn(async move |this, cx| {
6135 let requests = join_all(
6136 capable_lsps
6137 .into_iter()
6138 .map(|(id, server_name)| {
6139 let request = GetCompletions {
6140 position,
6141 context: context.clone(),
6142 server_id: Some(id),
6143 };
6144 let buffer = buffer.clone();
6145 let language = language.clone();
6146 let lsp_adapter = language.as_ref().and_then(|language| {
6147 let adapters = language_registry.lsp_adapters(&language.name());
6148 adapters
6149 .iter()
6150 .find(|adapter| adapter.name() == server_name)
6151 .or_else(|| adapters.first())
6152 .cloned()
6153 });
6154 let upstream_client = upstream_client.clone();
6155 let response = this
6156 .update(cx, |this, cx| {
6157 this.send_lsp_proto_request(
6158 buffer,
6159 upstream_client,
6160 project_id,
6161 request,
6162 cx,
6163 )
6164 })
6165 .log_err();
6166 async move {
6167 let response = response?.await.log_err()?;
6168
6169 let completions = populate_labels_for_completions(
6170 response.completions,
6171 language,
6172 lsp_adapter,
6173 )
6174 .await;
6175
6176 Some(CompletionResponse {
6177 completions,
6178 display_options: CompletionDisplayOptions::default(),
6179 is_incomplete: response.is_incomplete,
6180 })
6181 }
6182 })
6183 .collect::<Vec<_>>(),
6184 );
6185 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6186 })
6187 } else if let Some(local) = self.as_local() {
6188 let snapshot = buffer.read(cx).snapshot();
6189 let offset = position.to_offset(&snapshot);
6190 let scope = snapshot.language_scope_at(offset);
6191 let language = snapshot.language().cloned();
6192 let completion_settings = language_settings(
6193 language.as_ref().map(|language| language.name()),
6194 buffer.read(cx).file(),
6195 cx,
6196 )
6197 .completions
6198 .clone();
6199 if !completion_settings.lsp {
6200 return Task::ready(Ok(Vec::new()));
6201 }
6202
6203 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6204 local
6205 .language_servers_for_buffer(buffer, cx)
6206 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6207 .filter(|(adapter, _)| {
6208 scope
6209 .as_ref()
6210 .map(|scope| scope.language_allowed(&adapter.name))
6211 .unwrap_or(true)
6212 })
6213 .map(|(_, server)| server.server_id())
6214 .collect()
6215 });
6216
6217 let buffer = buffer.clone();
6218 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6219 let lsp_timeout = if lsp_timeout > 0 {
6220 Some(Duration::from_millis(lsp_timeout))
6221 } else {
6222 None
6223 };
6224 cx.spawn(async move |this, cx| {
6225 let mut tasks = Vec::with_capacity(server_ids.len());
6226 this.update(cx, |lsp_store, cx| {
6227 for server_id in server_ids {
6228 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6229 let lsp_timeout = lsp_timeout
6230 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6231 let mut timeout = cx.background_spawn(async move {
6232 match lsp_timeout {
6233 Some(lsp_timeout) => {
6234 lsp_timeout.await;
6235 true
6236 },
6237 None => false,
6238 }
6239 }).fuse();
6240 let mut lsp_request = lsp_store.request_lsp(
6241 buffer.clone(),
6242 LanguageServerToQuery::Other(server_id),
6243 GetCompletions {
6244 position,
6245 context: context.clone(),
6246 server_id: Some(server_id),
6247 },
6248 cx,
6249 ).fuse();
6250 let new_task = cx.background_spawn(async move {
6251 select_biased! {
6252 response = lsp_request => anyhow::Ok(Some(response?)),
6253 timeout_happened = timeout => {
6254 if timeout_happened {
6255 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6256 Ok(None)
6257 } else {
6258 let completions = lsp_request.await?;
6259 Ok(Some(completions))
6260 }
6261 },
6262 }
6263 });
6264 tasks.push((lsp_adapter, new_task));
6265 }
6266 })?;
6267
6268 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6269 let completion_response = task.await.ok()??;
6270 let completions = populate_labels_for_completions(
6271 completion_response.completions,
6272 language.clone(),
6273 lsp_adapter,
6274 )
6275 .await;
6276 Some(CompletionResponse {
6277 completions,
6278 display_options: CompletionDisplayOptions::default(),
6279 is_incomplete: completion_response.is_incomplete,
6280 })
6281 });
6282
6283 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6284
6285 Ok(responses.into_iter().flatten().collect())
6286 })
6287 } else {
6288 Task::ready(Err(anyhow!("No upstream client or local language server")))
6289 }
6290 }
6291
6292 pub fn resolve_completions(
6293 &self,
6294 buffer: Entity<Buffer>,
6295 completion_indices: Vec<usize>,
6296 completions: Rc<RefCell<Box<[Completion]>>>,
6297 cx: &mut Context<Self>,
6298 ) -> Task<Result<bool>> {
6299 let client = self.upstream_client();
6300 let buffer_id = buffer.read(cx).remote_id();
6301 let buffer_snapshot = buffer.read(cx).snapshot();
6302
6303 if !self.check_if_capable_for_proto_request(
6304 &buffer,
6305 GetCompletions::can_resolve_completions,
6306 cx,
6307 ) {
6308 return Task::ready(Ok(false));
6309 }
6310 cx.spawn(async move |lsp_store, cx| {
6311 let request_timeout = cx.update(|app| {
6312 ProjectSettings::get_global(app)
6313 .global_lsp_settings
6314 .get_request_timeout()
6315 });
6316
6317 let mut did_resolve = false;
6318 if let Some((client, project_id)) = client {
6319 for completion_index in completion_indices {
6320 let server_id = {
6321 let completion = &completions.borrow()[completion_index];
6322 completion.source.server_id()
6323 };
6324 if let Some(server_id) = server_id {
6325 if Self::resolve_completion_remote(
6326 project_id,
6327 server_id,
6328 buffer_id,
6329 completions.clone(),
6330 completion_index,
6331 client.clone(),
6332 )
6333 .await
6334 .log_err()
6335 .is_some()
6336 {
6337 did_resolve = true;
6338 }
6339 } else {
6340 resolve_word_completion(
6341 &buffer_snapshot,
6342 &mut completions.borrow_mut()[completion_index],
6343 );
6344 }
6345 }
6346 } else {
6347 for completion_index in completion_indices {
6348 let server_id = {
6349 let completion = &completions.borrow()[completion_index];
6350 completion.source.server_id()
6351 };
6352 if let Some(server_id) = server_id {
6353 let server_and_adapter = lsp_store
6354 .read_with(cx, |lsp_store, _| {
6355 let server = lsp_store.language_server_for_id(server_id)?;
6356 let adapter =
6357 lsp_store.language_server_adapter_for_id(server.server_id())?;
6358 Some((server, adapter))
6359 })
6360 .ok()
6361 .flatten();
6362 let Some((server, adapter)) = server_and_adapter else {
6363 continue;
6364 };
6365
6366 let resolved = Self::resolve_completion_local(
6367 server,
6368 completions.clone(),
6369 completion_index,
6370 request_timeout,
6371 )
6372 .await
6373 .log_err()
6374 .is_some();
6375 if resolved {
6376 Self::regenerate_completion_labels(
6377 adapter,
6378 &buffer_snapshot,
6379 completions.clone(),
6380 completion_index,
6381 )
6382 .await
6383 .log_err();
6384 did_resolve = true;
6385 }
6386 } else {
6387 resolve_word_completion(
6388 &buffer_snapshot,
6389 &mut completions.borrow_mut()[completion_index],
6390 );
6391 }
6392 }
6393 }
6394
6395 Ok(did_resolve)
6396 })
6397 }
6398
6399 async fn resolve_completion_local(
6400 server: Arc<lsp::LanguageServer>,
6401 completions: Rc<RefCell<Box<[Completion]>>>,
6402 completion_index: usize,
6403 request_timeout: Duration,
6404 ) -> Result<()> {
6405 let server_id = server.server_id();
6406 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6407 return Ok(());
6408 }
6409
6410 let request = {
6411 let completion = &completions.borrow()[completion_index];
6412 match &completion.source {
6413 CompletionSource::Lsp {
6414 lsp_completion,
6415 resolved,
6416 server_id: completion_server_id,
6417 ..
6418 } => {
6419 if *resolved {
6420 return Ok(());
6421 }
6422 anyhow::ensure!(
6423 server_id == *completion_server_id,
6424 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6425 );
6426 server.request::<lsp::request::ResolveCompletionItem>(
6427 *lsp_completion.clone(),
6428 request_timeout,
6429 )
6430 }
6431 CompletionSource::BufferWord { .. }
6432 | CompletionSource::Dap { .. }
6433 | CompletionSource::Custom => {
6434 return Ok(());
6435 }
6436 }
6437 };
6438 let resolved_completion = request
6439 .await
6440 .into_response()
6441 .context("resolve completion")?;
6442
6443 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6444 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6445
6446 let mut completions = completions.borrow_mut();
6447 let completion = &mut completions[completion_index];
6448 if let CompletionSource::Lsp {
6449 lsp_completion,
6450 resolved,
6451 server_id: completion_server_id,
6452 ..
6453 } = &mut completion.source
6454 {
6455 if *resolved {
6456 return Ok(());
6457 }
6458 anyhow::ensure!(
6459 server_id == *completion_server_id,
6460 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6461 );
6462 **lsp_completion = resolved_completion;
6463 *resolved = true;
6464 }
6465 Ok(())
6466 }
6467
6468 async fn regenerate_completion_labels(
6469 adapter: Arc<CachedLspAdapter>,
6470 snapshot: &BufferSnapshot,
6471 completions: Rc<RefCell<Box<[Completion]>>>,
6472 completion_index: usize,
6473 ) -> Result<()> {
6474 let completion_item = completions.borrow()[completion_index]
6475 .source
6476 .lsp_completion(true)
6477 .map(Cow::into_owned);
6478 if let Some(lsp_documentation) = completion_item
6479 .as_ref()
6480 .and_then(|completion_item| completion_item.documentation.clone())
6481 {
6482 let mut completions = completions.borrow_mut();
6483 let completion = &mut completions[completion_index];
6484 completion.documentation = Some(lsp_documentation.into());
6485 } else {
6486 let mut completions = completions.borrow_mut();
6487 let completion = &mut completions[completion_index];
6488 completion.documentation = Some(CompletionDocumentation::Undocumented);
6489 }
6490
6491 let mut new_label = match completion_item {
6492 Some(completion_item) => {
6493 // Some language servers always return `detail` lazily via resolve, regardless of
6494 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6495 // See: https://github.com/yioneko/vtsls/issues/213
6496 let language = snapshot.language();
6497 match language {
6498 Some(language) => {
6499 adapter
6500 .labels_for_completions(
6501 std::slice::from_ref(&completion_item),
6502 language,
6503 )
6504 .await?
6505 }
6506 None => Vec::new(),
6507 }
6508 .pop()
6509 .flatten()
6510 .unwrap_or_else(|| {
6511 CodeLabel::fallback_for_completion(
6512 &completion_item,
6513 language.map(|language| language.as_ref()),
6514 )
6515 })
6516 }
6517 None => CodeLabel::plain(
6518 completions.borrow()[completion_index].new_text.clone(),
6519 None,
6520 ),
6521 };
6522 ensure_uniform_list_compatible_label(&mut new_label);
6523
6524 let mut completions = completions.borrow_mut();
6525 let completion = &mut completions[completion_index];
6526 if completion.label.filter_text() == new_label.filter_text() {
6527 completion.label = new_label;
6528 } else {
6529 log::error!(
6530 "Resolved completion changed display label from {} to {}. \
6531 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6532 completion.label.text(),
6533 new_label.text(),
6534 completion.label.filter_text(),
6535 new_label.filter_text()
6536 );
6537 }
6538
6539 Ok(())
6540 }
6541
6542 async fn resolve_completion_remote(
6543 project_id: u64,
6544 server_id: LanguageServerId,
6545 buffer_id: BufferId,
6546 completions: Rc<RefCell<Box<[Completion]>>>,
6547 completion_index: usize,
6548 client: AnyProtoClient,
6549 ) -> Result<()> {
6550 let lsp_completion = {
6551 let completion = &completions.borrow()[completion_index];
6552 match &completion.source {
6553 CompletionSource::Lsp {
6554 lsp_completion,
6555 resolved,
6556 server_id: completion_server_id,
6557 ..
6558 } => {
6559 anyhow::ensure!(
6560 server_id == *completion_server_id,
6561 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6562 );
6563 if *resolved {
6564 return Ok(());
6565 }
6566 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6567 }
6568 CompletionSource::Custom
6569 | CompletionSource::Dap { .. }
6570 | CompletionSource::BufferWord { .. } => {
6571 return Ok(());
6572 }
6573 }
6574 };
6575 let request = proto::ResolveCompletionDocumentation {
6576 project_id,
6577 language_server_id: server_id.0 as u64,
6578 lsp_completion,
6579 buffer_id: buffer_id.into(),
6580 };
6581
6582 let response = client
6583 .request(request)
6584 .await
6585 .context("completion documentation resolve proto request")?;
6586 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6587
6588 let documentation = if response.documentation.is_empty() {
6589 CompletionDocumentation::Undocumented
6590 } else if response.documentation_is_markdown {
6591 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6592 } else if response.documentation.lines().count() <= 1 {
6593 CompletionDocumentation::SingleLine(response.documentation.into())
6594 } else {
6595 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6596 };
6597
6598 let mut completions = completions.borrow_mut();
6599 let completion = &mut completions[completion_index];
6600 completion.documentation = Some(documentation);
6601 if let CompletionSource::Lsp {
6602 insert_range,
6603 lsp_completion,
6604 resolved,
6605 server_id: completion_server_id,
6606 lsp_defaults: _,
6607 } = &mut completion.source
6608 {
6609 let completion_insert_range = response
6610 .old_insert_start
6611 .and_then(deserialize_anchor)
6612 .zip(response.old_insert_end.and_then(deserialize_anchor));
6613 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6614
6615 if *resolved {
6616 return Ok(());
6617 }
6618 anyhow::ensure!(
6619 server_id == *completion_server_id,
6620 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6621 );
6622 **lsp_completion = resolved_lsp_completion;
6623 *resolved = true;
6624 }
6625
6626 let replace_range = response
6627 .old_replace_start
6628 .and_then(deserialize_anchor)
6629 .zip(response.old_replace_end.and_then(deserialize_anchor));
6630 if let Some((old_replace_start, old_replace_end)) = replace_range
6631 && !response.new_text.is_empty()
6632 {
6633 completion.new_text = response.new_text;
6634 completion.replace_range = old_replace_start..old_replace_end;
6635 }
6636
6637 Ok(())
6638 }
6639
6640 pub fn apply_additional_edits_for_completion(
6641 &self,
6642 buffer_handle: Entity<Buffer>,
6643 completions: Rc<RefCell<Box<[Completion]>>>,
6644 completion_index: usize,
6645 push_to_history: bool,
6646 cx: &mut Context<Self>,
6647 ) -> Task<Result<Option<Transaction>>> {
6648 if let Some((client, project_id)) = self.upstream_client() {
6649 let buffer = buffer_handle.read(cx);
6650 let buffer_id = buffer.remote_id();
6651 cx.spawn(async move |_, cx| {
6652 let request = {
6653 let completion = completions.borrow()[completion_index].clone();
6654 proto::ApplyCompletionAdditionalEdits {
6655 project_id,
6656 buffer_id: buffer_id.into(),
6657 completion: Some(Self::serialize_completion(&CoreCompletion {
6658 replace_range: completion.replace_range,
6659 new_text: completion.new_text,
6660 source: completion.source,
6661 })),
6662 }
6663 };
6664
6665 let Some(transaction) = client.request(request).await?.transaction else {
6666 return Ok(None);
6667 };
6668
6669 let transaction = language::proto::deserialize_transaction(transaction)?;
6670 buffer_handle
6671 .update(cx, |buffer, _| {
6672 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6673 })
6674 .await?;
6675 if push_to_history {
6676 buffer_handle.update(cx, |buffer, _| {
6677 buffer.push_transaction(transaction.clone(), Instant::now());
6678 buffer.finalize_last_transaction();
6679 });
6680 }
6681 Ok(Some(transaction))
6682 })
6683 } else {
6684 let request_timeout = ProjectSettings::get_global(cx)
6685 .global_lsp_settings
6686 .get_request_timeout();
6687
6688 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6689 let completion = &completions.borrow()[completion_index];
6690 let server_id = completion.source.server_id()?;
6691 Some(
6692 self.language_server_for_local_buffer(buffer, server_id, cx)?
6693 .1
6694 .clone(),
6695 )
6696 }) else {
6697 return Task::ready(Ok(None));
6698 };
6699
6700 cx.spawn(async move |this, cx| {
6701 Self::resolve_completion_local(
6702 server.clone(),
6703 completions.clone(),
6704 completion_index,
6705 request_timeout,
6706 )
6707 .await
6708 .context("resolving completion")?;
6709 let completion = completions.borrow()[completion_index].clone();
6710 let additional_text_edits = completion
6711 .source
6712 .lsp_completion(true)
6713 .as_ref()
6714 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6715 if let Some(edits) = additional_text_edits {
6716 let edits = this
6717 .update(cx, |this, cx| {
6718 this.as_local_mut().unwrap().edits_from_lsp(
6719 &buffer_handle,
6720 edits,
6721 server.server_id(),
6722 None,
6723 cx,
6724 )
6725 })?
6726 .await?;
6727
6728 buffer_handle.update(cx, |buffer, cx| {
6729 buffer.finalize_last_transaction();
6730 buffer.start_transaction();
6731
6732 for (range, text) in edits {
6733 let primary = &completion.replace_range;
6734
6735 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6736 // and the primary completion is just an insertion (empty range), then this is likely
6737 // an auto-import scenario and should not be considered overlapping
6738 // https://github.com/zed-industries/zed/issues/26136
6739 let is_file_start_auto_import = {
6740 let snapshot = buffer.snapshot();
6741 let primary_start_point = primary.start.to_point(&snapshot);
6742 let range_start_point = range.start.to_point(&snapshot);
6743
6744 let result = primary_start_point.row == 0
6745 && primary_start_point.column == 0
6746 && range_start_point.row == 0
6747 && range_start_point.column == 0;
6748
6749 result
6750 };
6751
6752 let has_overlap = if is_file_start_auto_import {
6753 false
6754 } else {
6755 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6756 && primary.end.cmp(&range.start, buffer).is_ge();
6757 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6758 && range.end.cmp(&primary.end, buffer).is_ge();
6759 let result = start_within || end_within;
6760 result
6761 };
6762
6763 //Skip additional edits which overlap with the primary completion edit
6764 //https://github.com/zed-industries/zed/pull/1871
6765 if !has_overlap {
6766 buffer.edit([(range, text)], None, cx);
6767 }
6768 }
6769
6770 let transaction = if buffer.end_transaction(cx).is_some() {
6771 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6772 if !push_to_history {
6773 buffer.forget_transaction(transaction.id);
6774 }
6775 Some(transaction)
6776 } else {
6777 None
6778 };
6779 Ok(transaction)
6780 })
6781 } else {
6782 Ok(None)
6783 }
6784 })
6785 }
6786 }
6787
6788 pub fn pull_diagnostics(
6789 &mut self,
6790 buffer: Entity<Buffer>,
6791 cx: &mut Context<Self>,
6792 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6793 let buffer_id = buffer.read(cx).remote_id();
6794
6795 if let Some((client, upstream_project_id)) = self.upstream_client() {
6796 let mut suitable_capabilities = None;
6797 // Are we capable for proto request?
6798 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6799 &buffer,
6800 |capabilities| {
6801 if let Some(caps) = &capabilities.diagnostic_provider {
6802 suitable_capabilities = Some(caps.clone());
6803 true
6804 } else {
6805 false
6806 }
6807 },
6808 cx,
6809 );
6810 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6811 let Some(dynamic_caps) = suitable_capabilities else {
6812 return Task::ready(Ok(None));
6813 };
6814 assert!(any_server_has_diagnostics_provider);
6815
6816 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6817 let request = GetDocumentDiagnostics {
6818 previous_result_id: None,
6819 identifier,
6820 registration_id: None,
6821 };
6822 let request_timeout = ProjectSettings::get_global(cx)
6823 .global_lsp_settings
6824 .get_request_timeout();
6825 let request_task = client.request_lsp(
6826 upstream_project_id,
6827 None,
6828 request_timeout,
6829 cx.background_executor().clone(),
6830 request.to_proto(upstream_project_id, buffer.read(cx)),
6831 );
6832 cx.background_spawn(async move {
6833 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6834 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6835 // Do not attempt to further process the dummy responses here.
6836 let _response = request_task.await?;
6837 Ok(None)
6838 })
6839 } else {
6840 let servers = buffer.update(cx, |buffer, cx| {
6841 self.running_language_servers_for_local_buffer(buffer, cx)
6842 .map(|(_, server)| server.clone())
6843 .collect::<Vec<_>>()
6844 });
6845
6846 let pull_diagnostics = servers
6847 .into_iter()
6848 .flat_map(|server| {
6849 let result = maybe!({
6850 let local = self.as_local()?;
6851 let server_id = server.server_id();
6852 let providers_with_identifiers = local
6853 .language_server_dynamic_registrations
6854 .get(&server_id)
6855 .into_iter()
6856 .flat_map(|registrations| registrations.diagnostics.clone())
6857 .collect::<Vec<_>>();
6858 Some(
6859 providers_with_identifiers
6860 .into_iter()
6861 .map(|(registration_id, dynamic_caps)| {
6862 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6863 let registration_id = registration_id.map(SharedString::from);
6864 let result_id = self.result_id_for_buffer_pull(
6865 server_id,
6866 buffer_id,
6867 ®istration_id,
6868 cx,
6869 );
6870 self.request_lsp(
6871 buffer.clone(),
6872 LanguageServerToQuery::Other(server_id),
6873 GetDocumentDiagnostics {
6874 previous_result_id: result_id,
6875 registration_id,
6876 identifier,
6877 },
6878 cx,
6879 )
6880 })
6881 .collect::<Vec<_>>(),
6882 )
6883 });
6884
6885 result.unwrap_or_default()
6886 })
6887 .collect::<Vec<_>>();
6888
6889 cx.background_spawn(async move {
6890 let mut responses = Vec::new();
6891 for diagnostics in join_all(pull_diagnostics).await {
6892 responses.extend(diagnostics?);
6893 }
6894 Ok(Some(responses))
6895 })
6896 }
6897 }
6898
6899 pub fn applicable_inlay_chunks(
6900 &mut self,
6901 buffer: &Entity<Buffer>,
6902 ranges: &[Range<text::Anchor>],
6903 cx: &mut Context<Self>,
6904 ) -> Vec<Range<BufferRow>> {
6905 let buffer_snapshot = buffer.read(cx).snapshot();
6906 let ranges = ranges
6907 .iter()
6908 .map(|range| range.to_point(&buffer_snapshot))
6909 .collect::<Vec<_>>();
6910
6911 self.latest_lsp_data(buffer, cx)
6912 .inlay_hints
6913 .applicable_chunks(ranges.as_slice())
6914 .map(|chunk| chunk.row_range())
6915 .collect()
6916 }
6917
6918 pub fn invalidate_inlay_hints<'a>(
6919 &'a mut self,
6920 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6921 ) {
6922 for buffer_id in for_buffers {
6923 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6924 lsp_data.inlay_hints.clear();
6925 }
6926 }
6927 }
6928
6929 pub fn inlay_hints(
6930 &mut self,
6931 invalidate: InvalidationStrategy,
6932 buffer: Entity<Buffer>,
6933 ranges: Vec<Range<text::Anchor>>,
6934 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6935 cx: &mut Context<Self>,
6936 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6937 let next_hint_id = self.next_hint_id.clone();
6938 let lsp_data = self.latest_lsp_data(&buffer, cx);
6939 let query_version = lsp_data.buffer_version.clone();
6940 let mut lsp_refresh_requested = false;
6941 let for_server = if let InvalidationStrategy::RefreshRequested {
6942 server_id,
6943 request_id,
6944 } = invalidate
6945 {
6946 let invalidated = lsp_data
6947 .inlay_hints
6948 .invalidate_for_server_refresh(server_id, request_id);
6949 lsp_refresh_requested = invalidated;
6950 Some(server_id)
6951 } else {
6952 None
6953 };
6954 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6955 let known_chunks = known_chunks
6956 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6957 .map(|(_, known_chunks)| known_chunks)
6958 .unwrap_or_default();
6959
6960 let buffer_snapshot = buffer.read(cx).snapshot();
6961 let ranges = ranges
6962 .iter()
6963 .map(|range| range.to_point(&buffer_snapshot))
6964 .collect::<Vec<_>>();
6965
6966 let mut hint_fetch_tasks = Vec::new();
6967 let mut cached_inlay_hints = None;
6968 let mut ranges_to_query = None;
6969 let applicable_chunks = existing_inlay_hints
6970 .applicable_chunks(ranges.as_slice())
6971 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6972 .collect::<Vec<_>>();
6973 if applicable_chunks.is_empty() {
6974 return HashMap::default();
6975 }
6976
6977 for row_chunk in applicable_chunks {
6978 match (
6979 existing_inlay_hints
6980 .cached_hints(&row_chunk)
6981 .filter(|_| !lsp_refresh_requested)
6982 .cloned(),
6983 existing_inlay_hints
6984 .fetched_hints(&row_chunk)
6985 .as_ref()
6986 .filter(|_| !lsp_refresh_requested)
6987 .cloned(),
6988 ) {
6989 (None, None) => {
6990 let chunk_range = row_chunk.anchor_range();
6991 ranges_to_query
6992 .get_or_insert_with(Vec::new)
6993 .push((row_chunk, chunk_range));
6994 }
6995 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6996 (Some(cached_hints), None) => {
6997 for (server_id, cached_hints) in cached_hints {
6998 if for_server.is_none_or(|for_server| for_server == server_id) {
6999 cached_inlay_hints
7000 .get_or_insert_with(HashMap::default)
7001 .entry(row_chunk.row_range())
7002 .or_insert_with(HashMap::default)
7003 .entry(server_id)
7004 .or_insert_with(Vec::new)
7005 .extend(cached_hints);
7006 }
7007 }
7008 }
7009 (Some(cached_hints), Some(fetched_hints)) => {
7010 hint_fetch_tasks.push((row_chunk, fetched_hints));
7011 for (server_id, cached_hints) in cached_hints {
7012 if for_server.is_none_or(|for_server| for_server == server_id) {
7013 cached_inlay_hints
7014 .get_or_insert_with(HashMap::default)
7015 .entry(row_chunk.row_range())
7016 .or_insert_with(HashMap::default)
7017 .entry(server_id)
7018 .or_insert_with(Vec::new)
7019 .extend(cached_hints);
7020 }
7021 }
7022 }
7023 }
7024 }
7025
7026 if hint_fetch_tasks.is_empty()
7027 && ranges_to_query
7028 .as_ref()
7029 .is_none_or(|ranges| ranges.is_empty())
7030 && let Some(cached_inlay_hints) = cached_inlay_hints
7031 {
7032 cached_inlay_hints
7033 .into_iter()
7034 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7035 .collect()
7036 } else {
7037 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7038 // When a server refresh was requested, other servers' cached hints
7039 // are unaffected by the refresh and must be included in the result.
7040 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7041 // removes all visible hints but only adds back the requesting
7042 // server's new hints, permanently losing other servers' hints.
7043 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7044 lsp_data
7045 .inlay_hints
7046 .cached_hints(&chunk)
7047 .cloned()
7048 .unwrap_or_default()
7049 } else {
7050 HashMap::default()
7051 };
7052
7053 let next_hint_id = next_hint_id.clone();
7054 let buffer = buffer.clone();
7055 let query_version = query_version.clone();
7056 let new_inlay_hints = cx
7057 .spawn(async move |lsp_store, cx| {
7058 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7059 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7060 })?;
7061 new_fetch_task
7062 .await
7063 .and_then(|new_hints_by_server| {
7064 lsp_store.update(cx, |lsp_store, cx| {
7065 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7066 let update_cache = lsp_data.buffer_version == query_version;
7067 if new_hints_by_server.is_empty() {
7068 if update_cache {
7069 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7070 }
7071 other_servers_cached
7072 } else {
7073 let mut result = other_servers_cached;
7074 for (server_id, new_hints) in new_hints_by_server {
7075 let new_hints = new_hints
7076 .into_iter()
7077 .map(|new_hint| {
7078 (
7079 InlayId::Hint(next_hint_id.fetch_add(
7080 1,
7081 atomic::Ordering::AcqRel,
7082 )),
7083 new_hint,
7084 )
7085 })
7086 .collect::<Vec<_>>();
7087 if update_cache {
7088 lsp_data.inlay_hints.insert_new_hints(
7089 chunk,
7090 server_id,
7091 new_hints.clone(),
7092 );
7093 }
7094 result.insert(server_id, new_hints);
7095 }
7096 result
7097 }
7098 })
7099 })
7100 .map_err(Arc::new)
7101 })
7102 .shared();
7103
7104 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7105 *fetch_task = Some(new_inlay_hints.clone());
7106 hint_fetch_tasks.push((chunk, new_inlay_hints));
7107 }
7108
7109 cached_inlay_hints
7110 .unwrap_or_default()
7111 .into_iter()
7112 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7113 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7114 (
7115 chunk.row_range(),
7116 cx.spawn(async move |_, _| {
7117 hints_fetch.await.map_err(|e| {
7118 if e.error_code() != ErrorCode::Internal {
7119 anyhow!(e.error_code())
7120 } else {
7121 anyhow!("{e:#}")
7122 }
7123 })
7124 }),
7125 )
7126 }))
7127 .collect()
7128 }
7129 }
7130
7131 fn fetch_inlay_hints(
7132 &mut self,
7133 for_server: Option<LanguageServerId>,
7134 buffer: &Entity<Buffer>,
7135 range: Range<Anchor>,
7136 cx: &mut Context<Self>,
7137 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7138 let request = InlayHints {
7139 range: range.clone(),
7140 };
7141 if let Some((upstream_client, project_id)) = self.upstream_client() {
7142 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7143 return Task::ready(Ok(HashMap::default()));
7144 }
7145 let request_timeout = ProjectSettings::get_global(cx)
7146 .global_lsp_settings
7147 .get_request_timeout();
7148 let request_task = upstream_client.request_lsp(
7149 project_id,
7150 for_server.map(|id| id.to_proto()),
7151 request_timeout,
7152 cx.background_executor().clone(),
7153 request.to_proto(project_id, buffer.read(cx)),
7154 );
7155 let buffer = buffer.clone();
7156 cx.spawn(async move |weak_lsp_store, cx| {
7157 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7158 return Ok(HashMap::default());
7159 };
7160 let Some(responses) = request_task.await? else {
7161 return Ok(HashMap::default());
7162 };
7163
7164 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7165 let lsp_store = lsp_store.clone();
7166 let buffer = buffer.clone();
7167 let cx = cx.clone();
7168 let request = request.clone();
7169 async move {
7170 (
7171 LanguageServerId::from_proto(response.server_id),
7172 request
7173 .response_from_proto(response.response, lsp_store, buffer, cx)
7174 .await,
7175 )
7176 }
7177 }))
7178 .await;
7179
7180 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7181 let mut has_errors = false;
7182 let inlay_hints = inlay_hints
7183 .into_iter()
7184 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7185 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7186 Err(e) => {
7187 has_errors = true;
7188 log::error!("{e:#}");
7189 None
7190 }
7191 })
7192 .map(|(server_id, mut new_hints)| {
7193 new_hints.retain(|hint| {
7194 hint.position.is_valid(&buffer_snapshot)
7195 && range.start.is_valid(&buffer_snapshot)
7196 && range.end.is_valid(&buffer_snapshot)
7197 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7198 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7199 });
7200 (server_id, new_hints)
7201 })
7202 .collect::<HashMap<_, _>>();
7203 anyhow::ensure!(
7204 !has_errors || !inlay_hints.is_empty(),
7205 "Failed to fetch inlay hints"
7206 );
7207 Ok(inlay_hints)
7208 })
7209 } else {
7210 let inlay_hints_task = match for_server {
7211 Some(server_id) => {
7212 let server_task = self.request_lsp(
7213 buffer.clone(),
7214 LanguageServerToQuery::Other(server_id),
7215 request,
7216 cx,
7217 );
7218 cx.background_spawn(async move {
7219 let mut responses = Vec::new();
7220 match server_task.await {
7221 Ok(response) => responses.push((server_id, response)),
7222 // rust-analyzer likes to error with this when its still loading up
7223 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7224 Err(e) => log::error!(
7225 "Error handling response for inlay hints request: {e:#}"
7226 ),
7227 }
7228 responses
7229 })
7230 }
7231 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7232 };
7233 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7234 cx.background_spawn(async move {
7235 Ok(inlay_hints_task
7236 .await
7237 .into_iter()
7238 .map(|(server_id, mut new_hints)| {
7239 new_hints.retain(|hint| {
7240 hint.position.is_valid(&buffer_snapshot)
7241 && range.start.is_valid(&buffer_snapshot)
7242 && range.end.is_valid(&buffer_snapshot)
7243 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7244 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7245 });
7246 (server_id, new_hints)
7247 })
7248 .collect())
7249 })
7250 }
7251 }
7252
7253 fn diagnostic_registration_exists(
7254 &self,
7255 server_id: LanguageServerId,
7256 registration_id: &Option<SharedString>,
7257 ) -> bool {
7258 let Some(local) = self.as_local() else {
7259 return false;
7260 };
7261 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7262 else {
7263 return false;
7264 };
7265 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7266 registrations.diagnostics.contains_key(®istration_key)
7267 }
7268
7269 pub fn pull_diagnostics_for_buffer(
7270 &mut self,
7271 buffer: Entity<Buffer>,
7272 cx: &mut Context<Self>,
7273 ) -> Task<anyhow::Result<()>> {
7274 let diagnostics = self.pull_diagnostics(buffer, cx);
7275 cx.spawn(async move |lsp_store, cx| {
7276 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7277 return Ok(());
7278 };
7279 lsp_store.update(cx, |lsp_store, cx| {
7280 if lsp_store.as_local().is_none() {
7281 return;
7282 }
7283
7284 let mut unchanged_buffers = HashMap::default();
7285 let server_diagnostics_updates = diagnostics
7286 .into_iter()
7287 .filter_map(|diagnostics_set| match diagnostics_set {
7288 LspPullDiagnostics::Response {
7289 server_id,
7290 uri,
7291 diagnostics,
7292 registration_id,
7293 } => Some((server_id, uri, diagnostics, registration_id)),
7294 LspPullDiagnostics::Default => None,
7295 })
7296 .filter(|(server_id, _, _, registration_id)| {
7297 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7298 })
7299 .fold(
7300 HashMap::default(),
7301 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7302 let (result_id, diagnostics) = match diagnostics {
7303 PulledDiagnostics::Unchanged { result_id } => {
7304 unchanged_buffers
7305 .entry(new_registration_id.clone())
7306 .or_insert_with(HashSet::default)
7307 .insert(uri.clone());
7308 (Some(result_id), Vec::new())
7309 }
7310 PulledDiagnostics::Changed {
7311 result_id,
7312 diagnostics,
7313 } => (result_id, diagnostics),
7314 };
7315 let disk_based_sources = Cow::Owned(
7316 lsp_store
7317 .language_server_adapter_for_id(server_id)
7318 .as_ref()
7319 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7320 .unwrap_or(&[])
7321 .to_vec(),
7322 );
7323 acc.entry(server_id)
7324 .or_insert_with(HashMap::default)
7325 .entry(new_registration_id.clone())
7326 .or_insert_with(Vec::new)
7327 .push(DocumentDiagnosticsUpdate {
7328 server_id,
7329 diagnostics: lsp::PublishDiagnosticsParams {
7330 uri,
7331 diagnostics,
7332 version: None,
7333 },
7334 result_id: result_id.map(SharedString::new),
7335 disk_based_sources,
7336 registration_id: new_registration_id,
7337 });
7338 acc
7339 },
7340 );
7341
7342 for diagnostic_updates in server_diagnostics_updates.into_values() {
7343 for (registration_id, diagnostic_updates) in diagnostic_updates {
7344 lsp_store
7345 .merge_lsp_diagnostics(
7346 DiagnosticSourceKind::Pulled,
7347 diagnostic_updates,
7348 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7349 DiagnosticSourceKind::Pulled => {
7350 old_diagnostic.registration_id != registration_id
7351 || unchanged_buffers
7352 .get(&old_diagnostic.registration_id)
7353 .is_some_and(|unchanged_buffers| {
7354 unchanged_buffers.contains(&document_uri)
7355 })
7356 }
7357 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7358 true
7359 }
7360 },
7361 cx,
7362 )
7363 .log_err();
7364 }
7365 }
7366 })
7367 })
7368 }
7369
7370 pub fn signature_help<T: ToPointUtf16>(
7371 &mut self,
7372 buffer: &Entity<Buffer>,
7373 position: T,
7374 cx: &mut Context<Self>,
7375 ) -> Task<Option<Vec<SignatureHelp>>> {
7376 let position = position.to_point_utf16(buffer.read(cx));
7377
7378 if let Some((client, upstream_project_id)) = self.upstream_client() {
7379 let request = GetSignatureHelp { position };
7380 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7381 return Task::ready(None);
7382 }
7383 let request_timeout = ProjectSettings::get_global(cx)
7384 .global_lsp_settings
7385 .get_request_timeout();
7386 let request_task = client.request_lsp(
7387 upstream_project_id,
7388 None,
7389 request_timeout,
7390 cx.background_executor().clone(),
7391 request.to_proto(upstream_project_id, buffer.read(cx)),
7392 );
7393 let buffer = buffer.clone();
7394 cx.spawn(async move |weak_lsp_store, cx| {
7395 let lsp_store = weak_lsp_store.upgrade()?;
7396 let signatures = join_all(
7397 request_task
7398 .await
7399 .log_err()
7400 .flatten()
7401 .map(|response| response.payload)
7402 .unwrap_or_default()
7403 .into_iter()
7404 .map(|response| {
7405 let response = GetSignatureHelp { position }.response_from_proto(
7406 response.response,
7407 lsp_store.clone(),
7408 buffer.clone(),
7409 cx.clone(),
7410 );
7411 async move { response.await.log_err().flatten() }
7412 }),
7413 )
7414 .await
7415 .into_iter()
7416 .flatten()
7417 .collect();
7418 Some(signatures)
7419 })
7420 } else {
7421 let all_actions_task = self.request_multiple_lsp_locally(
7422 buffer,
7423 Some(position),
7424 GetSignatureHelp { position },
7425 cx,
7426 );
7427 cx.background_spawn(async move {
7428 Some(
7429 all_actions_task
7430 .await
7431 .into_iter()
7432 .flat_map(|(_, actions)| actions)
7433 .collect::<Vec<_>>(),
7434 )
7435 })
7436 }
7437 }
7438
7439 pub fn hover(
7440 &mut self,
7441 buffer: &Entity<Buffer>,
7442 position: PointUtf16,
7443 cx: &mut Context<Self>,
7444 ) -> Task<Option<Vec<Hover>>> {
7445 if let Some((client, upstream_project_id)) = self.upstream_client() {
7446 let request = GetHover { position };
7447 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7448 return Task::ready(None);
7449 }
7450 let request_timeout = ProjectSettings::get_global(cx)
7451 .global_lsp_settings
7452 .get_request_timeout();
7453 let request_task = client.request_lsp(
7454 upstream_project_id,
7455 None,
7456 request_timeout,
7457 cx.background_executor().clone(),
7458 request.to_proto(upstream_project_id, buffer.read(cx)),
7459 );
7460 let buffer = buffer.clone();
7461 cx.spawn(async move |weak_lsp_store, cx| {
7462 let lsp_store = weak_lsp_store.upgrade()?;
7463 let hovers = join_all(
7464 request_task
7465 .await
7466 .log_err()
7467 .flatten()
7468 .map(|response| response.payload)
7469 .unwrap_or_default()
7470 .into_iter()
7471 .map(|response| {
7472 let response = GetHover { position }.response_from_proto(
7473 response.response,
7474 lsp_store.clone(),
7475 buffer.clone(),
7476 cx.clone(),
7477 );
7478 async move {
7479 response
7480 .await
7481 .log_err()
7482 .flatten()
7483 .and_then(remove_empty_hover_blocks)
7484 }
7485 }),
7486 )
7487 .await
7488 .into_iter()
7489 .flatten()
7490 .collect();
7491 Some(hovers)
7492 })
7493 } else {
7494 let all_actions_task = self.request_multiple_lsp_locally(
7495 buffer,
7496 Some(position),
7497 GetHover { position },
7498 cx,
7499 );
7500 cx.background_spawn(async move {
7501 Some(
7502 all_actions_task
7503 .await
7504 .into_iter()
7505 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7506 .collect::<Vec<Hover>>(),
7507 )
7508 })
7509 }
7510 }
7511
7512 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7513 let language_registry = self.languages.clone();
7514
7515 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7516 let request = upstream_client.request(proto::GetProjectSymbols {
7517 project_id: *project_id,
7518 query: query.to_string(),
7519 });
7520 cx.foreground_executor().spawn(async move {
7521 let response = request.await?;
7522 let mut symbols = Vec::new();
7523 let core_symbols = response
7524 .symbols
7525 .into_iter()
7526 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7527 .collect::<Vec<_>>();
7528 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7529 .await;
7530 Ok(symbols)
7531 })
7532 } else if let Some(local) = self.as_local() {
7533 struct WorkspaceSymbolsResult {
7534 server_id: LanguageServerId,
7535 lsp_adapter: Arc<CachedLspAdapter>,
7536 worktree: WeakEntity<Worktree>,
7537 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7538 }
7539
7540 let mut requests = Vec::new();
7541 let mut requested_servers = BTreeSet::new();
7542 let request_timeout = ProjectSettings::get_global(cx)
7543 .global_lsp_settings
7544 .get_request_timeout();
7545
7546 for (seed, state) in local.language_server_ids.iter() {
7547 let Some(worktree_handle) = self
7548 .worktree_store
7549 .read(cx)
7550 .worktree_for_id(seed.worktree_id, cx)
7551 else {
7552 continue;
7553 };
7554
7555 let worktree = worktree_handle.read(cx);
7556 if !worktree.is_visible() {
7557 continue;
7558 }
7559
7560 if !requested_servers.insert(state.id) {
7561 continue;
7562 }
7563
7564 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7565 Some(LanguageServerState::Running {
7566 adapter, server, ..
7567 }) => (adapter.clone(), server),
7568
7569 _ => continue,
7570 };
7571
7572 let supports_workspace_symbol_request =
7573 match server.capabilities().workspace_symbol_provider {
7574 Some(OneOf::Left(supported)) => supported,
7575 Some(OneOf::Right(_)) => true,
7576 None => false,
7577 };
7578
7579 if !supports_workspace_symbol_request {
7580 continue;
7581 }
7582
7583 let worktree_handle = worktree_handle.clone();
7584 let server_id = server.server_id();
7585 requests.push(
7586 server
7587 .request::<lsp::request::WorkspaceSymbolRequest>(
7588 lsp::WorkspaceSymbolParams {
7589 query: query.to_string(),
7590 ..Default::default()
7591 },
7592 request_timeout,
7593 )
7594 .map(move |response| {
7595 let lsp_symbols = response
7596 .into_response()
7597 .context("workspace symbols request")
7598 .log_err()
7599 .flatten()
7600 .map(|symbol_response| match symbol_response {
7601 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7602 flat_responses
7603 .into_iter()
7604 .map(|lsp_symbol| {
7605 (
7606 lsp_symbol.name,
7607 lsp_symbol.kind,
7608 lsp_symbol.location,
7609 lsp_symbol.container_name,
7610 )
7611 })
7612 .collect::<Vec<_>>()
7613 }
7614 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7615 nested_responses
7616 .into_iter()
7617 .filter_map(|lsp_symbol| {
7618 let location = match lsp_symbol.location {
7619 OneOf::Left(location) => location,
7620 OneOf::Right(_) => {
7621 log::error!(
7622 "Unexpected: client capabilities \
7623 forbid symbol resolutions in \
7624 workspace.symbol.resolveSupport"
7625 );
7626 return None;
7627 }
7628 };
7629 Some((
7630 lsp_symbol.name,
7631 lsp_symbol.kind,
7632 location,
7633 lsp_symbol.container_name,
7634 ))
7635 })
7636 .collect::<Vec<_>>()
7637 }
7638 })
7639 .unwrap_or_default();
7640
7641 WorkspaceSymbolsResult {
7642 server_id,
7643 lsp_adapter,
7644 worktree: worktree_handle.downgrade(),
7645 lsp_symbols,
7646 }
7647 }),
7648 );
7649 }
7650
7651 cx.spawn(async move |this, cx| {
7652 let responses = futures::future::join_all(requests).await;
7653 let this = match this.upgrade() {
7654 Some(this) => this,
7655 None => return Ok(Vec::new()),
7656 };
7657
7658 let mut symbols = Vec::new();
7659 for result in responses {
7660 let core_symbols = this.update(cx, |this, cx| {
7661 result
7662 .lsp_symbols
7663 .into_iter()
7664 .filter_map(
7665 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7666 let abs_path = symbol_location.uri.to_file_path().ok()?;
7667 let source_worktree = result.worktree.upgrade()?;
7668 let source_worktree_id = source_worktree.read(cx).id();
7669
7670 let path = if let Some((tree, rel_path)) =
7671 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7672 {
7673 let worktree_id = tree.read(cx).id();
7674 SymbolLocation::InProject(ProjectPath {
7675 worktree_id,
7676 path: rel_path,
7677 })
7678 } else {
7679 SymbolLocation::OutsideProject {
7680 signature: this.symbol_signature(&abs_path),
7681 abs_path: abs_path.into(),
7682 }
7683 };
7684
7685 Some(CoreSymbol {
7686 source_language_server_id: result.server_id,
7687 language_server_name: result.lsp_adapter.name.clone(),
7688 source_worktree_id,
7689 path,
7690 kind: symbol_kind,
7691 name: collapse_newlines(&symbol_name, "↵ "),
7692 range: range_from_lsp(symbol_location.range),
7693 container_name: container_name
7694 .map(|c| collapse_newlines(&c, "↵ ")),
7695 })
7696 },
7697 )
7698 .collect::<Vec<_>>()
7699 });
7700
7701 populate_labels_for_symbols(
7702 core_symbols,
7703 &language_registry,
7704 Some(result.lsp_adapter),
7705 &mut symbols,
7706 )
7707 .await;
7708 }
7709
7710 Ok(symbols)
7711 })
7712 } else {
7713 Task::ready(Err(anyhow!("No upstream client or local language server")))
7714 }
7715 }
7716
7717 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7718 let mut summary = DiagnosticSummary::default();
7719 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7720 summary.error_count += path_summary.error_count;
7721 summary.warning_count += path_summary.warning_count;
7722 }
7723 summary
7724 }
7725
7726 /// Returns the diagnostic summary for a specific project path.
7727 pub fn diagnostic_summary_for_path(
7728 &self,
7729 project_path: &ProjectPath,
7730 _: &App,
7731 ) -> DiagnosticSummary {
7732 if let Some(summaries) = self
7733 .diagnostic_summaries
7734 .get(&project_path.worktree_id)
7735 .and_then(|map| map.get(&project_path.path))
7736 {
7737 let (error_count, warning_count) = summaries.iter().fold(
7738 (0, 0),
7739 |(error_count, warning_count), (_language_server_id, summary)| {
7740 (
7741 error_count + summary.error_count,
7742 warning_count + summary.warning_count,
7743 )
7744 },
7745 );
7746
7747 DiagnosticSummary {
7748 error_count,
7749 warning_count,
7750 }
7751 } else {
7752 DiagnosticSummary::default()
7753 }
7754 }
7755
7756 pub fn diagnostic_summaries<'a>(
7757 &'a self,
7758 include_ignored: bool,
7759 cx: &'a App,
7760 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7761 self.worktree_store
7762 .read(cx)
7763 .visible_worktrees(cx)
7764 .filter_map(|worktree| {
7765 let worktree = worktree.read(cx);
7766 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7767 })
7768 .flat_map(move |(worktree, summaries)| {
7769 let worktree_id = worktree.id();
7770 summaries
7771 .iter()
7772 .filter(move |(path, _)| {
7773 include_ignored
7774 || worktree
7775 .entry_for_path(path.as_ref())
7776 .is_some_and(|entry| !entry.is_ignored)
7777 })
7778 .flat_map(move |(path, summaries)| {
7779 summaries.iter().map(move |(server_id, summary)| {
7780 (
7781 ProjectPath {
7782 worktree_id,
7783 path: path.clone(),
7784 },
7785 *server_id,
7786 *summary,
7787 )
7788 })
7789 })
7790 })
7791 }
7792
7793 pub fn on_buffer_edited(
7794 &mut self,
7795 buffer: Entity<Buffer>,
7796 cx: &mut Context<Self>,
7797 ) -> Option<()> {
7798 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7799 Some(
7800 self.as_local()?
7801 .language_servers_for_buffer(buffer, cx)
7802 .map(|i| i.1.clone())
7803 .collect(),
7804 )
7805 })?;
7806
7807 let buffer = buffer.read(cx);
7808 let file = File::from_dyn(buffer.file())?;
7809 let abs_path = file.as_local()?.abs_path(cx);
7810 let uri = lsp::Uri::from_file_path(&abs_path)
7811 .ok()
7812 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7813 .log_err()?;
7814 let next_snapshot = buffer.text_snapshot();
7815 for language_server in language_servers {
7816 let language_server = language_server.clone();
7817
7818 let buffer_snapshots = self
7819 .as_local_mut()?
7820 .buffer_snapshots
7821 .get_mut(&buffer.remote_id())
7822 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7823 let previous_snapshot = buffer_snapshots.last()?;
7824
7825 let build_incremental_change = || {
7826 buffer
7827 .edits_since::<Dimensions<PointUtf16, usize>>(
7828 previous_snapshot.snapshot.version(),
7829 )
7830 .map(|edit| {
7831 let edit_start = edit.new.start.0;
7832 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7833 let new_text = next_snapshot
7834 .text_for_range(edit.new.start.1..edit.new.end.1)
7835 .collect();
7836 lsp::TextDocumentContentChangeEvent {
7837 range: Some(lsp::Range::new(
7838 point_to_lsp(edit_start),
7839 point_to_lsp(edit_end),
7840 )),
7841 range_length: None,
7842 text: new_text,
7843 }
7844 })
7845 .collect()
7846 };
7847
7848 let document_sync_kind = language_server
7849 .capabilities()
7850 .text_document_sync
7851 .as_ref()
7852 .and_then(|sync| match sync {
7853 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7854 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7855 });
7856
7857 let content_changes: Vec<_> = match document_sync_kind {
7858 Some(lsp::TextDocumentSyncKind::FULL) => {
7859 vec![lsp::TextDocumentContentChangeEvent {
7860 range: None,
7861 range_length: None,
7862 text: next_snapshot.text(),
7863 }]
7864 }
7865 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7866 _ => {
7867 #[cfg(any(test, feature = "test-support"))]
7868 {
7869 build_incremental_change()
7870 }
7871
7872 #[cfg(not(any(test, feature = "test-support")))]
7873 {
7874 continue;
7875 }
7876 }
7877 };
7878
7879 let next_version = previous_snapshot.version + 1;
7880 buffer_snapshots.push(LspBufferSnapshot {
7881 version: next_version,
7882 snapshot: next_snapshot.clone(),
7883 });
7884
7885 language_server
7886 .notify::<lsp::notification::DidChangeTextDocument>(
7887 lsp::DidChangeTextDocumentParams {
7888 text_document: lsp::VersionedTextDocumentIdentifier::new(
7889 uri.clone(),
7890 next_version,
7891 ),
7892 content_changes,
7893 },
7894 )
7895 .ok();
7896 self.pull_workspace_diagnostics(language_server.server_id());
7897 }
7898
7899 None
7900 }
7901
7902 pub fn on_buffer_saved(
7903 &mut self,
7904 buffer: Entity<Buffer>,
7905 cx: &mut Context<Self>,
7906 ) -> Option<()> {
7907 let file = File::from_dyn(buffer.read(cx).file())?;
7908 let worktree_id = file.worktree_id(cx);
7909 let abs_path = file.as_local()?.abs_path(cx);
7910 let text_document = lsp::TextDocumentIdentifier {
7911 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7912 };
7913 let local = self.as_local()?;
7914
7915 for server in local.language_servers_for_worktree(worktree_id) {
7916 if let Some(include_text) = include_text(server.as_ref()) {
7917 let text = if include_text {
7918 Some(buffer.read(cx).text())
7919 } else {
7920 None
7921 };
7922 server
7923 .notify::<lsp::notification::DidSaveTextDocument>(
7924 lsp::DidSaveTextDocumentParams {
7925 text_document: text_document.clone(),
7926 text,
7927 },
7928 )
7929 .ok();
7930 }
7931 }
7932
7933 let language_servers = buffer.update(cx, |buffer, cx| {
7934 local.language_server_ids_for_buffer(buffer, cx)
7935 });
7936 for language_server_id in language_servers {
7937 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7938 }
7939
7940 None
7941 }
7942
7943 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7944 maybe!(async move {
7945 let mut refreshed_servers = HashSet::default();
7946 let servers = lsp_store
7947 .update(cx, |lsp_store, cx| {
7948 let local = lsp_store.as_local()?;
7949
7950 let servers = local
7951 .language_server_ids
7952 .iter()
7953 .filter_map(|(seed, state)| {
7954 let worktree = lsp_store
7955 .worktree_store
7956 .read(cx)
7957 .worktree_for_id(seed.worktree_id, cx);
7958 let delegate: Arc<dyn LspAdapterDelegate> =
7959 worktree.map(|worktree| {
7960 LocalLspAdapterDelegate::new(
7961 local.languages.clone(),
7962 &local.environment,
7963 cx.weak_entity(),
7964 &worktree,
7965 local.http_client.clone(),
7966 local.fs.clone(),
7967 cx,
7968 )
7969 })?;
7970 let server_id = state.id;
7971
7972 let states = local.language_servers.get(&server_id)?;
7973
7974 match states {
7975 LanguageServerState::Starting { .. } => None,
7976 LanguageServerState::Running {
7977 adapter, server, ..
7978 } => {
7979 let adapter = adapter.clone();
7980 let server = server.clone();
7981 refreshed_servers.insert(server.name());
7982 let toolchain = seed.toolchain.clone();
7983 Some(cx.spawn(async move |_, cx| {
7984 let settings =
7985 LocalLspStore::workspace_configuration_for_adapter(
7986 adapter.adapter.clone(),
7987 &delegate,
7988 toolchain,
7989 None,
7990 cx,
7991 )
7992 .await
7993 .ok()?;
7994 server
7995 .notify::<lsp::notification::DidChangeConfiguration>(
7996 lsp::DidChangeConfigurationParams { settings },
7997 )
7998 .ok()?;
7999 Some(())
8000 }))
8001 }
8002 }
8003 })
8004 .collect::<Vec<_>>();
8005
8006 Some(servers)
8007 })
8008 .ok()
8009 .flatten()?;
8010
8011 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8012 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8013 // to stop and unregister its language server wrapper.
8014 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8015 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8016 let _: Vec<Option<()>> = join_all(servers).await;
8017
8018 Some(())
8019 })
8020 .await;
8021 }
8022
8023 fn maintain_workspace_config(
8024 external_refresh_requests: watch::Receiver<()>,
8025 cx: &mut Context<Self>,
8026 ) -> Task<Result<()>> {
8027 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8028 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8029
8030 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8031 *settings_changed_tx.borrow_mut() = ();
8032 });
8033
8034 let mut joint_future =
8035 futures::stream::select(settings_changed_rx, external_refresh_requests);
8036 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8037 // - 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).
8038 // - 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.
8039 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8040 // - 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,
8041 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8042 cx.spawn(async move |this, cx| {
8043 while let Some(()) = joint_future.next().await {
8044 this.update(cx, |this, cx| {
8045 this.refresh_server_tree(cx);
8046 })
8047 .ok();
8048
8049 Self::refresh_workspace_configurations(&this, cx).await;
8050 }
8051
8052 drop(settings_observation);
8053 anyhow::Ok(())
8054 })
8055 }
8056
8057 pub fn running_language_servers_for_local_buffer<'a>(
8058 &'a self,
8059 buffer: &Buffer,
8060 cx: &mut App,
8061 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8062 let local = self.as_local();
8063 let language_server_ids = local
8064 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8065 .unwrap_or_default();
8066
8067 language_server_ids
8068 .into_iter()
8069 .filter_map(
8070 move |server_id| match local?.language_servers.get(&server_id)? {
8071 LanguageServerState::Running {
8072 adapter, server, ..
8073 } => Some((adapter, server)),
8074 _ => None,
8075 },
8076 )
8077 }
8078
8079 pub fn language_servers_for_local_buffer(
8080 &self,
8081 buffer: &Buffer,
8082 cx: &mut App,
8083 ) -> Vec<LanguageServerId> {
8084 let local = self.as_local();
8085 local
8086 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8087 .unwrap_or_default()
8088 }
8089
8090 pub fn language_server_for_local_buffer<'a>(
8091 &'a self,
8092 buffer: &'a Buffer,
8093 server_id: LanguageServerId,
8094 cx: &'a mut App,
8095 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8096 self.as_local()?
8097 .language_servers_for_buffer(buffer, cx)
8098 .find(|(_, s)| s.server_id() == server_id)
8099 }
8100
8101 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8102 self.diagnostic_summaries.remove(&id_to_remove);
8103 if let Some(local) = self.as_local_mut() {
8104 let to_remove = local.remove_worktree(id_to_remove, cx);
8105 for server in to_remove {
8106 self.language_server_statuses.remove(&server);
8107 }
8108 }
8109 }
8110
8111 pub fn shared(
8112 &mut self,
8113 project_id: u64,
8114 downstream_client: AnyProtoClient,
8115 _: &mut Context<Self>,
8116 ) {
8117 self.downstream_client = Some((downstream_client.clone(), project_id));
8118
8119 for (server_id, status) in &self.language_server_statuses {
8120 if let Some(server) = self.language_server_for_id(*server_id) {
8121 downstream_client
8122 .send(proto::StartLanguageServer {
8123 project_id,
8124 server: Some(proto::LanguageServer {
8125 id: server_id.to_proto(),
8126 name: status.name.to_string(),
8127 worktree_id: status.worktree.map(|id| id.to_proto()),
8128 }),
8129 capabilities: serde_json::to_string(&server.capabilities())
8130 .expect("serializing server LSP capabilities"),
8131 })
8132 .log_err();
8133 }
8134 }
8135 }
8136
8137 pub fn disconnected_from_host(&mut self) {
8138 self.downstream_client.take();
8139 }
8140
8141 pub fn disconnected_from_ssh_remote(&mut self) {
8142 if let LspStoreMode::Remote(RemoteLspStore {
8143 upstream_client, ..
8144 }) = &mut self.mode
8145 {
8146 upstream_client.take();
8147 }
8148 }
8149
8150 pub(crate) fn set_language_server_statuses_from_proto(
8151 &mut self,
8152 project: WeakEntity<Project>,
8153 language_servers: Vec<proto::LanguageServer>,
8154 server_capabilities: Vec<String>,
8155 cx: &mut Context<Self>,
8156 ) {
8157 let lsp_logs = cx
8158 .try_global::<GlobalLogStore>()
8159 .map(|lsp_store| lsp_store.0.clone());
8160
8161 self.language_server_statuses = language_servers
8162 .into_iter()
8163 .zip(server_capabilities)
8164 .map(|(server, server_capabilities)| {
8165 let server_id = LanguageServerId(server.id as usize);
8166 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8167 self.lsp_server_capabilities
8168 .insert(server_id, server_capabilities);
8169 }
8170
8171 let name = LanguageServerName::from_proto(server.name);
8172 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8173
8174 if let Some(lsp_logs) = &lsp_logs {
8175 lsp_logs.update(cx, |lsp_logs, cx| {
8176 lsp_logs.add_language_server(
8177 // Only remote clients get their language servers set from proto
8178 LanguageServerKind::Remote {
8179 project: project.clone(),
8180 },
8181 server_id,
8182 Some(name.clone()),
8183 worktree,
8184 None,
8185 cx,
8186 );
8187 });
8188 }
8189
8190 (
8191 server_id,
8192 LanguageServerStatus {
8193 name,
8194 server_version: None,
8195 pending_work: Default::default(),
8196 has_pending_diagnostic_updates: false,
8197 progress_tokens: Default::default(),
8198 worktree,
8199 binary: None,
8200 configuration: None,
8201 workspace_folders: BTreeSet::new(),
8202 process_id: None,
8203 },
8204 )
8205 })
8206 .collect();
8207 }
8208
8209 #[cfg(feature = "test-support")]
8210 pub fn update_diagnostic_entries(
8211 &mut self,
8212 server_id: LanguageServerId,
8213 abs_path: PathBuf,
8214 result_id: Option<SharedString>,
8215 version: Option<i32>,
8216 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8217 cx: &mut Context<Self>,
8218 ) -> anyhow::Result<()> {
8219 self.merge_diagnostic_entries(
8220 vec![DocumentDiagnosticsUpdate {
8221 diagnostics: DocumentDiagnostics {
8222 diagnostics,
8223 document_abs_path: abs_path,
8224 version,
8225 },
8226 result_id,
8227 server_id,
8228 disk_based_sources: Cow::Borrowed(&[]),
8229 registration_id: None,
8230 }],
8231 |_, _, _| false,
8232 cx,
8233 )?;
8234 Ok(())
8235 }
8236
8237 pub fn merge_diagnostic_entries<'a>(
8238 &mut self,
8239 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8240 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8241 cx: &mut Context<Self>,
8242 ) -> anyhow::Result<()> {
8243 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8244 let mut updated_diagnostics_paths = HashMap::default();
8245 for mut update in diagnostic_updates {
8246 let abs_path = &update.diagnostics.document_abs_path;
8247 let server_id = update.server_id;
8248 let Some((worktree, relative_path)) =
8249 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8250 else {
8251 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8252 return Ok(());
8253 };
8254
8255 let worktree_id = worktree.read(cx).id();
8256 let project_path = ProjectPath {
8257 worktree_id,
8258 path: relative_path,
8259 };
8260
8261 let document_uri = lsp::Uri::from_file_path(abs_path)
8262 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8263 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8264 let snapshot = buffer_handle.read(cx).snapshot();
8265 let buffer = buffer_handle.read(cx);
8266 let reused_diagnostics = buffer
8267 .buffer_diagnostics(Some(server_id))
8268 .iter()
8269 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8270 .map(|v| {
8271 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8272 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8273 DiagnosticEntry {
8274 range: start..end,
8275 diagnostic: v.diagnostic.clone(),
8276 }
8277 })
8278 .collect::<Vec<_>>();
8279
8280 self.as_local_mut()
8281 .context("cannot merge diagnostics on a remote LspStore")?
8282 .update_buffer_diagnostics(
8283 &buffer_handle,
8284 server_id,
8285 Some(update.registration_id),
8286 update.result_id,
8287 update.diagnostics.version,
8288 update.diagnostics.diagnostics.clone(),
8289 reused_diagnostics.clone(),
8290 cx,
8291 )?;
8292
8293 update.diagnostics.diagnostics.extend(reused_diagnostics);
8294 } else if let Some(local) = self.as_local() {
8295 let reused_diagnostics = local
8296 .diagnostics
8297 .get(&worktree_id)
8298 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8299 .and_then(|diagnostics_by_server_id| {
8300 diagnostics_by_server_id
8301 .binary_search_by_key(&server_id, |e| e.0)
8302 .ok()
8303 .map(|ix| &diagnostics_by_server_id[ix].1)
8304 })
8305 .into_iter()
8306 .flatten()
8307 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8308
8309 update
8310 .diagnostics
8311 .diagnostics
8312 .extend(reused_diagnostics.cloned());
8313 }
8314
8315 let updated = worktree.update(cx, |worktree, cx| {
8316 self.update_worktree_diagnostics(
8317 worktree.id(),
8318 server_id,
8319 project_path.path.clone(),
8320 update.diagnostics.diagnostics,
8321 cx,
8322 )
8323 })?;
8324 match updated {
8325 ControlFlow::Continue(new_summary) => {
8326 if let Some((project_id, new_summary)) = new_summary {
8327 match &mut diagnostics_summary {
8328 Some(diagnostics_summary) => {
8329 diagnostics_summary
8330 .more_summaries
8331 .push(proto::DiagnosticSummary {
8332 path: project_path.path.as_ref().to_proto(),
8333 language_server_id: server_id.0 as u64,
8334 error_count: new_summary.error_count,
8335 warning_count: new_summary.warning_count,
8336 })
8337 }
8338 None => {
8339 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8340 project_id,
8341 worktree_id: worktree_id.to_proto(),
8342 summary: Some(proto::DiagnosticSummary {
8343 path: project_path.path.as_ref().to_proto(),
8344 language_server_id: server_id.0 as u64,
8345 error_count: new_summary.error_count,
8346 warning_count: new_summary.warning_count,
8347 }),
8348 more_summaries: Vec::new(),
8349 })
8350 }
8351 }
8352 }
8353 updated_diagnostics_paths
8354 .entry(server_id)
8355 .or_insert_with(Vec::new)
8356 .push(project_path);
8357 }
8358 ControlFlow::Break(()) => {}
8359 }
8360 }
8361
8362 if let Some((diagnostics_summary, (downstream_client, _))) =
8363 diagnostics_summary.zip(self.downstream_client.as_ref())
8364 {
8365 downstream_client.send(diagnostics_summary).log_err();
8366 }
8367 for (server_id, paths) in updated_diagnostics_paths {
8368 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8369 }
8370 Ok(())
8371 }
8372
8373 fn update_worktree_diagnostics(
8374 &mut self,
8375 worktree_id: WorktreeId,
8376 server_id: LanguageServerId,
8377 path_in_worktree: Arc<RelPath>,
8378 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8379 _: &mut Context<Worktree>,
8380 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8381 let local = match &mut self.mode {
8382 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8383 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8384 };
8385
8386 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8387 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8388 let summaries_by_server_id = summaries_for_tree
8389 .entry(path_in_worktree.clone())
8390 .or_default();
8391
8392 let old_summary = summaries_by_server_id
8393 .remove(&server_id)
8394 .unwrap_or_default();
8395
8396 let new_summary = DiagnosticSummary::new(&diagnostics);
8397 if diagnostics.is_empty() {
8398 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8399 {
8400 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8401 diagnostics_by_server_id.remove(ix);
8402 }
8403 if diagnostics_by_server_id.is_empty() {
8404 diagnostics_for_tree.remove(&path_in_worktree);
8405 }
8406 }
8407 } else {
8408 summaries_by_server_id.insert(server_id, new_summary);
8409 let diagnostics_by_server_id = diagnostics_for_tree
8410 .entry(path_in_worktree.clone())
8411 .or_default();
8412 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8413 Ok(ix) => {
8414 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8415 }
8416 Err(ix) => {
8417 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8418 }
8419 }
8420 }
8421
8422 if !old_summary.is_empty() || !new_summary.is_empty() {
8423 if let Some((_, project_id)) = &self.downstream_client {
8424 Ok(ControlFlow::Continue(Some((
8425 *project_id,
8426 proto::DiagnosticSummary {
8427 path: path_in_worktree.to_proto(),
8428 language_server_id: server_id.0 as u64,
8429 error_count: new_summary.error_count as u32,
8430 warning_count: new_summary.warning_count as u32,
8431 },
8432 ))))
8433 } else {
8434 Ok(ControlFlow::Continue(None))
8435 }
8436 } else {
8437 Ok(ControlFlow::Break(()))
8438 }
8439 }
8440
8441 pub fn open_buffer_for_symbol(
8442 &mut self,
8443 symbol: &Symbol,
8444 cx: &mut Context<Self>,
8445 ) -> Task<Result<Entity<Buffer>>> {
8446 if let Some((client, project_id)) = self.upstream_client() {
8447 let request = client.request(proto::OpenBufferForSymbol {
8448 project_id,
8449 symbol: Some(Self::serialize_symbol(symbol)),
8450 });
8451 cx.spawn(async move |this, cx| {
8452 let response = request.await?;
8453 let buffer_id = BufferId::new(response.buffer_id)?;
8454 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8455 .await
8456 })
8457 } else if let Some(local) = self.as_local() {
8458 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8459 seed.worktree_id == symbol.source_worktree_id
8460 && state.id == symbol.source_language_server_id
8461 && symbol.language_server_name == seed.name
8462 });
8463 if !is_valid {
8464 return Task::ready(Err(anyhow!(
8465 "language server for worktree and language not found"
8466 )));
8467 };
8468
8469 let symbol_abs_path = match &symbol.path {
8470 SymbolLocation::InProject(project_path) => self
8471 .worktree_store
8472 .read(cx)
8473 .absolutize(&project_path, cx)
8474 .context("no such worktree"),
8475 SymbolLocation::OutsideProject {
8476 abs_path,
8477 signature: _,
8478 } => Ok(abs_path.to_path_buf()),
8479 };
8480 let symbol_abs_path = match symbol_abs_path {
8481 Ok(abs_path) => abs_path,
8482 Err(err) => return Task::ready(Err(err)),
8483 };
8484 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8485 uri
8486 } else {
8487 return Task::ready(Err(anyhow!("invalid symbol path")));
8488 };
8489
8490 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8491 } else {
8492 Task::ready(Err(anyhow!("no upstream client or local store")))
8493 }
8494 }
8495
8496 pub(crate) fn open_local_buffer_via_lsp(
8497 &mut self,
8498 abs_path: lsp::Uri,
8499 language_server_id: LanguageServerId,
8500 cx: &mut Context<Self>,
8501 ) -> Task<Result<Entity<Buffer>>> {
8502 let path_style = self.worktree_store.read(cx).path_style();
8503 cx.spawn(async move |lsp_store, cx| {
8504 // Escape percent-encoded string.
8505 let current_scheme = abs_path.scheme().to_owned();
8506 // Uri is immutable, so we can't modify the scheme
8507
8508 let abs_path = abs_path
8509 .to_file_path_ext(path_style)
8510 .map_err(|()| anyhow!("can't convert URI to path"))?;
8511 let p = abs_path.clone();
8512 let yarn_worktree = lsp_store
8513 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8514 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8515 cx.spawn(async move |this, cx| {
8516 let t = this
8517 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8518 .ok()?;
8519 t.await
8520 })
8521 }),
8522 None => Task::ready(None),
8523 })?
8524 .await;
8525 let (worktree_root_target, known_relative_path) =
8526 if let Some((zip_root, relative_path)) = yarn_worktree {
8527 (zip_root, Some(relative_path))
8528 } else {
8529 (Arc::<Path>::from(abs_path.as_path()), None)
8530 };
8531 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8532 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8533 worktree_store.find_worktree(&worktree_root_target, cx)
8534 })
8535 })?;
8536 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8537 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8538 (result.0, relative_path, None)
8539 } else {
8540 let worktree = lsp_store
8541 .update(cx, |lsp_store, cx| {
8542 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8543 worktree_store.create_worktree(&worktree_root_target, false, cx)
8544 })
8545 })?
8546 .await?;
8547 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8548 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8549 lsp_store
8550 .update(cx, |lsp_store, cx| {
8551 if let Some(local) = lsp_store.as_local_mut() {
8552 local.register_language_server_for_invisible_worktree(
8553 &worktree,
8554 language_server_id,
8555 cx,
8556 )
8557 }
8558 match lsp_store.language_server_statuses.get(&language_server_id) {
8559 Some(status) => status.worktree,
8560 None => None,
8561 }
8562 })
8563 .ok()
8564 .flatten()
8565 .zip(Some(worktree_root.clone()))
8566 } else {
8567 None
8568 };
8569 let relative_path = if let Some(known_path) = known_relative_path {
8570 known_path
8571 } else {
8572 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8573 .into_arc()
8574 };
8575 (worktree, relative_path, source_ws)
8576 };
8577 let project_path = ProjectPath {
8578 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8579 path: relative_path,
8580 };
8581 let buffer = lsp_store
8582 .update(cx, |lsp_store, cx| {
8583 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8584 buffer_store.open_buffer(project_path, cx)
8585 })
8586 })?
8587 .await?;
8588 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8589 if let Some((source_ws, worktree_root)) = source_ws {
8590 buffer.update(cx, |buffer, cx| {
8591 let settings = WorktreeSettings::get(
8592 Some(
8593 (&ProjectPath {
8594 worktree_id: source_ws,
8595 path: Arc::from(RelPath::empty()),
8596 })
8597 .into(),
8598 ),
8599 cx,
8600 );
8601 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8602 if is_read_only {
8603 buffer.set_capability(Capability::ReadOnly, cx);
8604 }
8605 });
8606 }
8607 Ok(buffer)
8608 })
8609 }
8610
8611 fn local_lsp_servers_for_buffer(
8612 &self,
8613 buffer: &Entity<Buffer>,
8614 cx: &mut Context<Self>,
8615 ) -> Vec<LanguageServerId> {
8616 let Some(local) = self.as_local() else {
8617 return Vec::new();
8618 };
8619
8620 let snapshot = buffer.read(cx).snapshot();
8621
8622 buffer.update(cx, |buffer, cx| {
8623 local
8624 .language_servers_for_buffer(buffer, cx)
8625 .map(|(_, server)| server.server_id())
8626 .filter(|server_id| {
8627 self.as_local().is_none_or(|local| {
8628 local
8629 .buffers_opened_in_servers
8630 .get(&snapshot.remote_id())
8631 .is_some_and(|servers| servers.contains(server_id))
8632 })
8633 })
8634 .collect()
8635 })
8636 }
8637
8638 fn request_multiple_lsp_locally<P, R>(
8639 &mut self,
8640 buffer: &Entity<Buffer>,
8641 position: Option<P>,
8642 request: R,
8643 cx: &mut Context<Self>,
8644 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8645 where
8646 P: ToOffset,
8647 R: LspCommand + Clone,
8648 <R::LspRequest as lsp::request::Request>::Result: Send,
8649 <R::LspRequest as lsp::request::Request>::Params: Send,
8650 {
8651 let Some(local) = self.as_local() else {
8652 return Task::ready(Vec::new());
8653 };
8654
8655 let snapshot = buffer.read(cx).snapshot();
8656 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8657
8658 let server_ids = buffer.update(cx, |buffer, cx| {
8659 local
8660 .language_servers_for_buffer(buffer, cx)
8661 .filter(|(adapter, _)| {
8662 scope
8663 .as_ref()
8664 .map(|scope| scope.language_allowed(&adapter.name))
8665 .unwrap_or(true)
8666 })
8667 .map(|(_, server)| server.server_id())
8668 .filter(|server_id| {
8669 self.as_local().is_none_or(|local| {
8670 local
8671 .buffers_opened_in_servers
8672 .get(&snapshot.remote_id())
8673 .is_some_and(|servers| servers.contains(server_id))
8674 })
8675 })
8676 .collect::<Vec<_>>()
8677 });
8678
8679 let mut response_results = server_ids
8680 .into_iter()
8681 .map(|server_id| {
8682 let task = self.request_lsp(
8683 buffer.clone(),
8684 LanguageServerToQuery::Other(server_id),
8685 request.clone(),
8686 cx,
8687 );
8688 async move { (server_id, task.await) }
8689 })
8690 .collect::<FuturesUnordered<_>>();
8691
8692 cx.background_spawn(async move {
8693 let mut responses = Vec::with_capacity(response_results.len());
8694 while let Some((server_id, response_result)) = response_results.next().await {
8695 match response_result {
8696 Ok(response) => responses.push((server_id, response)),
8697 // rust-analyzer likes to error with this when its still loading up
8698 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8699 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8700 }
8701 }
8702 responses
8703 })
8704 }
8705
8706 async fn handle_lsp_get_completions(
8707 this: Entity<Self>,
8708 envelope: TypedEnvelope<proto::GetCompletions>,
8709 mut cx: AsyncApp,
8710 ) -> Result<proto::GetCompletionsResponse> {
8711 let sender_id = envelope.original_sender_id().unwrap_or_default();
8712
8713 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8714 let buffer_handle = this.update(&mut cx, |this, cx| {
8715 this.buffer_store.read(cx).get_existing(buffer_id)
8716 })?;
8717 let request = GetCompletions::from_proto(
8718 envelope.payload,
8719 this.clone(),
8720 buffer_handle.clone(),
8721 cx.clone(),
8722 )
8723 .await?;
8724
8725 let server_to_query = match request.server_id {
8726 Some(server_id) => LanguageServerToQuery::Other(server_id),
8727 None => LanguageServerToQuery::FirstCapable,
8728 };
8729
8730 let response = this
8731 .update(&mut cx, |this, cx| {
8732 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8733 })
8734 .await?;
8735 this.update(&mut cx, |this, cx| {
8736 Ok(GetCompletions::response_to_proto(
8737 response,
8738 this,
8739 sender_id,
8740 &buffer_handle.read(cx).version(),
8741 cx,
8742 ))
8743 })
8744 }
8745
8746 async fn handle_lsp_command<T: LspCommand>(
8747 this: Entity<Self>,
8748 envelope: TypedEnvelope<T::ProtoRequest>,
8749 mut cx: AsyncApp,
8750 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8751 where
8752 <T::LspRequest as lsp::request::Request>::Params: Send,
8753 <T::LspRequest as lsp::request::Request>::Result: Send,
8754 {
8755 let sender_id = envelope.original_sender_id().unwrap_or_default();
8756 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8757 let buffer_handle = this.update(&mut cx, |this, cx| {
8758 this.buffer_store.read(cx).get_existing(buffer_id)
8759 })?;
8760 let request = T::from_proto(
8761 envelope.payload,
8762 this.clone(),
8763 buffer_handle.clone(),
8764 cx.clone(),
8765 )
8766 .await?;
8767 let response = this
8768 .update(&mut cx, |this, cx| {
8769 this.request_lsp(
8770 buffer_handle.clone(),
8771 LanguageServerToQuery::FirstCapable,
8772 request,
8773 cx,
8774 )
8775 })
8776 .await?;
8777 this.update(&mut cx, |this, cx| {
8778 Ok(T::response_to_proto(
8779 response,
8780 this,
8781 sender_id,
8782 &buffer_handle.read(cx).version(),
8783 cx,
8784 ))
8785 })
8786 }
8787
8788 async fn handle_lsp_query(
8789 lsp_store: Entity<Self>,
8790 envelope: TypedEnvelope<proto::LspQuery>,
8791 mut cx: AsyncApp,
8792 ) -> Result<proto::Ack> {
8793 use proto::lsp_query::Request;
8794 let sender_id = envelope.original_sender_id().unwrap_or_default();
8795 let lsp_query = envelope.payload;
8796 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8797 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8798 match lsp_query.request.context("invalid LSP query request")? {
8799 Request::GetReferences(get_references) => {
8800 let position = get_references.position.clone().and_then(deserialize_anchor);
8801 Self::query_lsp_locally::<GetReferences>(
8802 lsp_store,
8803 server_id,
8804 sender_id,
8805 lsp_request_id,
8806 get_references,
8807 position,
8808 &mut cx,
8809 )
8810 .await?;
8811 }
8812 Request::GetDocumentColor(get_document_color) => {
8813 Self::query_lsp_locally::<GetDocumentColor>(
8814 lsp_store,
8815 server_id,
8816 sender_id,
8817 lsp_request_id,
8818 get_document_color,
8819 None,
8820 &mut cx,
8821 )
8822 .await?;
8823 }
8824 Request::GetFoldingRanges(get_folding_ranges) => {
8825 Self::query_lsp_locally::<GetFoldingRanges>(
8826 lsp_store,
8827 server_id,
8828 sender_id,
8829 lsp_request_id,
8830 get_folding_ranges,
8831 None,
8832 &mut cx,
8833 )
8834 .await?;
8835 }
8836 Request::GetDocumentSymbols(get_document_symbols) => {
8837 Self::query_lsp_locally::<GetDocumentSymbols>(
8838 lsp_store,
8839 server_id,
8840 sender_id,
8841 lsp_request_id,
8842 get_document_symbols,
8843 None,
8844 &mut cx,
8845 )
8846 .await?;
8847 }
8848 Request::GetHover(get_hover) => {
8849 let position = get_hover.position.clone().and_then(deserialize_anchor);
8850 Self::query_lsp_locally::<GetHover>(
8851 lsp_store,
8852 server_id,
8853 sender_id,
8854 lsp_request_id,
8855 get_hover,
8856 position,
8857 &mut cx,
8858 )
8859 .await?;
8860 }
8861 Request::GetCodeActions(get_code_actions) => {
8862 Self::query_lsp_locally::<GetCodeActions>(
8863 lsp_store,
8864 server_id,
8865 sender_id,
8866 lsp_request_id,
8867 get_code_actions,
8868 None,
8869 &mut cx,
8870 )
8871 .await?;
8872 }
8873 Request::GetSignatureHelp(get_signature_help) => {
8874 let position = get_signature_help
8875 .position
8876 .clone()
8877 .and_then(deserialize_anchor);
8878 Self::query_lsp_locally::<GetSignatureHelp>(
8879 lsp_store,
8880 server_id,
8881 sender_id,
8882 lsp_request_id,
8883 get_signature_help,
8884 position,
8885 &mut cx,
8886 )
8887 .await?;
8888 }
8889 Request::GetCodeLens(get_code_lens) => {
8890 Self::query_lsp_locally::<GetCodeLens>(
8891 lsp_store,
8892 server_id,
8893 sender_id,
8894 lsp_request_id,
8895 get_code_lens,
8896 None,
8897 &mut cx,
8898 )
8899 .await?;
8900 }
8901 Request::GetDefinition(get_definition) => {
8902 let position = get_definition.position.clone().and_then(deserialize_anchor);
8903 Self::query_lsp_locally::<GetDefinitions>(
8904 lsp_store,
8905 server_id,
8906 sender_id,
8907 lsp_request_id,
8908 get_definition,
8909 position,
8910 &mut cx,
8911 )
8912 .await?;
8913 }
8914 Request::GetDeclaration(get_declaration) => {
8915 let position = get_declaration
8916 .position
8917 .clone()
8918 .and_then(deserialize_anchor);
8919 Self::query_lsp_locally::<GetDeclarations>(
8920 lsp_store,
8921 server_id,
8922 sender_id,
8923 lsp_request_id,
8924 get_declaration,
8925 position,
8926 &mut cx,
8927 )
8928 .await?;
8929 }
8930 Request::GetTypeDefinition(get_type_definition) => {
8931 let position = get_type_definition
8932 .position
8933 .clone()
8934 .and_then(deserialize_anchor);
8935 Self::query_lsp_locally::<GetTypeDefinitions>(
8936 lsp_store,
8937 server_id,
8938 sender_id,
8939 lsp_request_id,
8940 get_type_definition,
8941 position,
8942 &mut cx,
8943 )
8944 .await?;
8945 }
8946 Request::GetImplementation(get_implementation) => {
8947 let position = get_implementation
8948 .position
8949 .clone()
8950 .and_then(deserialize_anchor);
8951 Self::query_lsp_locally::<GetImplementations>(
8952 lsp_store,
8953 server_id,
8954 sender_id,
8955 lsp_request_id,
8956 get_implementation,
8957 position,
8958 &mut cx,
8959 )
8960 .await?;
8961 }
8962 Request::InlayHints(inlay_hints) => {
8963 let query_start = inlay_hints
8964 .start
8965 .clone()
8966 .and_then(deserialize_anchor)
8967 .context("invalid inlay hints range start")?;
8968 let query_end = inlay_hints
8969 .end
8970 .clone()
8971 .and_then(deserialize_anchor)
8972 .context("invalid inlay hints range end")?;
8973 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8974 &lsp_store,
8975 server_id,
8976 lsp_request_id,
8977 &inlay_hints,
8978 query_start..query_end,
8979 &mut cx,
8980 )
8981 .await
8982 .context("preparing inlay hints request")?;
8983 Self::query_lsp_locally::<InlayHints>(
8984 lsp_store,
8985 server_id,
8986 sender_id,
8987 lsp_request_id,
8988 inlay_hints,
8989 None,
8990 &mut cx,
8991 )
8992 .await
8993 .context("querying for inlay hints")?
8994 }
8995 //////////////////////////////
8996 // Below are LSP queries that need to fetch more data,
8997 // hence cannot just proxy the request to language server with `query_lsp_locally`.
8998 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8999 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9000 &lsp_store,
9001 &get_document_diagnostics,
9002 &mut cx,
9003 )
9004 .await?;
9005 lsp_store.update(&mut cx, |lsp_store, cx| {
9006 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9007 let key = LspKey {
9008 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9009 server_queried: server_id,
9010 };
9011 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9012 ) {
9013 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9014 lsp_requests.clear();
9015 };
9016 }
9017
9018 lsp_data.lsp_requests.entry(key).or_default().insert(
9019 lsp_request_id,
9020 cx.spawn(async move |lsp_store, cx| {
9021 let diagnostics_pull = lsp_store
9022 .update(cx, |lsp_store, cx| {
9023 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9024 })
9025 .ok();
9026 if let Some(diagnostics_pull) = diagnostics_pull {
9027 match diagnostics_pull.await {
9028 Ok(()) => {}
9029 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9030 };
9031 }
9032 }),
9033 );
9034 });
9035 }
9036 Request::SemanticTokens(semantic_tokens) => {
9037 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9038 &lsp_store,
9039 &semantic_tokens,
9040 &mut cx,
9041 )
9042 .await?;
9043 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9044 lsp_store.update(&mut cx, |lsp_store, cx| {
9045 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9046 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9047 let key = LspKey {
9048 request_type: TypeId::of::<SemanticTokensFull>(),
9049 server_queried: server_id,
9050 };
9051 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9052 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9053 lsp_requests.clear();
9054 };
9055 }
9056
9057 lsp_data.lsp_requests.entry(key).or_default().insert(
9058 lsp_request_id,
9059 cx.spawn(async move |lsp_store, cx| {
9060 let tokens_fetch = lsp_store
9061 .update(cx, |lsp_store, cx| {
9062 lsp_store
9063 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9064 })
9065 .ok();
9066 if let Some(tokens_fetch) = tokens_fetch {
9067 let new_tokens = tokens_fetch.await;
9068 if let Some(new_tokens) = new_tokens {
9069 lsp_store
9070 .update(cx, |lsp_store, cx| {
9071 let response = new_tokens
9072 .into_iter()
9073 .map(|(server_id, response)| {
9074 (
9075 server_id.to_proto(),
9076 SemanticTokensFull::response_to_proto(
9077 response,
9078 lsp_store,
9079 sender_id,
9080 &buffer_version,
9081 cx,
9082 ),
9083 )
9084 })
9085 .collect::<HashMap<_, _>>();
9086 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9087 project_id,
9088 lsp_request_id,
9089 response,
9090 ) {
9091 Ok(()) => {}
9092 Err(e) => {
9093 log::error!(
9094 "Failed to send semantic tokens LSP response: {e:#}",
9095 )
9096 }
9097 }
9098 })
9099 .ok();
9100 }
9101 }
9102 }),
9103 );
9104 }
9105 });
9106 }
9107 }
9108 Ok(proto::Ack {})
9109 }
9110
9111 async fn handle_lsp_query_response(
9112 lsp_store: Entity<Self>,
9113 envelope: TypedEnvelope<proto::LspQueryResponse>,
9114 cx: AsyncApp,
9115 ) -> Result<()> {
9116 lsp_store.read_with(&cx, |lsp_store, _| {
9117 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9118 upstream_client.handle_lsp_response(envelope.clone());
9119 }
9120 });
9121 Ok(())
9122 }
9123
9124 async fn handle_apply_code_action(
9125 this: Entity<Self>,
9126 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9127 mut cx: AsyncApp,
9128 ) -> Result<proto::ApplyCodeActionResponse> {
9129 let sender_id = envelope.original_sender_id().unwrap_or_default();
9130 let action =
9131 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9132 let apply_code_action = this.update(&mut cx, |this, cx| {
9133 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9134 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9135 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9136 })?;
9137
9138 let project_transaction = apply_code_action.await?;
9139 let project_transaction = this.update(&mut cx, |this, cx| {
9140 this.buffer_store.update(cx, |buffer_store, cx| {
9141 buffer_store.serialize_project_transaction_for_peer(
9142 project_transaction,
9143 sender_id,
9144 cx,
9145 )
9146 })
9147 });
9148 Ok(proto::ApplyCodeActionResponse {
9149 transaction: Some(project_transaction),
9150 })
9151 }
9152
9153 async fn handle_register_buffer_with_language_servers(
9154 this: Entity<Self>,
9155 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9156 mut cx: AsyncApp,
9157 ) -> Result<proto::Ack> {
9158 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9159 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9160 this.update(&mut cx, |this, cx| {
9161 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9162 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9163 project_id: upstream_project_id,
9164 buffer_id: buffer_id.to_proto(),
9165 only_servers: envelope.payload.only_servers,
9166 });
9167 }
9168
9169 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9170 anyhow::bail!("buffer is not open");
9171 };
9172
9173 let handle = this.register_buffer_with_language_servers(
9174 &buffer,
9175 envelope
9176 .payload
9177 .only_servers
9178 .into_iter()
9179 .filter_map(|selector| {
9180 Some(match selector.selector? {
9181 proto::language_server_selector::Selector::ServerId(server_id) => {
9182 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9183 }
9184 proto::language_server_selector::Selector::Name(name) => {
9185 LanguageServerSelector::Name(LanguageServerName(
9186 SharedString::from(name),
9187 ))
9188 }
9189 })
9190 })
9191 .collect(),
9192 false,
9193 cx,
9194 );
9195 // Pull diagnostics for the buffer even if it was already registered.
9196 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9197 // but it's unclear if we need it.
9198 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9199 .detach();
9200 this.buffer_store().update(cx, |buffer_store, _| {
9201 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9202 });
9203
9204 Ok(())
9205 })?;
9206 Ok(proto::Ack {})
9207 }
9208
9209 async fn handle_rename_project_entry(
9210 this: Entity<Self>,
9211 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9212 mut cx: AsyncApp,
9213 ) -> Result<proto::ProjectEntryResponse> {
9214 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9215 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9216 let new_path =
9217 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9218
9219 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9220 .update(&mut cx, |this, cx| {
9221 let (worktree, entry) = this
9222 .worktree_store
9223 .read(cx)
9224 .worktree_and_entry_for_id(entry_id, cx)?;
9225 let new_worktree = this
9226 .worktree_store
9227 .read(cx)
9228 .worktree_for_id(new_worktree_id, cx)?;
9229 Some((
9230 this.worktree_store.clone(),
9231 worktree,
9232 new_worktree,
9233 entry.clone(),
9234 ))
9235 })
9236 .context("worktree not found")?;
9237 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9238 (worktree.absolutize(&old_entry.path), worktree.id())
9239 });
9240 let new_abs_path =
9241 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9242
9243 let _transaction = Self::will_rename_entry(
9244 this.downgrade(),
9245 old_worktree_id,
9246 &old_abs_path,
9247 &new_abs_path,
9248 old_entry.is_dir(),
9249 cx.clone(),
9250 )
9251 .await;
9252 let response = WorktreeStore::handle_rename_project_entry(
9253 worktree_store,
9254 envelope.payload,
9255 cx.clone(),
9256 )
9257 .await;
9258 this.read_with(&cx, |this, _| {
9259 this.did_rename_entry(
9260 old_worktree_id,
9261 &old_abs_path,
9262 &new_abs_path,
9263 old_entry.is_dir(),
9264 );
9265 });
9266 response
9267 }
9268
9269 async fn handle_update_diagnostic_summary(
9270 this: Entity<Self>,
9271 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9272 mut cx: AsyncApp,
9273 ) -> Result<()> {
9274 this.update(&mut cx, |lsp_store, cx| {
9275 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9276 let mut updated_diagnostics_paths = HashMap::default();
9277 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9278 for message_summary in envelope
9279 .payload
9280 .summary
9281 .into_iter()
9282 .chain(envelope.payload.more_summaries)
9283 {
9284 let project_path = ProjectPath {
9285 worktree_id,
9286 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9287 };
9288 let path = project_path.path.clone();
9289 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9290 let summary = DiagnosticSummary {
9291 error_count: message_summary.error_count as usize,
9292 warning_count: message_summary.warning_count as usize,
9293 };
9294
9295 if summary.is_empty() {
9296 if let Some(worktree_summaries) =
9297 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9298 && let Some(summaries) = worktree_summaries.get_mut(&path)
9299 {
9300 summaries.remove(&server_id);
9301 if summaries.is_empty() {
9302 worktree_summaries.remove(&path);
9303 }
9304 }
9305 } else {
9306 lsp_store
9307 .diagnostic_summaries
9308 .entry(worktree_id)
9309 .or_default()
9310 .entry(path)
9311 .or_default()
9312 .insert(server_id, summary);
9313 }
9314
9315 if let Some((_, project_id)) = &lsp_store.downstream_client {
9316 match &mut diagnostics_summary {
9317 Some(diagnostics_summary) => {
9318 diagnostics_summary
9319 .more_summaries
9320 .push(proto::DiagnosticSummary {
9321 path: project_path.path.as_ref().to_proto(),
9322 language_server_id: server_id.0 as u64,
9323 error_count: summary.error_count as u32,
9324 warning_count: summary.warning_count as u32,
9325 })
9326 }
9327 None => {
9328 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9329 project_id: *project_id,
9330 worktree_id: worktree_id.to_proto(),
9331 summary: Some(proto::DiagnosticSummary {
9332 path: project_path.path.as_ref().to_proto(),
9333 language_server_id: server_id.0 as u64,
9334 error_count: summary.error_count as u32,
9335 warning_count: summary.warning_count as u32,
9336 }),
9337 more_summaries: Vec::new(),
9338 })
9339 }
9340 }
9341 }
9342 updated_diagnostics_paths
9343 .entry(server_id)
9344 .or_insert_with(Vec::new)
9345 .push(project_path);
9346 }
9347
9348 if let Some((diagnostics_summary, (downstream_client, _))) =
9349 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9350 {
9351 downstream_client.send(diagnostics_summary).log_err();
9352 }
9353 for (server_id, paths) in updated_diagnostics_paths {
9354 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9355 }
9356 Ok(())
9357 })
9358 }
9359
9360 async fn handle_start_language_server(
9361 lsp_store: Entity<Self>,
9362 envelope: TypedEnvelope<proto::StartLanguageServer>,
9363 mut cx: AsyncApp,
9364 ) -> Result<()> {
9365 let server = envelope.payload.server.context("invalid server")?;
9366 let server_capabilities =
9367 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9368 .with_context(|| {
9369 format!(
9370 "incorrect server capabilities {}",
9371 envelope.payload.capabilities
9372 )
9373 })?;
9374 lsp_store.update(&mut cx, |lsp_store, cx| {
9375 let server_id = LanguageServerId(server.id as usize);
9376 let server_name = LanguageServerName::from_proto(server.name.clone());
9377 lsp_store
9378 .lsp_server_capabilities
9379 .insert(server_id, server_capabilities);
9380 lsp_store.language_server_statuses.insert(
9381 server_id,
9382 LanguageServerStatus {
9383 name: server_name.clone(),
9384 server_version: None,
9385 pending_work: Default::default(),
9386 has_pending_diagnostic_updates: false,
9387 progress_tokens: Default::default(),
9388 worktree: server.worktree_id.map(WorktreeId::from_proto),
9389 binary: None,
9390 configuration: None,
9391 workspace_folders: BTreeSet::new(),
9392 process_id: None,
9393 },
9394 );
9395 cx.emit(LspStoreEvent::LanguageServerAdded(
9396 server_id,
9397 server_name,
9398 server.worktree_id.map(WorktreeId::from_proto),
9399 ));
9400 cx.notify();
9401 });
9402 Ok(())
9403 }
9404
9405 async fn handle_update_language_server(
9406 lsp_store: Entity<Self>,
9407 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9408 mut cx: AsyncApp,
9409 ) -> Result<()> {
9410 lsp_store.update(&mut cx, |lsp_store, cx| {
9411 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9412
9413 match envelope.payload.variant.context("invalid variant")? {
9414 proto::update_language_server::Variant::WorkStart(payload) => {
9415 lsp_store.on_lsp_work_start(
9416 language_server_id,
9417 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9418 .context("invalid progress token value")?,
9419 LanguageServerProgress {
9420 title: payload.title,
9421 is_disk_based_diagnostics_progress: false,
9422 is_cancellable: payload.is_cancellable.unwrap_or(false),
9423 message: payload.message,
9424 percentage: payload.percentage.map(|p| p as usize),
9425 last_update_at: cx.background_executor().now(),
9426 },
9427 cx,
9428 );
9429 }
9430 proto::update_language_server::Variant::WorkProgress(payload) => {
9431 lsp_store.on_lsp_work_progress(
9432 language_server_id,
9433 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9434 .context("invalid progress token value")?,
9435 LanguageServerProgress {
9436 title: None,
9437 is_disk_based_diagnostics_progress: false,
9438 is_cancellable: payload.is_cancellable.unwrap_or(false),
9439 message: payload.message,
9440 percentage: payload.percentage.map(|p| p as usize),
9441 last_update_at: cx.background_executor().now(),
9442 },
9443 cx,
9444 );
9445 }
9446
9447 proto::update_language_server::Variant::WorkEnd(payload) => {
9448 lsp_store.on_lsp_work_end(
9449 language_server_id,
9450 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9451 .context("invalid progress token value")?,
9452 cx,
9453 );
9454 }
9455
9456 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9457 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9458 }
9459
9460 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9461 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9462 }
9463
9464 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9465 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9466 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9467 cx.emit(LspStoreEvent::LanguageServerUpdate {
9468 language_server_id,
9469 name: envelope
9470 .payload
9471 .server_name
9472 .map(SharedString::new)
9473 .map(LanguageServerName),
9474 message: non_lsp,
9475 });
9476 }
9477 }
9478
9479 Ok(())
9480 })
9481 }
9482
9483 async fn handle_language_server_log(
9484 this: Entity<Self>,
9485 envelope: TypedEnvelope<proto::LanguageServerLog>,
9486 mut cx: AsyncApp,
9487 ) -> Result<()> {
9488 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9489 let log_type = envelope
9490 .payload
9491 .log_type
9492 .map(LanguageServerLogType::from_proto)
9493 .context("invalid language server log type")?;
9494
9495 let message = envelope.payload.message;
9496
9497 this.update(&mut cx, |_, cx| {
9498 cx.emit(LspStoreEvent::LanguageServerLog(
9499 language_server_id,
9500 log_type,
9501 message,
9502 ));
9503 });
9504 Ok(())
9505 }
9506
9507 async fn handle_lsp_ext_cancel_flycheck(
9508 lsp_store: Entity<Self>,
9509 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9510 cx: AsyncApp,
9511 ) -> Result<proto::Ack> {
9512 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9513 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9514 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9515 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9516 } else {
9517 None
9518 }
9519 });
9520 if let Some(task) = task {
9521 task.context("handling lsp ext cancel flycheck")?;
9522 }
9523
9524 Ok(proto::Ack {})
9525 }
9526
9527 async fn handle_lsp_ext_run_flycheck(
9528 lsp_store: Entity<Self>,
9529 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9530 mut cx: AsyncApp,
9531 ) -> Result<proto::Ack> {
9532 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9533 lsp_store.update(&mut cx, |lsp_store, cx| {
9534 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9535 let text_document = if envelope.payload.current_file_only {
9536 let buffer_id = envelope
9537 .payload
9538 .buffer_id
9539 .map(|id| BufferId::new(id))
9540 .transpose()?;
9541 buffer_id
9542 .and_then(|buffer_id| {
9543 lsp_store
9544 .buffer_store()
9545 .read(cx)
9546 .get(buffer_id)
9547 .and_then(|buffer| {
9548 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9549 })
9550 .map(|path| make_text_document_identifier(&path))
9551 })
9552 .transpose()?
9553 } else {
9554 None
9555 };
9556 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9557 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9558 )?;
9559 }
9560 anyhow::Ok(())
9561 })?;
9562
9563 Ok(proto::Ack {})
9564 }
9565
9566 async fn handle_lsp_ext_clear_flycheck(
9567 lsp_store: Entity<Self>,
9568 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9569 cx: AsyncApp,
9570 ) -> Result<proto::Ack> {
9571 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9572 lsp_store.read_with(&cx, |lsp_store, _| {
9573 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9574 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9575 } else {
9576 None
9577 }
9578 });
9579
9580 Ok(proto::Ack {})
9581 }
9582
9583 pub fn disk_based_diagnostics_started(
9584 &mut self,
9585 language_server_id: LanguageServerId,
9586 cx: &mut Context<Self>,
9587 ) {
9588 if let Some(language_server_status) =
9589 self.language_server_statuses.get_mut(&language_server_id)
9590 {
9591 language_server_status.has_pending_diagnostic_updates = true;
9592 }
9593
9594 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9595 cx.emit(LspStoreEvent::LanguageServerUpdate {
9596 language_server_id,
9597 name: self
9598 .language_server_adapter_for_id(language_server_id)
9599 .map(|adapter| adapter.name()),
9600 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9601 Default::default(),
9602 ),
9603 })
9604 }
9605
9606 pub fn disk_based_diagnostics_finished(
9607 &mut self,
9608 language_server_id: LanguageServerId,
9609 cx: &mut Context<Self>,
9610 ) {
9611 if let Some(language_server_status) =
9612 self.language_server_statuses.get_mut(&language_server_id)
9613 {
9614 language_server_status.has_pending_diagnostic_updates = false;
9615 }
9616
9617 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9618 cx.emit(LspStoreEvent::LanguageServerUpdate {
9619 language_server_id,
9620 name: self
9621 .language_server_adapter_for_id(language_server_id)
9622 .map(|adapter| adapter.name()),
9623 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9624 Default::default(),
9625 ),
9626 })
9627 }
9628
9629 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9630 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9631 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9632 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9633 // the language server might take some time to publish diagnostics.
9634 fn simulate_disk_based_diagnostics_events_if_needed(
9635 &mut self,
9636 language_server_id: LanguageServerId,
9637 cx: &mut Context<Self>,
9638 ) {
9639 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9640
9641 let Some(LanguageServerState::Running {
9642 simulate_disk_based_diagnostics_completion,
9643 adapter,
9644 ..
9645 }) = self
9646 .as_local_mut()
9647 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9648 else {
9649 return;
9650 };
9651
9652 if adapter.disk_based_diagnostics_progress_token.is_some() {
9653 return;
9654 }
9655
9656 let prev_task =
9657 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9658 cx.background_executor()
9659 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9660 .await;
9661
9662 this.update(cx, |this, cx| {
9663 this.disk_based_diagnostics_finished(language_server_id, cx);
9664
9665 if let Some(LanguageServerState::Running {
9666 simulate_disk_based_diagnostics_completion,
9667 ..
9668 }) = this.as_local_mut().and_then(|local_store| {
9669 local_store.language_servers.get_mut(&language_server_id)
9670 }) {
9671 *simulate_disk_based_diagnostics_completion = None;
9672 }
9673 })
9674 .ok();
9675 }));
9676
9677 if prev_task.is_none() {
9678 self.disk_based_diagnostics_started(language_server_id, cx);
9679 }
9680 }
9681
9682 pub fn language_server_statuses(
9683 &self,
9684 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9685 self.language_server_statuses
9686 .iter()
9687 .map(|(key, value)| (*key, value))
9688 }
9689
9690 pub(super) fn did_rename_entry(
9691 &self,
9692 worktree_id: WorktreeId,
9693 old_path: &Path,
9694 new_path: &Path,
9695 is_dir: bool,
9696 ) {
9697 maybe!({
9698 let local_store = self.as_local()?;
9699
9700 let old_uri = lsp::Uri::from_file_path(old_path)
9701 .ok()
9702 .map(|uri| uri.to_string())?;
9703 let new_uri = lsp::Uri::from_file_path(new_path)
9704 .ok()
9705 .map(|uri| uri.to_string())?;
9706
9707 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9708 let Some(filter) = local_store
9709 .language_server_paths_watched_for_rename
9710 .get(&language_server.server_id())
9711 else {
9712 continue;
9713 };
9714
9715 if filter.should_send_did_rename(&old_uri, is_dir) {
9716 language_server
9717 .notify::<DidRenameFiles>(RenameFilesParams {
9718 files: vec![FileRename {
9719 old_uri: old_uri.clone(),
9720 new_uri: new_uri.clone(),
9721 }],
9722 })
9723 .ok();
9724 }
9725 }
9726 Some(())
9727 });
9728 }
9729
9730 pub(super) fn will_rename_entry(
9731 this: WeakEntity<Self>,
9732 worktree_id: WorktreeId,
9733 old_path: &Path,
9734 new_path: &Path,
9735 is_dir: bool,
9736 cx: AsyncApp,
9737 ) -> Task<ProjectTransaction> {
9738 let old_uri = lsp::Uri::from_file_path(old_path)
9739 .ok()
9740 .map(|uri| uri.to_string());
9741 let new_uri = lsp::Uri::from_file_path(new_path)
9742 .ok()
9743 .map(|uri| uri.to_string());
9744 cx.spawn(async move |cx| {
9745 let mut tasks = vec![];
9746 this.update(cx, |this, cx| {
9747 let local_store = this.as_local()?;
9748 let old_uri = old_uri?;
9749 let new_uri = new_uri?;
9750 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9751 let Some(filter) = local_store
9752 .language_server_paths_watched_for_rename
9753 .get(&language_server.server_id())
9754 else {
9755 continue;
9756 };
9757
9758 if !filter.should_send_will_rename(&old_uri, is_dir) {
9759 continue;
9760 }
9761 let request_timeout = ProjectSettings::get_global(cx)
9762 .global_lsp_settings
9763 .get_request_timeout();
9764
9765 let apply_edit = cx.spawn({
9766 let old_uri = old_uri.clone();
9767 let new_uri = new_uri.clone();
9768 let language_server = language_server.clone();
9769 async move |this, cx| {
9770 let edit = language_server
9771 .request::<WillRenameFiles>(
9772 RenameFilesParams {
9773 files: vec![FileRename { old_uri, new_uri }],
9774 },
9775 request_timeout,
9776 )
9777 .await
9778 .into_response()
9779 .context("will rename files")
9780 .log_err()
9781 .flatten()?;
9782
9783 LocalLspStore::deserialize_workspace_edit(
9784 this.upgrade()?,
9785 edit,
9786 false,
9787 language_server.clone(),
9788 cx,
9789 )
9790 .await
9791 .ok()
9792 }
9793 });
9794 tasks.push(apply_edit);
9795 }
9796 Some(())
9797 })
9798 .ok()
9799 .flatten();
9800 let mut merged_transaction = ProjectTransaction::default();
9801 for task in tasks {
9802 // Await on tasks sequentially so that the order of application of edits is deterministic
9803 // (at least with regards to the order of registration of language servers)
9804 if let Some(transaction) = task.await {
9805 for (buffer, buffer_transaction) in transaction.0 {
9806 merged_transaction.0.insert(buffer, buffer_transaction);
9807 }
9808 }
9809 }
9810 merged_transaction
9811 })
9812 }
9813
9814 fn lsp_notify_abs_paths_changed(
9815 &mut self,
9816 server_id: LanguageServerId,
9817 changes: Vec<PathEvent>,
9818 ) {
9819 maybe!({
9820 let server = self.language_server_for_id(server_id)?;
9821 let changes = changes
9822 .into_iter()
9823 .filter_map(|event| {
9824 let typ = match event.kind? {
9825 PathEventKind::Created => lsp::FileChangeType::CREATED,
9826 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9827 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9828 };
9829 Some(lsp::FileEvent {
9830 uri: file_path_to_lsp_url(&event.path).log_err()?,
9831 typ,
9832 })
9833 })
9834 .collect::<Vec<_>>();
9835 if !changes.is_empty() {
9836 server
9837 .notify::<lsp::notification::DidChangeWatchedFiles>(
9838 lsp::DidChangeWatchedFilesParams { changes },
9839 )
9840 .ok();
9841 }
9842 Some(())
9843 });
9844 }
9845
9846 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9847 self.as_local()?.language_server_for_id(id)
9848 }
9849
9850 fn on_lsp_progress(
9851 &mut self,
9852 progress_params: lsp::ProgressParams,
9853 language_server_id: LanguageServerId,
9854 disk_based_diagnostics_progress_token: Option<String>,
9855 cx: &mut Context<Self>,
9856 ) {
9857 match progress_params.value {
9858 lsp::ProgressParamsValue::WorkDone(progress) => {
9859 self.handle_work_done_progress(
9860 progress,
9861 language_server_id,
9862 disk_based_diagnostics_progress_token,
9863 ProgressToken::from_lsp(progress_params.token),
9864 cx,
9865 );
9866 }
9867 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9868 let registration_id = match progress_params.token {
9869 lsp::NumberOrString::Number(_) => None,
9870 lsp::NumberOrString::String(token) => token
9871 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9872 .map(|(_, id)| id.to_owned()),
9873 };
9874 if let Some(LanguageServerState::Running {
9875 workspace_diagnostics_refresh_tasks,
9876 ..
9877 }) = self
9878 .as_local_mut()
9879 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9880 && let Some(workspace_diagnostics) =
9881 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9882 {
9883 workspace_diagnostics.progress_tx.try_send(()).ok();
9884 self.apply_workspace_diagnostic_report(
9885 language_server_id,
9886 report,
9887 registration_id.map(SharedString::from),
9888 cx,
9889 )
9890 }
9891 }
9892 }
9893 }
9894
9895 fn handle_work_done_progress(
9896 &mut self,
9897 progress: lsp::WorkDoneProgress,
9898 language_server_id: LanguageServerId,
9899 disk_based_diagnostics_progress_token: Option<String>,
9900 token: ProgressToken,
9901 cx: &mut Context<Self>,
9902 ) {
9903 let language_server_status =
9904 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9905 status
9906 } else {
9907 return;
9908 };
9909
9910 if !language_server_status.progress_tokens.contains(&token) {
9911 return;
9912 }
9913
9914 let is_disk_based_diagnostics_progress =
9915 if let (Some(disk_based_token), ProgressToken::String(token)) =
9916 (&disk_based_diagnostics_progress_token, &token)
9917 {
9918 token.starts_with(disk_based_token)
9919 } else {
9920 false
9921 };
9922
9923 match progress {
9924 lsp::WorkDoneProgress::Begin(report) => {
9925 if is_disk_based_diagnostics_progress {
9926 self.disk_based_diagnostics_started(language_server_id, cx);
9927 }
9928 self.on_lsp_work_start(
9929 language_server_id,
9930 token.clone(),
9931 LanguageServerProgress {
9932 title: Some(report.title),
9933 is_disk_based_diagnostics_progress,
9934 is_cancellable: report.cancellable.unwrap_or(false),
9935 message: report.message.clone(),
9936 percentage: report.percentage.map(|p| p as usize),
9937 last_update_at: cx.background_executor().now(),
9938 },
9939 cx,
9940 );
9941 }
9942 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9943 language_server_id,
9944 token,
9945 LanguageServerProgress {
9946 title: None,
9947 is_disk_based_diagnostics_progress,
9948 is_cancellable: report.cancellable.unwrap_or(false),
9949 message: report.message,
9950 percentage: report.percentage.map(|p| p as usize),
9951 last_update_at: cx.background_executor().now(),
9952 },
9953 cx,
9954 ),
9955 lsp::WorkDoneProgress::End(_) => {
9956 language_server_status.progress_tokens.remove(&token);
9957 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9958 if is_disk_based_diagnostics_progress {
9959 self.disk_based_diagnostics_finished(language_server_id, cx);
9960 }
9961 }
9962 }
9963 }
9964
9965 fn on_lsp_work_start(
9966 &mut self,
9967 language_server_id: LanguageServerId,
9968 token: ProgressToken,
9969 progress: LanguageServerProgress,
9970 cx: &mut Context<Self>,
9971 ) {
9972 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9973 status.pending_work.insert(token.clone(), progress.clone());
9974 cx.notify();
9975 }
9976 cx.emit(LspStoreEvent::LanguageServerUpdate {
9977 language_server_id,
9978 name: self
9979 .language_server_adapter_for_id(language_server_id)
9980 .map(|adapter| adapter.name()),
9981 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9982 token: Some(token.to_proto()),
9983 title: progress.title,
9984 message: progress.message,
9985 percentage: progress.percentage.map(|p| p as u32),
9986 is_cancellable: Some(progress.is_cancellable),
9987 }),
9988 })
9989 }
9990
9991 fn on_lsp_work_progress(
9992 &mut self,
9993 language_server_id: LanguageServerId,
9994 token: ProgressToken,
9995 progress: LanguageServerProgress,
9996 cx: &mut Context<Self>,
9997 ) {
9998 let mut did_update = false;
9999 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10000 match status.pending_work.entry(token.clone()) {
10001 btree_map::Entry::Vacant(entry) => {
10002 entry.insert(progress.clone());
10003 did_update = true;
10004 }
10005 btree_map::Entry::Occupied(mut entry) => {
10006 let entry = entry.get_mut();
10007 if (progress.last_update_at - entry.last_update_at)
10008 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10009 {
10010 entry.last_update_at = progress.last_update_at;
10011 if progress.message.is_some() {
10012 entry.message = progress.message.clone();
10013 }
10014 if progress.percentage.is_some() {
10015 entry.percentage = progress.percentage;
10016 }
10017 if progress.is_cancellable != entry.is_cancellable {
10018 entry.is_cancellable = progress.is_cancellable;
10019 }
10020 did_update = true;
10021 }
10022 }
10023 }
10024 }
10025
10026 if did_update {
10027 cx.emit(LspStoreEvent::LanguageServerUpdate {
10028 language_server_id,
10029 name: self
10030 .language_server_adapter_for_id(language_server_id)
10031 .map(|adapter| adapter.name()),
10032 message: proto::update_language_server::Variant::WorkProgress(
10033 proto::LspWorkProgress {
10034 token: Some(token.to_proto()),
10035 message: progress.message,
10036 percentage: progress.percentage.map(|p| p as u32),
10037 is_cancellable: Some(progress.is_cancellable),
10038 },
10039 ),
10040 })
10041 }
10042 }
10043
10044 fn on_lsp_work_end(
10045 &mut self,
10046 language_server_id: LanguageServerId,
10047 token: ProgressToken,
10048 cx: &mut Context<Self>,
10049 ) {
10050 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10051 if let Some(work) = status.pending_work.remove(&token)
10052 && !work.is_disk_based_diagnostics_progress
10053 {
10054 cx.emit(LspStoreEvent::RefreshInlayHints {
10055 server_id: language_server_id,
10056 request_id: None,
10057 });
10058 }
10059 cx.notify();
10060 }
10061
10062 cx.emit(LspStoreEvent::LanguageServerUpdate {
10063 language_server_id,
10064 name: self
10065 .language_server_adapter_for_id(language_server_id)
10066 .map(|adapter| adapter.name()),
10067 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10068 token: Some(token.to_proto()),
10069 }),
10070 })
10071 }
10072
10073 pub async fn handle_resolve_completion_documentation(
10074 this: Entity<Self>,
10075 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10076 mut cx: AsyncApp,
10077 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10078 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10079
10080 let completion = this
10081 .read_with(&cx, |this, cx| {
10082 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10083 let server = this
10084 .language_server_for_id(id)
10085 .with_context(|| format!("No language server {id}"))?;
10086
10087 let request_timeout = ProjectSettings::get_global(cx)
10088 .global_lsp_settings
10089 .get_request_timeout();
10090
10091 anyhow::Ok(cx.background_spawn(async move {
10092 let can_resolve = server
10093 .capabilities()
10094 .completion_provider
10095 .as_ref()
10096 .and_then(|options| options.resolve_provider)
10097 .unwrap_or(false);
10098 if can_resolve {
10099 server
10100 .request::<lsp::request::ResolveCompletionItem>(
10101 lsp_completion,
10102 request_timeout,
10103 )
10104 .await
10105 .into_response()
10106 .context("resolve completion item")
10107 } else {
10108 anyhow::Ok(lsp_completion)
10109 }
10110 }))
10111 })?
10112 .await?;
10113
10114 let mut documentation_is_markdown = false;
10115 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10116 let documentation = match completion.documentation {
10117 Some(lsp::Documentation::String(text)) => text,
10118
10119 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10120 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10121 value
10122 }
10123
10124 _ => String::new(),
10125 };
10126
10127 // If we have a new buffer_id, that means we're talking to a new client
10128 // and want to check for new text_edits in the completion too.
10129 let mut old_replace_start = None;
10130 let mut old_replace_end = None;
10131 let mut old_insert_start = None;
10132 let mut old_insert_end = None;
10133 let mut new_text = String::default();
10134 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10135 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10136 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10137 anyhow::Ok(buffer.read(cx).snapshot())
10138 })?;
10139
10140 if let Some(text_edit) = completion.text_edit.as_ref() {
10141 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10142
10143 if let Some(mut edit) = edit {
10144 LineEnding::normalize(&mut edit.new_text);
10145
10146 new_text = edit.new_text;
10147 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10148 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10149 if let Some(insert_range) = edit.insert_range {
10150 old_insert_start = Some(serialize_anchor(&insert_range.start));
10151 old_insert_end = Some(serialize_anchor(&insert_range.end));
10152 }
10153 }
10154 }
10155 }
10156
10157 Ok(proto::ResolveCompletionDocumentationResponse {
10158 documentation,
10159 documentation_is_markdown,
10160 old_replace_start,
10161 old_replace_end,
10162 new_text,
10163 lsp_completion,
10164 old_insert_start,
10165 old_insert_end,
10166 })
10167 }
10168
10169 async fn handle_on_type_formatting(
10170 this: Entity<Self>,
10171 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10172 mut cx: AsyncApp,
10173 ) -> Result<proto::OnTypeFormattingResponse> {
10174 let on_type_formatting = this.update(&mut cx, |this, cx| {
10175 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10176 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10177 let position = envelope
10178 .payload
10179 .position
10180 .and_then(deserialize_anchor)
10181 .context("invalid position")?;
10182 anyhow::Ok(this.apply_on_type_formatting(
10183 buffer,
10184 position,
10185 envelope.payload.trigger.clone(),
10186 cx,
10187 ))
10188 })?;
10189
10190 let transaction = on_type_formatting
10191 .await?
10192 .as_ref()
10193 .map(language::proto::serialize_transaction);
10194 Ok(proto::OnTypeFormattingResponse { transaction })
10195 }
10196
10197 async fn handle_pull_workspace_diagnostics(
10198 lsp_store: Entity<Self>,
10199 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10200 mut cx: AsyncApp,
10201 ) -> Result<proto::Ack> {
10202 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10203 lsp_store.update(&mut cx, |lsp_store, _| {
10204 lsp_store.pull_workspace_diagnostics(server_id);
10205 });
10206 Ok(proto::Ack {})
10207 }
10208
10209 async fn handle_open_buffer_for_symbol(
10210 this: Entity<Self>,
10211 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10212 mut cx: AsyncApp,
10213 ) -> Result<proto::OpenBufferForSymbolResponse> {
10214 let peer_id = envelope.original_sender_id().unwrap_or_default();
10215 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10216 let symbol = Self::deserialize_symbol(symbol)?;
10217 this.read_with(&cx, |this, _| {
10218 if let SymbolLocation::OutsideProject {
10219 abs_path,
10220 signature,
10221 } = &symbol.path
10222 {
10223 let new_signature = this.symbol_signature(&abs_path);
10224 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10225 }
10226 Ok(())
10227 })?;
10228 let buffer = this
10229 .update(&mut cx, |this, cx| {
10230 this.open_buffer_for_symbol(
10231 &Symbol {
10232 language_server_name: symbol.language_server_name,
10233 source_worktree_id: symbol.source_worktree_id,
10234 source_language_server_id: symbol.source_language_server_id,
10235 path: symbol.path,
10236 name: symbol.name,
10237 kind: symbol.kind,
10238 range: symbol.range,
10239 label: CodeLabel::default(),
10240 container_name: symbol.container_name,
10241 },
10242 cx,
10243 )
10244 })
10245 .await?;
10246
10247 this.update(&mut cx, |this, cx| {
10248 let is_private = buffer
10249 .read(cx)
10250 .file()
10251 .map(|f| f.is_private())
10252 .unwrap_or_default();
10253 if is_private {
10254 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10255 } else {
10256 this.buffer_store
10257 .update(cx, |buffer_store, cx| {
10258 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10259 })
10260 .detach_and_log_err(cx);
10261 let buffer_id = buffer.read(cx).remote_id().to_proto();
10262 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10263 }
10264 })
10265 }
10266
10267 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10268 let mut hasher = Sha256::new();
10269 hasher.update(abs_path.to_string_lossy().as_bytes());
10270 hasher.update(self.nonce.to_be_bytes());
10271 hasher.finalize().as_slice().try_into().unwrap()
10272 }
10273
10274 pub async fn handle_get_project_symbols(
10275 this: Entity<Self>,
10276 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10277 mut cx: AsyncApp,
10278 ) -> Result<proto::GetProjectSymbolsResponse> {
10279 let symbols = this
10280 .update(&mut cx, |this, cx| {
10281 this.symbols(&envelope.payload.query, cx)
10282 })
10283 .await?;
10284
10285 Ok(proto::GetProjectSymbolsResponse {
10286 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10287 })
10288 }
10289
10290 pub async fn handle_restart_language_servers(
10291 this: Entity<Self>,
10292 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10293 mut cx: AsyncApp,
10294 ) -> Result<proto::Ack> {
10295 this.update(&mut cx, |lsp_store, cx| {
10296 let buffers =
10297 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10298 lsp_store.restart_language_servers_for_buffers(
10299 buffers,
10300 envelope
10301 .payload
10302 .only_servers
10303 .into_iter()
10304 .filter_map(|selector| {
10305 Some(match selector.selector? {
10306 proto::language_server_selector::Selector::ServerId(server_id) => {
10307 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10308 }
10309 proto::language_server_selector::Selector::Name(name) => {
10310 LanguageServerSelector::Name(LanguageServerName(
10311 SharedString::from(name),
10312 ))
10313 }
10314 })
10315 })
10316 .collect(),
10317 cx,
10318 );
10319 });
10320
10321 Ok(proto::Ack {})
10322 }
10323
10324 pub async fn handle_stop_language_servers(
10325 lsp_store: Entity<Self>,
10326 envelope: TypedEnvelope<proto::StopLanguageServers>,
10327 mut cx: AsyncApp,
10328 ) -> Result<proto::Ack> {
10329 lsp_store.update(&mut cx, |lsp_store, cx| {
10330 if envelope.payload.all
10331 && envelope.payload.also_servers.is_empty()
10332 && envelope.payload.buffer_ids.is_empty()
10333 {
10334 lsp_store.stop_all_language_servers(cx);
10335 } else {
10336 let buffers =
10337 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10338 lsp_store
10339 .stop_language_servers_for_buffers(
10340 buffers,
10341 envelope
10342 .payload
10343 .also_servers
10344 .into_iter()
10345 .filter_map(|selector| {
10346 Some(match selector.selector? {
10347 proto::language_server_selector::Selector::ServerId(
10348 server_id,
10349 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10350 server_id,
10351 )),
10352 proto::language_server_selector::Selector::Name(name) => {
10353 LanguageServerSelector::Name(LanguageServerName(
10354 SharedString::from(name),
10355 ))
10356 }
10357 })
10358 })
10359 .collect(),
10360 cx,
10361 )
10362 .detach_and_log_err(cx);
10363 }
10364 });
10365
10366 Ok(proto::Ack {})
10367 }
10368
10369 pub async fn handle_cancel_language_server_work(
10370 lsp_store: Entity<Self>,
10371 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10372 mut cx: AsyncApp,
10373 ) -> Result<proto::Ack> {
10374 lsp_store.update(&mut cx, |lsp_store, cx| {
10375 if let Some(work) = envelope.payload.work {
10376 match work {
10377 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10378 let buffers =
10379 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10380 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10381 }
10382 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10383 let server_id = LanguageServerId::from_proto(work.language_server_id);
10384 let token = work
10385 .token
10386 .map(|token| {
10387 ProgressToken::from_proto(token)
10388 .context("invalid work progress token")
10389 })
10390 .transpose()?;
10391 lsp_store.cancel_language_server_work(server_id, token, cx);
10392 }
10393 }
10394 }
10395 anyhow::Ok(())
10396 })?;
10397
10398 Ok(proto::Ack {})
10399 }
10400
10401 fn buffer_ids_to_buffers(
10402 &mut self,
10403 buffer_ids: impl Iterator<Item = u64>,
10404 cx: &mut Context<Self>,
10405 ) -> Vec<Entity<Buffer>> {
10406 buffer_ids
10407 .into_iter()
10408 .flat_map(|buffer_id| {
10409 self.buffer_store
10410 .read(cx)
10411 .get(BufferId::new(buffer_id).log_err()?)
10412 })
10413 .collect::<Vec<_>>()
10414 }
10415
10416 async fn handle_apply_additional_edits_for_completion(
10417 this: Entity<Self>,
10418 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10419 mut cx: AsyncApp,
10420 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10421 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10422 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10423 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10424 let completion = Self::deserialize_completion(
10425 envelope.payload.completion.context("invalid completion")?,
10426 )?;
10427 anyhow::Ok((buffer, completion))
10428 })?;
10429
10430 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10431 this.apply_additional_edits_for_completion(
10432 buffer,
10433 Rc::new(RefCell::new(Box::new([Completion {
10434 replace_range: completion.replace_range,
10435 new_text: completion.new_text,
10436 source: completion.source,
10437 documentation: None,
10438 label: CodeLabel::default(),
10439 match_start: None,
10440 snippet_deduplication_key: None,
10441 insert_text_mode: None,
10442 icon_path: None,
10443 confirm: None,
10444 }]))),
10445 0,
10446 false,
10447 cx,
10448 )
10449 });
10450
10451 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10452 transaction: apply_additional_edits
10453 .await?
10454 .as_ref()
10455 .map(language::proto::serialize_transaction),
10456 })
10457 }
10458
10459 pub fn last_formatting_failure(&self) -> Option<&str> {
10460 self.last_formatting_failure.as_deref()
10461 }
10462
10463 pub fn reset_last_formatting_failure(&mut self) {
10464 self.last_formatting_failure = None;
10465 }
10466
10467 pub fn environment_for_buffer(
10468 &self,
10469 buffer: &Entity<Buffer>,
10470 cx: &mut Context<Self>,
10471 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10472 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10473 environment.update(cx, |env, cx| {
10474 env.buffer_environment(buffer, &self.worktree_store, cx)
10475 })
10476 } else {
10477 Task::ready(None).shared()
10478 }
10479 }
10480
10481 pub fn format(
10482 &mut self,
10483 buffers: HashSet<Entity<Buffer>>,
10484 target: LspFormatTarget,
10485 push_to_history: bool,
10486 trigger: FormatTrigger,
10487 cx: &mut Context<Self>,
10488 ) -> Task<anyhow::Result<ProjectTransaction>> {
10489 let logger = zlog::scoped!("format");
10490 if self.as_local().is_some() {
10491 zlog::trace!(logger => "Formatting locally");
10492 let logger = zlog::scoped!(logger => "local");
10493 let buffers = buffers
10494 .into_iter()
10495 .map(|buffer_handle| {
10496 let buffer = buffer_handle.read(cx);
10497 let buffer_abs_path = File::from_dyn(buffer.file())
10498 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10499
10500 (buffer_handle, buffer_abs_path, buffer.remote_id())
10501 })
10502 .collect::<Vec<_>>();
10503
10504 cx.spawn(async move |lsp_store, cx| {
10505 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10506
10507 for (handle, abs_path, id) in buffers {
10508 let env = lsp_store
10509 .update(cx, |lsp_store, cx| {
10510 lsp_store.environment_for_buffer(&handle, cx)
10511 })?
10512 .await;
10513
10514 let ranges = match &target {
10515 LspFormatTarget::Buffers => None,
10516 LspFormatTarget::Ranges(ranges) => {
10517 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10518 }
10519 };
10520
10521 formattable_buffers.push(FormattableBuffer {
10522 handle,
10523 abs_path,
10524 env,
10525 ranges,
10526 });
10527 }
10528 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10529
10530 let format_timer = zlog::time!(logger => "Formatting buffers");
10531 let result = LocalLspStore::format_locally(
10532 lsp_store.clone(),
10533 formattable_buffers,
10534 push_to_history,
10535 trigger,
10536 logger,
10537 cx,
10538 )
10539 .await;
10540 format_timer.end();
10541
10542 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10543
10544 lsp_store.update(cx, |lsp_store, _| {
10545 lsp_store.update_last_formatting_failure(&result);
10546 })?;
10547
10548 result
10549 })
10550 } else if let Some((client, project_id)) = self.upstream_client() {
10551 zlog::trace!(logger => "Formatting remotely");
10552 let logger = zlog::scoped!(logger => "remote");
10553
10554 let buffer_ranges = match &target {
10555 LspFormatTarget::Buffers => Vec::new(),
10556 LspFormatTarget::Ranges(ranges) => ranges
10557 .iter()
10558 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10559 buffer_id: buffer_id.to_proto(),
10560 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10561 })
10562 .collect(),
10563 };
10564
10565 let buffer_store = self.buffer_store();
10566 cx.spawn(async move |lsp_store, cx| {
10567 zlog::trace!(logger => "Sending remote format request");
10568 let request_timer = zlog::time!(logger => "remote format request");
10569 let result = client
10570 .request(proto::FormatBuffers {
10571 project_id,
10572 trigger: trigger as i32,
10573 buffer_ids: buffers
10574 .iter()
10575 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10576 .collect(),
10577 buffer_ranges,
10578 })
10579 .await
10580 .and_then(|result| result.transaction.context("missing transaction"));
10581 request_timer.end();
10582
10583 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10584
10585 lsp_store.update(cx, |lsp_store, _| {
10586 lsp_store.update_last_formatting_failure(&result);
10587 })?;
10588
10589 let transaction_response = result?;
10590 let _timer = zlog::time!(logger => "deserializing project transaction");
10591 buffer_store
10592 .update(cx, |buffer_store, cx| {
10593 buffer_store.deserialize_project_transaction(
10594 transaction_response,
10595 push_to_history,
10596 cx,
10597 )
10598 })
10599 .await
10600 })
10601 } else {
10602 zlog::trace!(logger => "Not formatting");
10603 Task::ready(Ok(ProjectTransaction::default()))
10604 }
10605 }
10606
10607 async fn handle_format_buffers(
10608 this: Entity<Self>,
10609 envelope: TypedEnvelope<proto::FormatBuffers>,
10610 mut cx: AsyncApp,
10611 ) -> Result<proto::FormatBuffersResponse> {
10612 let sender_id = envelope.original_sender_id().unwrap_or_default();
10613 let format = this.update(&mut cx, |this, cx| {
10614 let mut buffers = HashSet::default();
10615 for buffer_id in &envelope.payload.buffer_ids {
10616 let buffer_id = BufferId::new(*buffer_id)?;
10617 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10618 }
10619
10620 let target = if envelope.payload.buffer_ranges.is_empty() {
10621 LspFormatTarget::Buffers
10622 } else {
10623 let mut ranges_map = BTreeMap::new();
10624 for buffer_range in &envelope.payload.buffer_ranges {
10625 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10626 let ranges: Result<Vec<_>> = buffer_range
10627 .ranges
10628 .iter()
10629 .map(|range| {
10630 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10631 })
10632 .collect();
10633 ranges_map.insert(buffer_id, ranges?);
10634 }
10635 LspFormatTarget::Ranges(ranges_map)
10636 };
10637
10638 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10639 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10640 })?;
10641
10642 let project_transaction = format.await?;
10643 let project_transaction = this.update(&mut cx, |this, cx| {
10644 this.buffer_store.update(cx, |buffer_store, cx| {
10645 buffer_store.serialize_project_transaction_for_peer(
10646 project_transaction,
10647 sender_id,
10648 cx,
10649 )
10650 })
10651 });
10652 Ok(proto::FormatBuffersResponse {
10653 transaction: Some(project_transaction),
10654 })
10655 }
10656
10657 async fn handle_apply_code_action_kind(
10658 this: Entity<Self>,
10659 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10660 mut cx: AsyncApp,
10661 ) -> Result<proto::ApplyCodeActionKindResponse> {
10662 let sender_id = envelope.original_sender_id().unwrap_or_default();
10663 let format = this.update(&mut cx, |this, cx| {
10664 let mut buffers = HashSet::default();
10665 for buffer_id in &envelope.payload.buffer_ids {
10666 let buffer_id = BufferId::new(*buffer_id)?;
10667 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10668 }
10669 let kind = match envelope.payload.kind.as_str() {
10670 "" => CodeActionKind::EMPTY,
10671 "quickfix" => CodeActionKind::QUICKFIX,
10672 "refactor" => CodeActionKind::REFACTOR,
10673 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10674 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10675 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10676 "source" => CodeActionKind::SOURCE,
10677 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10678 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10679 _ => anyhow::bail!(
10680 "Invalid code action kind {}",
10681 envelope.payload.kind.as_str()
10682 ),
10683 };
10684 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10685 })?;
10686
10687 let project_transaction = format.await?;
10688 let project_transaction = this.update(&mut cx, |this, cx| {
10689 this.buffer_store.update(cx, |buffer_store, cx| {
10690 buffer_store.serialize_project_transaction_for_peer(
10691 project_transaction,
10692 sender_id,
10693 cx,
10694 )
10695 })
10696 });
10697 Ok(proto::ApplyCodeActionKindResponse {
10698 transaction: Some(project_transaction),
10699 })
10700 }
10701
10702 async fn shutdown_language_server(
10703 server_state: Option<LanguageServerState>,
10704 name: LanguageServerName,
10705 cx: &mut AsyncApp,
10706 ) {
10707 let server = match server_state {
10708 Some(LanguageServerState::Starting { startup, .. }) => {
10709 let mut timer = cx
10710 .background_executor()
10711 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10712 .fuse();
10713
10714 select! {
10715 server = startup.fuse() => server,
10716 () = timer => {
10717 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10718 None
10719 },
10720 }
10721 }
10722
10723 Some(LanguageServerState::Running { server, .. }) => Some(server),
10724
10725 None => None,
10726 };
10727
10728 let Some(server) = server else { return };
10729 if let Some(shutdown) = server.shutdown() {
10730 shutdown.await;
10731 }
10732 }
10733
10734 // Returns a list of all of the worktrees which no longer have a language server and the root path
10735 // for the stopped server
10736 fn stop_local_language_server(
10737 &mut self,
10738 server_id: LanguageServerId,
10739 cx: &mut Context<Self>,
10740 ) -> Task<()> {
10741 let local = match &mut self.mode {
10742 LspStoreMode::Local(local) => local,
10743 _ => {
10744 return Task::ready(());
10745 }
10746 };
10747
10748 // Remove this server ID from all entries in the given worktree.
10749 local
10750 .language_server_ids
10751 .retain(|_, state| state.id != server_id);
10752 self.buffer_store.update(cx, |buffer_store, cx| {
10753 for buffer in buffer_store.buffers() {
10754 buffer.update(cx, |buffer, cx| {
10755 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10756 buffer.set_completion_triggers(server_id, Default::default(), cx);
10757 });
10758 }
10759 });
10760
10761 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10762 summaries.retain(|path, summaries_by_server_id| {
10763 if summaries_by_server_id.remove(&server_id).is_some() {
10764 if let Some((client, project_id)) = self.downstream_client.clone() {
10765 client
10766 .send(proto::UpdateDiagnosticSummary {
10767 project_id,
10768 worktree_id: worktree_id.to_proto(),
10769 summary: Some(proto::DiagnosticSummary {
10770 path: path.as_ref().to_proto(),
10771 language_server_id: server_id.0 as u64,
10772 error_count: 0,
10773 warning_count: 0,
10774 }),
10775 more_summaries: Vec::new(),
10776 })
10777 .log_err();
10778 }
10779 !summaries_by_server_id.is_empty()
10780 } else {
10781 true
10782 }
10783 });
10784 }
10785
10786 let local = self.as_local_mut().unwrap();
10787 for diagnostics in local.diagnostics.values_mut() {
10788 diagnostics.retain(|_, diagnostics_by_server_id| {
10789 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10790 diagnostics_by_server_id.remove(ix);
10791 !diagnostics_by_server_id.is_empty()
10792 } else {
10793 true
10794 }
10795 });
10796 }
10797 local.language_server_watched_paths.remove(&server_id);
10798
10799 let server_state = local.language_servers.remove(&server_id);
10800 self.cleanup_lsp_data(server_id);
10801 let name = self
10802 .language_server_statuses
10803 .remove(&server_id)
10804 .map(|status| status.name)
10805 .or_else(|| {
10806 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10807 Some(adapter.name())
10808 } else {
10809 None
10810 }
10811 });
10812
10813 if let Some(name) = name {
10814 log::info!("stopping language server {name}");
10815 self.languages
10816 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10817 cx.notify();
10818
10819 return cx.spawn(async move |lsp_store, cx| {
10820 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10821 lsp_store
10822 .update(cx, |lsp_store, cx| {
10823 lsp_store
10824 .languages
10825 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10826 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10827 cx.notify();
10828 })
10829 .ok();
10830 });
10831 }
10832
10833 if server_state.is_some() {
10834 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10835 }
10836 Task::ready(())
10837 }
10838
10839 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10840 self.shutdown_all_language_servers(cx).detach();
10841 }
10842
10843 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10844 if let Some((client, project_id)) = self.upstream_client() {
10845 let request = client.request(proto::StopLanguageServers {
10846 project_id,
10847 buffer_ids: Vec::new(),
10848 also_servers: Vec::new(),
10849 all: true,
10850 });
10851 cx.background_spawn(async move {
10852 request.await.ok();
10853 })
10854 } else {
10855 let Some(local) = self.as_local_mut() else {
10856 return Task::ready(());
10857 };
10858 let language_servers_to_stop = local
10859 .language_server_ids
10860 .values()
10861 .map(|state| state.id)
10862 .collect();
10863 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10864 let tasks = language_servers_to_stop
10865 .into_iter()
10866 .map(|server| self.stop_local_language_server(server, cx))
10867 .collect::<Vec<_>>();
10868 cx.background_spawn(async move {
10869 futures::future::join_all(tasks).await;
10870 })
10871 }
10872 }
10873
10874 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10875 let buffers = self.buffer_store.read(cx).buffers().collect();
10876 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10877 }
10878
10879 pub fn restart_language_servers_for_buffers(
10880 &mut self,
10881 buffers: Vec<Entity<Buffer>>,
10882 only_restart_servers: HashSet<LanguageServerSelector>,
10883 cx: &mut Context<Self>,
10884 ) {
10885 if let Some((client, project_id)) = self.upstream_client() {
10886 let request = client.request(proto::RestartLanguageServers {
10887 project_id,
10888 buffer_ids: buffers
10889 .into_iter()
10890 .map(|b| b.read(cx).remote_id().to_proto())
10891 .collect(),
10892 only_servers: only_restart_servers
10893 .into_iter()
10894 .map(|selector| {
10895 let selector = match selector {
10896 LanguageServerSelector::Id(language_server_id) => {
10897 proto::language_server_selector::Selector::ServerId(
10898 language_server_id.to_proto(),
10899 )
10900 }
10901 LanguageServerSelector::Name(language_server_name) => {
10902 proto::language_server_selector::Selector::Name(
10903 language_server_name.to_string(),
10904 )
10905 }
10906 };
10907 proto::LanguageServerSelector {
10908 selector: Some(selector),
10909 }
10910 })
10911 .collect(),
10912 all: false,
10913 });
10914 cx.background_spawn(request).detach_and_log_err(cx);
10915 } else {
10916 let stop_task = if only_restart_servers.is_empty() {
10917 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10918 } else {
10919 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10920 };
10921 cx.spawn(async move |lsp_store, cx| {
10922 stop_task.await;
10923 lsp_store.update(cx, |lsp_store, cx| {
10924 for buffer in buffers {
10925 lsp_store.register_buffer_with_language_servers(
10926 &buffer,
10927 only_restart_servers.clone(),
10928 true,
10929 cx,
10930 );
10931 }
10932 })
10933 })
10934 .detach();
10935 }
10936 }
10937
10938 pub fn stop_language_servers_for_buffers(
10939 &mut self,
10940 buffers: Vec<Entity<Buffer>>,
10941 also_stop_servers: HashSet<LanguageServerSelector>,
10942 cx: &mut Context<Self>,
10943 ) -> Task<Result<()>> {
10944 if let Some((client, project_id)) = self.upstream_client() {
10945 let request = client.request(proto::StopLanguageServers {
10946 project_id,
10947 buffer_ids: buffers
10948 .into_iter()
10949 .map(|b| b.read(cx).remote_id().to_proto())
10950 .collect(),
10951 also_servers: also_stop_servers
10952 .into_iter()
10953 .map(|selector| {
10954 let selector = match selector {
10955 LanguageServerSelector::Id(language_server_id) => {
10956 proto::language_server_selector::Selector::ServerId(
10957 language_server_id.to_proto(),
10958 )
10959 }
10960 LanguageServerSelector::Name(language_server_name) => {
10961 proto::language_server_selector::Selector::Name(
10962 language_server_name.to_string(),
10963 )
10964 }
10965 };
10966 proto::LanguageServerSelector {
10967 selector: Some(selector),
10968 }
10969 })
10970 .collect(),
10971 all: false,
10972 });
10973 cx.background_spawn(async move {
10974 let _ = request.await?;
10975 Ok(())
10976 })
10977 } else {
10978 let task =
10979 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10980 cx.background_spawn(async move {
10981 task.await;
10982 Ok(())
10983 })
10984 }
10985 }
10986
10987 fn stop_local_language_servers_for_buffers(
10988 &mut self,
10989 buffers: &[Entity<Buffer>],
10990 also_stop_servers: HashSet<LanguageServerSelector>,
10991 cx: &mut Context<Self>,
10992 ) -> Task<()> {
10993 let Some(local) = self.as_local_mut() else {
10994 return Task::ready(());
10995 };
10996 let mut language_server_names_to_stop = BTreeSet::default();
10997 let mut language_servers_to_stop = also_stop_servers
10998 .into_iter()
10999 .flat_map(|selector| match selector {
11000 LanguageServerSelector::Id(id) => Some(id),
11001 LanguageServerSelector::Name(name) => {
11002 language_server_names_to_stop.insert(name);
11003 None
11004 }
11005 })
11006 .collect::<BTreeSet<_>>();
11007
11008 let mut covered_worktrees = HashSet::default();
11009 for buffer in buffers {
11010 buffer.update(cx, |buffer, cx| {
11011 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11012 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11013 && covered_worktrees.insert(worktree_id)
11014 {
11015 language_server_names_to_stop.retain(|name| {
11016 let old_ids_count = language_servers_to_stop.len();
11017 let all_language_servers_with_this_name = local
11018 .language_server_ids
11019 .iter()
11020 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11021 language_servers_to_stop.extend(all_language_servers_with_this_name);
11022 old_ids_count == language_servers_to_stop.len()
11023 });
11024 }
11025 });
11026 }
11027 for name in language_server_names_to_stop {
11028 language_servers_to_stop.extend(
11029 local
11030 .language_server_ids
11031 .iter()
11032 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11033 );
11034 }
11035
11036 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11037 let tasks = language_servers_to_stop
11038 .into_iter()
11039 .map(|server| self.stop_local_language_server(server, cx))
11040 .collect::<Vec<_>>();
11041
11042 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11043 }
11044
11045 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11046 let (worktree, relative_path) =
11047 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11048
11049 let project_path = ProjectPath {
11050 worktree_id: worktree.read(cx).id(),
11051 path: relative_path,
11052 };
11053
11054 Some(
11055 self.buffer_store()
11056 .read(cx)
11057 .get_by_path(&project_path)?
11058 .read(cx),
11059 )
11060 }
11061
11062 #[cfg(any(test, feature = "test-support"))]
11063 pub fn update_diagnostics(
11064 &mut self,
11065 server_id: LanguageServerId,
11066 diagnostics: lsp::PublishDiagnosticsParams,
11067 result_id: Option<SharedString>,
11068 source_kind: DiagnosticSourceKind,
11069 disk_based_sources: &[String],
11070 cx: &mut Context<Self>,
11071 ) -> Result<()> {
11072 self.merge_lsp_diagnostics(
11073 source_kind,
11074 vec![DocumentDiagnosticsUpdate {
11075 diagnostics,
11076 result_id,
11077 server_id,
11078 disk_based_sources: Cow::Borrowed(disk_based_sources),
11079 registration_id: None,
11080 }],
11081 |_, _, _| false,
11082 cx,
11083 )
11084 }
11085
11086 pub fn merge_lsp_diagnostics(
11087 &mut self,
11088 source_kind: DiagnosticSourceKind,
11089 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11090 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11091 cx: &mut Context<Self>,
11092 ) -> Result<()> {
11093 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11094 let updates = lsp_diagnostics
11095 .into_iter()
11096 .filter_map(|update| {
11097 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11098 Some(DocumentDiagnosticsUpdate {
11099 diagnostics: self.lsp_to_document_diagnostics(
11100 abs_path,
11101 source_kind,
11102 update.server_id,
11103 update.diagnostics,
11104 &update.disk_based_sources,
11105 update.registration_id.clone(),
11106 ),
11107 result_id: update.result_id,
11108 server_id: update.server_id,
11109 disk_based_sources: update.disk_based_sources,
11110 registration_id: update.registration_id,
11111 })
11112 })
11113 .collect();
11114 self.merge_diagnostic_entries(updates, merge, cx)?;
11115 Ok(())
11116 }
11117
11118 fn lsp_to_document_diagnostics(
11119 &mut self,
11120 document_abs_path: PathBuf,
11121 source_kind: DiagnosticSourceKind,
11122 server_id: LanguageServerId,
11123 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11124 disk_based_sources: &[String],
11125 registration_id: Option<SharedString>,
11126 ) -> DocumentDiagnostics {
11127 let mut diagnostics = Vec::default();
11128 let mut primary_diagnostic_group_ids = HashMap::default();
11129 let mut sources_by_group_id = HashMap::default();
11130 let mut supporting_diagnostics = HashMap::default();
11131
11132 let adapter = self.language_server_adapter_for_id(server_id);
11133
11134 // Ensure that primary diagnostics are always the most severe
11135 lsp_diagnostics
11136 .diagnostics
11137 .sort_by_key(|item| item.severity);
11138
11139 for diagnostic in &lsp_diagnostics.diagnostics {
11140 let source = diagnostic.source.as_ref();
11141 let range = range_from_lsp(diagnostic.range);
11142 let is_supporting = diagnostic
11143 .related_information
11144 .as_ref()
11145 .is_some_and(|infos| {
11146 infos.iter().any(|info| {
11147 primary_diagnostic_group_ids.contains_key(&(
11148 source,
11149 diagnostic.code.clone(),
11150 range_from_lsp(info.location.range),
11151 ))
11152 })
11153 });
11154
11155 let is_unnecessary = diagnostic
11156 .tags
11157 .as_ref()
11158 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11159
11160 let underline = self
11161 .language_server_adapter_for_id(server_id)
11162 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11163
11164 if is_supporting {
11165 supporting_diagnostics.insert(
11166 (source, diagnostic.code.clone(), range),
11167 (diagnostic.severity, is_unnecessary),
11168 );
11169 } else {
11170 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11171 let is_disk_based =
11172 source.is_some_and(|source| disk_based_sources.contains(source));
11173
11174 sources_by_group_id.insert(group_id, source);
11175 primary_diagnostic_group_ids
11176 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11177
11178 diagnostics.push(DiagnosticEntry {
11179 range,
11180 diagnostic: Diagnostic {
11181 source: diagnostic.source.clone(),
11182 source_kind,
11183 code: diagnostic.code.clone(),
11184 code_description: diagnostic
11185 .code_description
11186 .as_ref()
11187 .and_then(|d| d.href.clone()),
11188 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11189 markdown: adapter.as_ref().and_then(|adapter| {
11190 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11191 }),
11192 message: diagnostic.message.trim().to_string(),
11193 group_id,
11194 is_primary: true,
11195 is_disk_based,
11196 is_unnecessary,
11197 underline,
11198 data: diagnostic.data.clone(),
11199 registration_id: registration_id.clone(),
11200 },
11201 });
11202 if let Some(infos) = &diagnostic.related_information {
11203 for info in infos {
11204 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11205 let range = range_from_lsp(info.location.range);
11206 diagnostics.push(DiagnosticEntry {
11207 range,
11208 diagnostic: Diagnostic {
11209 source: diagnostic.source.clone(),
11210 source_kind,
11211 code: diagnostic.code.clone(),
11212 code_description: diagnostic
11213 .code_description
11214 .as_ref()
11215 .and_then(|d| d.href.clone()),
11216 severity: DiagnosticSeverity::INFORMATION,
11217 markdown: adapter.as_ref().and_then(|adapter| {
11218 adapter.diagnostic_message_to_markdown(&info.message)
11219 }),
11220 message: info.message.trim().to_string(),
11221 group_id,
11222 is_primary: false,
11223 is_disk_based,
11224 is_unnecessary: false,
11225 underline,
11226 data: diagnostic.data.clone(),
11227 registration_id: registration_id.clone(),
11228 },
11229 });
11230 }
11231 }
11232 }
11233 }
11234 }
11235
11236 for entry in &mut diagnostics {
11237 let diagnostic = &mut entry.diagnostic;
11238 if !diagnostic.is_primary {
11239 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11240 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11241 source,
11242 diagnostic.code.clone(),
11243 entry.range.clone(),
11244 )) {
11245 if let Some(severity) = severity {
11246 diagnostic.severity = severity;
11247 }
11248 diagnostic.is_unnecessary = is_unnecessary;
11249 }
11250 }
11251 }
11252
11253 DocumentDiagnostics {
11254 diagnostics,
11255 document_abs_path,
11256 version: lsp_diagnostics.version,
11257 }
11258 }
11259
11260 fn insert_newly_running_language_server(
11261 &mut self,
11262 adapter: Arc<CachedLspAdapter>,
11263 language_server: Arc<LanguageServer>,
11264 server_id: LanguageServerId,
11265 key: LanguageServerSeed,
11266 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11267 cx: &mut Context<Self>,
11268 ) {
11269 let Some(local) = self.as_local_mut() else {
11270 return;
11271 };
11272 // If the language server for this key doesn't match the server id, don't store the
11273 // server. Which will cause it to be dropped, killing the process
11274 if local
11275 .language_server_ids
11276 .get(&key)
11277 .map(|state| state.id != server_id)
11278 .unwrap_or(false)
11279 {
11280 return;
11281 }
11282
11283 // Update language_servers collection with Running variant of LanguageServerState
11284 // indicating that the server is up and running and ready
11285 let workspace_folders = workspace_folders.lock().clone();
11286 language_server.set_workspace_folders(workspace_folders);
11287
11288 let workspace_diagnostics_refresh_tasks = language_server
11289 .capabilities()
11290 .diagnostic_provider
11291 .and_then(|provider| {
11292 local
11293 .language_server_dynamic_registrations
11294 .entry(server_id)
11295 .or_default()
11296 .diagnostics
11297 .entry(None)
11298 .or_insert(provider.clone());
11299 let workspace_refresher =
11300 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11301
11302 Some((None, workspace_refresher))
11303 })
11304 .into_iter()
11305 .collect();
11306 local.language_servers.insert(
11307 server_id,
11308 LanguageServerState::Running {
11309 workspace_diagnostics_refresh_tasks,
11310 adapter: adapter.clone(),
11311 server: language_server.clone(),
11312 simulate_disk_based_diagnostics_completion: None,
11313 },
11314 );
11315 local
11316 .languages
11317 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11318 if let Some(file_ops_caps) = language_server
11319 .capabilities()
11320 .workspace
11321 .as_ref()
11322 .and_then(|ws| ws.file_operations.as_ref())
11323 {
11324 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11325 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11326 if did_rename_caps.or(will_rename_caps).is_some() {
11327 let watcher = RenamePathsWatchedForServer::default()
11328 .with_did_rename_patterns(did_rename_caps)
11329 .with_will_rename_patterns(will_rename_caps);
11330 local
11331 .language_server_paths_watched_for_rename
11332 .insert(server_id, watcher);
11333 }
11334 }
11335
11336 self.language_server_statuses.insert(
11337 server_id,
11338 LanguageServerStatus {
11339 name: language_server.name(),
11340 server_version: language_server.version(),
11341 pending_work: Default::default(),
11342 has_pending_diagnostic_updates: false,
11343 progress_tokens: Default::default(),
11344 worktree: Some(key.worktree_id),
11345 binary: Some(language_server.binary().clone()),
11346 configuration: Some(language_server.configuration().clone()),
11347 workspace_folders: language_server.workspace_folders(),
11348 process_id: language_server.process_id(),
11349 },
11350 );
11351
11352 cx.emit(LspStoreEvent::LanguageServerAdded(
11353 server_id,
11354 language_server.name(),
11355 Some(key.worktree_id),
11356 ));
11357
11358 let server_capabilities = language_server.capabilities();
11359 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11360 downstream_client
11361 .send(proto::StartLanguageServer {
11362 project_id: *project_id,
11363 server: Some(proto::LanguageServer {
11364 id: server_id.to_proto(),
11365 name: language_server.name().to_string(),
11366 worktree_id: Some(key.worktree_id.to_proto()),
11367 }),
11368 capabilities: serde_json::to_string(&server_capabilities)
11369 .expect("serializing server LSP capabilities"),
11370 })
11371 .log_err();
11372 }
11373 self.lsp_server_capabilities
11374 .insert(server_id, server_capabilities);
11375
11376 // Tell the language server about every open buffer in the worktree that matches the language.
11377 // Also check for buffers in worktrees that reused this server
11378 let mut worktrees_using_server = vec![key.worktree_id];
11379 if let Some(local) = self.as_local() {
11380 // Find all worktrees that have this server in their language server tree
11381 for (worktree_id, servers) in &local.lsp_tree.instances {
11382 if *worktree_id != key.worktree_id {
11383 for server_map in servers.roots.values() {
11384 if server_map
11385 .values()
11386 .any(|(node, _)| node.id() == Some(server_id))
11387 {
11388 worktrees_using_server.push(*worktree_id);
11389 }
11390 }
11391 }
11392 }
11393 }
11394
11395 let mut buffer_paths_registered = Vec::new();
11396 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11397 let mut lsp_adapters = HashMap::default();
11398 for buffer_handle in buffer_store.buffers() {
11399 let buffer = buffer_handle.read(cx);
11400 let file = match File::from_dyn(buffer.file()) {
11401 Some(file) => file,
11402 None => continue,
11403 };
11404 let language = match buffer.language() {
11405 Some(language) => language,
11406 None => continue,
11407 };
11408
11409 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11410 || !lsp_adapters
11411 .entry(language.name())
11412 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11413 .iter()
11414 .any(|a| a.name == key.name)
11415 {
11416 continue;
11417 }
11418 // didOpen
11419 let file = match file.as_local() {
11420 Some(file) => file,
11421 None => continue,
11422 };
11423
11424 let local = self.as_local_mut().unwrap();
11425
11426 let buffer_id = buffer.remote_id();
11427 if local.registered_buffers.contains_key(&buffer_id) {
11428 let abs_path = file.abs_path(cx);
11429 let uri = match lsp::Uri::from_file_path(&abs_path) {
11430 Ok(uri) => uri,
11431 Err(()) => {
11432 log::error!("failed to convert path to URI: {:?}", abs_path);
11433 continue;
11434 }
11435 };
11436
11437 let versions = local
11438 .buffer_snapshots
11439 .entry(buffer_id)
11440 .or_default()
11441 .entry(server_id)
11442 .and_modify(|_| {
11443 assert!(
11444 false,
11445 "There should not be an existing snapshot for a newly inserted buffer"
11446 )
11447 })
11448 .or_insert_with(|| {
11449 vec![LspBufferSnapshot {
11450 version: 0,
11451 snapshot: buffer.text_snapshot(),
11452 }]
11453 });
11454
11455 let snapshot = versions.last().unwrap();
11456 let version = snapshot.version;
11457 let initial_snapshot = &snapshot.snapshot;
11458 language_server.register_buffer(
11459 uri,
11460 adapter.language_id(&language.name()),
11461 version,
11462 initial_snapshot.text(),
11463 );
11464 buffer_paths_registered.push((buffer_id, abs_path));
11465 local
11466 .buffers_opened_in_servers
11467 .entry(buffer_id)
11468 .or_default()
11469 .insert(server_id);
11470 }
11471 buffer_handle.update(cx, |buffer, cx| {
11472 buffer.set_completion_triggers(
11473 server_id,
11474 language_server
11475 .capabilities()
11476 .completion_provider
11477 .as_ref()
11478 .and_then(|provider| {
11479 provider
11480 .trigger_characters
11481 .as_ref()
11482 .map(|characters| characters.iter().cloned().collect())
11483 })
11484 .unwrap_or_default(),
11485 cx,
11486 )
11487 });
11488 }
11489 });
11490
11491 for (buffer_id, abs_path) in buffer_paths_registered {
11492 cx.emit(LspStoreEvent::LanguageServerUpdate {
11493 language_server_id: server_id,
11494 name: Some(adapter.name()),
11495 message: proto::update_language_server::Variant::RegisteredForBuffer(
11496 proto::RegisteredForBuffer {
11497 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11498 buffer_id: buffer_id.to_proto(),
11499 },
11500 ),
11501 });
11502 }
11503
11504 cx.notify();
11505 }
11506
11507 pub fn language_servers_running_disk_based_diagnostics(
11508 &self,
11509 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11510 self.language_server_statuses
11511 .iter()
11512 .filter_map(|(id, status)| {
11513 if status.has_pending_diagnostic_updates {
11514 Some(*id)
11515 } else {
11516 None
11517 }
11518 })
11519 }
11520
11521 pub(crate) fn cancel_language_server_work_for_buffers(
11522 &mut self,
11523 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11524 cx: &mut Context<Self>,
11525 ) {
11526 if let Some((client, project_id)) = self.upstream_client() {
11527 let request = client.request(proto::CancelLanguageServerWork {
11528 project_id,
11529 work: Some(proto::cancel_language_server_work::Work::Buffers(
11530 proto::cancel_language_server_work::Buffers {
11531 buffer_ids: buffers
11532 .into_iter()
11533 .map(|b| b.read(cx).remote_id().to_proto())
11534 .collect(),
11535 },
11536 )),
11537 });
11538 cx.background_spawn(request).detach_and_log_err(cx);
11539 } else if let Some(local) = self.as_local() {
11540 let servers = buffers
11541 .into_iter()
11542 .flat_map(|buffer| {
11543 buffer.update(cx, |buffer, cx| {
11544 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11545 })
11546 })
11547 .collect::<HashSet<_>>();
11548 for server_id in servers {
11549 self.cancel_language_server_work(server_id, None, cx);
11550 }
11551 }
11552 }
11553
11554 pub(crate) fn cancel_language_server_work(
11555 &mut self,
11556 server_id: LanguageServerId,
11557 token_to_cancel: Option<ProgressToken>,
11558 cx: &mut Context<Self>,
11559 ) {
11560 if let Some(local) = self.as_local() {
11561 let status = self.language_server_statuses.get(&server_id);
11562 let server = local.language_servers.get(&server_id);
11563 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11564 {
11565 for (token, progress) in &status.pending_work {
11566 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11567 && token != token_to_cancel
11568 {
11569 continue;
11570 }
11571 if progress.is_cancellable {
11572 server
11573 .notify::<lsp::notification::WorkDoneProgressCancel>(
11574 WorkDoneProgressCancelParams {
11575 token: token.to_lsp(),
11576 },
11577 )
11578 .ok();
11579 }
11580 }
11581 }
11582 } else if let Some((client, project_id)) = self.upstream_client() {
11583 let request = client.request(proto::CancelLanguageServerWork {
11584 project_id,
11585 work: Some(
11586 proto::cancel_language_server_work::Work::LanguageServerWork(
11587 proto::cancel_language_server_work::LanguageServerWork {
11588 language_server_id: server_id.to_proto(),
11589 token: token_to_cancel.map(|token| token.to_proto()),
11590 },
11591 ),
11592 ),
11593 });
11594 cx.background_spawn(request).detach_and_log_err(cx);
11595 }
11596 }
11597
11598 fn register_supplementary_language_server(
11599 &mut self,
11600 id: LanguageServerId,
11601 name: LanguageServerName,
11602 server: Arc<LanguageServer>,
11603 cx: &mut Context<Self>,
11604 ) {
11605 if let Some(local) = self.as_local_mut() {
11606 local
11607 .supplementary_language_servers
11608 .insert(id, (name.clone(), server));
11609 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11610 }
11611 }
11612
11613 fn unregister_supplementary_language_server(
11614 &mut self,
11615 id: LanguageServerId,
11616 cx: &mut Context<Self>,
11617 ) {
11618 if let Some(local) = self.as_local_mut() {
11619 local.supplementary_language_servers.remove(&id);
11620 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11621 }
11622 }
11623
11624 pub(crate) fn supplementary_language_servers(
11625 &self,
11626 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11627 self.as_local().into_iter().flat_map(|local| {
11628 local
11629 .supplementary_language_servers
11630 .iter()
11631 .map(|(id, (name, _))| (*id, name.clone()))
11632 })
11633 }
11634
11635 pub fn language_server_adapter_for_id(
11636 &self,
11637 id: LanguageServerId,
11638 ) -> Option<Arc<CachedLspAdapter>> {
11639 self.as_local()
11640 .and_then(|local| local.language_servers.get(&id))
11641 .and_then(|language_server_state| match language_server_state {
11642 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11643 _ => None,
11644 })
11645 }
11646
11647 pub(super) fn update_local_worktree_language_servers(
11648 &mut self,
11649 worktree_handle: &Entity<Worktree>,
11650 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11651 cx: &mut Context<Self>,
11652 ) {
11653 if changes.is_empty() {
11654 return;
11655 }
11656
11657 let Some(local) = self.as_local() else { return };
11658
11659 local.prettier_store.update(cx, |prettier_store, cx| {
11660 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11661 });
11662
11663 let worktree_id = worktree_handle.read(cx).id();
11664 let mut language_server_ids = local
11665 .language_server_ids
11666 .iter()
11667 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11668 .collect::<Vec<_>>();
11669 language_server_ids.sort();
11670 language_server_ids.dedup();
11671
11672 // let abs_path = worktree_handle.read(cx).abs_path();
11673 for server_id in &language_server_ids {
11674 if let Some(LanguageServerState::Running { server, .. }) =
11675 local.language_servers.get(server_id)
11676 && let Some(watched_paths) = local
11677 .language_server_watched_paths
11678 .get(server_id)
11679 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11680 {
11681 let params = lsp::DidChangeWatchedFilesParams {
11682 changes: changes
11683 .iter()
11684 .filter_map(|(path, _, change)| {
11685 if !watched_paths.is_match(path.as_std_path()) {
11686 return None;
11687 }
11688 let typ = match change {
11689 PathChange::Loaded => return None,
11690 PathChange::Added => lsp::FileChangeType::CREATED,
11691 PathChange::Removed => lsp::FileChangeType::DELETED,
11692 PathChange::Updated => lsp::FileChangeType::CHANGED,
11693 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11694 };
11695 let uri = lsp::Uri::from_file_path(
11696 worktree_handle.read(cx).absolutize(&path),
11697 )
11698 .ok()?;
11699 Some(lsp::FileEvent { uri, typ })
11700 })
11701 .collect(),
11702 };
11703 if !params.changes.is_empty() {
11704 server
11705 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11706 .ok();
11707 }
11708 }
11709 }
11710 for (path, _, _) in changes {
11711 if let Some(file_name) = path.file_name()
11712 && local.watched_manifest_filenames.contains(file_name)
11713 {
11714 self.request_workspace_config_refresh();
11715 break;
11716 }
11717 }
11718 }
11719
11720 pub fn wait_for_remote_buffer(
11721 &mut self,
11722 id: BufferId,
11723 cx: &mut Context<Self>,
11724 ) -> Task<Result<Entity<Buffer>>> {
11725 self.buffer_store.update(cx, |buffer_store, cx| {
11726 buffer_store.wait_for_remote_buffer(id, cx)
11727 })
11728 }
11729
11730 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11731 let mut result = proto::Symbol {
11732 language_server_name: symbol.language_server_name.0.to_string(),
11733 source_worktree_id: symbol.source_worktree_id.to_proto(),
11734 language_server_id: symbol.source_language_server_id.to_proto(),
11735 name: symbol.name.clone(),
11736 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11737 start: Some(proto::PointUtf16 {
11738 row: symbol.range.start.0.row,
11739 column: symbol.range.start.0.column,
11740 }),
11741 end: Some(proto::PointUtf16 {
11742 row: symbol.range.end.0.row,
11743 column: symbol.range.end.0.column,
11744 }),
11745 worktree_id: Default::default(),
11746 path: Default::default(),
11747 signature: Default::default(),
11748 container_name: symbol.container_name.clone(),
11749 };
11750 match &symbol.path {
11751 SymbolLocation::InProject(path) => {
11752 result.worktree_id = path.worktree_id.to_proto();
11753 result.path = path.path.to_proto();
11754 }
11755 SymbolLocation::OutsideProject {
11756 abs_path,
11757 signature,
11758 } => {
11759 result.path = abs_path.to_string_lossy().into_owned();
11760 result.signature = signature.to_vec();
11761 }
11762 }
11763 result
11764 }
11765
11766 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11767 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11768 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11769 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11770
11771 let path = if serialized_symbol.signature.is_empty() {
11772 SymbolLocation::InProject(ProjectPath {
11773 worktree_id,
11774 path: RelPath::from_proto(&serialized_symbol.path)
11775 .context("invalid symbol path")?,
11776 })
11777 } else {
11778 SymbolLocation::OutsideProject {
11779 abs_path: Path::new(&serialized_symbol.path).into(),
11780 signature: serialized_symbol
11781 .signature
11782 .try_into()
11783 .map_err(|_| anyhow!("invalid signature"))?,
11784 }
11785 };
11786
11787 let start = serialized_symbol.start.context("invalid start")?;
11788 let end = serialized_symbol.end.context("invalid end")?;
11789 Ok(CoreSymbol {
11790 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11791 source_worktree_id,
11792 source_language_server_id: LanguageServerId::from_proto(
11793 serialized_symbol.language_server_id,
11794 ),
11795 path,
11796 name: serialized_symbol.name,
11797 range: Unclipped(PointUtf16::new(start.row, start.column))
11798 ..Unclipped(PointUtf16::new(end.row, end.column)),
11799 kind,
11800 container_name: serialized_symbol.container_name,
11801 })
11802 }
11803
11804 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11805 let mut serialized_completion = proto::Completion {
11806 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11807 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11808 new_text: completion.new_text.clone(),
11809 ..proto::Completion::default()
11810 };
11811 match &completion.source {
11812 CompletionSource::Lsp {
11813 insert_range,
11814 server_id,
11815 lsp_completion,
11816 lsp_defaults,
11817 resolved,
11818 } => {
11819 let (old_insert_start, old_insert_end) = insert_range
11820 .as_ref()
11821 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11822 .unzip();
11823
11824 serialized_completion.old_insert_start = old_insert_start;
11825 serialized_completion.old_insert_end = old_insert_end;
11826 serialized_completion.source = proto::completion::Source::Lsp as i32;
11827 serialized_completion.server_id = server_id.0 as u64;
11828 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11829 serialized_completion.lsp_defaults = lsp_defaults
11830 .as_deref()
11831 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11832 serialized_completion.resolved = *resolved;
11833 }
11834 CompletionSource::BufferWord {
11835 word_range,
11836 resolved,
11837 } => {
11838 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11839 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11840 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11841 serialized_completion.resolved = *resolved;
11842 }
11843 CompletionSource::Custom => {
11844 serialized_completion.source = proto::completion::Source::Custom as i32;
11845 serialized_completion.resolved = true;
11846 }
11847 CompletionSource::Dap { sort_text } => {
11848 serialized_completion.source = proto::completion::Source::Dap as i32;
11849 serialized_completion.sort_text = Some(sort_text.clone());
11850 }
11851 }
11852
11853 serialized_completion
11854 }
11855
11856 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11857 let old_replace_start = completion
11858 .old_replace_start
11859 .and_then(deserialize_anchor)
11860 .context("invalid old start")?;
11861 let old_replace_end = completion
11862 .old_replace_end
11863 .and_then(deserialize_anchor)
11864 .context("invalid old end")?;
11865 let insert_range = {
11866 match completion.old_insert_start.zip(completion.old_insert_end) {
11867 Some((start, end)) => {
11868 let start = deserialize_anchor(start).context("invalid insert old start")?;
11869 let end = deserialize_anchor(end).context("invalid insert old end")?;
11870 Some(start..end)
11871 }
11872 None => None,
11873 }
11874 };
11875 Ok(CoreCompletion {
11876 replace_range: old_replace_start..old_replace_end,
11877 new_text: completion.new_text,
11878 source: match proto::completion::Source::from_i32(completion.source) {
11879 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11880 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11881 insert_range,
11882 server_id: LanguageServerId::from_proto(completion.server_id),
11883 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11884 lsp_defaults: completion
11885 .lsp_defaults
11886 .as_deref()
11887 .map(serde_json::from_slice)
11888 .transpose()?,
11889 resolved: completion.resolved,
11890 },
11891 Some(proto::completion::Source::BufferWord) => {
11892 let word_range = completion
11893 .buffer_word_start
11894 .and_then(deserialize_anchor)
11895 .context("invalid buffer word start")?
11896 ..completion
11897 .buffer_word_end
11898 .and_then(deserialize_anchor)
11899 .context("invalid buffer word end")?;
11900 CompletionSource::BufferWord {
11901 word_range,
11902 resolved: completion.resolved,
11903 }
11904 }
11905 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11906 sort_text: completion
11907 .sort_text
11908 .context("expected sort text to exist")?,
11909 },
11910 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11911 },
11912 })
11913 }
11914
11915 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11916 let (kind, lsp_action) = match &action.lsp_action {
11917 LspAction::Action(code_action) => (
11918 proto::code_action::Kind::Action as i32,
11919 serde_json::to_vec(code_action).unwrap(),
11920 ),
11921 LspAction::Command(command) => (
11922 proto::code_action::Kind::Command as i32,
11923 serde_json::to_vec(command).unwrap(),
11924 ),
11925 LspAction::CodeLens(code_lens) => (
11926 proto::code_action::Kind::CodeLens as i32,
11927 serde_json::to_vec(code_lens).unwrap(),
11928 ),
11929 };
11930
11931 proto::CodeAction {
11932 server_id: action.server_id.0 as u64,
11933 start: Some(serialize_anchor(&action.range.start)),
11934 end: Some(serialize_anchor(&action.range.end)),
11935 lsp_action,
11936 kind,
11937 resolved: action.resolved,
11938 }
11939 }
11940
11941 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11942 let start = action
11943 .start
11944 .and_then(deserialize_anchor)
11945 .context("invalid start")?;
11946 let end = action
11947 .end
11948 .and_then(deserialize_anchor)
11949 .context("invalid end")?;
11950 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11951 Some(proto::code_action::Kind::Action) => {
11952 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11953 }
11954 Some(proto::code_action::Kind::Command) => {
11955 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11956 }
11957 Some(proto::code_action::Kind::CodeLens) => {
11958 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11959 }
11960 None => anyhow::bail!("Unknown action kind {}", action.kind),
11961 };
11962 Ok(CodeAction {
11963 server_id: LanguageServerId(action.server_id as usize),
11964 range: start..end,
11965 resolved: action.resolved,
11966 lsp_action,
11967 })
11968 }
11969
11970 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11971 match &formatting_result {
11972 Ok(_) => self.last_formatting_failure = None,
11973 Err(error) => {
11974 let error_string = format!("{error:#}");
11975 log::error!("Formatting failed: {error_string}");
11976 self.last_formatting_failure
11977 .replace(error_string.lines().join(" "));
11978 }
11979 }
11980 }
11981
11982 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11983 self.lsp_server_capabilities.remove(&for_server);
11984 self.semantic_token_config.remove_server_data(for_server);
11985 for lsp_data in self.lsp_data.values_mut() {
11986 lsp_data.remove_server_data(for_server);
11987 }
11988 if let Some(local) = self.as_local_mut() {
11989 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11990 local
11991 .workspace_pull_diagnostics_result_ids
11992 .remove(&for_server);
11993 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11994 buffer_servers.remove(&for_server);
11995 }
11996 }
11997 }
11998
11999 pub fn result_id_for_buffer_pull(
12000 &self,
12001 server_id: LanguageServerId,
12002 buffer_id: BufferId,
12003 registration_id: &Option<SharedString>,
12004 cx: &App,
12005 ) -> Option<SharedString> {
12006 let abs_path = self
12007 .buffer_store
12008 .read(cx)
12009 .get(buffer_id)
12010 .and_then(|b| File::from_dyn(b.read(cx).file()))
12011 .map(|f| f.abs_path(cx))?;
12012 self.as_local()?
12013 .buffer_pull_diagnostics_result_ids
12014 .get(&server_id)?
12015 .get(registration_id)?
12016 .get(&abs_path)?
12017 .clone()
12018 }
12019
12020 /// Gets all result_ids for a workspace diagnostics pull request.
12021 /// 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.
12022 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12023 pub fn result_ids_for_workspace_refresh(
12024 &self,
12025 server_id: LanguageServerId,
12026 registration_id: &Option<SharedString>,
12027 ) -> HashMap<PathBuf, SharedString> {
12028 let Some(local) = self.as_local() else {
12029 return HashMap::default();
12030 };
12031 local
12032 .workspace_pull_diagnostics_result_ids
12033 .get(&server_id)
12034 .into_iter()
12035 .filter_map(|diagnostics| diagnostics.get(registration_id))
12036 .flatten()
12037 .filter_map(|(abs_path, result_id)| {
12038 let result_id = local
12039 .buffer_pull_diagnostics_result_ids
12040 .get(&server_id)
12041 .and_then(|buffer_ids_result_ids| {
12042 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12043 })
12044 .cloned()
12045 .flatten()
12046 .or_else(|| result_id.clone())?;
12047 Some((abs_path.clone(), result_id))
12048 })
12049 .collect()
12050 }
12051
12052 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12053 if let Some(LanguageServerState::Running {
12054 workspace_diagnostics_refresh_tasks,
12055 ..
12056 }) = self
12057 .as_local_mut()
12058 .and_then(|local| local.language_servers.get_mut(&server_id))
12059 {
12060 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12061 diagnostics.refresh_tx.try_send(()).ok();
12062 }
12063 }
12064 }
12065
12066 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12067 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12068 /// which requires refreshing both workspace and document diagnostics.
12069 pub fn pull_document_diagnostics_for_server(
12070 &mut self,
12071 server_id: LanguageServerId,
12072 source_buffer_id: Option<BufferId>,
12073 cx: &mut Context<Self>,
12074 ) -> Shared<Task<()>> {
12075 let Some(local) = self.as_local_mut() else {
12076 return Task::ready(()).shared();
12077 };
12078 let mut buffers_to_refresh = HashSet::default();
12079 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12080 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12081 buffers_to_refresh.insert(*buffer_id);
12082 }
12083 }
12084
12085 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12086 }
12087
12088 pub fn pull_document_diagnostics_for_buffer_edit(
12089 &mut self,
12090 buffer_id: BufferId,
12091 cx: &mut Context<Self>,
12092 ) {
12093 let Some(local) = self.as_local_mut() else {
12094 return;
12095 };
12096 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12097 else {
12098 return;
12099 };
12100 for server_id in languages_servers {
12101 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12102 }
12103 }
12104
12105 fn apply_workspace_diagnostic_report(
12106 &mut self,
12107 server_id: LanguageServerId,
12108 report: lsp::WorkspaceDiagnosticReportResult,
12109 registration_id: Option<SharedString>,
12110 cx: &mut Context<Self>,
12111 ) {
12112 let mut workspace_diagnostics =
12113 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12114 report,
12115 server_id,
12116 registration_id,
12117 );
12118 workspace_diagnostics.retain(|d| match &d.diagnostics {
12119 LspPullDiagnostics::Response {
12120 server_id,
12121 registration_id,
12122 ..
12123 } => self.diagnostic_registration_exists(*server_id, registration_id),
12124 LspPullDiagnostics::Default => false,
12125 });
12126 let mut unchanged_buffers = HashMap::default();
12127 let workspace_diagnostics_updates = workspace_diagnostics
12128 .into_iter()
12129 .filter_map(
12130 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12131 LspPullDiagnostics::Response {
12132 server_id,
12133 uri,
12134 diagnostics,
12135 registration_id,
12136 } => Some((
12137 server_id,
12138 uri,
12139 diagnostics,
12140 workspace_diagnostics.version,
12141 registration_id,
12142 )),
12143 LspPullDiagnostics::Default => None,
12144 },
12145 )
12146 .fold(
12147 HashMap::default(),
12148 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12149 let (result_id, diagnostics) = match diagnostics {
12150 PulledDiagnostics::Unchanged { result_id } => {
12151 unchanged_buffers
12152 .entry(new_registration_id.clone())
12153 .or_insert_with(HashSet::default)
12154 .insert(uri.clone());
12155 (Some(result_id), Vec::new())
12156 }
12157 PulledDiagnostics::Changed {
12158 result_id,
12159 diagnostics,
12160 } => (result_id, diagnostics),
12161 };
12162 let disk_based_sources = Cow::Owned(
12163 self.language_server_adapter_for_id(server_id)
12164 .as_ref()
12165 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12166 .unwrap_or(&[])
12167 .to_vec(),
12168 );
12169
12170 let Some(abs_path) = uri.to_file_path().ok() else {
12171 return acc;
12172 };
12173 let Some((worktree, relative_path)) =
12174 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12175 else {
12176 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12177 return acc;
12178 };
12179 let worktree_id = worktree.read(cx).id();
12180 let project_path = ProjectPath {
12181 worktree_id,
12182 path: relative_path,
12183 };
12184 if let Some(local_lsp_store) = self.as_local_mut() {
12185 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12186 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12187 }
12188 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12189 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12190 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12191 acc.entry(server_id)
12192 .or_insert_with(HashMap::default)
12193 .entry(new_registration_id.clone())
12194 .or_insert_with(Vec::new)
12195 .push(DocumentDiagnosticsUpdate {
12196 server_id,
12197 diagnostics: lsp::PublishDiagnosticsParams {
12198 uri,
12199 diagnostics,
12200 version,
12201 },
12202 result_id: result_id.map(SharedString::new),
12203 disk_based_sources,
12204 registration_id: new_registration_id,
12205 });
12206 }
12207 acc
12208 },
12209 );
12210
12211 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12212 for (registration_id, diagnostic_updates) in diagnostic_updates {
12213 self.merge_lsp_diagnostics(
12214 DiagnosticSourceKind::Pulled,
12215 diagnostic_updates,
12216 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12217 DiagnosticSourceKind::Pulled => {
12218 old_diagnostic.registration_id != registration_id
12219 || unchanged_buffers
12220 .get(&old_diagnostic.registration_id)
12221 .is_some_and(|unchanged_buffers| {
12222 unchanged_buffers.contains(&document_uri)
12223 })
12224 }
12225 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12226 },
12227 cx,
12228 )
12229 .log_err();
12230 }
12231 }
12232 }
12233
12234 fn register_server_capabilities(
12235 &mut self,
12236 server_id: LanguageServerId,
12237 params: lsp::RegistrationParams,
12238 cx: &mut Context<Self>,
12239 ) -> anyhow::Result<()> {
12240 let server = self
12241 .language_server_for_id(server_id)
12242 .with_context(|| format!("no server {server_id} found"))?;
12243 for reg in params.registrations {
12244 match reg.method.as_str() {
12245 "workspace/didChangeWatchedFiles" => {
12246 if let Some(options) = reg.register_options {
12247 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12248 let caps = serde_json::from_value(options)?;
12249 local_lsp_store
12250 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12251 true
12252 } else {
12253 false
12254 };
12255 if notify {
12256 notify_server_capabilities_updated(&server, cx);
12257 }
12258 }
12259 }
12260 "workspace/didChangeConfiguration" => {
12261 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12262 }
12263 "workspace/didChangeWorkspaceFolders" => {
12264 // In this case register options is an empty object, we can ignore it
12265 let caps = lsp::WorkspaceFoldersServerCapabilities {
12266 supported: Some(true),
12267 change_notifications: Some(OneOf::Right(reg.id)),
12268 };
12269 server.update_capabilities(|capabilities| {
12270 capabilities
12271 .workspace
12272 .get_or_insert_default()
12273 .workspace_folders = Some(caps);
12274 });
12275 notify_server_capabilities_updated(&server, cx);
12276 }
12277 "workspace/symbol" => {
12278 let options = parse_register_capabilities(reg)?;
12279 server.update_capabilities(|capabilities| {
12280 capabilities.workspace_symbol_provider = Some(options);
12281 });
12282 notify_server_capabilities_updated(&server, cx);
12283 }
12284 "workspace/fileOperations" => {
12285 if let Some(options) = reg.register_options {
12286 let caps = serde_json::from_value(options)?;
12287 server.update_capabilities(|capabilities| {
12288 capabilities
12289 .workspace
12290 .get_or_insert_default()
12291 .file_operations = Some(caps);
12292 });
12293 notify_server_capabilities_updated(&server, cx);
12294 }
12295 }
12296 "workspace/executeCommand" => {
12297 if let Some(options) = reg.register_options {
12298 let options = serde_json::from_value(options)?;
12299 server.update_capabilities(|capabilities| {
12300 capabilities.execute_command_provider = Some(options);
12301 });
12302 notify_server_capabilities_updated(&server, cx);
12303 }
12304 }
12305 "textDocument/rangeFormatting" => {
12306 let options = parse_register_capabilities(reg)?;
12307 server.update_capabilities(|capabilities| {
12308 capabilities.document_range_formatting_provider = Some(options);
12309 });
12310 notify_server_capabilities_updated(&server, cx);
12311 }
12312 "textDocument/onTypeFormatting" => {
12313 if let Some(options) = reg
12314 .register_options
12315 .map(serde_json::from_value)
12316 .transpose()?
12317 {
12318 server.update_capabilities(|capabilities| {
12319 capabilities.document_on_type_formatting_provider = Some(options);
12320 });
12321 notify_server_capabilities_updated(&server, cx);
12322 }
12323 }
12324 "textDocument/formatting" => {
12325 let options = parse_register_capabilities(reg)?;
12326 server.update_capabilities(|capabilities| {
12327 capabilities.document_formatting_provider = Some(options);
12328 });
12329 notify_server_capabilities_updated(&server, cx);
12330 }
12331 "textDocument/rename" => {
12332 let options = parse_register_capabilities(reg)?;
12333 server.update_capabilities(|capabilities| {
12334 capabilities.rename_provider = Some(options);
12335 });
12336 notify_server_capabilities_updated(&server, cx);
12337 }
12338 "textDocument/inlayHint" => {
12339 let options = parse_register_capabilities(reg)?;
12340 server.update_capabilities(|capabilities| {
12341 capabilities.inlay_hint_provider = Some(options);
12342 });
12343 notify_server_capabilities_updated(&server, cx);
12344 }
12345 "textDocument/documentSymbol" => {
12346 let options = parse_register_capabilities(reg)?;
12347 server.update_capabilities(|capabilities| {
12348 capabilities.document_symbol_provider = Some(options);
12349 });
12350 notify_server_capabilities_updated(&server, cx);
12351 }
12352 "textDocument/codeAction" => {
12353 let options = parse_register_capabilities(reg)?;
12354 let provider = match options {
12355 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12356 OneOf::Right(caps) => caps,
12357 };
12358 server.update_capabilities(|capabilities| {
12359 capabilities.code_action_provider = Some(provider);
12360 });
12361 notify_server_capabilities_updated(&server, cx);
12362 }
12363 "textDocument/definition" => {
12364 let options = parse_register_capabilities(reg)?;
12365 server.update_capabilities(|capabilities| {
12366 capabilities.definition_provider = Some(options);
12367 });
12368 notify_server_capabilities_updated(&server, cx);
12369 }
12370 "textDocument/completion" => {
12371 if let Some(caps) = reg
12372 .register_options
12373 .map(serde_json::from_value::<CompletionOptions>)
12374 .transpose()?
12375 {
12376 server.update_capabilities(|capabilities| {
12377 capabilities.completion_provider = Some(caps.clone());
12378 });
12379
12380 if let Some(local) = self.as_local() {
12381 let mut buffers_with_language_server = Vec::new();
12382 for handle in self.buffer_store.read(cx).buffers() {
12383 let buffer_id = handle.read(cx).remote_id();
12384 if local
12385 .buffers_opened_in_servers
12386 .get(&buffer_id)
12387 .filter(|s| s.contains(&server_id))
12388 .is_some()
12389 {
12390 buffers_with_language_server.push(handle);
12391 }
12392 }
12393 let triggers = caps
12394 .trigger_characters
12395 .unwrap_or_default()
12396 .into_iter()
12397 .collect::<BTreeSet<_>>();
12398 for handle in buffers_with_language_server {
12399 let triggers = triggers.clone();
12400 let _ = handle.update(cx, move |buffer, cx| {
12401 buffer.set_completion_triggers(server_id, triggers, cx);
12402 });
12403 }
12404 }
12405 notify_server_capabilities_updated(&server, cx);
12406 }
12407 }
12408 "textDocument/hover" => {
12409 let options = parse_register_capabilities(reg)?;
12410 let provider = match options {
12411 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12412 OneOf::Right(caps) => caps,
12413 };
12414 server.update_capabilities(|capabilities| {
12415 capabilities.hover_provider = Some(provider);
12416 });
12417 notify_server_capabilities_updated(&server, cx);
12418 }
12419 "textDocument/signatureHelp" => {
12420 if let Some(caps) = reg
12421 .register_options
12422 .map(serde_json::from_value)
12423 .transpose()?
12424 {
12425 server.update_capabilities(|capabilities| {
12426 capabilities.signature_help_provider = Some(caps);
12427 });
12428 notify_server_capabilities_updated(&server, cx);
12429 }
12430 }
12431 "textDocument/didChange" => {
12432 if let Some(sync_kind) = reg
12433 .register_options
12434 .and_then(|opts| opts.get("syncKind").cloned())
12435 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12436 .transpose()?
12437 {
12438 server.update_capabilities(|capabilities| {
12439 let mut sync_options =
12440 Self::take_text_document_sync_options(capabilities);
12441 sync_options.change = Some(sync_kind);
12442 capabilities.text_document_sync =
12443 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12444 });
12445 notify_server_capabilities_updated(&server, cx);
12446 }
12447 }
12448 "textDocument/didSave" => {
12449 if let Some(include_text) = reg
12450 .register_options
12451 .map(|opts| {
12452 let transpose = opts
12453 .get("includeText")
12454 .cloned()
12455 .map(serde_json::from_value::<Option<bool>>)
12456 .transpose();
12457 match transpose {
12458 Ok(value) => Ok(value.flatten()),
12459 Err(e) => Err(e),
12460 }
12461 })
12462 .transpose()?
12463 {
12464 server.update_capabilities(|capabilities| {
12465 let mut sync_options =
12466 Self::take_text_document_sync_options(capabilities);
12467 sync_options.save =
12468 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12469 include_text,
12470 }));
12471 capabilities.text_document_sync =
12472 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12473 });
12474 notify_server_capabilities_updated(&server, cx);
12475 }
12476 }
12477 "textDocument/codeLens" => {
12478 if let Some(caps) = reg
12479 .register_options
12480 .map(serde_json::from_value)
12481 .transpose()?
12482 {
12483 server.update_capabilities(|capabilities| {
12484 capabilities.code_lens_provider = Some(caps);
12485 });
12486 notify_server_capabilities_updated(&server, cx);
12487 }
12488 }
12489 "textDocument/diagnostic" => {
12490 if let Some(caps) = reg
12491 .register_options
12492 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12493 .transpose()?
12494 {
12495 let local = self
12496 .as_local_mut()
12497 .context("Expected LSP Store to be local")?;
12498 let state = local
12499 .language_servers
12500 .get_mut(&server_id)
12501 .context("Could not obtain Language Servers state")?;
12502 local
12503 .language_server_dynamic_registrations
12504 .entry(server_id)
12505 .or_default()
12506 .diagnostics
12507 .insert(Some(reg.id.clone()), caps.clone());
12508
12509 let supports_workspace_diagnostics =
12510 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12511 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12512 diagnostic_options.workspace_diagnostics
12513 }
12514 DiagnosticServerCapabilities::RegistrationOptions(
12515 diagnostic_registration_options,
12516 ) => {
12517 diagnostic_registration_options
12518 .diagnostic_options
12519 .workspace_diagnostics
12520 }
12521 };
12522
12523 if supports_workspace_diagnostics(&caps) {
12524 if let LanguageServerState::Running {
12525 workspace_diagnostics_refresh_tasks,
12526 ..
12527 } = state
12528 && let Some(task) = lsp_workspace_diagnostics_refresh(
12529 Some(reg.id.clone()),
12530 caps.clone(),
12531 server.clone(),
12532 cx,
12533 )
12534 {
12535 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12536 }
12537 }
12538
12539 server.update_capabilities(|capabilities| {
12540 capabilities.diagnostic_provider = Some(caps);
12541 });
12542
12543 notify_server_capabilities_updated(&server, cx);
12544
12545 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12546 }
12547 }
12548 "textDocument/documentColor" => {
12549 let options = parse_register_capabilities(reg)?;
12550 let provider = match options {
12551 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12552 OneOf::Right(caps) => caps,
12553 };
12554 server.update_capabilities(|capabilities| {
12555 capabilities.color_provider = Some(provider);
12556 });
12557 notify_server_capabilities_updated(&server, cx);
12558 }
12559 "textDocument/foldingRange" => {
12560 let options = parse_register_capabilities(reg)?;
12561 let provider = match options {
12562 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12563 OneOf::Right(caps) => caps,
12564 };
12565 server.update_capabilities(|capabilities| {
12566 capabilities.folding_range_provider = Some(provider);
12567 });
12568 notify_server_capabilities_updated(&server, cx);
12569 }
12570 _ => log::warn!("unhandled capability registration: {reg:?}"),
12571 }
12572 }
12573
12574 Ok(())
12575 }
12576
12577 fn unregister_server_capabilities(
12578 &mut self,
12579 server_id: LanguageServerId,
12580 params: lsp::UnregistrationParams,
12581 cx: &mut Context<Self>,
12582 ) -> anyhow::Result<()> {
12583 let server = self
12584 .language_server_for_id(server_id)
12585 .with_context(|| format!("no server {server_id} found"))?;
12586 for unreg in params.unregisterations.iter() {
12587 match unreg.method.as_str() {
12588 "workspace/didChangeWatchedFiles" => {
12589 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12590 local_lsp_store
12591 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12592 true
12593 } else {
12594 false
12595 };
12596 if notify {
12597 notify_server_capabilities_updated(&server, cx);
12598 }
12599 }
12600 "workspace/didChangeConfiguration" => {
12601 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12602 }
12603 "workspace/didChangeWorkspaceFolders" => {
12604 server.update_capabilities(|capabilities| {
12605 capabilities
12606 .workspace
12607 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12608 workspace_folders: None,
12609 file_operations: None,
12610 })
12611 .workspace_folders = None;
12612 });
12613 notify_server_capabilities_updated(&server, cx);
12614 }
12615 "workspace/symbol" => {
12616 server.update_capabilities(|capabilities| {
12617 capabilities.workspace_symbol_provider = None
12618 });
12619 notify_server_capabilities_updated(&server, cx);
12620 }
12621 "workspace/fileOperations" => {
12622 server.update_capabilities(|capabilities| {
12623 capabilities
12624 .workspace
12625 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12626 workspace_folders: None,
12627 file_operations: None,
12628 })
12629 .file_operations = None;
12630 });
12631 notify_server_capabilities_updated(&server, cx);
12632 }
12633 "workspace/executeCommand" => {
12634 server.update_capabilities(|capabilities| {
12635 capabilities.execute_command_provider = None;
12636 });
12637 notify_server_capabilities_updated(&server, cx);
12638 }
12639 "textDocument/rangeFormatting" => {
12640 server.update_capabilities(|capabilities| {
12641 capabilities.document_range_formatting_provider = None
12642 });
12643 notify_server_capabilities_updated(&server, cx);
12644 }
12645 "textDocument/onTypeFormatting" => {
12646 server.update_capabilities(|capabilities| {
12647 capabilities.document_on_type_formatting_provider = None;
12648 });
12649 notify_server_capabilities_updated(&server, cx);
12650 }
12651 "textDocument/formatting" => {
12652 server.update_capabilities(|capabilities| {
12653 capabilities.document_formatting_provider = None;
12654 });
12655 notify_server_capabilities_updated(&server, cx);
12656 }
12657 "textDocument/rename" => {
12658 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12659 notify_server_capabilities_updated(&server, cx);
12660 }
12661 "textDocument/codeAction" => {
12662 server.update_capabilities(|capabilities| {
12663 capabilities.code_action_provider = None;
12664 });
12665 notify_server_capabilities_updated(&server, cx);
12666 }
12667 "textDocument/definition" => {
12668 server.update_capabilities(|capabilities| {
12669 capabilities.definition_provider = None;
12670 });
12671 notify_server_capabilities_updated(&server, cx);
12672 }
12673 "textDocument/completion" => {
12674 server.update_capabilities(|capabilities| {
12675 capabilities.completion_provider = None;
12676 });
12677 notify_server_capabilities_updated(&server, cx);
12678 }
12679 "textDocument/hover" => {
12680 server.update_capabilities(|capabilities| {
12681 capabilities.hover_provider = None;
12682 });
12683 notify_server_capabilities_updated(&server, cx);
12684 }
12685 "textDocument/signatureHelp" => {
12686 server.update_capabilities(|capabilities| {
12687 capabilities.signature_help_provider = None;
12688 });
12689 notify_server_capabilities_updated(&server, cx);
12690 }
12691 "textDocument/didChange" => {
12692 server.update_capabilities(|capabilities| {
12693 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12694 sync_options.change = None;
12695 capabilities.text_document_sync =
12696 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12697 });
12698 notify_server_capabilities_updated(&server, cx);
12699 }
12700 "textDocument/didSave" => {
12701 server.update_capabilities(|capabilities| {
12702 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12703 sync_options.save = None;
12704 capabilities.text_document_sync =
12705 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12706 });
12707 notify_server_capabilities_updated(&server, cx);
12708 }
12709 "textDocument/codeLens" => {
12710 server.update_capabilities(|capabilities| {
12711 capabilities.code_lens_provider = None;
12712 });
12713 notify_server_capabilities_updated(&server, cx);
12714 }
12715 "textDocument/diagnostic" => {
12716 let local = self
12717 .as_local_mut()
12718 .context("Expected LSP Store to be local")?;
12719
12720 let state = local
12721 .language_servers
12722 .get_mut(&server_id)
12723 .context("Could not obtain Language Servers state")?;
12724 let registrations = local
12725 .language_server_dynamic_registrations
12726 .get_mut(&server_id)
12727 .with_context(|| {
12728 format!("Expected dynamic registration to exist for server {server_id}")
12729 })?;
12730 registrations.diagnostics
12731 .remove(&Some(unreg.id.clone()))
12732 .with_context(|| format!(
12733 "Attempted to unregister non-existent diagnostic registration with ID {}",
12734 unreg.id)
12735 )?;
12736 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12737
12738 if let LanguageServerState::Running {
12739 workspace_diagnostics_refresh_tasks,
12740 ..
12741 } = state
12742 {
12743 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12744 }
12745
12746 self.clear_unregistered_diagnostics(
12747 server_id,
12748 SharedString::from(unreg.id.clone()),
12749 cx,
12750 )?;
12751
12752 if removed_last_diagnostic_provider {
12753 server.update_capabilities(|capabilities| {
12754 debug_assert!(capabilities.diagnostic_provider.is_some());
12755 capabilities.diagnostic_provider = None;
12756 });
12757 }
12758
12759 notify_server_capabilities_updated(&server, cx);
12760 }
12761 "textDocument/documentColor" => {
12762 server.update_capabilities(|capabilities| {
12763 capabilities.color_provider = None;
12764 });
12765 notify_server_capabilities_updated(&server, cx);
12766 }
12767 "textDocument/foldingRange" => {
12768 server.update_capabilities(|capabilities| {
12769 capabilities.folding_range_provider = None;
12770 });
12771 notify_server_capabilities_updated(&server, cx);
12772 }
12773 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12774 }
12775 }
12776
12777 Ok(())
12778 }
12779
12780 fn clear_unregistered_diagnostics(
12781 &mut self,
12782 server_id: LanguageServerId,
12783 cleared_registration_id: SharedString,
12784 cx: &mut Context<Self>,
12785 ) -> anyhow::Result<()> {
12786 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12787
12788 self.buffer_store.update(cx, |buffer_store, cx| {
12789 for buffer_handle in buffer_store.buffers() {
12790 let buffer = buffer_handle.read(cx);
12791 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12792 let Some(abs_path) = abs_path else {
12793 continue;
12794 };
12795 affected_abs_paths.insert(abs_path);
12796 }
12797 });
12798
12799 let local = self.as_local().context("Expected LSP Store to be local")?;
12800 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12801 let Some(worktree) = self
12802 .worktree_store
12803 .read(cx)
12804 .worktree_for_id(*worktree_id, cx)
12805 else {
12806 continue;
12807 };
12808
12809 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12810 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12811 let has_matching_registration =
12812 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12813 entry.diagnostic.registration_id.as_ref()
12814 == Some(&cleared_registration_id)
12815 });
12816 if has_matching_registration {
12817 let abs_path = worktree.read(cx).absolutize(rel_path);
12818 affected_abs_paths.insert(abs_path);
12819 }
12820 }
12821 }
12822 }
12823
12824 if affected_abs_paths.is_empty() {
12825 return Ok(());
12826 }
12827
12828 // Send a fake diagnostic update which clears the state for the registration ID
12829 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12830 affected_abs_paths
12831 .into_iter()
12832 .map(|abs_path| DocumentDiagnosticsUpdate {
12833 diagnostics: DocumentDiagnostics {
12834 diagnostics: Vec::new(),
12835 document_abs_path: abs_path,
12836 version: None,
12837 },
12838 result_id: None,
12839 registration_id: Some(cleared_registration_id.clone()),
12840 server_id,
12841 disk_based_sources: Cow::Borrowed(&[]),
12842 })
12843 .collect();
12844
12845 let merge_registration_id = cleared_registration_id.clone();
12846 self.merge_diagnostic_entries(
12847 clears,
12848 move |_, diagnostic, _| {
12849 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12850 diagnostic.registration_id != Some(merge_registration_id.clone())
12851 } else {
12852 true
12853 }
12854 },
12855 cx,
12856 )?;
12857
12858 Ok(())
12859 }
12860
12861 async fn deduplicate_range_based_lsp_requests<T>(
12862 lsp_store: &Entity<Self>,
12863 server_id: Option<LanguageServerId>,
12864 lsp_request_id: LspRequestId,
12865 proto_request: &T::ProtoRequest,
12866 range: Range<Anchor>,
12867 cx: &mut AsyncApp,
12868 ) -> Result<()>
12869 where
12870 T: LspCommand,
12871 T::ProtoRequest: proto::LspRequestMessage,
12872 {
12873 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12874 let version = deserialize_version(proto_request.buffer_version());
12875 let buffer = lsp_store.update(cx, |this, cx| {
12876 this.buffer_store.read(cx).get_existing(buffer_id)
12877 })?;
12878 buffer
12879 .update(cx, |buffer, _| buffer.wait_for_version(version))
12880 .await?;
12881 lsp_store.update(cx, |lsp_store, cx| {
12882 let buffer_snapshot = buffer.read(cx).snapshot();
12883 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12884 let chunks_queried_for = lsp_data
12885 .inlay_hints
12886 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12887 .collect::<Vec<_>>();
12888 match chunks_queried_for.as_slice() {
12889 &[chunk] => {
12890 let key = LspKey {
12891 request_type: TypeId::of::<T>(),
12892 server_queried: server_id,
12893 };
12894 let previous_request = lsp_data
12895 .chunk_lsp_requests
12896 .entry(key)
12897 .or_default()
12898 .insert(chunk, lsp_request_id);
12899 if let Some((previous_request, running_requests)) =
12900 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12901 {
12902 running_requests.remove(&previous_request);
12903 }
12904 }
12905 _ambiguous_chunks => {
12906 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12907 // there, a buffer version-based check will be performed and outdated requests discarded.
12908 }
12909 }
12910 anyhow::Ok(())
12911 })?;
12912
12913 Ok(())
12914 }
12915
12916 async fn query_lsp_locally<T>(
12917 lsp_store: Entity<Self>,
12918 for_server_id: Option<LanguageServerId>,
12919 sender_id: proto::PeerId,
12920 lsp_request_id: LspRequestId,
12921 proto_request: T::ProtoRequest,
12922 position: Option<Anchor>,
12923 cx: &mut AsyncApp,
12924 ) -> Result<()>
12925 where
12926 T: LspCommand + Clone,
12927 T::ProtoRequest: proto::LspRequestMessage,
12928 <T::ProtoRequest as proto::RequestMessage>::Response:
12929 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12930 {
12931 let (buffer_version, buffer) =
12932 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12933 let request =
12934 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12935 let key = LspKey {
12936 request_type: TypeId::of::<T>(),
12937 server_queried: for_server_id,
12938 };
12939 lsp_store.update(cx, |lsp_store, cx| {
12940 let request_task = match for_server_id {
12941 Some(server_id) => {
12942 let server_task = lsp_store.request_lsp(
12943 buffer.clone(),
12944 LanguageServerToQuery::Other(server_id),
12945 request.clone(),
12946 cx,
12947 );
12948 cx.background_spawn(async move {
12949 let mut responses = Vec::new();
12950 match server_task.await {
12951 Ok(response) => responses.push((server_id, response)),
12952 // rust-analyzer likes to error with this when its still loading up
12953 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12954 Err(e) => log::error!(
12955 "Error handling response for request {request:?}: {e:#}"
12956 ),
12957 }
12958 responses
12959 })
12960 }
12961 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12962 };
12963 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12964 if T::ProtoRequest::stop_previous_requests() {
12965 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12966 lsp_requests.clear();
12967 }
12968 }
12969 lsp_data.lsp_requests.entry(key).or_default().insert(
12970 lsp_request_id,
12971 cx.spawn(async move |lsp_store, cx| {
12972 let response = request_task.await;
12973 lsp_store
12974 .update(cx, |lsp_store, cx| {
12975 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12976 {
12977 let response = response
12978 .into_iter()
12979 .map(|(server_id, response)| {
12980 (
12981 server_id.to_proto(),
12982 T::response_to_proto(
12983 response,
12984 lsp_store,
12985 sender_id,
12986 &buffer_version,
12987 cx,
12988 )
12989 .into(),
12990 )
12991 })
12992 .collect::<HashMap<_, _>>();
12993 match client.send_lsp_response::<T::ProtoRequest>(
12994 project_id,
12995 lsp_request_id,
12996 response,
12997 ) {
12998 Ok(()) => {}
12999 Err(e) => {
13000 log::error!("Failed to send LSP response: {e:#}",)
13001 }
13002 }
13003 }
13004 })
13005 .ok();
13006 }),
13007 );
13008 });
13009 Ok(())
13010 }
13011
13012 async fn wait_for_buffer_version<T>(
13013 lsp_store: &Entity<Self>,
13014 proto_request: &T::ProtoRequest,
13015 cx: &mut AsyncApp,
13016 ) -> Result<(Global, Entity<Buffer>)>
13017 where
13018 T: LspCommand,
13019 T::ProtoRequest: proto::LspRequestMessage,
13020 {
13021 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13022 let version = deserialize_version(proto_request.buffer_version());
13023 let buffer = lsp_store.update(cx, |this, cx| {
13024 this.buffer_store.read(cx).get_existing(buffer_id)
13025 })?;
13026 buffer
13027 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13028 .await?;
13029 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13030 Ok((buffer_version, buffer))
13031 }
13032
13033 fn take_text_document_sync_options(
13034 capabilities: &mut lsp::ServerCapabilities,
13035 ) -> lsp::TextDocumentSyncOptions {
13036 match capabilities.text_document_sync.take() {
13037 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13038 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13039 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13040 sync_options.change = Some(sync_kind);
13041 sync_options
13042 }
13043 None => lsp::TextDocumentSyncOptions::default(),
13044 }
13045 }
13046
13047 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13048 self.downstream_client.clone()
13049 }
13050
13051 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13052 self.worktree_store.clone()
13053 }
13054
13055 /// Gets what's stored in the LSP data for the given buffer.
13056 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13057 self.lsp_data.get_mut(&buffer_id)
13058 }
13059
13060 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13061 /// new [`BufferLspData`] will be created to replace the previous state.
13062 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13063 let (buffer_id, buffer_version) =
13064 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13065 let lsp_data = self
13066 .lsp_data
13067 .entry(buffer_id)
13068 .or_insert_with(|| BufferLspData::new(buffer, cx));
13069 if buffer_version.changed_since(&lsp_data.buffer_version) {
13070 // To send delta requests for semantic tokens, the previous tokens
13071 // need to be kept between buffer changes.
13072 let semantic_tokens = lsp_data.semantic_tokens.take();
13073 *lsp_data = BufferLspData::new(buffer, cx);
13074 lsp_data.semantic_tokens = semantic_tokens;
13075 }
13076 lsp_data
13077 }
13078}
13079
13080// Registration with registerOptions as null, should fallback to true.
13081// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13082fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13083 reg: lsp::Registration,
13084) -> Result<OneOf<bool, T>> {
13085 Ok(match reg.register_options {
13086 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13087 None => OneOf::Left(true),
13088 })
13089}
13090
13091fn subscribe_to_binary_statuses(
13092 languages: &Arc<LanguageRegistry>,
13093 cx: &mut Context<'_, LspStore>,
13094) -> Task<()> {
13095 let mut server_statuses = languages.language_server_binary_statuses();
13096 cx.spawn(async move |lsp_store, cx| {
13097 while let Some((server_name, binary_status)) = server_statuses.next().await {
13098 if lsp_store
13099 .update(cx, |_, cx| {
13100 let mut message = None;
13101 let binary_status = match binary_status {
13102 BinaryStatus::None => proto::ServerBinaryStatus::None,
13103 BinaryStatus::CheckingForUpdate => {
13104 proto::ServerBinaryStatus::CheckingForUpdate
13105 }
13106 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13107 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13108 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13109 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13110 BinaryStatus::Failed { error } => {
13111 message = Some(error);
13112 proto::ServerBinaryStatus::Failed
13113 }
13114 };
13115 cx.emit(LspStoreEvent::LanguageServerUpdate {
13116 // Binary updates are about the binary that might not have any language server id at that point.
13117 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13118 language_server_id: LanguageServerId(0),
13119 name: Some(server_name),
13120 message: proto::update_language_server::Variant::StatusUpdate(
13121 proto::StatusUpdate {
13122 message,
13123 status: Some(proto::status_update::Status::Binary(
13124 binary_status as i32,
13125 )),
13126 },
13127 ),
13128 });
13129 })
13130 .is_err()
13131 {
13132 break;
13133 }
13134 }
13135 })
13136}
13137
13138fn lsp_workspace_diagnostics_refresh(
13139 registration_id: Option<String>,
13140 options: DiagnosticServerCapabilities,
13141 server: Arc<LanguageServer>,
13142 cx: &mut Context<'_, LspStore>,
13143) -> Option<WorkspaceRefreshTask> {
13144 let identifier = workspace_diagnostic_identifier(&options)?;
13145 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13146
13147 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13148 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13149 refresh_tx.try_send(()).ok();
13150
13151 let request_timeout = ProjectSettings::get_global(cx)
13152 .global_lsp_settings
13153 .get_request_timeout();
13154
13155 // 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.
13156 // This allows users to increase the duration if need be
13157 let timeout = if request_timeout != Duration::ZERO {
13158 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13159 } else {
13160 request_timeout
13161 };
13162
13163 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13164 let mut attempts = 0;
13165 let max_attempts = 50;
13166 let mut requests = 0;
13167
13168 loop {
13169 let Some(()) = refresh_rx.recv().await else {
13170 return;
13171 };
13172
13173 'request: loop {
13174 requests += 1;
13175 if attempts > max_attempts {
13176 log::error!(
13177 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13178 );
13179 return;
13180 }
13181 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13182 cx.background_executor()
13183 .timer(Duration::from_millis(backoff_millis))
13184 .await;
13185 attempts += 1;
13186
13187 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13188 lsp_store
13189 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13190 .into_iter()
13191 .filter_map(|(abs_path, result_id)| {
13192 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13193 Some(lsp::PreviousResultId {
13194 uri,
13195 value: result_id.to_string(),
13196 })
13197 })
13198 .collect()
13199 }) else {
13200 return;
13201 };
13202
13203 let token = if let Some(registration_id) = ®istration_id {
13204 format!(
13205 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13206 server.server_id(),
13207 )
13208 } else {
13209 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13210 };
13211
13212 progress_rx.try_recv().ok();
13213 let timer = server.request_timer(timeout).fuse();
13214 let progress = pin!(progress_rx.recv().fuse());
13215 let response_result = server
13216 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13217 lsp::WorkspaceDiagnosticParams {
13218 previous_result_ids,
13219 identifier: identifier.clone(),
13220 work_done_progress_params: Default::default(),
13221 partial_result_params: lsp::PartialResultParams {
13222 partial_result_token: Some(lsp::ProgressToken::String(token)),
13223 },
13224 },
13225 select(timer, progress).then(|either| match either {
13226 Either::Left((message, ..)) => ready(message).left_future(),
13227 Either::Right(..) => pending::<String>().right_future(),
13228 }),
13229 )
13230 .await;
13231
13232 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13233 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13234 match response_result {
13235 ConnectionResult::Timeout => {
13236 log::error!("Timeout during workspace diagnostics pull");
13237 continue 'request;
13238 }
13239 ConnectionResult::ConnectionReset => {
13240 log::error!("Server closed a workspace diagnostics pull request");
13241 continue 'request;
13242 }
13243 ConnectionResult::Result(Err(e)) => {
13244 log::error!("Error during workspace diagnostics pull: {e:#}");
13245 break 'request;
13246 }
13247 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13248 attempts = 0;
13249 if lsp_store
13250 .update(cx, |lsp_store, cx| {
13251 lsp_store.apply_workspace_diagnostic_report(
13252 server.server_id(),
13253 pulled_diagnostics,
13254 registration_id_shared.clone(),
13255 cx,
13256 )
13257 })
13258 .is_err()
13259 {
13260 return;
13261 }
13262 break 'request;
13263 }
13264 }
13265 }
13266 }
13267 });
13268
13269 Some(WorkspaceRefreshTask {
13270 refresh_tx,
13271 progress_tx,
13272 task: workspace_query_language_server,
13273 })
13274}
13275
13276fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13277 match &options {
13278 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13279 .identifier
13280 .as_deref()
13281 .map(SharedString::new),
13282 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13283 let diagnostic_options = ®istration_options.diagnostic_options;
13284 diagnostic_options
13285 .identifier
13286 .as_deref()
13287 .map(SharedString::new)
13288 }
13289 }
13290}
13291
13292fn workspace_diagnostic_identifier(
13293 options: &DiagnosticServerCapabilities,
13294) -> Option<Option<String>> {
13295 match &options {
13296 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13297 if !diagnostic_options.workspace_diagnostics {
13298 return None;
13299 }
13300 Some(diagnostic_options.identifier.clone())
13301 }
13302 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13303 let diagnostic_options = ®istration_options.diagnostic_options;
13304 if !diagnostic_options.workspace_diagnostics {
13305 return None;
13306 }
13307 Some(diagnostic_options.identifier.clone())
13308 }
13309 }
13310}
13311
13312fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13313 let CompletionSource::BufferWord {
13314 word_range,
13315 resolved,
13316 } = &mut completion.source
13317 else {
13318 return;
13319 };
13320 if *resolved {
13321 return;
13322 }
13323
13324 if completion.new_text
13325 != snapshot
13326 .text_for_range(word_range.clone())
13327 .collect::<String>()
13328 {
13329 return;
13330 }
13331
13332 let mut offset = 0;
13333 for chunk in snapshot.chunks(word_range.clone(), true) {
13334 let end_offset = offset + chunk.text.len();
13335 if let Some(highlight_id) = chunk.syntax_highlight_id {
13336 completion
13337 .label
13338 .runs
13339 .push((offset..end_offset, highlight_id));
13340 }
13341 offset = end_offset;
13342 }
13343 *resolved = true;
13344}
13345
13346impl EventEmitter<LspStoreEvent> for LspStore {}
13347
13348fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13349 hover
13350 .contents
13351 .retain(|hover_block| !hover_block.text.trim().is_empty());
13352 if hover.contents.is_empty() {
13353 None
13354 } else {
13355 Some(hover)
13356 }
13357}
13358
13359async fn populate_labels_for_completions(
13360 new_completions: Vec<CoreCompletion>,
13361 language: Option<Arc<Language>>,
13362 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13363) -> Vec<Completion> {
13364 let lsp_completions = new_completions
13365 .iter()
13366 .filter_map(|new_completion| {
13367 new_completion
13368 .source
13369 .lsp_completion(true)
13370 .map(|lsp_completion| lsp_completion.into_owned())
13371 })
13372 .collect::<Vec<_>>();
13373
13374 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13375 lsp_adapter
13376 .labels_for_completions(&lsp_completions, language)
13377 .await
13378 .log_err()
13379 .unwrap_or_default()
13380 } else {
13381 Vec::new()
13382 }
13383 .into_iter()
13384 .fuse();
13385
13386 let mut completions = Vec::new();
13387 for completion in new_completions {
13388 match completion.source.lsp_completion(true) {
13389 Some(lsp_completion) => {
13390 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13391
13392 let mut label = labels.next().flatten().unwrap_or_else(|| {
13393 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13394 });
13395 ensure_uniform_list_compatible_label(&mut label);
13396 completions.push(Completion {
13397 label,
13398 documentation,
13399 replace_range: completion.replace_range,
13400 new_text: completion.new_text,
13401 insert_text_mode: lsp_completion.insert_text_mode,
13402 source: completion.source,
13403 icon_path: None,
13404 confirm: None,
13405 match_start: None,
13406 snippet_deduplication_key: None,
13407 });
13408 }
13409 None => {
13410 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13411 ensure_uniform_list_compatible_label(&mut label);
13412 completions.push(Completion {
13413 label,
13414 documentation: None,
13415 replace_range: completion.replace_range,
13416 new_text: completion.new_text,
13417 source: completion.source,
13418 insert_text_mode: None,
13419 icon_path: None,
13420 confirm: None,
13421 match_start: None,
13422 snippet_deduplication_key: None,
13423 });
13424 }
13425 }
13426 }
13427 completions
13428}
13429
13430#[derive(Debug)]
13431pub enum LanguageServerToQuery {
13432 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13433 FirstCapable,
13434 /// Query a specific language server.
13435 Other(LanguageServerId),
13436}
13437
13438#[derive(Default)]
13439struct RenamePathsWatchedForServer {
13440 did_rename: Vec<RenameActionPredicate>,
13441 will_rename: Vec<RenameActionPredicate>,
13442}
13443
13444impl RenamePathsWatchedForServer {
13445 fn with_did_rename_patterns(
13446 mut self,
13447 did_rename: Option<&FileOperationRegistrationOptions>,
13448 ) -> Self {
13449 if let Some(did_rename) = did_rename {
13450 self.did_rename = did_rename
13451 .filters
13452 .iter()
13453 .filter_map(|filter| filter.try_into().log_err())
13454 .collect();
13455 }
13456 self
13457 }
13458 fn with_will_rename_patterns(
13459 mut self,
13460 will_rename: Option<&FileOperationRegistrationOptions>,
13461 ) -> Self {
13462 if let Some(will_rename) = will_rename {
13463 self.will_rename = will_rename
13464 .filters
13465 .iter()
13466 .filter_map(|filter| filter.try_into().log_err())
13467 .collect();
13468 }
13469 self
13470 }
13471
13472 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13473 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13474 }
13475 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13476 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13477 }
13478}
13479
13480impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13481 type Error = globset::Error;
13482 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13483 Ok(Self {
13484 kind: ops.pattern.matches.clone(),
13485 glob: GlobBuilder::new(&ops.pattern.glob)
13486 .case_insensitive(
13487 ops.pattern
13488 .options
13489 .as_ref()
13490 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13491 )
13492 .build()?
13493 .compile_matcher(),
13494 })
13495 }
13496}
13497struct RenameActionPredicate {
13498 glob: GlobMatcher,
13499 kind: Option<FileOperationPatternKind>,
13500}
13501
13502impl RenameActionPredicate {
13503 // Returns true if language server should be notified
13504 fn eval(&self, path: &str, is_dir: bool) -> bool {
13505 self.kind.as_ref().is_none_or(|kind| {
13506 let expected_kind = if is_dir {
13507 FileOperationPatternKind::Folder
13508 } else {
13509 FileOperationPatternKind::File
13510 };
13511 kind == &expected_kind
13512 }) && self.glob.is_match(path)
13513 }
13514}
13515
13516#[derive(Default)]
13517struct LanguageServerWatchedPaths {
13518 worktree_paths: HashMap<WorktreeId, GlobSet>,
13519 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13520}
13521
13522#[derive(Default)]
13523struct LanguageServerWatchedPathsBuilder {
13524 worktree_paths: HashMap<WorktreeId, GlobSet>,
13525 abs_paths: HashMap<Arc<Path>, GlobSet>,
13526}
13527
13528impl LanguageServerWatchedPathsBuilder {
13529 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13530 self.worktree_paths.insert(worktree_id, glob_set);
13531 }
13532 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13533 self.abs_paths.insert(path, glob_set);
13534 }
13535 fn build(
13536 self,
13537 fs: Arc<dyn Fs>,
13538 language_server_id: LanguageServerId,
13539 cx: &mut Context<LspStore>,
13540 ) -> LanguageServerWatchedPaths {
13541 let lsp_store = cx.weak_entity();
13542
13543 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13544 let abs_paths = self
13545 .abs_paths
13546 .into_iter()
13547 .map(|(abs_path, globset)| {
13548 let task = cx.spawn({
13549 let abs_path = abs_path.clone();
13550 let fs = fs.clone();
13551
13552 let lsp_store = lsp_store.clone();
13553 async move |_, cx| {
13554 maybe!(async move {
13555 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13556 while let Some(update) = push_updates.0.next().await {
13557 let action = lsp_store
13558 .update(cx, |this, _| {
13559 let Some(local) = this.as_local() else {
13560 return ControlFlow::Break(());
13561 };
13562 let Some(watcher) = local
13563 .language_server_watched_paths
13564 .get(&language_server_id)
13565 else {
13566 return ControlFlow::Break(());
13567 };
13568 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13569 "Watched abs path is not registered with a watcher",
13570 );
13571 let matching_entries = update
13572 .into_iter()
13573 .filter(|event| globs.is_match(&event.path))
13574 .collect::<Vec<_>>();
13575 this.lsp_notify_abs_paths_changed(
13576 language_server_id,
13577 matching_entries,
13578 );
13579 ControlFlow::Continue(())
13580 })
13581 .ok()?;
13582
13583 if action.is_break() {
13584 break;
13585 }
13586 }
13587 Some(())
13588 })
13589 .await;
13590 }
13591 });
13592 (abs_path, (globset, task))
13593 })
13594 .collect();
13595 LanguageServerWatchedPaths {
13596 worktree_paths: self.worktree_paths,
13597 abs_paths,
13598 }
13599 }
13600}
13601
13602struct LspBufferSnapshot {
13603 version: i32,
13604 snapshot: TextBufferSnapshot,
13605}
13606
13607/// A prompt requested by LSP server.
13608#[derive(Clone, Debug)]
13609pub struct LanguageServerPromptRequest {
13610 pub id: usize,
13611 pub level: PromptLevel,
13612 pub message: String,
13613 pub actions: Vec<MessageActionItem>,
13614 pub lsp_name: String,
13615 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13616}
13617
13618impl LanguageServerPromptRequest {
13619 pub fn new(
13620 level: PromptLevel,
13621 message: String,
13622 actions: Vec<MessageActionItem>,
13623 lsp_name: String,
13624 response_channel: smol::channel::Sender<MessageActionItem>,
13625 ) -> Self {
13626 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13627 LanguageServerPromptRequest {
13628 id,
13629 level,
13630 message,
13631 actions,
13632 lsp_name,
13633 response_channel,
13634 }
13635 }
13636 pub async fn respond(self, index: usize) -> Option<()> {
13637 if let Some(response) = self.actions.into_iter().nth(index) {
13638 self.response_channel.send(response).await.ok()
13639 } else {
13640 None
13641 }
13642 }
13643
13644 #[cfg(any(test, feature = "test-support"))]
13645 pub fn test(
13646 level: PromptLevel,
13647 message: String,
13648 actions: Vec<MessageActionItem>,
13649 lsp_name: String,
13650 ) -> Self {
13651 let (tx, _rx) = smol::channel::unbounded();
13652 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13653 }
13654}
13655impl PartialEq for LanguageServerPromptRequest {
13656 fn eq(&self, other: &Self) -> bool {
13657 self.message == other.message && self.actions == other.actions
13658 }
13659}
13660
13661#[derive(Clone, Debug, PartialEq)]
13662pub enum LanguageServerLogType {
13663 Log(MessageType),
13664 Trace { verbose_info: Option<String> },
13665 Rpc { received: bool },
13666}
13667
13668impl LanguageServerLogType {
13669 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13670 match self {
13671 Self::Log(log_type) => {
13672 use proto::log_message::LogLevel;
13673 let level = match *log_type {
13674 MessageType::ERROR => LogLevel::Error,
13675 MessageType::WARNING => LogLevel::Warning,
13676 MessageType::INFO => LogLevel::Info,
13677 MessageType::LOG => LogLevel::Log,
13678 other => {
13679 log::warn!("Unknown lsp log message type: {other:?}");
13680 LogLevel::Log
13681 }
13682 };
13683 proto::language_server_log::LogType::Log(proto::LogMessage {
13684 level: level as i32,
13685 })
13686 }
13687 Self::Trace { verbose_info } => {
13688 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13689 verbose_info: verbose_info.to_owned(),
13690 })
13691 }
13692 Self::Rpc { received } => {
13693 let kind = if *received {
13694 proto::rpc_message::Kind::Received
13695 } else {
13696 proto::rpc_message::Kind::Sent
13697 };
13698 let kind = kind as i32;
13699 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13700 }
13701 }
13702 }
13703
13704 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13705 use proto::log_message::LogLevel;
13706 use proto::rpc_message;
13707 match log_type {
13708 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13709 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13710 LogLevel::Error => MessageType::ERROR,
13711 LogLevel::Warning => MessageType::WARNING,
13712 LogLevel::Info => MessageType::INFO,
13713 LogLevel::Log => MessageType::LOG,
13714 },
13715 ),
13716 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13717 verbose_info: trace_message.verbose_info,
13718 },
13719 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13720 received: match rpc_message::Kind::from_i32(message.kind)
13721 .unwrap_or(rpc_message::Kind::Received)
13722 {
13723 rpc_message::Kind::Received => true,
13724 rpc_message::Kind::Sent => false,
13725 },
13726 },
13727 }
13728 }
13729}
13730
13731pub struct WorkspaceRefreshTask {
13732 refresh_tx: mpsc::Sender<()>,
13733 progress_tx: mpsc::Sender<()>,
13734 #[allow(dead_code)]
13735 task: Task<()>,
13736}
13737
13738pub enum LanguageServerState {
13739 Starting {
13740 startup: Task<Option<Arc<LanguageServer>>>,
13741 /// List of language servers that will be added to the workspace once it's initialization completes.
13742 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13743 },
13744
13745 Running {
13746 adapter: Arc<CachedLspAdapter>,
13747 server: Arc<LanguageServer>,
13748 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13749 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13750 },
13751}
13752
13753impl LanguageServerState {
13754 fn add_workspace_folder(&self, uri: Uri) {
13755 match self {
13756 LanguageServerState::Starting {
13757 pending_workspace_folders,
13758 ..
13759 } => {
13760 pending_workspace_folders.lock().insert(uri);
13761 }
13762 LanguageServerState::Running { server, .. } => {
13763 server.add_workspace_folder(uri);
13764 }
13765 }
13766 }
13767 fn _remove_workspace_folder(&self, uri: Uri) {
13768 match self {
13769 LanguageServerState::Starting {
13770 pending_workspace_folders,
13771 ..
13772 } => {
13773 pending_workspace_folders.lock().remove(&uri);
13774 }
13775 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13776 }
13777 }
13778}
13779
13780impl std::fmt::Debug for LanguageServerState {
13781 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13782 match self {
13783 LanguageServerState::Starting { .. } => {
13784 f.debug_struct("LanguageServerState::Starting").finish()
13785 }
13786 LanguageServerState::Running { .. } => {
13787 f.debug_struct("LanguageServerState::Running").finish()
13788 }
13789 }
13790 }
13791}
13792
13793#[derive(Clone, Debug, Serialize)]
13794pub struct LanguageServerProgress {
13795 pub is_disk_based_diagnostics_progress: bool,
13796 pub is_cancellable: bool,
13797 pub title: Option<String>,
13798 pub message: Option<String>,
13799 pub percentage: Option<usize>,
13800 #[serde(skip_serializing)]
13801 pub last_update_at: Instant,
13802}
13803
13804#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13805pub struct DiagnosticSummary {
13806 pub error_count: usize,
13807 pub warning_count: usize,
13808}
13809
13810impl DiagnosticSummary {
13811 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13812 let mut this = Self {
13813 error_count: 0,
13814 warning_count: 0,
13815 };
13816
13817 for entry in diagnostics {
13818 if entry.diagnostic.is_primary {
13819 match entry.diagnostic.severity {
13820 DiagnosticSeverity::ERROR => this.error_count += 1,
13821 DiagnosticSeverity::WARNING => this.warning_count += 1,
13822 _ => {}
13823 }
13824 }
13825 }
13826
13827 this
13828 }
13829
13830 pub fn is_empty(&self) -> bool {
13831 self.error_count == 0 && self.warning_count == 0
13832 }
13833
13834 pub fn to_proto(
13835 self,
13836 language_server_id: LanguageServerId,
13837 path: &RelPath,
13838 ) -> proto::DiagnosticSummary {
13839 proto::DiagnosticSummary {
13840 path: path.to_proto(),
13841 language_server_id: language_server_id.0 as u64,
13842 error_count: self.error_count as u32,
13843 warning_count: self.warning_count as u32,
13844 }
13845 }
13846}
13847
13848#[derive(Clone, Debug)]
13849pub enum CompletionDocumentation {
13850 /// There is no documentation for this completion.
13851 Undocumented,
13852 /// A single line of documentation.
13853 SingleLine(SharedString),
13854 /// Multiple lines of plain text documentation.
13855 MultiLinePlainText(SharedString),
13856 /// Markdown documentation.
13857 MultiLineMarkdown(SharedString),
13858 /// Both single line and multiple lines of plain text documentation.
13859 SingleLineAndMultiLinePlainText {
13860 single_line: SharedString,
13861 plain_text: Option<SharedString>,
13862 },
13863}
13864
13865impl CompletionDocumentation {
13866 #[cfg(any(test, feature = "test-support"))]
13867 pub fn text(&self) -> SharedString {
13868 match self {
13869 CompletionDocumentation::Undocumented => "".into(),
13870 CompletionDocumentation::SingleLine(s) => s.clone(),
13871 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13872 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13873 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13874 single_line.clone()
13875 }
13876 }
13877 }
13878}
13879
13880impl From<lsp::Documentation> for CompletionDocumentation {
13881 fn from(docs: lsp::Documentation) -> Self {
13882 match docs {
13883 lsp::Documentation::String(text) => {
13884 if text.lines().count() <= 1 {
13885 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13886 } else {
13887 CompletionDocumentation::MultiLinePlainText(text.into())
13888 }
13889 }
13890
13891 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13892 lsp::MarkupKind::PlainText => {
13893 if value.lines().count() <= 1 {
13894 CompletionDocumentation::SingleLine(value.into())
13895 } else {
13896 CompletionDocumentation::MultiLinePlainText(value.into())
13897 }
13898 }
13899
13900 lsp::MarkupKind::Markdown => {
13901 CompletionDocumentation::MultiLineMarkdown(value.into())
13902 }
13903 },
13904 }
13905 }
13906}
13907
13908pub enum ResolvedHint {
13909 Resolved(InlayHint),
13910 Resolving(Shared<Task<()>>),
13911}
13912
13913pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13914 glob.components()
13915 .take_while(|component| match component {
13916 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13917 _ => true,
13918 })
13919 .collect()
13920}
13921
13922pub struct SshLspAdapter {
13923 name: LanguageServerName,
13924 binary: LanguageServerBinary,
13925 initialization_options: Option<String>,
13926 code_action_kinds: Option<Vec<CodeActionKind>>,
13927}
13928
13929impl SshLspAdapter {
13930 pub fn new(
13931 name: LanguageServerName,
13932 binary: LanguageServerBinary,
13933 initialization_options: Option<String>,
13934 code_action_kinds: Option<String>,
13935 ) -> Self {
13936 Self {
13937 name,
13938 binary,
13939 initialization_options,
13940 code_action_kinds: code_action_kinds
13941 .as_ref()
13942 .and_then(|c| serde_json::from_str(c).ok()),
13943 }
13944 }
13945}
13946
13947impl LspInstaller for SshLspAdapter {
13948 type BinaryVersion = ();
13949 async fn check_if_user_installed(
13950 &self,
13951 _: &dyn LspAdapterDelegate,
13952 _: Option<Toolchain>,
13953 _: &AsyncApp,
13954 ) -> Option<LanguageServerBinary> {
13955 Some(self.binary.clone())
13956 }
13957
13958 async fn cached_server_binary(
13959 &self,
13960 _: PathBuf,
13961 _: &dyn LspAdapterDelegate,
13962 ) -> Option<LanguageServerBinary> {
13963 None
13964 }
13965
13966 async fn fetch_latest_server_version(
13967 &self,
13968 _: &dyn LspAdapterDelegate,
13969 _: bool,
13970 _: &mut AsyncApp,
13971 ) -> Result<()> {
13972 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13973 }
13974
13975 async fn fetch_server_binary(
13976 &self,
13977 _: (),
13978 _: PathBuf,
13979 _: &dyn LspAdapterDelegate,
13980 ) -> Result<LanguageServerBinary> {
13981 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13982 }
13983}
13984
13985#[async_trait(?Send)]
13986impl LspAdapter for SshLspAdapter {
13987 fn name(&self) -> LanguageServerName {
13988 self.name.clone()
13989 }
13990
13991 async fn initialization_options(
13992 self: Arc<Self>,
13993 _: &Arc<dyn LspAdapterDelegate>,
13994 _: &mut AsyncApp,
13995 ) -> Result<Option<serde_json::Value>> {
13996 let Some(options) = &self.initialization_options else {
13997 return Ok(None);
13998 };
13999 let result = serde_json::from_str(options)?;
14000 Ok(result)
14001 }
14002
14003 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14004 self.code_action_kinds.clone()
14005 }
14006}
14007
14008pub fn language_server_settings<'a>(
14009 delegate: &'a dyn LspAdapterDelegate,
14010 language: &LanguageServerName,
14011 cx: &'a App,
14012) -> Option<&'a LspSettings> {
14013 language_server_settings_for(
14014 SettingsLocation {
14015 worktree_id: delegate.worktree_id(),
14016 path: RelPath::empty(),
14017 },
14018 language,
14019 cx,
14020 )
14021}
14022
14023pub fn language_server_settings_for<'a>(
14024 location: SettingsLocation<'a>,
14025 language: &LanguageServerName,
14026 cx: &'a App,
14027) -> Option<&'a LspSettings> {
14028 ProjectSettings::get(Some(location), cx).lsp.get(language)
14029}
14030
14031pub struct LocalLspAdapterDelegate {
14032 lsp_store: WeakEntity<LspStore>,
14033 worktree: worktree::Snapshot,
14034 fs: Arc<dyn Fs>,
14035 http_client: Arc<dyn HttpClient>,
14036 language_registry: Arc<LanguageRegistry>,
14037 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14038}
14039
14040impl LocalLspAdapterDelegate {
14041 pub fn new(
14042 language_registry: Arc<LanguageRegistry>,
14043 environment: &Entity<ProjectEnvironment>,
14044 lsp_store: WeakEntity<LspStore>,
14045 worktree: &Entity<Worktree>,
14046 http_client: Arc<dyn HttpClient>,
14047 fs: Arc<dyn Fs>,
14048 cx: &mut App,
14049 ) -> Arc<Self> {
14050 let load_shell_env_task =
14051 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14052
14053 Arc::new(Self {
14054 lsp_store,
14055 worktree: worktree.read(cx).snapshot(),
14056 fs,
14057 http_client,
14058 language_registry,
14059 load_shell_env_task,
14060 })
14061 }
14062
14063 pub fn from_local_lsp(
14064 local: &LocalLspStore,
14065 worktree: &Entity<Worktree>,
14066 cx: &mut App,
14067 ) -> Arc<Self> {
14068 Self::new(
14069 local.languages.clone(),
14070 &local.environment,
14071 local.weak.clone(),
14072 worktree,
14073 local.http_client.clone(),
14074 local.fs.clone(),
14075 cx,
14076 )
14077 }
14078}
14079
14080#[async_trait]
14081impl LspAdapterDelegate for LocalLspAdapterDelegate {
14082 fn show_notification(&self, message: &str, cx: &mut App) {
14083 self.lsp_store
14084 .update(cx, |_, cx| {
14085 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14086 })
14087 .ok();
14088 }
14089
14090 fn http_client(&self) -> Arc<dyn HttpClient> {
14091 self.http_client.clone()
14092 }
14093
14094 fn worktree_id(&self) -> WorktreeId {
14095 self.worktree.id()
14096 }
14097
14098 fn worktree_root_path(&self) -> &Path {
14099 self.worktree.abs_path().as_ref()
14100 }
14101
14102 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14103 self.worktree.resolve_relative_path(path)
14104 }
14105
14106 async fn shell_env(&self) -> HashMap<String, String> {
14107 let task = self.load_shell_env_task.clone();
14108 task.await.unwrap_or_default()
14109 }
14110
14111 async fn npm_package_installed_version(
14112 &self,
14113 package_name: &str,
14114 ) -> Result<Option<(PathBuf, Version)>> {
14115 let local_package_directory = self.worktree_root_path();
14116 let node_modules_directory = local_package_directory.join("node_modules");
14117
14118 if let Some(version) =
14119 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14120 {
14121 return Ok(Some((node_modules_directory, version)));
14122 }
14123 let Some(npm) = self.which("npm".as_ref()).await else {
14124 log::warn!(
14125 "Failed to find npm executable for {:?}",
14126 local_package_directory
14127 );
14128 return Ok(None);
14129 };
14130
14131 let env = self.shell_env().await;
14132 let output = util::command::new_command(&npm)
14133 .args(["root", "-g"])
14134 .envs(env)
14135 .current_dir(local_package_directory)
14136 .output()
14137 .await?;
14138 let global_node_modules =
14139 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14140
14141 if let Some(version) =
14142 read_package_installed_version(global_node_modules.clone(), package_name).await?
14143 {
14144 return Ok(Some((global_node_modules, version)));
14145 }
14146 return Ok(None);
14147 }
14148
14149 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14150 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14151 if self.fs.is_file(&worktree_abs_path).await {
14152 worktree_abs_path.pop();
14153 }
14154
14155 let env = self.shell_env().await;
14156
14157 let shell_path = env.get("PATH").cloned();
14158
14159 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14160 }
14161
14162 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14163 let mut working_dir = self.worktree_root_path().to_path_buf();
14164 if self.fs.is_file(&working_dir).await {
14165 working_dir.pop();
14166 }
14167 let output = util::command::new_command(&command.path)
14168 .args(command.arguments)
14169 .envs(command.env.clone().unwrap_or_default())
14170 .current_dir(working_dir)
14171 .output()
14172 .await?;
14173
14174 anyhow::ensure!(
14175 output.status.success(),
14176 "{}, stdout: {:?}, stderr: {:?}",
14177 output.status,
14178 String::from_utf8_lossy(&output.stdout),
14179 String::from_utf8_lossy(&output.stderr)
14180 );
14181 Ok(())
14182 }
14183
14184 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14185 self.language_registry
14186 .update_lsp_binary_status(server_name, status);
14187 }
14188
14189 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14190 self.language_registry
14191 .all_lsp_adapters()
14192 .into_iter()
14193 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14194 .collect()
14195 }
14196
14197 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14198 let dir = self.language_registry.language_server_download_dir(name)?;
14199
14200 if !dir.exists() {
14201 smol::fs::create_dir_all(&dir)
14202 .await
14203 .context("failed to create container directory")
14204 .log_err()?;
14205 }
14206
14207 Some(dir)
14208 }
14209
14210 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14211 let entry = self
14212 .worktree
14213 .entry_for_path(path)
14214 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14215 let abs_path = self.worktree.absolutize(&entry.path);
14216 self.fs.load(&abs_path).await
14217 }
14218}
14219
14220async fn populate_labels_for_symbols(
14221 symbols: Vec<CoreSymbol>,
14222 language_registry: &Arc<LanguageRegistry>,
14223 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14224 output: &mut Vec<Symbol>,
14225) {
14226 #[allow(clippy::mutable_key_type)]
14227 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14228
14229 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14230 for symbol in symbols {
14231 let Some(file_name) = symbol.path.file_name() else {
14232 continue;
14233 };
14234 let language = language_registry
14235 .load_language_for_file_path(Path::new(file_name))
14236 .await
14237 .ok()
14238 .or_else(|| {
14239 unknown_paths.insert(file_name.into());
14240 None
14241 });
14242 symbols_by_language
14243 .entry(language)
14244 .or_default()
14245 .push(symbol);
14246 }
14247
14248 for unknown_path in unknown_paths {
14249 log::info!("no language found for symbol in file {unknown_path:?}");
14250 }
14251
14252 let mut label_params = Vec::new();
14253 for (language, mut symbols) in symbols_by_language {
14254 label_params.clear();
14255 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14256 name: mem::take(&mut symbol.name),
14257 kind: symbol.kind,
14258 container_name: symbol.container_name.take(),
14259 }));
14260
14261 let mut labels = Vec::new();
14262 if let Some(language) = language {
14263 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14264 language_registry
14265 .lsp_adapters(&language.name())
14266 .first()
14267 .cloned()
14268 });
14269 if let Some(lsp_adapter) = lsp_adapter {
14270 labels = lsp_adapter
14271 .labels_for_symbols(&label_params, &language)
14272 .await
14273 .log_err()
14274 .unwrap_or_default();
14275 }
14276 }
14277
14278 for (
14279 (
14280 symbol,
14281 language::Symbol {
14282 name,
14283 container_name,
14284 ..
14285 },
14286 ),
14287 label,
14288 ) in symbols
14289 .into_iter()
14290 .zip(label_params.drain(..))
14291 .zip(labels.into_iter().chain(iter::repeat(None)))
14292 {
14293 output.push(Symbol {
14294 language_server_name: symbol.language_server_name,
14295 source_worktree_id: symbol.source_worktree_id,
14296 source_language_server_id: symbol.source_language_server_id,
14297 path: symbol.path,
14298 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14299 name,
14300 kind: symbol.kind,
14301 range: symbol.range,
14302 container_name,
14303 });
14304 }
14305 }
14306}
14307
14308pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14309 text.lines()
14310 .map(|line| line.trim())
14311 .filter(|line| !line.is_empty())
14312 .join(separator)
14313}
14314
14315fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14316 match server.capabilities().text_document_sync.as_ref()? {
14317 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14318 // Server wants didSave but didn't specify includeText.
14319 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14320 // Server doesn't want didSave at all.
14321 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14322 // Server provided SaveOptions.
14323 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14324 Some(save_options.include_text.unwrap_or(false))
14325 }
14326 },
14327 // We do not have any save info. Kind affects didChange only.
14328 lsp::TextDocumentSyncCapability::Kind(_) => None,
14329 }
14330}
14331
14332/// Completion items are displayed in a `UniformList`.
14333/// Usually, those items are single-line strings, but in LSP responses,
14334/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14335/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14336/// 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,
14337/// breaking the completions menu presentation.
14338///
14339/// 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.
14340pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14341 let mut new_text = String::with_capacity(label.text.len());
14342 let mut offset_map = vec![0; label.text.len() + 1];
14343 let mut last_char_was_space = false;
14344 let mut new_idx = 0;
14345 let chars = label.text.char_indices().fuse();
14346 let mut newlines_removed = false;
14347
14348 for (idx, c) in chars {
14349 offset_map[idx] = new_idx;
14350
14351 match c {
14352 '\n' if last_char_was_space => {
14353 newlines_removed = true;
14354 }
14355 '\t' | ' ' if last_char_was_space => {}
14356 '\n' if !last_char_was_space => {
14357 new_text.push(' ');
14358 new_idx += 1;
14359 last_char_was_space = true;
14360 newlines_removed = true;
14361 }
14362 ' ' | '\t' => {
14363 new_text.push(' ');
14364 new_idx += 1;
14365 last_char_was_space = true;
14366 }
14367 _ => {
14368 new_text.push(c);
14369 new_idx += c.len_utf8();
14370 last_char_was_space = false;
14371 }
14372 }
14373 }
14374 offset_map[label.text.len()] = new_idx;
14375
14376 // Only modify the label if newlines were removed.
14377 if !newlines_removed {
14378 return;
14379 }
14380
14381 let last_index = new_idx;
14382 let mut run_ranges_errors = Vec::new();
14383 label.runs.retain_mut(|(range, _)| {
14384 match offset_map.get(range.start) {
14385 Some(&start) => range.start = start,
14386 None => {
14387 run_ranges_errors.push(range.clone());
14388 return false;
14389 }
14390 }
14391
14392 match offset_map.get(range.end) {
14393 Some(&end) => range.end = end,
14394 None => {
14395 run_ranges_errors.push(range.clone());
14396 range.end = last_index;
14397 }
14398 }
14399 true
14400 });
14401 if !run_ranges_errors.is_empty() {
14402 log::error!(
14403 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14404 label.text
14405 );
14406 }
14407
14408 let mut wrong_filter_range = None;
14409 if label.filter_range == (0..label.text.len()) {
14410 label.filter_range = 0..new_text.len();
14411 } else {
14412 let mut original_filter_range = Some(label.filter_range.clone());
14413 match offset_map.get(label.filter_range.start) {
14414 Some(&start) => label.filter_range.start = start,
14415 None => {
14416 wrong_filter_range = original_filter_range.take();
14417 label.filter_range.start = last_index;
14418 }
14419 }
14420
14421 match offset_map.get(label.filter_range.end) {
14422 Some(&end) => label.filter_range.end = end,
14423 None => {
14424 wrong_filter_range = original_filter_range.take();
14425 label.filter_range.end = last_index;
14426 }
14427 }
14428 }
14429 if let Some(wrong_filter_range) = wrong_filter_range {
14430 log::error!(
14431 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14432 label.text
14433 );
14434 }
14435
14436 label.text = new_text;
14437}