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 )
552 .await?;
553
554 match (&mut initialization_options, override_options) {
555 (Some(initialization_options), Some(override_options)) => {
556 merge_json_value_into(override_options, initialization_options);
557 }
558 (None, override_options) => initialization_options = override_options,
559 _ => {}
560 }
561
562 let initialization_params = cx.update(|cx| {
563 let mut params = language_server.default_initialize_params(
564 pull_diagnostics,
565 augments_syntax_tokens,
566 cx,
567 );
568 params.initialization_options = initialization_options;
569 adapter.adapter.prepare_initialize_params(params, cx)
570 })?;
571
572 Self::setup_lsp_messages(
573 lsp_store.clone(),
574 &language_server,
575 delegate.clone(),
576 adapter.clone(),
577 );
578
579 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
580 settings: workspace_config,
581 };
582 let language_server = cx
583 .update(|cx| {
584 let request_timeout = ProjectSettings::get_global(cx)
585 .global_lsp_settings
586 .get_request_timeout();
587
588 language_server.initialize(
589 initialization_params,
590 Arc::new(did_change_configuration_params.clone()),
591 request_timeout,
592 cx,
593 )
594 })
595 .await
596 .inspect_err(|_| {
597 if let Some(lsp_store) = lsp_store.upgrade() {
598 lsp_store.update(cx, |lsp_store, cx| {
599 lsp_store.cleanup_lsp_data(server_id);
600 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
601 });
602 }
603 })?;
604
605 language_server.notify::<lsp::notification::DidChangeConfiguration>(
606 did_change_configuration_params,
607 )?;
608
609 anyhow::Ok(language_server)
610 }
611 .await;
612
613 match result {
614 Ok(server) => {
615 lsp_store
616 .update(cx, |lsp_store, cx| {
617 lsp_store.insert_newly_running_language_server(
618 adapter,
619 server.clone(),
620 server_id,
621 key,
622 pending_workspace_folders,
623 cx,
624 );
625 })
626 .ok();
627 stderr_capture.lock().take();
628 Some(server)
629 }
630
631 Err(err) => {
632 let log = stderr_capture.lock().take().unwrap_or_default();
633 delegate.update_status(
634 adapter.name(),
635 BinaryStatus::Failed {
636 error: if log.is_empty() {
637 format!("{err:#}")
638 } else {
639 format!("{err:#}\n-- stderr --\n{log}")
640 },
641 },
642 );
643 log::error!(
644 "Failed to start language server {server_name:?}: {}",
645 redact_command(&format!("{err:?}"))
646 );
647 if !log.is_empty() {
648 log::error!("server stderr: {}", redact_command(&log));
649 }
650 None
651 }
652 }
653 })
654 };
655 let state = LanguageServerState::Starting {
656 startup,
657 pending_workspace_folders,
658 };
659
660 if update_binary_status {
661 self.languages
662 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
663 }
664
665 self.language_servers.insert(server_id, state);
666 self.language_server_ids
667 .entry(key)
668 .or_insert(UnifiedLanguageServer {
669 id: server_id,
670 project_roots: Default::default(),
671 });
672 server_id
673 }
674
675 fn get_language_server_binary(
676 &self,
677 worktree_abs_path: Arc<Path>,
678 adapter: Arc<CachedLspAdapter>,
679 settings: Arc<LspSettings>,
680 toolchain: Option<Toolchain>,
681 delegate: Arc<dyn LspAdapterDelegate>,
682 allow_binary_download: bool,
683 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
684 cx: &mut App,
685 ) -> Task<Result<LanguageServerBinary>> {
686 if let Some(settings) = &settings.binary
687 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
688 {
689 let settings = settings.clone();
690 let languages = self.languages.clone();
691 return cx.background_spawn(async move {
692 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
693 let already_trusted = *wait_until_worktree_trust.borrow();
694 if !already_trusted {
695 log::info!(
696 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
697 adapter.name(),
698 );
699 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
700 if worktree_trusted {
701 break;
702 }
703 }
704 log::info!(
705 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
706 adapter.name(),
707 );
708 }
709 languages
710 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
711 }
712 let mut env = delegate.shell_env().await;
713 env.extend(settings.env.unwrap_or_default());
714
715 Ok(LanguageServerBinary {
716 path: delegate.resolve_relative_path(path),
717 env: Some(env),
718 arguments: settings
719 .arguments
720 .unwrap_or_default()
721 .iter()
722 .map(Into::into)
723 .collect(),
724 })
725 });
726 }
727 let lsp_binary_options = LanguageServerBinaryOptions {
728 allow_path_lookup: !settings
729 .binary
730 .as_ref()
731 .and_then(|b| b.ignore_system_version)
732 .unwrap_or_default(),
733 allow_binary_download,
734 pre_release: settings
735 .fetch
736 .as_ref()
737 .and_then(|f| f.pre_release)
738 .unwrap_or(false),
739 };
740
741 cx.spawn(async move |cx| {
742 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
743 let already_trusted = *wait_until_worktree_trust.borrow();
744 if !already_trusted {
745 log::info!(
746 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
747 adapter.name(),
748 );
749 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
750 if worktree_trusted {
751 break;
752 }
753 }
754 log::info!(
755 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
756 adapter.name(),
757 );
758 }
759 }
760
761 let (existing_binary, maybe_download_binary) = adapter
762 .clone()
763 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
764 .await
765 .await;
766
767 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
768
769 let mut binary = match (existing_binary, maybe_download_binary) {
770 (binary, None) => binary?,
771 (Err(_), Some(downloader)) => downloader.await?,
772 (Ok(existing_binary), Some(downloader)) => {
773 let mut download_timeout = cx
774 .background_executor()
775 .timer(SERVER_DOWNLOAD_TIMEOUT)
776 .fuse();
777 let mut downloader = downloader.fuse();
778 futures::select! {
779 _ = download_timeout => {
780 // Return existing binary and kick the existing work to the background.
781 cx.spawn(async move |_| downloader.await).detach();
782 Ok(existing_binary)
783 },
784 downloaded_or_existing_binary = downloader => {
785 // If download fails, this results in the existing binary.
786 downloaded_or_existing_binary
787 }
788 }?
789 }
790 };
791 let mut shell_env = delegate.shell_env().await;
792
793 shell_env.extend(binary.env.unwrap_or_default());
794
795 if let Some(settings) = settings.binary.as_ref() {
796 if let Some(arguments) = &settings.arguments {
797 binary.arguments = arguments.iter().map(Into::into).collect();
798 }
799 if let Some(env) = &settings.env {
800 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
801 }
802 }
803
804 binary.env = Some(shell_env);
805 Ok(binary)
806 })
807 }
808
809 fn setup_lsp_messages(
810 lsp_store: WeakEntity<LspStore>,
811 language_server: &LanguageServer,
812 delegate: Arc<dyn LspAdapterDelegate>,
813 adapter: Arc<CachedLspAdapter>,
814 ) {
815 let name = language_server.name();
816 let server_id = language_server.server_id();
817 language_server
818 .on_notification::<lsp::notification::PublishDiagnostics, _>({
819 let adapter = adapter.clone();
820 let this = lsp_store.clone();
821 move |mut params, cx| {
822 let adapter = adapter.clone();
823 if let Some(this) = this.upgrade() {
824 this.update(cx, |this, cx| {
825 {
826 let buffer = params
827 .uri
828 .to_file_path()
829 .map(|file_path| this.get_buffer(&file_path, cx))
830 .ok()
831 .flatten();
832 adapter.process_diagnostics(&mut params, server_id, buffer);
833 }
834
835 this.merge_lsp_diagnostics(
836 DiagnosticSourceKind::Pushed,
837 vec![DocumentDiagnosticsUpdate {
838 server_id,
839 diagnostics: params,
840 result_id: None,
841 disk_based_sources: Cow::Borrowed(
842 &adapter.disk_based_diagnostic_sources,
843 ),
844 registration_id: None,
845 }],
846 |_, diagnostic, cx| match diagnostic.source_kind {
847 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
848 adapter.retain_old_diagnostic(diagnostic, cx)
849 }
850 DiagnosticSourceKind::Pulled => true,
851 },
852 cx,
853 )
854 .log_err();
855 });
856 }
857 }
858 })
859 .detach();
860 language_server
861 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
862 let adapter = adapter.adapter.clone();
863 let delegate = delegate.clone();
864 let this = lsp_store.clone();
865 move |params, cx| {
866 let adapter = adapter.clone();
867 let delegate = delegate.clone();
868 let this = this.clone();
869 let mut cx = cx.clone();
870 async move {
871 let toolchain_for_id = this
872 .update(&mut cx, |this, _| {
873 this.as_local()?.language_server_ids.iter().find_map(
874 |(seed, value)| {
875 (value.id == server_id).then(|| seed.toolchain.clone())
876 },
877 )
878 })?
879 .context("Expected the LSP store to be in a local mode")?;
880
881 let mut scope_uri_to_workspace_config = BTreeMap::new();
882 for item in ¶ms.items {
883 let scope_uri = item.scope_uri.clone();
884 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
885 scope_uri_to_workspace_config.entry(scope_uri.clone())
886 else {
887 // We've already queried workspace configuration of this URI.
888 continue;
889 };
890 let workspace_config = Self::workspace_configuration_for_adapter(
891 adapter.clone(),
892 &delegate,
893 toolchain_for_id.clone(),
894 scope_uri,
895 &mut cx,
896 )
897 .await?;
898 new_scope_uri.insert(workspace_config);
899 }
900
901 Ok(params
902 .items
903 .into_iter()
904 .filter_map(|item| {
905 let workspace_config =
906 scope_uri_to_workspace_config.get(&item.scope_uri)?;
907 if let Some(section) = &item.section {
908 Some(
909 workspace_config
910 .get(section)
911 .cloned()
912 .unwrap_or(serde_json::Value::Null),
913 )
914 } else {
915 Some(workspace_config.clone())
916 }
917 })
918 .collect())
919 }
920 }
921 })
922 .detach();
923
924 language_server
925 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
926 let this = lsp_store.clone();
927 move |_, cx| {
928 let this = this.clone();
929 let cx = cx.clone();
930 async move {
931 let Some(server) =
932 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
933 else {
934 return Ok(None);
935 };
936 let root = server.workspace_folders();
937 Ok(Some(
938 root.into_iter()
939 .map(|uri| WorkspaceFolder {
940 uri,
941 name: Default::default(),
942 })
943 .collect(),
944 ))
945 }
946 }
947 })
948 .detach();
949 // Even though we don't have handling for these requests, respond to them to
950 // avoid stalling any language server like `gopls` which waits for a response
951 // to these requests when initializing.
952 language_server
953 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
954 let this = lsp_store.clone();
955 move |params, cx| {
956 let this = this.clone();
957 let mut cx = cx.clone();
958 async move {
959 this.update(&mut cx, |this, _| {
960 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
961 {
962 status
963 .progress_tokens
964 .insert(ProgressToken::from_lsp(params.token));
965 }
966 })?;
967
968 Ok(())
969 }
970 }
971 })
972 .detach();
973
974 language_server
975 .on_request::<lsp::request::RegisterCapability, _, _>({
976 let lsp_store = lsp_store.clone();
977 move |params, cx| {
978 let lsp_store = lsp_store.clone();
979 let mut cx = cx.clone();
980 async move {
981 lsp_store
982 .update(&mut cx, |lsp_store, cx| {
983 if lsp_store.as_local().is_some() {
984 match lsp_store
985 .register_server_capabilities(server_id, params, cx)
986 {
987 Ok(()) => {}
988 Err(e) => {
989 log::error!(
990 "Failed to register server capabilities: {e:#}"
991 );
992 }
993 };
994 }
995 })
996 .ok();
997 Ok(())
998 }
999 }
1000 })
1001 .detach();
1002
1003 language_server
1004 .on_request::<lsp::request::UnregisterCapability, _, _>({
1005 let lsp_store = lsp_store.clone();
1006 move |params, cx| {
1007 let lsp_store = lsp_store.clone();
1008 let mut cx = cx.clone();
1009 async move {
1010 lsp_store
1011 .update(&mut cx, |lsp_store, cx| {
1012 if lsp_store.as_local().is_some() {
1013 match lsp_store
1014 .unregister_server_capabilities(server_id, params, cx)
1015 {
1016 Ok(()) => {}
1017 Err(e) => {
1018 log::error!(
1019 "Failed to unregister server capabilities: {e:#}"
1020 );
1021 }
1022 }
1023 }
1024 })
1025 .ok();
1026 Ok(())
1027 }
1028 }
1029 })
1030 .detach();
1031
1032 language_server
1033 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1034 let this = lsp_store.clone();
1035 move |params, cx| {
1036 let mut cx = cx.clone();
1037 let this = this.clone();
1038 async move {
1039 LocalLspStore::on_lsp_workspace_edit(
1040 this.clone(),
1041 params,
1042 server_id,
1043 &mut cx,
1044 )
1045 .await
1046 }
1047 }
1048 })
1049 .detach();
1050
1051 language_server
1052 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1053 let lsp_store = lsp_store.clone();
1054 let request_id = Arc::new(AtomicUsize::new(0));
1055 move |(), cx| {
1056 let lsp_store = lsp_store.clone();
1057 let request_id = request_id.clone();
1058 let mut cx = cx.clone();
1059 async move {
1060 lsp_store
1061 .update(&mut cx, |lsp_store, cx| {
1062 let request_id =
1063 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1064 cx.emit(LspStoreEvent::RefreshInlayHints {
1065 server_id,
1066 request_id,
1067 });
1068 lsp_store
1069 .downstream_client
1070 .as_ref()
1071 .map(|(client, project_id)| {
1072 client.send(proto::RefreshInlayHints {
1073 project_id: *project_id,
1074 server_id: server_id.to_proto(),
1075 request_id: request_id.map(|id| id as u64),
1076 })
1077 })
1078 })?
1079 .transpose()?;
1080 Ok(())
1081 }
1082 }
1083 })
1084 .detach();
1085
1086 language_server
1087 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1088 let this = lsp_store.clone();
1089 move |(), cx| {
1090 let this = this.clone();
1091 let mut cx = cx.clone();
1092 async move {
1093 this.update(&mut cx, |this, cx| {
1094 cx.emit(LspStoreEvent::RefreshCodeLens);
1095 this.downstream_client.as_ref().map(|(client, project_id)| {
1096 client.send(proto::RefreshCodeLens {
1097 project_id: *project_id,
1098 })
1099 })
1100 })?
1101 .transpose()?;
1102 Ok(())
1103 }
1104 }
1105 })
1106 .detach();
1107
1108 language_server
1109 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1110 let lsp_store = lsp_store.clone();
1111 let request_id = Arc::new(AtomicUsize::new(0));
1112 move |(), cx| {
1113 let lsp_store = lsp_store.clone();
1114 let request_id = request_id.clone();
1115 let mut cx = cx.clone();
1116 async move {
1117 lsp_store
1118 .update(&mut cx, |lsp_store, cx| {
1119 let request_id =
1120 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1121 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1122 server_id,
1123 request_id,
1124 });
1125 lsp_store
1126 .downstream_client
1127 .as_ref()
1128 .map(|(client, project_id)| {
1129 client.send(proto::RefreshSemanticTokens {
1130 project_id: *project_id,
1131 server_id: server_id.to_proto(),
1132 request_id: request_id.map(|id| id as u64),
1133 })
1134 })
1135 })?
1136 .transpose()?;
1137 Ok(())
1138 }
1139 }
1140 })
1141 .detach();
1142
1143 language_server
1144 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1145 let this = lsp_store.clone();
1146 move |(), cx| {
1147 let this = this.clone();
1148 let mut cx = cx.clone();
1149 async move {
1150 this.update(&mut cx, |lsp_store, cx| {
1151 lsp_store.pull_workspace_diagnostics(server_id);
1152 lsp_store
1153 .downstream_client
1154 .as_ref()
1155 .map(|(client, project_id)| {
1156 client.send(proto::PullWorkspaceDiagnostics {
1157 project_id: *project_id,
1158 server_id: server_id.to_proto(),
1159 })
1160 })
1161 .transpose()?;
1162 anyhow::Ok(
1163 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1164 )
1165 })??
1166 .await;
1167 Ok(())
1168 }
1169 }
1170 })
1171 .detach();
1172
1173 language_server
1174 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1175 let this = lsp_store.clone();
1176 let name = name.to_string();
1177 let adapter = adapter.clone();
1178 move |params, cx| {
1179 let this = this.clone();
1180 let name = name.to_string();
1181 let adapter = adapter.clone();
1182 let mut cx = cx.clone();
1183 async move {
1184 let actions = params.actions.unwrap_or_default();
1185 let message = params.message.clone();
1186 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1187 let level = match params.typ {
1188 lsp::MessageType::ERROR => PromptLevel::Critical,
1189 lsp::MessageType::WARNING => PromptLevel::Warning,
1190 _ => PromptLevel::Info,
1191 };
1192 let request = LanguageServerPromptRequest::new(
1193 level,
1194 params.message,
1195 actions,
1196 name.clone(),
1197 tx,
1198 );
1199
1200 let did_update = this
1201 .update(&mut cx, |_, cx| {
1202 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1203 })
1204 .is_ok();
1205 if did_update {
1206 let response = rx.recv().await.ok();
1207 if let Some(ref selected_action) = response {
1208 let context = language::PromptResponseContext {
1209 message,
1210 selected_action: selected_action.clone(),
1211 };
1212 adapter.process_prompt_response(&context, &mut cx)
1213 }
1214
1215 Ok(response)
1216 } else {
1217 Ok(None)
1218 }
1219 }
1220 }
1221 })
1222 .detach();
1223 language_server
1224 .on_notification::<lsp::notification::ShowMessage, _>({
1225 let this = lsp_store.clone();
1226 let name = name.to_string();
1227 move |params, cx| {
1228 let this = this.clone();
1229 let name = name.to_string();
1230 let mut cx = cx.clone();
1231
1232 let (tx, _) = smol::channel::bounded(1);
1233 let level = match params.typ {
1234 lsp::MessageType::ERROR => PromptLevel::Critical,
1235 lsp::MessageType::WARNING => PromptLevel::Warning,
1236 _ => PromptLevel::Info,
1237 };
1238 let request =
1239 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1240
1241 let _ = this.update(&mut cx, |_, cx| {
1242 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1243 });
1244 }
1245 })
1246 .detach();
1247
1248 let disk_based_diagnostics_progress_token =
1249 adapter.disk_based_diagnostics_progress_token.clone();
1250
1251 language_server
1252 .on_notification::<lsp::notification::Progress, _>({
1253 let this = lsp_store.clone();
1254 move |params, cx| {
1255 if let Some(this) = this.upgrade() {
1256 this.update(cx, |this, cx| {
1257 this.on_lsp_progress(
1258 params,
1259 server_id,
1260 disk_based_diagnostics_progress_token.clone(),
1261 cx,
1262 );
1263 });
1264 }
1265 }
1266 })
1267 .detach();
1268
1269 language_server
1270 .on_notification::<lsp::notification::LogMessage, _>({
1271 let this = lsp_store.clone();
1272 move |params, cx| {
1273 if let Some(this) = this.upgrade() {
1274 this.update(cx, |_, cx| {
1275 cx.emit(LspStoreEvent::LanguageServerLog(
1276 server_id,
1277 LanguageServerLogType::Log(params.typ),
1278 params.message,
1279 ));
1280 });
1281 }
1282 }
1283 })
1284 .detach();
1285
1286 language_server
1287 .on_notification::<lsp::notification::LogTrace, _>({
1288 let this = lsp_store.clone();
1289 move |params, cx| {
1290 let mut cx = cx.clone();
1291 if let Some(this) = this.upgrade() {
1292 this.update(&mut cx, |_, cx| {
1293 cx.emit(LspStoreEvent::LanguageServerLog(
1294 server_id,
1295 LanguageServerLogType::Trace {
1296 verbose_info: params.verbose,
1297 },
1298 params.message,
1299 ));
1300 });
1301 }
1302 }
1303 })
1304 .detach();
1305
1306 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1307 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1309 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1310 }
1311
1312 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1313 let shutdown_futures = self
1314 .language_servers
1315 .drain()
1316 .map(|(_, server_state)| Self::shutdown_server(server_state))
1317 .collect::<Vec<_>>();
1318
1319 async move {
1320 join_all(shutdown_futures).await;
1321 }
1322 }
1323
1324 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1325 match server_state {
1326 LanguageServerState::Running { server, .. } => {
1327 if let Some(shutdown) = server.shutdown() {
1328 shutdown.await;
1329 }
1330 }
1331 LanguageServerState::Starting { startup, .. } => {
1332 if let Some(server) = startup.await
1333 && let Some(shutdown) = server.shutdown()
1334 {
1335 shutdown.await;
1336 }
1337 }
1338 }
1339 Ok(())
1340 }
1341
1342 fn language_servers_for_worktree(
1343 &self,
1344 worktree_id: WorktreeId,
1345 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1346 self.language_server_ids
1347 .iter()
1348 .filter_map(move |(seed, state)| {
1349 if seed.worktree_id != worktree_id {
1350 return None;
1351 }
1352
1353 if let Some(LanguageServerState::Running { server, .. }) =
1354 self.language_servers.get(&state.id)
1355 {
1356 Some(server)
1357 } else {
1358 None
1359 }
1360 })
1361 }
1362
1363 fn language_server_ids_for_project_path(
1364 &self,
1365 project_path: ProjectPath,
1366 language: &Language,
1367 cx: &mut App,
1368 ) -> Vec<LanguageServerId> {
1369 let Some(worktree) = self
1370 .worktree_store
1371 .read(cx)
1372 .worktree_for_id(project_path.worktree_id, cx)
1373 else {
1374 return Vec::new();
1375 };
1376 let delegate: Arc<dyn ManifestDelegate> =
1377 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1378
1379 self.lsp_tree
1380 .get(
1381 project_path,
1382 language.name(),
1383 language.manifest(),
1384 &delegate,
1385 cx,
1386 )
1387 .collect::<Vec<_>>()
1388 }
1389
1390 fn language_server_ids_for_buffer(
1391 &self,
1392 buffer: &Buffer,
1393 cx: &mut App,
1394 ) -> Vec<LanguageServerId> {
1395 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1396 let worktree_id = file.worktree_id(cx);
1397
1398 let path: Arc<RelPath> = file
1399 .path()
1400 .parent()
1401 .map(Arc::from)
1402 .unwrap_or_else(|| file.path().clone());
1403 let worktree_path = ProjectPath { worktree_id, path };
1404 self.language_server_ids_for_project_path(worktree_path, language, cx)
1405 } else {
1406 Vec::new()
1407 }
1408 }
1409
1410 fn language_servers_for_buffer<'a>(
1411 &'a self,
1412 buffer: &'a Buffer,
1413 cx: &'a mut App,
1414 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1415 self.language_server_ids_for_buffer(buffer, cx)
1416 .into_iter()
1417 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1418 LanguageServerState::Running {
1419 adapter, server, ..
1420 } => Some((adapter, server)),
1421 _ => None,
1422 })
1423 }
1424
1425 async fn execute_code_action_kind_locally(
1426 lsp_store: WeakEntity<LspStore>,
1427 mut buffers: Vec<Entity<Buffer>>,
1428 kind: CodeActionKind,
1429 push_to_history: bool,
1430 cx: &mut AsyncApp,
1431 ) -> anyhow::Result<ProjectTransaction> {
1432 // Do not allow multiple concurrent code actions requests for the
1433 // same buffer.
1434 lsp_store.update(cx, |this, cx| {
1435 let this = this.as_local_mut().unwrap();
1436 buffers.retain(|buffer| {
1437 this.buffers_being_formatted
1438 .insert(buffer.read(cx).remote_id())
1439 });
1440 })?;
1441 let _cleanup = defer({
1442 let this = lsp_store.clone();
1443 let mut cx = cx.clone();
1444 let buffers = &buffers;
1445 move || {
1446 this.update(&mut cx, |this, cx| {
1447 let this = this.as_local_mut().unwrap();
1448 for buffer in buffers {
1449 this.buffers_being_formatted
1450 .remove(&buffer.read(cx).remote_id());
1451 }
1452 })
1453 .ok();
1454 }
1455 });
1456 let mut project_transaction = ProjectTransaction::default();
1457
1458 for buffer in &buffers {
1459 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1460 buffer.update(cx, |buffer, cx| {
1461 lsp_store
1462 .as_local()
1463 .unwrap()
1464 .language_servers_for_buffer(buffer, cx)
1465 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1466 .collect::<Vec<_>>()
1467 })
1468 })?;
1469 for (_, language_server) in adapters_and_servers.iter() {
1470 let actions = Self::get_server_code_actions_from_action_kinds(
1471 &lsp_store,
1472 language_server.server_id(),
1473 vec![kind.clone()],
1474 buffer,
1475 cx,
1476 )
1477 .await?;
1478 Self::execute_code_actions_on_server(
1479 &lsp_store,
1480 language_server,
1481 actions,
1482 push_to_history,
1483 &mut project_transaction,
1484 cx,
1485 )
1486 .await?;
1487 }
1488 }
1489 Ok(project_transaction)
1490 }
1491
1492 async fn format_locally(
1493 lsp_store: WeakEntity<LspStore>,
1494 mut buffers: Vec<FormattableBuffer>,
1495 push_to_history: bool,
1496 trigger: FormatTrigger,
1497 logger: zlog::Logger,
1498 cx: &mut AsyncApp,
1499 ) -> anyhow::Result<ProjectTransaction> {
1500 // Do not allow multiple concurrent formatting requests for the
1501 // same buffer.
1502 lsp_store.update(cx, |this, cx| {
1503 let this = this.as_local_mut().unwrap();
1504 buffers.retain(|buffer| {
1505 this.buffers_being_formatted
1506 .insert(buffer.handle.read(cx).remote_id())
1507 });
1508 })?;
1509
1510 let _cleanup = defer({
1511 let this = lsp_store.clone();
1512 let mut cx = cx.clone();
1513 let buffers = &buffers;
1514 move || {
1515 this.update(&mut cx, |this, cx| {
1516 let this = this.as_local_mut().unwrap();
1517 for buffer in buffers {
1518 this.buffers_being_formatted
1519 .remove(&buffer.handle.read(cx).remote_id());
1520 }
1521 })
1522 .ok();
1523 }
1524 });
1525
1526 let mut project_transaction = ProjectTransaction::default();
1527
1528 for buffer in &buffers {
1529 zlog::debug!(
1530 logger =>
1531 "formatting buffer '{:?}'",
1532 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1533 );
1534 // Create an empty transaction to hold all of the formatting edits.
1535 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1536 // ensure no transactions created while formatting are
1537 // grouped with the previous transaction in the history
1538 // based on the transaction group interval
1539 buffer.finalize_last_transaction();
1540 buffer
1541 .start_transaction()
1542 .context("transaction already open")?;
1543 buffer.end_transaction(cx);
1544 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1545 buffer.finalize_last_transaction();
1546 anyhow::Ok(transaction_id)
1547 })?;
1548
1549 let result = Self::format_buffer_locally(
1550 lsp_store.clone(),
1551 buffer,
1552 formatting_transaction_id,
1553 trigger,
1554 logger,
1555 cx,
1556 )
1557 .await;
1558
1559 buffer.handle.update(cx, |buffer, cx| {
1560 let Some(formatting_transaction) =
1561 buffer.get_transaction(formatting_transaction_id).cloned()
1562 else {
1563 zlog::warn!(logger => "no formatting transaction");
1564 return;
1565 };
1566 if formatting_transaction.edit_ids.is_empty() {
1567 zlog::debug!(logger => "no changes made while formatting");
1568 buffer.forget_transaction(formatting_transaction_id);
1569 return;
1570 }
1571 if !push_to_history {
1572 zlog::trace!(logger => "forgetting format transaction");
1573 buffer.forget_transaction(formatting_transaction.id);
1574 }
1575 project_transaction
1576 .0
1577 .insert(cx.entity(), formatting_transaction);
1578 });
1579
1580 result?;
1581 }
1582
1583 Ok(project_transaction)
1584 }
1585
1586 async fn format_buffer_locally(
1587 lsp_store: WeakEntity<LspStore>,
1588 buffer: &FormattableBuffer,
1589 formatting_transaction_id: clock::Lamport,
1590 trigger: FormatTrigger,
1591 logger: zlog::Logger,
1592 cx: &mut AsyncApp,
1593 ) -> Result<()> {
1594 let (adapters_and_servers, settings, request_timeout) =
1595 lsp_store.update(cx, |lsp_store, cx| {
1596 buffer.handle.update(cx, |buffer, cx| {
1597 let adapters_and_servers = lsp_store
1598 .as_local()
1599 .unwrap()
1600 .language_servers_for_buffer(buffer, cx)
1601 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1602 .collect::<Vec<_>>();
1603 let settings =
1604 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1605 .into_owned();
1606 let request_timeout = ProjectSettings::get_global(cx)
1607 .global_lsp_settings
1608 .get_request_timeout();
1609 (adapters_and_servers, settings, request_timeout)
1610 })
1611 })?;
1612
1613 /// Apply edits to the buffer that will become part of the formatting transaction.
1614 /// Fails if the buffer has been edited since the start of that transaction.
1615 fn extend_formatting_transaction(
1616 buffer: &FormattableBuffer,
1617 formatting_transaction_id: text::TransactionId,
1618 cx: &mut AsyncApp,
1619 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1620 ) -> anyhow::Result<()> {
1621 buffer.handle.update(cx, |buffer, cx| {
1622 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1623 if last_transaction_id != Some(formatting_transaction_id) {
1624 anyhow::bail!("Buffer edited while formatting. Aborting")
1625 }
1626 buffer.start_transaction();
1627 operation(buffer, cx);
1628 if let Some(transaction_id) = buffer.end_transaction(cx) {
1629 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1630 }
1631 Ok(())
1632 })
1633 }
1634
1635 // handle whitespace formatting
1636 if settings.remove_trailing_whitespace_on_save {
1637 zlog::trace!(logger => "removing trailing whitespace");
1638 let diff = buffer
1639 .handle
1640 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1641 .await;
1642 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1643 buffer.apply_diff(diff, cx);
1644 })?;
1645 }
1646
1647 if settings.ensure_final_newline_on_save {
1648 zlog::trace!(logger => "ensuring final newline");
1649 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1650 buffer.ensure_final_newline(cx);
1651 })?;
1652 }
1653
1654 // Formatter for `code_actions_on_format` that runs before
1655 // the rest of the formatters
1656 let mut code_actions_on_format_formatters = None;
1657 let should_run_code_actions_on_format = !matches!(
1658 (trigger, &settings.format_on_save),
1659 (FormatTrigger::Save, &FormatOnSave::Off)
1660 );
1661 if should_run_code_actions_on_format {
1662 let have_code_actions_to_run_on_format = settings
1663 .code_actions_on_format
1664 .values()
1665 .any(|enabled| *enabled);
1666 if have_code_actions_to_run_on_format {
1667 zlog::trace!(logger => "going to run code actions on format");
1668 code_actions_on_format_formatters = Some(
1669 settings
1670 .code_actions_on_format
1671 .iter()
1672 .filter_map(|(action, enabled)| enabled.then_some(action))
1673 .cloned()
1674 .map(Formatter::CodeAction)
1675 .collect::<Vec<_>>(),
1676 );
1677 }
1678 }
1679
1680 let formatters = match (trigger, &settings.format_on_save) {
1681 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1682 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1683 settings.formatter.as_ref()
1684 }
1685 };
1686
1687 let formatters = code_actions_on_format_formatters
1688 .iter()
1689 .flatten()
1690 .chain(formatters);
1691
1692 for formatter in formatters {
1693 let formatter = if formatter == &Formatter::Auto {
1694 if settings.prettier.allowed {
1695 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1696 &Formatter::Prettier
1697 } else {
1698 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1699 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1700 }
1701 } else {
1702 formatter
1703 };
1704 match formatter {
1705 Formatter::Auto => unreachable!("Auto resolved above"),
1706 Formatter::Prettier => {
1707 let logger = zlog::scoped!(logger => "prettier");
1708 zlog::trace!(logger => "formatting");
1709 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1710
1711 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1712 lsp_store.prettier_store().unwrap().downgrade()
1713 })?;
1714 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1715 .await
1716 .transpose()?;
1717 let Some(diff) = diff else {
1718 zlog::trace!(logger => "No changes");
1719 continue;
1720 };
1721
1722 extend_formatting_transaction(
1723 buffer,
1724 formatting_transaction_id,
1725 cx,
1726 |buffer, cx| {
1727 buffer.apply_diff(diff, cx);
1728 },
1729 )?;
1730 }
1731 Formatter::External { command, arguments } => {
1732 let logger = zlog::scoped!(logger => "command");
1733 zlog::trace!(logger => "formatting");
1734 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1735
1736 let diff = Self::format_via_external_command(
1737 buffer,
1738 &command,
1739 arguments.as_deref(),
1740 cx,
1741 )
1742 .await
1743 .with_context(|| {
1744 format!("Failed to format buffer via external command: {}", command)
1745 })?;
1746 let Some(diff) = diff else {
1747 zlog::trace!(logger => "No changes");
1748 continue;
1749 };
1750
1751 extend_formatting_transaction(
1752 buffer,
1753 formatting_transaction_id,
1754 cx,
1755 |buffer, cx| {
1756 buffer.apply_diff(diff, cx);
1757 },
1758 )?;
1759 }
1760 Formatter::LanguageServer(specifier) => {
1761 let logger = zlog::scoped!(logger => "language-server");
1762 zlog::trace!(logger => "formatting");
1763 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1764
1765 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1766 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1767 continue;
1768 };
1769
1770 let language_server = match specifier {
1771 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1772 adapters_and_servers.iter().find_map(|(adapter, server)| {
1773 if adapter.name.0.as_ref() == name {
1774 Some(server.clone())
1775 } else {
1776 None
1777 }
1778 })
1779 }
1780 settings::LanguageServerFormatterSpecifier::Current => {
1781 adapters_and_servers.first().map(|e| e.1.clone())
1782 }
1783 };
1784
1785 let Some(language_server) = language_server else {
1786 log::debug!(
1787 "No language server found to format buffer '{:?}'. Skipping",
1788 buffer_path_abs.as_path().to_string_lossy()
1789 );
1790 continue;
1791 };
1792
1793 zlog::trace!(
1794 logger =>
1795 "Formatting buffer '{:?}' using language server '{:?}'",
1796 buffer_path_abs.as_path().to_string_lossy(),
1797 language_server.name()
1798 );
1799
1800 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1801 zlog::trace!(logger => "formatting ranges");
1802 Self::format_ranges_via_lsp(
1803 &lsp_store,
1804 &buffer.handle,
1805 ranges,
1806 buffer_path_abs,
1807 &language_server,
1808 &settings,
1809 cx,
1810 )
1811 .await
1812 .context("Failed to format ranges via language server")?
1813 } else {
1814 zlog::trace!(logger => "formatting full");
1815 Self::format_via_lsp(
1816 &lsp_store,
1817 &buffer.handle,
1818 buffer_path_abs,
1819 &language_server,
1820 &settings,
1821 cx,
1822 )
1823 .await
1824 .context("failed to format via language server")?
1825 };
1826
1827 if edits.is_empty() {
1828 zlog::trace!(logger => "No changes");
1829 continue;
1830 }
1831 extend_formatting_transaction(
1832 buffer,
1833 formatting_transaction_id,
1834 cx,
1835 |buffer, cx| {
1836 buffer.edit(edits, None, cx);
1837 },
1838 )?;
1839 }
1840 Formatter::CodeAction(code_action_name) => {
1841 let logger = zlog::scoped!(logger => "code-actions");
1842 zlog::trace!(logger => "formatting");
1843 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1844
1845 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1846 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1847 continue;
1848 };
1849
1850 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1851 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1852
1853 let mut actions_and_servers = Vec::new();
1854
1855 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1856 let actions_result = Self::get_server_code_actions_from_action_kinds(
1857 &lsp_store,
1858 language_server.server_id(),
1859 vec![code_action_kind.clone()],
1860 &buffer.handle,
1861 cx,
1862 )
1863 .await
1864 .with_context(|| {
1865 format!(
1866 "Failed to resolve code action {:?} with language server {}",
1867 code_action_kind,
1868 language_server.name()
1869 )
1870 });
1871 let Ok(actions) = actions_result else {
1872 // note: it may be better to set result to the error and break formatters here
1873 // but for now we try to execute the actions that we can resolve and skip the rest
1874 zlog::error!(
1875 logger =>
1876 "Failed to resolve code action {:?} with language server {}",
1877 code_action_kind,
1878 language_server.name()
1879 );
1880 continue;
1881 };
1882 for action in actions {
1883 actions_and_servers.push((action, index));
1884 }
1885 }
1886
1887 if actions_and_servers.is_empty() {
1888 zlog::warn!(logger => "No code actions were resolved, continuing");
1889 continue;
1890 }
1891
1892 'actions: for (mut action, server_index) in actions_and_servers {
1893 let server = &adapters_and_servers[server_index].1;
1894
1895 let describe_code_action = |action: &CodeAction| {
1896 format!(
1897 "code action '{}' with title \"{}\" on server {}",
1898 action
1899 .lsp_action
1900 .action_kind()
1901 .unwrap_or("unknown".into())
1902 .as_str(),
1903 action.lsp_action.title(),
1904 server.name(),
1905 )
1906 };
1907
1908 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1909
1910 if let Err(err) =
1911 Self::try_resolve_code_action(server, &mut action, request_timeout)
1912 .await
1913 {
1914 zlog::error!(
1915 logger =>
1916 "Failed to resolve {}. Error: {}",
1917 describe_code_action(&action),
1918 err
1919 );
1920 continue;
1921 }
1922
1923 if let Some(edit) = action.lsp_action.edit().cloned() {
1924 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1925 // but filters out and logs warnings for code actions that require unreasonably
1926 // difficult handling on our part, such as:
1927 // - applying edits that call commands
1928 // which can result in arbitrary workspace edits being sent from the server that
1929 // have no way of being tied back to the command that initiated them (i.e. we
1930 // can't know which edits are part of the format request, or if the server is done sending
1931 // actions in response to the command)
1932 // - actions that create/delete/modify/rename files other than the one we are formatting
1933 // as we then would need to handle such changes correctly in the local history as well
1934 // as the remote history through the ProjectTransaction
1935 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1936 // Supporting these actions is not impossible, but not supported as of yet.
1937 if edit.changes.is_none() && edit.document_changes.is_none() {
1938 zlog::trace!(
1939 logger =>
1940 "No changes for code action. Skipping {}",
1941 describe_code_action(&action),
1942 );
1943 continue;
1944 }
1945
1946 let mut operations = Vec::new();
1947 if let Some(document_changes) = edit.document_changes {
1948 match document_changes {
1949 lsp::DocumentChanges::Edits(edits) => operations.extend(
1950 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1951 ),
1952 lsp::DocumentChanges::Operations(ops) => operations = ops,
1953 }
1954 } else if let Some(changes) = edit.changes {
1955 operations.extend(changes.into_iter().map(|(uri, edits)| {
1956 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1957 text_document:
1958 lsp::OptionalVersionedTextDocumentIdentifier {
1959 uri,
1960 version: None,
1961 },
1962 edits: edits.into_iter().map(Edit::Plain).collect(),
1963 })
1964 }));
1965 }
1966
1967 let mut edits = Vec::with_capacity(operations.len());
1968
1969 if operations.is_empty() {
1970 zlog::trace!(
1971 logger =>
1972 "No changes for code action. Skipping {}",
1973 describe_code_action(&action),
1974 );
1975 continue;
1976 }
1977 for operation in operations {
1978 let op = match operation {
1979 lsp::DocumentChangeOperation::Edit(op) => op,
1980 lsp::DocumentChangeOperation::Op(_) => {
1981 zlog::warn!(
1982 logger =>
1983 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1984 describe_code_action(&action),
1985 );
1986 continue 'actions;
1987 }
1988 };
1989 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1990 zlog::warn!(
1991 logger =>
1992 "Failed to convert URI '{:?}' to file path. Skipping {}",
1993 &op.text_document.uri,
1994 describe_code_action(&action),
1995 );
1996 continue 'actions;
1997 };
1998 if &file_path != buffer_path_abs {
1999 zlog::warn!(
2000 logger =>
2001 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2002 file_path,
2003 buffer_path_abs,
2004 describe_code_action(&action),
2005 );
2006 continue 'actions;
2007 }
2008
2009 let mut lsp_edits = Vec::new();
2010 for edit in op.edits {
2011 match edit {
2012 Edit::Plain(edit) => {
2013 if !lsp_edits.contains(&edit) {
2014 lsp_edits.push(edit);
2015 }
2016 }
2017 Edit::Annotated(edit) => {
2018 if !lsp_edits.contains(&edit.text_edit) {
2019 lsp_edits.push(edit.text_edit);
2020 }
2021 }
2022 Edit::Snippet(_) => {
2023 zlog::warn!(
2024 logger =>
2025 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2026 describe_code_action(&action),
2027 );
2028 continue 'actions;
2029 }
2030 }
2031 }
2032 let edits_result = lsp_store
2033 .update(cx, |lsp_store, cx| {
2034 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2035 &buffer.handle,
2036 lsp_edits,
2037 server.server_id(),
2038 op.text_document.version,
2039 cx,
2040 )
2041 })?
2042 .await;
2043 let Ok(resolved_edits) = edits_result else {
2044 zlog::warn!(
2045 logger =>
2046 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2047 buffer_path_abs.as_path(),
2048 describe_code_action(&action),
2049 );
2050 continue 'actions;
2051 };
2052 edits.extend(resolved_edits);
2053 }
2054
2055 if edits.is_empty() {
2056 zlog::warn!(logger => "No edits resolved from LSP");
2057 continue;
2058 }
2059
2060 extend_formatting_transaction(
2061 buffer,
2062 formatting_transaction_id,
2063 cx,
2064 |buffer, cx| {
2065 zlog::info!(
2066 "Applying edits {edits:?}. Content: {:?}",
2067 buffer.text()
2068 );
2069 buffer.edit(edits, None, cx);
2070 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2071 },
2072 )?;
2073 }
2074
2075 // bail early if command is invalid
2076 let Some(command) = action.lsp_action.command() else {
2077 continue;
2078 };
2079
2080 zlog::warn!(
2081 logger =>
2082 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2083 &command.command,
2084 );
2085
2086 let server_capabilities = server.capabilities();
2087 let available_commands = server_capabilities
2088 .execute_command_provider
2089 .as_ref()
2090 .map(|options| options.commands.as_slice())
2091 .unwrap_or_default();
2092 if !available_commands.contains(&command.command) {
2093 zlog::warn!(
2094 logger =>
2095 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2096 command.command,
2097 server.name(),
2098 );
2099 continue;
2100 }
2101
2102 // noop so we just ensure buffer hasn't been edited since resolving code actions
2103 extend_formatting_transaction(
2104 buffer,
2105 formatting_transaction_id,
2106 cx,
2107 |_, _| {},
2108 )?;
2109 zlog::info!(logger => "Executing command {}", &command.command);
2110
2111 lsp_store.update(cx, |this, _| {
2112 this.as_local_mut()
2113 .unwrap()
2114 .last_workspace_edits_by_language_server
2115 .remove(&server.server_id());
2116 })?;
2117
2118 let execute_command_result = server
2119 .request::<lsp::request::ExecuteCommand>(
2120 lsp::ExecuteCommandParams {
2121 command: command.command.clone(),
2122 arguments: command.arguments.clone().unwrap_or_default(),
2123 ..Default::default()
2124 },
2125 request_timeout,
2126 )
2127 .await
2128 .into_response();
2129
2130 if execute_command_result.is_err() {
2131 zlog::error!(
2132 logger =>
2133 "Failed to execute command '{}' as part of {}",
2134 &command.command,
2135 describe_code_action(&action),
2136 );
2137 continue 'actions;
2138 }
2139
2140 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2141 this.as_local_mut()
2142 .unwrap()
2143 .last_workspace_edits_by_language_server
2144 .remove(&server.server_id())
2145 .unwrap_or_default()
2146 })?;
2147
2148 if let Some(transaction) =
2149 project_transaction_command.0.remove(&buffer.handle)
2150 {
2151 zlog::trace!(
2152 logger =>
2153 "Successfully captured {} edits that resulted from command {}",
2154 transaction.edit_ids.len(),
2155 &command.command,
2156 );
2157 let transaction_id_project_transaction = transaction.id;
2158 buffer.handle.update(cx, |buffer, _| {
2159 // it may have been removed from history if push_to_history was
2160 // false in deserialize_workspace_edit. If so push it so we
2161 // can merge it with the format transaction
2162 // and pop the combined transaction off the history stack
2163 // later if push_to_history is false
2164 if buffer.get_transaction(transaction.id).is_none() {
2165 buffer.push_transaction(transaction, Instant::now());
2166 }
2167 buffer.merge_transactions(
2168 transaction_id_project_transaction,
2169 formatting_transaction_id,
2170 );
2171 });
2172 }
2173
2174 if project_transaction_command.0.is_empty() {
2175 continue;
2176 }
2177
2178 let mut extra_buffers = String::new();
2179 for buffer in project_transaction_command.0.keys() {
2180 buffer.read_with(cx, |b, cx| {
2181 let Some(path) = b.project_path(cx) else {
2182 return;
2183 };
2184
2185 if !extra_buffers.is_empty() {
2186 extra_buffers.push_str(", ");
2187 }
2188 extra_buffers.push_str(path.path.as_unix_str());
2189 });
2190 }
2191 zlog::warn!(
2192 logger =>
2193 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2194 &command.command,
2195 extra_buffers,
2196 );
2197 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2198 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2199 // add it so it's included, and merge it into the format transaction when its created later
2200 }
2201 }
2202 }
2203 }
2204
2205 Ok(())
2206 }
2207
2208 pub async fn format_ranges_via_lsp(
2209 this: &WeakEntity<LspStore>,
2210 buffer_handle: &Entity<Buffer>,
2211 ranges: &[Range<Anchor>],
2212 abs_path: &Path,
2213 language_server: &Arc<LanguageServer>,
2214 settings: &LanguageSettings,
2215 cx: &mut AsyncApp,
2216 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2217 let capabilities = &language_server.capabilities();
2218 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2219 if range_formatting_provider == Some(&OneOf::Left(false)) {
2220 anyhow::bail!(
2221 "{} language server does not support range formatting",
2222 language_server.name()
2223 );
2224 }
2225
2226 let uri = file_path_to_lsp_url(abs_path)?;
2227 let text_document = lsp::TextDocumentIdentifier::new(uri);
2228
2229 let request_timeout = cx.update(|app| {
2230 ProjectSettings::get_global(app)
2231 .global_lsp_settings
2232 .get_request_timeout()
2233 });
2234 let lsp_edits = {
2235 let mut lsp_ranges = Vec::new();
2236 this.update(cx, |_this, cx| {
2237 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2238 // not have been sent to the language server. This seems like a fairly systemic
2239 // issue, though, the resolution probably is not specific to formatting.
2240 //
2241 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2242 // LSP.
2243 let snapshot = buffer_handle.read(cx).snapshot();
2244 for range in ranges {
2245 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2246 }
2247 anyhow::Ok(())
2248 })??;
2249
2250 let mut edits = None;
2251 for range in lsp_ranges {
2252 if let Some(mut edit) = language_server
2253 .request::<lsp::request::RangeFormatting>(
2254 lsp::DocumentRangeFormattingParams {
2255 text_document: text_document.clone(),
2256 range,
2257 options: lsp_command::lsp_formatting_options(settings),
2258 work_done_progress_params: Default::default(),
2259 },
2260 request_timeout,
2261 )
2262 .await
2263 .into_response()?
2264 {
2265 edits.get_or_insert_with(Vec::new).append(&mut edit);
2266 }
2267 }
2268 edits
2269 };
2270
2271 if let Some(lsp_edits) = lsp_edits {
2272 this.update(cx, |this, cx| {
2273 this.as_local_mut().unwrap().edits_from_lsp(
2274 buffer_handle,
2275 lsp_edits,
2276 language_server.server_id(),
2277 None,
2278 cx,
2279 )
2280 })?
2281 .await
2282 } else {
2283 Ok(Vec::with_capacity(0))
2284 }
2285 }
2286
2287 async fn format_via_lsp(
2288 this: &WeakEntity<LspStore>,
2289 buffer: &Entity<Buffer>,
2290 abs_path: &Path,
2291 language_server: &Arc<LanguageServer>,
2292 settings: &LanguageSettings,
2293 cx: &mut AsyncApp,
2294 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2295 let logger = zlog::scoped!("lsp_format");
2296 zlog::debug!(logger => "Formatting via LSP");
2297
2298 let uri = file_path_to_lsp_url(abs_path)?;
2299 let text_document = lsp::TextDocumentIdentifier::new(uri);
2300 let capabilities = &language_server.capabilities();
2301
2302 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2303 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2304
2305 let request_timeout = cx.update(|app| {
2306 ProjectSettings::get_global(app)
2307 .global_lsp_settings
2308 .get_request_timeout()
2309 });
2310
2311 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2312 let _timer = zlog::time!(logger => "format-full");
2313 language_server
2314 .request::<lsp::request::Formatting>(
2315 lsp::DocumentFormattingParams {
2316 text_document,
2317 options: lsp_command::lsp_formatting_options(settings),
2318 work_done_progress_params: Default::default(),
2319 },
2320 request_timeout,
2321 )
2322 .await
2323 .into_response()?
2324 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2325 let _timer = zlog::time!(logger => "format-range");
2326 let buffer_start = lsp::Position::new(0, 0);
2327 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2328 language_server
2329 .request::<lsp::request::RangeFormatting>(
2330 lsp::DocumentRangeFormattingParams {
2331 text_document: text_document.clone(),
2332 range: lsp::Range::new(buffer_start, buffer_end),
2333 options: lsp_command::lsp_formatting_options(settings),
2334 work_done_progress_params: Default::default(),
2335 },
2336 request_timeout,
2337 )
2338 .await
2339 .into_response()?
2340 } else {
2341 None
2342 };
2343
2344 if let Some(lsp_edits) = lsp_edits {
2345 this.update(cx, |this, cx| {
2346 this.as_local_mut().unwrap().edits_from_lsp(
2347 buffer,
2348 lsp_edits,
2349 language_server.server_id(),
2350 None,
2351 cx,
2352 )
2353 })?
2354 .await
2355 } else {
2356 Ok(Vec::with_capacity(0))
2357 }
2358 }
2359
2360 async fn format_via_external_command(
2361 buffer: &FormattableBuffer,
2362 command: &str,
2363 arguments: Option<&[String]>,
2364 cx: &mut AsyncApp,
2365 ) -> Result<Option<Diff>> {
2366 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2367 let file = File::from_dyn(buffer.file())?;
2368 let worktree = file.worktree.read(cx);
2369 let mut worktree_path = worktree.abs_path().to_path_buf();
2370 if worktree.root_entry()?.is_file() {
2371 worktree_path.pop();
2372 }
2373 Some(worktree_path)
2374 });
2375
2376 use util::command::Stdio;
2377 let mut child = util::command::new_command(command);
2378
2379 if let Some(buffer_env) = buffer.env.as_ref() {
2380 child.envs(buffer_env);
2381 }
2382
2383 if let Some(working_dir_path) = working_dir_path {
2384 child.current_dir(working_dir_path);
2385 }
2386
2387 if let Some(arguments) = arguments {
2388 child.args(arguments.iter().map(|arg| {
2389 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2390 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2391 } else {
2392 arg.replace("{buffer_path}", "Untitled")
2393 }
2394 }));
2395 }
2396
2397 let mut child = child
2398 .stdin(Stdio::piped())
2399 .stdout(Stdio::piped())
2400 .stderr(Stdio::piped())
2401 .spawn()?;
2402
2403 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2404 let text = buffer
2405 .handle
2406 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2407 for chunk in text.chunks() {
2408 stdin.write_all(chunk.as_bytes()).await?;
2409 }
2410 stdin.flush().await?;
2411
2412 let output = child.output().await?;
2413 anyhow::ensure!(
2414 output.status.success(),
2415 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2416 output.status.code(),
2417 String::from_utf8_lossy(&output.stdout),
2418 String::from_utf8_lossy(&output.stderr),
2419 );
2420
2421 let stdout = String::from_utf8(output.stdout)?;
2422 Ok(Some(
2423 buffer
2424 .handle
2425 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2426 .await,
2427 ))
2428 }
2429
2430 async fn try_resolve_code_action(
2431 lang_server: &LanguageServer,
2432 action: &mut CodeAction,
2433 request_timeout: Duration,
2434 ) -> anyhow::Result<()> {
2435 match &mut action.lsp_action {
2436 LspAction::Action(lsp_action) => {
2437 if !action.resolved
2438 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2439 && lsp_action.data.is_some()
2440 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2441 {
2442 **lsp_action = lang_server
2443 .request::<lsp::request::CodeActionResolveRequest>(
2444 *lsp_action.clone(),
2445 request_timeout,
2446 )
2447 .await
2448 .into_response()?;
2449 }
2450 }
2451 LspAction::CodeLens(lens) => {
2452 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2453 *lens = lang_server
2454 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2455 .await
2456 .into_response()?;
2457 }
2458 }
2459 LspAction::Command(_) => {}
2460 }
2461
2462 action.resolved = true;
2463 anyhow::Ok(())
2464 }
2465
2466 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2467 let buffer = buffer_handle.read(cx);
2468
2469 let file = buffer.file().cloned();
2470
2471 let Some(file) = File::from_dyn(file.as_ref()) else {
2472 return;
2473 };
2474 if !file.is_local() {
2475 return;
2476 }
2477 let path = ProjectPath::from_file(file, cx);
2478 let worktree_id = file.worktree_id(cx);
2479 let language = buffer.language().cloned();
2480
2481 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2482 for (server_id, diagnostics) in
2483 diagnostics.get(file.path()).cloned().unwrap_or_default()
2484 {
2485 self.update_buffer_diagnostics(
2486 buffer_handle,
2487 server_id,
2488 None,
2489 None,
2490 None,
2491 Vec::new(),
2492 diagnostics,
2493 cx,
2494 )
2495 .log_err();
2496 }
2497 }
2498 let Some(language) = language else {
2499 return;
2500 };
2501 let Some(snapshot) = self
2502 .worktree_store
2503 .read(cx)
2504 .worktree_for_id(worktree_id, cx)
2505 .map(|worktree| worktree.read(cx).snapshot())
2506 else {
2507 return;
2508 };
2509 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2510
2511 for server_id in
2512 self.lsp_tree
2513 .get(path, language.name(), language.manifest(), &delegate, cx)
2514 {
2515 let server = self
2516 .language_servers
2517 .get(&server_id)
2518 .and_then(|server_state| {
2519 if let LanguageServerState::Running { server, .. } = server_state {
2520 Some(server.clone())
2521 } else {
2522 None
2523 }
2524 });
2525 let server = match server {
2526 Some(server) => server,
2527 None => continue,
2528 };
2529
2530 buffer_handle.update(cx, |buffer, cx| {
2531 buffer.set_completion_triggers(
2532 server.server_id(),
2533 server
2534 .capabilities()
2535 .completion_provider
2536 .as_ref()
2537 .and_then(|provider| {
2538 provider
2539 .trigger_characters
2540 .as_ref()
2541 .map(|characters| characters.iter().cloned().collect())
2542 })
2543 .unwrap_or_default(),
2544 cx,
2545 );
2546 });
2547 }
2548 }
2549
2550 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2551 buffer.update(cx, |buffer, cx| {
2552 let Some(language) = buffer.language() else {
2553 return;
2554 };
2555 let path = ProjectPath {
2556 worktree_id: old_file.worktree_id(cx),
2557 path: old_file.path.clone(),
2558 };
2559 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2560 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2561 buffer.set_completion_triggers(server_id, Default::default(), cx);
2562 }
2563 });
2564 }
2565
2566 fn update_buffer_diagnostics(
2567 &mut self,
2568 buffer: &Entity<Buffer>,
2569 server_id: LanguageServerId,
2570 registration_id: Option<Option<SharedString>>,
2571 result_id: Option<SharedString>,
2572 version: Option<i32>,
2573 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2574 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2575 cx: &mut Context<LspStore>,
2576 ) -> Result<()> {
2577 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2578 Ordering::Equal
2579 .then_with(|| b.is_primary.cmp(&a.is_primary))
2580 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2581 .then_with(|| a.severity.cmp(&b.severity))
2582 .then_with(|| a.message.cmp(&b.message))
2583 }
2584
2585 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2586 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2587 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2588
2589 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2590 Ordering::Equal
2591 .then_with(|| a.range.start.cmp(&b.range.start))
2592 .then_with(|| b.range.end.cmp(&a.range.end))
2593 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2594 });
2595
2596 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2597
2598 let edits_since_save = std::cell::LazyCell::new(|| {
2599 let saved_version = buffer.read(cx).saved_version();
2600 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2601 });
2602
2603 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2604
2605 for (new_diagnostic, entry) in diagnostics {
2606 let start;
2607 let end;
2608 if new_diagnostic && entry.diagnostic.is_disk_based {
2609 // Some diagnostics are based on files on disk instead of buffers'
2610 // current contents. Adjust these diagnostics' ranges to reflect
2611 // any unsaved edits.
2612 // Do not alter the reused ones though, as their coordinates were stored as anchors
2613 // and were properly adjusted on reuse.
2614 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2615 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2616 } else {
2617 start = entry.range.start;
2618 end = entry.range.end;
2619 }
2620
2621 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2622 ..snapshot.clip_point_utf16(end, Bias::Right);
2623
2624 // Expand empty ranges by one codepoint
2625 if range.start == range.end {
2626 // This will be go to the next boundary when being clipped
2627 range.end.column += 1;
2628 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2629 if range.start == range.end && range.end.column > 0 {
2630 range.start.column -= 1;
2631 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2632 }
2633 }
2634
2635 sanitized_diagnostics.push(DiagnosticEntry {
2636 range,
2637 diagnostic: entry.diagnostic,
2638 });
2639 }
2640 drop(edits_since_save);
2641
2642 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2643 buffer.update(cx, |buffer, cx| {
2644 if let Some(registration_id) = registration_id {
2645 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2646 self.buffer_pull_diagnostics_result_ids
2647 .entry(server_id)
2648 .or_default()
2649 .entry(registration_id)
2650 .or_default()
2651 .insert(abs_path, result_id);
2652 }
2653 }
2654
2655 buffer.update_diagnostics(server_id, set, cx)
2656 });
2657
2658 Ok(())
2659 }
2660
2661 fn register_language_server_for_invisible_worktree(
2662 &mut self,
2663 worktree: &Entity<Worktree>,
2664 language_server_id: LanguageServerId,
2665 cx: &mut App,
2666 ) {
2667 let worktree = worktree.read(cx);
2668 let worktree_id = worktree.id();
2669 debug_assert!(!worktree.is_visible());
2670 let Some(mut origin_seed) = self
2671 .language_server_ids
2672 .iter()
2673 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2674 else {
2675 return;
2676 };
2677 origin_seed.worktree_id = worktree_id;
2678 self.language_server_ids
2679 .entry(origin_seed)
2680 .or_insert_with(|| UnifiedLanguageServer {
2681 id: language_server_id,
2682 project_roots: Default::default(),
2683 });
2684 }
2685
2686 fn register_buffer_with_language_servers(
2687 &mut self,
2688 buffer_handle: &Entity<Buffer>,
2689 only_register_servers: HashSet<LanguageServerSelector>,
2690 cx: &mut Context<LspStore>,
2691 ) {
2692 let buffer = buffer_handle.read(cx);
2693 let buffer_id = buffer.remote_id();
2694
2695 let Some(file) = File::from_dyn(buffer.file()) else {
2696 return;
2697 };
2698 if !file.is_local() {
2699 return;
2700 }
2701
2702 let abs_path = file.abs_path(cx);
2703 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2704 return;
2705 };
2706 let initial_snapshot = buffer.text_snapshot();
2707 let worktree_id = file.worktree_id(cx);
2708
2709 let Some(language) = buffer.language().cloned() else {
2710 return;
2711 };
2712 let path: Arc<RelPath> = file
2713 .path()
2714 .parent()
2715 .map(Arc::from)
2716 .unwrap_or_else(|| file.path().clone());
2717 let Some(worktree) = self
2718 .worktree_store
2719 .read(cx)
2720 .worktree_for_id(worktree_id, cx)
2721 else {
2722 return;
2723 };
2724 let language_name = language.name();
2725 let (reused, delegate, servers) = self
2726 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2727 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2728 .unwrap_or_else(|| {
2729 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2730 let delegate: Arc<dyn ManifestDelegate> =
2731 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2732
2733 let servers = self
2734 .lsp_tree
2735 .walk(
2736 ProjectPath { worktree_id, path },
2737 language.name(),
2738 language.manifest(),
2739 &delegate,
2740 cx,
2741 )
2742 .collect::<Vec<_>>();
2743 (false, lsp_delegate, servers)
2744 });
2745 let servers_and_adapters = servers
2746 .into_iter()
2747 .filter_map(|server_node| {
2748 if reused && server_node.server_id().is_none() {
2749 return None;
2750 }
2751 if !only_register_servers.is_empty() {
2752 if let Some(server_id) = server_node.server_id()
2753 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2754 {
2755 return None;
2756 }
2757 if let Some(name) = server_node.name()
2758 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2759 {
2760 return None;
2761 }
2762 }
2763
2764 let server_id = server_node.server_id_or_init(|disposition| {
2765 let path = &disposition.path;
2766
2767 {
2768 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2769
2770 let server_id = self.get_or_insert_language_server(
2771 &worktree,
2772 delegate.clone(),
2773 disposition,
2774 &language_name,
2775 cx,
2776 );
2777
2778 if let Some(state) = self.language_servers.get(&server_id)
2779 && let Ok(uri) = uri
2780 {
2781 state.add_workspace_folder(uri);
2782 };
2783 server_id
2784 }
2785 })?;
2786 let server_state = self.language_servers.get(&server_id)?;
2787 if let LanguageServerState::Running {
2788 server, adapter, ..
2789 } = server_state
2790 {
2791 Some((server.clone(), adapter.clone()))
2792 } else {
2793 None
2794 }
2795 })
2796 .collect::<Vec<_>>();
2797 for (server, adapter) in servers_and_adapters {
2798 buffer_handle.update(cx, |buffer, cx| {
2799 buffer.set_completion_triggers(
2800 server.server_id(),
2801 server
2802 .capabilities()
2803 .completion_provider
2804 .as_ref()
2805 .and_then(|provider| {
2806 provider
2807 .trigger_characters
2808 .as_ref()
2809 .map(|characters| characters.iter().cloned().collect())
2810 })
2811 .unwrap_or_default(),
2812 cx,
2813 );
2814 });
2815
2816 let snapshot = LspBufferSnapshot {
2817 version: 0,
2818 snapshot: initial_snapshot.clone(),
2819 };
2820
2821 let mut registered = false;
2822 self.buffer_snapshots
2823 .entry(buffer_id)
2824 .or_default()
2825 .entry(server.server_id())
2826 .or_insert_with(|| {
2827 registered = true;
2828 server.register_buffer(
2829 uri.clone(),
2830 adapter.language_id(&language.name()),
2831 0,
2832 initial_snapshot.text(),
2833 );
2834
2835 vec![snapshot]
2836 });
2837
2838 self.buffers_opened_in_servers
2839 .entry(buffer_id)
2840 .or_default()
2841 .insert(server.server_id());
2842 if registered {
2843 cx.emit(LspStoreEvent::LanguageServerUpdate {
2844 language_server_id: server.server_id(),
2845 name: None,
2846 message: proto::update_language_server::Variant::RegisteredForBuffer(
2847 proto::RegisteredForBuffer {
2848 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2849 buffer_id: buffer_id.to_proto(),
2850 },
2851 ),
2852 });
2853 }
2854 }
2855 }
2856
2857 fn reuse_existing_language_server<'lang_name>(
2858 &self,
2859 server_tree: &LanguageServerTree,
2860 worktree: &Entity<Worktree>,
2861 language_name: &'lang_name LanguageName,
2862 cx: &mut App,
2863 ) -> Option<(
2864 Arc<LocalLspAdapterDelegate>,
2865 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2866 )> {
2867 if worktree.read(cx).is_visible() {
2868 return None;
2869 }
2870
2871 let worktree_store = self.worktree_store.read(cx);
2872 let servers = server_tree
2873 .instances
2874 .iter()
2875 .filter(|(worktree_id, _)| {
2876 worktree_store
2877 .worktree_for_id(**worktree_id, cx)
2878 .is_some_and(|worktree| worktree.read(cx).is_visible())
2879 })
2880 .flat_map(|(worktree_id, servers)| {
2881 servers
2882 .roots
2883 .iter()
2884 .flat_map(|(_, language_servers)| language_servers)
2885 .map(move |(_, (server_node, server_languages))| {
2886 (worktree_id, server_node, server_languages)
2887 })
2888 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2889 .map(|(worktree_id, server_node, _)| {
2890 (
2891 *worktree_id,
2892 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2893 )
2894 })
2895 })
2896 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2897 acc.entry(worktree_id)
2898 .or_insert_with(Vec::new)
2899 .push(server_node);
2900 acc
2901 })
2902 .into_values()
2903 .max_by_key(|servers| servers.len())?;
2904
2905 let worktree_id = worktree.read(cx).id();
2906 let apply = move |tree: &mut LanguageServerTree| {
2907 for server_node in &servers {
2908 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2909 }
2910 servers
2911 };
2912
2913 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2914 Some((delegate, apply))
2915 }
2916
2917 pub(crate) fn unregister_old_buffer_from_language_servers(
2918 &mut self,
2919 buffer: &Entity<Buffer>,
2920 old_file: &File,
2921 cx: &mut App,
2922 ) {
2923 let old_path = match old_file.as_local() {
2924 Some(local) => local.abs_path(cx),
2925 None => return,
2926 };
2927
2928 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2929 debug_panic!("{old_path:?} is not parseable as an URI");
2930 return;
2931 };
2932 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2933 }
2934
2935 pub(crate) fn unregister_buffer_from_language_servers(
2936 &mut self,
2937 buffer: &Entity<Buffer>,
2938 file_url: &lsp::Uri,
2939 cx: &mut App,
2940 ) {
2941 buffer.update(cx, |buffer, cx| {
2942 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2943
2944 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2945 if snapshots
2946 .as_mut()
2947 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2948 {
2949 language_server.unregister_buffer(file_url.clone());
2950 }
2951 }
2952 });
2953 }
2954
2955 fn buffer_snapshot_for_lsp_version(
2956 &mut self,
2957 buffer: &Entity<Buffer>,
2958 server_id: LanguageServerId,
2959 version: Option<i32>,
2960 cx: &App,
2961 ) -> Result<TextBufferSnapshot> {
2962 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2963
2964 if let Some(version) = version {
2965 let buffer_id = buffer.read(cx).remote_id();
2966 let snapshots = if let Some(snapshots) = self
2967 .buffer_snapshots
2968 .get_mut(&buffer_id)
2969 .and_then(|m| m.get_mut(&server_id))
2970 {
2971 snapshots
2972 } else if version == 0 {
2973 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2974 // We detect this case and treat it as if the version was `None`.
2975 return Ok(buffer.read(cx).text_snapshot());
2976 } else {
2977 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2978 };
2979
2980 let found_snapshot = snapshots
2981 .binary_search_by_key(&version, |e| e.version)
2982 .map(|ix| snapshots[ix].snapshot.clone())
2983 .map_err(|_| {
2984 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2985 })?;
2986
2987 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2988 Ok(found_snapshot)
2989 } else {
2990 Ok((buffer.read(cx)).text_snapshot())
2991 }
2992 }
2993
2994 async fn get_server_code_actions_from_action_kinds(
2995 lsp_store: &WeakEntity<LspStore>,
2996 language_server_id: LanguageServerId,
2997 code_action_kinds: Vec<lsp::CodeActionKind>,
2998 buffer: &Entity<Buffer>,
2999 cx: &mut AsyncApp,
3000 ) -> Result<Vec<CodeAction>> {
3001 let actions = lsp_store
3002 .update(cx, move |this, cx| {
3003 let request = GetCodeActions {
3004 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3005 kinds: Some(code_action_kinds),
3006 };
3007 let server = LanguageServerToQuery::Other(language_server_id);
3008 this.request_lsp(buffer.clone(), server, request, cx)
3009 })?
3010 .await?;
3011 Ok(actions)
3012 }
3013
3014 pub async fn execute_code_actions_on_server(
3015 lsp_store: &WeakEntity<LspStore>,
3016 language_server: &Arc<LanguageServer>,
3017 actions: Vec<CodeAction>,
3018 push_to_history: bool,
3019 project_transaction: &mut ProjectTransaction,
3020 cx: &mut AsyncApp,
3021 ) -> anyhow::Result<()> {
3022 let request_timeout = cx.update(|app| {
3023 ProjectSettings::get_global(app)
3024 .global_lsp_settings
3025 .get_request_timeout()
3026 });
3027
3028 for mut action in actions {
3029 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3030 .await
3031 .context("resolving a formatting code action")?;
3032
3033 if let Some(edit) = action.lsp_action.edit() {
3034 if edit.changes.is_none() && edit.document_changes.is_none() {
3035 continue;
3036 }
3037
3038 let new = Self::deserialize_workspace_edit(
3039 lsp_store.upgrade().context("project dropped")?,
3040 edit.clone(),
3041 push_to_history,
3042 language_server.clone(),
3043 cx,
3044 )
3045 .await?;
3046 project_transaction.0.extend(new.0);
3047 }
3048
3049 let Some(command) = action.lsp_action.command() else {
3050 continue;
3051 };
3052
3053 let server_capabilities = language_server.capabilities();
3054 let available_commands = server_capabilities
3055 .execute_command_provider
3056 .as_ref()
3057 .map(|options| options.commands.as_slice())
3058 .unwrap_or_default();
3059 if !available_commands.contains(&command.command) {
3060 log::warn!(
3061 "Cannot execute a command {} not listed in the language server capabilities",
3062 command.command
3063 );
3064 continue;
3065 }
3066
3067 lsp_store.update(cx, |lsp_store, _| {
3068 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3069 mode.last_workspace_edits_by_language_server
3070 .remove(&language_server.server_id());
3071 }
3072 })?;
3073
3074 language_server
3075 .request::<lsp::request::ExecuteCommand>(
3076 lsp::ExecuteCommandParams {
3077 command: command.command.clone(),
3078 arguments: command.arguments.clone().unwrap_or_default(),
3079 ..Default::default()
3080 },
3081 request_timeout,
3082 )
3083 .await
3084 .into_response()
3085 .context("execute command")?;
3086
3087 lsp_store.update(cx, |this, _| {
3088 if let LspStoreMode::Local(mode) = &mut this.mode {
3089 project_transaction.0.extend(
3090 mode.last_workspace_edits_by_language_server
3091 .remove(&language_server.server_id())
3092 .unwrap_or_default()
3093 .0,
3094 )
3095 }
3096 })?;
3097 }
3098 Ok(())
3099 }
3100
3101 pub async fn deserialize_text_edits(
3102 this: Entity<LspStore>,
3103 buffer_to_edit: Entity<Buffer>,
3104 edits: Vec<lsp::TextEdit>,
3105 push_to_history: bool,
3106 _: Arc<CachedLspAdapter>,
3107 language_server: Arc<LanguageServer>,
3108 cx: &mut AsyncApp,
3109 ) -> Result<Option<Transaction>> {
3110 let edits = this
3111 .update(cx, |this, cx| {
3112 this.as_local_mut().unwrap().edits_from_lsp(
3113 &buffer_to_edit,
3114 edits,
3115 language_server.server_id(),
3116 None,
3117 cx,
3118 )
3119 })
3120 .await?;
3121
3122 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3123 buffer.finalize_last_transaction();
3124 buffer.start_transaction();
3125 for (range, text) in edits {
3126 buffer.edit([(range, text)], None, cx);
3127 }
3128
3129 if buffer.end_transaction(cx).is_some() {
3130 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3131 if !push_to_history {
3132 buffer.forget_transaction(transaction.id);
3133 }
3134 Some(transaction)
3135 } else {
3136 None
3137 }
3138 });
3139
3140 Ok(transaction)
3141 }
3142
3143 #[allow(clippy::type_complexity)]
3144 pub fn edits_from_lsp(
3145 &mut self,
3146 buffer: &Entity<Buffer>,
3147 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3148 server_id: LanguageServerId,
3149 version: Option<i32>,
3150 cx: &mut Context<LspStore>,
3151 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3152 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3153 cx.background_spawn(async move {
3154 let snapshot = snapshot?;
3155 let mut lsp_edits = lsp_edits
3156 .into_iter()
3157 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3158 .collect::<Vec<_>>();
3159
3160 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3161
3162 let mut lsp_edits = lsp_edits.into_iter().peekable();
3163 let mut edits = Vec::new();
3164 while let Some((range, mut new_text)) = lsp_edits.next() {
3165 // Clip invalid ranges provided by the language server.
3166 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3167 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3168
3169 // Combine any LSP edits that are adjacent.
3170 //
3171 // Also, combine LSP edits that are separated from each other by only
3172 // a newline. This is important because for some code actions,
3173 // Rust-analyzer rewrites the entire buffer via a series of edits that
3174 // are separated by unchanged newline characters.
3175 //
3176 // In order for the diffing logic below to work properly, any edits that
3177 // cancel each other out must be combined into one.
3178 while let Some((next_range, next_text)) = lsp_edits.peek() {
3179 if next_range.start.0 > range.end {
3180 if next_range.start.0.row > range.end.row + 1
3181 || next_range.start.0.column > 0
3182 || snapshot.clip_point_utf16(
3183 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3184 Bias::Left,
3185 ) > range.end
3186 {
3187 break;
3188 }
3189 new_text.push('\n');
3190 }
3191 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3192 new_text.push_str(next_text);
3193 lsp_edits.next();
3194 }
3195
3196 // For multiline edits, perform a diff of the old and new text so that
3197 // we can identify the changes more precisely, preserving the locations
3198 // of any anchors positioned in the unchanged regions.
3199 if range.end.row > range.start.row {
3200 let offset = range.start.to_offset(&snapshot);
3201 let old_text = snapshot.text_for_range(range).collect::<String>();
3202 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3203 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3204 (
3205 snapshot.anchor_after(offset + range.start)
3206 ..snapshot.anchor_before(offset + range.end),
3207 replacement,
3208 )
3209 }));
3210 } else if range.end == range.start {
3211 let anchor = snapshot.anchor_after(range.start);
3212 edits.push((anchor..anchor, new_text.into()));
3213 } else {
3214 let edit_start = snapshot.anchor_after(range.start);
3215 let edit_end = snapshot.anchor_before(range.end);
3216 edits.push((edit_start..edit_end, new_text.into()));
3217 }
3218 }
3219
3220 Ok(edits)
3221 })
3222 }
3223
3224 pub(crate) async fn deserialize_workspace_edit(
3225 this: Entity<LspStore>,
3226 edit: lsp::WorkspaceEdit,
3227 push_to_history: bool,
3228 language_server: Arc<LanguageServer>,
3229 cx: &mut AsyncApp,
3230 ) -> Result<ProjectTransaction> {
3231 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3232
3233 let mut operations = Vec::new();
3234 if let Some(document_changes) = edit.document_changes {
3235 match document_changes {
3236 lsp::DocumentChanges::Edits(edits) => {
3237 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3238 }
3239 lsp::DocumentChanges::Operations(ops) => operations = ops,
3240 }
3241 } else if let Some(changes) = edit.changes {
3242 operations.extend(changes.into_iter().map(|(uri, edits)| {
3243 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3244 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3245 uri,
3246 version: None,
3247 },
3248 edits: edits.into_iter().map(Edit::Plain).collect(),
3249 })
3250 }));
3251 }
3252
3253 let mut project_transaction = ProjectTransaction::default();
3254 for operation in operations {
3255 match operation {
3256 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3257 let abs_path = op
3258 .uri
3259 .to_file_path()
3260 .map_err(|()| anyhow!("can't convert URI to path"))?;
3261
3262 if let Some(parent_path) = abs_path.parent() {
3263 fs.create_dir(parent_path).await?;
3264 }
3265 if abs_path.ends_with("/") {
3266 fs.create_dir(&abs_path).await?;
3267 } else {
3268 fs.create_file(
3269 &abs_path,
3270 op.options
3271 .map(|options| fs::CreateOptions {
3272 overwrite: options.overwrite.unwrap_or(false),
3273 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3274 })
3275 .unwrap_or_default(),
3276 )
3277 .await?;
3278 }
3279 }
3280
3281 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3282 let source_abs_path = op
3283 .old_uri
3284 .to_file_path()
3285 .map_err(|()| anyhow!("can't convert URI to path"))?;
3286 let target_abs_path = op
3287 .new_uri
3288 .to_file_path()
3289 .map_err(|()| anyhow!("can't convert URI to path"))?;
3290
3291 let options = fs::RenameOptions {
3292 overwrite: op
3293 .options
3294 .as_ref()
3295 .and_then(|options| options.overwrite)
3296 .unwrap_or(false),
3297 ignore_if_exists: op
3298 .options
3299 .as_ref()
3300 .and_then(|options| options.ignore_if_exists)
3301 .unwrap_or(false),
3302 create_parents: true,
3303 };
3304
3305 fs.rename(&source_abs_path, &target_abs_path, options)
3306 .await?;
3307 }
3308
3309 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3310 let abs_path = op
3311 .uri
3312 .to_file_path()
3313 .map_err(|()| anyhow!("can't convert URI to path"))?;
3314 let options = op
3315 .options
3316 .map(|options| fs::RemoveOptions {
3317 recursive: options.recursive.unwrap_or(false),
3318 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3319 })
3320 .unwrap_or_default();
3321 if abs_path.ends_with("/") {
3322 fs.remove_dir(&abs_path, options).await?;
3323 } else {
3324 fs.remove_file(&abs_path, options).await?;
3325 }
3326 }
3327
3328 lsp::DocumentChangeOperation::Edit(op) => {
3329 let buffer_to_edit = this
3330 .update(cx, |this, cx| {
3331 this.open_local_buffer_via_lsp(
3332 op.text_document.uri.clone(),
3333 language_server.server_id(),
3334 cx,
3335 )
3336 })
3337 .await?;
3338
3339 let edits = this
3340 .update(cx, |this, cx| {
3341 let path = buffer_to_edit.read(cx).project_path(cx);
3342 let active_entry = this.active_entry;
3343 let is_active_entry = path.is_some_and(|project_path| {
3344 this.worktree_store
3345 .read(cx)
3346 .entry_for_path(&project_path, cx)
3347 .is_some_and(|entry| Some(entry.id) == active_entry)
3348 });
3349 let local = this.as_local_mut().unwrap();
3350
3351 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3352 for edit in op.edits {
3353 match edit {
3354 Edit::Plain(edit) => {
3355 if !edits.contains(&edit) {
3356 edits.push(edit)
3357 }
3358 }
3359 Edit::Annotated(edit) => {
3360 if !edits.contains(&edit.text_edit) {
3361 edits.push(edit.text_edit)
3362 }
3363 }
3364 Edit::Snippet(edit) => {
3365 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3366 else {
3367 continue;
3368 };
3369
3370 if is_active_entry {
3371 snippet_edits.push((edit.range, snippet));
3372 } else {
3373 // Since this buffer is not focused, apply a normal edit.
3374 let new_edit = TextEdit {
3375 range: edit.range,
3376 new_text: snippet.text,
3377 };
3378 if !edits.contains(&new_edit) {
3379 edits.push(new_edit);
3380 }
3381 }
3382 }
3383 }
3384 }
3385 if !snippet_edits.is_empty() {
3386 let buffer_id = buffer_to_edit.read(cx).remote_id();
3387 let version = if let Some(buffer_version) = op.text_document.version
3388 {
3389 local
3390 .buffer_snapshot_for_lsp_version(
3391 &buffer_to_edit,
3392 language_server.server_id(),
3393 Some(buffer_version),
3394 cx,
3395 )
3396 .ok()
3397 .map(|snapshot| snapshot.version)
3398 } else {
3399 Some(buffer_to_edit.read(cx).saved_version().clone())
3400 };
3401
3402 let most_recent_edit =
3403 version.and_then(|version| version.most_recent());
3404 // Check if the edit that triggered that edit has been made by this participant.
3405
3406 if let Some(most_recent_edit) = most_recent_edit {
3407 cx.emit(LspStoreEvent::SnippetEdit {
3408 buffer_id,
3409 edits: snippet_edits,
3410 most_recent_edit,
3411 });
3412 }
3413 }
3414
3415 local.edits_from_lsp(
3416 &buffer_to_edit,
3417 edits,
3418 language_server.server_id(),
3419 op.text_document.version,
3420 cx,
3421 )
3422 })
3423 .await?;
3424
3425 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3426 buffer.finalize_last_transaction();
3427 buffer.start_transaction();
3428 for (range, text) in edits {
3429 buffer.edit([(range, text)], None, cx);
3430 }
3431
3432 buffer.end_transaction(cx).and_then(|transaction_id| {
3433 if push_to_history {
3434 buffer.finalize_last_transaction();
3435 buffer.get_transaction(transaction_id).cloned()
3436 } else {
3437 buffer.forget_transaction(transaction_id)
3438 }
3439 })
3440 });
3441 if let Some(transaction) = transaction {
3442 project_transaction.0.insert(buffer_to_edit, transaction);
3443 }
3444 }
3445 }
3446 }
3447
3448 Ok(project_transaction)
3449 }
3450
3451 async fn on_lsp_workspace_edit(
3452 this: WeakEntity<LspStore>,
3453 params: lsp::ApplyWorkspaceEditParams,
3454 server_id: LanguageServerId,
3455 cx: &mut AsyncApp,
3456 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3457 let this = this.upgrade().context("project project closed")?;
3458 let language_server = this
3459 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3460 .context("language server not found")?;
3461 let transaction = Self::deserialize_workspace_edit(
3462 this.clone(),
3463 params.edit,
3464 true,
3465 language_server.clone(),
3466 cx,
3467 )
3468 .await
3469 .log_err();
3470 this.update(cx, |this, cx| {
3471 if let Some(transaction) = transaction {
3472 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3473
3474 this.as_local_mut()
3475 .unwrap()
3476 .last_workspace_edits_by_language_server
3477 .insert(server_id, transaction);
3478 }
3479 });
3480 Ok(lsp::ApplyWorkspaceEditResponse {
3481 applied: true,
3482 failed_change: None,
3483 failure_reason: None,
3484 })
3485 }
3486
3487 fn remove_worktree(
3488 &mut self,
3489 id_to_remove: WorktreeId,
3490 cx: &mut Context<LspStore>,
3491 ) -> Vec<LanguageServerId> {
3492 self.restricted_worktrees_tasks.remove(&id_to_remove);
3493 self.diagnostics.remove(&id_to_remove);
3494 self.prettier_store.update(cx, |prettier_store, cx| {
3495 prettier_store.remove_worktree(id_to_remove, cx);
3496 });
3497
3498 let mut servers_to_remove = BTreeSet::default();
3499 let mut servers_to_preserve = HashSet::default();
3500 for (seed, state) in &self.language_server_ids {
3501 if seed.worktree_id == id_to_remove {
3502 servers_to_remove.insert(state.id);
3503 } else {
3504 servers_to_preserve.insert(state.id);
3505 }
3506 }
3507 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3508 self.language_server_ids
3509 .retain(|_, state| !servers_to_remove.contains(&state.id));
3510 for server_id_to_remove in &servers_to_remove {
3511 self.language_server_watched_paths
3512 .remove(server_id_to_remove);
3513 self.language_server_paths_watched_for_rename
3514 .remove(server_id_to_remove);
3515 self.last_workspace_edits_by_language_server
3516 .remove(server_id_to_remove);
3517 self.language_servers.remove(server_id_to_remove);
3518 self.buffer_pull_diagnostics_result_ids
3519 .remove(server_id_to_remove);
3520 self.workspace_pull_diagnostics_result_ids
3521 .remove(server_id_to_remove);
3522 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3523 buffer_servers.remove(server_id_to_remove);
3524 }
3525 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3526 }
3527 servers_to_remove.into_iter().collect()
3528 }
3529
3530 fn rebuild_watched_paths_inner<'a>(
3531 &'a self,
3532 language_server_id: LanguageServerId,
3533 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3534 cx: &mut Context<LspStore>,
3535 ) -> LanguageServerWatchedPathsBuilder {
3536 let worktrees = self
3537 .worktree_store
3538 .read(cx)
3539 .worktrees()
3540 .filter_map(|worktree| {
3541 self.language_servers_for_worktree(worktree.read(cx).id())
3542 .find(|server| server.server_id() == language_server_id)
3543 .map(|_| worktree)
3544 })
3545 .collect::<Vec<_>>();
3546
3547 let mut worktree_globs = HashMap::default();
3548 let mut abs_globs = HashMap::default();
3549 log::trace!(
3550 "Processing new watcher paths for language server with id {}",
3551 language_server_id
3552 );
3553
3554 for watcher in watchers {
3555 if let Some((worktree, literal_prefix, pattern)) =
3556 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3557 {
3558 worktree.update(cx, |worktree, _| {
3559 if let Some((tree, glob)) =
3560 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3561 {
3562 tree.add_path_prefix_to_scan(literal_prefix);
3563 worktree_globs
3564 .entry(tree.id())
3565 .or_insert_with(GlobSetBuilder::new)
3566 .add(glob);
3567 }
3568 });
3569 } else {
3570 let (path, pattern) = match &watcher.glob_pattern {
3571 lsp::GlobPattern::String(s) => {
3572 let watcher_path = SanitizedPath::new(s);
3573 let path = glob_literal_prefix(watcher_path.as_path());
3574 let pattern = watcher_path
3575 .as_path()
3576 .strip_prefix(&path)
3577 .map(|p| p.to_string_lossy().into_owned())
3578 .unwrap_or_else(|e| {
3579 debug_panic!(
3580 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3581 s,
3582 path.display(),
3583 e
3584 );
3585 watcher_path.as_path().to_string_lossy().into_owned()
3586 });
3587 (path, pattern)
3588 }
3589 lsp::GlobPattern::Relative(rp) => {
3590 let Ok(mut base_uri) = match &rp.base_uri {
3591 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3592 lsp::OneOf::Right(base_uri) => base_uri,
3593 }
3594 .to_file_path() else {
3595 continue;
3596 };
3597
3598 let path = glob_literal_prefix(Path::new(&rp.pattern));
3599 let pattern = Path::new(&rp.pattern)
3600 .strip_prefix(&path)
3601 .map(|p| p.to_string_lossy().into_owned())
3602 .unwrap_or_else(|e| {
3603 debug_panic!(
3604 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3605 rp.pattern,
3606 path.display(),
3607 e
3608 );
3609 rp.pattern.clone()
3610 });
3611 base_uri.push(path);
3612 (base_uri, pattern)
3613 }
3614 };
3615
3616 if let Some(glob) = Glob::new(&pattern).log_err() {
3617 if !path
3618 .components()
3619 .any(|c| matches!(c, path::Component::Normal(_)))
3620 {
3621 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3622 // rather than adding a new watcher for `/`.
3623 for worktree in &worktrees {
3624 worktree_globs
3625 .entry(worktree.read(cx).id())
3626 .or_insert_with(GlobSetBuilder::new)
3627 .add(glob.clone());
3628 }
3629 } else {
3630 abs_globs
3631 .entry(path.into())
3632 .or_insert_with(GlobSetBuilder::new)
3633 .add(glob);
3634 }
3635 }
3636 }
3637 }
3638
3639 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3640 for (worktree_id, builder) in worktree_globs {
3641 if let Ok(globset) = builder.build() {
3642 watch_builder.watch_worktree(worktree_id, globset);
3643 }
3644 }
3645 for (abs_path, builder) in abs_globs {
3646 if let Ok(globset) = builder.build() {
3647 watch_builder.watch_abs_path(abs_path, globset);
3648 }
3649 }
3650 watch_builder
3651 }
3652
3653 fn worktree_and_path_for_file_watcher(
3654 worktrees: &[Entity<Worktree>],
3655 watcher: &FileSystemWatcher,
3656 cx: &App,
3657 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3658 worktrees.iter().find_map(|worktree| {
3659 let tree = worktree.read(cx);
3660 let worktree_root_path = tree.abs_path();
3661 let path_style = tree.path_style();
3662 match &watcher.glob_pattern {
3663 lsp::GlobPattern::String(s) => {
3664 let watcher_path = SanitizedPath::new(s);
3665 let relative = watcher_path
3666 .as_path()
3667 .strip_prefix(&worktree_root_path)
3668 .ok()?;
3669 let literal_prefix = glob_literal_prefix(relative);
3670 Some((
3671 worktree.clone(),
3672 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3673 relative.to_string_lossy().into_owned(),
3674 ))
3675 }
3676 lsp::GlobPattern::Relative(rp) => {
3677 let base_uri = match &rp.base_uri {
3678 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3679 lsp::OneOf::Right(base_uri) => base_uri,
3680 }
3681 .to_file_path()
3682 .ok()?;
3683 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3684 let mut literal_prefix = relative.to_owned();
3685 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3686 Some((
3687 worktree.clone(),
3688 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3689 rp.pattern.clone(),
3690 ))
3691 }
3692 }
3693 })
3694 }
3695
3696 fn rebuild_watched_paths(
3697 &mut self,
3698 language_server_id: LanguageServerId,
3699 cx: &mut Context<LspStore>,
3700 ) {
3701 let Some(registrations) = self
3702 .language_server_dynamic_registrations
3703 .get(&language_server_id)
3704 else {
3705 return;
3706 };
3707
3708 let watch_builder = self.rebuild_watched_paths_inner(
3709 language_server_id,
3710 registrations.did_change_watched_files.values().flatten(),
3711 cx,
3712 );
3713 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3714 self.language_server_watched_paths
3715 .insert(language_server_id, watcher);
3716
3717 cx.notify();
3718 }
3719
3720 fn on_lsp_did_change_watched_files(
3721 &mut self,
3722 language_server_id: LanguageServerId,
3723 registration_id: &str,
3724 params: DidChangeWatchedFilesRegistrationOptions,
3725 cx: &mut Context<LspStore>,
3726 ) {
3727 let registrations = self
3728 .language_server_dynamic_registrations
3729 .entry(language_server_id)
3730 .or_default();
3731
3732 registrations
3733 .did_change_watched_files
3734 .insert(registration_id.to_string(), params.watchers);
3735
3736 self.rebuild_watched_paths(language_server_id, cx);
3737 }
3738
3739 fn on_lsp_unregister_did_change_watched_files(
3740 &mut self,
3741 language_server_id: LanguageServerId,
3742 registration_id: &str,
3743 cx: &mut Context<LspStore>,
3744 ) {
3745 let registrations = self
3746 .language_server_dynamic_registrations
3747 .entry(language_server_id)
3748 .or_default();
3749
3750 if registrations
3751 .did_change_watched_files
3752 .remove(registration_id)
3753 .is_some()
3754 {
3755 log::info!(
3756 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3757 language_server_id,
3758 registration_id
3759 );
3760 } else {
3761 log::warn!(
3762 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3763 language_server_id,
3764 registration_id
3765 );
3766 }
3767
3768 self.rebuild_watched_paths(language_server_id, cx);
3769 }
3770
3771 async fn initialization_options_for_adapter(
3772 adapter: Arc<dyn LspAdapter>,
3773 delegate: &Arc<dyn LspAdapterDelegate>,
3774 ) -> Result<Option<serde_json::Value>> {
3775 let Some(mut initialization_config) =
3776 adapter.clone().initialization_options(delegate).await?
3777 else {
3778 return Ok(None);
3779 };
3780
3781 for other_adapter in delegate.registered_lsp_adapters() {
3782 if other_adapter.name() == adapter.name() {
3783 continue;
3784 }
3785 if let Ok(Some(target_config)) = other_adapter
3786 .clone()
3787 .additional_initialization_options(adapter.name(), delegate)
3788 .await
3789 {
3790 merge_json_value_into(target_config.clone(), &mut initialization_config);
3791 }
3792 }
3793
3794 Ok(Some(initialization_config))
3795 }
3796
3797 async fn workspace_configuration_for_adapter(
3798 adapter: Arc<dyn LspAdapter>,
3799 delegate: &Arc<dyn LspAdapterDelegate>,
3800 toolchain: Option<Toolchain>,
3801 requested_uri: Option<Uri>,
3802 cx: &mut AsyncApp,
3803 ) -> Result<serde_json::Value> {
3804 let mut workspace_config = adapter
3805 .clone()
3806 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3807 .await?;
3808
3809 for other_adapter in delegate.registered_lsp_adapters() {
3810 if other_adapter.name() == adapter.name() {
3811 continue;
3812 }
3813 if let Ok(Some(target_config)) = other_adapter
3814 .clone()
3815 .additional_workspace_configuration(adapter.name(), delegate, cx)
3816 .await
3817 {
3818 merge_json_value_into(target_config.clone(), &mut workspace_config);
3819 }
3820 }
3821
3822 Ok(workspace_config)
3823 }
3824
3825 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3826 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3827 Some(server.clone())
3828 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3829 Some(Arc::clone(server))
3830 } else {
3831 None
3832 }
3833 }
3834}
3835
3836fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3837 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3838 cx.emit(LspStoreEvent::LanguageServerUpdate {
3839 language_server_id: server.server_id(),
3840 name: Some(server.name()),
3841 message: proto::update_language_server::Variant::MetadataUpdated(
3842 proto::ServerMetadataUpdated {
3843 capabilities: Some(capabilities),
3844 binary: Some(proto::LanguageServerBinaryInfo {
3845 path: server.binary().path.to_string_lossy().into_owned(),
3846 arguments: server
3847 .binary()
3848 .arguments
3849 .iter()
3850 .map(|arg| arg.to_string_lossy().into_owned())
3851 .collect(),
3852 }),
3853 configuration: serde_json::to_string(server.configuration()).ok(),
3854 workspace_folders: server
3855 .workspace_folders()
3856 .iter()
3857 .map(|uri| uri.to_string())
3858 .collect(),
3859 },
3860 ),
3861 });
3862 }
3863}
3864
3865#[derive(Debug)]
3866pub struct FormattableBuffer {
3867 handle: Entity<Buffer>,
3868 abs_path: Option<PathBuf>,
3869 env: Option<HashMap<String, String>>,
3870 ranges: Option<Vec<Range<Anchor>>>,
3871}
3872
3873pub struct RemoteLspStore {
3874 upstream_client: Option<AnyProtoClient>,
3875 upstream_project_id: u64,
3876}
3877
3878pub(crate) enum LspStoreMode {
3879 Local(LocalLspStore), // ssh host and collab host
3880 Remote(RemoteLspStore), // collab guest
3881}
3882
3883impl LspStoreMode {
3884 fn is_local(&self) -> bool {
3885 matches!(self, LspStoreMode::Local(_))
3886 }
3887}
3888
3889pub struct LspStore {
3890 mode: LspStoreMode,
3891 last_formatting_failure: Option<String>,
3892 downstream_client: Option<(AnyProtoClient, u64)>,
3893 nonce: u128,
3894 buffer_store: Entity<BufferStore>,
3895 worktree_store: Entity<WorktreeStore>,
3896 pub languages: Arc<LanguageRegistry>,
3897 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3898 active_entry: Option<ProjectEntryId>,
3899 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3900 _maintain_buffer_languages: Task<()>,
3901 diagnostic_summaries:
3902 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3903 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3904 semantic_token_config: SemanticTokenConfig,
3905 lsp_data: HashMap<BufferId, BufferLspData>,
3906 next_hint_id: Arc<AtomicUsize>,
3907}
3908
3909#[derive(Debug)]
3910pub struct BufferLspData {
3911 buffer_version: Global,
3912 document_colors: Option<DocumentColorData>,
3913 code_lens: Option<CodeLensData>,
3914 semantic_tokens: Option<SemanticTokensData>,
3915 folding_ranges: Option<FoldingRangeData>,
3916 document_symbols: Option<DocumentSymbolsData>,
3917 inlay_hints: BufferInlayHints,
3918 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3919 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3920}
3921
3922#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3923struct LspKey {
3924 request_type: TypeId,
3925 server_queried: Option<LanguageServerId>,
3926}
3927
3928impl BufferLspData {
3929 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3930 Self {
3931 buffer_version: buffer.read(cx).version(),
3932 document_colors: None,
3933 code_lens: None,
3934 semantic_tokens: None,
3935 folding_ranges: None,
3936 document_symbols: None,
3937 inlay_hints: BufferInlayHints::new(buffer, cx),
3938 lsp_requests: HashMap::default(),
3939 chunk_lsp_requests: HashMap::default(),
3940 }
3941 }
3942
3943 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3944 if let Some(document_colors) = &mut self.document_colors {
3945 document_colors.remove_server_data(for_server);
3946 }
3947
3948 if let Some(code_lens) = &mut self.code_lens {
3949 code_lens.remove_server_data(for_server);
3950 }
3951
3952 self.inlay_hints.remove_server_data(for_server);
3953
3954 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3955 semantic_tokens.raw_tokens.servers.remove(&for_server);
3956 semantic_tokens
3957 .latest_invalidation_requests
3958 .remove(&for_server);
3959 }
3960
3961 if let Some(folding_ranges) = &mut self.folding_ranges {
3962 folding_ranges.ranges.remove(&for_server);
3963 }
3964
3965 if let Some(document_symbols) = &mut self.document_symbols {
3966 document_symbols.remove_server_data(for_server);
3967 }
3968 }
3969
3970 #[cfg(any(test, feature = "test-support"))]
3971 pub fn inlay_hints(&self) -> &BufferInlayHints {
3972 &self.inlay_hints
3973 }
3974}
3975
3976#[derive(Debug)]
3977pub enum LspStoreEvent {
3978 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3979 LanguageServerRemoved(LanguageServerId),
3980 LanguageServerUpdate {
3981 language_server_id: LanguageServerId,
3982 name: Option<LanguageServerName>,
3983 message: proto::update_language_server::Variant,
3984 },
3985 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3986 LanguageServerPrompt(LanguageServerPromptRequest),
3987 LanguageDetected {
3988 buffer: Entity<Buffer>,
3989 new_language: Option<Arc<Language>>,
3990 },
3991 Notification(String),
3992 RefreshInlayHints {
3993 server_id: LanguageServerId,
3994 request_id: Option<usize>,
3995 },
3996 RefreshSemanticTokens {
3997 server_id: LanguageServerId,
3998 request_id: Option<usize>,
3999 },
4000 RefreshCodeLens,
4001 DiagnosticsUpdated {
4002 server_id: LanguageServerId,
4003 paths: Vec<ProjectPath>,
4004 },
4005 DiskBasedDiagnosticsStarted {
4006 language_server_id: LanguageServerId,
4007 },
4008 DiskBasedDiagnosticsFinished {
4009 language_server_id: LanguageServerId,
4010 },
4011 SnippetEdit {
4012 buffer_id: BufferId,
4013 edits: Vec<(lsp::Range, Snippet)>,
4014 most_recent_edit: clock::Lamport,
4015 },
4016 WorkspaceEditApplied(ProjectTransaction),
4017}
4018
4019#[derive(Clone, Debug, Serialize)]
4020pub struct LanguageServerStatus {
4021 pub name: LanguageServerName,
4022 pub server_version: Option<SharedString>,
4023 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4024 pub has_pending_diagnostic_updates: bool,
4025 pub progress_tokens: HashSet<ProgressToken>,
4026 pub worktree: Option<WorktreeId>,
4027 pub binary: Option<LanguageServerBinary>,
4028 pub configuration: Option<Value>,
4029 pub workspace_folders: BTreeSet<Uri>,
4030 pub process_id: Option<u32>,
4031}
4032
4033#[derive(Clone, Debug)]
4034struct CoreSymbol {
4035 pub language_server_name: LanguageServerName,
4036 pub source_worktree_id: WorktreeId,
4037 pub source_language_server_id: LanguageServerId,
4038 pub path: SymbolLocation,
4039 pub name: String,
4040 pub kind: lsp::SymbolKind,
4041 pub range: Range<Unclipped<PointUtf16>>,
4042 pub container_name: Option<String>,
4043}
4044
4045#[derive(Clone, Debug, PartialEq, Eq)]
4046pub enum SymbolLocation {
4047 InProject(ProjectPath),
4048 OutsideProject {
4049 abs_path: Arc<Path>,
4050 signature: [u8; 32],
4051 },
4052}
4053
4054impl SymbolLocation {
4055 fn file_name(&self) -> Option<&str> {
4056 match self {
4057 Self::InProject(path) => path.path.file_name(),
4058 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4059 }
4060 }
4061}
4062
4063impl LspStore {
4064 pub fn init(client: &AnyProtoClient) {
4065 client.add_entity_request_handler(Self::handle_lsp_query);
4066 client.add_entity_message_handler(Self::handle_lsp_query_response);
4067 client.add_entity_request_handler(Self::handle_restart_language_servers);
4068 client.add_entity_request_handler(Self::handle_stop_language_servers);
4069 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4070 client.add_entity_message_handler(Self::handle_start_language_server);
4071 client.add_entity_message_handler(Self::handle_update_language_server);
4072 client.add_entity_message_handler(Self::handle_language_server_log);
4073 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4074 client.add_entity_request_handler(Self::handle_format_buffers);
4075 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4076 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4077 client.add_entity_request_handler(Self::handle_apply_code_action);
4078 client.add_entity_request_handler(Self::handle_get_project_symbols);
4079 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4080 client.add_entity_request_handler(Self::handle_get_color_presentation);
4081 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4082 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4083 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4084 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4085 client.add_entity_request_handler(Self::handle_on_type_formatting);
4086 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4087 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4088 client.add_entity_request_handler(Self::handle_rename_project_entry);
4089 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4090 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4091 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4092 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4093 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4094 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4095 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4096
4097 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4098 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4099 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4100 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4101 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4102 client.add_entity_request_handler(
4103 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4104 );
4105 client.add_entity_request_handler(
4106 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4107 );
4108 client.add_entity_request_handler(
4109 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4110 );
4111 }
4112
4113 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4114 match &self.mode {
4115 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4116 _ => None,
4117 }
4118 }
4119
4120 pub fn as_local(&self) -> Option<&LocalLspStore> {
4121 match &self.mode {
4122 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4123 _ => None,
4124 }
4125 }
4126
4127 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4128 match &mut self.mode {
4129 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4130 _ => None,
4131 }
4132 }
4133
4134 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4135 match &self.mode {
4136 LspStoreMode::Remote(RemoteLspStore {
4137 upstream_client: Some(upstream_client),
4138 upstream_project_id,
4139 ..
4140 }) => Some((upstream_client.clone(), *upstream_project_id)),
4141
4142 LspStoreMode::Remote(RemoteLspStore {
4143 upstream_client: None,
4144 ..
4145 }) => None,
4146 LspStoreMode::Local(_) => None,
4147 }
4148 }
4149
4150 pub fn new_local(
4151 buffer_store: Entity<BufferStore>,
4152 worktree_store: Entity<WorktreeStore>,
4153 prettier_store: Entity<PrettierStore>,
4154 toolchain_store: Entity<LocalToolchainStore>,
4155 environment: Entity<ProjectEnvironment>,
4156 manifest_tree: Entity<ManifestTree>,
4157 languages: Arc<LanguageRegistry>,
4158 http_client: Arc<dyn HttpClient>,
4159 fs: Arc<dyn Fs>,
4160 cx: &mut Context<Self>,
4161 ) -> Self {
4162 let yarn = YarnPathStore::new(fs.clone(), cx);
4163 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4164 .detach();
4165 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4166 .detach();
4167 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4168 .detach();
4169 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4170 .detach();
4171 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4172 .detach();
4173 subscribe_to_binary_statuses(&languages, cx).detach();
4174
4175 let _maintain_workspace_config = {
4176 let (sender, receiver) = watch::channel();
4177 (Self::maintain_workspace_config(receiver, cx), sender)
4178 };
4179
4180 Self {
4181 mode: LspStoreMode::Local(LocalLspStore {
4182 weak: cx.weak_entity(),
4183 worktree_store: worktree_store.clone(),
4184
4185 supplementary_language_servers: Default::default(),
4186 languages: languages.clone(),
4187 language_server_ids: Default::default(),
4188 language_servers: Default::default(),
4189 last_workspace_edits_by_language_server: Default::default(),
4190 language_server_watched_paths: Default::default(),
4191 language_server_paths_watched_for_rename: Default::default(),
4192 language_server_dynamic_registrations: Default::default(),
4193 buffers_being_formatted: Default::default(),
4194 buffers_to_refresh_hash_set: HashSet::default(),
4195 buffers_to_refresh_queue: VecDeque::new(),
4196 _background_diagnostics_worker: Task::ready(()).shared(),
4197 buffer_snapshots: Default::default(),
4198 prettier_store,
4199 environment,
4200 http_client,
4201 fs,
4202 yarn,
4203 next_diagnostic_group_id: Default::default(),
4204 diagnostics: Default::default(),
4205 _subscription: cx.on_app_quit(|this, _| {
4206 this.as_local_mut()
4207 .unwrap()
4208 .shutdown_language_servers_on_quit()
4209 }),
4210 lsp_tree: LanguageServerTree::new(
4211 manifest_tree,
4212 languages.clone(),
4213 toolchain_store.clone(),
4214 ),
4215 toolchain_store,
4216 registered_buffers: HashMap::default(),
4217 buffers_opened_in_servers: HashMap::default(),
4218 buffer_pull_diagnostics_result_ids: HashMap::default(),
4219 workspace_pull_diagnostics_result_ids: HashMap::default(),
4220 restricted_worktrees_tasks: HashMap::default(),
4221 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4222 .manifest_file_names(),
4223 }),
4224 last_formatting_failure: None,
4225 downstream_client: None,
4226 buffer_store,
4227 worktree_store,
4228 languages: languages.clone(),
4229 language_server_statuses: Default::default(),
4230 nonce: StdRng::from_os_rng().random(),
4231 diagnostic_summaries: HashMap::default(),
4232 lsp_server_capabilities: HashMap::default(),
4233 semantic_token_config: SemanticTokenConfig::new(cx),
4234 lsp_data: HashMap::default(),
4235 next_hint_id: Arc::default(),
4236 active_entry: None,
4237 _maintain_workspace_config,
4238 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4239 }
4240 }
4241
4242 fn send_lsp_proto_request<R: LspCommand>(
4243 &self,
4244 buffer: Entity<Buffer>,
4245 client: AnyProtoClient,
4246 upstream_project_id: u64,
4247 request: R,
4248 cx: &mut Context<LspStore>,
4249 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4250 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4251 return Task::ready(Ok(R::Response::default()));
4252 }
4253 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4254 cx.spawn(async move |this, cx| {
4255 let response = client.request(message).await?;
4256 let this = this.upgrade().context("project dropped")?;
4257 request
4258 .response_from_proto(response, this, buffer, cx.clone())
4259 .await
4260 })
4261 }
4262
4263 pub(super) fn new_remote(
4264 buffer_store: Entity<BufferStore>,
4265 worktree_store: Entity<WorktreeStore>,
4266 languages: Arc<LanguageRegistry>,
4267 upstream_client: AnyProtoClient,
4268 project_id: u64,
4269 cx: &mut Context<Self>,
4270 ) -> Self {
4271 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4272 .detach();
4273 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4274 .detach();
4275 subscribe_to_binary_statuses(&languages, cx).detach();
4276 let _maintain_workspace_config = {
4277 let (sender, receiver) = watch::channel();
4278 (Self::maintain_workspace_config(receiver, cx), sender)
4279 };
4280 Self {
4281 mode: LspStoreMode::Remote(RemoteLspStore {
4282 upstream_client: Some(upstream_client),
4283 upstream_project_id: project_id,
4284 }),
4285 downstream_client: None,
4286 last_formatting_failure: None,
4287 buffer_store,
4288 worktree_store,
4289 languages: languages.clone(),
4290 language_server_statuses: Default::default(),
4291 nonce: StdRng::from_os_rng().random(),
4292 diagnostic_summaries: HashMap::default(),
4293 lsp_server_capabilities: HashMap::default(),
4294 semantic_token_config: SemanticTokenConfig::new(cx),
4295 next_hint_id: Arc::default(),
4296 lsp_data: HashMap::default(),
4297 active_entry: None,
4298
4299 _maintain_workspace_config,
4300 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4301 }
4302 }
4303
4304 fn on_buffer_store_event(
4305 &mut self,
4306 _: Entity<BufferStore>,
4307 event: &BufferStoreEvent,
4308 cx: &mut Context<Self>,
4309 ) {
4310 match event {
4311 BufferStoreEvent::BufferAdded(buffer) => {
4312 self.on_buffer_added(buffer, cx).log_err();
4313 }
4314 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4315 let buffer_id = buffer.read(cx).remote_id();
4316 if let Some(local) = self.as_local_mut()
4317 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4318 {
4319 local.reset_buffer(buffer, old_file, cx);
4320
4321 if local.registered_buffers.contains_key(&buffer_id) {
4322 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4323 }
4324 }
4325
4326 self.detect_language_for_buffer(buffer, cx);
4327 if let Some(local) = self.as_local_mut() {
4328 local.initialize_buffer(buffer, cx);
4329 if local.registered_buffers.contains_key(&buffer_id) {
4330 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4331 }
4332 }
4333 }
4334 _ => {}
4335 }
4336 }
4337
4338 fn on_worktree_store_event(
4339 &mut self,
4340 _: Entity<WorktreeStore>,
4341 event: &WorktreeStoreEvent,
4342 cx: &mut Context<Self>,
4343 ) {
4344 match event {
4345 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4346 if !worktree.read(cx).is_local() {
4347 return;
4348 }
4349 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4350 worktree::Event::UpdatedEntries(changes) => {
4351 this.update_local_worktree_language_servers(&worktree, changes, cx);
4352 }
4353 worktree::Event::UpdatedGitRepositories(_)
4354 | worktree::Event::DeletedEntry(_) => {}
4355 })
4356 .detach()
4357 }
4358 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4359 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4360 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4361 }
4362 WorktreeStoreEvent::WorktreeReleased(..)
4363 | WorktreeStoreEvent::WorktreeOrderChanged
4364 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4365 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4366 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4367 }
4368 }
4369
4370 fn on_prettier_store_event(
4371 &mut self,
4372 _: Entity<PrettierStore>,
4373 event: &PrettierStoreEvent,
4374 cx: &mut Context<Self>,
4375 ) {
4376 match event {
4377 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4378 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4379 }
4380 PrettierStoreEvent::LanguageServerAdded {
4381 new_server_id,
4382 name,
4383 prettier_server,
4384 } => {
4385 self.register_supplementary_language_server(
4386 *new_server_id,
4387 name.clone(),
4388 prettier_server.clone(),
4389 cx,
4390 );
4391 }
4392 }
4393 }
4394
4395 fn on_toolchain_store_event(
4396 &mut self,
4397 _: Entity<LocalToolchainStore>,
4398 event: &ToolchainStoreEvent,
4399 _: &mut Context<Self>,
4400 ) {
4401 if let ToolchainStoreEvent::ToolchainActivated = event {
4402 self.request_workspace_config_refresh()
4403 }
4404 }
4405
4406 fn request_workspace_config_refresh(&mut self) {
4407 *self._maintain_workspace_config.1.borrow_mut() = ();
4408 }
4409
4410 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4411 self.as_local().map(|local| local.prettier_store.clone())
4412 }
4413
4414 fn on_buffer_event(
4415 &mut self,
4416 buffer: Entity<Buffer>,
4417 event: &language::BufferEvent,
4418 cx: &mut Context<Self>,
4419 ) {
4420 match event {
4421 language::BufferEvent::Edited => {
4422 self.on_buffer_edited(buffer, cx);
4423 }
4424
4425 language::BufferEvent::Saved => {
4426 self.on_buffer_saved(buffer, cx);
4427 }
4428
4429 _ => {}
4430 }
4431 }
4432
4433 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4434 buffer
4435 .read(cx)
4436 .set_language_registry(self.languages.clone());
4437
4438 cx.subscribe(buffer, |this, buffer, event, cx| {
4439 this.on_buffer_event(buffer, event, cx);
4440 })
4441 .detach();
4442
4443 self.detect_language_for_buffer(buffer, cx);
4444 if let Some(local) = self.as_local_mut() {
4445 local.initialize_buffer(buffer, cx);
4446 }
4447
4448 Ok(())
4449 }
4450
4451 pub fn refresh_background_diagnostics_for_buffers(
4452 &mut self,
4453 buffers: HashSet<BufferId>,
4454 cx: &mut Context<Self>,
4455 ) -> Shared<Task<()>> {
4456 let Some(local) = self.as_local_mut() else {
4457 return Task::ready(()).shared();
4458 };
4459 for buffer in buffers {
4460 if local.buffers_to_refresh_hash_set.insert(buffer) {
4461 local.buffers_to_refresh_queue.push_back(buffer);
4462 if local.buffers_to_refresh_queue.len() == 1 {
4463 local._background_diagnostics_worker =
4464 Self::background_diagnostics_worker(cx).shared();
4465 }
4466 }
4467 }
4468
4469 local._background_diagnostics_worker.clone()
4470 }
4471
4472 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4473 let buffer_store = self.buffer_store.clone();
4474 let local = self.as_local_mut()?;
4475 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4476 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4477 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4478 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4479 }
4480 }
4481 None
4482 }
4483
4484 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4485 cx.spawn(async move |this, cx| {
4486 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4487 task.await.log_err();
4488 }
4489 })
4490 }
4491
4492 pub(crate) fn register_buffer_with_language_servers(
4493 &mut self,
4494 buffer: &Entity<Buffer>,
4495 only_register_servers: HashSet<LanguageServerSelector>,
4496 ignore_refcounts: bool,
4497 cx: &mut Context<Self>,
4498 ) -> OpenLspBufferHandle {
4499 let buffer_id = buffer.read(cx).remote_id();
4500 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4501 if let Some(local) = self.as_local_mut() {
4502 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4503 if !ignore_refcounts {
4504 *refcount += 1;
4505 }
4506
4507 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4508 // 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
4509 // 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
4510 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4511 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4512 return handle;
4513 };
4514 if !file.is_local() {
4515 return handle;
4516 }
4517
4518 if ignore_refcounts || *refcount == 1 {
4519 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4520 }
4521 if !ignore_refcounts {
4522 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4523 let refcount = {
4524 let local = lsp_store.as_local_mut().unwrap();
4525 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4526 debug_panic!("bad refcounting");
4527 return;
4528 };
4529
4530 *refcount -= 1;
4531 *refcount
4532 };
4533 if refcount == 0 {
4534 lsp_store.lsp_data.remove(&buffer_id);
4535 let local = lsp_store.as_local_mut().unwrap();
4536 local.registered_buffers.remove(&buffer_id);
4537
4538 local.buffers_opened_in_servers.remove(&buffer_id);
4539 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4540 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4541
4542 let buffer_abs_path = file.abs_path(cx);
4543 for (_, buffer_pull_diagnostics_result_ids) in
4544 &mut local.buffer_pull_diagnostics_result_ids
4545 {
4546 buffer_pull_diagnostics_result_ids.retain(
4547 |_, buffer_result_ids| {
4548 buffer_result_ids.remove(&buffer_abs_path);
4549 !buffer_result_ids.is_empty()
4550 },
4551 );
4552 }
4553
4554 let diagnostic_updates = local
4555 .language_servers
4556 .keys()
4557 .cloned()
4558 .map(|server_id| DocumentDiagnosticsUpdate {
4559 diagnostics: DocumentDiagnostics {
4560 document_abs_path: buffer_abs_path.clone(),
4561 version: None,
4562 diagnostics: Vec::new(),
4563 },
4564 result_id: None,
4565 registration_id: None,
4566 server_id,
4567 disk_based_sources: Cow::Borrowed(&[]),
4568 })
4569 .collect::<Vec<_>>();
4570
4571 lsp_store
4572 .merge_diagnostic_entries(
4573 diagnostic_updates,
4574 |_, diagnostic, _| {
4575 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4576 },
4577 cx,
4578 )
4579 .context("Clearing diagnostics for the closed buffer")
4580 .log_err();
4581 }
4582 }
4583 })
4584 .detach();
4585 }
4586 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4587 let buffer_id = buffer.read(cx).remote_id().to_proto();
4588 cx.background_spawn(async move {
4589 upstream_client
4590 .request(proto::RegisterBufferWithLanguageServers {
4591 project_id: upstream_project_id,
4592 buffer_id,
4593 only_servers: only_register_servers
4594 .into_iter()
4595 .map(|selector| {
4596 let selector = match selector {
4597 LanguageServerSelector::Id(language_server_id) => {
4598 proto::language_server_selector::Selector::ServerId(
4599 language_server_id.to_proto(),
4600 )
4601 }
4602 LanguageServerSelector::Name(language_server_name) => {
4603 proto::language_server_selector::Selector::Name(
4604 language_server_name.to_string(),
4605 )
4606 }
4607 };
4608 proto::LanguageServerSelector {
4609 selector: Some(selector),
4610 }
4611 })
4612 .collect(),
4613 })
4614 .await
4615 })
4616 .detach();
4617 } else {
4618 // Our remote connection got closed
4619 }
4620 handle
4621 }
4622
4623 fn maintain_buffer_languages(
4624 languages: Arc<LanguageRegistry>,
4625 cx: &mut Context<Self>,
4626 ) -> Task<()> {
4627 let mut subscription = languages.subscribe();
4628 let mut prev_reload_count = languages.reload_count();
4629 cx.spawn(async move |this, cx| {
4630 while let Some(()) = subscription.next().await {
4631 if let Some(this) = this.upgrade() {
4632 // If the language registry has been reloaded, then remove and
4633 // re-assign the languages on all open buffers.
4634 let reload_count = languages.reload_count();
4635 if reload_count > prev_reload_count {
4636 prev_reload_count = reload_count;
4637 this.update(cx, |this, cx| {
4638 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4639 for buffer in buffer_store.buffers() {
4640 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4641 {
4642 buffer.update(cx, |buffer, cx| {
4643 buffer.set_language_async(None, cx)
4644 });
4645 if let Some(local) = this.as_local_mut() {
4646 local.reset_buffer(&buffer, &f, cx);
4647
4648 if local
4649 .registered_buffers
4650 .contains_key(&buffer.read(cx).remote_id())
4651 && let Some(file_url) =
4652 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4653 {
4654 local.unregister_buffer_from_language_servers(
4655 &buffer, &file_url, cx,
4656 );
4657 }
4658 }
4659 }
4660 }
4661 });
4662 });
4663 }
4664
4665 this.update(cx, |this, cx| {
4666 let mut plain_text_buffers = Vec::new();
4667 let mut buffers_with_unknown_injections = Vec::new();
4668 for handle in this.buffer_store.read(cx).buffers() {
4669 let buffer = handle.read(cx);
4670 if buffer.language().is_none()
4671 || buffer.language() == Some(&*language::PLAIN_TEXT)
4672 {
4673 plain_text_buffers.push(handle);
4674 } else if buffer.contains_unknown_injections() {
4675 buffers_with_unknown_injections.push(handle);
4676 }
4677 }
4678
4679 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4680 // and reused later in the invisible worktrees.
4681 plain_text_buffers.sort_by_key(|buffer| {
4682 Reverse(
4683 File::from_dyn(buffer.read(cx).file())
4684 .map(|file| file.worktree.read(cx).is_visible()),
4685 )
4686 });
4687
4688 for buffer in plain_text_buffers {
4689 this.detect_language_for_buffer(&buffer, cx);
4690 if let Some(local) = this.as_local_mut() {
4691 local.initialize_buffer(&buffer, cx);
4692 if local
4693 .registered_buffers
4694 .contains_key(&buffer.read(cx).remote_id())
4695 {
4696 local.register_buffer_with_language_servers(
4697 &buffer,
4698 HashSet::default(),
4699 cx,
4700 );
4701 }
4702 }
4703 }
4704
4705 for buffer in buffers_with_unknown_injections {
4706 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4707 }
4708 });
4709 }
4710 }
4711 })
4712 }
4713
4714 fn detect_language_for_buffer(
4715 &mut self,
4716 buffer_handle: &Entity<Buffer>,
4717 cx: &mut Context<Self>,
4718 ) -> Option<language::AvailableLanguage> {
4719 // If the buffer has a language, set it and start the language server if we haven't already.
4720 let buffer = buffer_handle.read(cx);
4721 let file = buffer.file()?;
4722
4723 let content = buffer.as_rope();
4724 let available_language = self.languages.language_for_file(file, Some(content), cx);
4725 if let Some(available_language) = &available_language {
4726 if let Some(Ok(Ok(new_language))) = self
4727 .languages
4728 .load_language(available_language)
4729 .now_or_never()
4730 {
4731 self.set_language_for_buffer(buffer_handle, new_language, cx);
4732 }
4733 } else {
4734 cx.emit(LspStoreEvent::LanguageDetected {
4735 buffer: buffer_handle.clone(),
4736 new_language: None,
4737 });
4738 }
4739
4740 available_language
4741 }
4742
4743 pub(crate) fn set_language_for_buffer(
4744 &mut self,
4745 buffer_entity: &Entity<Buffer>,
4746 new_language: Arc<Language>,
4747 cx: &mut Context<Self>,
4748 ) {
4749 let buffer = buffer_entity.read(cx);
4750 let buffer_file = buffer.file().cloned();
4751 let buffer_id = buffer.remote_id();
4752 if let Some(local_store) = self.as_local_mut()
4753 && local_store.registered_buffers.contains_key(&buffer_id)
4754 && let Some(abs_path) =
4755 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4756 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4757 {
4758 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4759 }
4760 buffer_entity.update(cx, |buffer, cx| {
4761 if buffer
4762 .language()
4763 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4764 {
4765 buffer.set_language_async(Some(new_language.clone()), cx);
4766 }
4767 });
4768
4769 let settings =
4770 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4771 let buffer_file = File::from_dyn(buffer_file.as_ref());
4772
4773 let worktree_id = if let Some(file) = buffer_file {
4774 let worktree = file.worktree.clone();
4775
4776 if let Some(local) = self.as_local_mut()
4777 && local.registered_buffers.contains_key(&buffer_id)
4778 {
4779 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4780 }
4781 Some(worktree.read(cx).id())
4782 } else {
4783 None
4784 };
4785
4786 if settings.prettier.allowed
4787 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4788 {
4789 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4790 if let Some(prettier_store) = prettier_store {
4791 prettier_store.update(cx, |prettier_store, cx| {
4792 prettier_store.install_default_prettier(
4793 worktree_id,
4794 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4795 cx,
4796 )
4797 })
4798 }
4799 }
4800
4801 cx.emit(LspStoreEvent::LanguageDetected {
4802 buffer: buffer_entity.clone(),
4803 new_language: Some(new_language),
4804 })
4805 }
4806
4807 pub fn buffer_store(&self) -> Entity<BufferStore> {
4808 self.buffer_store.clone()
4809 }
4810
4811 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4812 self.active_entry = active_entry;
4813 }
4814
4815 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4816 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4817 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4818 {
4819 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4820 summaries
4821 .iter()
4822 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4823 });
4824 if let Some(summary) = summaries.next() {
4825 client
4826 .send(proto::UpdateDiagnosticSummary {
4827 project_id: downstream_project_id,
4828 worktree_id: worktree.id().to_proto(),
4829 summary: Some(summary),
4830 more_summaries: summaries.collect(),
4831 })
4832 .log_err();
4833 }
4834 }
4835 }
4836
4837 fn is_capable_for_proto_request<R>(
4838 &self,
4839 buffer: &Entity<Buffer>,
4840 request: &R,
4841 cx: &App,
4842 ) -> bool
4843 where
4844 R: LspCommand,
4845 {
4846 self.check_if_capable_for_proto_request(
4847 buffer,
4848 |capabilities| {
4849 request.check_capabilities(AdapterServerCapabilities {
4850 server_capabilities: capabilities.clone(),
4851 code_action_kinds: None,
4852 })
4853 },
4854 cx,
4855 )
4856 }
4857
4858 fn check_if_capable_for_proto_request<F>(
4859 &self,
4860 buffer: &Entity<Buffer>,
4861 check: F,
4862 cx: &App,
4863 ) -> bool
4864 where
4865 F: FnMut(&lsp::ServerCapabilities) -> bool,
4866 {
4867 let Some(language) = buffer.read(cx).language().cloned() else {
4868 return false;
4869 };
4870 let registered_language_servers = self
4871 .languages
4872 .lsp_adapters(&language.name())
4873 .into_iter()
4874 .map(|lsp_adapter| lsp_adapter.name())
4875 .collect::<HashSet<_>>();
4876 self.language_server_statuses
4877 .iter()
4878 .filter_map(|(server_id, server_status)| {
4879 // Include servers that are either registered for this language OR
4880 // available to be loaded (for SSH remote mode where adapters like
4881 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4882 // but only loaded on the server side)
4883 let is_relevant = registered_language_servers.contains(&server_status.name)
4884 || self.languages.is_lsp_adapter_available(&server_status.name);
4885 is_relevant.then_some(server_id)
4886 })
4887 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4888 .any(check)
4889 }
4890
4891 fn all_capable_for_proto_request<F>(
4892 &self,
4893 buffer: &Entity<Buffer>,
4894 mut check: F,
4895 cx: &App,
4896 ) -> Vec<lsp::LanguageServerId>
4897 where
4898 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4899 {
4900 let Some(language) = buffer.read(cx).language().cloned() else {
4901 return Vec::default();
4902 };
4903 let registered_language_servers = self
4904 .languages
4905 .lsp_adapters(&language.name())
4906 .into_iter()
4907 .map(|lsp_adapter| lsp_adapter.name())
4908 .collect::<HashSet<_>>();
4909 self.language_server_statuses
4910 .iter()
4911 .filter_map(|(server_id, server_status)| {
4912 // Include servers that are either registered for this language OR
4913 // available to be loaded (for SSH remote mode where adapters like
4914 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4915 // but only loaded on the server side)
4916 let is_relevant = registered_language_servers.contains(&server_status.name)
4917 || self.languages.is_lsp_adapter_available(&server_status.name);
4918 is_relevant.then_some((server_id, &server_status.name))
4919 })
4920 .filter_map(|(server_id, server_name)| {
4921 self.lsp_server_capabilities
4922 .get(server_id)
4923 .map(|c| (server_id, server_name, c))
4924 })
4925 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4926 .map(|(server_id, _, _)| *server_id)
4927 .collect()
4928 }
4929
4930 pub fn request_lsp<R>(
4931 &mut self,
4932 buffer: Entity<Buffer>,
4933 server: LanguageServerToQuery,
4934 request: R,
4935 cx: &mut Context<Self>,
4936 ) -> Task<Result<R::Response>>
4937 where
4938 R: LspCommand,
4939 <R::LspRequest as lsp::request::Request>::Result: Send,
4940 <R::LspRequest as lsp::request::Request>::Params: Send,
4941 {
4942 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4943 return self.send_lsp_proto_request(
4944 buffer,
4945 upstream_client,
4946 upstream_project_id,
4947 request,
4948 cx,
4949 );
4950 }
4951
4952 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4953 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4954 local
4955 .language_servers_for_buffer(buffer, cx)
4956 .find(|(_, server)| {
4957 request.check_capabilities(server.adapter_server_capabilities())
4958 })
4959 .map(|(_, server)| server.clone())
4960 }),
4961 LanguageServerToQuery::Other(id) => self
4962 .language_server_for_local_buffer(buffer, id, cx)
4963 .and_then(|(_, server)| {
4964 request
4965 .check_capabilities(server.adapter_server_capabilities())
4966 .then(|| Arc::clone(server))
4967 }),
4968 }) else {
4969 return Task::ready(Ok(Default::default()));
4970 };
4971
4972 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4973
4974 let Some(file) = file else {
4975 return Task::ready(Ok(Default::default()));
4976 };
4977
4978 let lsp_params = match request.to_lsp_params_or_response(
4979 &file.abs_path(cx),
4980 buffer.read(cx),
4981 &language_server,
4982 cx,
4983 ) {
4984 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4985 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4986 Err(err) => {
4987 let message = format!(
4988 "{} via {} failed: {}",
4989 request.display_name(),
4990 language_server.name(),
4991 err
4992 );
4993 // rust-analyzer likes to error with this when its still loading up
4994 if !message.ends_with("content modified") {
4995 log::warn!("{message}");
4996 }
4997 return Task::ready(Err(anyhow!(message)));
4998 }
4999 };
5000
5001 let status = request.status();
5002 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
5003 return Task::ready(Ok(Default::default()));
5004 }
5005
5006 let request_timeout = ProjectSettings::get_global(cx)
5007 .global_lsp_settings
5008 .get_request_timeout();
5009
5010 cx.spawn(async move |this, cx| {
5011 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5012
5013 let id = lsp_request.id();
5014 let _cleanup = if status.is_some() {
5015 cx.update(|cx| {
5016 this.update(cx, |this, cx| {
5017 this.on_lsp_work_start(
5018 language_server.server_id(),
5019 ProgressToken::Number(id),
5020 LanguageServerProgress {
5021 is_disk_based_diagnostics_progress: false,
5022 is_cancellable: false,
5023 title: None,
5024 message: status.clone(),
5025 percentage: None,
5026 last_update_at: cx.background_executor().now(),
5027 },
5028 cx,
5029 );
5030 })
5031 })
5032 .log_err();
5033
5034 Some(defer(|| {
5035 cx.update(|cx| {
5036 this.update(cx, |this, cx| {
5037 this.on_lsp_work_end(
5038 language_server.server_id(),
5039 ProgressToken::Number(id),
5040 cx,
5041 );
5042 })
5043 })
5044 .log_err();
5045 }))
5046 } else {
5047 None
5048 };
5049
5050 let result = lsp_request.await.into_response();
5051
5052 let response = result.map_err(|err| {
5053 let message = format!(
5054 "{} via {} failed: {}",
5055 request.display_name(),
5056 language_server.name(),
5057 err
5058 );
5059 // rust-analyzer likes to error with this when its still loading up
5060 if !message.ends_with("content modified") {
5061 log::warn!("{message}");
5062 }
5063 anyhow::anyhow!(message)
5064 })?;
5065
5066 request
5067 .response_from_lsp(
5068 response,
5069 this.upgrade().context("no app context")?,
5070 buffer,
5071 language_server.server_id(),
5072 cx.clone(),
5073 )
5074 .await
5075 })
5076 }
5077
5078 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5079 let mut language_formatters_to_check = Vec::new();
5080 for buffer in self.buffer_store.read(cx).buffers() {
5081 let buffer = buffer.read(cx);
5082 let buffer_file = File::from_dyn(buffer.file());
5083 let buffer_language = buffer.language();
5084 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5085 if buffer_language.is_some() {
5086 language_formatters_to_check.push((
5087 buffer_file.map(|f| f.worktree_id(cx)),
5088 settings.into_owned(),
5089 ));
5090 }
5091 }
5092
5093 self.request_workspace_config_refresh();
5094
5095 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5096 prettier_store.update(cx, |prettier_store, cx| {
5097 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5098 })
5099 }
5100
5101 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5102 .global_lsp_settings
5103 .semantic_token_rules
5104 .clone();
5105 self.semantic_token_config
5106 .update_rules(new_semantic_token_rules);
5107
5108 let new_global_semantic_tokens_mode =
5109 all_language_settings(None, cx).defaults.semantic_tokens;
5110 if self
5111 .semantic_token_config
5112 .update_global_mode(new_global_semantic_tokens_mode)
5113 {
5114 self.restart_all_language_servers(cx);
5115 }
5116
5117 cx.notify();
5118 }
5119
5120 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5121 let buffer_store = self.buffer_store.clone();
5122 let Some(local) = self.as_local_mut() else {
5123 return;
5124 };
5125 let mut adapters = BTreeMap::default();
5126 let get_adapter = {
5127 let languages = local.languages.clone();
5128 let environment = local.environment.clone();
5129 let weak = local.weak.clone();
5130 let worktree_store = local.worktree_store.clone();
5131 let http_client = local.http_client.clone();
5132 let fs = local.fs.clone();
5133 move |worktree_id, cx: &mut App| {
5134 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5135 Some(LocalLspAdapterDelegate::new(
5136 languages.clone(),
5137 &environment,
5138 weak.clone(),
5139 &worktree,
5140 http_client.clone(),
5141 fs.clone(),
5142 cx,
5143 ))
5144 }
5145 };
5146
5147 let mut messages_to_report = Vec::new();
5148 let (new_tree, to_stop) = {
5149 let mut rebase = local.lsp_tree.rebase();
5150 let buffers = buffer_store
5151 .read(cx)
5152 .buffers()
5153 .filter_map(|buffer| {
5154 let raw_buffer = buffer.read(cx);
5155 if !local
5156 .registered_buffers
5157 .contains_key(&raw_buffer.remote_id())
5158 {
5159 return None;
5160 }
5161 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5162 let language = raw_buffer.language().cloned()?;
5163 Some((file, language, raw_buffer.remote_id()))
5164 })
5165 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5166 for (file, language, buffer_id) in buffers {
5167 let worktree_id = file.worktree_id(cx);
5168 let Some(worktree) = local
5169 .worktree_store
5170 .read(cx)
5171 .worktree_for_id(worktree_id, cx)
5172 else {
5173 continue;
5174 };
5175
5176 if let Some((_, apply)) = local.reuse_existing_language_server(
5177 rebase.server_tree(),
5178 &worktree,
5179 &language.name(),
5180 cx,
5181 ) {
5182 (apply)(rebase.server_tree());
5183 } else if let Some(lsp_delegate) = adapters
5184 .entry(worktree_id)
5185 .or_insert_with(|| get_adapter(worktree_id, cx))
5186 .clone()
5187 {
5188 let delegate =
5189 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5190 let path = file
5191 .path()
5192 .parent()
5193 .map(Arc::from)
5194 .unwrap_or_else(|| file.path().clone());
5195 let worktree_path = ProjectPath { worktree_id, path };
5196 let abs_path = file.abs_path(cx);
5197 let nodes = rebase
5198 .walk(
5199 worktree_path,
5200 language.name(),
5201 language.manifest(),
5202 delegate.clone(),
5203 cx,
5204 )
5205 .collect::<Vec<_>>();
5206 for node in nodes {
5207 let server_id = node.server_id_or_init(|disposition| {
5208 let path = &disposition.path;
5209 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5210 let key = LanguageServerSeed {
5211 worktree_id,
5212 name: disposition.server_name.clone(),
5213 settings: LanguageServerSeedSettings {
5214 binary: disposition.settings.binary.clone(),
5215 initialization_options: disposition
5216 .settings
5217 .initialization_options
5218 .clone(),
5219 },
5220 toolchain: local.toolchain_store.read(cx).active_toolchain(
5221 path.worktree_id,
5222 &path.path,
5223 language.name(),
5224 ),
5225 };
5226 local.language_server_ids.remove(&key);
5227
5228 let server_id = local.get_or_insert_language_server(
5229 &worktree,
5230 lsp_delegate.clone(),
5231 disposition,
5232 &language.name(),
5233 cx,
5234 );
5235 if let Some(state) = local.language_servers.get(&server_id)
5236 && let Ok(uri) = uri
5237 {
5238 state.add_workspace_folder(uri);
5239 };
5240 server_id
5241 });
5242
5243 if let Some(language_server_id) = server_id {
5244 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5245 language_server_id,
5246 name: node.name(),
5247 message:
5248 proto::update_language_server::Variant::RegisteredForBuffer(
5249 proto::RegisteredForBuffer {
5250 buffer_abs_path: abs_path
5251 .to_string_lossy()
5252 .into_owned(),
5253 buffer_id: buffer_id.to_proto(),
5254 },
5255 ),
5256 });
5257 }
5258 }
5259 } else {
5260 continue;
5261 }
5262 }
5263 rebase.finish()
5264 };
5265 for message in messages_to_report {
5266 cx.emit(message);
5267 }
5268 local.lsp_tree = new_tree;
5269 for (id, _) in to_stop {
5270 self.stop_local_language_server(id, cx).detach();
5271 }
5272 }
5273
5274 pub fn apply_code_action(
5275 &self,
5276 buffer_handle: Entity<Buffer>,
5277 mut action: CodeAction,
5278 push_to_history: bool,
5279 cx: &mut Context<Self>,
5280 ) -> Task<Result<ProjectTransaction>> {
5281 if let Some((upstream_client, project_id)) = self.upstream_client() {
5282 let request = proto::ApplyCodeAction {
5283 project_id,
5284 buffer_id: buffer_handle.read(cx).remote_id().into(),
5285 action: Some(Self::serialize_code_action(&action)),
5286 };
5287 let buffer_store = self.buffer_store();
5288 cx.spawn(async move |_, cx| {
5289 let response = upstream_client
5290 .request(request)
5291 .await?
5292 .transaction
5293 .context("missing transaction")?;
5294
5295 buffer_store
5296 .update(cx, |buffer_store, cx| {
5297 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5298 })
5299 .await
5300 })
5301 } else if self.mode.is_local() {
5302 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5303 let request_timeout = ProjectSettings::get_global(cx)
5304 .global_lsp_settings
5305 .get_request_timeout();
5306 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5307 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5308 }) else {
5309 return Task::ready(Ok(ProjectTransaction::default()));
5310 };
5311
5312 cx.spawn(async move |this, cx| {
5313 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5314 .await
5315 .context("resolving a code action")?;
5316 if let Some(edit) = action.lsp_action.edit()
5317 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5318 return LocalLspStore::deserialize_workspace_edit(
5319 this.upgrade().context("no app present")?,
5320 edit.clone(),
5321 push_to_history,
5322
5323 lang_server.clone(),
5324 cx,
5325 )
5326 .await;
5327 }
5328
5329 let Some(command) = action.lsp_action.command() else {
5330 return Ok(ProjectTransaction::default())
5331 };
5332
5333 let server_capabilities = lang_server.capabilities();
5334 let available_commands = server_capabilities
5335 .execute_command_provider
5336 .as_ref()
5337 .map(|options| options.commands.as_slice())
5338 .unwrap_or_default();
5339
5340 if !available_commands.contains(&command.command) {
5341 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5342 return Ok(ProjectTransaction::default())
5343 }
5344
5345 let request_timeout = cx.update(|app|
5346 ProjectSettings::get_global(app)
5347 .global_lsp_settings
5348 .get_request_timeout()
5349 );
5350
5351 this.update(cx, |this, _| {
5352 this.as_local_mut()
5353 .unwrap()
5354 .last_workspace_edits_by_language_server
5355 .remove(&lang_server.server_id());
5356 })?;
5357
5358 let _result = lang_server
5359 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5360 command: command.command.clone(),
5361 arguments: command.arguments.clone().unwrap_or_default(),
5362 ..lsp::ExecuteCommandParams::default()
5363 }, request_timeout)
5364 .await.into_response()
5365 .context("execute command")?;
5366
5367 return this.update(cx, |this, _| {
5368 this.as_local_mut()
5369 .unwrap()
5370 .last_workspace_edits_by_language_server
5371 .remove(&lang_server.server_id())
5372 .unwrap_or_default()
5373 });
5374 })
5375 } else {
5376 Task::ready(Err(anyhow!("no upstream client and not local")))
5377 }
5378 }
5379
5380 pub fn apply_code_action_kind(
5381 &mut self,
5382 buffers: HashSet<Entity<Buffer>>,
5383 kind: CodeActionKind,
5384 push_to_history: bool,
5385 cx: &mut Context<Self>,
5386 ) -> Task<anyhow::Result<ProjectTransaction>> {
5387 if self.as_local().is_some() {
5388 cx.spawn(async move |lsp_store, cx| {
5389 let buffers = buffers.into_iter().collect::<Vec<_>>();
5390 let result = LocalLspStore::execute_code_action_kind_locally(
5391 lsp_store.clone(),
5392 buffers,
5393 kind,
5394 push_to_history,
5395 cx,
5396 )
5397 .await;
5398 lsp_store.update(cx, |lsp_store, _| {
5399 lsp_store.update_last_formatting_failure(&result);
5400 })?;
5401 result
5402 })
5403 } else if let Some((client, project_id)) = self.upstream_client() {
5404 let buffer_store = self.buffer_store();
5405 cx.spawn(async move |lsp_store, cx| {
5406 let result = client
5407 .request(proto::ApplyCodeActionKind {
5408 project_id,
5409 kind: kind.as_str().to_owned(),
5410 buffer_ids: buffers
5411 .iter()
5412 .map(|buffer| {
5413 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5414 })
5415 .collect(),
5416 })
5417 .await
5418 .and_then(|result| result.transaction.context("missing transaction"));
5419 lsp_store.update(cx, |lsp_store, _| {
5420 lsp_store.update_last_formatting_failure(&result);
5421 })?;
5422
5423 let transaction_response = result?;
5424 buffer_store
5425 .update(cx, |buffer_store, cx| {
5426 buffer_store.deserialize_project_transaction(
5427 transaction_response,
5428 push_to_history,
5429 cx,
5430 )
5431 })
5432 .await
5433 })
5434 } else {
5435 Task::ready(Ok(ProjectTransaction::default()))
5436 }
5437 }
5438
5439 pub fn resolved_hint(
5440 &mut self,
5441 buffer_id: BufferId,
5442 id: InlayId,
5443 cx: &mut Context<Self>,
5444 ) -> Option<ResolvedHint> {
5445 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5446
5447 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5448 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5449 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5450 let (server_id, resolve_data) = match &hint.resolve_state {
5451 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5452 ResolveState::Resolving => {
5453 return Some(ResolvedHint::Resolving(
5454 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5455 ));
5456 }
5457 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5458 };
5459
5460 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5461 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5462 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5463 id,
5464 cx.spawn(async move |lsp_store, cx| {
5465 let resolved_hint = resolve_task.await;
5466 lsp_store
5467 .update(cx, |lsp_store, _| {
5468 if let Some(old_inlay_hint) = lsp_store
5469 .lsp_data
5470 .get_mut(&buffer_id)
5471 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5472 {
5473 match resolved_hint {
5474 Ok(resolved_hint) => {
5475 *old_inlay_hint = resolved_hint;
5476 }
5477 Err(e) => {
5478 old_inlay_hint.resolve_state =
5479 ResolveState::CanResolve(server_id, resolve_data);
5480 log::error!("Inlay hint resolve failed: {e:#}");
5481 }
5482 }
5483 }
5484 })
5485 .ok();
5486 })
5487 .shared(),
5488 );
5489 debug_assert!(
5490 previous_task.is_none(),
5491 "Did not change hint's resolve state after spawning its resolve"
5492 );
5493 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5494 None
5495 }
5496
5497 pub(crate) fn linked_edits(
5498 &mut self,
5499 buffer: &Entity<Buffer>,
5500 position: Anchor,
5501 cx: &mut Context<Self>,
5502 ) -> Task<Result<Vec<Range<Anchor>>>> {
5503 let snapshot = buffer.read(cx).snapshot();
5504 let scope = snapshot.language_scope_at(position);
5505 let Some(server_id) = self
5506 .as_local()
5507 .and_then(|local| {
5508 buffer.update(cx, |buffer, cx| {
5509 local
5510 .language_servers_for_buffer(buffer, cx)
5511 .filter(|(_, server)| {
5512 LinkedEditingRange::check_server_capabilities(server.capabilities())
5513 })
5514 .filter(|(adapter, _)| {
5515 scope
5516 .as_ref()
5517 .map(|scope| scope.language_allowed(&adapter.name))
5518 .unwrap_or(true)
5519 })
5520 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5521 .next()
5522 })
5523 })
5524 .or_else(|| {
5525 self.upstream_client()
5526 .is_some()
5527 .then_some(LanguageServerToQuery::FirstCapable)
5528 })
5529 .filter(|_| {
5530 maybe!({
5531 let language = buffer.read(cx).language_at(position)?;
5532 Some(
5533 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5534 .linked_edits,
5535 )
5536 }) == Some(true)
5537 })
5538 else {
5539 return Task::ready(Ok(Vec::new()));
5540 };
5541
5542 self.request_lsp(
5543 buffer.clone(),
5544 server_id,
5545 LinkedEditingRange { position },
5546 cx,
5547 )
5548 }
5549
5550 fn apply_on_type_formatting(
5551 &mut self,
5552 buffer: Entity<Buffer>,
5553 position: Anchor,
5554 trigger: String,
5555 cx: &mut Context<Self>,
5556 ) -> Task<Result<Option<Transaction>>> {
5557 if let Some((client, project_id)) = self.upstream_client() {
5558 if !self.check_if_capable_for_proto_request(
5559 &buffer,
5560 |capabilities| {
5561 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5562 },
5563 cx,
5564 ) {
5565 return Task::ready(Ok(None));
5566 }
5567 let request = proto::OnTypeFormatting {
5568 project_id,
5569 buffer_id: buffer.read(cx).remote_id().into(),
5570 position: Some(serialize_anchor(&position)),
5571 trigger,
5572 version: serialize_version(&buffer.read(cx).version()),
5573 };
5574 cx.background_spawn(async move {
5575 client
5576 .request(request)
5577 .await?
5578 .transaction
5579 .map(language::proto::deserialize_transaction)
5580 .transpose()
5581 })
5582 } else if let Some(local) = self.as_local_mut() {
5583 let buffer_id = buffer.read(cx).remote_id();
5584 local.buffers_being_formatted.insert(buffer_id);
5585 cx.spawn(async move |this, cx| {
5586 let _cleanup = defer({
5587 let this = this.clone();
5588 let mut cx = cx.clone();
5589 move || {
5590 this.update(&mut cx, |this, _| {
5591 if let Some(local) = this.as_local_mut() {
5592 local.buffers_being_formatted.remove(&buffer_id);
5593 }
5594 })
5595 .ok();
5596 }
5597 });
5598
5599 buffer
5600 .update(cx, |buffer, _| {
5601 buffer.wait_for_edits(Some(position.timestamp()))
5602 })
5603 .await?;
5604 this.update(cx, |this, cx| {
5605 let position = position.to_point_utf16(buffer.read(cx));
5606 this.on_type_format(buffer, position, trigger, false, cx)
5607 })?
5608 .await
5609 })
5610 } else {
5611 Task::ready(Err(anyhow!("No upstream client or local language server")))
5612 }
5613 }
5614
5615 pub fn on_type_format<T: ToPointUtf16>(
5616 &mut self,
5617 buffer: Entity<Buffer>,
5618 position: T,
5619 trigger: String,
5620 push_to_history: bool,
5621 cx: &mut Context<Self>,
5622 ) -> Task<Result<Option<Transaction>>> {
5623 let position = position.to_point_utf16(buffer.read(cx));
5624 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5625 }
5626
5627 fn on_type_format_impl(
5628 &mut self,
5629 buffer: Entity<Buffer>,
5630 position: PointUtf16,
5631 trigger: String,
5632 push_to_history: bool,
5633 cx: &mut Context<Self>,
5634 ) -> Task<Result<Option<Transaction>>> {
5635 let options = buffer.update(cx, |buffer, cx| {
5636 lsp_command::lsp_formatting_options(
5637 language_settings(
5638 buffer.language_at(position).map(|l| l.name()),
5639 buffer.file(),
5640 cx,
5641 )
5642 .as_ref(),
5643 )
5644 });
5645
5646 cx.spawn(async move |this, cx| {
5647 if let Some(waiter) =
5648 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5649 {
5650 waiter.await?;
5651 }
5652 cx.update(|cx| {
5653 this.update(cx, |this, cx| {
5654 this.request_lsp(
5655 buffer.clone(),
5656 LanguageServerToQuery::FirstCapable,
5657 OnTypeFormatting {
5658 position,
5659 trigger,
5660 options,
5661 push_to_history,
5662 },
5663 cx,
5664 )
5665 })
5666 })?
5667 .await
5668 })
5669 }
5670
5671 pub fn definitions(
5672 &mut self,
5673 buffer: &Entity<Buffer>,
5674 position: PointUtf16,
5675 cx: &mut Context<Self>,
5676 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5677 if let Some((upstream_client, project_id)) = self.upstream_client() {
5678 let request = GetDefinitions { position };
5679 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5680 return Task::ready(Ok(None));
5681 }
5682
5683 let request_timeout = ProjectSettings::get_global(cx)
5684 .global_lsp_settings
5685 .get_request_timeout();
5686
5687 let request_task = upstream_client.request_lsp(
5688 project_id,
5689 None,
5690 request_timeout,
5691 cx.background_executor().clone(),
5692 request.to_proto(project_id, buffer.read(cx)),
5693 );
5694 let buffer = buffer.clone();
5695 cx.spawn(async move |weak_lsp_store, cx| {
5696 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5697 return Ok(None);
5698 };
5699 let Some(responses) = request_task.await? else {
5700 return Ok(None);
5701 };
5702 let actions = join_all(responses.payload.into_iter().map(|response| {
5703 GetDefinitions { position }.response_from_proto(
5704 response.response,
5705 lsp_store.clone(),
5706 buffer.clone(),
5707 cx.clone(),
5708 )
5709 }))
5710 .await;
5711
5712 Ok(Some(
5713 actions
5714 .into_iter()
5715 .collect::<Result<Vec<Vec<_>>>>()?
5716 .into_iter()
5717 .flatten()
5718 .dedup()
5719 .collect(),
5720 ))
5721 })
5722 } else {
5723 let definitions_task = self.request_multiple_lsp_locally(
5724 buffer,
5725 Some(position),
5726 GetDefinitions { position },
5727 cx,
5728 );
5729 cx.background_spawn(async move {
5730 Ok(Some(
5731 definitions_task
5732 .await
5733 .into_iter()
5734 .flat_map(|(_, definitions)| definitions)
5735 .dedup()
5736 .collect(),
5737 ))
5738 })
5739 }
5740 }
5741
5742 pub fn declarations(
5743 &mut self,
5744 buffer: &Entity<Buffer>,
5745 position: PointUtf16,
5746 cx: &mut Context<Self>,
5747 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5748 if let Some((upstream_client, project_id)) = self.upstream_client() {
5749 let request = GetDeclarations { position };
5750 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5751 return Task::ready(Ok(None));
5752 }
5753 let request_timeout = ProjectSettings::get_global(cx)
5754 .global_lsp_settings
5755 .get_request_timeout();
5756 let request_task = upstream_client.request_lsp(
5757 project_id,
5758 None,
5759 request_timeout,
5760 cx.background_executor().clone(),
5761 request.to_proto(project_id, buffer.read(cx)),
5762 );
5763 let buffer = buffer.clone();
5764 cx.spawn(async move |weak_lsp_store, cx| {
5765 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5766 return Ok(None);
5767 };
5768 let Some(responses) = request_task.await? else {
5769 return Ok(None);
5770 };
5771 let actions = join_all(responses.payload.into_iter().map(|response| {
5772 GetDeclarations { position }.response_from_proto(
5773 response.response,
5774 lsp_store.clone(),
5775 buffer.clone(),
5776 cx.clone(),
5777 )
5778 }))
5779 .await;
5780
5781 Ok(Some(
5782 actions
5783 .into_iter()
5784 .collect::<Result<Vec<Vec<_>>>>()?
5785 .into_iter()
5786 .flatten()
5787 .dedup()
5788 .collect(),
5789 ))
5790 })
5791 } else {
5792 let declarations_task = self.request_multiple_lsp_locally(
5793 buffer,
5794 Some(position),
5795 GetDeclarations { position },
5796 cx,
5797 );
5798 cx.background_spawn(async move {
5799 Ok(Some(
5800 declarations_task
5801 .await
5802 .into_iter()
5803 .flat_map(|(_, declarations)| declarations)
5804 .dedup()
5805 .collect(),
5806 ))
5807 })
5808 }
5809 }
5810
5811 pub fn type_definitions(
5812 &mut self,
5813 buffer: &Entity<Buffer>,
5814 position: PointUtf16,
5815 cx: &mut Context<Self>,
5816 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5817 if let Some((upstream_client, project_id)) = self.upstream_client() {
5818 let request = GetTypeDefinitions { position };
5819 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5820 return Task::ready(Ok(None));
5821 }
5822 let request_timeout = ProjectSettings::get_global(cx)
5823 .global_lsp_settings
5824 .get_request_timeout();
5825 let request_task = upstream_client.request_lsp(
5826 project_id,
5827 None,
5828 request_timeout,
5829 cx.background_executor().clone(),
5830 request.to_proto(project_id, buffer.read(cx)),
5831 );
5832 let buffer = buffer.clone();
5833 cx.spawn(async move |weak_lsp_store, cx| {
5834 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5835 return Ok(None);
5836 };
5837 let Some(responses) = request_task.await? else {
5838 return Ok(None);
5839 };
5840 let actions = join_all(responses.payload.into_iter().map(|response| {
5841 GetTypeDefinitions { position }.response_from_proto(
5842 response.response,
5843 lsp_store.clone(),
5844 buffer.clone(),
5845 cx.clone(),
5846 )
5847 }))
5848 .await;
5849
5850 Ok(Some(
5851 actions
5852 .into_iter()
5853 .collect::<Result<Vec<Vec<_>>>>()?
5854 .into_iter()
5855 .flatten()
5856 .dedup()
5857 .collect(),
5858 ))
5859 })
5860 } else {
5861 let type_definitions_task = self.request_multiple_lsp_locally(
5862 buffer,
5863 Some(position),
5864 GetTypeDefinitions { position },
5865 cx,
5866 );
5867 cx.background_spawn(async move {
5868 Ok(Some(
5869 type_definitions_task
5870 .await
5871 .into_iter()
5872 .flat_map(|(_, type_definitions)| type_definitions)
5873 .dedup()
5874 .collect(),
5875 ))
5876 })
5877 }
5878 }
5879
5880 pub fn implementations(
5881 &mut self,
5882 buffer: &Entity<Buffer>,
5883 position: PointUtf16,
5884 cx: &mut Context<Self>,
5885 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5886 if let Some((upstream_client, project_id)) = self.upstream_client() {
5887 let request = GetImplementations { position };
5888 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5889 return Task::ready(Ok(None));
5890 }
5891
5892 let request_timeout = ProjectSettings::get_global(cx)
5893 .global_lsp_settings
5894 .get_request_timeout();
5895 let request_task = upstream_client.request_lsp(
5896 project_id,
5897 None,
5898 request_timeout,
5899 cx.background_executor().clone(),
5900 request.to_proto(project_id, buffer.read(cx)),
5901 );
5902 let buffer = buffer.clone();
5903 cx.spawn(async move |weak_lsp_store, cx| {
5904 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5905 return Ok(None);
5906 };
5907 let Some(responses) = request_task.await? else {
5908 return Ok(None);
5909 };
5910 let actions = join_all(responses.payload.into_iter().map(|response| {
5911 GetImplementations { position }.response_from_proto(
5912 response.response,
5913 lsp_store.clone(),
5914 buffer.clone(),
5915 cx.clone(),
5916 )
5917 }))
5918 .await;
5919
5920 Ok(Some(
5921 actions
5922 .into_iter()
5923 .collect::<Result<Vec<Vec<_>>>>()?
5924 .into_iter()
5925 .flatten()
5926 .dedup()
5927 .collect(),
5928 ))
5929 })
5930 } else {
5931 let implementations_task = self.request_multiple_lsp_locally(
5932 buffer,
5933 Some(position),
5934 GetImplementations { position },
5935 cx,
5936 );
5937 cx.background_spawn(async move {
5938 Ok(Some(
5939 implementations_task
5940 .await
5941 .into_iter()
5942 .flat_map(|(_, implementations)| implementations)
5943 .dedup()
5944 .collect(),
5945 ))
5946 })
5947 }
5948 }
5949
5950 pub fn references(
5951 &mut self,
5952 buffer: &Entity<Buffer>,
5953 position: PointUtf16,
5954 cx: &mut Context<Self>,
5955 ) -> Task<Result<Option<Vec<Location>>>> {
5956 if let Some((upstream_client, project_id)) = self.upstream_client() {
5957 let request = GetReferences { position };
5958 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5959 return Task::ready(Ok(None));
5960 }
5961
5962 let request_timeout = ProjectSettings::get_global(cx)
5963 .global_lsp_settings
5964 .get_request_timeout();
5965 let request_task = upstream_client.request_lsp(
5966 project_id,
5967 None,
5968 request_timeout,
5969 cx.background_executor().clone(),
5970 request.to_proto(project_id, buffer.read(cx)),
5971 );
5972 let buffer = buffer.clone();
5973 cx.spawn(async move |weak_lsp_store, cx| {
5974 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5975 return Ok(None);
5976 };
5977 let Some(responses) = request_task.await? else {
5978 return Ok(None);
5979 };
5980
5981 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5982 GetReferences { position }.response_from_proto(
5983 lsp_response.response,
5984 lsp_store.clone(),
5985 buffer.clone(),
5986 cx.clone(),
5987 )
5988 }))
5989 .await
5990 .into_iter()
5991 .collect::<Result<Vec<Vec<_>>>>()?
5992 .into_iter()
5993 .flatten()
5994 .dedup()
5995 .collect();
5996 Ok(Some(locations))
5997 })
5998 } else {
5999 let references_task = self.request_multiple_lsp_locally(
6000 buffer,
6001 Some(position),
6002 GetReferences { position },
6003 cx,
6004 );
6005 cx.background_spawn(async move {
6006 Ok(Some(
6007 references_task
6008 .await
6009 .into_iter()
6010 .flat_map(|(_, references)| references)
6011 .dedup()
6012 .collect(),
6013 ))
6014 })
6015 }
6016 }
6017
6018 pub fn code_actions(
6019 &mut self,
6020 buffer: &Entity<Buffer>,
6021 range: Range<Anchor>,
6022 kinds: Option<Vec<CodeActionKind>>,
6023 cx: &mut Context<Self>,
6024 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6025 if let Some((upstream_client, project_id)) = self.upstream_client() {
6026 let request = GetCodeActions {
6027 range: range.clone(),
6028 kinds: kinds.clone(),
6029 };
6030 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6031 return Task::ready(Ok(None));
6032 }
6033 let request_timeout = ProjectSettings::get_global(cx)
6034 .global_lsp_settings
6035 .get_request_timeout();
6036 let request_task = upstream_client.request_lsp(
6037 project_id,
6038 None,
6039 request_timeout,
6040 cx.background_executor().clone(),
6041 request.to_proto(project_id, buffer.read(cx)),
6042 );
6043 let buffer = buffer.clone();
6044 cx.spawn(async move |weak_lsp_store, cx| {
6045 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6046 return Ok(None);
6047 };
6048 let Some(responses) = request_task.await? else {
6049 return Ok(None);
6050 };
6051 let actions = join_all(responses.payload.into_iter().map(|response| {
6052 GetCodeActions {
6053 range: range.clone(),
6054 kinds: kinds.clone(),
6055 }
6056 .response_from_proto(
6057 response.response,
6058 lsp_store.clone(),
6059 buffer.clone(),
6060 cx.clone(),
6061 )
6062 }))
6063 .await;
6064
6065 Ok(Some(
6066 actions
6067 .into_iter()
6068 .collect::<Result<Vec<Vec<_>>>>()?
6069 .into_iter()
6070 .flatten()
6071 .collect(),
6072 ))
6073 })
6074 } else {
6075 let all_actions_task = self.request_multiple_lsp_locally(
6076 buffer,
6077 Some(range.start),
6078 GetCodeActions { range, kinds },
6079 cx,
6080 );
6081 cx.background_spawn(async move {
6082 Ok(Some(
6083 all_actions_task
6084 .await
6085 .into_iter()
6086 .flat_map(|(_, actions)| actions)
6087 .collect(),
6088 ))
6089 })
6090 }
6091 }
6092
6093 #[inline(never)]
6094 pub fn completions(
6095 &self,
6096 buffer: &Entity<Buffer>,
6097 position: PointUtf16,
6098 context: CompletionContext,
6099 cx: &mut Context<Self>,
6100 ) -> Task<Result<Vec<CompletionResponse>>> {
6101 let language_registry = self.languages.clone();
6102
6103 if let Some((upstream_client, project_id)) = self.upstream_client() {
6104 let snapshot = buffer.read(cx).snapshot();
6105 let offset = position.to_offset(&snapshot);
6106 let scope = snapshot.language_scope_at(offset);
6107 let capable_lsps = self.all_capable_for_proto_request(
6108 buffer,
6109 |server_name, capabilities| {
6110 capabilities.completion_provider.is_some()
6111 && scope
6112 .as_ref()
6113 .map(|scope| scope.language_allowed(server_name))
6114 .unwrap_or(true)
6115 },
6116 cx,
6117 );
6118 if capable_lsps.is_empty() {
6119 return Task::ready(Ok(Vec::new()));
6120 }
6121
6122 let language = buffer.read(cx).language().cloned();
6123
6124 // In the future, we should provide project guests with the names of LSP adapters,
6125 // so that they can use the correct LSP adapter when computing labels. For now,
6126 // guests just use the first LSP adapter associated with the buffer's language.
6127 let lsp_adapter = language.as_ref().and_then(|language| {
6128 language_registry
6129 .lsp_adapters(&language.name())
6130 .first()
6131 .cloned()
6132 });
6133
6134 let buffer = buffer.clone();
6135
6136 cx.spawn(async move |this, cx| {
6137 let requests = join_all(
6138 capable_lsps
6139 .into_iter()
6140 .map(|id| {
6141 let request = GetCompletions {
6142 position,
6143 context: context.clone(),
6144 server_id: Some(id),
6145 };
6146 let buffer = buffer.clone();
6147 let language = language.clone();
6148 let lsp_adapter = lsp_adapter.clone();
6149 let upstream_client = upstream_client.clone();
6150 let response = this
6151 .update(cx, |this, cx| {
6152 this.send_lsp_proto_request(
6153 buffer,
6154 upstream_client,
6155 project_id,
6156 request,
6157 cx,
6158 )
6159 })
6160 .log_err();
6161 async move {
6162 let response = response?.await.log_err()?;
6163
6164 let completions = populate_labels_for_completions(
6165 response.completions,
6166 language,
6167 lsp_adapter,
6168 )
6169 .await;
6170
6171 Some(CompletionResponse {
6172 completions,
6173 display_options: CompletionDisplayOptions::default(),
6174 is_incomplete: response.is_incomplete,
6175 })
6176 }
6177 })
6178 .collect::<Vec<_>>(),
6179 );
6180 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6181 })
6182 } else if let Some(local) = self.as_local() {
6183 let snapshot = buffer.read(cx).snapshot();
6184 let offset = position.to_offset(&snapshot);
6185 let scope = snapshot.language_scope_at(offset);
6186 let language = snapshot.language().cloned();
6187 let completion_settings = language_settings(
6188 language.as_ref().map(|language| language.name()),
6189 buffer.read(cx).file(),
6190 cx,
6191 )
6192 .completions
6193 .clone();
6194 if !completion_settings.lsp {
6195 return Task::ready(Ok(Vec::new()));
6196 }
6197
6198 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6199 local
6200 .language_servers_for_buffer(buffer, cx)
6201 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6202 .filter(|(adapter, _)| {
6203 scope
6204 .as_ref()
6205 .map(|scope| scope.language_allowed(&adapter.name))
6206 .unwrap_or(true)
6207 })
6208 .map(|(_, server)| server.server_id())
6209 .collect()
6210 });
6211
6212 let buffer = buffer.clone();
6213 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6214 let lsp_timeout = if lsp_timeout > 0 {
6215 Some(Duration::from_millis(lsp_timeout))
6216 } else {
6217 None
6218 };
6219 cx.spawn(async move |this, cx| {
6220 let mut tasks = Vec::with_capacity(server_ids.len());
6221 this.update(cx, |lsp_store, cx| {
6222 for server_id in server_ids {
6223 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6224 let lsp_timeout = lsp_timeout
6225 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6226 let mut timeout = cx.background_spawn(async move {
6227 match lsp_timeout {
6228 Some(lsp_timeout) => {
6229 lsp_timeout.await;
6230 true
6231 },
6232 None => false,
6233 }
6234 }).fuse();
6235 let mut lsp_request = lsp_store.request_lsp(
6236 buffer.clone(),
6237 LanguageServerToQuery::Other(server_id),
6238 GetCompletions {
6239 position,
6240 context: context.clone(),
6241 server_id: Some(server_id),
6242 },
6243 cx,
6244 ).fuse();
6245 let new_task = cx.background_spawn(async move {
6246 select_biased! {
6247 response = lsp_request => anyhow::Ok(Some(response?)),
6248 timeout_happened = timeout => {
6249 if timeout_happened {
6250 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6251 Ok(None)
6252 } else {
6253 let completions = lsp_request.await?;
6254 Ok(Some(completions))
6255 }
6256 },
6257 }
6258 });
6259 tasks.push((lsp_adapter, new_task));
6260 }
6261 })?;
6262
6263 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6264 let completion_response = task.await.ok()??;
6265 let completions = populate_labels_for_completions(
6266 completion_response.completions,
6267 language.clone(),
6268 lsp_adapter,
6269 )
6270 .await;
6271 Some(CompletionResponse {
6272 completions,
6273 display_options: CompletionDisplayOptions::default(),
6274 is_incomplete: completion_response.is_incomplete,
6275 })
6276 });
6277
6278 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6279
6280 Ok(responses.into_iter().flatten().collect())
6281 })
6282 } else {
6283 Task::ready(Err(anyhow!("No upstream client or local language server")))
6284 }
6285 }
6286
6287 pub fn resolve_completions(
6288 &self,
6289 buffer: Entity<Buffer>,
6290 completion_indices: Vec<usize>,
6291 completions: Rc<RefCell<Box<[Completion]>>>,
6292 cx: &mut Context<Self>,
6293 ) -> Task<Result<bool>> {
6294 let client = self.upstream_client();
6295 let buffer_id = buffer.read(cx).remote_id();
6296 let buffer_snapshot = buffer.read(cx).snapshot();
6297
6298 if !self.check_if_capable_for_proto_request(
6299 &buffer,
6300 GetCompletions::can_resolve_completions,
6301 cx,
6302 ) {
6303 return Task::ready(Ok(false));
6304 }
6305 cx.spawn(async move |lsp_store, cx| {
6306 let request_timeout = cx.update(|app| {
6307 ProjectSettings::get_global(app)
6308 .global_lsp_settings
6309 .get_request_timeout()
6310 });
6311
6312 let mut did_resolve = false;
6313 if let Some((client, project_id)) = client {
6314 for completion_index in completion_indices {
6315 let server_id = {
6316 let completion = &completions.borrow()[completion_index];
6317 completion.source.server_id()
6318 };
6319 if let Some(server_id) = server_id {
6320 if Self::resolve_completion_remote(
6321 project_id,
6322 server_id,
6323 buffer_id,
6324 completions.clone(),
6325 completion_index,
6326 client.clone(),
6327 )
6328 .await
6329 .log_err()
6330 .is_some()
6331 {
6332 did_resolve = true;
6333 }
6334 } else {
6335 resolve_word_completion(
6336 &buffer_snapshot,
6337 &mut completions.borrow_mut()[completion_index],
6338 );
6339 }
6340 }
6341 } else {
6342 for completion_index in completion_indices {
6343 let server_id = {
6344 let completion = &completions.borrow()[completion_index];
6345 completion.source.server_id()
6346 };
6347 if let Some(server_id) = server_id {
6348 let server_and_adapter = lsp_store
6349 .read_with(cx, |lsp_store, _| {
6350 let server = lsp_store.language_server_for_id(server_id)?;
6351 let adapter =
6352 lsp_store.language_server_adapter_for_id(server.server_id())?;
6353 Some((server, adapter))
6354 })
6355 .ok()
6356 .flatten();
6357 let Some((server, adapter)) = server_and_adapter else {
6358 continue;
6359 };
6360
6361 let resolved = Self::resolve_completion_local(
6362 server,
6363 completions.clone(),
6364 completion_index,
6365 request_timeout,
6366 )
6367 .await
6368 .log_err()
6369 .is_some();
6370 if resolved {
6371 Self::regenerate_completion_labels(
6372 adapter,
6373 &buffer_snapshot,
6374 completions.clone(),
6375 completion_index,
6376 )
6377 .await
6378 .log_err();
6379 did_resolve = true;
6380 }
6381 } else {
6382 resolve_word_completion(
6383 &buffer_snapshot,
6384 &mut completions.borrow_mut()[completion_index],
6385 );
6386 }
6387 }
6388 }
6389
6390 Ok(did_resolve)
6391 })
6392 }
6393
6394 async fn resolve_completion_local(
6395 server: Arc<lsp::LanguageServer>,
6396 completions: Rc<RefCell<Box<[Completion]>>>,
6397 completion_index: usize,
6398 request_timeout: Duration,
6399 ) -> Result<()> {
6400 let server_id = server.server_id();
6401 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6402 return Ok(());
6403 }
6404
6405 let request = {
6406 let completion = &completions.borrow()[completion_index];
6407 match &completion.source {
6408 CompletionSource::Lsp {
6409 lsp_completion,
6410 resolved,
6411 server_id: completion_server_id,
6412 ..
6413 } => {
6414 if *resolved {
6415 return Ok(());
6416 }
6417 anyhow::ensure!(
6418 server_id == *completion_server_id,
6419 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6420 );
6421 server.request::<lsp::request::ResolveCompletionItem>(
6422 *lsp_completion.clone(),
6423 request_timeout,
6424 )
6425 }
6426 CompletionSource::BufferWord { .. }
6427 | CompletionSource::Dap { .. }
6428 | CompletionSource::Custom => {
6429 return Ok(());
6430 }
6431 }
6432 };
6433 let resolved_completion = request
6434 .await
6435 .into_response()
6436 .context("resolve completion")?;
6437
6438 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6439 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6440
6441 let mut completions = completions.borrow_mut();
6442 let completion = &mut completions[completion_index];
6443 if let CompletionSource::Lsp {
6444 lsp_completion,
6445 resolved,
6446 server_id: completion_server_id,
6447 ..
6448 } = &mut completion.source
6449 {
6450 if *resolved {
6451 return Ok(());
6452 }
6453 anyhow::ensure!(
6454 server_id == *completion_server_id,
6455 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6456 );
6457 **lsp_completion = resolved_completion;
6458 *resolved = true;
6459 }
6460 Ok(())
6461 }
6462
6463 async fn regenerate_completion_labels(
6464 adapter: Arc<CachedLspAdapter>,
6465 snapshot: &BufferSnapshot,
6466 completions: Rc<RefCell<Box<[Completion]>>>,
6467 completion_index: usize,
6468 ) -> Result<()> {
6469 let completion_item = completions.borrow()[completion_index]
6470 .source
6471 .lsp_completion(true)
6472 .map(Cow::into_owned);
6473 if let Some(lsp_documentation) = completion_item
6474 .as_ref()
6475 .and_then(|completion_item| completion_item.documentation.clone())
6476 {
6477 let mut completions = completions.borrow_mut();
6478 let completion = &mut completions[completion_index];
6479 completion.documentation = Some(lsp_documentation.into());
6480 } else {
6481 let mut completions = completions.borrow_mut();
6482 let completion = &mut completions[completion_index];
6483 completion.documentation = Some(CompletionDocumentation::Undocumented);
6484 }
6485
6486 let mut new_label = match completion_item {
6487 Some(completion_item) => {
6488 // Some language servers always return `detail` lazily via resolve, regardless of
6489 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6490 // See: https://github.com/yioneko/vtsls/issues/213
6491 let language = snapshot.language();
6492 match language {
6493 Some(language) => {
6494 adapter
6495 .labels_for_completions(
6496 std::slice::from_ref(&completion_item),
6497 language,
6498 )
6499 .await?
6500 }
6501 None => Vec::new(),
6502 }
6503 .pop()
6504 .flatten()
6505 .unwrap_or_else(|| {
6506 CodeLabel::fallback_for_completion(
6507 &completion_item,
6508 language.map(|language| language.as_ref()),
6509 )
6510 })
6511 }
6512 None => CodeLabel::plain(
6513 completions.borrow()[completion_index].new_text.clone(),
6514 None,
6515 ),
6516 };
6517 ensure_uniform_list_compatible_label(&mut new_label);
6518
6519 let mut completions = completions.borrow_mut();
6520 let completion = &mut completions[completion_index];
6521 if completion.label.filter_text() == new_label.filter_text() {
6522 completion.label = new_label;
6523 } else {
6524 log::error!(
6525 "Resolved completion changed display label from {} to {}. \
6526 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6527 completion.label.text(),
6528 new_label.text(),
6529 completion.label.filter_text(),
6530 new_label.filter_text()
6531 );
6532 }
6533
6534 Ok(())
6535 }
6536
6537 async fn resolve_completion_remote(
6538 project_id: u64,
6539 server_id: LanguageServerId,
6540 buffer_id: BufferId,
6541 completions: Rc<RefCell<Box<[Completion]>>>,
6542 completion_index: usize,
6543 client: AnyProtoClient,
6544 ) -> Result<()> {
6545 let lsp_completion = {
6546 let completion = &completions.borrow()[completion_index];
6547 match &completion.source {
6548 CompletionSource::Lsp {
6549 lsp_completion,
6550 resolved,
6551 server_id: completion_server_id,
6552 ..
6553 } => {
6554 anyhow::ensure!(
6555 server_id == *completion_server_id,
6556 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6557 );
6558 if *resolved {
6559 return Ok(());
6560 }
6561 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6562 }
6563 CompletionSource::Custom
6564 | CompletionSource::Dap { .. }
6565 | CompletionSource::BufferWord { .. } => {
6566 return Ok(());
6567 }
6568 }
6569 };
6570 let request = proto::ResolveCompletionDocumentation {
6571 project_id,
6572 language_server_id: server_id.0 as u64,
6573 lsp_completion,
6574 buffer_id: buffer_id.into(),
6575 };
6576
6577 let response = client
6578 .request(request)
6579 .await
6580 .context("completion documentation resolve proto request")?;
6581 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6582
6583 let documentation = if response.documentation.is_empty() {
6584 CompletionDocumentation::Undocumented
6585 } else if response.documentation_is_markdown {
6586 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6587 } else if response.documentation.lines().count() <= 1 {
6588 CompletionDocumentation::SingleLine(response.documentation.into())
6589 } else {
6590 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6591 };
6592
6593 let mut completions = completions.borrow_mut();
6594 let completion = &mut completions[completion_index];
6595 completion.documentation = Some(documentation);
6596 if let CompletionSource::Lsp {
6597 insert_range,
6598 lsp_completion,
6599 resolved,
6600 server_id: completion_server_id,
6601 lsp_defaults: _,
6602 } = &mut completion.source
6603 {
6604 let completion_insert_range = response
6605 .old_insert_start
6606 .and_then(deserialize_anchor)
6607 .zip(response.old_insert_end.and_then(deserialize_anchor));
6608 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6609
6610 if *resolved {
6611 return Ok(());
6612 }
6613 anyhow::ensure!(
6614 server_id == *completion_server_id,
6615 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6616 );
6617 **lsp_completion = resolved_lsp_completion;
6618 *resolved = true;
6619 }
6620
6621 let replace_range = response
6622 .old_replace_start
6623 .and_then(deserialize_anchor)
6624 .zip(response.old_replace_end.and_then(deserialize_anchor));
6625 if let Some((old_replace_start, old_replace_end)) = replace_range
6626 && !response.new_text.is_empty()
6627 {
6628 completion.new_text = response.new_text;
6629 completion.replace_range = old_replace_start..old_replace_end;
6630 }
6631
6632 Ok(())
6633 }
6634
6635 pub fn apply_additional_edits_for_completion(
6636 &self,
6637 buffer_handle: Entity<Buffer>,
6638 completions: Rc<RefCell<Box<[Completion]>>>,
6639 completion_index: usize,
6640 push_to_history: bool,
6641 cx: &mut Context<Self>,
6642 ) -> Task<Result<Option<Transaction>>> {
6643 if let Some((client, project_id)) = self.upstream_client() {
6644 let buffer = buffer_handle.read(cx);
6645 let buffer_id = buffer.remote_id();
6646 cx.spawn(async move |_, cx| {
6647 let request = {
6648 let completion = completions.borrow()[completion_index].clone();
6649 proto::ApplyCompletionAdditionalEdits {
6650 project_id,
6651 buffer_id: buffer_id.into(),
6652 completion: Some(Self::serialize_completion(&CoreCompletion {
6653 replace_range: completion.replace_range,
6654 new_text: completion.new_text,
6655 source: completion.source,
6656 })),
6657 }
6658 };
6659
6660 let Some(transaction) = client.request(request).await?.transaction else {
6661 return Ok(None);
6662 };
6663
6664 let transaction = language::proto::deserialize_transaction(transaction)?;
6665 buffer_handle
6666 .update(cx, |buffer, _| {
6667 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6668 })
6669 .await?;
6670 if push_to_history {
6671 buffer_handle.update(cx, |buffer, _| {
6672 buffer.push_transaction(transaction.clone(), Instant::now());
6673 buffer.finalize_last_transaction();
6674 });
6675 }
6676 Ok(Some(transaction))
6677 })
6678 } else {
6679 let request_timeout = ProjectSettings::get_global(cx)
6680 .global_lsp_settings
6681 .get_request_timeout();
6682
6683 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6684 let completion = &completions.borrow()[completion_index];
6685 let server_id = completion.source.server_id()?;
6686 Some(
6687 self.language_server_for_local_buffer(buffer, server_id, cx)?
6688 .1
6689 .clone(),
6690 )
6691 }) else {
6692 return Task::ready(Ok(None));
6693 };
6694
6695 cx.spawn(async move |this, cx| {
6696 Self::resolve_completion_local(
6697 server.clone(),
6698 completions.clone(),
6699 completion_index,
6700 request_timeout,
6701 )
6702 .await
6703 .context("resolving completion")?;
6704 let completion = completions.borrow()[completion_index].clone();
6705 let additional_text_edits = completion
6706 .source
6707 .lsp_completion(true)
6708 .as_ref()
6709 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6710 if let Some(edits) = additional_text_edits {
6711 let edits = this
6712 .update(cx, |this, cx| {
6713 this.as_local_mut().unwrap().edits_from_lsp(
6714 &buffer_handle,
6715 edits,
6716 server.server_id(),
6717 None,
6718 cx,
6719 )
6720 })?
6721 .await?;
6722
6723 buffer_handle.update(cx, |buffer, cx| {
6724 buffer.finalize_last_transaction();
6725 buffer.start_transaction();
6726
6727 for (range, text) in edits {
6728 let primary = &completion.replace_range;
6729
6730 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6731 // and the primary completion is just an insertion (empty range), then this is likely
6732 // an auto-import scenario and should not be considered overlapping
6733 // https://github.com/zed-industries/zed/issues/26136
6734 let is_file_start_auto_import = {
6735 let snapshot = buffer.snapshot();
6736 let primary_start_point = primary.start.to_point(&snapshot);
6737 let range_start_point = range.start.to_point(&snapshot);
6738
6739 let result = primary_start_point.row == 0
6740 && primary_start_point.column == 0
6741 && range_start_point.row == 0
6742 && range_start_point.column == 0;
6743
6744 result
6745 };
6746
6747 let has_overlap = if is_file_start_auto_import {
6748 false
6749 } else {
6750 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6751 && primary.end.cmp(&range.start, buffer).is_ge();
6752 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6753 && range.end.cmp(&primary.end, buffer).is_ge();
6754 let result = start_within || end_within;
6755 result
6756 };
6757
6758 //Skip additional edits which overlap with the primary completion edit
6759 //https://github.com/zed-industries/zed/pull/1871
6760 if !has_overlap {
6761 buffer.edit([(range, text)], None, cx);
6762 }
6763 }
6764
6765 let transaction = if buffer.end_transaction(cx).is_some() {
6766 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6767 if !push_to_history {
6768 buffer.forget_transaction(transaction.id);
6769 }
6770 Some(transaction)
6771 } else {
6772 None
6773 };
6774 Ok(transaction)
6775 })
6776 } else {
6777 Ok(None)
6778 }
6779 })
6780 }
6781 }
6782
6783 pub fn pull_diagnostics(
6784 &mut self,
6785 buffer: Entity<Buffer>,
6786 cx: &mut Context<Self>,
6787 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6788 let buffer_id = buffer.read(cx).remote_id();
6789
6790 if let Some((client, upstream_project_id)) = self.upstream_client() {
6791 let mut suitable_capabilities = None;
6792 // Are we capable for proto request?
6793 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6794 &buffer,
6795 |capabilities| {
6796 if let Some(caps) = &capabilities.diagnostic_provider {
6797 suitable_capabilities = Some(caps.clone());
6798 true
6799 } else {
6800 false
6801 }
6802 },
6803 cx,
6804 );
6805 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6806 let Some(dynamic_caps) = suitable_capabilities else {
6807 return Task::ready(Ok(None));
6808 };
6809 assert!(any_server_has_diagnostics_provider);
6810
6811 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6812 let request = GetDocumentDiagnostics {
6813 previous_result_id: None,
6814 identifier,
6815 registration_id: None,
6816 };
6817 let request_timeout = ProjectSettings::get_global(cx)
6818 .global_lsp_settings
6819 .get_request_timeout();
6820 let request_task = client.request_lsp(
6821 upstream_project_id,
6822 None,
6823 request_timeout,
6824 cx.background_executor().clone(),
6825 request.to_proto(upstream_project_id, buffer.read(cx)),
6826 );
6827 cx.background_spawn(async move {
6828 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6829 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6830 // Do not attempt to further process the dummy responses here.
6831 let _response = request_task.await?;
6832 Ok(None)
6833 })
6834 } else {
6835 let servers = buffer.update(cx, |buffer, cx| {
6836 self.running_language_servers_for_local_buffer(buffer, cx)
6837 .map(|(_, server)| server.clone())
6838 .collect::<Vec<_>>()
6839 });
6840
6841 let pull_diagnostics = servers
6842 .into_iter()
6843 .flat_map(|server| {
6844 let result = maybe!({
6845 let local = self.as_local()?;
6846 let server_id = server.server_id();
6847 let providers_with_identifiers = local
6848 .language_server_dynamic_registrations
6849 .get(&server_id)
6850 .into_iter()
6851 .flat_map(|registrations| registrations.diagnostics.clone())
6852 .collect::<Vec<_>>();
6853 Some(
6854 providers_with_identifiers
6855 .into_iter()
6856 .map(|(registration_id, dynamic_caps)| {
6857 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6858 let registration_id = registration_id.map(SharedString::from);
6859 let result_id = self.result_id_for_buffer_pull(
6860 server_id,
6861 buffer_id,
6862 ®istration_id,
6863 cx,
6864 );
6865 self.request_lsp(
6866 buffer.clone(),
6867 LanguageServerToQuery::Other(server_id),
6868 GetDocumentDiagnostics {
6869 previous_result_id: result_id,
6870 registration_id,
6871 identifier,
6872 },
6873 cx,
6874 )
6875 })
6876 .collect::<Vec<_>>(),
6877 )
6878 });
6879
6880 result.unwrap_or_default()
6881 })
6882 .collect::<Vec<_>>();
6883
6884 cx.background_spawn(async move {
6885 let mut responses = Vec::new();
6886 for diagnostics in join_all(pull_diagnostics).await {
6887 responses.extend(diagnostics?);
6888 }
6889 Ok(Some(responses))
6890 })
6891 }
6892 }
6893
6894 pub fn applicable_inlay_chunks(
6895 &mut self,
6896 buffer: &Entity<Buffer>,
6897 ranges: &[Range<text::Anchor>],
6898 cx: &mut Context<Self>,
6899 ) -> Vec<Range<BufferRow>> {
6900 let buffer_snapshot = buffer.read(cx).snapshot();
6901 let ranges = ranges
6902 .iter()
6903 .map(|range| range.to_point(&buffer_snapshot))
6904 .collect::<Vec<_>>();
6905
6906 self.latest_lsp_data(buffer, cx)
6907 .inlay_hints
6908 .applicable_chunks(ranges.as_slice())
6909 .map(|chunk| chunk.row_range())
6910 .collect()
6911 }
6912
6913 pub fn invalidate_inlay_hints<'a>(
6914 &'a mut self,
6915 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6916 ) {
6917 for buffer_id in for_buffers {
6918 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6919 lsp_data.inlay_hints.clear();
6920 }
6921 }
6922 }
6923
6924 pub fn inlay_hints(
6925 &mut self,
6926 invalidate: InvalidationStrategy,
6927 buffer: Entity<Buffer>,
6928 ranges: Vec<Range<text::Anchor>>,
6929 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6930 cx: &mut Context<Self>,
6931 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6932 let next_hint_id = self.next_hint_id.clone();
6933 let lsp_data = self.latest_lsp_data(&buffer, cx);
6934 let query_version = lsp_data.buffer_version.clone();
6935 let mut lsp_refresh_requested = false;
6936 let for_server = if let InvalidationStrategy::RefreshRequested {
6937 server_id,
6938 request_id,
6939 } = invalidate
6940 {
6941 let invalidated = lsp_data
6942 .inlay_hints
6943 .invalidate_for_server_refresh(server_id, request_id);
6944 lsp_refresh_requested = invalidated;
6945 Some(server_id)
6946 } else {
6947 None
6948 };
6949 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6950 let known_chunks = known_chunks
6951 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6952 .map(|(_, known_chunks)| known_chunks)
6953 .unwrap_or_default();
6954
6955 let buffer_snapshot = buffer.read(cx).snapshot();
6956 let ranges = ranges
6957 .iter()
6958 .map(|range| range.to_point(&buffer_snapshot))
6959 .collect::<Vec<_>>();
6960
6961 let mut hint_fetch_tasks = Vec::new();
6962 let mut cached_inlay_hints = None;
6963 let mut ranges_to_query = None;
6964 let applicable_chunks = existing_inlay_hints
6965 .applicable_chunks(ranges.as_slice())
6966 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6967 .collect::<Vec<_>>();
6968 if applicable_chunks.is_empty() {
6969 return HashMap::default();
6970 }
6971
6972 for row_chunk in applicable_chunks {
6973 match (
6974 existing_inlay_hints
6975 .cached_hints(&row_chunk)
6976 .filter(|_| !lsp_refresh_requested)
6977 .cloned(),
6978 existing_inlay_hints
6979 .fetched_hints(&row_chunk)
6980 .as_ref()
6981 .filter(|_| !lsp_refresh_requested)
6982 .cloned(),
6983 ) {
6984 (None, None) => {
6985 let chunk_range = row_chunk.anchor_range();
6986 ranges_to_query
6987 .get_or_insert_with(Vec::new)
6988 .push((row_chunk, chunk_range));
6989 }
6990 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6991 (Some(cached_hints), None) => {
6992 for (server_id, cached_hints) in cached_hints {
6993 if for_server.is_none_or(|for_server| for_server == server_id) {
6994 cached_inlay_hints
6995 .get_or_insert_with(HashMap::default)
6996 .entry(row_chunk.row_range())
6997 .or_insert_with(HashMap::default)
6998 .entry(server_id)
6999 .or_insert_with(Vec::new)
7000 .extend(cached_hints);
7001 }
7002 }
7003 }
7004 (Some(cached_hints), Some(fetched_hints)) => {
7005 hint_fetch_tasks.push((row_chunk, fetched_hints));
7006 for (server_id, cached_hints) in cached_hints {
7007 if for_server.is_none_or(|for_server| for_server == server_id) {
7008 cached_inlay_hints
7009 .get_or_insert_with(HashMap::default)
7010 .entry(row_chunk.row_range())
7011 .or_insert_with(HashMap::default)
7012 .entry(server_id)
7013 .or_insert_with(Vec::new)
7014 .extend(cached_hints);
7015 }
7016 }
7017 }
7018 }
7019 }
7020
7021 if hint_fetch_tasks.is_empty()
7022 && ranges_to_query
7023 .as_ref()
7024 .is_none_or(|ranges| ranges.is_empty())
7025 && let Some(cached_inlay_hints) = cached_inlay_hints
7026 {
7027 cached_inlay_hints
7028 .into_iter()
7029 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7030 .collect()
7031 } else {
7032 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7033 let next_hint_id = next_hint_id.clone();
7034 let buffer = buffer.clone();
7035 let query_version = query_version.clone();
7036 let new_inlay_hints = cx
7037 .spawn(async move |lsp_store, cx| {
7038 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7039 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7040 })?;
7041 new_fetch_task
7042 .await
7043 .and_then(|new_hints_by_server| {
7044 lsp_store.update(cx, |lsp_store, cx| {
7045 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7046 let update_cache = lsp_data.buffer_version == query_version;
7047 if new_hints_by_server.is_empty() {
7048 if update_cache {
7049 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7050 }
7051 HashMap::default()
7052 } else {
7053 new_hints_by_server
7054 .into_iter()
7055 .map(|(server_id, new_hints)| {
7056 let new_hints = new_hints
7057 .into_iter()
7058 .map(|new_hint| {
7059 (
7060 InlayId::Hint(next_hint_id.fetch_add(
7061 1,
7062 atomic::Ordering::AcqRel,
7063 )),
7064 new_hint,
7065 )
7066 })
7067 .collect::<Vec<_>>();
7068 if update_cache {
7069 lsp_data.inlay_hints.insert_new_hints(
7070 chunk,
7071 server_id,
7072 new_hints.clone(),
7073 );
7074 }
7075 (server_id, new_hints)
7076 })
7077 .collect()
7078 }
7079 })
7080 })
7081 .map_err(Arc::new)
7082 })
7083 .shared();
7084
7085 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7086 *fetch_task = Some(new_inlay_hints.clone());
7087 hint_fetch_tasks.push((chunk, new_inlay_hints));
7088 }
7089
7090 cached_inlay_hints
7091 .unwrap_or_default()
7092 .into_iter()
7093 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7094 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7095 (
7096 chunk.row_range(),
7097 cx.spawn(async move |_, _| {
7098 hints_fetch.await.map_err(|e| {
7099 if e.error_code() != ErrorCode::Internal {
7100 anyhow!(e.error_code())
7101 } else {
7102 anyhow!("{e:#}")
7103 }
7104 })
7105 }),
7106 )
7107 }))
7108 .collect()
7109 }
7110 }
7111
7112 fn fetch_inlay_hints(
7113 &mut self,
7114 for_server: Option<LanguageServerId>,
7115 buffer: &Entity<Buffer>,
7116 range: Range<Anchor>,
7117 cx: &mut Context<Self>,
7118 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7119 let request = InlayHints {
7120 range: range.clone(),
7121 };
7122 if let Some((upstream_client, project_id)) = self.upstream_client() {
7123 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7124 return Task::ready(Ok(HashMap::default()));
7125 }
7126 let request_timeout = ProjectSettings::get_global(cx)
7127 .global_lsp_settings
7128 .get_request_timeout();
7129 let request_task = upstream_client.request_lsp(
7130 project_id,
7131 for_server.map(|id| id.to_proto()),
7132 request_timeout,
7133 cx.background_executor().clone(),
7134 request.to_proto(project_id, buffer.read(cx)),
7135 );
7136 let buffer = buffer.clone();
7137 cx.spawn(async move |weak_lsp_store, cx| {
7138 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7139 return Ok(HashMap::default());
7140 };
7141 let Some(responses) = request_task.await? else {
7142 return Ok(HashMap::default());
7143 };
7144
7145 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7146 let lsp_store = lsp_store.clone();
7147 let buffer = buffer.clone();
7148 let cx = cx.clone();
7149 let request = request.clone();
7150 async move {
7151 (
7152 LanguageServerId::from_proto(response.server_id),
7153 request
7154 .response_from_proto(response.response, lsp_store, buffer, cx)
7155 .await,
7156 )
7157 }
7158 }))
7159 .await;
7160
7161 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7162 let mut has_errors = false;
7163 let inlay_hints = inlay_hints
7164 .into_iter()
7165 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7166 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7167 Err(e) => {
7168 has_errors = true;
7169 log::error!("{e:#}");
7170 None
7171 }
7172 })
7173 .map(|(server_id, mut new_hints)| {
7174 new_hints.retain(|hint| {
7175 hint.position.is_valid(&buffer_snapshot)
7176 && range.start.is_valid(&buffer_snapshot)
7177 && range.end.is_valid(&buffer_snapshot)
7178 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7179 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7180 });
7181 (server_id, new_hints)
7182 })
7183 .collect::<HashMap<_, _>>();
7184 anyhow::ensure!(
7185 !has_errors || !inlay_hints.is_empty(),
7186 "Failed to fetch inlay hints"
7187 );
7188 Ok(inlay_hints)
7189 })
7190 } else {
7191 let inlay_hints_task = match for_server {
7192 Some(server_id) => {
7193 let server_task = self.request_lsp(
7194 buffer.clone(),
7195 LanguageServerToQuery::Other(server_id),
7196 request,
7197 cx,
7198 );
7199 cx.background_spawn(async move {
7200 let mut responses = Vec::new();
7201 match server_task.await {
7202 Ok(response) => responses.push((server_id, response)),
7203 // rust-analyzer likes to error with this when its still loading up
7204 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7205 Err(e) => log::error!(
7206 "Error handling response for inlay hints request: {e:#}"
7207 ),
7208 }
7209 responses
7210 })
7211 }
7212 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7213 };
7214 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7215 cx.background_spawn(async move {
7216 Ok(inlay_hints_task
7217 .await
7218 .into_iter()
7219 .map(|(server_id, mut new_hints)| {
7220 new_hints.retain(|hint| {
7221 hint.position.is_valid(&buffer_snapshot)
7222 && range.start.is_valid(&buffer_snapshot)
7223 && range.end.is_valid(&buffer_snapshot)
7224 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7225 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7226 });
7227 (server_id, new_hints)
7228 })
7229 .collect())
7230 })
7231 }
7232 }
7233
7234 fn diagnostic_registration_exists(
7235 &self,
7236 server_id: LanguageServerId,
7237 registration_id: &Option<SharedString>,
7238 ) -> bool {
7239 let Some(local) = self.as_local() else {
7240 return false;
7241 };
7242 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7243 else {
7244 return false;
7245 };
7246 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7247 registrations.diagnostics.contains_key(®istration_key)
7248 }
7249
7250 pub fn pull_diagnostics_for_buffer(
7251 &mut self,
7252 buffer: Entity<Buffer>,
7253 cx: &mut Context<Self>,
7254 ) -> Task<anyhow::Result<()>> {
7255 let diagnostics = self.pull_diagnostics(buffer, cx);
7256 cx.spawn(async move |lsp_store, cx| {
7257 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7258 return Ok(());
7259 };
7260 lsp_store.update(cx, |lsp_store, cx| {
7261 if lsp_store.as_local().is_none() {
7262 return;
7263 }
7264
7265 let mut unchanged_buffers = HashMap::default();
7266 let server_diagnostics_updates = diagnostics
7267 .into_iter()
7268 .filter_map(|diagnostics_set| match diagnostics_set {
7269 LspPullDiagnostics::Response {
7270 server_id,
7271 uri,
7272 diagnostics,
7273 registration_id,
7274 } => Some((server_id, uri, diagnostics, registration_id)),
7275 LspPullDiagnostics::Default => None,
7276 })
7277 .filter(|(server_id, _, _, registration_id)| {
7278 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7279 })
7280 .fold(
7281 HashMap::default(),
7282 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7283 let (result_id, diagnostics) = match diagnostics {
7284 PulledDiagnostics::Unchanged { result_id } => {
7285 unchanged_buffers
7286 .entry(new_registration_id.clone())
7287 .or_insert_with(HashSet::default)
7288 .insert(uri.clone());
7289 (Some(result_id), Vec::new())
7290 }
7291 PulledDiagnostics::Changed {
7292 result_id,
7293 diagnostics,
7294 } => (result_id, diagnostics),
7295 };
7296 let disk_based_sources = Cow::Owned(
7297 lsp_store
7298 .language_server_adapter_for_id(server_id)
7299 .as_ref()
7300 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7301 .unwrap_or(&[])
7302 .to_vec(),
7303 );
7304 acc.entry(server_id)
7305 .or_insert_with(HashMap::default)
7306 .entry(new_registration_id.clone())
7307 .or_insert_with(Vec::new)
7308 .push(DocumentDiagnosticsUpdate {
7309 server_id,
7310 diagnostics: lsp::PublishDiagnosticsParams {
7311 uri,
7312 diagnostics,
7313 version: None,
7314 },
7315 result_id: result_id.map(SharedString::new),
7316 disk_based_sources,
7317 registration_id: new_registration_id,
7318 });
7319 acc
7320 },
7321 );
7322
7323 for diagnostic_updates in server_diagnostics_updates.into_values() {
7324 for (registration_id, diagnostic_updates) in diagnostic_updates {
7325 lsp_store
7326 .merge_lsp_diagnostics(
7327 DiagnosticSourceKind::Pulled,
7328 diagnostic_updates,
7329 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7330 DiagnosticSourceKind::Pulled => {
7331 old_diagnostic.registration_id != registration_id
7332 || unchanged_buffers
7333 .get(&old_diagnostic.registration_id)
7334 .is_some_and(|unchanged_buffers| {
7335 unchanged_buffers.contains(&document_uri)
7336 })
7337 }
7338 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7339 true
7340 }
7341 },
7342 cx,
7343 )
7344 .log_err();
7345 }
7346 }
7347 })
7348 })
7349 }
7350
7351 pub fn signature_help<T: ToPointUtf16>(
7352 &mut self,
7353 buffer: &Entity<Buffer>,
7354 position: T,
7355 cx: &mut Context<Self>,
7356 ) -> Task<Option<Vec<SignatureHelp>>> {
7357 let position = position.to_point_utf16(buffer.read(cx));
7358
7359 if let Some((client, upstream_project_id)) = self.upstream_client() {
7360 let request = GetSignatureHelp { position };
7361 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7362 return Task::ready(None);
7363 }
7364 let request_timeout = ProjectSettings::get_global(cx)
7365 .global_lsp_settings
7366 .get_request_timeout();
7367 let request_task = client.request_lsp(
7368 upstream_project_id,
7369 None,
7370 request_timeout,
7371 cx.background_executor().clone(),
7372 request.to_proto(upstream_project_id, buffer.read(cx)),
7373 );
7374 let buffer = buffer.clone();
7375 cx.spawn(async move |weak_lsp_store, cx| {
7376 let lsp_store = weak_lsp_store.upgrade()?;
7377 let signatures = join_all(
7378 request_task
7379 .await
7380 .log_err()
7381 .flatten()
7382 .map(|response| response.payload)
7383 .unwrap_or_default()
7384 .into_iter()
7385 .map(|response| {
7386 let response = GetSignatureHelp { position }.response_from_proto(
7387 response.response,
7388 lsp_store.clone(),
7389 buffer.clone(),
7390 cx.clone(),
7391 );
7392 async move { response.await.log_err().flatten() }
7393 }),
7394 )
7395 .await
7396 .into_iter()
7397 .flatten()
7398 .collect();
7399 Some(signatures)
7400 })
7401 } else {
7402 let all_actions_task = self.request_multiple_lsp_locally(
7403 buffer,
7404 Some(position),
7405 GetSignatureHelp { position },
7406 cx,
7407 );
7408 cx.background_spawn(async move {
7409 Some(
7410 all_actions_task
7411 .await
7412 .into_iter()
7413 .flat_map(|(_, actions)| actions)
7414 .collect::<Vec<_>>(),
7415 )
7416 })
7417 }
7418 }
7419
7420 pub fn hover(
7421 &mut self,
7422 buffer: &Entity<Buffer>,
7423 position: PointUtf16,
7424 cx: &mut Context<Self>,
7425 ) -> Task<Option<Vec<Hover>>> {
7426 if let Some((client, upstream_project_id)) = self.upstream_client() {
7427 let request = GetHover { position };
7428 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7429 return Task::ready(None);
7430 }
7431 let request_timeout = ProjectSettings::get_global(cx)
7432 .global_lsp_settings
7433 .get_request_timeout();
7434 let request_task = client.request_lsp(
7435 upstream_project_id,
7436 None,
7437 request_timeout,
7438 cx.background_executor().clone(),
7439 request.to_proto(upstream_project_id, buffer.read(cx)),
7440 );
7441 let buffer = buffer.clone();
7442 cx.spawn(async move |weak_lsp_store, cx| {
7443 let lsp_store = weak_lsp_store.upgrade()?;
7444 let hovers = join_all(
7445 request_task
7446 .await
7447 .log_err()
7448 .flatten()
7449 .map(|response| response.payload)
7450 .unwrap_or_default()
7451 .into_iter()
7452 .map(|response| {
7453 let response = GetHover { position }.response_from_proto(
7454 response.response,
7455 lsp_store.clone(),
7456 buffer.clone(),
7457 cx.clone(),
7458 );
7459 async move {
7460 response
7461 .await
7462 .log_err()
7463 .flatten()
7464 .and_then(remove_empty_hover_blocks)
7465 }
7466 }),
7467 )
7468 .await
7469 .into_iter()
7470 .flatten()
7471 .collect();
7472 Some(hovers)
7473 })
7474 } else {
7475 let all_actions_task = self.request_multiple_lsp_locally(
7476 buffer,
7477 Some(position),
7478 GetHover { position },
7479 cx,
7480 );
7481 cx.background_spawn(async move {
7482 Some(
7483 all_actions_task
7484 .await
7485 .into_iter()
7486 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7487 .collect::<Vec<Hover>>(),
7488 )
7489 })
7490 }
7491 }
7492
7493 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7494 let language_registry = self.languages.clone();
7495
7496 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7497 let request = upstream_client.request(proto::GetProjectSymbols {
7498 project_id: *project_id,
7499 query: query.to_string(),
7500 });
7501 cx.foreground_executor().spawn(async move {
7502 let response = request.await?;
7503 let mut symbols = Vec::new();
7504 let core_symbols = response
7505 .symbols
7506 .into_iter()
7507 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7508 .collect::<Vec<_>>();
7509 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7510 .await;
7511 Ok(symbols)
7512 })
7513 } else if let Some(local) = self.as_local() {
7514 struct WorkspaceSymbolsResult {
7515 server_id: LanguageServerId,
7516 lsp_adapter: Arc<CachedLspAdapter>,
7517 worktree: WeakEntity<Worktree>,
7518 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7519 }
7520
7521 let mut requests = Vec::new();
7522 let mut requested_servers = BTreeSet::new();
7523 let request_timeout = ProjectSettings::get_global(cx)
7524 .global_lsp_settings
7525 .get_request_timeout();
7526
7527 for (seed, state) in local.language_server_ids.iter() {
7528 let Some(worktree_handle) = self
7529 .worktree_store
7530 .read(cx)
7531 .worktree_for_id(seed.worktree_id, cx)
7532 else {
7533 continue;
7534 };
7535
7536 let worktree = worktree_handle.read(cx);
7537 if !worktree.is_visible() {
7538 continue;
7539 }
7540
7541 if !requested_servers.insert(state.id) {
7542 continue;
7543 }
7544
7545 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7546 Some(LanguageServerState::Running {
7547 adapter, server, ..
7548 }) => (adapter.clone(), server),
7549
7550 _ => continue,
7551 };
7552
7553 let supports_workspace_symbol_request =
7554 match server.capabilities().workspace_symbol_provider {
7555 Some(OneOf::Left(supported)) => supported,
7556 Some(OneOf::Right(_)) => true,
7557 None => false,
7558 };
7559
7560 if !supports_workspace_symbol_request {
7561 continue;
7562 }
7563
7564 let worktree_handle = worktree_handle.clone();
7565 let server_id = server.server_id();
7566 requests.push(
7567 server
7568 .request::<lsp::request::WorkspaceSymbolRequest>(
7569 lsp::WorkspaceSymbolParams {
7570 query: query.to_string(),
7571 ..Default::default()
7572 },
7573 request_timeout,
7574 )
7575 .map(move |response| {
7576 let lsp_symbols = response
7577 .into_response()
7578 .context("workspace symbols request")
7579 .log_err()
7580 .flatten()
7581 .map(|symbol_response| match symbol_response {
7582 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7583 flat_responses
7584 .into_iter()
7585 .map(|lsp_symbol| {
7586 (
7587 lsp_symbol.name,
7588 lsp_symbol.kind,
7589 lsp_symbol.location,
7590 lsp_symbol.container_name,
7591 )
7592 })
7593 .collect::<Vec<_>>()
7594 }
7595 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7596 nested_responses
7597 .into_iter()
7598 .filter_map(|lsp_symbol| {
7599 let location = match lsp_symbol.location {
7600 OneOf::Left(location) => location,
7601 OneOf::Right(_) => {
7602 log::error!(
7603 "Unexpected: client capabilities \
7604 forbid symbol resolutions in \
7605 workspace.symbol.resolveSupport"
7606 );
7607 return None;
7608 }
7609 };
7610 Some((
7611 lsp_symbol.name,
7612 lsp_symbol.kind,
7613 location,
7614 lsp_symbol.container_name,
7615 ))
7616 })
7617 .collect::<Vec<_>>()
7618 }
7619 })
7620 .unwrap_or_default();
7621
7622 WorkspaceSymbolsResult {
7623 server_id,
7624 lsp_adapter,
7625 worktree: worktree_handle.downgrade(),
7626 lsp_symbols,
7627 }
7628 }),
7629 );
7630 }
7631
7632 cx.spawn(async move |this, cx| {
7633 let responses = futures::future::join_all(requests).await;
7634 let this = match this.upgrade() {
7635 Some(this) => this,
7636 None => return Ok(Vec::new()),
7637 };
7638
7639 let mut symbols = Vec::new();
7640 for result in responses {
7641 let core_symbols = this.update(cx, |this, cx| {
7642 result
7643 .lsp_symbols
7644 .into_iter()
7645 .filter_map(
7646 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7647 let abs_path = symbol_location.uri.to_file_path().ok()?;
7648 let source_worktree = result.worktree.upgrade()?;
7649 let source_worktree_id = source_worktree.read(cx).id();
7650
7651 let path = if let Some((tree, rel_path)) =
7652 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7653 {
7654 let worktree_id = tree.read(cx).id();
7655 SymbolLocation::InProject(ProjectPath {
7656 worktree_id,
7657 path: rel_path,
7658 })
7659 } else {
7660 SymbolLocation::OutsideProject {
7661 signature: this.symbol_signature(&abs_path),
7662 abs_path: abs_path.into(),
7663 }
7664 };
7665
7666 Some(CoreSymbol {
7667 source_language_server_id: result.server_id,
7668 language_server_name: result.lsp_adapter.name.clone(),
7669 source_worktree_id,
7670 path,
7671 kind: symbol_kind,
7672 name: collapse_newlines(&symbol_name, "↵ "),
7673 range: range_from_lsp(symbol_location.range),
7674 container_name: container_name
7675 .map(|c| collapse_newlines(&c, "↵ ")),
7676 })
7677 },
7678 )
7679 .collect::<Vec<_>>()
7680 });
7681
7682 populate_labels_for_symbols(
7683 core_symbols,
7684 &language_registry,
7685 Some(result.lsp_adapter),
7686 &mut symbols,
7687 )
7688 .await;
7689 }
7690
7691 Ok(symbols)
7692 })
7693 } else {
7694 Task::ready(Err(anyhow!("No upstream client or local language server")))
7695 }
7696 }
7697
7698 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7699 let mut summary = DiagnosticSummary::default();
7700 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7701 summary.error_count += path_summary.error_count;
7702 summary.warning_count += path_summary.warning_count;
7703 }
7704 summary
7705 }
7706
7707 /// Returns the diagnostic summary for a specific project path.
7708 pub fn diagnostic_summary_for_path(
7709 &self,
7710 project_path: &ProjectPath,
7711 _: &App,
7712 ) -> DiagnosticSummary {
7713 if let Some(summaries) = self
7714 .diagnostic_summaries
7715 .get(&project_path.worktree_id)
7716 .and_then(|map| map.get(&project_path.path))
7717 {
7718 let (error_count, warning_count) = summaries.iter().fold(
7719 (0, 0),
7720 |(error_count, warning_count), (_language_server_id, summary)| {
7721 (
7722 error_count + summary.error_count,
7723 warning_count + summary.warning_count,
7724 )
7725 },
7726 );
7727
7728 DiagnosticSummary {
7729 error_count,
7730 warning_count,
7731 }
7732 } else {
7733 DiagnosticSummary::default()
7734 }
7735 }
7736
7737 pub fn diagnostic_summaries<'a>(
7738 &'a self,
7739 include_ignored: bool,
7740 cx: &'a App,
7741 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7742 self.worktree_store
7743 .read(cx)
7744 .visible_worktrees(cx)
7745 .filter_map(|worktree| {
7746 let worktree = worktree.read(cx);
7747 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7748 })
7749 .flat_map(move |(worktree, summaries)| {
7750 let worktree_id = worktree.id();
7751 summaries
7752 .iter()
7753 .filter(move |(path, _)| {
7754 include_ignored
7755 || worktree
7756 .entry_for_path(path.as_ref())
7757 .is_some_and(|entry| !entry.is_ignored)
7758 })
7759 .flat_map(move |(path, summaries)| {
7760 summaries.iter().map(move |(server_id, summary)| {
7761 (
7762 ProjectPath {
7763 worktree_id,
7764 path: path.clone(),
7765 },
7766 *server_id,
7767 *summary,
7768 )
7769 })
7770 })
7771 })
7772 }
7773
7774 pub fn on_buffer_edited(
7775 &mut self,
7776 buffer: Entity<Buffer>,
7777 cx: &mut Context<Self>,
7778 ) -> Option<()> {
7779 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7780 Some(
7781 self.as_local()?
7782 .language_servers_for_buffer(buffer, cx)
7783 .map(|i| i.1.clone())
7784 .collect(),
7785 )
7786 })?;
7787
7788 let buffer = buffer.read(cx);
7789 let file = File::from_dyn(buffer.file())?;
7790 let abs_path = file.as_local()?.abs_path(cx);
7791 let uri = lsp::Uri::from_file_path(&abs_path)
7792 .ok()
7793 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7794 .log_err()?;
7795 let next_snapshot = buffer.text_snapshot();
7796 for language_server in language_servers {
7797 let language_server = language_server.clone();
7798
7799 let buffer_snapshots = self
7800 .as_local_mut()?
7801 .buffer_snapshots
7802 .get_mut(&buffer.remote_id())
7803 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7804 let previous_snapshot = buffer_snapshots.last()?;
7805
7806 let build_incremental_change = || {
7807 buffer
7808 .edits_since::<Dimensions<PointUtf16, usize>>(
7809 previous_snapshot.snapshot.version(),
7810 )
7811 .map(|edit| {
7812 let edit_start = edit.new.start.0;
7813 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7814 let new_text = next_snapshot
7815 .text_for_range(edit.new.start.1..edit.new.end.1)
7816 .collect();
7817 lsp::TextDocumentContentChangeEvent {
7818 range: Some(lsp::Range::new(
7819 point_to_lsp(edit_start),
7820 point_to_lsp(edit_end),
7821 )),
7822 range_length: None,
7823 text: new_text,
7824 }
7825 })
7826 .collect()
7827 };
7828
7829 let document_sync_kind = language_server
7830 .capabilities()
7831 .text_document_sync
7832 .as_ref()
7833 .and_then(|sync| match sync {
7834 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7835 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7836 });
7837
7838 let content_changes: Vec<_> = match document_sync_kind {
7839 Some(lsp::TextDocumentSyncKind::FULL) => {
7840 vec![lsp::TextDocumentContentChangeEvent {
7841 range: None,
7842 range_length: None,
7843 text: next_snapshot.text(),
7844 }]
7845 }
7846 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7847 _ => {
7848 #[cfg(any(test, feature = "test-support"))]
7849 {
7850 build_incremental_change()
7851 }
7852
7853 #[cfg(not(any(test, feature = "test-support")))]
7854 {
7855 continue;
7856 }
7857 }
7858 };
7859
7860 let next_version = previous_snapshot.version + 1;
7861 buffer_snapshots.push(LspBufferSnapshot {
7862 version: next_version,
7863 snapshot: next_snapshot.clone(),
7864 });
7865
7866 language_server
7867 .notify::<lsp::notification::DidChangeTextDocument>(
7868 lsp::DidChangeTextDocumentParams {
7869 text_document: lsp::VersionedTextDocumentIdentifier::new(
7870 uri.clone(),
7871 next_version,
7872 ),
7873 content_changes,
7874 },
7875 )
7876 .ok();
7877 self.pull_workspace_diagnostics(language_server.server_id());
7878 }
7879
7880 None
7881 }
7882
7883 pub fn on_buffer_saved(
7884 &mut self,
7885 buffer: Entity<Buffer>,
7886 cx: &mut Context<Self>,
7887 ) -> Option<()> {
7888 let file = File::from_dyn(buffer.read(cx).file())?;
7889 let worktree_id = file.worktree_id(cx);
7890 let abs_path = file.as_local()?.abs_path(cx);
7891 let text_document = lsp::TextDocumentIdentifier {
7892 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7893 };
7894 let local = self.as_local()?;
7895
7896 for server in local.language_servers_for_worktree(worktree_id) {
7897 if let Some(include_text) = include_text(server.as_ref()) {
7898 let text = if include_text {
7899 Some(buffer.read(cx).text())
7900 } else {
7901 None
7902 };
7903 server
7904 .notify::<lsp::notification::DidSaveTextDocument>(
7905 lsp::DidSaveTextDocumentParams {
7906 text_document: text_document.clone(),
7907 text,
7908 },
7909 )
7910 .ok();
7911 }
7912 }
7913
7914 let language_servers = buffer.update(cx, |buffer, cx| {
7915 local.language_server_ids_for_buffer(buffer, cx)
7916 });
7917 for language_server_id in language_servers {
7918 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7919 }
7920
7921 None
7922 }
7923
7924 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7925 maybe!(async move {
7926 let mut refreshed_servers = HashSet::default();
7927 let servers = lsp_store
7928 .update(cx, |lsp_store, cx| {
7929 let local = lsp_store.as_local()?;
7930
7931 let servers = local
7932 .language_server_ids
7933 .iter()
7934 .filter_map(|(seed, state)| {
7935 let worktree = lsp_store
7936 .worktree_store
7937 .read(cx)
7938 .worktree_for_id(seed.worktree_id, cx);
7939 let delegate: Arc<dyn LspAdapterDelegate> =
7940 worktree.map(|worktree| {
7941 LocalLspAdapterDelegate::new(
7942 local.languages.clone(),
7943 &local.environment,
7944 cx.weak_entity(),
7945 &worktree,
7946 local.http_client.clone(),
7947 local.fs.clone(),
7948 cx,
7949 )
7950 })?;
7951 let server_id = state.id;
7952
7953 let states = local.language_servers.get(&server_id)?;
7954
7955 match states {
7956 LanguageServerState::Starting { .. } => None,
7957 LanguageServerState::Running {
7958 adapter, server, ..
7959 } => {
7960 let adapter = adapter.clone();
7961 let server = server.clone();
7962 refreshed_servers.insert(server.name());
7963 let toolchain = seed.toolchain.clone();
7964 Some(cx.spawn(async move |_, cx| {
7965 let settings =
7966 LocalLspStore::workspace_configuration_for_adapter(
7967 adapter.adapter.clone(),
7968 &delegate,
7969 toolchain,
7970 None,
7971 cx,
7972 )
7973 .await
7974 .ok()?;
7975 server
7976 .notify::<lsp::notification::DidChangeConfiguration>(
7977 lsp::DidChangeConfigurationParams { settings },
7978 )
7979 .ok()?;
7980 Some(())
7981 }))
7982 }
7983 }
7984 })
7985 .collect::<Vec<_>>();
7986
7987 Some(servers)
7988 })
7989 .ok()
7990 .flatten()?;
7991
7992 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7993 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7994 // to stop and unregister its language server wrapper.
7995 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7996 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7997 let _: Vec<Option<()>> = join_all(servers).await;
7998
7999 Some(())
8000 })
8001 .await;
8002 }
8003
8004 fn maintain_workspace_config(
8005 external_refresh_requests: watch::Receiver<()>,
8006 cx: &mut Context<Self>,
8007 ) -> Task<Result<()>> {
8008 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8009 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8010
8011 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8012 *settings_changed_tx.borrow_mut() = ();
8013 });
8014
8015 let mut joint_future =
8016 futures::stream::select(settings_changed_rx, external_refresh_requests);
8017 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8018 // - 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).
8019 // - 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.
8020 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8021 // - 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,
8022 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8023 cx.spawn(async move |this, cx| {
8024 while let Some(()) = joint_future.next().await {
8025 this.update(cx, |this, cx| {
8026 this.refresh_server_tree(cx);
8027 })
8028 .ok();
8029
8030 Self::refresh_workspace_configurations(&this, cx).await;
8031 }
8032
8033 drop(settings_observation);
8034 anyhow::Ok(())
8035 })
8036 }
8037
8038 pub fn running_language_servers_for_local_buffer<'a>(
8039 &'a self,
8040 buffer: &Buffer,
8041 cx: &mut App,
8042 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8043 let local = self.as_local();
8044 let language_server_ids = local
8045 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8046 .unwrap_or_default();
8047
8048 language_server_ids
8049 .into_iter()
8050 .filter_map(
8051 move |server_id| match local?.language_servers.get(&server_id)? {
8052 LanguageServerState::Running {
8053 adapter, server, ..
8054 } => Some((adapter, server)),
8055 _ => None,
8056 },
8057 )
8058 }
8059
8060 pub fn language_servers_for_local_buffer(
8061 &self,
8062 buffer: &Buffer,
8063 cx: &mut App,
8064 ) -> Vec<LanguageServerId> {
8065 let local = self.as_local();
8066 local
8067 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8068 .unwrap_or_default()
8069 }
8070
8071 pub fn language_server_for_local_buffer<'a>(
8072 &'a self,
8073 buffer: &'a Buffer,
8074 server_id: LanguageServerId,
8075 cx: &'a mut App,
8076 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8077 self.as_local()?
8078 .language_servers_for_buffer(buffer, cx)
8079 .find(|(_, s)| s.server_id() == server_id)
8080 }
8081
8082 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8083 self.diagnostic_summaries.remove(&id_to_remove);
8084 if let Some(local) = self.as_local_mut() {
8085 let to_remove = local.remove_worktree(id_to_remove, cx);
8086 for server in to_remove {
8087 self.language_server_statuses.remove(&server);
8088 }
8089 }
8090 }
8091
8092 pub fn shared(
8093 &mut self,
8094 project_id: u64,
8095 downstream_client: AnyProtoClient,
8096 _: &mut Context<Self>,
8097 ) {
8098 self.downstream_client = Some((downstream_client.clone(), project_id));
8099
8100 for (server_id, status) in &self.language_server_statuses {
8101 if let Some(server) = self.language_server_for_id(*server_id) {
8102 downstream_client
8103 .send(proto::StartLanguageServer {
8104 project_id,
8105 server: Some(proto::LanguageServer {
8106 id: server_id.to_proto(),
8107 name: status.name.to_string(),
8108 worktree_id: status.worktree.map(|id| id.to_proto()),
8109 }),
8110 capabilities: serde_json::to_string(&server.capabilities())
8111 .expect("serializing server LSP capabilities"),
8112 })
8113 .log_err();
8114 }
8115 }
8116 }
8117
8118 pub fn disconnected_from_host(&mut self) {
8119 self.downstream_client.take();
8120 }
8121
8122 pub fn disconnected_from_ssh_remote(&mut self) {
8123 if let LspStoreMode::Remote(RemoteLspStore {
8124 upstream_client, ..
8125 }) = &mut self.mode
8126 {
8127 upstream_client.take();
8128 }
8129 }
8130
8131 pub(crate) fn set_language_server_statuses_from_proto(
8132 &mut self,
8133 project: WeakEntity<Project>,
8134 language_servers: Vec<proto::LanguageServer>,
8135 server_capabilities: Vec<String>,
8136 cx: &mut Context<Self>,
8137 ) {
8138 let lsp_logs = cx
8139 .try_global::<GlobalLogStore>()
8140 .map(|lsp_store| lsp_store.0.clone());
8141
8142 self.language_server_statuses = language_servers
8143 .into_iter()
8144 .zip(server_capabilities)
8145 .map(|(server, server_capabilities)| {
8146 let server_id = LanguageServerId(server.id as usize);
8147 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8148 self.lsp_server_capabilities
8149 .insert(server_id, server_capabilities);
8150 }
8151
8152 let name = LanguageServerName::from_proto(server.name);
8153 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8154
8155 if let Some(lsp_logs) = &lsp_logs {
8156 lsp_logs.update(cx, |lsp_logs, cx| {
8157 lsp_logs.add_language_server(
8158 // Only remote clients get their language servers set from proto
8159 LanguageServerKind::Remote {
8160 project: project.clone(),
8161 },
8162 server_id,
8163 Some(name.clone()),
8164 worktree,
8165 None,
8166 cx,
8167 );
8168 });
8169 }
8170
8171 (
8172 server_id,
8173 LanguageServerStatus {
8174 name,
8175 server_version: None,
8176 pending_work: Default::default(),
8177 has_pending_diagnostic_updates: false,
8178 progress_tokens: Default::default(),
8179 worktree,
8180 binary: None,
8181 configuration: None,
8182 workspace_folders: BTreeSet::new(),
8183 process_id: None,
8184 },
8185 )
8186 })
8187 .collect();
8188 }
8189
8190 #[cfg(feature = "test-support")]
8191 pub fn update_diagnostic_entries(
8192 &mut self,
8193 server_id: LanguageServerId,
8194 abs_path: PathBuf,
8195 result_id: Option<SharedString>,
8196 version: Option<i32>,
8197 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8198 cx: &mut Context<Self>,
8199 ) -> anyhow::Result<()> {
8200 self.merge_diagnostic_entries(
8201 vec![DocumentDiagnosticsUpdate {
8202 diagnostics: DocumentDiagnostics {
8203 diagnostics,
8204 document_abs_path: abs_path,
8205 version,
8206 },
8207 result_id,
8208 server_id,
8209 disk_based_sources: Cow::Borrowed(&[]),
8210 registration_id: None,
8211 }],
8212 |_, _, _| false,
8213 cx,
8214 )?;
8215 Ok(())
8216 }
8217
8218 pub fn merge_diagnostic_entries<'a>(
8219 &mut self,
8220 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8221 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8222 cx: &mut Context<Self>,
8223 ) -> anyhow::Result<()> {
8224 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8225 let mut updated_diagnostics_paths = HashMap::default();
8226 for mut update in diagnostic_updates {
8227 let abs_path = &update.diagnostics.document_abs_path;
8228 let server_id = update.server_id;
8229 let Some((worktree, relative_path)) =
8230 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8231 else {
8232 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8233 return Ok(());
8234 };
8235
8236 let worktree_id = worktree.read(cx).id();
8237 let project_path = ProjectPath {
8238 worktree_id,
8239 path: relative_path,
8240 };
8241
8242 let document_uri = lsp::Uri::from_file_path(abs_path)
8243 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8244 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8245 let snapshot = buffer_handle.read(cx).snapshot();
8246 let buffer = buffer_handle.read(cx);
8247 let reused_diagnostics = buffer
8248 .buffer_diagnostics(Some(server_id))
8249 .iter()
8250 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8251 .map(|v| {
8252 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8253 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8254 DiagnosticEntry {
8255 range: start..end,
8256 diagnostic: v.diagnostic.clone(),
8257 }
8258 })
8259 .collect::<Vec<_>>();
8260
8261 self.as_local_mut()
8262 .context("cannot merge diagnostics on a remote LspStore")?
8263 .update_buffer_diagnostics(
8264 &buffer_handle,
8265 server_id,
8266 Some(update.registration_id),
8267 update.result_id,
8268 update.diagnostics.version,
8269 update.diagnostics.diagnostics.clone(),
8270 reused_diagnostics.clone(),
8271 cx,
8272 )?;
8273
8274 update.diagnostics.diagnostics.extend(reused_diagnostics);
8275 } else if let Some(local) = self.as_local() {
8276 let reused_diagnostics = local
8277 .diagnostics
8278 .get(&worktree_id)
8279 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8280 .and_then(|diagnostics_by_server_id| {
8281 diagnostics_by_server_id
8282 .binary_search_by_key(&server_id, |e| e.0)
8283 .ok()
8284 .map(|ix| &diagnostics_by_server_id[ix].1)
8285 })
8286 .into_iter()
8287 .flatten()
8288 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8289
8290 update
8291 .diagnostics
8292 .diagnostics
8293 .extend(reused_diagnostics.cloned());
8294 }
8295
8296 let updated = worktree.update(cx, |worktree, cx| {
8297 self.update_worktree_diagnostics(
8298 worktree.id(),
8299 server_id,
8300 project_path.path.clone(),
8301 update.diagnostics.diagnostics,
8302 cx,
8303 )
8304 })?;
8305 match updated {
8306 ControlFlow::Continue(new_summary) => {
8307 if let Some((project_id, new_summary)) = new_summary {
8308 match &mut diagnostics_summary {
8309 Some(diagnostics_summary) => {
8310 diagnostics_summary
8311 .more_summaries
8312 .push(proto::DiagnosticSummary {
8313 path: project_path.path.as_ref().to_proto(),
8314 language_server_id: server_id.0 as u64,
8315 error_count: new_summary.error_count,
8316 warning_count: new_summary.warning_count,
8317 })
8318 }
8319 None => {
8320 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8321 project_id,
8322 worktree_id: worktree_id.to_proto(),
8323 summary: Some(proto::DiagnosticSummary {
8324 path: project_path.path.as_ref().to_proto(),
8325 language_server_id: server_id.0 as u64,
8326 error_count: new_summary.error_count,
8327 warning_count: new_summary.warning_count,
8328 }),
8329 more_summaries: Vec::new(),
8330 })
8331 }
8332 }
8333 }
8334 updated_diagnostics_paths
8335 .entry(server_id)
8336 .or_insert_with(Vec::new)
8337 .push(project_path);
8338 }
8339 ControlFlow::Break(()) => {}
8340 }
8341 }
8342
8343 if let Some((diagnostics_summary, (downstream_client, _))) =
8344 diagnostics_summary.zip(self.downstream_client.as_ref())
8345 {
8346 downstream_client.send(diagnostics_summary).log_err();
8347 }
8348 for (server_id, paths) in updated_diagnostics_paths {
8349 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8350 }
8351 Ok(())
8352 }
8353
8354 fn update_worktree_diagnostics(
8355 &mut self,
8356 worktree_id: WorktreeId,
8357 server_id: LanguageServerId,
8358 path_in_worktree: Arc<RelPath>,
8359 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8360 _: &mut Context<Worktree>,
8361 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8362 let local = match &mut self.mode {
8363 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8364 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8365 };
8366
8367 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8368 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8369 let summaries_by_server_id = summaries_for_tree
8370 .entry(path_in_worktree.clone())
8371 .or_default();
8372
8373 let old_summary = summaries_by_server_id
8374 .remove(&server_id)
8375 .unwrap_or_default();
8376
8377 let new_summary = DiagnosticSummary::new(&diagnostics);
8378 if diagnostics.is_empty() {
8379 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8380 {
8381 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8382 diagnostics_by_server_id.remove(ix);
8383 }
8384 if diagnostics_by_server_id.is_empty() {
8385 diagnostics_for_tree.remove(&path_in_worktree);
8386 }
8387 }
8388 } else {
8389 summaries_by_server_id.insert(server_id, new_summary);
8390 let diagnostics_by_server_id = diagnostics_for_tree
8391 .entry(path_in_worktree.clone())
8392 .or_default();
8393 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8394 Ok(ix) => {
8395 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8396 }
8397 Err(ix) => {
8398 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8399 }
8400 }
8401 }
8402
8403 if !old_summary.is_empty() || !new_summary.is_empty() {
8404 if let Some((_, project_id)) = &self.downstream_client {
8405 Ok(ControlFlow::Continue(Some((
8406 *project_id,
8407 proto::DiagnosticSummary {
8408 path: path_in_worktree.to_proto(),
8409 language_server_id: server_id.0 as u64,
8410 error_count: new_summary.error_count as u32,
8411 warning_count: new_summary.warning_count as u32,
8412 },
8413 ))))
8414 } else {
8415 Ok(ControlFlow::Continue(None))
8416 }
8417 } else {
8418 Ok(ControlFlow::Break(()))
8419 }
8420 }
8421
8422 pub fn open_buffer_for_symbol(
8423 &mut self,
8424 symbol: &Symbol,
8425 cx: &mut Context<Self>,
8426 ) -> Task<Result<Entity<Buffer>>> {
8427 if let Some((client, project_id)) = self.upstream_client() {
8428 let request = client.request(proto::OpenBufferForSymbol {
8429 project_id,
8430 symbol: Some(Self::serialize_symbol(symbol)),
8431 });
8432 cx.spawn(async move |this, cx| {
8433 let response = request.await?;
8434 let buffer_id = BufferId::new(response.buffer_id)?;
8435 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8436 .await
8437 })
8438 } else if let Some(local) = self.as_local() {
8439 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8440 seed.worktree_id == symbol.source_worktree_id
8441 && state.id == symbol.source_language_server_id
8442 && symbol.language_server_name == seed.name
8443 });
8444 if !is_valid {
8445 return Task::ready(Err(anyhow!(
8446 "language server for worktree and language not found"
8447 )));
8448 };
8449
8450 let symbol_abs_path = match &symbol.path {
8451 SymbolLocation::InProject(project_path) => self
8452 .worktree_store
8453 .read(cx)
8454 .absolutize(&project_path, cx)
8455 .context("no such worktree"),
8456 SymbolLocation::OutsideProject {
8457 abs_path,
8458 signature: _,
8459 } => Ok(abs_path.to_path_buf()),
8460 };
8461 let symbol_abs_path = match symbol_abs_path {
8462 Ok(abs_path) => abs_path,
8463 Err(err) => return Task::ready(Err(err)),
8464 };
8465 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8466 uri
8467 } else {
8468 return Task::ready(Err(anyhow!("invalid symbol path")));
8469 };
8470
8471 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8472 } else {
8473 Task::ready(Err(anyhow!("no upstream client or local store")))
8474 }
8475 }
8476
8477 pub(crate) fn open_local_buffer_via_lsp(
8478 &mut self,
8479 abs_path: lsp::Uri,
8480 language_server_id: LanguageServerId,
8481 cx: &mut Context<Self>,
8482 ) -> Task<Result<Entity<Buffer>>> {
8483 let path_style = self.worktree_store.read(cx).path_style();
8484 cx.spawn(async move |lsp_store, cx| {
8485 // Escape percent-encoded string.
8486 let current_scheme = abs_path.scheme().to_owned();
8487 // Uri is immutable, so we can't modify the scheme
8488
8489 let abs_path = abs_path
8490 .to_file_path_ext(path_style)
8491 .map_err(|()| anyhow!("can't convert URI to path"))?;
8492 let p = abs_path.clone();
8493 let yarn_worktree = lsp_store
8494 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8495 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8496 cx.spawn(async move |this, cx| {
8497 let t = this
8498 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8499 .ok()?;
8500 t.await
8501 })
8502 }),
8503 None => Task::ready(None),
8504 })?
8505 .await;
8506 let (worktree_root_target, known_relative_path) =
8507 if let Some((zip_root, relative_path)) = yarn_worktree {
8508 (zip_root, Some(relative_path))
8509 } else {
8510 (Arc::<Path>::from(abs_path.as_path()), None)
8511 };
8512 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8513 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8514 worktree_store.find_worktree(&worktree_root_target, cx)
8515 })
8516 })?;
8517 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8518 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8519 (result.0, relative_path, None)
8520 } else {
8521 let worktree = lsp_store
8522 .update(cx, |lsp_store, cx| {
8523 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8524 worktree_store.create_worktree(&worktree_root_target, false, cx)
8525 })
8526 })?
8527 .await?;
8528 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8529 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8530 lsp_store
8531 .update(cx, |lsp_store, cx| {
8532 if let Some(local) = lsp_store.as_local_mut() {
8533 local.register_language_server_for_invisible_worktree(
8534 &worktree,
8535 language_server_id,
8536 cx,
8537 )
8538 }
8539 match lsp_store.language_server_statuses.get(&language_server_id) {
8540 Some(status) => status.worktree,
8541 None => None,
8542 }
8543 })
8544 .ok()
8545 .flatten()
8546 .zip(Some(worktree_root.clone()))
8547 } else {
8548 None
8549 };
8550 let relative_path = if let Some(known_path) = known_relative_path {
8551 known_path
8552 } else {
8553 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8554 .into_arc()
8555 };
8556 (worktree, relative_path, source_ws)
8557 };
8558 let project_path = ProjectPath {
8559 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8560 path: relative_path,
8561 };
8562 let buffer = lsp_store
8563 .update(cx, |lsp_store, cx| {
8564 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8565 buffer_store.open_buffer(project_path, cx)
8566 })
8567 })?
8568 .await?;
8569 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8570 if let Some((source_ws, worktree_root)) = source_ws {
8571 buffer.update(cx, |buffer, cx| {
8572 let settings = WorktreeSettings::get(
8573 Some(
8574 (&ProjectPath {
8575 worktree_id: source_ws,
8576 path: Arc::from(RelPath::empty()),
8577 })
8578 .into(),
8579 ),
8580 cx,
8581 );
8582 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8583 if is_read_only {
8584 buffer.set_capability(Capability::ReadOnly, cx);
8585 }
8586 });
8587 }
8588 Ok(buffer)
8589 })
8590 }
8591
8592 fn local_lsp_servers_for_buffer(
8593 &self,
8594 buffer: &Entity<Buffer>,
8595 cx: &mut Context<Self>,
8596 ) -> Vec<LanguageServerId> {
8597 let Some(local) = self.as_local() else {
8598 return Vec::new();
8599 };
8600
8601 let snapshot = buffer.read(cx).snapshot();
8602
8603 buffer.update(cx, |buffer, cx| {
8604 local
8605 .language_servers_for_buffer(buffer, cx)
8606 .map(|(_, server)| server.server_id())
8607 .filter(|server_id| {
8608 self.as_local().is_none_or(|local| {
8609 local
8610 .buffers_opened_in_servers
8611 .get(&snapshot.remote_id())
8612 .is_some_and(|servers| servers.contains(server_id))
8613 })
8614 })
8615 .collect()
8616 })
8617 }
8618
8619 fn request_multiple_lsp_locally<P, R>(
8620 &mut self,
8621 buffer: &Entity<Buffer>,
8622 position: Option<P>,
8623 request: R,
8624 cx: &mut Context<Self>,
8625 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8626 where
8627 P: ToOffset,
8628 R: LspCommand + Clone,
8629 <R::LspRequest as lsp::request::Request>::Result: Send,
8630 <R::LspRequest as lsp::request::Request>::Params: Send,
8631 {
8632 let Some(local) = self.as_local() else {
8633 return Task::ready(Vec::new());
8634 };
8635
8636 let snapshot = buffer.read(cx).snapshot();
8637 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8638
8639 let server_ids = buffer.update(cx, |buffer, cx| {
8640 local
8641 .language_servers_for_buffer(buffer, cx)
8642 .filter(|(adapter, _)| {
8643 scope
8644 .as_ref()
8645 .map(|scope| scope.language_allowed(&adapter.name))
8646 .unwrap_or(true)
8647 })
8648 .map(|(_, server)| server.server_id())
8649 .filter(|server_id| {
8650 self.as_local().is_none_or(|local| {
8651 local
8652 .buffers_opened_in_servers
8653 .get(&snapshot.remote_id())
8654 .is_some_and(|servers| servers.contains(server_id))
8655 })
8656 })
8657 .collect::<Vec<_>>()
8658 });
8659
8660 let mut response_results = server_ids
8661 .into_iter()
8662 .map(|server_id| {
8663 let task = self.request_lsp(
8664 buffer.clone(),
8665 LanguageServerToQuery::Other(server_id),
8666 request.clone(),
8667 cx,
8668 );
8669 async move { (server_id, task.await) }
8670 })
8671 .collect::<FuturesUnordered<_>>();
8672
8673 cx.background_spawn(async move {
8674 let mut responses = Vec::with_capacity(response_results.len());
8675 while let Some((server_id, response_result)) = response_results.next().await {
8676 match response_result {
8677 Ok(response) => responses.push((server_id, response)),
8678 // rust-analyzer likes to error with this when its still loading up
8679 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8680 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8681 }
8682 }
8683 responses
8684 })
8685 }
8686
8687 async fn handle_lsp_get_completions(
8688 this: Entity<Self>,
8689 envelope: TypedEnvelope<proto::GetCompletions>,
8690 mut cx: AsyncApp,
8691 ) -> Result<proto::GetCompletionsResponse> {
8692 let sender_id = envelope.original_sender_id().unwrap_or_default();
8693
8694 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8695 let buffer_handle = this.update(&mut cx, |this, cx| {
8696 this.buffer_store.read(cx).get_existing(buffer_id)
8697 })?;
8698 let request = GetCompletions::from_proto(
8699 envelope.payload,
8700 this.clone(),
8701 buffer_handle.clone(),
8702 cx.clone(),
8703 )
8704 .await?;
8705
8706 let server_to_query = match request.server_id {
8707 Some(server_id) => LanguageServerToQuery::Other(server_id),
8708 None => LanguageServerToQuery::FirstCapable,
8709 };
8710
8711 let response = this
8712 .update(&mut cx, |this, cx| {
8713 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8714 })
8715 .await?;
8716 this.update(&mut cx, |this, cx| {
8717 Ok(GetCompletions::response_to_proto(
8718 response,
8719 this,
8720 sender_id,
8721 &buffer_handle.read(cx).version(),
8722 cx,
8723 ))
8724 })
8725 }
8726
8727 async fn handle_lsp_command<T: LspCommand>(
8728 this: Entity<Self>,
8729 envelope: TypedEnvelope<T::ProtoRequest>,
8730 mut cx: AsyncApp,
8731 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8732 where
8733 <T::LspRequest as lsp::request::Request>::Params: Send,
8734 <T::LspRequest as lsp::request::Request>::Result: Send,
8735 {
8736 let sender_id = envelope.original_sender_id().unwrap_or_default();
8737 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8738 let buffer_handle = this.update(&mut cx, |this, cx| {
8739 this.buffer_store.read(cx).get_existing(buffer_id)
8740 })?;
8741 let request = T::from_proto(
8742 envelope.payload,
8743 this.clone(),
8744 buffer_handle.clone(),
8745 cx.clone(),
8746 )
8747 .await?;
8748 let response = this
8749 .update(&mut cx, |this, cx| {
8750 this.request_lsp(
8751 buffer_handle.clone(),
8752 LanguageServerToQuery::FirstCapable,
8753 request,
8754 cx,
8755 )
8756 })
8757 .await?;
8758 this.update(&mut cx, |this, cx| {
8759 Ok(T::response_to_proto(
8760 response,
8761 this,
8762 sender_id,
8763 &buffer_handle.read(cx).version(),
8764 cx,
8765 ))
8766 })
8767 }
8768
8769 async fn handle_lsp_query(
8770 lsp_store: Entity<Self>,
8771 envelope: TypedEnvelope<proto::LspQuery>,
8772 mut cx: AsyncApp,
8773 ) -> Result<proto::Ack> {
8774 use proto::lsp_query::Request;
8775 let sender_id = envelope.original_sender_id().unwrap_or_default();
8776 let lsp_query = envelope.payload;
8777 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8778 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8779 match lsp_query.request.context("invalid LSP query request")? {
8780 Request::GetReferences(get_references) => {
8781 let position = get_references.position.clone().and_then(deserialize_anchor);
8782 Self::query_lsp_locally::<GetReferences>(
8783 lsp_store,
8784 server_id,
8785 sender_id,
8786 lsp_request_id,
8787 get_references,
8788 position,
8789 &mut cx,
8790 )
8791 .await?;
8792 }
8793 Request::GetDocumentColor(get_document_color) => {
8794 Self::query_lsp_locally::<GetDocumentColor>(
8795 lsp_store,
8796 server_id,
8797 sender_id,
8798 lsp_request_id,
8799 get_document_color,
8800 None,
8801 &mut cx,
8802 )
8803 .await?;
8804 }
8805 Request::GetFoldingRanges(get_folding_ranges) => {
8806 Self::query_lsp_locally::<GetFoldingRanges>(
8807 lsp_store,
8808 server_id,
8809 sender_id,
8810 lsp_request_id,
8811 get_folding_ranges,
8812 None,
8813 &mut cx,
8814 )
8815 .await?;
8816 }
8817 Request::GetDocumentSymbols(get_document_symbols) => {
8818 Self::query_lsp_locally::<GetDocumentSymbols>(
8819 lsp_store,
8820 server_id,
8821 sender_id,
8822 lsp_request_id,
8823 get_document_symbols,
8824 None,
8825 &mut cx,
8826 )
8827 .await?;
8828 }
8829 Request::GetHover(get_hover) => {
8830 let position = get_hover.position.clone().and_then(deserialize_anchor);
8831 Self::query_lsp_locally::<GetHover>(
8832 lsp_store,
8833 server_id,
8834 sender_id,
8835 lsp_request_id,
8836 get_hover,
8837 position,
8838 &mut cx,
8839 )
8840 .await?;
8841 }
8842 Request::GetCodeActions(get_code_actions) => {
8843 Self::query_lsp_locally::<GetCodeActions>(
8844 lsp_store,
8845 server_id,
8846 sender_id,
8847 lsp_request_id,
8848 get_code_actions,
8849 None,
8850 &mut cx,
8851 )
8852 .await?;
8853 }
8854 Request::GetSignatureHelp(get_signature_help) => {
8855 let position = get_signature_help
8856 .position
8857 .clone()
8858 .and_then(deserialize_anchor);
8859 Self::query_lsp_locally::<GetSignatureHelp>(
8860 lsp_store,
8861 server_id,
8862 sender_id,
8863 lsp_request_id,
8864 get_signature_help,
8865 position,
8866 &mut cx,
8867 )
8868 .await?;
8869 }
8870 Request::GetCodeLens(get_code_lens) => {
8871 Self::query_lsp_locally::<GetCodeLens>(
8872 lsp_store,
8873 server_id,
8874 sender_id,
8875 lsp_request_id,
8876 get_code_lens,
8877 None,
8878 &mut cx,
8879 )
8880 .await?;
8881 }
8882 Request::GetDefinition(get_definition) => {
8883 let position = get_definition.position.clone().and_then(deserialize_anchor);
8884 Self::query_lsp_locally::<GetDefinitions>(
8885 lsp_store,
8886 server_id,
8887 sender_id,
8888 lsp_request_id,
8889 get_definition,
8890 position,
8891 &mut cx,
8892 )
8893 .await?;
8894 }
8895 Request::GetDeclaration(get_declaration) => {
8896 let position = get_declaration
8897 .position
8898 .clone()
8899 .and_then(deserialize_anchor);
8900 Self::query_lsp_locally::<GetDeclarations>(
8901 lsp_store,
8902 server_id,
8903 sender_id,
8904 lsp_request_id,
8905 get_declaration,
8906 position,
8907 &mut cx,
8908 )
8909 .await?;
8910 }
8911 Request::GetTypeDefinition(get_type_definition) => {
8912 let position = get_type_definition
8913 .position
8914 .clone()
8915 .and_then(deserialize_anchor);
8916 Self::query_lsp_locally::<GetTypeDefinitions>(
8917 lsp_store,
8918 server_id,
8919 sender_id,
8920 lsp_request_id,
8921 get_type_definition,
8922 position,
8923 &mut cx,
8924 )
8925 .await?;
8926 }
8927 Request::GetImplementation(get_implementation) => {
8928 let position = get_implementation
8929 .position
8930 .clone()
8931 .and_then(deserialize_anchor);
8932 Self::query_lsp_locally::<GetImplementations>(
8933 lsp_store,
8934 server_id,
8935 sender_id,
8936 lsp_request_id,
8937 get_implementation,
8938 position,
8939 &mut cx,
8940 )
8941 .await?;
8942 }
8943 Request::InlayHints(inlay_hints) => {
8944 let query_start = inlay_hints
8945 .start
8946 .clone()
8947 .and_then(deserialize_anchor)
8948 .context("invalid inlay hints range start")?;
8949 let query_end = inlay_hints
8950 .end
8951 .clone()
8952 .and_then(deserialize_anchor)
8953 .context("invalid inlay hints range end")?;
8954 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8955 &lsp_store,
8956 server_id,
8957 lsp_request_id,
8958 &inlay_hints,
8959 query_start..query_end,
8960 &mut cx,
8961 )
8962 .await
8963 .context("preparing inlay hints request")?;
8964 Self::query_lsp_locally::<InlayHints>(
8965 lsp_store,
8966 server_id,
8967 sender_id,
8968 lsp_request_id,
8969 inlay_hints,
8970 None,
8971 &mut cx,
8972 )
8973 .await
8974 .context("querying for inlay hints")?
8975 }
8976 //////////////////////////////
8977 // Below are LSP queries that need to fetch more data,
8978 // hence cannot just proxy the request to language server with `query_lsp_locally`.
8979 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8980 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
8981 &lsp_store,
8982 &get_document_diagnostics,
8983 &mut cx,
8984 )
8985 .await?;
8986 lsp_store.update(&mut cx, |lsp_store, cx| {
8987 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8988 let key = LspKey {
8989 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8990 server_queried: server_id,
8991 };
8992 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8993 ) {
8994 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8995 lsp_requests.clear();
8996 };
8997 }
8998
8999 lsp_data.lsp_requests.entry(key).or_default().insert(
9000 lsp_request_id,
9001 cx.spawn(async move |lsp_store, cx| {
9002 let diagnostics_pull = lsp_store
9003 .update(cx, |lsp_store, cx| {
9004 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9005 })
9006 .ok();
9007 if let Some(diagnostics_pull) = diagnostics_pull {
9008 match diagnostics_pull.await {
9009 Ok(()) => {}
9010 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9011 };
9012 }
9013 }),
9014 );
9015 });
9016 }
9017 Request::SemanticTokens(semantic_tokens) => {
9018 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9019 &lsp_store,
9020 &semantic_tokens,
9021 &mut cx,
9022 )
9023 .await?;
9024 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9025 lsp_store.update(&mut cx, |lsp_store, cx| {
9026 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9027 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9028 let key = LspKey {
9029 request_type: TypeId::of::<SemanticTokensFull>(),
9030 server_queried: server_id,
9031 };
9032 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9033 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9034 lsp_requests.clear();
9035 };
9036 }
9037
9038 lsp_data.lsp_requests.entry(key).or_default().insert(
9039 lsp_request_id,
9040 cx.spawn(async move |lsp_store, cx| {
9041 let tokens_fetch = lsp_store
9042 .update(cx, |lsp_store, cx| {
9043 lsp_store
9044 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9045 })
9046 .ok();
9047 if let Some(tokens_fetch) = tokens_fetch {
9048 let new_tokens = tokens_fetch.await;
9049 if let Some(new_tokens) = new_tokens {
9050 lsp_store
9051 .update(cx, |lsp_store, cx| {
9052 let response = new_tokens
9053 .into_iter()
9054 .map(|(server_id, response)| {
9055 (
9056 server_id.to_proto(),
9057 SemanticTokensFull::response_to_proto(
9058 response,
9059 lsp_store,
9060 sender_id,
9061 &buffer_version,
9062 cx,
9063 ),
9064 )
9065 })
9066 .collect::<HashMap<_, _>>();
9067 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9068 project_id,
9069 lsp_request_id,
9070 response,
9071 ) {
9072 Ok(()) => {}
9073 Err(e) => {
9074 log::error!(
9075 "Failed to send semantic tokens LSP response: {e:#}",
9076 )
9077 }
9078 }
9079 })
9080 .ok();
9081 }
9082 }
9083 }),
9084 );
9085 }
9086 });
9087 }
9088 }
9089 Ok(proto::Ack {})
9090 }
9091
9092 async fn handle_lsp_query_response(
9093 lsp_store: Entity<Self>,
9094 envelope: TypedEnvelope<proto::LspQueryResponse>,
9095 cx: AsyncApp,
9096 ) -> Result<()> {
9097 lsp_store.read_with(&cx, |lsp_store, _| {
9098 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9099 upstream_client.handle_lsp_response(envelope.clone());
9100 }
9101 });
9102 Ok(())
9103 }
9104
9105 async fn handle_apply_code_action(
9106 this: Entity<Self>,
9107 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9108 mut cx: AsyncApp,
9109 ) -> Result<proto::ApplyCodeActionResponse> {
9110 let sender_id = envelope.original_sender_id().unwrap_or_default();
9111 let action =
9112 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9113 let apply_code_action = this.update(&mut cx, |this, cx| {
9114 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9115 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9116 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9117 })?;
9118
9119 let project_transaction = apply_code_action.await?;
9120 let project_transaction = this.update(&mut cx, |this, cx| {
9121 this.buffer_store.update(cx, |buffer_store, cx| {
9122 buffer_store.serialize_project_transaction_for_peer(
9123 project_transaction,
9124 sender_id,
9125 cx,
9126 )
9127 })
9128 });
9129 Ok(proto::ApplyCodeActionResponse {
9130 transaction: Some(project_transaction),
9131 })
9132 }
9133
9134 async fn handle_register_buffer_with_language_servers(
9135 this: Entity<Self>,
9136 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9137 mut cx: AsyncApp,
9138 ) -> Result<proto::Ack> {
9139 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9140 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9141 this.update(&mut cx, |this, cx| {
9142 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9143 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9144 project_id: upstream_project_id,
9145 buffer_id: buffer_id.to_proto(),
9146 only_servers: envelope.payload.only_servers,
9147 });
9148 }
9149
9150 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9151 anyhow::bail!("buffer is not open");
9152 };
9153
9154 let handle = this.register_buffer_with_language_servers(
9155 &buffer,
9156 envelope
9157 .payload
9158 .only_servers
9159 .into_iter()
9160 .filter_map(|selector| {
9161 Some(match selector.selector? {
9162 proto::language_server_selector::Selector::ServerId(server_id) => {
9163 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9164 }
9165 proto::language_server_selector::Selector::Name(name) => {
9166 LanguageServerSelector::Name(LanguageServerName(
9167 SharedString::from(name),
9168 ))
9169 }
9170 })
9171 })
9172 .collect(),
9173 false,
9174 cx,
9175 );
9176 // Pull diagnostics for the buffer even if it was already registered.
9177 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9178 // but it's unclear if we need it.
9179 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9180 .detach();
9181 this.buffer_store().update(cx, |buffer_store, _| {
9182 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9183 });
9184
9185 Ok(())
9186 })?;
9187 Ok(proto::Ack {})
9188 }
9189
9190 async fn handle_rename_project_entry(
9191 this: Entity<Self>,
9192 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9193 mut cx: AsyncApp,
9194 ) -> Result<proto::ProjectEntryResponse> {
9195 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9196 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9197 let new_path =
9198 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9199
9200 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9201 .update(&mut cx, |this, cx| {
9202 let (worktree, entry) = this
9203 .worktree_store
9204 .read(cx)
9205 .worktree_and_entry_for_id(entry_id, cx)?;
9206 let new_worktree = this
9207 .worktree_store
9208 .read(cx)
9209 .worktree_for_id(new_worktree_id, cx)?;
9210 Some((
9211 this.worktree_store.clone(),
9212 worktree,
9213 new_worktree,
9214 entry.clone(),
9215 ))
9216 })
9217 .context("worktree not found")?;
9218 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9219 (worktree.absolutize(&old_entry.path), worktree.id())
9220 });
9221 let new_abs_path =
9222 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9223
9224 let _transaction = Self::will_rename_entry(
9225 this.downgrade(),
9226 old_worktree_id,
9227 &old_abs_path,
9228 &new_abs_path,
9229 old_entry.is_dir(),
9230 cx.clone(),
9231 )
9232 .await;
9233 let response = WorktreeStore::handle_rename_project_entry(
9234 worktree_store,
9235 envelope.payload,
9236 cx.clone(),
9237 )
9238 .await;
9239 this.read_with(&cx, |this, _| {
9240 this.did_rename_entry(
9241 old_worktree_id,
9242 &old_abs_path,
9243 &new_abs_path,
9244 old_entry.is_dir(),
9245 );
9246 });
9247 response
9248 }
9249
9250 async fn handle_update_diagnostic_summary(
9251 this: Entity<Self>,
9252 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9253 mut cx: AsyncApp,
9254 ) -> Result<()> {
9255 this.update(&mut cx, |lsp_store, cx| {
9256 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9257 let mut updated_diagnostics_paths = HashMap::default();
9258 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9259 for message_summary in envelope
9260 .payload
9261 .summary
9262 .into_iter()
9263 .chain(envelope.payload.more_summaries)
9264 {
9265 let project_path = ProjectPath {
9266 worktree_id,
9267 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9268 };
9269 let path = project_path.path.clone();
9270 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9271 let summary = DiagnosticSummary {
9272 error_count: message_summary.error_count as usize,
9273 warning_count: message_summary.warning_count as usize,
9274 };
9275
9276 if summary.is_empty() {
9277 if let Some(worktree_summaries) =
9278 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9279 && let Some(summaries) = worktree_summaries.get_mut(&path)
9280 {
9281 summaries.remove(&server_id);
9282 if summaries.is_empty() {
9283 worktree_summaries.remove(&path);
9284 }
9285 }
9286 } else {
9287 lsp_store
9288 .diagnostic_summaries
9289 .entry(worktree_id)
9290 .or_default()
9291 .entry(path)
9292 .or_default()
9293 .insert(server_id, summary);
9294 }
9295
9296 if let Some((_, project_id)) = &lsp_store.downstream_client {
9297 match &mut diagnostics_summary {
9298 Some(diagnostics_summary) => {
9299 diagnostics_summary
9300 .more_summaries
9301 .push(proto::DiagnosticSummary {
9302 path: project_path.path.as_ref().to_proto(),
9303 language_server_id: server_id.0 as u64,
9304 error_count: summary.error_count as u32,
9305 warning_count: summary.warning_count as u32,
9306 })
9307 }
9308 None => {
9309 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9310 project_id: *project_id,
9311 worktree_id: worktree_id.to_proto(),
9312 summary: Some(proto::DiagnosticSummary {
9313 path: project_path.path.as_ref().to_proto(),
9314 language_server_id: server_id.0 as u64,
9315 error_count: summary.error_count as u32,
9316 warning_count: summary.warning_count as u32,
9317 }),
9318 more_summaries: Vec::new(),
9319 })
9320 }
9321 }
9322 }
9323 updated_diagnostics_paths
9324 .entry(server_id)
9325 .or_insert_with(Vec::new)
9326 .push(project_path);
9327 }
9328
9329 if let Some((diagnostics_summary, (downstream_client, _))) =
9330 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9331 {
9332 downstream_client.send(diagnostics_summary).log_err();
9333 }
9334 for (server_id, paths) in updated_diagnostics_paths {
9335 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9336 }
9337 Ok(())
9338 })
9339 }
9340
9341 async fn handle_start_language_server(
9342 lsp_store: Entity<Self>,
9343 envelope: TypedEnvelope<proto::StartLanguageServer>,
9344 mut cx: AsyncApp,
9345 ) -> Result<()> {
9346 let server = envelope.payload.server.context("invalid server")?;
9347 let server_capabilities =
9348 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9349 .with_context(|| {
9350 format!(
9351 "incorrect server capabilities {}",
9352 envelope.payload.capabilities
9353 )
9354 })?;
9355 lsp_store.update(&mut cx, |lsp_store, cx| {
9356 let server_id = LanguageServerId(server.id as usize);
9357 let server_name = LanguageServerName::from_proto(server.name.clone());
9358 lsp_store
9359 .lsp_server_capabilities
9360 .insert(server_id, server_capabilities);
9361 lsp_store.language_server_statuses.insert(
9362 server_id,
9363 LanguageServerStatus {
9364 name: server_name.clone(),
9365 server_version: None,
9366 pending_work: Default::default(),
9367 has_pending_diagnostic_updates: false,
9368 progress_tokens: Default::default(),
9369 worktree: server.worktree_id.map(WorktreeId::from_proto),
9370 binary: None,
9371 configuration: None,
9372 workspace_folders: BTreeSet::new(),
9373 process_id: None,
9374 },
9375 );
9376 cx.emit(LspStoreEvent::LanguageServerAdded(
9377 server_id,
9378 server_name,
9379 server.worktree_id.map(WorktreeId::from_proto),
9380 ));
9381 cx.notify();
9382 });
9383 Ok(())
9384 }
9385
9386 async fn handle_update_language_server(
9387 lsp_store: Entity<Self>,
9388 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9389 mut cx: AsyncApp,
9390 ) -> Result<()> {
9391 lsp_store.update(&mut cx, |lsp_store, cx| {
9392 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9393
9394 match envelope.payload.variant.context("invalid variant")? {
9395 proto::update_language_server::Variant::WorkStart(payload) => {
9396 lsp_store.on_lsp_work_start(
9397 language_server_id,
9398 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9399 .context("invalid progress token value")?,
9400 LanguageServerProgress {
9401 title: payload.title,
9402 is_disk_based_diagnostics_progress: false,
9403 is_cancellable: payload.is_cancellable.unwrap_or(false),
9404 message: payload.message,
9405 percentage: payload.percentage.map(|p| p as usize),
9406 last_update_at: cx.background_executor().now(),
9407 },
9408 cx,
9409 );
9410 }
9411 proto::update_language_server::Variant::WorkProgress(payload) => {
9412 lsp_store.on_lsp_work_progress(
9413 language_server_id,
9414 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9415 .context("invalid progress token value")?,
9416 LanguageServerProgress {
9417 title: None,
9418 is_disk_based_diagnostics_progress: false,
9419 is_cancellable: payload.is_cancellable.unwrap_or(false),
9420 message: payload.message,
9421 percentage: payload.percentage.map(|p| p as usize),
9422 last_update_at: cx.background_executor().now(),
9423 },
9424 cx,
9425 );
9426 }
9427
9428 proto::update_language_server::Variant::WorkEnd(payload) => {
9429 lsp_store.on_lsp_work_end(
9430 language_server_id,
9431 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9432 .context("invalid progress token value")?,
9433 cx,
9434 );
9435 }
9436
9437 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9438 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9439 }
9440
9441 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9442 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9443 }
9444
9445 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9446 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9447 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9448 cx.emit(LspStoreEvent::LanguageServerUpdate {
9449 language_server_id,
9450 name: envelope
9451 .payload
9452 .server_name
9453 .map(SharedString::new)
9454 .map(LanguageServerName),
9455 message: non_lsp,
9456 });
9457 }
9458 }
9459
9460 Ok(())
9461 })
9462 }
9463
9464 async fn handle_language_server_log(
9465 this: Entity<Self>,
9466 envelope: TypedEnvelope<proto::LanguageServerLog>,
9467 mut cx: AsyncApp,
9468 ) -> Result<()> {
9469 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9470 let log_type = envelope
9471 .payload
9472 .log_type
9473 .map(LanguageServerLogType::from_proto)
9474 .context("invalid language server log type")?;
9475
9476 let message = envelope.payload.message;
9477
9478 this.update(&mut cx, |_, cx| {
9479 cx.emit(LspStoreEvent::LanguageServerLog(
9480 language_server_id,
9481 log_type,
9482 message,
9483 ));
9484 });
9485 Ok(())
9486 }
9487
9488 async fn handle_lsp_ext_cancel_flycheck(
9489 lsp_store: Entity<Self>,
9490 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9491 cx: AsyncApp,
9492 ) -> Result<proto::Ack> {
9493 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9494 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9495 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9496 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9497 } else {
9498 None
9499 }
9500 });
9501 if let Some(task) = task {
9502 task.context("handling lsp ext cancel flycheck")?;
9503 }
9504
9505 Ok(proto::Ack {})
9506 }
9507
9508 async fn handle_lsp_ext_run_flycheck(
9509 lsp_store: Entity<Self>,
9510 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9511 mut cx: AsyncApp,
9512 ) -> Result<proto::Ack> {
9513 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9514 lsp_store.update(&mut cx, |lsp_store, cx| {
9515 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9516 let text_document = if envelope.payload.current_file_only {
9517 let buffer_id = envelope
9518 .payload
9519 .buffer_id
9520 .map(|id| BufferId::new(id))
9521 .transpose()?;
9522 buffer_id
9523 .and_then(|buffer_id| {
9524 lsp_store
9525 .buffer_store()
9526 .read(cx)
9527 .get(buffer_id)
9528 .and_then(|buffer| {
9529 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9530 })
9531 .map(|path| make_text_document_identifier(&path))
9532 })
9533 .transpose()?
9534 } else {
9535 None
9536 };
9537 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9538 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9539 )?;
9540 }
9541 anyhow::Ok(())
9542 })?;
9543
9544 Ok(proto::Ack {})
9545 }
9546
9547 async fn handle_lsp_ext_clear_flycheck(
9548 lsp_store: Entity<Self>,
9549 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9550 cx: AsyncApp,
9551 ) -> Result<proto::Ack> {
9552 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9553 lsp_store.read_with(&cx, |lsp_store, _| {
9554 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9555 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9556 } else {
9557 None
9558 }
9559 });
9560
9561 Ok(proto::Ack {})
9562 }
9563
9564 pub fn disk_based_diagnostics_started(
9565 &mut self,
9566 language_server_id: LanguageServerId,
9567 cx: &mut Context<Self>,
9568 ) {
9569 if let Some(language_server_status) =
9570 self.language_server_statuses.get_mut(&language_server_id)
9571 {
9572 language_server_status.has_pending_diagnostic_updates = true;
9573 }
9574
9575 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9576 cx.emit(LspStoreEvent::LanguageServerUpdate {
9577 language_server_id,
9578 name: self
9579 .language_server_adapter_for_id(language_server_id)
9580 .map(|adapter| adapter.name()),
9581 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9582 Default::default(),
9583 ),
9584 })
9585 }
9586
9587 pub fn disk_based_diagnostics_finished(
9588 &mut self,
9589 language_server_id: LanguageServerId,
9590 cx: &mut Context<Self>,
9591 ) {
9592 if let Some(language_server_status) =
9593 self.language_server_statuses.get_mut(&language_server_id)
9594 {
9595 language_server_status.has_pending_diagnostic_updates = false;
9596 }
9597
9598 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9599 cx.emit(LspStoreEvent::LanguageServerUpdate {
9600 language_server_id,
9601 name: self
9602 .language_server_adapter_for_id(language_server_id)
9603 .map(|adapter| adapter.name()),
9604 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9605 Default::default(),
9606 ),
9607 })
9608 }
9609
9610 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9611 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9612 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9613 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9614 // the language server might take some time to publish diagnostics.
9615 fn simulate_disk_based_diagnostics_events_if_needed(
9616 &mut self,
9617 language_server_id: LanguageServerId,
9618 cx: &mut Context<Self>,
9619 ) {
9620 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9621
9622 let Some(LanguageServerState::Running {
9623 simulate_disk_based_diagnostics_completion,
9624 adapter,
9625 ..
9626 }) = self
9627 .as_local_mut()
9628 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9629 else {
9630 return;
9631 };
9632
9633 if adapter.disk_based_diagnostics_progress_token.is_some() {
9634 return;
9635 }
9636
9637 let prev_task =
9638 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9639 cx.background_executor()
9640 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9641 .await;
9642
9643 this.update(cx, |this, cx| {
9644 this.disk_based_diagnostics_finished(language_server_id, cx);
9645
9646 if let Some(LanguageServerState::Running {
9647 simulate_disk_based_diagnostics_completion,
9648 ..
9649 }) = this.as_local_mut().and_then(|local_store| {
9650 local_store.language_servers.get_mut(&language_server_id)
9651 }) {
9652 *simulate_disk_based_diagnostics_completion = None;
9653 }
9654 })
9655 .ok();
9656 }));
9657
9658 if prev_task.is_none() {
9659 self.disk_based_diagnostics_started(language_server_id, cx);
9660 }
9661 }
9662
9663 pub fn language_server_statuses(
9664 &self,
9665 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9666 self.language_server_statuses
9667 .iter()
9668 .map(|(key, value)| (*key, value))
9669 }
9670
9671 pub(super) fn did_rename_entry(
9672 &self,
9673 worktree_id: WorktreeId,
9674 old_path: &Path,
9675 new_path: &Path,
9676 is_dir: bool,
9677 ) {
9678 maybe!({
9679 let local_store = self.as_local()?;
9680
9681 let old_uri = lsp::Uri::from_file_path(old_path)
9682 .ok()
9683 .map(|uri| uri.to_string())?;
9684 let new_uri = lsp::Uri::from_file_path(new_path)
9685 .ok()
9686 .map(|uri| uri.to_string())?;
9687
9688 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9689 let Some(filter) = local_store
9690 .language_server_paths_watched_for_rename
9691 .get(&language_server.server_id())
9692 else {
9693 continue;
9694 };
9695
9696 if filter.should_send_did_rename(&old_uri, is_dir) {
9697 language_server
9698 .notify::<DidRenameFiles>(RenameFilesParams {
9699 files: vec![FileRename {
9700 old_uri: old_uri.clone(),
9701 new_uri: new_uri.clone(),
9702 }],
9703 })
9704 .ok();
9705 }
9706 }
9707 Some(())
9708 });
9709 }
9710
9711 pub(super) fn will_rename_entry(
9712 this: WeakEntity<Self>,
9713 worktree_id: WorktreeId,
9714 old_path: &Path,
9715 new_path: &Path,
9716 is_dir: bool,
9717 cx: AsyncApp,
9718 ) -> Task<ProjectTransaction> {
9719 let old_uri = lsp::Uri::from_file_path(old_path)
9720 .ok()
9721 .map(|uri| uri.to_string());
9722 let new_uri = lsp::Uri::from_file_path(new_path)
9723 .ok()
9724 .map(|uri| uri.to_string());
9725 cx.spawn(async move |cx| {
9726 let mut tasks = vec![];
9727 this.update(cx, |this, cx| {
9728 let local_store = this.as_local()?;
9729 let old_uri = old_uri?;
9730 let new_uri = new_uri?;
9731 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9732 let Some(filter) = local_store
9733 .language_server_paths_watched_for_rename
9734 .get(&language_server.server_id())
9735 else {
9736 continue;
9737 };
9738
9739 if !filter.should_send_will_rename(&old_uri, is_dir) {
9740 continue;
9741 }
9742 let request_timeout = ProjectSettings::get_global(cx)
9743 .global_lsp_settings
9744 .get_request_timeout();
9745
9746 let apply_edit = cx.spawn({
9747 let old_uri = old_uri.clone();
9748 let new_uri = new_uri.clone();
9749 let language_server = language_server.clone();
9750 async move |this, cx| {
9751 let edit = language_server
9752 .request::<WillRenameFiles>(
9753 RenameFilesParams {
9754 files: vec![FileRename { old_uri, new_uri }],
9755 },
9756 request_timeout,
9757 )
9758 .await
9759 .into_response()
9760 .context("will rename files")
9761 .log_err()
9762 .flatten()?;
9763
9764 LocalLspStore::deserialize_workspace_edit(
9765 this.upgrade()?,
9766 edit,
9767 false,
9768 language_server.clone(),
9769 cx,
9770 )
9771 .await
9772 .ok()
9773 }
9774 });
9775 tasks.push(apply_edit);
9776 }
9777 Some(())
9778 })
9779 .ok()
9780 .flatten();
9781 let mut merged_transaction = ProjectTransaction::default();
9782 for task in tasks {
9783 // Await on tasks sequentially so that the order of application of edits is deterministic
9784 // (at least with regards to the order of registration of language servers)
9785 if let Some(transaction) = task.await {
9786 for (buffer, buffer_transaction) in transaction.0 {
9787 merged_transaction.0.insert(buffer, buffer_transaction);
9788 }
9789 }
9790 }
9791 merged_transaction
9792 })
9793 }
9794
9795 fn lsp_notify_abs_paths_changed(
9796 &mut self,
9797 server_id: LanguageServerId,
9798 changes: Vec<PathEvent>,
9799 ) {
9800 maybe!({
9801 let server = self.language_server_for_id(server_id)?;
9802 let changes = changes
9803 .into_iter()
9804 .filter_map(|event| {
9805 let typ = match event.kind? {
9806 PathEventKind::Created => lsp::FileChangeType::CREATED,
9807 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9808 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9809 };
9810 Some(lsp::FileEvent {
9811 uri: file_path_to_lsp_url(&event.path).log_err()?,
9812 typ,
9813 })
9814 })
9815 .collect::<Vec<_>>();
9816 if !changes.is_empty() {
9817 server
9818 .notify::<lsp::notification::DidChangeWatchedFiles>(
9819 lsp::DidChangeWatchedFilesParams { changes },
9820 )
9821 .ok();
9822 }
9823 Some(())
9824 });
9825 }
9826
9827 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9828 self.as_local()?.language_server_for_id(id)
9829 }
9830
9831 fn on_lsp_progress(
9832 &mut self,
9833 progress_params: lsp::ProgressParams,
9834 language_server_id: LanguageServerId,
9835 disk_based_diagnostics_progress_token: Option<String>,
9836 cx: &mut Context<Self>,
9837 ) {
9838 match progress_params.value {
9839 lsp::ProgressParamsValue::WorkDone(progress) => {
9840 self.handle_work_done_progress(
9841 progress,
9842 language_server_id,
9843 disk_based_diagnostics_progress_token,
9844 ProgressToken::from_lsp(progress_params.token),
9845 cx,
9846 );
9847 }
9848 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9849 let registration_id = match progress_params.token {
9850 lsp::NumberOrString::Number(_) => None,
9851 lsp::NumberOrString::String(token) => token
9852 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9853 .map(|(_, id)| id.to_owned()),
9854 };
9855 if let Some(LanguageServerState::Running {
9856 workspace_diagnostics_refresh_tasks,
9857 ..
9858 }) = self
9859 .as_local_mut()
9860 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9861 && let Some(workspace_diagnostics) =
9862 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9863 {
9864 workspace_diagnostics.progress_tx.try_send(()).ok();
9865 self.apply_workspace_diagnostic_report(
9866 language_server_id,
9867 report,
9868 registration_id.map(SharedString::from),
9869 cx,
9870 )
9871 }
9872 }
9873 }
9874 }
9875
9876 fn handle_work_done_progress(
9877 &mut self,
9878 progress: lsp::WorkDoneProgress,
9879 language_server_id: LanguageServerId,
9880 disk_based_diagnostics_progress_token: Option<String>,
9881 token: ProgressToken,
9882 cx: &mut Context<Self>,
9883 ) {
9884 let language_server_status =
9885 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9886 status
9887 } else {
9888 return;
9889 };
9890
9891 if !language_server_status.progress_tokens.contains(&token) {
9892 return;
9893 }
9894
9895 let is_disk_based_diagnostics_progress =
9896 if let (Some(disk_based_token), ProgressToken::String(token)) =
9897 (&disk_based_diagnostics_progress_token, &token)
9898 {
9899 token.starts_with(disk_based_token)
9900 } else {
9901 false
9902 };
9903
9904 match progress {
9905 lsp::WorkDoneProgress::Begin(report) => {
9906 if is_disk_based_diagnostics_progress {
9907 self.disk_based_diagnostics_started(language_server_id, cx);
9908 }
9909 self.on_lsp_work_start(
9910 language_server_id,
9911 token.clone(),
9912 LanguageServerProgress {
9913 title: Some(report.title),
9914 is_disk_based_diagnostics_progress,
9915 is_cancellable: report.cancellable.unwrap_or(false),
9916 message: report.message.clone(),
9917 percentage: report.percentage.map(|p| p as usize),
9918 last_update_at: cx.background_executor().now(),
9919 },
9920 cx,
9921 );
9922 }
9923 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9924 language_server_id,
9925 token,
9926 LanguageServerProgress {
9927 title: None,
9928 is_disk_based_diagnostics_progress,
9929 is_cancellable: report.cancellable.unwrap_or(false),
9930 message: report.message,
9931 percentage: report.percentage.map(|p| p as usize),
9932 last_update_at: cx.background_executor().now(),
9933 },
9934 cx,
9935 ),
9936 lsp::WorkDoneProgress::End(_) => {
9937 language_server_status.progress_tokens.remove(&token);
9938 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9939 if is_disk_based_diagnostics_progress {
9940 self.disk_based_diagnostics_finished(language_server_id, cx);
9941 }
9942 }
9943 }
9944 }
9945
9946 fn on_lsp_work_start(
9947 &mut self,
9948 language_server_id: LanguageServerId,
9949 token: ProgressToken,
9950 progress: LanguageServerProgress,
9951 cx: &mut Context<Self>,
9952 ) {
9953 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9954 status.pending_work.insert(token.clone(), progress.clone());
9955 cx.notify();
9956 }
9957 cx.emit(LspStoreEvent::LanguageServerUpdate {
9958 language_server_id,
9959 name: self
9960 .language_server_adapter_for_id(language_server_id)
9961 .map(|adapter| adapter.name()),
9962 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9963 token: Some(token.to_proto()),
9964 title: progress.title,
9965 message: progress.message,
9966 percentage: progress.percentage.map(|p| p as u32),
9967 is_cancellable: Some(progress.is_cancellable),
9968 }),
9969 })
9970 }
9971
9972 fn on_lsp_work_progress(
9973 &mut self,
9974 language_server_id: LanguageServerId,
9975 token: ProgressToken,
9976 progress: LanguageServerProgress,
9977 cx: &mut Context<Self>,
9978 ) {
9979 let mut did_update = false;
9980 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9981 match status.pending_work.entry(token.clone()) {
9982 btree_map::Entry::Vacant(entry) => {
9983 entry.insert(progress.clone());
9984 did_update = true;
9985 }
9986 btree_map::Entry::Occupied(mut entry) => {
9987 let entry = entry.get_mut();
9988 if (progress.last_update_at - entry.last_update_at)
9989 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9990 {
9991 entry.last_update_at = progress.last_update_at;
9992 if progress.message.is_some() {
9993 entry.message = progress.message.clone();
9994 }
9995 if progress.percentage.is_some() {
9996 entry.percentage = progress.percentage;
9997 }
9998 if progress.is_cancellable != entry.is_cancellable {
9999 entry.is_cancellable = progress.is_cancellable;
10000 }
10001 did_update = true;
10002 }
10003 }
10004 }
10005 }
10006
10007 if did_update {
10008 cx.emit(LspStoreEvent::LanguageServerUpdate {
10009 language_server_id,
10010 name: self
10011 .language_server_adapter_for_id(language_server_id)
10012 .map(|adapter| adapter.name()),
10013 message: proto::update_language_server::Variant::WorkProgress(
10014 proto::LspWorkProgress {
10015 token: Some(token.to_proto()),
10016 message: progress.message,
10017 percentage: progress.percentage.map(|p| p as u32),
10018 is_cancellable: Some(progress.is_cancellable),
10019 },
10020 ),
10021 })
10022 }
10023 }
10024
10025 fn on_lsp_work_end(
10026 &mut self,
10027 language_server_id: LanguageServerId,
10028 token: ProgressToken,
10029 cx: &mut Context<Self>,
10030 ) {
10031 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10032 if let Some(work) = status.pending_work.remove(&token)
10033 && !work.is_disk_based_diagnostics_progress
10034 {
10035 cx.emit(LspStoreEvent::RefreshInlayHints {
10036 server_id: language_server_id,
10037 request_id: None,
10038 });
10039 }
10040 cx.notify();
10041 }
10042
10043 cx.emit(LspStoreEvent::LanguageServerUpdate {
10044 language_server_id,
10045 name: self
10046 .language_server_adapter_for_id(language_server_id)
10047 .map(|adapter| adapter.name()),
10048 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10049 token: Some(token.to_proto()),
10050 }),
10051 })
10052 }
10053
10054 pub async fn handle_resolve_completion_documentation(
10055 this: Entity<Self>,
10056 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10057 mut cx: AsyncApp,
10058 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10059 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10060
10061 let completion = this
10062 .read_with(&cx, |this, cx| {
10063 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10064 let server = this
10065 .language_server_for_id(id)
10066 .with_context(|| format!("No language server {id}"))?;
10067
10068 let request_timeout = ProjectSettings::get_global(cx)
10069 .global_lsp_settings
10070 .get_request_timeout();
10071
10072 anyhow::Ok(cx.background_spawn(async move {
10073 let can_resolve = server
10074 .capabilities()
10075 .completion_provider
10076 .as_ref()
10077 .and_then(|options| options.resolve_provider)
10078 .unwrap_or(false);
10079 if can_resolve {
10080 server
10081 .request::<lsp::request::ResolveCompletionItem>(
10082 lsp_completion,
10083 request_timeout,
10084 )
10085 .await
10086 .into_response()
10087 .context("resolve completion item")
10088 } else {
10089 anyhow::Ok(lsp_completion)
10090 }
10091 }))
10092 })?
10093 .await?;
10094
10095 let mut documentation_is_markdown = false;
10096 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10097 let documentation = match completion.documentation {
10098 Some(lsp::Documentation::String(text)) => text,
10099
10100 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10101 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10102 value
10103 }
10104
10105 _ => String::new(),
10106 };
10107
10108 // If we have a new buffer_id, that means we're talking to a new client
10109 // and want to check for new text_edits in the completion too.
10110 let mut old_replace_start = None;
10111 let mut old_replace_end = None;
10112 let mut old_insert_start = None;
10113 let mut old_insert_end = None;
10114 let mut new_text = String::default();
10115 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10116 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10117 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10118 anyhow::Ok(buffer.read(cx).snapshot())
10119 })?;
10120
10121 if let Some(text_edit) = completion.text_edit.as_ref() {
10122 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10123
10124 if let Some(mut edit) = edit {
10125 LineEnding::normalize(&mut edit.new_text);
10126
10127 new_text = edit.new_text;
10128 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10129 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10130 if let Some(insert_range) = edit.insert_range {
10131 old_insert_start = Some(serialize_anchor(&insert_range.start));
10132 old_insert_end = Some(serialize_anchor(&insert_range.end));
10133 }
10134 }
10135 }
10136 }
10137
10138 Ok(proto::ResolveCompletionDocumentationResponse {
10139 documentation,
10140 documentation_is_markdown,
10141 old_replace_start,
10142 old_replace_end,
10143 new_text,
10144 lsp_completion,
10145 old_insert_start,
10146 old_insert_end,
10147 })
10148 }
10149
10150 async fn handle_on_type_formatting(
10151 this: Entity<Self>,
10152 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10153 mut cx: AsyncApp,
10154 ) -> Result<proto::OnTypeFormattingResponse> {
10155 let on_type_formatting = this.update(&mut cx, |this, cx| {
10156 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10157 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10158 let position = envelope
10159 .payload
10160 .position
10161 .and_then(deserialize_anchor)
10162 .context("invalid position")?;
10163 anyhow::Ok(this.apply_on_type_formatting(
10164 buffer,
10165 position,
10166 envelope.payload.trigger.clone(),
10167 cx,
10168 ))
10169 })?;
10170
10171 let transaction = on_type_formatting
10172 .await?
10173 .as_ref()
10174 .map(language::proto::serialize_transaction);
10175 Ok(proto::OnTypeFormattingResponse { transaction })
10176 }
10177
10178 async fn handle_pull_workspace_diagnostics(
10179 lsp_store: Entity<Self>,
10180 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10181 mut cx: AsyncApp,
10182 ) -> Result<proto::Ack> {
10183 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10184 lsp_store.update(&mut cx, |lsp_store, _| {
10185 lsp_store.pull_workspace_diagnostics(server_id);
10186 });
10187 Ok(proto::Ack {})
10188 }
10189
10190 async fn handle_open_buffer_for_symbol(
10191 this: Entity<Self>,
10192 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10193 mut cx: AsyncApp,
10194 ) -> Result<proto::OpenBufferForSymbolResponse> {
10195 let peer_id = envelope.original_sender_id().unwrap_or_default();
10196 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10197 let symbol = Self::deserialize_symbol(symbol)?;
10198 this.read_with(&cx, |this, _| {
10199 if let SymbolLocation::OutsideProject {
10200 abs_path,
10201 signature,
10202 } = &symbol.path
10203 {
10204 let new_signature = this.symbol_signature(&abs_path);
10205 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10206 }
10207 Ok(())
10208 })?;
10209 let buffer = this
10210 .update(&mut cx, |this, cx| {
10211 this.open_buffer_for_symbol(
10212 &Symbol {
10213 language_server_name: symbol.language_server_name,
10214 source_worktree_id: symbol.source_worktree_id,
10215 source_language_server_id: symbol.source_language_server_id,
10216 path: symbol.path,
10217 name: symbol.name,
10218 kind: symbol.kind,
10219 range: symbol.range,
10220 label: CodeLabel::default(),
10221 container_name: symbol.container_name,
10222 },
10223 cx,
10224 )
10225 })
10226 .await?;
10227
10228 this.update(&mut cx, |this, cx| {
10229 let is_private = buffer
10230 .read(cx)
10231 .file()
10232 .map(|f| f.is_private())
10233 .unwrap_or_default();
10234 if is_private {
10235 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10236 } else {
10237 this.buffer_store
10238 .update(cx, |buffer_store, cx| {
10239 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10240 })
10241 .detach_and_log_err(cx);
10242 let buffer_id = buffer.read(cx).remote_id().to_proto();
10243 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10244 }
10245 })
10246 }
10247
10248 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10249 let mut hasher = Sha256::new();
10250 hasher.update(abs_path.to_string_lossy().as_bytes());
10251 hasher.update(self.nonce.to_be_bytes());
10252 hasher.finalize().as_slice().try_into().unwrap()
10253 }
10254
10255 pub async fn handle_get_project_symbols(
10256 this: Entity<Self>,
10257 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10258 mut cx: AsyncApp,
10259 ) -> Result<proto::GetProjectSymbolsResponse> {
10260 let symbols = this
10261 .update(&mut cx, |this, cx| {
10262 this.symbols(&envelope.payload.query, cx)
10263 })
10264 .await?;
10265
10266 Ok(proto::GetProjectSymbolsResponse {
10267 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10268 })
10269 }
10270
10271 pub async fn handle_restart_language_servers(
10272 this: Entity<Self>,
10273 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10274 mut cx: AsyncApp,
10275 ) -> Result<proto::Ack> {
10276 this.update(&mut cx, |lsp_store, cx| {
10277 let buffers =
10278 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10279 lsp_store.restart_language_servers_for_buffers(
10280 buffers,
10281 envelope
10282 .payload
10283 .only_servers
10284 .into_iter()
10285 .filter_map(|selector| {
10286 Some(match selector.selector? {
10287 proto::language_server_selector::Selector::ServerId(server_id) => {
10288 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10289 }
10290 proto::language_server_selector::Selector::Name(name) => {
10291 LanguageServerSelector::Name(LanguageServerName(
10292 SharedString::from(name),
10293 ))
10294 }
10295 })
10296 })
10297 .collect(),
10298 cx,
10299 );
10300 });
10301
10302 Ok(proto::Ack {})
10303 }
10304
10305 pub async fn handle_stop_language_servers(
10306 lsp_store: Entity<Self>,
10307 envelope: TypedEnvelope<proto::StopLanguageServers>,
10308 mut cx: AsyncApp,
10309 ) -> Result<proto::Ack> {
10310 lsp_store.update(&mut cx, |lsp_store, cx| {
10311 if envelope.payload.all
10312 && envelope.payload.also_servers.is_empty()
10313 && envelope.payload.buffer_ids.is_empty()
10314 {
10315 lsp_store.stop_all_language_servers(cx);
10316 } else {
10317 let buffers =
10318 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10319 lsp_store
10320 .stop_language_servers_for_buffers(
10321 buffers,
10322 envelope
10323 .payload
10324 .also_servers
10325 .into_iter()
10326 .filter_map(|selector| {
10327 Some(match selector.selector? {
10328 proto::language_server_selector::Selector::ServerId(
10329 server_id,
10330 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10331 server_id,
10332 )),
10333 proto::language_server_selector::Selector::Name(name) => {
10334 LanguageServerSelector::Name(LanguageServerName(
10335 SharedString::from(name),
10336 ))
10337 }
10338 })
10339 })
10340 .collect(),
10341 cx,
10342 )
10343 .detach_and_log_err(cx);
10344 }
10345 });
10346
10347 Ok(proto::Ack {})
10348 }
10349
10350 pub async fn handle_cancel_language_server_work(
10351 lsp_store: Entity<Self>,
10352 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10353 mut cx: AsyncApp,
10354 ) -> Result<proto::Ack> {
10355 lsp_store.update(&mut cx, |lsp_store, cx| {
10356 if let Some(work) = envelope.payload.work {
10357 match work {
10358 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10359 let buffers =
10360 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10361 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10362 }
10363 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10364 let server_id = LanguageServerId::from_proto(work.language_server_id);
10365 let token = work
10366 .token
10367 .map(|token| {
10368 ProgressToken::from_proto(token)
10369 .context("invalid work progress token")
10370 })
10371 .transpose()?;
10372 lsp_store.cancel_language_server_work(server_id, token, cx);
10373 }
10374 }
10375 }
10376 anyhow::Ok(())
10377 })?;
10378
10379 Ok(proto::Ack {})
10380 }
10381
10382 fn buffer_ids_to_buffers(
10383 &mut self,
10384 buffer_ids: impl Iterator<Item = u64>,
10385 cx: &mut Context<Self>,
10386 ) -> Vec<Entity<Buffer>> {
10387 buffer_ids
10388 .into_iter()
10389 .flat_map(|buffer_id| {
10390 self.buffer_store
10391 .read(cx)
10392 .get(BufferId::new(buffer_id).log_err()?)
10393 })
10394 .collect::<Vec<_>>()
10395 }
10396
10397 async fn handle_apply_additional_edits_for_completion(
10398 this: Entity<Self>,
10399 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10400 mut cx: AsyncApp,
10401 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10402 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10403 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10404 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10405 let completion = Self::deserialize_completion(
10406 envelope.payload.completion.context("invalid completion")?,
10407 )?;
10408 anyhow::Ok((buffer, completion))
10409 })?;
10410
10411 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10412 this.apply_additional_edits_for_completion(
10413 buffer,
10414 Rc::new(RefCell::new(Box::new([Completion {
10415 replace_range: completion.replace_range,
10416 new_text: completion.new_text,
10417 source: completion.source,
10418 documentation: None,
10419 label: CodeLabel::default(),
10420 match_start: None,
10421 snippet_deduplication_key: None,
10422 insert_text_mode: None,
10423 icon_path: None,
10424 confirm: None,
10425 }]))),
10426 0,
10427 false,
10428 cx,
10429 )
10430 });
10431
10432 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10433 transaction: apply_additional_edits
10434 .await?
10435 .as_ref()
10436 .map(language::proto::serialize_transaction),
10437 })
10438 }
10439
10440 pub fn last_formatting_failure(&self) -> Option<&str> {
10441 self.last_formatting_failure.as_deref()
10442 }
10443
10444 pub fn reset_last_formatting_failure(&mut self) {
10445 self.last_formatting_failure = None;
10446 }
10447
10448 pub fn environment_for_buffer(
10449 &self,
10450 buffer: &Entity<Buffer>,
10451 cx: &mut Context<Self>,
10452 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10453 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10454 environment.update(cx, |env, cx| {
10455 env.buffer_environment(buffer, &self.worktree_store, cx)
10456 })
10457 } else {
10458 Task::ready(None).shared()
10459 }
10460 }
10461
10462 pub fn format(
10463 &mut self,
10464 buffers: HashSet<Entity<Buffer>>,
10465 target: LspFormatTarget,
10466 push_to_history: bool,
10467 trigger: FormatTrigger,
10468 cx: &mut Context<Self>,
10469 ) -> Task<anyhow::Result<ProjectTransaction>> {
10470 let logger = zlog::scoped!("format");
10471 if self.as_local().is_some() {
10472 zlog::trace!(logger => "Formatting locally");
10473 let logger = zlog::scoped!(logger => "local");
10474 let buffers = buffers
10475 .into_iter()
10476 .map(|buffer_handle| {
10477 let buffer = buffer_handle.read(cx);
10478 let buffer_abs_path = File::from_dyn(buffer.file())
10479 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10480
10481 (buffer_handle, buffer_abs_path, buffer.remote_id())
10482 })
10483 .collect::<Vec<_>>();
10484
10485 cx.spawn(async move |lsp_store, cx| {
10486 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10487
10488 for (handle, abs_path, id) in buffers {
10489 let env = lsp_store
10490 .update(cx, |lsp_store, cx| {
10491 lsp_store.environment_for_buffer(&handle, cx)
10492 })?
10493 .await;
10494
10495 let ranges = match &target {
10496 LspFormatTarget::Buffers => None,
10497 LspFormatTarget::Ranges(ranges) => {
10498 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10499 }
10500 };
10501
10502 formattable_buffers.push(FormattableBuffer {
10503 handle,
10504 abs_path,
10505 env,
10506 ranges,
10507 });
10508 }
10509 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10510
10511 let format_timer = zlog::time!(logger => "Formatting buffers");
10512 let result = LocalLspStore::format_locally(
10513 lsp_store.clone(),
10514 formattable_buffers,
10515 push_to_history,
10516 trigger,
10517 logger,
10518 cx,
10519 )
10520 .await;
10521 format_timer.end();
10522
10523 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10524
10525 lsp_store.update(cx, |lsp_store, _| {
10526 lsp_store.update_last_formatting_failure(&result);
10527 })?;
10528
10529 result
10530 })
10531 } else if let Some((client, project_id)) = self.upstream_client() {
10532 zlog::trace!(logger => "Formatting remotely");
10533 let logger = zlog::scoped!(logger => "remote");
10534
10535 let buffer_ranges = match &target {
10536 LspFormatTarget::Buffers => Vec::new(),
10537 LspFormatTarget::Ranges(ranges) => ranges
10538 .iter()
10539 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10540 buffer_id: buffer_id.to_proto(),
10541 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10542 })
10543 .collect(),
10544 };
10545
10546 let buffer_store = self.buffer_store();
10547 cx.spawn(async move |lsp_store, cx| {
10548 zlog::trace!(logger => "Sending remote format request");
10549 let request_timer = zlog::time!(logger => "remote format request");
10550 let result = client
10551 .request(proto::FormatBuffers {
10552 project_id,
10553 trigger: trigger as i32,
10554 buffer_ids: buffers
10555 .iter()
10556 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10557 .collect(),
10558 buffer_ranges,
10559 })
10560 .await
10561 .and_then(|result| result.transaction.context("missing transaction"));
10562 request_timer.end();
10563
10564 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10565
10566 lsp_store.update(cx, |lsp_store, _| {
10567 lsp_store.update_last_formatting_failure(&result);
10568 })?;
10569
10570 let transaction_response = result?;
10571 let _timer = zlog::time!(logger => "deserializing project transaction");
10572 buffer_store
10573 .update(cx, |buffer_store, cx| {
10574 buffer_store.deserialize_project_transaction(
10575 transaction_response,
10576 push_to_history,
10577 cx,
10578 )
10579 })
10580 .await
10581 })
10582 } else {
10583 zlog::trace!(logger => "Not formatting");
10584 Task::ready(Ok(ProjectTransaction::default()))
10585 }
10586 }
10587
10588 async fn handle_format_buffers(
10589 this: Entity<Self>,
10590 envelope: TypedEnvelope<proto::FormatBuffers>,
10591 mut cx: AsyncApp,
10592 ) -> Result<proto::FormatBuffersResponse> {
10593 let sender_id = envelope.original_sender_id().unwrap_or_default();
10594 let format = this.update(&mut cx, |this, cx| {
10595 let mut buffers = HashSet::default();
10596 for buffer_id in &envelope.payload.buffer_ids {
10597 let buffer_id = BufferId::new(*buffer_id)?;
10598 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10599 }
10600
10601 let target = if envelope.payload.buffer_ranges.is_empty() {
10602 LspFormatTarget::Buffers
10603 } else {
10604 let mut ranges_map = BTreeMap::new();
10605 for buffer_range in &envelope.payload.buffer_ranges {
10606 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10607 let ranges: Result<Vec<_>> = buffer_range
10608 .ranges
10609 .iter()
10610 .map(|range| {
10611 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10612 })
10613 .collect();
10614 ranges_map.insert(buffer_id, ranges?);
10615 }
10616 LspFormatTarget::Ranges(ranges_map)
10617 };
10618
10619 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10620 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10621 })?;
10622
10623 let project_transaction = format.await?;
10624 let project_transaction = this.update(&mut cx, |this, cx| {
10625 this.buffer_store.update(cx, |buffer_store, cx| {
10626 buffer_store.serialize_project_transaction_for_peer(
10627 project_transaction,
10628 sender_id,
10629 cx,
10630 )
10631 })
10632 });
10633 Ok(proto::FormatBuffersResponse {
10634 transaction: Some(project_transaction),
10635 })
10636 }
10637
10638 async fn handle_apply_code_action_kind(
10639 this: Entity<Self>,
10640 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10641 mut cx: AsyncApp,
10642 ) -> Result<proto::ApplyCodeActionKindResponse> {
10643 let sender_id = envelope.original_sender_id().unwrap_or_default();
10644 let format = this.update(&mut cx, |this, cx| {
10645 let mut buffers = HashSet::default();
10646 for buffer_id in &envelope.payload.buffer_ids {
10647 let buffer_id = BufferId::new(*buffer_id)?;
10648 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10649 }
10650 let kind = match envelope.payload.kind.as_str() {
10651 "" => CodeActionKind::EMPTY,
10652 "quickfix" => CodeActionKind::QUICKFIX,
10653 "refactor" => CodeActionKind::REFACTOR,
10654 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10655 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10656 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10657 "source" => CodeActionKind::SOURCE,
10658 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10659 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10660 _ => anyhow::bail!(
10661 "Invalid code action kind {}",
10662 envelope.payload.kind.as_str()
10663 ),
10664 };
10665 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10666 })?;
10667
10668 let project_transaction = format.await?;
10669 let project_transaction = this.update(&mut cx, |this, cx| {
10670 this.buffer_store.update(cx, |buffer_store, cx| {
10671 buffer_store.serialize_project_transaction_for_peer(
10672 project_transaction,
10673 sender_id,
10674 cx,
10675 )
10676 })
10677 });
10678 Ok(proto::ApplyCodeActionKindResponse {
10679 transaction: Some(project_transaction),
10680 })
10681 }
10682
10683 async fn shutdown_language_server(
10684 server_state: Option<LanguageServerState>,
10685 name: LanguageServerName,
10686 cx: &mut AsyncApp,
10687 ) {
10688 let server = match server_state {
10689 Some(LanguageServerState::Starting { startup, .. }) => {
10690 let mut timer = cx
10691 .background_executor()
10692 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10693 .fuse();
10694
10695 select! {
10696 server = startup.fuse() => server,
10697 () = timer => {
10698 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10699 None
10700 },
10701 }
10702 }
10703
10704 Some(LanguageServerState::Running { server, .. }) => Some(server),
10705
10706 None => None,
10707 };
10708
10709 let Some(server) = server else { return };
10710 if let Some(shutdown) = server.shutdown() {
10711 shutdown.await;
10712 }
10713 }
10714
10715 // Returns a list of all of the worktrees which no longer have a language server and the root path
10716 // for the stopped server
10717 fn stop_local_language_server(
10718 &mut self,
10719 server_id: LanguageServerId,
10720 cx: &mut Context<Self>,
10721 ) -> Task<()> {
10722 let local = match &mut self.mode {
10723 LspStoreMode::Local(local) => local,
10724 _ => {
10725 return Task::ready(());
10726 }
10727 };
10728
10729 // Remove this server ID from all entries in the given worktree.
10730 local
10731 .language_server_ids
10732 .retain(|_, state| state.id != server_id);
10733 self.buffer_store.update(cx, |buffer_store, cx| {
10734 for buffer in buffer_store.buffers() {
10735 buffer.update(cx, |buffer, cx| {
10736 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10737 buffer.set_completion_triggers(server_id, Default::default(), cx);
10738 });
10739 }
10740 });
10741
10742 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10743 summaries.retain(|path, summaries_by_server_id| {
10744 if summaries_by_server_id.remove(&server_id).is_some() {
10745 if let Some((client, project_id)) = self.downstream_client.clone() {
10746 client
10747 .send(proto::UpdateDiagnosticSummary {
10748 project_id,
10749 worktree_id: worktree_id.to_proto(),
10750 summary: Some(proto::DiagnosticSummary {
10751 path: path.as_ref().to_proto(),
10752 language_server_id: server_id.0 as u64,
10753 error_count: 0,
10754 warning_count: 0,
10755 }),
10756 more_summaries: Vec::new(),
10757 })
10758 .log_err();
10759 }
10760 !summaries_by_server_id.is_empty()
10761 } else {
10762 true
10763 }
10764 });
10765 }
10766
10767 let local = self.as_local_mut().unwrap();
10768 for diagnostics in local.diagnostics.values_mut() {
10769 diagnostics.retain(|_, diagnostics_by_server_id| {
10770 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10771 diagnostics_by_server_id.remove(ix);
10772 !diagnostics_by_server_id.is_empty()
10773 } else {
10774 true
10775 }
10776 });
10777 }
10778 local.language_server_watched_paths.remove(&server_id);
10779
10780 let server_state = local.language_servers.remove(&server_id);
10781 self.cleanup_lsp_data(server_id);
10782 let name = self
10783 .language_server_statuses
10784 .remove(&server_id)
10785 .map(|status| status.name)
10786 .or_else(|| {
10787 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10788 Some(adapter.name())
10789 } else {
10790 None
10791 }
10792 });
10793
10794 if let Some(name) = name {
10795 log::info!("stopping language server {name}");
10796 self.languages
10797 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10798 cx.notify();
10799
10800 return cx.spawn(async move |lsp_store, cx| {
10801 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10802 lsp_store
10803 .update(cx, |lsp_store, cx| {
10804 lsp_store
10805 .languages
10806 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10807 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10808 cx.notify();
10809 })
10810 .ok();
10811 });
10812 }
10813
10814 if server_state.is_some() {
10815 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10816 }
10817 Task::ready(())
10818 }
10819
10820 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10821 self.shutdown_all_language_servers(cx).detach();
10822 }
10823
10824 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10825 if let Some((client, project_id)) = self.upstream_client() {
10826 let request = client.request(proto::StopLanguageServers {
10827 project_id,
10828 buffer_ids: Vec::new(),
10829 also_servers: Vec::new(),
10830 all: true,
10831 });
10832 cx.background_spawn(async move {
10833 request.await.ok();
10834 })
10835 } else {
10836 let Some(local) = self.as_local_mut() else {
10837 return Task::ready(());
10838 };
10839 let language_servers_to_stop = local
10840 .language_server_ids
10841 .values()
10842 .map(|state| state.id)
10843 .collect();
10844 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10845 let tasks = language_servers_to_stop
10846 .into_iter()
10847 .map(|server| self.stop_local_language_server(server, cx))
10848 .collect::<Vec<_>>();
10849 cx.background_spawn(async move {
10850 futures::future::join_all(tasks).await;
10851 })
10852 }
10853 }
10854
10855 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10856 let buffers = self.buffer_store.read(cx).buffers().collect();
10857 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10858 }
10859
10860 pub fn restart_language_servers_for_buffers(
10861 &mut self,
10862 buffers: Vec<Entity<Buffer>>,
10863 only_restart_servers: HashSet<LanguageServerSelector>,
10864 cx: &mut Context<Self>,
10865 ) {
10866 if let Some((client, project_id)) = self.upstream_client() {
10867 let request = client.request(proto::RestartLanguageServers {
10868 project_id,
10869 buffer_ids: buffers
10870 .into_iter()
10871 .map(|b| b.read(cx).remote_id().to_proto())
10872 .collect(),
10873 only_servers: only_restart_servers
10874 .into_iter()
10875 .map(|selector| {
10876 let selector = match selector {
10877 LanguageServerSelector::Id(language_server_id) => {
10878 proto::language_server_selector::Selector::ServerId(
10879 language_server_id.to_proto(),
10880 )
10881 }
10882 LanguageServerSelector::Name(language_server_name) => {
10883 proto::language_server_selector::Selector::Name(
10884 language_server_name.to_string(),
10885 )
10886 }
10887 };
10888 proto::LanguageServerSelector {
10889 selector: Some(selector),
10890 }
10891 })
10892 .collect(),
10893 all: false,
10894 });
10895 cx.background_spawn(request).detach_and_log_err(cx);
10896 } else {
10897 let stop_task = if only_restart_servers.is_empty() {
10898 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10899 } else {
10900 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10901 };
10902 cx.spawn(async move |lsp_store, cx| {
10903 stop_task.await;
10904 lsp_store.update(cx, |lsp_store, cx| {
10905 for buffer in buffers {
10906 lsp_store.register_buffer_with_language_servers(
10907 &buffer,
10908 only_restart_servers.clone(),
10909 true,
10910 cx,
10911 );
10912 }
10913 })
10914 })
10915 .detach();
10916 }
10917 }
10918
10919 pub fn stop_language_servers_for_buffers(
10920 &mut self,
10921 buffers: Vec<Entity<Buffer>>,
10922 also_stop_servers: HashSet<LanguageServerSelector>,
10923 cx: &mut Context<Self>,
10924 ) -> Task<Result<()>> {
10925 if let Some((client, project_id)) = self.upstream_client() {
10926 let request = client.request(proto::StopLanguageServers {
10927 project_id,
10928 buffer_ids: buffers
10929 .into_iter()
10930 .map(|b| b.read(cx).remote_id().to_proto())
10931 .collect(),
10932 also_servers: also_stop_servers
10933 .into_iter()
10934 .map(|selector| {
10935 let selector = match selector {
10936 LanguageServerSelector::Id(language_server_id) => {
10937 proto::language_server_selector::Selector::ServerId(
10938 language_server_id.to_proto(),
10939 )
10940 }
10941 LanguageServerSelector::Name(language_server_name) => {
10942 proto::language_server_selector::Selector::Name(
10943 language_server_name.to_string(),
10944 )
10945 }
10946 };
10947 proto::LanguageServerSelector {
10948 selector: Some(selector),
10949 }
10950 })
10951 .collect(),
10952 all: false,
10953 });
10954 cx.background_spawn(async move {
10955 let _ = request.await?;
10956 Ok(())
10957 })
10958 } else {
10959 let task =
10960 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10961 cx.background_spawn(async move {
10962 task.await;
10963 Ok(())
10964 })
10965 }
10966 }
10967
10968 fn stop_local_language_servers_for_buffers(
10969 &mut self,
10970 buffers: &[Entity<Buffer>],
10971 also_stop_servers: HashSet<LanguageServerSelector>,
10972 cx: &mut Context<Self>,
10973 ) -> Task<()> {
10974 let Some(local) = self.as_local_mut() else {
10975 return Task::ready(());
10976 };
10977 let mut language_server_names_to_stop = BTreeSet::default();
10978 let mut language_servers_to_stop = also_stop_servers
10979 .into_iter()
10980 .flat_map(|selector| match selector {
10981 LanguageServerSelector::Id(id) => Some(id),
10982 LanguageServerSelector::Name(name) => {
10983 language_server_names_to_stop.insert(name);
10984 None
10985 }
10986 })
10987 .collect::<BTreeSet<_>>();
10988
10989 let mut covered_worktrees = HashSet::default();
10990 for buffer in buffers {
10991 buffer.update(cx, |buffer, cx| {
10992 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10993 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10994 && covered_worktrees.insert(worktree_id)
10995 {
10996 language_server_names_to_stop.retain(|name| {
10997 let old_ids_count = language_servers_to_stop.len();
10998 let all_language_servers_with_this_name = local
10999 .language_server_ids
11000 .iter()
11001 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11002 language_servers_to_stop.extend(all_language_servers_with_this_name);
11003 old_ids_count == language_servers_to_stop.len()
11004 });
11005 }
11006 });
11007 }
11008 for name in language_server_names_to_stop {
11009 language_servers_to_stop.extend(
11010 local
11011 .language_server_ids
11012 .iter()
11013 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11014 );
11015 }
11016
11017 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11018 let tasks = language_servers_to_stop
11019 .into_iter()
11020 .map(|server| self.stop_local_language_server(server, cx))
11021 .collect::<Vec<_>>();
11022
11023 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11024 }
11025
11026 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11027 let (worktree, relative_path) =
11028 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11029
11030 let project_path = ProjectPath {
11031 worktree_id: worktree.read(cx).id(),
11032 path: relative_path,
11033 };
11034
11035 Some(
11036 self.buffer_store()
11037 .read(cx)
11038 .get_by_path(&project_path)?
11039 .read(cx),
11040 )
11041 }
11042
11043 #[cfg(any(test, feature = "test-support"))]
11044 pub fn update_diagnostics(
11045 &mut self,
11046 server_id: LanguageServerId,
11047 diagnostics: lsp::PublishDiagnosticsParams,
11048 result_id: Option<SharedString>,
11049 source_kind: DiagnosticSourceKind,
11050 disk_based_sources: &[String],
11051 cx: &mut Context<Self>,
11052 ) -> Result<()> {
11053 self.merge_lsp_diagnostics(
11054 source_kind,
11055 vec![DocumentDiagnosticsUpdate {
11056 diagnostics,
11057 result_id,
11058 server_id,
11059 disk_based_sources: Cow::Borrowed(disk_based_sources),
11060 registration_id: None,
11061 }],
11062 |_, _, _| false,
11063 cx,
11064 )
11065 }
11066
11067 pub fn merge_lsp_diagnostics(
11068 &mut self,
11069 source_kind: DiagnosticSourceKind,
11070 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11071 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11072 cx: &mut Context<Self>,
11073 ) -> Result<()> {
11074 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11075 let updates = lsp_diagnostics
11076 .into_iter()
11077 .filter_map(|update| {
11078 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11079 Some(DocumentDiagnosticsUpdate {
11080 diagnostics: self.lsp_to_document_diagnostics(
11081 abs_path,
11082 source_kind,
11083 update.server_id,
11084 update.diagnostics,
11085 &update.disk_based_sources,
11086 update.registration_id.clone(),
11087 ),
11088 result_id: update.result_id,
11089 server_id: update.server_id,
11090 disk_based_sources: update.disk_based_sources,
11091 registration_id: update.registration_id,
11092 })
11093 })
11094 .collect();
11095 self.merge_diagnostic_entries(updates, merge, cx)?;
11096 Ok(())
11097 }
11098
11099 fn lsp_to_document_diagnostics(
11100 &mut self,
11101 document_abs_path: PathBuf,
11102 source_kind: DiagnosticSourceKind,
11103 server_id: LanguageServerId,
11104 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11105 disk_based_sources: &[String],
11106 registration_id: Option<SharedString>,
11107 ) -> DocumentDiagnostics {
11108 let mut diagnostics = Vec::default();
11109 let mut primary_diagnostic_group_ids = HashMap::default();
11110 let mut sources_by_group_id = HashMap::default();
11111 let mut supporting_diagnostics = HashMap::default();
11112
11113 let adapter = self.language_server_adapter_for_id(server_id);
11114
11115 // Ensure that primary diagnostics are always the most severe
11116 lsp_diagnostics
11117 .diagnostics
11118 .sort_by_key(|item| item.severity);
11119
11120 for diagnostic in &lsp_diagnostics.diagnostics {
11121 let source = diagnostic.source.as_ref();
11122 let range = range_from_lsp(diagnostic.range);
11123 let is_supporting = diagnostic
11124 .related_information
11125 .as_ref()
11126 .is_some_and(|infos| {
11127 infos.iter().any(|info| {
11128 primary_diagnostic_group_ids.contains_key(&(
11129 source,
11130 diagnostic.code.clone(),
11131 range_from_lsp(info.location.range),
11132 ))
11133 })
11134 });
11135
11136 let is_unnecessary = diagnostic
11137 .tags
11138 .as_ref()
11139 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11140
11141 let underline = self
11142 .language_server_adapter_for_id(server_id)
11143 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11144
11145 if is_supporting {
11146 supporting_diagnostics.insert(
11147 (source, diagnostic.code.clone(), range),
11148 (diagnostic.severity, is_unnecessary),
11149 );
11150 } else {
11151 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11152 let is_disk_based =
11153 source.is_some_and(|source| disk_based_sources.contains(source));
11154
11155 sources_by_group_id.insert(group_id, source);
11156 primary_diagnostic_group_ids
11157 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11158
11159 diagnostics.push(DiagnosticEntry {
11160 range,
11161 diagnostic: Diagnostic {
11162 source: diagnostic.source.clone(),
11163 source_kind,
11164 code: diagnostic.code.clone(),
11165 code_description: diagnostic
11166 .code_description
11167 .as_ref()
11168 .and_then(|d| d.href.clone()),
11169 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11170 markdown: adapter.as_ref().and_then(|adapter| {
11171 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11172 }),
11173 message: diagnostic.message.trim().to_string(),
11174 group_id,
11175 is_primary: true,
11176 is_disk_based,
11177 is_unnecessary,
11178 underline,
11179 data: diagnostic.data.clone(),
11180 registration_id: registration_id.clone(),
11181 },
11182 });
11183 if let Some(infos) = &diagnostic.related_information {
11184 for info in infos {
11185 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11186 let range = range_from_lsp(info.location.range);
11187 diagnostics.push(DiagnosticEntry {
11188 range,
11189 diagnostic: Diagnostic {
11190 source: diagnostic.source.clone(),
11191 source_kind,
11192 code: diagnostic.code.clone(),
11193 code_description: diagnostic
11194 .code_description
11195 .as_ref()
11196 .and_then(|d| d.href.clone()),
11197 severity: DiagnosticSeverity::INFORMATION,
11198 markdown: adapter.as_ref().and_then(|adapter| {
11199 adapter.diagnostic_message_to_markdown(&info.message)
11200 }),
11201 message: info.message.trim().to_string(),
11202 group_id,
11203 is_primary: false,
11204 is_disk_based,
11205 is_unnecessary: false,
11206 underline,
11207 data: diagnostic.data.clone(),
11208 registration_id: registration_id.clone(),
11209 },
11210 });
11211 }
11212 }
11213 }
11214 }
11215 }
11216
11217 for entry in &mut diagnostics {
11218 let diagnostic = &mut entry.diagnostic;
11219 if !diagnostic.is_primary {
11220 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11221 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11222 source,
11223 diagnostic.code.clone(),
11224 entry.range.clone(),
11225 )) {
11226 if let Some(severity) = severity {
11227 diagnostic.severity = severity;
11228 }
11229 diagnostic.is_unnecessary = is_unnecessary;
11230 }
11231 }
11232 }
11233
11234 DocumentDiagnostics {
11235 diagnostics,
11236 document_abs_path,
11237 version: lsp_diagnostics.version,
11238 }
11239 }
11240
11241 fn insert_newly_running_language_server(
11242 &mut self,
11243 adapter: Arc<CachedLspAdapter>,
11244 language_server: Arc<LanguageServer>,
11245 server_id: LanguageServerId,
11246 key: LanguageServerSeed,
11247 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11248 cx: &mut Context<Self>,
11249 ) {
11250 let Some(local) = self.as_local_mut() else {
11251 return;
11252 };
11253 // If the language server for this key doesn't match the server id, don't store the
11254 // server. Which will cause it to be dropped, killing the process
11255 if local
11256 .language_server_ids
11257 .get(&key)
11258 .map(|state| state.id != server_id)
11259 .unwrap_or(false)
11260 {
11261 return;
11262 }
11263
11264 // Update language_servers collection with Running variant of LanguageServerState
11265 // indicating that the server is up and running and ready
11266 let workspace_folders = workspace_folders.lock().clone();
11267 language_server.set_workspace_folders(workspace_folders);
11268
11269 let workspace_diagnostics_refresh_tasks = language_server
11270 .capabilities()
11271 .diagnostic_provider
11272 .and_then(|provider| {
11273 local
11274 .language_server_dynamic_registrations
11275 .entry(server_id)
11276 .or_default()
11277 .diagnostics
11278 .entry(None)
11279 .or_insert(provider.clone());
11280 let workspace_refresher =
11281 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11282
11283 Some((None, workspace_refresher))
11284 })
11285 .into_iter()
11286 .collect();
11287 local.language_servers.insert(
11288 server_id,
11289 LanguageServerState::Running {
11290 workspace_diagnostics_refresh_tasks,
11291 adapter: adapter.clone(),
11292 server: language_server.clone(),
11293 simulate_disk_based_diagnostics_completion: None,
11294 },
11295 );
11296 local
11297 .languages
11298 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11299 if let Some(file_ops_caps) = language_server
11300 .capabilities()
11301 .workspace
11302 .as_ref()
11303 .and_then(|ws| ws.file_operations.as_ref())
11304 {
11305 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11306 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11307 if did_rename_caps.or(will_rename_caps).is_some() {
11308 let watcher = RenamePathsWatchedForServer::default()
11309 .with_did_rename_patterns(did_rename_caps)
11310 .with_will_rename_patterns(will_rename_caps);
11311 local
11312 .language_server_paths_watched_for_rename
11313 .insert(server_id, watcher);
11314 }
11315 }
11316
11317 self.language_server_statuses.insert(
11318 server_id,
11319 LanguageServerStatus {
11320 name: language_server.name(),
11321 server_version: language_server.version(),
11322 pending_work: Default::default(),
11323 has_pending_diagnostic_updates: false,
11324 progress_tokens: Default::default(),
11325 worktree: Some(key.worktree_id),
11326 binary: Some(language_server.binary().clone()),
11327 configuration: Some(language_server.configuration().clone()),
11328 workspace_folders: language_server.workspace_folders(),
11329 process_id: language_server.process_id(),
11330 },
11331 );
11332
11333 cx.emit(LspStoreEvent::LanguageServerAdded(
11334 server_id,
11335 language_server.name(),
11336 Some(key.worktree_id),
11337 ));
11338
11339 let server_capabilities = language_server.capabilities();
11340 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11341 downstream_client
11342 .send(proto::StartLanguageServer {
11343 project_id: *project_id,
11344 server: Some(proto::LanguageServer {
11345 id: server_id.to_proto(),
11346 name: language_server.name().to_string(),
11347 worktree_id: Some(key.worktree_id.to_proto()),
11348 }),
11349 capabilities: serde_json::to_string(&server_capabilities)
11350 .expect("serializing server LSP capabilities"),
11351 })
11352 .log_err();
11353 }
11354 self.lsp_server_capabilities
11355 .insert(server_id, server_capabilities);
11356
11357 // Tell the language server about every open buffer in the worktree that matches the language.
11358 // Also check for buffers in worktrees that reused this server
11359 let mut worktrees_using_server = vec![key.worktree_id];
11360 if let Some(local) = self.as_local() {
11361 // Find all worktrees that have this server in their language server tree
11362 for (worktree_id, servers) in &local.lsp_tree.instances {
11363 if *worktree_id != key.worktree_id {
11364 for server_map in servers.roots.values() {
11365 if server_map
11366 .values()
11367 .any(|(node, _)| node.id() == Some(server_id))
11368 {
11369 worktrees_using_server.push(*worktree_id);
11370 }
11371 }
11372 }
11373 }
11374 }
11375
11376 let mut buffer_paths_registered = Vec::new();
11377 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11378 let mut lsp_adapters = HashMap::default();
11379 for buffer_handle in buffer_store.buffers() {
11380 let buffer = buffer_handle.read(cx);
11381 let file = match File::from_dyn(buffer.file()) {
11382 Some(file) => file,
11383 None => continue,
11384 };
11385 let language = match buffer.language() {
11386 Some(language) => language,
11387 None => continue,
11388 };
11389
11390 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11391 || !lsp_adapters
11392 .entry(language.name())
11393 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11394 .iter()
11395 .any(|a| a.name == key.name)
11396 {
11397 continue;
11398 }
11399 // didOpen
11400 let file = match file.as_local() {
11401 Some(file) => file,
11402 None => continue,
11403 };
11404
11405 let local = self.as_local_mut().unwrap();
11406
11407 let buffer_id = buffer.remote_id();
11408 if local.registered_buffers.contains_key(&buffer_id) {
11409 let abs_path = file.abs_path(cx);
11410 let uri = match lsp::Uri::from_file_path(&abs_path) {
11411 Ok(uri) => uri,
11412 Err(()) => {
11413 log::error!("failed to convert path to URI: {:?}", abs_path);
11414 continue;
11415 }
11416 };
11417
11418 let versions = local
11419 .buffer_snapshots
11420 .entry(buffer_id)
11421 .or_default()
11422 .entry(server_id)
11423 .and_modify(|_| {
11424 assert!(
11425 false,
11426 "There should not be an existing snapshot for a newly inserted buffer"
11427 )
11428 })
11429 .or_insert_with(|| {
11430 vec![LspBufferSnapshot {
11431 version: 0,
11432 snapshot: buffer.text_snapshot(),
11433 }]
11434 });
11435
11436 let snapshot = versions.last().unwrap();
11437 let version = snapshot.version;
11438 let initial_snapshot = &snapshot.snapshot;
11439 language_server.register_buffer(
11440 uri,
11441 adapter.language_id(&language.name()),
11442 version,
11443 initial_snapshot.text(),
11444 );
11445 buffer_paths_registered.push((buffer_id, abs_path));
11446 local
11447 .buffers_opened_in_servers
11448 .entry(buffer_id)
11449 .or_default()
11450 .insert(server_id);
11451 }
11452 buffer_handle.update(cx, |buffer, cx| {
11453 buffer.set_completion_triggers(
11454 server_id,
11455 language_server
11456 .capabilities()
11457 .completion_provider
11458 .as_ref()
11459 .and_then(|provider| {
11460 provider
11461 .trigger_characters
11462 .as_ref()
11463 .map(|characters| characters.iter().cloned().collect())
11464 })
11465 .unwrap_or_default(),
11466 cx,
11467 )
11468 });
11469 }
11470 });
11471
11472 for (buffer_id, abs_path) in buffer_paths_registered {
11473 cx.emit(LspStoreEvent::LanguageServerUpdate {
11474 language_server_id: server_id,
11475 name: Some(adapter.name()),
11476 message: proto::update_language_server::Variant::RegisteredForBuffer(
11477 proto::RegisteredForBuffer {
11478 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11479 buffer_id: buffer_id.to_proto(),
11480 },
11481 ),
11482 });
11483 }
11484
11485 cx.notify();
11486 }
11487
11488 pub fn language_servers_running_disk_based_diagnostics(
11489 &self,
11490 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11491 self.language_server_statuses
11492 .iter()
11493 .filter_map(|(id, status)| {
11494 if status.has_pending_diagnostic_updates {
11495 Some(*id)
11496 } else {
11497 None
11498 }
11499 })
11500 }
11501
11502 pub(crate) fn cancel_language_server_work_for_buffers(
11503 &mut self,
11504 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11505 cx: &mut Context<Self>,
11506 ) {
11507 if let Some((client, project_id)) = self.upstream_client() {
11508 let request = client.request(proto::CancelLanguageServerWork {
11509 project_id,
11510 work: Some(proto::cancel_language_server_work::Work::Buffers(
11511 proto::cancel_language_server_work::Buffers {
11512 buffer_ids: buffers
11513 .into_iter()
11514 .map(|b| b.read(cx).remote_id().to_proto())
11515 .collect(),
11516 },
11517 )),
11518 });
11519 cx.background_spawn(request).detach_and_log_err(cx);
11520 } else if let Some(local) = self.as_local() {
11521 let servers = buffers
11522 .into_iter()
11523 .flat_map(|buffer| {
11524 buffer.update(cx, |buffer, cx| {
11525 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11526 })
11527 })
11528 .collect::<HashSet<_>>();
11529 for server_id in servers {
11530 self.cancel_language_server_work(server_id, None, cx);
11531 }
11532 }
11533 }
11534
11535 pub(crate) fn cancel_language_server_work(
11536 &mut self,
11537 server_id: LanguageServerId,
11538 token_to_cancel: Option<ProgressToken>,
11539 cx: &mut Context<Self>,
11540 ) {
11541 if let Some(local) = self.as_local() {
11542 let status = self.language_server_statuses.get(&server_id);
11543 let server = local.language_servers.get(&server_id);
11544 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11545 {
11546 for (token, progress) in &status.pending_work {
11547 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11548 && token != token_to_cancel
11549 {
11550 continue;
11551 }
11552 if progress.is_cancellable {
11553 server
11554 .notify::<lsp::notification::WorkDoneProgressCancel>(
11555 WorkDoneProgressCancelParams {
11556 token: token.to_lsp(),
11557 },
11558 )
11559 .ok();
11560 }
11561 }
11562 }
11563 } else if let Some((client, project_id)) = self.upstream_client() {
11564 let request = client.request(proto::CancelLanguageServerWork {
11565 project_id,
11566 work: Some(
11567 proto::cancel_language_server_work::Work::LanguageServerWork(
11568 proto::cancel_language_server_work::LanguageServerWork {
11569 language_server_id: server_id.to_proto(),
11570 token: token_to_cancel.map(|token| token.to_proto()),
11571 },
11572 ),
11573 ),
11574 });
11575 cx.background_spawn(request).detach_and_log_err(cx);
11576 }
11577 }
11578
11579 fn register_supplementary_language_server(
11580 &mut self,
11581 id: LanguageServerId,
11582 name: LanguageServerName,
11583 server: Arc<LanguageServer>,
11584 cx: &mut Context<Self>,
11585 ) {
11586 if let Some(local) = self.as_local_mut() {
11587 local
11588 .supplementary_language_servers
11589 .insert(id, (name.clone(), server));
11590 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11591 }
11592 }
11593
11594 fn unregister_supplementary_language_server(
11595 &mut self,
11596 id: LanguageServerId,
11597 cx: &mut Context<Self>,
11598 ) {
11599 if let Some(local) = self.as_local_mut() {
11600 local.supplementary_language_servers.remove(&id);
11601 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11602 }
11603 }
11604
11605 pub(crate) fn supplementary_language_servers(
11606 &self,
11607 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11608 self.as_local().into_iter().flat_map(|local| {
11609 local
11610 .supplementary_language_servers
11611 .iter()
11612 .map(|(id, (name, _))| (*id, name.clone()))
11613 })
11614 }
11615
11616 pub fn language_server_adapter_for_id(
11617 &self,
11618 id: LanguageServerId,
11619 ) -> Option<Arc<CachedLspAdapter>> {
11620 self.as_local()
11621 .and_then(|local| local.language_servers.get(&id))
11622 .and_then(|language_server_state| match language_server_state {
11623 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11624 _ => None,
11625 })
11626 }
11627
11628 pub(super) fn update_local_worktree_language_servers(
11629 &mut self,
11630 worktree_handle: &Entity<Worktree>,
11631 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11632 cx: &mut Context<Self>,
11633 ) {
11634 if changes.is_empty() {
11635 return;
11636 }
11637
11638 let Some(local) = self.as_local() else { return };
11639
11640 local.prettier_store.update(cx, |prettier_store, cx| {
11641 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11642 });
11643
11644 let worktree_id = worktree_handle.read(cx).id();
11645 let mut language_server_ids = local
11646 .language_server_ids
11647 .iter()
11648 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11649 .collect::<Vec<_>>();
11650 language_server_ids.sort();
11651 language_server_ids.dedup();
11652
11653 // let abs_path = worktree_handle.read(cx).abs_path();
11654 for server_id in &language_server_ids {
11655 if let Some(LanguageServerState::Running { server, .. }) =
11656 local.language_servers.get(server_id)
11657 && let Some(watched_paths) = local
11658 .language_server_watched_paths
11659 .get(server_id)
11660 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11661 {
11662 let params = lsp::DidChangeWatchedFilesParams {
11663 changes: changes
11664 .iter()
11665 .filter_map(|(path, _, change)| {
11666 if !watched_paths.is_match(path.as_std_path()) {
11667 return None;
11668 }
11669 let typ = match change {
11670 PathChange::Loaded => return None,
11671 PathChange::Added => lsp::FileChangeType::CREATED,
11672 PathChange::Removed => lsp::FileChangeType::DELETED,
11673 PathChange::Updated => lsp::FileChangeType::CHANGED,
11674 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11675 };
11676 let uri = lsp::Uri::from_file_path(
11677 worktree_handle.read(cx).absolutize(&path),
11678 )
11679 .ok()?;
11680 Some(lsp::FileEvent { uri, typ })
11681 })
11682 .collect(),
11683 };
11684 if !params.changes.is_empty() {
11685 server
11686 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11687 .ok();
11688 }
11689 }
11690 }
11691 for (path, _, _) in changes {
11692 if let Some(file_name) = path.file_name()
11693 && local.watched_manifest_filenames.contains(file_name)
11694 {
11695 self.request_workspace_config_refresh();
11696 break;
11697 }
11698 }
11699 }
11700
11701 pub fn wait_for_remote_buffer(
11702 &mut self,
11703 id: BufferId,
11704 cx: &mut Context<Self>,
11705 ) -> Task<Result<Entity<Buffer>>> {
11706 self.buffer_store.update(cx, |buffer_store, cx| {
11707 buffer_store.wait_for_remote_buffer(id, cx)
11708 })
11709 }
11710
11711 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11712 let mut result = proto::Symbol {
11713 language_server_name: symbol.language_server_name.0.to_string(),
11714 source_worktree_id: symbol.source_worktree_id.to_proto(),
11715 language_server_id: symbol.source_language_server_id.to_proto(),
11716 name: symbol.name.clone(),
11717 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11718 start: Some(proto::PointUtf16 {
11719 row: symbol.range.start.0.row,
11720 column: symbol.range.start.0.column,
11721 }),
11722 end: Some(proto::PointUtf16 {
11723 row: symbol.range.end.0.row,
11724 column: symbol.range.end.0.column,
11725 }),
11726 worktree_id: Default::default(),
11727 path: Default::default(),
11728 signature: Default::default(),
11729 container_name: symbol.container_name.clone(),
11730 };
11731 match &symbol.path {
11732 SymbolLocation::InProject(path) => {
11733 result.worktree_id = path.worktree_id.to_proto();
11734 result.path = path.path.to_proto();
11735 }
11736 SymbolLocation::OutsideProject {
11737 abs_path,
11738 signature,
11739 } => {
11740 result.path = abs_path.to_string_lossy().into_owned();
11741 result.signature = signature.to_vec();
11742 }
11743 }
11744 result
11745 }
11746
11747 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11748 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11749 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11750 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11751
11752 let path = if serialized_symbol.signature.is_empty() {
11753 SymbolLocation::InProject(ProjectPath {
11754 worktree_id,
11755 path: RelPath::from_proto(&serialized_symbol.path)
11756 .context("invalid symbol path")?,
11757 })
11758 } else {
11759 SymbolLocation::OutsideProject {
11760 abs_path: Path::new(&serialized_symbol.path).into(),
11761 signature: serialized_symbol
11762 .signature
11763 .try_into()
11764 .map_err(|_| anyhow!("invalid signature"))?,
11765 }
11766 };
11767
11768 let start = serialized_symbol.start.context("invalid start")?;
11769 let end = serialized_symbol.end.context("invalid end")?;
11770 Ok(CoreSymbol {
11771 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11772 source_worktree_id,
11773 source_language_server_id: LanguageServerId::from_proto(
11774 serialized_symbol.language_server_id,
11775 ),
11776 path,
11777 name: serialized_symbol.name,
11778 range: Unclipped(PointUtf16::new(start.row, start.column))
11779 ..Unclipped(PointUtf16::new(end.row, end.column)),
11780 kind,
11781 container_name: serialized_symbol.container_name,
11782 })
11783 }
11784
11785 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11786 let mut serialized_completion = proto::Completion {
11787 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11788 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11789 new_text: completion.new_text.clone(),
11790 ..proto::Completion::default()
11791 };
11792 match &completion.source {
11793 CompletionSource::Lsp {
11794 insert_range,
11795 server_id,
11796 lsp_completion,
11797 lsp_defaults,
11798 resolved,
11799 } => {
11800 let (old_insert_start, old_insert_end) = insert_range
11801 .as_ref()
11802 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11803 .unzip();
11804
11805 serialized_completion.old_insert_start = old_insert_start;
11806 serialized_completion.old_insert_end = old_insert_end;
11807 serialized_completion.source = proto::completion::Source::Lsp as i32;
11808 serialized_completion.server_id = server_id.0 as u64;
11809 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11810 serialized_completion.lsp_defaults = lsp_defaults
11811 .as_deref()
11812 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11813 serialized_completion.resolved = *resolved;
11814 }
11815 CompletionSource::BufferWord {
11816 word_range,
11817 resolved,
11818 } => {
11819 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11820 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11821 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11822 serialized_completion.resolved = *resolved;
11823 }
11824 CompletionSource::Custom => {
11825 serialized_completion.source = proto::completion::Source::Custom as i32;
11826 serialized_completion.resolved = true;
11827 }
11828 CompletionSource::Dap { sort_text } => {
11829 serialized_completion.source = proto::completion::Source::Dap as i32;
11830 serialized_completion.sort_text = Some(sort_text.clone());
11831 }
11832 }
11833
11834 serialized_completion
11835 }
11836
11837 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11838 let old_replace_start = completion
11839 .old_replace_start
11840 .and_then(deserialize_anchor)
11841 .context("invalid old start")?;
11842 let old_replace_end = completion
11843 .old_replace_end
11844 .and_then(deserialize_anchor)
11845 .context("invalid old end")?;
11846 let insert_range = {
11847 match completion.old_insert_start.zip(completion.old_insert_end) {
11848 Some((start, end)) => {
11849 let start = deserialize_anchor(start).context("invalid insert old start")?;
11850 let end = deserialize_anchor(end).context("invalid insert old end")?;
11851 Some(start..end)
11852 }
11853 None => None,
11854 }
11855 };
11856 Ok(CoreCompletion {
11857 replace_range: old_replace_start..old_replace_end,
11858 new_text: completion.new_text,
11859 source: match proto::completion::Source::from_i32(completion.source) {
11860 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11861 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11862 insert_range,
11863 server_id: LanguageServerId::from_proto(completion.server_id),
11864 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11865 lsp_defaults: completion
11866 .lsp_defaults
11867 .as_deref()
11868 .map(serde_json::from_slice)
11869 .transpose()?,
11870 resolved: completion.resolved,
11871 },
11872 Some(proto::completion::Source::BufferWord) => {
11873 let word_range = completion
11874 .buffer_word_start
11875 .and_then(deserialize_anchor)
11876 .context("invalid buffer word start")?
11877 ..completion
11878 .buffer_word_end
11879 .and_then(deserialize_anchor)
11880 .context("invalid buffer word end")?;
11881 CompletionSource::BufferWord {
11882 word_range,
11883 resolved: completion.resolved,
11884 }
11885 }
11886 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11887 sort_text: completion
11888 .sort_text
11889 .context("expected sort text to exist")?,
11890 },
11891 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11892 },
11893 })
11894 }
11895
11896 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11897 let (kind, lsp_action) = match &action.lsp_action {
11898 LspAction::Action(code_action) => (
11899 proto::code_action::Kind::Action as i32,
11900 serde_json::to_vec(code_action).unwrap(),
11901 ),
11902 LspAction::Command(command) => (
11903 proto::code_action::Kind::Command as i32,
11904 serde_json::to_vec(command).unwrap(),
11905 ),
11906 LspAction::CodeLens(code_lens) => (
11907 proto::code_action::Kind::CodeLens as i32,
11908 serde_json::to_vec(code_lens).unwrap(),
11909 ),
11910 };
11911
11912 proto::CodeAction {
11913 server_id: action.server_id.0 as u64,
11914 start: Some(serialize_anchor(&action.range.start)),
11915 end: Some(serialize_anchor(&action.range.end)),
11916 lsp_action,
11917 kind,
11918 resolved: action.resolved,
11919 }
11920 }
11921
11922 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11923 let start = action
11924 .start
11925 .and_then(deserialize_anchor)
11926 .context("invalid start")?;
11927 let end = action
11928 .end
11929 .and_then(deserialize_anchor)
11930 .context("invalid end")?;
11931 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11932 Some(proto::code_action::Kind::Action) => {
11933 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11934 }
11935 Some(proto::code_action::Kind::Command) => {
11936 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11937 }
11938 Some(proto::code_action::Kind::CodeLens) => {
11939 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11940 }
11941 None => anyhow::bail!("Unknown action kind {}", action.kind),
11942 };
11943 Ok(CodeAction {
11944 server_id: LanguageServerId(action.server_id as usize),
11945 range: start..end,
11946 resolved: action.resolved,
11947 lsp_action,
11948 })
11949 }
11950
11951 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11952 match &formatting_result {
11953 Ok(_) => self.last_formatting_failure = None,
11954 Err(error) => {
11955 let error_string = format!("{error:#}");
11956 log::error!("Formatting failed: {error_string}");
11957 self.last_formatting_failure
11958 .replace(error_string.lines().join(" "));
11959 }
11960 }
11961 }
11962
11963 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11964 self.lsp_server_capabilities.remove(&for_server);
11965 self.semantic_token_config.remove_server_data(for_server);
11966 for lsp_data in self.lsp_data.values_mut() {
11967 lsp_data.remove_server_data(for_server);
11968 }
11969 if let Some(local) = self.as_local_mut() {
11970 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11971 local
11972 .workspace_pull_diagnostics_result_ids
11973 .remove(&for_server);
11974 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11975 buffer_servers.remove(&for_server);
11976 }
11977 }
11978 }
11979
11980 pub fn result_id_for_buffer_pull(
11981 &self,
11982 server_id: LanguageServerId,
11983 buffer_id: BufferId,
11984 registration_id: &Option<SharedString>,
11985 cx: &App,
11986 ) -> Option<SharedString> {
11987 let abs_path = self
11988 .buffer_store
11989 .read(cx)
11990 .get(buffer_id)
11991 .and_then(|b| File::from_dyn(b.read(cx).file()))
11992 .map(|f| f.abs_path(cx))?;
11993 self.as_local()?
11994 .buffer_pull_diagnostics_result_ids
11995 .get(&server_id)?
11996 .get(registration_id)?
11997 .get(&abs_path)?
11998 .clone()
11999 }
12000
12001 /// Gets all result_ids for a workspace diagnostics pull request.
12002 /// 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.
12003 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12004 pub fn result_ids_for_workspace_refresh(
12005 &self,
12006 server_id: LanguageServerId,
12007 registration_id: &Option<SharedString>,
12008 ) -> HashMap<PathBuf, SharedString> {
12009 let Some(local) = self.as_local() else {
12010 return HashMap::default();
12011 };
12012 local
12013 .workspace_pull_diagnostics_result_ids
12014 .get(&server_id)
12015 .into_iter()
12016 .filter_map(|diagnostics| diagnostics.get(registration_id))
12017 .flatten()
12018 .filter_map(|(abs_path, result_id)| {
12019 let result_id = local
12020 .buffer_pull_diagnostics_result_ids
12021 .get(&server_id)
12022 .and_then(|buffer_ids_result_ids| {
12023 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12024 })
12025 .cloned()
12026 .flatten()
12027 .or_else(|| result_id.clone())?;
12028 Some((abs_path.clone(), result_id))
12029 })
12030 .collect()
12031 }
12032
12033 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12034 if let Some(LanguageServerState::Running {
12035 workspace_diagnostics_refresh_tasks,
12036 ..
12037 }) = self
12038 .as_local_mut()
12039 .and_then(|local| local.language_servers.get_mut(&server_id))
12040 {
12041 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12042 diagnostics.refresh_tx.try_send(()).ok();
12043 }
12044 }
12045 }
12046
12047 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12048 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12049 /// which requires refreshing both workspace and document diagnostics.
12050 pub fn pull_document_diagnostics_for_server(
12051 &mut self,
12052 server_id: LanguageServerId,
12053 source_buffer_id: Option<BufferId>,
12054 cx: &mut Context<Self>,
12055 ) -> Shared<Task<()>> {
12056 let Some(local) = self.as_local_mut() else {
12057 return Task::ready(()).shared();
12058 };
12059 let mut buffers_to_refresh = HashSet::default();
12060 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12061 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12062 buffers_to_refresh.insert(*buffer_id);
12063 }
12064 }
12065
12066 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12067 }
12068
12069 pub fn pull_document_diagnostics_for_buffer_edit(
12070 &mut self,
12071 buffer_id: BufferId,
12072 cx: &mut Context<Self>,
12073 ) {
12074 let Some(local) = self.as_local_mut() else {
12075 return;
12076 };
12077 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12078 else {
12079 return;
12080 };
12081 for server_id in languages_servers {
12082 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12083 }
12084 }
12085
12086 fn apply_workspace_diagnostic_report(
12087 &mut self,
12088 server_id: LanguageServerId,
12089 report: lsp::WorkspaceDiagnosticReportResult,
12090 registration_id: Option<SharedString>,
12091 cx: &mut Context<Self>,
12092 ) {
12093 let mut workspace_diagnostics =
12094 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12095 report,
12096 server_id,
12097 registration_id,
12098 );
12099 workspace_diagnostics.retain(|d| match &d.diagnostics {
12100 LspPullDiagnostics::Response {
12101 server_id,
12102 registration_id,
12103 ..
12104 } => self.diagnostic_registration_exists(*server_id, registration_id),
12105 LspPullDiagnostics::Default => false,
12106 });
12107 let mut unchanged_buffers = HashMap::default();
12108 let workspace_diagnostics_updates = workspace_diagnostics
12109 .into_iter()
12110 .filter_map(
12111 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12112 LspPullDiagnostics::Response {
12113 server_id,
12114 uri,
12115 diagnostics,
12116 registration_id,
12117 } => Some((
12118 server_id,
12119 uri,
12120 diagnostics,
12121 workspace_diagnostics.version,
12122 registration_id,
12123 )),
12124 LspPullDiagnostics::Default => None,
12125 },
12126 )
12127 .fold(
12128 HashMap::default(),
12129 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12130 let (result_id, diagnostics) = match diagnostics {
12131 PulledDiagnostics::Unchanged { result_id } => {
12132 unchanged_buffers
12133 .entry(new_registration_id.clone())
12134 .or_insert_with(HashSet::default)
12135 .insert(uri.clone());
12136 (Some(result_id), Vec::new())
12137 }
12138 PulledDiagnostics::Changed {
12139 result_id,
12140 diagnostics,
12141 } => (result_id, diagnostics),
12142 };
12143 let disk_based_sources = Cow::Owned(
12144 self.language_server_adapter_for_id(server_id)
12145 .as_ref()
12146 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12147 .unwrap_or(&[])
12148 .to_vec(),
12149 );
12150
12151 let Some(abs_path) = uri.to_file_path().ok() else {
12152 return acc;
12153 };
12154 let Some((worktree, relative_path)) =
12155 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12156 else {
12157 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12158 return acc;
12159 };
12160 let worktree_id = worktree.read(cx).id();
12161 let project_path = ProjectPath {
12162 worktree_id,
12163 path: relative_path,
12164 };
12165 if let Some(local_lsp_store) = self.as_local_mut() {
12166 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12167 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12168 }
12169 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12170 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12171 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12172 acc.entry(server_id)
12173 .or_insert_with(HashMap::default)
12174 .entry(new_registration_id.clone())
12175 .or_insert_with(Vec::new)
12176 .push(DocumentDiagnosticsUpdate {
12177 server_id,
12178 diagnostics: lsp::PublishDiagnosticsParams {
12179 uri,
12180 diagnostics,
12181 version,
12182 },
12183 result_id: result_id.map(SharedString::new),
12184 disk_based_sources,
12185 registration_id: new_registration_id,
12186 });
12187 }
12188 acc
12189 },
12190 );
12191
12192 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12193 for (registration_id, diagnostic_updates) in diagnostic_updates {
12194 self.merge_lsp_diagnostics(
12195 DiagnosticSourceKind::Pulled,
12196 diagnostic_updates,
12197 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12198 DiagnosticSourceKind::Pulled => {
12199 old_diagnostic.registration_id != registration_id
12200 || unchanged_buffers
12201 .get(&old_diagnostic.registration_id)
12202 .is_some_and(|unchanged_buffers| {
12203 unchanged_buffers.contains(&document_uri)
12204 })
12205 }
12206 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12207 },
12208 cx,
12209 )
12210 .log_err();
12211 }
12212 }
12213 }
12214
12215 fn register_server_capabilities(
12216 &mut self,
12217 server_id: LanguageServerId,
12218 params: lsp::RegistrationParams,
12219 cx: &mut Context<Self>,
12220 ) -> anyhow::Result<()> {
12221 let server = self
12222 .language_server_for_id(server_id)
12223 .with_context(|| format!("no server {server_id} found"))?;
12224 for reg in params.registrations {
12225 match reg.method.as_str() {
12226 "workspace/didChangeWatchedFiles" => {
12227 if let Some(options) = reg.register_options {
12228 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12229 let caps = serde_json::from_value(options)?;
12230 local_lsp_store
12231 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12232 true
12233 } else {
12234 false
12235 };
12236 if notify {
12237 notify_server_capabilities_updated(&server, cx);
12238 }
12239 }
12240 }
12241 "workspace/didChangeConfiguration" => {
12242 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12243 }
12244 "workspace/didChangeWorkspaceFolders" => {
12245 // In this case register options is an empty object, we can ignore it
12246 let caps = lsp::WorkspaceFoldersServerCapabilities {
12247 supported: Some(true),
12248 change_notifications: Some(OneOf::Right(reg.id)),
12249 };
12250 server.update_capabilities(|capabilities| {
12251 capabilities
12252 .workspace
12253 .get_or_insert_default()
12254 .workspace_folders = Some(caps);
12255 });
12256 notify_server_capabilities_updated(&server, cx);
12257 }
12258 "workspace/symbol" => {
12259 let options = parse_register_capabilities(reg)?;
12260 server.update_capabilities(|capabilities| {
12261 capabilities.workspace_symbol_provider = Some(options);
12262 });
12263 notify_server_capabilities_updated(&server, cx);
12264 }
12265 "workspace/fileOperations" => {
12266 if let Some(options) = reg.register_options {
12267 let caps = serde_json::from_value(options)?;
12268 server.update_capabilities(|capabilities| {
12269 capabilities
12270 .workspace
12271 .get_or_insert_default()
12272 .file_operations = Some(caps);
12273 });
12274 notify_server_capabilities_updated(&server, cx);
12275 }
12276 }
12277 "workspace/executeCommand" => {
12278 if let Some(options) = reg.register_options {
12279 let options = serde_json::from_value(options)?;
12280 server.update_capabilities(|capabilities| {
12281 capabilities.execute_command_provider = Some(options);
12282 });
12283 notify_server_capabilities_updated(&server, cx);
12284 }
12285 }
12286 "textDocument/rangeFormatting" => {
12287 let options = parse_register_capabilities(reg)?;
12288 server.update_capabilities(|capabilities| {
12289 capabilities.document_range_formatting_provider = Some(options);
12290 });
12291 notify_server_capabilities_updated(&server, cx);
12292 }
12293 "textDocument/onTypeFormatting" => {
12294 if let Some(options) = reg
12295 .register_options
12296 .map(serde_json::from_value)
12297 .transpose()?
12298 {
12299 server.update_capabilities(|capabilities| {
12300 capabilities.document_on_type_formatting_provider = Some(options);
12301 });
12302 notify_server_capabilities_updated(&server, cx);
12303 }
12304 }
12305 "textDocument/formatting" => {
12306 let options = parse_register_capabilities(reg)?;
12307 server.update_capabilities(|capabilities| {
12308 capabilities.document_formatting_provider = Some(options);
12309 });
12310 notify_server_capabilities_updated(&server, cx);
12311 }
12312 "textDocument/rename" => {
12313 let options = parse_register_capabilities(reg)?;
12314 server.update_capabilities(|capabilities| {
12315 capabilities.rename_provider = Some(options);
12316 });
12317 notify_server_capabilities_updated(&server, cx);
12318 }
12319 "textDocument/inlayHint" => {
12320 let options = parse_register_capabilities(reg)?;
12321 server.update_capabilities(|capabilities| {
12322 capabilities.inlay_hint_provider = Some(options);
12323 });
12324 notify_server_capabilities_updated(&server, cx);
12325 }
12326 "textDocument/documentSymbol" => {
12327 let options = parse_register_capabilities(reg)?;
12328 server.update_capabilities(|capabilities| {
12329 capabilities.document_symbol_provider = Some(options);
12330 });
12331 notify_server_capabilities_updated(&server, cx);
12332 }
12333 "textDocument/codeAction" => {
12334 let options = parse_register_capabilities(reg)?;
12335 let provider = match options {
12336 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12337 OneOf::Right(caps) => caps,
12338 };
12339 server.update_capabilities(|capabilities| {
12340 capabilities.code_action_provider = Some(provider);
12341 });
12342 notify_server_capabilities_updated(&server, cx);
12343 }
12344 "textDocument/definition" => {
12345 let options = parse_register_capabilities(reg)?;
12346 server.update_capabilities(|capabilities| {
12347 capabilities.definition_provider = Some(options);
12348 });
12349 notify_server_capabilities_updated(&server, cx);
12350 }
12351 "textDocument/completion" => {
12352 if let Some(caps) = reg
12353 .register_options
12354 .map(serde_json::from_value::<CompletionOptions>)
12355 .transpose()?
12356 {
12357 server.update_capabilities(|capabilities| {
12358 capabilities.completion_provider = Some(caps.clone());
12359 });
12360
12361 if let Some(local) = self.as_local() {
12362 let mut buffers_with_language_server = Vec::new();
12363 for handle in self.buffer_store.read(cx).buffers() {
12364 let buffer_id = handle.read(cx).remote_id();
12365 if local
12366 .buffers_opened_in_servers
12367 .get(&buffer_id)
12368 .filter(|s| s.contains(&server_id))
12369 .is_some()
12370 {
12371 buffers_with_language_server.push(handle);
12372 }
12373 }
12374 let triggers = caps
12375 .trigger_characters
12376 .unwrap_or_default()
12377 .into_iter()
12378 .collect::<BTreeSet<_>>();
12379 for handle in buffers_with_language_server {
12380 let triggers = triggers.clone();
12381 let _ = handle.update(cx, move |buffer, cx| {
12382 buffer.set_completion_triggers(server_id, triggers, cx);
12383 });
12384 }
12385 }
12386 notify_server_capabilities_updated(&server, cx);
12387 }
12388 }
12389 "textDocument/hover" => {
12390 let options = parse_register_capabilities(reg)?;
12391 let provider = match options {
12392 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12393 OneOf::Right(caps) => caps,
12394 };
12395 server.update_capabilities(|capabilities| {
12396 capabilities.hover_provider = Some(provider);
12397 });
12398 notify_server_capabilities_updated(&server, cx);
12399 }
12400 "textDocument/signatureHelp" => {
12401 if let Some(caps) = reg
12402 .register_options
12403 .map(serde_json::from_value)
12404 .transpose()?
12405 {
12406 server.update_capabilities(|capabilities| {
12407 capabilities.signature_help_provider = Some(caps);
12408 });
12409 notify_server_capabilities_updated(&server, cx);
12410 }
12411 }
12412 "textDocument/didChange" => {
12413 if let Some(sync_kind) = reg
12414 .register_options
12415 .and_then(|opts| opts.get("syncKind").cloned())
12416 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12417 .transpose()?
12418 {
12419 server.update_capabilities(|capabilities| {
12420 let mut sync_options =
12421 Self::take_text_document_sync_options(capabilities);
12422 sync_options.change = Some(sync_kind);
12423 capabilities.text_document_sync =
12424 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12425 });
12426 notify_server_capabilities_updated(&server, cx);
12427 }
12428 }
12429 "textDocument/didSave" => {
12430 if let Some(include_text) = reg
12431 .register_options
12432 .map(|opts| {
12433 let transpose = opts
12434 .get("includeText")
12435 .cloned()
12436 .map(serde_json::from_value::<Option<bool>>)
12437 .transpose();
12438 match transpose {
12439 Ok(value) => Ok(value.flatten()),
12440 Err(e) => Err(e),
12441 }
12442 })
12443 .transpose()?
12444 {
12445 server.update_capabilities(|capabilities| {
12446 let mut sync_options =
12447 Self::take_text_document_sync_options(capabilities);
12448 sync_options.save =
12449 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12450 include_text,
12451 }));
12452 capabilities.text_document_sync =
12453 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12454 });
12455 notify_server_capabilities_updated(&server, cx);
12456 }
12457 }
12458 "textDocument/codeLens" => {
12459 if let Some(caps) = reg
12460 .register_options
12461 .map(serde_json::from_value)
12462 .transpose()?
12463 {
12464 server.update_capabilities(|capabilities| {
12465 capabilities.code_lens_provider = Some(caps);
12466 });
12467 notify_server_capabilities_updated(&server, cx);
12468 }
12469 }
12470 "textDocument/diagnostic" => {
12471 if let Some(caps) = reg
12472 .register_options
12473 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12474 .transpose()?
12475 {
12476 let local = self
12477 .as_local_mut()
12478 .context("Expected LSP Store to be local")?;
12479 let state = local
12480 .language_servers
12481 .get_mut(&server_id)
12482 .context("Could not obtain Language Servers state")?;
12483 local
12484 .language_server_dynamic_registrations
12485 .entry(server_id)
12486 .or_default()
12487 .diagnostics
12488 .insert(Some(reg.id.clone()), caps.clone());
12489
12490 let supports_workspace_diagnostics =
12491 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12492 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12493 diagnostic_options.workspace_diagnostics
12494 }
12495 DiagnosticServerCapabilities::RegistrationOptions(
12496 diagnostic_registration_options,
12497 ) => {
12498 diagnostic_registration_options
12499 .diagnostic_options
12500 .workspace_diagnostics
12501 }
12502 };
12503
12504 if supports_workspace_diagnostics(&caps) {
12505 if let LanguageServerState::Running {
12506 workspace_diagnostics_refresh_tasks,
12507 ..
12508 } = state
12509 && let Some(task) = lsp_workspace_diagnostics_refresh(
12510 Some(reg.id.clone()),
12511 caps.clone(),
12512 server.clone(),
12513 cx,
12514 )
12515 {
12516 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12517 }
12518 }
12519
12520 server.update_capabilities(|capabilities| {
12521 capabilities.diagnostic_provider = Some(caps);
12522 });
12523
12524 notify_server_capabilities_updated(&server, cx);
12525
12526 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12527 }
12528 }
12529 "textDocument/documentColor" => {
12530 let options = parse_register_capabilities(reg)?;
12531 let provider = match options {
12532 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12533 OneOf::Right(caps) => caps,
12534 };
12535 server.update_capabilities(|capabilities| {
12536 capabilities.color_provider = Some(provider);
12537 });
12538 notify_server_capabilities_updated(&server, cx);
12539 }
12540 "textDocument/foldingRange" => {
12541 let options = parse_register_capabilities(reg)?;
12542 let provider = match options {
12543 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12544 OneOf::Right(caps) => caps,
12545 };
12546 server.update_capabilities(|capabilities| {
12547 capabilities.folding_range_provider = Some(provider);
12548 });
12549 notify_server_capabilities_updated(&server, cx);
12550 }
12551 _ => log::warn!("unhandled capability registration: {reg:?}"),
12552 }
12553 }
12554
12555 Ok(())
12556 }
12557
12558 fn unregister_server_capabilities(
12559 &mut self,
12560 server_id: LanguageServerId,
12561 params: lsp::UnregistrationParams,
12562 cx: &mut Context<Self>,
12563 ) -> anyhow::Result<()> {
12564 let server = self
12565 .language_server_for_id(server_id)
12566 .with_context(|| format!("no server {server_id} found"))?;
12567 for unreg in params.unregisterations.iter() {
12568 match unreg.method.as_str() {
12569 "workspace/didChangeWatchedFiles" => {
12570 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12571 local_lsp_store
12572 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12573 true
12574 } else {
12575 false
12576 };
12577 if notify {
12578 notify_server_capabilities_updated(&server, cx);
12579 }
12580 }
12581 "workspace/didChangeConfiguration" => {
12582 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12583 }
12584 "workspace/didChangeWorkspaceFolders" => {
12585 server.update_capabilities(|capabilities| {
12586 capabilities
12587 .workspace
12588 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12589 workspace_folders: None,
12590 file_operations: None,
12591 })
12592 .workspace_folders = None;
12593 });
12594 notify_server_capabilities_updated(&server, cx);
12595 }
12596 "workspace/symbol" => {
12597 server.update_capabilities(|capabilities| {
12598 capabilities.workspace_symbol_provider = None
12599 });
12600 notify_server_capabilities_updated(&server, cx);
12601 }
12602 "workspace/fileOperations" => {
12603 server.update_capabilities(|capabilities| {
12604 capabilities
12605 .workspace
12606 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12607 workspace_folders: None,
12608 file_operations: None,
12609 })
12610 .file_operations = None;
12611 });
12612 notify_server_capabilities_updated(&server, cx);
12613 }
12614 "workspace/executeCommand" => {
12615 server.update_capabilities(|capabilities| {
12616 capabilities.execute_command_provider = None;
12617 });
12618 notify_server_capabilities_updated(&server, cx);
12619 }
12620 "textDocument/rangeFormatting" => {
12621 server.update_capabilities(|capabilities| {
12622 capabilities.document_range_formatting_provider = None
12623 });
12624 notify_server_capabilities_updated(&server, cx);
12625 }
12626 "textDocument/onTypeFormatting" => {
12627 server.update_capabilities(|capabilities| {
12628 capabilities.document_on_type_formatting_provider = None;
12629 });
12630 notify_server_capabilities_updated(&server, cx);
12631 }
12632 "textDocument/formatting" => {
12633 server.update_capabilities(|capabilities| {
12634 capabilities.document_formatting_provider = None;
12635 });
12636 notify_server_capabilities_updated(&server, cx);
12637 }
12638 "textDocument/rename" => {
12639 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12640 notify_server_capabilities_updated(&server, cx);
12641 }
12642 "textDocument/codeAction" => {
12643 server.update_capabilities(|capabilities| {
12644 capabilities.code_action_provider = None;
12645 });
12646 notify_server_capabilities_updated(&server, cx);
12647 }
12648 "textDocument/definition" => {
12649 server.update_capabilities(|capabilities| {
12650 capabilities.definition_provider = None;
12651 });
12652 notify_server_capabilities_updated(&server, cx);
12653 }
12654 "textDocument/completion" => {
12655 server.update_capabilities(|capabilities| {
12656 capabilities.completion_provider = None;
12657 });
12658 notify_server_capabilities_updated(&server, cx);
12659 }
12660 "textDocument/hover" => {
12661 server.update_capabilities(|capabilities| {
12662 capabilities.hover_provider = None;
12663 });
12664 notify_server_capabilities_updated(&server, cx);
12665 }
12666 "textDocument/signatureHelp" => {
12667 server.update_capabilities(|capabilities| {
12668 capabilities.signature_help_provider = None;
12669 });
12670 notify_server_capabilities_updated(&server, cx);
12671 }
12672 "textDocument/didChange" => {
12673 server.update_capabilities(|capabilities| {
12674 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12675 sync_options.change = None;
12676 capabilities.text_document_sync =
12677 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12678 });
12679 notify_server_capabilities_updated(&server, cx);
12680 }
12681 "textDocument/didSave" => {
12682 server.update_capabilities(|capabilities| {
12683 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12684 sync_options.save = None;
12685 capabilities.text_document_sync =
12686 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12687 });
12688 notify_server_capabilities_updated(&server, cx);
12689 }
12690 "textDocument/codeLens" => {
12691 server.update_capabilities(|capabilities| {
12692 capabilities.code_lens_provider = None;
12693 });
12694 notify_server_capabilities_updated(&server, cx);
12695 }
12696 "textDocument/diagnostic" => {
12697 let local = self
12698 .as_local_mut()
12699 .context("Expected LSP Store to be local")?;
12700
12701 let state = local
12702 .language_servers
12703 .get_mut(&server_id)
12704 .context("Could not obtain Language Servers state")?;
12705 let registrations = local
12706 .language_server_dynamic_registrations
12707 .get_mut(&server_id)
12708 .with_context(|| {
12709 format!("Expected dynamic registration to exist for server {server_id}")
12710 })?;
12711 registrations.diagnostics
12712 .remove(&Some(unreg.id.clone()))
12713 .with_context(|| format!(
12714 "Attempted to unregister non-existent diagnostic registration with ID {}",
12715 unreg.id)
12716 )?;
12717 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12718
12719 if let LanguageServerState::Running {
12720 workspace_diagnostics_refresh_tasks,
12721 ..
12722 } = state
12723 {
12724 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12725 }
12726
12727 self.clear_unregistered_diagnostics(
12728 server_id,
12729 SharedString::from(unreg.id.clone()),
12730 cx,
12731 )?;
12732
12733 if removed_last_diagnostic_provider {
12734 server.update_capabilities(|capabilities| {
12735 debug_assert!(capabilities.diagnostic_provider.is_some());
12736 capabilities.diagnostic_provider = None;
12737 });
12738 }
12739
12740 notify_server_capabilities_updated(&server, cx);
12741 }
12742 "textDocument/documentColor" => {
12743 server.update_capabilities(|capabilities| {
12744 capabilities.color_provider = None;
12745 });
12746 notify_server_capabilities_updated(&server, cx);
12747 }
12748 "textDocument/foldingRange" => {
12749 server.update_capabilities(|capabilities| {
12750 capabilities.folding_range_provider = None;
12751 });
12752 notify_server_capabilities_updated(&server, cx);
12753 }
12754 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12755 }
12756 }
12757
12758 Ok(())
12759 }
12760
12761 fn clear_unregistered_diagnostics(
12762 &mut self,
12763 server_id: LanguageServerId,
12764 cleared_registration_id: SharedString,
12765 cx: &mut Context<Self>,
12766 ) -> anyhow::Result<()> {
12767 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12768
12769 self.buffer_store.update(cx, |buffer_store, cx| {
12770 for buffer_handle in buffer_store.buffers() {
12771 let buffer = buffer_handle.read(cx);
12772 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12773 let Some(abs_path) = abs_path else {
12774 continue;
12775 };
12776 affected_abs_paths.insert(abs_path);
12777 }
12778 });
12779
12780 let local = self.as_local().context("Expected LSP Store to be local")?;
12781 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12782 let Some(worktree) = self
12783 .worktree_store
12784 .read(cx)
12785 .worktree_for_id(*worktree_id, cx)
12786 else {
12787 continue;
12788 };
12789
12790 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12791 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12792 let has_matching_registration =
12793 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12794 entry.diagnostic.registration_id.as_ref()
12795 == Some(&cleared_registration_id)
12796 });
12797 if has_matching_registration {
12798 let abs_path = worktree.read(cx).absolutize(rel_path);
12799 affected_abs_paths.insert(abs_path);
12800 }
12801 }
12802 }
12803 }
12804
12805 if affected_abs_paths.is_empty() {
12806 return Ok(());
12807 }
12808
12809 // Send a fake diagnostic update which clears the state for the registration ID
12810 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12811 affected_abs_paths
12812 .into_iter()
12813 .map(|abs_path| DocumentDiagnosticsUpdate {
12814 diagnostics: DocumentDiagnostics {
12815 diagnostics: Vec::new(),
12816 document_abs_path: abs_path,
12817 version: None,
12818 },
12819 result_id: None,
12820 registration_id: Some(cleared_registration_id.clone()),
12821 server_id,
12822 disk_based_sources: Cow::Borrowed(&[]),
12823 })
12824 .collect();
12825
12826 let merge_registration_id = cleared_registration_id.clone();
12827 self.merge_diagnostic_entries(
12828 clears,
12829 move |_, diagnostic, _| {
12830 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12831 diagnostic.registration_id != Some(merge_registration_id.clone())
12832 } else {
12833 true
12834 }
12835 },
12836 cx,
12837 )?;
12838
12839 Ok(())
12840 }
12841
12842 async fn deduplicate_range_based_lsp_requests<T>(
12843 lsp_store: &Entity<Self>,
12844 server_id: Option<LanguageServerId>,
12845 lsp_request_id: LspRequestId,
12846 proto_request: &T::ProtoRequest,
12847 range: Range<Anchor>,
12848 cx: &mut AsyncApp,
12849 ) -> Result<()>
12850 where
12851 T: LspCommand,
12852 T::ProtoRequest: proto::LspRequestMessage,
12853 {
12854 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12855 let version = deserialize_version(proto_request.buffer_version());
12856 let buffer = lsp_store.update(cx, |this, cx| {
12857 this.buffer_store.read(cx).get_existing(buffer_id)
12858 })?;
12859 buffer
12860 .update(cx, |buffer, _| buffer.wait_for_version(version))
12861 .await?;
12862 lsp_store.update(cx, |lsp_store, cx| {
12863 let buffer_snapshot = buffer.read(cx).snapshot();
12864 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12865 let chunks_queried_for = lsp_data
12866 .inlay_hints
12867 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12868 .collect::<Vec<_>>();
12869 match chunks_queried_for.as_slice() {
12870 &[chunk] => {
12871 let key = LspKey {
12872 request_type: TypeId::of::<T>(),
12873 server_queried: server_id,
12874 };
12875 let previous_request = lsp_data
12876 .chunk_lsp_requests
12877 .entry(key)
12878 .or_default()
12879 .insert(chunk, lsp_request_id);
12880 if let Some((previous_request, running_requests)) =
12881 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12882 {
12883 running_requests.remove(&previous_request);
12884 }
12885 }
12886 _ambiguous_chunks => {
12887 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12888 // there, a buffer version-based check will be performed and outdated requests discarded.
12889 }
12890 }
12891 anyhow::Ok(())
12892 })?;
12893
12894 Ok(())
12895 }
12896
12897 async fn query_lsp_locally<T>(
12898 lsp_store: Entity<Self>,
12899 for_server_id: Option<LanguageServerId>,
12900 sender_id: proto::PeerId,
12901 lsp_request_id: LspRequestId,
12902 proto_request: T::ProtoRequest,
12903 position: Option<Anchor>,
12904 cx: &mut AsyncApp,
12905 ) -> Result<()>
12906 where
12907 T: LspCommand + Clone,
12908 T::ProtoRequest: proto::LspRequestMessage,
12909 <T::ProtoRequest as proto::RequestMessage>::Response:
12910 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12911 {
12912 let (buffer_version, buffer) =
12913 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12914 let request =
12915 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12916 let key = LspKey {
12917 request_type: TypeId::of::<T>(),
12918 server_queried: for_server_id,
12919 };
12920 lsp_store.update(cx, |lsp_store, cx| {
12921 let request_task = match for_server_id {
12922 Some(server_id) => {
12923 let server_task = lsp_store.request_lsp(
12924 buffer.clone(),
12925 LanguageServerToQuery::Other(server_id),
12926 request.clone(),
12927 cx,
12928 );
12929 cx.background_spawn(async move {
12930 let mut responses = Vec::new();
12931 match server_task.await {
12932 Ok(response) => responses.push((server_id, response)),
12933 // rust-analyzer likes to error with this when its still loading up
12934 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12935 Err(e) => log::error!(
12936 "Error handling response for request {request:?}: {e:#}"
12937 ),
12938 }
12939 responses
12940 })
12941 }
12942 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12943 };
12944 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12945 if T::ProtoRequest::stop_previous_requests() {
12946 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12947 lsp_requests.clear();
12948 }
12949 }
12950 lsp_data.lsp_requests.entry(key).or_default().insert(
12951 lsp_request_id,
12952 cx.spawn(async move |lsp_store, cx| {
12953 let response = request_task.await;
12954 lsp_store
12955 .update(cx, |lsp_store, cx| {
12956 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12957 {
12958 let response = response
12959 .into_iter()
12960 .map(|(server_id, response)| {
12961 (
12962 server_id.to_proto(),
12963 T::response_to_proto(
12964 response,
12965 lsp_store,
12966 sender_id,
12967 &buffer_version,
12968 cx,
12969 )
12970 .into(),
12971 )
12972 })
12973 .collect::<HashMap<_, _>>();
12974 match client.send_lsp_response::<T::ProtoRequest>(
12975 project_id,
12976 lsp_request_id,
12977 response,
12978 ) {
12979 Ok(()) => {}
12980 Err(e) => {
12981 log::error!("Failed to send LSP response: {e:#}",)
12982 }
12983 }
12984 }
12985 })
12986 .ok();
12987 }),
12988 );
12989 });
12990 Ok(())
12991 }
12992
12993 async fn wait_for_buffer_version<T>(
12994 lsp_store: &Entity<Self>,
12995 proto_request: &T::ProtoRequest,
12996 cx: &mut AsyncApp,
12997 ) -> Result<(Global, Entity<Buffer>)>
12998 where
12999 T: LspCommand,
13000 T::ProtoRequest: proto::LspRequestMessage,
13001 {
13002 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13003 let version = deserialize_version(proto_request.buffer_version());
13004 let buffer = lsp_store.update(cx, |this, cx| {
13005 this.buffer_store.read(cx).get_existing(buffer_id)
13006 })?;
13007 buffer
13008 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13009 .await?;
13010 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13011 Ok((buffer_version, buffer))
13012 }
13013
13014 fn take_text_document_sync_options(
13015 capabilities: &mut lsp::ServerCapabilities,
13016 ) -> lsp::TextDocumentSyncOptions {
13017 match capabilities.text_document_sync.take() {
13018 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13019 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13020 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13021 sync_options.change = Some(sync_kind);
13022 sync_options
13023 }
13024 None => lsp::TextDocumentSyncOptions::default(),
13025 }
13026 }
13027
13028 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13029 self.downstream_client.clone()
13030 }
13031
13032 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13033 self.worktree_store.clone()
13034 }
13035
13036 /// Gets what's stored in the LSP data for the given buffer.
13037 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13038 self.lsp_data.get_mut(&buffer_id)
13039 }
13040
13041 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13042 /// new [`BufferLspData`] will be created to replace the previous state.
13043 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13044 let (buffer_id, buffer_version) =
13045 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13046 let lsp_data = self
13047 .lsp_data
13048 .entry(buffer_id)
13049 .or_insert_with(|| BufferLspData::new(buffer, cx));
13050 if buffer_version.changed_since(&lsp_data.buffer_version) {
13051 // To send delta requests for semantic tokens, the previous tokens
13052 // need to be kept between buffer changes.
13053 let semantic_tokens = lsp_data.semantic_tokens.take();
13054 *lsp_data = BufferLspData::new(buffer, cx);
13055 lsp_data.semantic_tokens = semantic_tokens;
13056 }
13057 lsp_data
13058 }
13059}
13060
13061// Registration with registerOptions as null, should fallback to true.
13062// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13063fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13064 reg: lsp::Registration,
13065) -> Result<OneOf<bool, T>> {
13066 Ok(match reg.register_options {
13067 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13068 None => OneOf::Left(true),
13069 })
13070}
13071
13072fn subscribe_to_binary_statuses(
13073 languages: &Arc<LanguageRegistry>,
13074 cx: &mut Context<'_, LspStore>,
13075) -> Task<()> {
13076 let mut server_statuses = languages.language_server_binary_statuses();
13077 cx.spawn(async move |lsp_store, cx| {
13078 while let Some((server_name, binary_status)) = server_statuses.next().await {
13079 if lsp_store
13080 .update(cx, |_, cx| {
13081 let mut message = None;
13082 let binary_status = match binary_status {
13083 BinaryStatus::None => proto::ServerBinaryStatus::None,
13084 BinaryStatus::CheckingForUpdate => {
13085 proto::ServerBinaryStatus::CheckingForUpdate
13086 }
13087 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13088 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13089 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13090 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13091 BinaryStatus::Failed { error } => {
13092 message = Some(error);
13093 proto::ServerBinaryStatus::Failed
13094 }
13095 };
13096 cx.emit(LspStoreEvent::LanguageServerUpdate {
13097 // Binary updates are about the binary that might not have any language server id at that point.
13098 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13099 language_server_id: LanguageServerId(0),
13100 name: Some(server_name),
13101 message: proto::update_language_server::Variant::StatusUpdate(
13102 proto::StatusUpdate {
13103 message,
13104 status: Some(proto::status_update::Status::Binary(
13105 binary_status as i32,
13106 )),
13107 },
13108 ),
13109 });
13110 })
13111 .is_err()
13112 {
13113 break;
13114 }
13115 }
13116 })
13117}
13118
13119fn lsp_workspace_diagnostics_refresh(
13120 registration_id: Option<String>,
13121 options: DiagnosticServerCapabilities,
13122 server: Arc<LanguageServer>,
13123 cx: &mut Context<'_, LspStore>,
13124) -> Option<WorkspaceRefreshTask> {
13125 let identifier = workspace_diagnostic_identifier(&options)?;
13126 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13127
13128 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13129 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13130 refresh_tx.try_send(()).ok();
13131
13132 let request_timeout = ProjectSettings::get_global(cx)
13133 .global_lsp_settings
13134 .get_request_timeout();
13135
13136 // 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.
13137 // This allows users to increase the duration if need be
13138 let timeout = if request_timeout != Duration::ZERO {
13139 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13140 } else {
13141 request_timeout
13142 };
13143
13144 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13145 let mut attempts = 0;
13146 let max_attempts = 50;
13147 let mut requests = 0;
13148
13149 loop {
13150 let Some(()) = refresh_rx.recv().await else {
13151 return;
13152 };
13153
13154 'request: loop {
13155 requests += 1;
13156 if attempts > max_attempts {
13157 log::error!(
13158 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13159 );
13160 return;
13161 }
13162 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13163 cx.background_executor()
13164 .timer(Duration::from_millis(backoff_millis))
13165 .await;
13166 attempts += 1;
13167
13168 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13169 lsp_store
13170 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13171 .into_iter()
13172 .filter_map(|(abs_path, result_id)| {
13173 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13174 Some(lsp::PreviousResultId {
13175 uri,
13176 value: result_id.to_string(),
13177 })
13178 })
13179 .collect()
13180 }) else {
13181 return;
13182 };
13183
13184 let token = if let Some(registration_id) = ®istration_id {
13185 format!(
13186 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13187 server.server_id(),
13188 )
13189 } else {
13190 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13191 };
13192
13193 progress_rx.try_recv().ok();
13194 let timer = server.request_timer(timeout).fuse();
13195 let progress = pin!(progress_rx.recv().fuse());
13196 let response_result = server
13197 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13198 lsp::WorkspaceDiagnosticParams {
13199 previous_result_ids,
13200 identifier: identifier.clone(),
13201 work_done_progress_params: Default::default(),
13202 partial_result_params: lsp::PartialResultParams {
13203 partial_result_token: Some(lsp::ProgressToken::String(token)),
13204 },
13205 },
13206 select(timer, progress).then(|either| match either {
13207 Either::Left((message, ..)) => ready(message).left_future(),
13208 Either::Right(..) => pending::<String>().right_future(),
13209 }),
13210 )
13211 .await;
13212
13213 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13214 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13215 match response_result {
13216 ConnectionResult::Timeout => {
13217 log::error!("Timeout during workspace diagnostics pull");
13218 continue 'request;
13219 }
13220 ConnectionResult::ConnectionReset => {
13221 log::error!("Server closed a workspace diagnostics pull request");
13222 continue 'request;
13223 }
13224 ConnectionResult::Result(Err(e)) => {
13225 log::error!("Error during workspace diagnostics pull: {e:#}");
13226 break 'request;
13227 }
13228 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13229 attempts = 0;
13230 if lsp_store
13231 .update(cx, |lsp_store, cx| {
13232 lsp_store.apply_workspace_diagnostic_report(
13233 server.server_id(),
13234 pulled_diagnostics,
13235 registration_id_shared.clone(),
13236 cx,
13237 )
13238 })
13239 .is_err()
13240 {
13241 return;
13242 }
13243 break 'request;
13244 }
13245 }
13246 }
13247 }
13248 });
13249
13250 Some(WorkspaceRefreshTask {
13251 refresh_tx,
13252 progress_tx,
13253 task: workspace_query_language_server,
13254 })
13255}
13256
13257fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13258 match &options {
13259 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13260 .identifier
13261 .as_deref()
13262 .map(SharedString::new),
13263 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13264 let diagnostic_options = ®istration_options.diagnostic_options;
13265 diagnostic_options
13266 .identifier
13267 .as_deref()
13268 .map(SharedString::new)
13269 }
13270 }
13271}
13272
13273fn workspace_diagnostic_identifier(
13274 options: &DiagnosticServerCapabilities,
13275) -> Option<Option<String>> {
13276 match &options {
13277 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13278 if !diagnostic_options.workspace_diagnostics {
13279 return None;
13280 }
13281 Some(diagnostic_options.identifier.clone())
13282 }
13283 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13284 let diagnostic_options = ®istration_options.diagnostic_options;
13285 if !diagnostic_options.workspace_diagnostics {
13286 return None;
13287 }
13288 Some(diagnostic_options.identifier.clone())
13289 }
13290 }
13291}
13292
13293fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13294 let CompletionSource::BufferWord {
13295 word_range,
13296 resolved,
13297 } = &mut completion.source
13298 else {
13299 return;
13300 };
13301 if *resolved {
13302 return;
13303 }
13304
13305 if completion.new_text
13306 != snapshot
13307 .text_for_range(word_range.clone())
13308 .collect::<String>()
13309 {
13310 return;
13311 }
13312
13313 let mut offset = 0;
13314 for chunk in snapshot.chunks(word_range.clone(), true) {
13315 let end_offset = offset + chunk.text.len();
13316 if let Some(highlight_id) = chunk.syntax_highlight_id {
13317 completion
13318 .label
13319 .runs
13320 .push((offset..end_offset, highlight_id));
13321 }
13322 offset = end_offset;
13323 }
13324 *resolved = true;
13325}
13326
13327impl EventEmitter<LspStoreEvent> for LspStore {}
13328
13329fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13330 hover
13331 .contents
13332 .retain(|hover_block| !hover_block.text.trim().is_empty());
13333 if hover.contents.is_empty() {
13334 None
13335 } else {
13336 Some(hover)
13337 }
13338}
13339
13340async fn populate_labels_for_completions(
13341 new_completions: Vec<CoreCompletion>,
13342 language: Option<Arc<Language>>,
13343 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13344) -> Vec<Completion> {
13345 let lsp_completions = new_completions
13346 .iter()
13347 .filter_map(|new_completion| {
13348 new_completion
13349 .source
13350 .lsp_completion(true)
13351 .map(|lsp_completion| lsp_completion.into_owned())
13352 })
13353 .collect::<Vec<_>>();
13354
13355 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13356 lsp_adapter
13357 .labels_for_completions(&lsp_completions, language)
13358 .await
13359 .log_err()
13360 .unwrap_or_default()
13361 } else {
13362 Vec::new()
13363 }
13364 .into_iter()
13365 .fuse();
13366
13367 let mut completions = Vec::new();
13368 for completion in new_completions {
13369 match completion.source.lsp_completion(true) {
13370 Some(lsp_completion) => {
13371 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13372
13373 let mut label = labels.next().flatten().unwrap_or_else(|| {
13374 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13375 });
13376 ensure_uniform_list_compatible_label(&mut label);
13377 completions.push(Completion {
13378 label,
13379 documentation,
13380 replace_range: completion.replace_range,
13381 new_text: completion.new_text,
13382 insert_text_mode: lsp_completion.insert_text_mode,
13383 source: completion.source,
13384 icon_path: None,
13385 confirm: None,
13386 match_start: None,
13387 snippet_deduplication_key: None,
13388 });
13389 }
13390 None => {
13391 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13392 ensure_uniform_list_compatible_label(&mut label);
13393 completions.push(Completion {
13394 label,
13395 documentation: None,
13396 replace_range: completion.replace_range,
13397 new_text: completion.new_text,
13398 source: completion.source,
13399 insert_text_mode: None,
13400 icon_path: None,
13401 confirm: None,
13402 match_start: None,
13403 snippet_deduplication_key: None,
13404 });
13405 }
13406 }
13407 }
13408 completions
13409}
13410
13411#[derive(Debug)]
13412pub enum LanguageServerToQuery {
13413 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13414 FirstCapable,
13415 /// Query a specific language server.
13416 Other(LanguageServerId),
13417}
13418
13419#[derive(Default)]
13420struct RenamePathsWatchedForServer {
13421 did_rename: Vec<RenameActionPredicate>,
13422 will_rename: Vec<RenameActionPredicate>,
13423}
13424
13425impl RenamePathsWatchedForServer {
13426 fn with_did_rename_patterns(
13427 mut self,
13428 did_rename: Option<&FileOperationRegistrationOptions>,
13429 ) -> Self {
13430 if let Some(did_rename) = did_rename {
13431 self.did_rename = did_rename
13432 .filters
13433 .iter()
13434 .filter_map(|filter| filter.try_into().log_err())
13435 .collect();
13436 }
13437 self
13438 }
13439 fn with_will_rename_patterns(
13440 mut self,
13441 will_rename: Option<&FileOperationRegistrationOptions>,
13442 ) -> Self {
13443 if let Some(will_rename) = will_rename {
13444 self.will_rename = will_rename
13445 .filters
13446 .iter()
13447 .filter_map(|filter| filter.try_into().log_err())
13448 .collect();
13449 }
13450 self
13451 }
13452
13453 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13454 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13455 }
13456 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13457 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13458 }
13459}
13460
13461impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13462 type Error = globset::Error;
13463 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13464 Ok(Self {
13465 kind: ops.pattern.matches.clone(),
13466 glob: GlobBuilder::new(&ops.pattern.glob)
13467 .case_insensitive(
13468 ops.pattern
13469 .options
13470 .as_ref()
13471 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13472 )
13473 .build()?
13474 .compile_matcher(),
13475 })
13476 }
13477}
13478struct RenameActionPredicate {
13479 glob: GlobMatcher,
13480 kind: Option<FileOperationPatternKind>,
13481}
13482
13483impl RenameActionPredicate {
13484 // Returns true if language server should be notified
13485 fn eval(&self, path: &str, is_dir: bool) -> bool {
13486 self.kind.as_ref().is_none_or(|kind| {
13487 let expected_kind = if is_dir {
13488 FileOperationPatternKind::Folder
13489 } else {
13490 FileOperationPatternKind::File
13491 };
13492 kind == &expected_kind
13493 }) && self.glob.is_match(path)
13494 }
13495}
13496
13497#[derive(Default)]
13498struct LanguageServerWatchedPaths {
13499 worktree_paths: HashMap<WorktreeId, GlobSet>,
13500 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13501}
13502
13503#[derive(Default)]
13504struct LanguageServerWatchedPathsBuilder {
13505 worktree_paths: HashMap<WorktreeId, GlobSet>,
13506 abs_paths: HashMap<Arc<Path>, GlobSet>,
13507}
13508
13509impl LanguageServerWatchedPathsBuilder {
13510 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13511 self.worktree_paths.insert(worktree_id, glob_set);
13512 }
13513 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13514 self.abs_paths.insert(path, glob_set);
13515 }
13516 fn build(
13517 self,
13518 fs: Arc<dyn Fs>,
13519 language_server_id: LanguageServerId,
13520 cx: &mut Context<LspStore>,
13521 ) -> LanguageServerWatchedPaths {
13522 let lsp_store = cx.weak_entity();
13523
13524 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13525 let abs_paths = self
13526 .abs_paths
13527 .into_iter()
13528 .map(|(abs_path, globset)| {
13529 let task = cx.spawn({
13530 let abs_path = abs_path.clone();
13531 let fs = fs.clone();
13532
13533 let lsp_store = lsp_store.clone();
13534 async move |_, cx| {
13535 maybe!(async move {
13536 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13537 while let Some(update) = push_updates.0.next().await {
13538 let action = lsp_store
13539 .update(cx, |this, _| {
13540 let Some(local) = this.as_local() else {
13541 return ControlFlow::Break(());
13542 };
13543 let Some(watcher) = local
13544 .language_server_watched_paths
13545 .get(&language_server_id)
13546 else {
13547 return ControlFlow::Break(());
13548 };
13549 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13550 "Watched abs path is not registered with a watcher",
13551 );
13552 let matching_entries = update
13553 .into_iter()
13554 .filter(|event| globs.is_match(&event.path))
13555 .collect::<Vec<_>>();
13556 this.lsp_notify_abs_paths_changed(
13557 language_server_id,
13558 matching_entries,
13559 );
13560 ControlFlow::Continue(())
13561 })
13562 .ok()?;
13563
13564 if action.is_break() {
13565 break;
13566 }
13567 }
13568 Some(())
13569 })
13570 .await;
13571 }
13572 });
13573 (abs_path, (globset, task))
13574 })
13575 .collect();
13576 LanguageServerWatchedPaths {
13577 worktree_paths: self.worktree_paths,
13578 abs_paths,
13579 }
13580 }
13581}
13582
13583struct LspBufferSnapshot {
13584 version: i32,
13585 snapshot: TextBufferSnapshot,
13586}
13587
13588/// A prompt requested by LSP server.
13589#[derive(Clone, Debug)]
13590pub struct LanguageServerPromptRequest {
13591 pub id: usize,
13592 pub level: PromptLevel,
13593 pub message: String,
13594 pub actions: Vec<MessageActionItem>,
13595 pub lsp_name: String,
13596 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13597}
13598
13599impl LanguageServerPromptRequest {
13600 pub fn new(
13601 level: PromptLevel,
13602 message: String,
13603 actions: Vec<MessageActionItem>,
13604 lsp_name: String,
13605 response_channel: smol::channel::Sender<MessageActionItem>,
13606 ) -> Self {
13607 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13608 LanguageServerPromptRequest {
13609 id,
13610 level,
13611 message,
13612 actions,
13613 lsp_name,
13614 response_channel,
13615 }
13616 }
13617 pub async fn respond(self, index: usize) -> Option<()> {
13618 if let Some(response) = self.actions.into_iter().nth(index) {
13619 self.response_channel.send(response).await.ok()
13620 } else {
13621 None
13622 }
13623 }
13624
13625 #[cfg(any(test, feature = "test-support"))]
13626 pub fn test(
13627 level: PromptLevel,
13628 message: String,
13629 actions: Vec<MessageActionItem>,
13630 lsp_name: String,
13631 ) -> Self {
13632 let (tx, _rx) = smol::channel::unbounded();
13633 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13634 }
13635}
13636impl PartialEq for LanguageServerPromptRequest {
13637 fn eq(&self, other: &Self) -> bool {
13638 self.message == other.message && self.actions == other.actions
13639 }
13640}
13641
13642#[derive(Clone, Debug, PartialEq)]
13643pub enum LanguageServerLogType {
13644 Log(MessageType),
13645 Trace { verbose_info: Option<String> },
13646 Rpc { received: bool },
13647}
13648
13649impl LanguageServerLogType {
13650 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13651 match self {
13652 Self::Log(log_type) => {
13653 use proto::log_message::LogLevel;
13654 let level = match *log_type {
13655 MessageType::ERROR => LogLevel::Error,
13656 MessageType::WARNING => LogLevel::Warning,
13657 MessageType::INFO => LogLevel::Info,
13658 MessageType::LOG => LogLevel::Log,
13659 other => {
13660 log::warn!("Unknown lsp log message type: {other:?}");
13661 LogLevel::Log
13662 }
13663 };
13664 proto::language_server_log::LogType::Log(proto::LogMessage {
13665 level: level as i32,
13666 })
13667 }
13668 Self::Trace { verbose_info } => {
13669 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13670 verbose_info: verbose_info.to_owned(),
13671 })
13672 }
13673 Self::Rpc { received } => {
13674 let kind = if *received {
13675 proto::rpc_message::Kind::Received
13676 } else {
13677 proto::rpc_message::Kind::Sent
13678 };
13679 let kind = kind as i32;
13680 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13681 }
13682 }
13683 }
13684
13685 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13686 use proto::log_message::LogLevel;
13687 use proto::rpc_message;
13688 match log_type {
13689 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13690 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13691 LogLevel::Error => MessageType::ERROR,
13692 LogLevel::Warning => MessageType::WARNING,
13693 LogLevel::Info => MessageType::INFO,
13694 LogLevel::Log => MessageType::LOG,
13695 },
13696 ),
13697 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13698 verbose_info: trace_message.verbose_info,
13699 },
13700 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13701 received: match rpc_message::Kind::from_i32(message.kind)
13702 .unwrap_or(rpc_message::Kind::Received)
13703 {
13704 rpc_message::Kind::Received => true,
13705 rpc_message::Kind::Sent => false,
13706 },
13707 },
13708 }
13709 }
13710}
13711
13712pub struct WorkspaceRefreshTask {
13713 refresh_tx: mpsc::Sender<()>,
13714 progress_tx: mpsc::Sender<()>,
13715 #[allow(dead_code)]
13716 task: Task<()>,
13717}
13718
13719pub enum LanguageServerState {
13720 Starting {
13721 startup: Task<Option<Arc<LanguageServer>>>,
13722 /// List of language servers that will be added to the workspace once it's initialization completes.
13723 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13724 },
13725
13726 Running {
13727 adapter: Arc<CachedLspAdapter>,
13728 server: Arc<LanguageServer>,
13729 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13730 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13731 },
13732}
13733
13734impl LanguageServerState {
13735 fn add_workspace_folder(&self, uri: Uri) {
13736 match self {
13737 LanguageServerState::Starting {
13738 pending_workspace_folders,
13739 ..
13740 } => {
13741 pending_workspace_folders.lock().insert(uri);
13742 }
13743 LanguageServerState::Running { server, .. } => {
13744 server.add_workspace_folder(uri);
13745 }
13746 }
13747 }
13748 fn _remove_workspace_folder(&self, uri: Uri) {
13749 match self {
13750 LanguageServerState::Starting {
13751 pending_workspace_folders,
13752 ..
13753 } => {
13754 pending_workspace_folders.lock().remove(&uri);
13755 }
13756 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13757 }
13758 }
13759}
13760
13761impl std::fmt::Debug for LanguageServerState {
13762 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13763 match self {
13764 LanguageServerState::Starting { .. } => {
13765 f.debug_struct("LanguageServerState::Starting").finish()
13766 }
13767 LanguageServerState::Running { .. } => {
13768 f.debug_struct("LanguageServerState::Running").finish()
13769 }
13770 }
13771 }
13772}
13773
13774#[derive(Clone, Debug, Serialize)]
13775pub struct LanguageServerProgress {
13776 pub is_disk_based_diagnostics_progress: bool,
13777 pub is_cancellable: bool,
13778 pub title: Option<String>,
13779 pub message: Option<String>,
13780 pub percentage: Option<usize>,
13781 #[serde(skip_serializing)]
13782 pub last_update_at: Instant,
13783}
13784
13785#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13786pub struct DiagnosticSummary {
13787 pub error_count: usize,
13788 pub warning_count: usize,
13789}
13790
13791impl DiagnosticSummary {
13792 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13793 let mut this = Self {
13794 error_count: 0,
13795 warning_count: 0,
13796 };
13797
13798 for entry in diagnostics {
13799 if entry.diagnostic.is_primary {
13800 match entry.diagnostic.severity {
13801 DiagnosticSeverity::ERROR => this.error_count += 1,
13802 DiagnosticSeverity::WARNING => this.warning_count += 1,
13803 _ => {}
13804 }
13805 }
13806 }
13807
13808 this
13809 }
13810
13811 pub fn is_empty(&self) -> bool {
13812 self.error_count == 0 && self.warning_count == 0
13813 }
13814
13815 pub fn to_proto(
13816 self,
13817 language_server_id: LanguageServerId,
13818 path: &RelPath,
13819 ) -> proto::DiagnosticSummary {
13820 proto::DiagnosticSummary {
13821 path: path.to_proto(),
13822 language_server_id: language_server_id.0 as u64,
13823 error_count: self.error_count as u32,
13824 warning_count: self.warning_count as u32,
13825 }
13826 }
13827}
13828
13829#[derive(Clone, Debug)]
13830pub enum CompletionDocumentation {
13831 /// There is no documentation for this completion.
13832 Undocumented,
13833 /// A single line of documentation.
13834 SingleLine(SharedString),
13835 /// Multiple lines of plain text documentation.
13836 MultiLinePlainText(SharedString),
13837 /// Markdown documentation.
13838 MultiLineMarkdown(SharedString),
13839 /// Both single line and multiple lines of plain text documentation.
13840 SingleLineAndMultiLinePlainText {
13841 single_line: SharedString,
13842 plain_text: Option<SharedString>,
13843 },
13844}
13845
13846impl CompletionDocumentation {
13847 #[cfg(any(test, feature = "test-support"))]
13848 pub fn text(&self) -> SharedString {
13849 match self {
13850 CompletionDocumentation::Undocumented => "".into(),
13851 CompletionDocumentation::SingleLine(s) => s.clone(),
13852 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13853 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13854 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13855 single_line.clone()
13856 }
13857 }
13858 }
13859}
13860
13861impl From<lsp::Documentation> for CompletionDocumentation {
13862 fn from(docs: lsp::Documentation) -> Self {
13863 match docs {
13864 lsp::Documentation::String(text) => {
13865 if text.lines().count() <= 1 {
13866 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13867 } else {
13868 CompletionDocumentation::MultiLinePlainText(text.into())
13869 }
13870 }
13871
13872 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13873 lsp::MarkupKind::PlainText => {
13874 if value.lines().count() <= 1 {
13875 CompletionDocumentation::SingleLine(value.into())
13876 } else {
13877 CompletionDocumentation::MultiLinePlainText(value.into())
13878 }
13879 }
13880
13881 lsp::MarkupKind::Markdown => {
13882 CompletionDocumentation::MultiLineMarkdown(value.into())
13883 }
13884 },
13885 }
13886 }
13887}
13888
13889pub enum ResolvedHint {
13890 Resolved(InlayHint),
13891 Resolving(Shared<Task<()>>),
13892}
13893
13894pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13895 glob.components()
13896 .take_while(|component| match component {
13897 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13898 _ => true,
13899 })
13900 .collect()
13901}
13902
13903pub struct SshLspAdapter {
13904 name: LanguageServerName,
13905 binary: LanguageServerBinary,
13906 initialization_options: Option<String>,
13907 code_action_kinds: Option<Vec<CodeActionKind>>,
13908}
13909
13910impl SshLspAdapter {
13911 pub fn new(
13912 name: LanguageServerName,
13913 binary: LanguageServerBinary,
13914 initialization_options: Option<String>,
13915 code_action_kinds: Option<String>,
13916 ) -> Self {
13917 Self {
13918 name,
13919 binary,
13920 initialization_options,
13921 code_action_kinds: code_action_kinds
13922 .as_ref()
13923 .and_then(|c| serde_json::from_str(c).ok()),
13924 }
13925 }
13926}
13927
13928impl LspInstaller for SshLspAdapter {
13929 type BinaryVersion = ();
13930 async fn check_if_user_installed(
13931 &self,
13932 _: &dyn LspAdapterDelegate,
13933 _: Option<Toolchain>,
13934 _: &AsyncApp,
13935 ) -> Option<LanguageServerBinary> {
13936 Some(self.binary.clone())
13937 }
13938
13939 async fn cached_server_binary(
13940 &self,
13941 _: PathBuf,
13942 _: &dyn LspAdapterDelegate,
13943 ) -> Option<LanguageServerBinary> {
13944 None
13945 }
13946
13947 async fn fetch_latest_server_version(
13948 &self,
13949 _: &dyn LspAdapterDelegate,
13950 _: bool,
13951 _: &mut AsyncApp,
13952 ) -> Result<()> {
13953 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13954 }
13955
13956 async fn fetch_server_binary(
13957 &self,
13958 _: (),
13959 _: PathBuf,
13960 _: &dyn LspAdapterDelegate,
13961 ) -> Result<LanguageServerBinary> {
13962 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13963 }
13964}
13965
13966#[async_trait(?Send)]
13967impl LspAdapter for SshLspAdapter {
13968 fn name(&self) -> LanguageServerName {
13969 self.name.clone()
13970 }
13971
13972 async fn initialization_options(
13973 self: Arc<Self>,
13974 _: &Arc<dyn LspAdapterDelegate>,
13975 ) -> Result<Option<serde_json::Value>> {
13976 let Some(options) = &self.initialization_options else {
13977 return Ok(None);
13978 };
13979 let result = serde_json::from_str(options)?;
13980 Ok(result)
13981 }
13982
13983 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13984 self.code_action_kinds.clone()
13985 }
13986}
13987
13988pub fn language_server_settings<'a>(
13989 delegate: &'a dyn LspAdapterDelegate,
13990 language: &LanguageServerName,
13991 cx: &'a App,
13992) -> Option<&'a LspSettings> {
13993 language_server_settings_for(
13994 SettingsLocation {
13995 worktree_id: delegate.worktree_id(),
13996 path: RelPath::empty(),
13997 },
13998 language,
13999 cx,
14000 )
14001}
14002
14003pub fn language_server_settings_for<'a>(
14004 location: SettingsLocation<'a>,
14005 language: &LanguageServerName,
14006 cx: &'a App,
14007) -> Option<&'a LspSettings> {
14008 ProjectSettings::get(Some(location), cx).lsp.get(language)
14009}
14010
14011pub struct LocalLspAdapterDelegate {
14012 lsp_store: WeakEntity<LspStore>,
14013 worktree: worktree::Snapshot,
14014 fs: Arc<dyn Fs>,
14015 http_client: Arc<dyn HttpClient>,
14016 language_registry: Arc<LanguageRegistry>,
14017 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14018}
14019
14020impl LocalLspAdapterDelegate {
14021 pub fn new(
14022 language_registry: Arc<LanguageRegistry>,
14023 environment: &Entity<ProjectEnvironment>,
14024 lsp_store: WeakEntity<LspStore>,
14025 worktree: &Entity<Worktree>,
14026 http_client: Arc<dyn HttpClient>,
14027 fs: Arc<dyn Fs>,
14028 cx: &mut App,
14029 ) -> Arc<Self> {
14030 let load_shell_env_task =
14031 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14032
14033 Arc::new(Self {
14034 lsp_store,
14035 worktree: worktree.read(cx).snapshot(),
14036 fs,
14037 http_client,
14038 language_registry,
14039 load_shell_env_task,
14040 })
14041 }
14042
14043 pub fn from_local_lsp(
14044 local: &LocalLspStore,
14045 worktree: &Entity<Worktree>,
14046 cx: &mut App,
14047 ) -> Arc<Self> {
14048 Self::new(
14049 local.languages.clone(),
14050 &local.environment,
14051 local.weak.clone(),
14052 worktree,
14053 local.http_client.clone(),
14054 local.fs.clone(),
14055 cx,
14056 )
14057 }
14058}
14059
14060#[async_trait]
14061impl LspAdapterDelegate for LocalLspAdapterDelegate {
14062 fn show_notification(&self, message: &str, cx: &mut App) {
14063 self.lsp_store
14064 .update(cx, |_, cx| {
14065 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14066 })
14067 .ok();
14068 }
14069
14070 fn http_client(&self) -> Arc<dyn HttpClient> {
14071 self.http_client.clone()
14072 }
14073
14074 fn worktree_id(&self) -> WorktreeId {
14075 self.worktree.id()
14076 }
14077
14078 fn worktree_root_path(&self) -> &Path {
14079 self.worktree.abs_path().as_ref()
14080 }
14081
14082 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14083 self.worktree.resolve_relative_path(path)
14084 }
14085
14086 async fn shell_env(&self) -> HashMap<String, String> {
14087 let task = self.load_shell_env_task.clone();
14088 task.await.unwrap_or_default()
14089 }
14090
14091 async fn npm_package_installed_version(
14092 &self,
14093 package_name: &str,
14094 ) -> Result<Option<(PathBuf, Version)>> {
14095 let local_package_directory = self.worktree_root_path();
14096 let node_modules_directory = local_package_directory.join("node_modules");
14097
14098 if let Some(version) =
14099 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14100 {
14101 return Ok(Some((node_modules_directory, version)));
14102 }
14103 let Some(npm) = self.which("npm".as_ref()).await else {
14104 log::warn!(
14105 "Failed to find npm executable for {:?}",
14106 local_package_directory
14107 );
14108 return Ok(None);
14109 };
14110
14111 let env = self.shell_env().await;
14112 let output = util::command::new_command(&npm)
14113 .args(["root", "-g"])
14114 .envs(env)
14115 .current_dir(local_package_directory)
14116 .output()
14117 .await?;
14118 let global_node_modules =
14119 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14120
14121 if let Some(version) =
14122 read_package_installed_version(global_node_modules.clone(), package_name).await?
14123 {
14124 return Ok(Some((global_node_modules, version)));
14125 }
14126 return Ok(None);
14127 }
14128
14129 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14130 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14131 if self.fs.is_file(&worktree_abs_path).await {
14132 worktree_abs_path.pop();
14133 }
14134
14135 let env = self.shell_env().await;
14136
14137 let shell_path = env.get("PATH").cloned();
14138
14139 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14140 }
14141
14142 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14143 let mut working_dir = self.worktree_root_path().to_path_buf();
14144 if self.fs.is_file(&working_dir).await {
14145 working_dir.pop();
14146 }
14147 let output = util::command::new_command(&command.path)
14148 .args(command.arguments)
14149 .envs(command.env.clone().unwrap_or_default())
14150 .current_dir(working_dir)
14151 .output()
14152 .await?;
14153
14154 anyhow::ensure!(
14155 output.status.success(),
14156 "{}, stdout: {:?}, stderr: {:?}",
14157 output.status,
14158 String::from_utf8_lossy(&output.stdout),
14159 String::from_utf8_lossy(&output.stderr)
14160 );
14161 Ok(())
14162 }
14163
14164 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14165 self.language_registry
14166 .update_lsp_binary_status(server_name, status);
14167 }
14168
14169 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14170 self.language_registry
14171 .all_lsp_adapters()
14172 .into_iter()
14173 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14174 .collect()
14175 }
14176
14177 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14178 let dir = self.language_registry.language_server_download_dir(name)?;
14179
14180 if !dir.exists() {
14181 smol::fs::create_dir_all(&dir)
14182 .await
14183 .context("failed to create container directory")
14184 .log_err()?;
14185 }
14186
14187 Some(dir)
14188 }
14189
14190 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14191 let entry = self
14192 .worktree
14193 .entry_for_path(path)
14194 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14195 let abs_path = self.worktree.absolutize(&entry.path);
14196 self.fs.load(&abs_path).await
14197 }
14198}
14199
14200async fn populate_labels_for_symbols(
14201 symbols: Vec<CoreSymbol>,
14202 language_registry: &Arc<LanguageRegistry>,
14203 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14204 output: &mut Vec<Symbol>,
14205) {
14206 #[allow(clippy::mutable_key_type)]
14207 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14208
14209 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14210 for symbol in symbols {
14211 let Some(file_name) = symbol.path.file_name() else {
14212 continue;
14213 };
14214 let language = language_registry
14215 .load_language_for_file_path(Path::new(file_name))
14216 .await
14217 .ok()
14218 .or_else(|| {
14219 unknown_paths.insert(file_name.into());
14220 None
14221 });
14222 symbols_by_language
14223 .entry(language)
14224 .or_default()
14225 .push(symbol);
14226 }
14227
14228 for unknown_path in unknown_paths {
14229 log::info!("no language found for symbol in file {unknown_path:?}");
14230 }
14231
14232 let mut label_params = Vec::new();
14233 for (language, mut symbols) in symbols_by_language {
14234 label_params.clear();
14235 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14236 name: mem::take(&mut symbol.name),
14237 kind: symbol.kind,
14238 container_name: symbol.container_name.take(),
14239 }));
14240
14241 let mut labels = Vec::new();
14242 if let Some(language) = language {
14243 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14244 language_registry
14245 .lsp_adapters(&language.name())
14246 .first()
14247 .cloned()
14248 });
14249 if let Some(lsp_adapter) = lsp_adapter {
14250 labels = lsp_adapter
14251 .labels_for_symbols(&label_params, &language)
14252 .await
14253 .log_err()
14254 .unwrap_or_default();
14255 }
14256 }
14257
14258 for (
14259 (
14260 symbol,
14261 language::Symbol {
14262 name,
14263 container_name,
14264 ..
14265 },
14266 ),
14267 label,
14268 ) in symbols
14269 .into_iter()
14270 .zip(label_params.drain(..))
14271 .zip(labels.into_iter().chain(iter::repeat(None)))
14272 {
14273 output.push(Symbol {
14274 language_server_name: symbol.language_server_name,
14275 source_worktree_id: symbol.source_worktree_id,
14276 source_language_server_id: symbol.source_language_server_id,
14277 path: symbol.path,
14278 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14279 name,
14280 kind: symbol.kind,
14281 range: symbol.range,
14282 container_name,
14283 });
14284 }
14285 }
14286}
14287
14288pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14289 text.lines()
14290 .map(|line| line.trim())
14291 .filter(|line| !line.is_empty())
14292 .join(separator)
14293}
14294
14295fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14296 match server.capabilities().text_document_sync.as_ref()? {
14297 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14298 // Server wants didSave but didn't specify includeText.
14299 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14300 // Server doesn't want didSave at all.
14301 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14302 // Server provided SaveOptions.
14303 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14304 Some(save_options.include_text.unwrap_or(false))
14305 }
14306 },
14307 // We do not have any save info. Kind affects didChange only.
14308 lsp::TextDocumentSyncCapability::Kind(_) => None,
14309 }
14310}
14311
14312/// Completion items are displayed in a `UniformList`.
14313/// Usually, those items are single-line strings, but in LSP responses,
14314/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14315/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14316/// 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,
14317/// breaking the completions menu presentation.
14318///
14319/// 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.
14320pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14321 let mut new_text = String::with_capacity(label.text.len());
14322 let mut offset_map = vec![0; label.text.len() + 1];
14323 let mut last_char_was_space = false;
14324 let mut new_idx = 0;
14325 let chars = label.text.char_indices().fuse();
14326 let mut newlines_removed = false;
14327
14328 for (idx, c) in chars {
14329 offset_map[idx] = new_idx;
14330
14331 match c {
14332 '\n' if last_char_was_space => {
14333 newlines_removed = true;
14334 }
14335 '\t' | ' ' if last_char_was_space => {}
14336 '\n' if !last_char_was_space => {
14337 new_text.push(' ');
14338 new_idx += 1;
14339 last_char_was_space = true;
14340 newlines_removed = true;
14341 }
14342 ' ' | '\t' => {
14343 new_text.push(' ');
14344 new_idx += 1;
14345 last_char_was_space = true;
14346 }
14347 _ => {
14348 new_text.push(c);
14349 new_idx += c.len_utf8();
14350 last_char_was_space = false;
14351 }
14352 }
14353 }
14354 offset_map[label.text.len()] = new_idx;
14355
14356 // Only modify the label if newlines were removed.
14357 if !newlines_removed {
14358 return;
14359 }
14360
14361 let last_index = new_idx;
14362 let mut run_ranges_errors = Vec::new();
14363 label.runs.retain_mut(|(range, _)| {
14364 match offset_map.get(range.start) {
14365 Some(&start) => range.start = start,
14366 None => {
14367 run_ranges_errors.push(range.clone());
14368 return false;
14369 }
14370 }
14371
14372 match offset_map.get(range.end) {
14373 Some(&end) => range.end = end,
14374 None => {
14375 run_ranges_errors.push(range.clone());
14376 range.end = last_index;
14377 }
14378 }
14379 true
14380 });
14381 if !run_ranges_errors.is_empty() {
14382 log::error!(
14383 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14384 label.text
14385 );
14386 }
14387
14388 let mut wrong_filter_range = None;
14389 if label.filter_range == (0..label.text.len()) {
14390 label.filter_range = 0..new_text.len();
14391 } else {
14392 let mut original_filter_range = Some(label.filter_range.clone());
14393 match offset_map.get(label.filter_range.start) {
14394 Some(&start) => label.filter_range.start = start,
14395 None => {
14396 wrong_filter_range = original_filter_range.take();
14397 label.filter_range.start = last_index;
14398 }
14399 }
14400
14401 match offset_map.get(label.filter_range.end) {
14402 Some(&end) => label.filter_range.end = end,
14403 None => {
14404 wrong_filter_range = original_filter_range.take();
14405 label.filter_range.end = last_index;
14406 }
14407 }
14408 }
14409 if let Some(wrong_filter_range) = wrong_filter_range {
14410 log::error!(
14411 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14412 label.text
14413 );
14414 }
14415
14416 label.text = new_text;
14417}