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 CodeLabelExt, Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff,
75 File as _, Language, LanguageAwareStyling, LanguageName, LanguageRegistry, LocalFile,
76 LspAdapter, LspAdapterDelegate, LspInstaller, ManifestDelegate, ManifestName, ModelineSettings,
77 OffsetUtf16, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToOffsetUtf16, ToPointUtf16,
78 Toolchain, Transaction, Unclipped,
79 language_settings::{
80 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
81 },
82 modeline, 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;
153#[cfg(any(test, feature = "test-support"))]
154pub use prettier::RANGE_FORMAT_SUFFIX as TEST_PRETTIER_RANGE_FORMAT_SUFFIX;
155pub use semantic_tokens::{
156 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
157};
158
159pub use worktree::{
160 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
161 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
162};
163
164const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
165pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
166const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
167const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
168static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
169
170#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
171pub enum ProgressToken {
172 Number(i32),
173 String(SharedString),
174}
175
176impl std::fmt::Display for ProgressToken {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 match self {
179 Self::Number(number) => write!(f, "{number}"),
180 Self::String(string) => write!(f, "{string}"),
181 }
182 }
183}
184
185impl ProgressToken {
186 fn from_lsp(value: lsp::NumberOrString) -> Self {
187 match value {
188 lsp::NumberOrString::Number(number) => Self::Number(number),
189 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
190 }
191 }
192
193 fn to_lsp(&self) -> lsp::NumberOrString {
194 match self {
195 Self::Number(number) => lsp::NumberOrString::Number(*number),
196 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
197 }
198 }
199
200 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
201 Some(match value.value? {
202 proto::progress_token::Value::Number(number) => Self::Number(number),
203 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
204 })
205 }
206
207 fn to_proto(&self) -> proto::ProgressToken {
208 proto::ProgressToken {
209 value: Some(match self {
210 Self::Number(number) => proto::progress_token::Value::Number(*number),
211 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
212 }),
213 }
214 }
215}
216
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
218pub enum FormatTrigger {
219 Save,
220 Manual,
221}
222
223pub enum LspFormatTarget {
224 Buffers,
225 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
226}
227
228#[derive(Debug, Clone, PartialEq, Eq, Hash)]
229pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
230
231struct OpenLspBuffer(Entity<Buffer>);
232
233impl FormatTrigger {
234 fn from_proto(value: i32) -> FormatTrigger {
235 match value {
236 0 => FormatTrigger::Save,
237 1 => FormatTrigger::Manual,
238 _ => FormatTrigger::Save,
239 }
240 }
241}
242
243#[derive(Clone)]
244struct UnifiedLanguageServer {
245 id: LanguageServerId,
246 project_roots: HashSet<Arc<RelPath>>,
247}
248
249/// Settings that affect language server identity.
250///
251/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
252/// updated via `workspace/didChangeConfiguration` without restarting the server.
253#[derive(Clone, Debug, Hash, PartialEq, Eq)]
254struct LanguageServerSeedSettings {
255 binary: Option<BinarySettings>,
256 initialization_options: Option<serde_json::Value>,
257}
258
259#[derive(Clone, Debug, Hash, PartialEq, Eq)]
260struct LanguageServerSeed {
261 worktree_id: WorktreeId,
262 name: LanguageServerName,
263 toolchain: Option<Toolchain>,
264 settings: LanguageServerSeedSettings,
265}
266
267#[derive(Debug)]
268pub struct DocumentDiagnosticsUpdate<'a, D> {
269 pub diagnostics: D,
270 pub result_id: Option<SharedString>,
271 pub registration_id: Option<SharedString>,
272 pub server_id: LanguageServerId,
273 pub disk_based_sources: Cow<'a, [String]>,
274}
275
276pub struct DocumentDiagnostics {
277 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
278 document_abs_path: PathBuf,
279 version: Option<i32>,
280}
281
282#[derive(Default, Debug)]
283struct DynamicRegistrations {
284 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
285 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
286}
287
288pub struct LocalLspStore {
289 weak: WeakEntity<LspStore>,
290 pub worktree_store: Entity<WorktreeStore>,
291 toolchain_store: Entity<LocalToolchainStore>,
292 http_client: Arc<dyn HttpClient>,
293 environment: Entity<ProjectEnvironment>,
294 fs: Arc<dyn Fs>,
295 languages: Arc<LanguageRegistry>,
296 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
297 yarn: Entity<YarnPathStore>,
298 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
299 buffers_being_formatted: HashSet<BufferId>,
300 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
301 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
302 watched_manifest_filenames: HashSet<ManifestName>,
303 language_server_paths_watched_for_rename:
304 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
305 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
306 supplementary_language_servers:
307 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
308 prettier_store: Entity<PrettierStore>,
309 next_diagnostic_group_id: usize,
310 diagnostics: HashMap<
311 WorktreeId,
312 HashMap<
313 Arc<RelPath>,
314 Vec<(
315 LanguageServerId,
316 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
317 )>,
318 >,
319 >,
320 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
321 _subscription: gpui::Subscription,
322 lsp_tree: LanguageServerTree,
323 registered_buffers: HashMap<BufferId, usize>,
324 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
325 buffer_pull_diagnostics_result_ids: HashMap<
326 LanguageServerId,
327 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
328 >,
329 workspace_pull_diagnostics_result_ids: HashMap<
330 LanguageServerId,
331 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
332 >,
333 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
334
335 buffers_to_refresh_hash_set: HashSet<BufferId>,
336 buffers_to_refresh_queue: VecDeque<BufferId>,
337 _background_diagnostics_worker: Shared<Task<()>>,
338}
339
340impl LocalLspStore {
341 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
342 pub fn running_language_server_for_id(
343 &self,
344 id: LanguageServerId,
345 ) -> Option<&Arc<LanguageServer>> {
346 let language_server_state = self.language_servers.get(&id)?;
347
348 match language_server_state {
349 LanguageServerState::Running { server, .. } => Some(server),
350 LanguageServerState::Starting { .. } => None,
351 }
352 }
353
354 fn get_or_insert_language_server(
355 &mut self,
356 worktree_handle: &Entity<Worktree>,
357 delegate: Arc<LocalLspAdapterDelegate>,
358 disposition: &Arc<LaunchDisposition>,
359 language_name: &LanguageName,
360 cx: &mut App,
361 ) -> LanguageServerId {
362 let key = LanguageServerSeed {
363 worktree_id: worktree_handle.read(cx).id(),
364 name: disposition.server_name.clone(),
365 settings: LanguageServerSeedSettings {
366 binary: disposition.settings.binary.clone(),
367 initialization_options: disposition.settings.initialization_options.clone(),
368 },
369 toolchain: disposition.toolchain.clone(),
370 };
371 if let Some(state) = self.language_server_ids.get_mut(&key) {
372 state.project_roots.insert(disposition.path.path.clone());
373 state.id
374 } else {
375 let adapter = self
376 .languages
377 .lsp_adapters(language_name)
378 .into_iter()
379 .find(|adapter| adapter.name() == disposition.server_name)
380 .expect("To find LSP adapter");
381 let new_language_server_id = self.start_language_server(
382 worktree_handle,
383 delegate,
384 adapter,
385 disposition.settings.clone(),
386 key.clone(),
387 language_name.clone(),
388 cx,
389 );
390 if let Some(state) = self.language_server_ids.get_mut(&key) {
391 state.project_roots.insert(disposition.path.path.clone());
392 } else {
393 debug_assert!(
394 false,
395 "Expected `start_language_server` to ensure that `key` exists in a map"
396 );
397 }
398 new_language_server_id
399 }
400 }
401
402 fn start_language_server(
403 &mut self,
404 worktree_handle: &Entity<Worktree>,
405 delegate: Arc<LocalLspAdapterDelegate>,
406 adapter: Arc<CachedLspAdapter>,
407 settings: Arc<LspSettings>,
408 key: LanguageServerSeed,
409 language_name: LanguageName,
410 cx: &mut App,
411 ) -> LanguageServerId {
412 let worktree = worktree_handle.read(cx);
413
414 let worktree_id = worktree.id();
415 let worktree_abs_path = worktree.abs_path();
416 let toolchain = key.toolchain.clone();
417 let override_options = settings.initialization_options.clone();
418
419 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
420
421 let server_id = self.languages.next_language_server_id();
422 log::trace!(
423 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
424 adapter.name.0
425 );
426
427 let wait_until_worktree_trust =
428 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
429 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
430 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
431 });
432 if can_trust {
433 self.restricted_worktrees_tasks.remove(&worktree_id);
434 None
435 } else {
436 match self.restricted_worktrees_tasks.entry(worktree_id) {
437 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
438 hash_map::Entry::Vacant(v) => {
439 let (mut tx, rx) = watch::channel::<bool>();
440 let lsp_store = self.weak.clone();
441 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
442 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
443 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
444 tx.blocking_send(true).ok();
445 lsp_store
446 .update(cx, |lsp_store, _| {
447 if let Some(local_lsp_store) =
448 lsp_store.as_local_mut()
449 {
450 local_lsp_store
451 .restricted_worktrees_tasks
452 .remove(&worktree_id);
453 }
454 })
455 .ok();
456 }
457 }
458 });
459 v.insert((subscription, rx.clone()));
460 Some(rx)
461 }
462 }
463 }
464 });
465 let update_binary_status = wait_until_worktree_trust.is_none();
466
467 let binary = self.get_language_server_binary(
468 worktree_abs_path.clone(),
469 adapter.clone(),
470 settings,
471 toolchain.clone(),
472 delegate.clone(),
473 true,
474 wait_until_worktree_trust,
475 cx,
476 );
477 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
478
479 let pending_server = cx.spawn({
480 let adapter = adapter.clone();
481 let server_name = adapter.name.clone();
482 let stderr_capture = stderr_capture.clone();
483 #[cfg(any(test, feature = "test-support"))]
484 let lsp_store = self.weak.clone();
485 let pending_workspace_folders = pending_workspace_folders.clone();
486 async move |cx| {
487 let binary = binary.await?;
488 #[cfg(any(test, feature = "test-support"))]
489 if let Some(server) = lsp_store
490 .update(&mut cx.clone(), |this, cx| {
491 this.languages.create_fake_language_server(
492 server_id,
493 &server_name,
494 binary.clone(),
495 &mut cx.to_async(),
496 )
497 })
498 .ok()
499 .flatten()
500 {
501 return Ok(server);
502 }
503
504 let code_action_kinds = adapter.code_action_kinds();
505 lsp::LanguageServer::new(
506 stderr_capture,
507 server_id,
508 server_name,
509 binary,
510 &worktree_abs_path,
511 code_action_kinds,
512 Some(pending_workspace_folders),
513 cx,
514 )
515 }
516 });
517
518 let startup = {
519 let server_name = adapter.name.0.clone();
520 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
521 let key = key.clone();
522 let adapter = adapter.clone();
523 let lsp_store = self.weak.clone();
524 let pending_workspace_folders = pending_workspace_folders.clone();
525 let pull_diagnostics = ProjectSettings::get_global(cx)
526 .diagnostics
527 .lsp_pull_diagnostics
528 .enabled;
529 let settings_location = SettingsLocation {
530 worktree_id,
531 path: RelPath::empty(),
532 };
533 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
534 .language(Some(settings_location), Some(&language_name), cx)
535 .semantic_tokens
536 .use_tree_sitter();
537 cx.spawn(async move |cx| {
538 let result = async {
539 let language_server = pending_server.await?;
540
541 let workspace_config = Self::workspace_configuration_for_adapter(
542 adapter.adapter.clone(),
543 &delegate,
544 toolchain,
545 None,
546 cx,
547 )
548 .await?;
549
550 let mut initialization_options = Self::initialization_options_for_adapter(
551 adapter.adapter.clone(),
552 &delegate,
553 cx,
554 )
555 .await?;
556
557 match (&mut initialization_options, override_options) {
558 (Some(initialization_options), Some(override_options)) => {
559 merge_json_value_into(override_options, initialization_options);
560 }
561 (None, override_options) => initialization_options = override_options,
562 _ => {}
563 }
564
565 let initialization_params = cx.update(|cx| {
566 let mut params = language_server.default_initialize_params(
567 pull_diagnostics,
568 augments_syntax_tokens,
569 cx,
570 );
571 params.initialization_options = initialization_options;
572 adapter.adapter.prepare_initialize_params(params, cx)
573 })?;
574
575 Self::setup_lsp_messages(
576 lsp_store.clone(),
577 &language_server,
578 delegate.clone(),
579 adapter.clone(),
580 );
581
582 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
583 settings: workspace_config,
584 };
585 let language_server = cx
586 .update(|cx| {
587 let request_timeout = ProjectSettings::get_global(cx)
588 .global_lsp_settings
589 .get_request_timeout();
590
591 language_server.initialize(
592 initialization_params,
593 Arc::new(did_change_configuration_params.clone()),
594 request_timeout,
595 cx,
596 )
597 })
598 .await
599 .inspect_err(|_| {
600 if let Some(lsp_store) = lsp_store.upgrade() {
601 lsp_store.update(cx, |lsp_store, cx| {
602 lsp_store.cleanup_lsp_data(server_id);
603 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
604 });
605 }
606 })?;
607
608 language_server.notify::<lsp::notification::DidChangeConfiguration>(
609 did_change_configuration_params,
610 )?;
611
612 anyhow::Ok(language_server)
613 }
614 .await;
615
616 match result {
617 Ok(server) => {
618 lsp_store
619 .update(cx, |lsp_store, cx| {
620 lsp_store.insert_newly_running_language_server(
621 adapter,
622 server.clone(),
623 server_id,
624 key,
625 pending_workspace_folders,
626 cx,
627 );
628 })
629 .ok();
630 stderr_capture.lock().take();
631 Some(server)
632 }
633
634 Err(err) => {
635 let log = stderr_capture.lock().take().unwrap_or_default();
636 delegate.update_status(
637 adapter.name(),
638 BinaryStatus::Failed {
639 error: if log.is_empty() {
640 format!("{err:#}")
641 } else {
642 format!("{err:#}\n-- stderr --\n{log}")
643 },
644 },
645 );
646 log::error!(
647 "Failed to start language server {server_name:?}: {}",
648 redact_command(&format!("{err:?}"))
649 );
650 if !log.is_empty() {
651 log::error!("server stderr: {}", redact_command(&log));
652 }
653 None
654 }
655 }
656 })
657 };
658 let state = LanguageServerState::Starting {
659 startup,
660 pending_workspace_folders,
661 };
662
663 if update_binary_status {
664 self.languages
665 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
666 }
667
668 self.language_servers.insert(server_id, state);
669 self.language_server_ids
670 .entry(key)
671 .or_insert(UnifiedLanguageServer {
672 id: server_id,
673 project_roots: Default::default(),
674 });
675 server_id
676 }
677
678 fn get_language_server_binary(
679 &self,
680 worktree_abs_path: Arc<Path>,
681 adapter: Arc<CachedLspAdapter>,
682 settings: Arc<LspSettings>,
683 toolchain: Option<Toolchain>,
684 delegate: Arc<dyn LspAdapterDelegate>,
685 allow_binary_download: bool,
686 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
687 cx: &mut App,
688 ) -> Task<Result<LanguageServerBinary>> {
689 if let Some(settings) = &settings.binary
690 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
691 {
692 let settings = settings.clone();
693 let languages = self.languages.clone();
694 return cx.background_spawn(async move {
695 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
696 let already_trusted = *wait_until_worktree_trust.borrow();
697 if !already_trusted {
698 log::info!(
699 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
700 adapter.name(),
701 );
702 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
703 if worktree_trusted {
704 break;
705 }
706 }
707 log::info!(
708 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
709 adapter.name(),
710 );
711 }
712 languages
713 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
714 }
715 let mut env = delegate.shell_env().await;
716 env.extend(settings.env.unwrap_or_default());
717
718 Ok(LanguageServerBinary {
719 path: delegate.resolve_relative_path(path),
720 env: Some(env),
721 arguments: settings
722 .arguments
723 .unwrap_or_default()
724 .iter()
725 .map(Into::into)
726 .collect(),
727 })
728 });
729 }
730 let lsp_binary_options = LanguageServerBinaryOptions {
731 allow_path_lookup: !settings
732 .binary
733 .as_ref()
734 .and_then(|b| b.ignore_system_version)
735 .unwrap_or_default(),
736 allow_binary_download,
737 pre_release: settings
738 .fetch
739 .as_ref()
740 .and_then(|f| f.pre_release)
741 .unwrap_or(false),
742 };
743
744 cx.spawn(async move |cx| {
745 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
746 let already_trusted = *wait_until_worktree_trust.borrow();
747 if !already_trusted {
748 log::info!(
749 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
750 adapter.name(),
751 );
752 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
753 if worktree_trusted {
754 break;
755 }
756 }
757 log::info!(
758 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
759 adapter.name(),
760 );
761 }
762 }
763
764 let (existing_binary, maybe_download_binary) = adapter
765 .clone()
766 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
767 .await
768 .await;
769
770 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
771
772 let mut binary = match (existing_binary, maybe_download_binary) {
773 (binary, None) => binary?,
774 (Err(_), Some(downloader)) => downloader.await?,
775 (Ok(existing_binary), Some(downloader)) => {
776 let mut download_timeout = cx
777 .background_executor()
778 .timer(SERVER_DOWNLOAD_TIMEOUT)
779 .fuse();
780 let mut downloader = downloader.fuse();
781 futures::select! {
782 _ = download_timeout => {
783 // Return existing binary and kick the existing work to the background.
784 cx.spawn(async move |_| downloader.await).detach();
785 Ok(existing_binary)
786 },
787 downloaded_or_existing_binary = downloader => {
788 // If download fails, this results in the existing binary.
789 downloaded_or_existing_binary
790 }
791 }?
792 }
793 };
794 let mut shell_env = delegate.shell_env().await;
795
796 shell_env.extend(binary.env.unwrap_or_default());
797
798 if let Some(settings) = settings.binary.as_ref() {
799 if let Some(arguments) = &settings.arguments {
800 binary.arguments = arguments.iter().map(Into::into).collect();
801 }
802 if let Some(env) = &settings.env {
803 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
804 }
805 }
806
807 binary.env = Some(shell_env);
808 Ok(binary)
809 })
810 }
811
812 fn setup_lsp_messages(
813 lsp_store: WeakEntity<LspStore>,
814 language_server: &LanguageServer,
815 delegate: Arc<dyn LspAdapterDelegate>,
816 adapter: Arc<CachedLspAdapter>,
817 ) {
818 let name = language_server.name();
819 let server_id = language_server.server_id();
820 language_server
821 .on_notification::<lsp::notification::PublishDiagnostics, _>({
822 let adapter = adapter.clone();
823 let this = lsp_store.clone();
824 move |mut params, cx| {
825 let adapter = adapter.clone();
826 if let Some(this) = this.upgrade() {
827 this.update(cx, |this, cx| {
828 adapter.process_diagnostics(&mut params, server_id);
829
830 this.merge_lsp_diagnostics(
831 DiagnosticSourceKind::Pushed,
832 vec![DocumentDiagnosticsUpdate {
833 server_id,
834 diagnostics: params,
835 result_id: None,
836 disk_based_sources: Cow::Borrowed(
837 &adapter.disk_based_diagnostic_sources,
838 ),
839 registration_id: None,
840 }],
841 |_, diagnostic, _cx| match diagnostic.source_kind {
842 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
843 adapter.retain_old_diagnostic(diagnostic)
844 }
845 DiagnosticSourceKind::Pulled => true,
846 },
847 cx,
848 )
849 .log_err();
850 });
851 }
852 }
853 })
854 .detach();
855 language_server
856 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
857 let adapter = adapter.adapter.clone();
858 let delegate = delegate.clone();
859 let this = lsp_store.clone();
860 move |params, cx| {
861 let adapter = adapter.clone();
862 let delegate = delegate.clone();
863 let this = this.clone();
864 let mut cx = cx.clone();
865 async move {
866 let toolchain_for_id = this
867 .update(&mut cx, |this, _| {
868 this.as_local()?.language_server_ids.iter().find_map(
869 |(seed, value)| {
870 (value.id == server_id).then(|| seed.toolchain.clone())
871 },
872 )
873 })?
874 .context("Expected the LSP store to be in a local mode")?;
875
876 let mut scope_uri_to_workspace_config = BTreeMap::new();
877 for item in ¶ms.items {
878 let scope_uri = item.scope_uri.clone();
879 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
880 scope_uri_to_workspace_config.entry(scope_uri.clone())
881 else {
882 // We've already queried workspace configuration of this URI.
883 continue;
884 };
885 let workspace_config = Self::workspace_configuration_for_adapter(
886 adapter.clone(),
887 &delegate,
888 toolchain_for_id.clone(),
889 scope_uri,
890 &mut cx,
891 )
892 .await?;
893 new_scope_uri.insert(workspace_config);
894 }
895
896 Ok(params
897 .items
898 .into_iter()
899 .filter_map(|item| {
900 let workspace_config =
901 scope_uri_to_workspace_config.get(&item.scope_uri)?;
902 if let Some(section) = &item.section {
903 Some(
904 workspace_config
905 .get(section)
906 .cloned()
907 .unwrap_or(serde_json::Value::Null),
908 )
909 } else {
910 Some(workspace_config.clone())
911 }
912 })
913 .collect())
914 }
915 }
916 })
917 .detach();
918
919 language_server
920 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
921 let this = lsp_store.clone();
922 move |_, cx| {
923 let this = this.clone();
924 let cx = cx.clone();
925 async move {
926 let Some(server) =
927 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
928 else {
929 return Ok(None);
930 };
931 let root = server.workspace_folders();
932 Ok(Some(
933 root.into_iter()
934 .map(|uri| WorkspaceFolder {
935 uri,
936 name: Default::default(),
937 })
938 .collect(),
939 ))
940 }
941 }
942 })
943 .detach();
944 // Even though we don't have handling for these requests, respond to them to
945 // avoid stalling any language server like `gopls` which waits for a response
946 // to these requests when initializing.
947 language_server
948 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
949 let this = lsp_store.clone();
950 move |params, cx| {
951 let this = this.clone();
952 let mut cx = cx.clone();
953 async move {
954 this.update(&mut cx, |this, _| {
955 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
956 {
957 status
958 .progress_tokens
959 .insert(ProgressToken::from_lsp(params.token));
960 }
961 })?;
962
963 Ok(())
964 }
965 }
966 })
967 .detach();
968
969 language_server
970 .on_request::<lsp::request::RegisterCapability, _, _>({
971 let lsp_store = lsp_store.clone();
972 move |params, cx| {
973 let lsp_store = lsp_store.clone();
974 let mut cx = cx.clone();
975 async move {
976 lsp_store
977 .update(&mut cx, |lsp_store, cx| {
978 if lsp_store.as_local().is_some() {
979 match lsp_store
980 .register_server_capabilities(server_id, params, cx)
981 {
982 Ok(()) => {}
983 Err(e) => {
984 log::error!(
985 "Failed to register server capabilities: {e:#}"
986 );
987 }
988 };
989 }
990 })
991 .ok();
992 Ok(())
993 }
994 }
995 })
996 .detach();
997
998 language_server
999 .on_request::<lsp::request::UnregisterCapability, _, _>({
1000 let lsp_store = lsp_store.clone();
1001 move |params, cx| {
1002 let lsp_store = lsp_store.clone();
1003 let mut cx = cx.clone();
1004 async move {
1005 lsp_store
1006 .update(&mut cx, |lsp_store, cx| {
1007 if lsp_store.as_local().is_some() {
1008 match lsp_store
1009 .unregister_server_capabilities(server_id, params, cx)
1010 {
1011 Ok(()) => {}
1012 Err(e) => {
1013 log::error!(
1014 "Failed to unregister server capabilities: {e:#}"
1015 );
1016 }
1017 }
1018 }
1019 })
1020 .ok();
1021 Ok(())
1022 }
1023 }
1024 })
1025 .detach();
1026
1027 language_server
1028 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1029 let this = lsp_store.clone();
1030 move |params, cx| {
1031 let mut cx = cx.clone();
1032 let this = this.clone();
1033 async move {
1034 LocalLspStore::on_lsp_workspace_edit(
1035 this.clone(),
1036 params,
1037 server_id,
1038 &mut cx,
1039 )
1040 .await
1041 }
1042 }
1043 })
1044 .detach();
1045
1046 language_server
1047 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1048 let lsp_store = lsp_store.clone();
1049 let request_id = Arc::new(AtomicUsize::new(0));
1050 move |(), cx| {
1051 let lsp_store = lsp_store.clone();
1052 let request_id = request_id.clone();
1053 let mut cx = cx.clone();
1054 async move {
1055 lsp_store
1056 .update(&mut cx, |lsp_store, cx| {
1057 let request_id =
1058 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1059 cx.emit(LspStoreEvent::RefreshInlayHints {
1060 server_id,
1061 request_id,
1062 });
1063 lsp_store
1064 .downstream_client
1065 .as_ref()
1066 .map(|(client, project_id)| {
1067 client.send(proto::RefreshInlayHints {
1068 project_id: *project_id,
1069 server_id: server_id.to_proto(),
1070 request_id: request_id.map(|id| id as u64),
1071 })
1072 })
1073 })?
1074 .transpose()?;
1075 Ok(())
1076 }
1077 }
1078 })
1079 .detach();
1080
1081 language_server
1082 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1083 let this = lsp_store.clone();
1084 move |(), cx| {
1085 let this = this.clone();
1086 let mut cx = cx.clone();
1087 async move {
1088 this.update(&mut cx, |this, cx| {
1089 cx.emit(LspStoreEvent::RefreshCodeLens);
1090 this.downstream_client.as_ref().map(|(client, project_id)| {
1091 client.send(proto::RefreshCodeLens {
1092 project_id: *project_id,
1093 })
1094 })
1095 })?
1096 .transpose()?;
1097 Ok(())
1098 }
1099 }
1100 })
1101 .detach();
1102
1103 language_server
1104 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1105 let lsp_store = lsp_store.clone();
1106 let request_id = Arc::new(AtomicUsize::new(0));
1107 move |(), cx| {
1108 let lsp_store = lsp_store.clone();
1109 let request_id = request_id.clone();
1110 let mut cx = cx.clone();
1111 async move {
1112 lsp_store
1113 .update(&mut cx, |lsp_store, cx| {
1114 let request_id =
1115 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1116 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1117 server_id,
1118 request_id,
1119 });
1120 lsp_store
1121 .downstream_client
1122 .as_ref()
1123 .map(|(client, project_id)| {
1124 client.send(proto::RefreshSemanticTokens {
1125 project_id: *project_id,
1126 server_id: server_id.to_proto(),
1127 request_id: request_id.map(|id| id as u64),
1128 })
1129 })
1130 })?
1131 .transpose()?;
1132 Ok(())
1133 }
1134 }
1135 })
1136 .detach();
1137
1138 language_server
1139 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1140 let this = lsp_store.clone();
1141 move |(), cx| {
1142 let this = this.clone();
1143 let mut cx = cx.clone();
1144 async move {
1145 this.update(&mut cx, |lsp_store, cx| {
1146 lsp_store.pull_workspace_diagnostics(server_id);
1147 lsp_store
1148 .downstream_client
1149 .as_ref()
1150 .map(|(client, project_id)| {
1151 client.send(proto::PullWorkspaceDiagnostics {
1152 project_id: *project_id,
1153 server_id: server_id.to_proto(),
1154 })
1155 })
1156 .transpose()?;
1157 anyhow::Ok(
1158 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1159 )
1160 })??
1161 .await;
1162 Ok(())
1163 }
1164 }
1165 })
1166 .detach();
1167
1168 language_server
1169 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1170 let this = lsp_store.clone();
1171 let name = name.to_string();
1172 let adapter = adapter.clone();
1173 move |params, cx| {
1174 let this = this.clone();
1175 let name = name.to_string();
1176 let adapter = adapter.clone();
1177 let mut cx = cx.clone();
1178 async move {
1179 let actions = params.actions.unwrap_or_default();
1180 let message = params.message.clone();
1181 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1182 let level = match params.typ {
1183 lsp::MessageType::ERROR => PromptLevel::Critical,
1184 lsp::MessageType::WARNING => PromptLevel::Warning,
1185 _ => PromptLevel::Info,
1186 };
1187 let request = LanguageServerPromptRequest::new(
1188 level,
1189 params.message,
1190 actions,
1191 name.clone(),
1192 tx,
1193 );
1194
1195 let did_update = this
1196 .update(&mut cx, |_, cx| {
1197 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1198 })
1199 .is_ok();
1200 if did_update {
1201 let response = rx.recv().await.ok();
1202 if let Some(ref selected_action) = response {
1203 let context = language::PromptResponseContext {
1204 message,
1205 selected_action: selected_action.clone(),
1206 };
1207 adapter.process_prompt_response(&context, &mut cx)
1208 }
1209
1210 Ok(response)
1211 } else {
1212 Ok(None)
1213 }
1214 }
1215 }
1216 })
1217 .detach();
1218 language_server
1219 .on_notification::<lsp::notification::ShowMessage, _>({
1220 let this = lsp_store.clone();
1221 let name = name.to_string();
1222 move |params, cx| {
1223 let this = this.clone();
1224 let name = name.to_string();
1225 let mut cx = cx.clone();
1226
1227 let (tx, _) = smol::channel::bounded(1);
1228 let level = match params.typ {
1229 lsp::MessageType::ERROR => PromptLevel::Critical,
1230 lsp::MessageType::WARNING => PromptLevel::Warning,
1231 _ => PromptLevel::Info,
1232 };
1233 let request =
1234 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1235
1236 let _ = this.update(&mut cx, |_, cx| {
1237 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1238 });
1239 }
1240 })
1241 .detach();
1242
1243 let disk_based_diagnostics_progress_token =
1244 adapter.disk_based_diagnostics_progress_token.clone();
1245
1246 language_server
1247 .on_notification::<lsp::notification::Progress, _>({
1248 let this = lsp_store.clone();
1249 move |params, cx| {
1250 if let Some(this) = this.upgrade() {
1251 this.update(cx, |this, cx| {
1252 this.on_lsp_progress(
1253 params,
1254 server_id,
1255 disk_based_diagnostics_progress_token.clone(),
1256 cx,
1257 );
1258 });
1259 }
1260 }
1261 })
1262 .detach();
1263
1264 language_server
1265 .on_notification::<lsp::notification::LogMessage, _>({
1266 let this = lsp_store.clone();
1267 move |params, cx| {
1268 if let Some(this) = this.upgrade() {
1269 this.update(cx, |_, cx| {
1270 cx.emit(LspStoreEvent::LanguageServerLog(
1271 server_id,
1272 LanguageServerLogType::Log(params.typ),
1273 params.message,
1274 ));
1275 });
1276 }
1277 }
1278 })
1279 .detach();
1280
1281 language_server
1282 .on_notification::<lsp::notification::LogTrace, _>({
1283 let this = lsp_store.clone();
1284 move |params, cx| {
1285 let mut cx = cx.clone();
1286 if let Some(this) = this.upgrade() {
1287 this.update(&mut cx, |_, cx| {
1288 cx.emit(LspStoreEvent::LanguageServerLog(
1289 server_id,
1290 LanguageServerLogType::Trace {
1291 verbose_info: params.verbose,
1292 },
1293 params.message,
1294 ));
1295 });
1296 }
1297 }
1298 })
1299 .detach();
1300
1301 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1302 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1303 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1304 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1305 }
1306
1307 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1308 let shutdown_futures = self
1309 .language_servers
1310 .drain()
1311 .map(|(_, server_state)| Self::shutdown_server(server_state))
1312 .collect::<Vec<_>>();
1313
1314 async move {
1315 join_all(shutdown_futures).await;
1316 }
1317 }
1318
1319 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1320 match server_state {
1321 LanguageServerState::Running { server, .. } => {
1322 if let Some(shutdown) = server.shutdown() {
1323 shutdown.await;
1324 }
1325 }
1326 LanguageServerState::Starting { startup, .. } => {
1327 if let Some(server) = startup.await
1328 && let Some(shutdown) = server.shutdown()
1329 {
1330 shutdown.await;
1331 }
1332 }
1333 }
1334 Ok(())
1335 }
1336
1337 fn language_servers_for_worktree(
1338 &self,
1339 worktree_id: WorktreeId,
1340 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1341 self.language_server_ids
1342 .iter()
1343 .filter_map(move |(seed, state)| {
1344 if seed.worktree_id != worktree_id {
1345 return None;
1346 }
1347
1348 if let Some(LanguageServerState::Running { server, .. }) =
1349 self.language_servers.get(&state.id)
1350 {
1351 Some(server)
1352 } else {
1353 None
1354 }
1355 })
1356 }
1357
1358 fn language_server_ids_for_project_path(
1359 &self,
1360 project_path: ProjectPath,
1361 language: &Language,
1362 cx: &mut App,
1363 ) -> Vec<LanguageServerId> {
1364 let Some(worktree) = self
1365 .worktree_store
1366 .read(cx)
1367 .worktree_for_id(project_path.worktree_id, cx)
1368 else {
1369 return Vec::new();
1370 };
1371 let delegate: Arc<dyn ManifestDelegate> =
1372 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1373
1374 self.lsp_tree
1375 .get(
1376 project_path,
1377 language.name(),
1378 language.manifest(),
1379 &delegate,
1380 cx,
1381 )
1382 .collect::<Vec<_>>()
1383 }
1384
1385 fn language_server_ids_for_buffer(
1386 &self,
1387 buffer: &Buffer,
1388 cx: &mut App,
1389 ) -> Vec<LanguageServerId> {
1390 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1391 let worktree_id = file.worktree_id(cx);
1392
1393 let path: Arc<RelPath> = file
1394 .path()
1395 .parent()
1396 .map(Arc::from)
1397 .unwrap_or_else(|| file.path().clone());
1398 let worktree_path = ProjectPath { worktree_id, path };
1399 self.language_server_ids_for_project_path(worktree_path, language, cx)
1400 } else {
1401 Vec::new()
1402 }
1403 }
1404
1405 fn language_servers_for_buffer<'a>(
1406 &'a self,
1407 buffer: &'a Buffer,
1408 cx: &'a mut App,
1409 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1410 self.language_server_ids_for_buffer(buffer, cx)
1411 .into_iter()
1412 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1413 LanguageServerState::Running {
1414 adapter, server, ..
1415 } => Some((adapter, server)),
1416 _ => None,
1417 })
1418 }
1419
1420 async fn execute_code_action_kind_locally(
1421 lsp_store: WeakEntity<LspStore>,
1422 mut buffers: Vec<Entity<Buffer>>,
1423 kind: CodeActionKind,
1424 push_to_history: bool,
1425 cx: &mut AsyncApp,
1426 ) -> anyhow::Result<ProjectTransaction> {
1427 // Do not allow multiple concurrent code actions requests for the
1428 // same buffer.
1429 lsp_store.update(cx, |this, cx| {
1430 let this = this.as_local_mut().unwrap();
1431 buffers.retain(|buffer| {
1432 this.buffers_being_formatted
1433 .insert(buffer.read(cx).remote_id())
1434 });
1435 })?;
1436 let _cleanup = defer({
1437 let this = lsp_store.clone();
1438 let mut cx = cx.clone();
1439 let buffers = &buffers;
1440 move || {
1441 this.update(&mut cx, |this, cx| {
1442 let this = this.as_local_mut().unwrap();
1443 for buffer in buffers {
1444 this.buffers_being_formatted
1445 .remove(&buffer.read(cx).remote_id());
1446 }
1447 })
1448 .ok();
1449 }
1450 });
1451 let mut project_transaction = ProjectTransaction::default();
1452
1453 for buffer in &buffers {
1454 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1455 buffer.update(cx, |buffer, cx| {
1456 lsp_store
1457 .as_local()
1458 .unwrap()
1459 .language_servers_for_buffer(buffer, cx)
1460 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1461 .collect::<Vec<_>>()
1462 })
1463 })?;
1464 for (_, language_server) in adapters_and_servers.iter() {
1465 let actions = Self::get_server_code_actions_from_action_kinds(
1466 &lsp_store,
1467 language_server.server_id(),
1468 vec![kind.clone()],
1469 buffer,
1470 cx,
1471 )
1472 .await?;
1473 Self::execute_code_actions_on_server(
1474 &lsp_store,
1475 language_server,
1476 actions,
1477 push_to_history,
1478 &mut project_transaction,
1479 cx,
1480 )
1481 .await?;
1482 }
1483 }
1484 Ok(project_transaction)
1485 }
1486
1487 async fn format_locally(
1488 lsp_store: WeakEntity<LspStore>,
1489 mut buffers: Vec<FormattableBuffer>,
1490 push_to_history: bool,
1491 trigger: FormatTrigger,
1492 logger: zlog::Logger,
1493 cx: &mut AsyncApp,
1494 ) -> anyhow::Result<ProjectTransaction> {
1495 // Do not allow multiple concurrent formatting requests for the
1496 // same buffer.
1497 lsp_store.update(cx, |this, cx| {
1498 let this = this.as_local_mut().unwrap();
1499 buffers.retain(|buffer| {
1500 this.buffers_being_formatted
1501 .insert(buffer.handle.read(cx).remote_id())
1502 });
1503 })?;
1504
1505 let _cleanup = defer({
1506 let this = lsp_store.clone();
1507 let mut cx = cx.clone();
1508 let buffers = &buffers;
1509 move || {
1510 this.update(&mut cx, |this, cx| {
1511 let this = this.as_local_mut().unwrap();
1512 for buffer in buffers {
1513 this.buffers_being_formatted
1514 .remove(&buffer.handle.read(cx).remote_id());
1515 }
1516 })
1517 .ok();
1518 }
1519 });
1520
1521 let mut project_transaction = ProjectTransaction::default();
1522
1523 for buffer in &buffers {
1524 zlog::debug!(
1525 logger =>
1526 "formatting buffer '{:?}'",
1527 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1528 );
1529 // Create an empty transaction to hold all of the formatting edits.
1530 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1531 // ensure no transactions created while formatting are
1532 // grouped with the previous transaction in the history
1533 // based on the transaction group interval
1534 buffer.finalize_last_transaction();
1535 buffer
1536 .start_transaction()
1537 .context("transaction already open")?;
1538 buffer.end_transaction(cx);
1539 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1540 buffer.finalize_last_transaction();
1541 anyhow::Ok(transaction_id)
1542 })?;
1543
1544 let result = Self::format_buffer_locally(
1545 lsp_store.clone(),
1546 buffer,
1547 formatting_transaction_id,
1548 trigger,
1549 logger,
1550 cx,
1551 )
1552 .await;
1553
1554 buffer.handle.update(cx, |buffer, cx| {
1555 let Some(formatting_transaction) =
1556 buffer.get_transaction(formatting_transaction_id).cloned()
1557 else {
1558 zlog::warn!(logger => "no formatting transaction");
1559 return;
1560 };
1561 if formatting_transaction.edit_ids.is_empty() {
1562 zlog::debug!(logger => "no changes made while formatting");
1563 buffer.forget_transaction(formatting_transaction_id);
1564 return;
1565 }
1566 if !push_to_history {
1567 zlog::trace!(logger => "forgetting format transaction");
1568 buffer.forget_transaction(formatting_transaction.id);
1569 }
1570 project_transaction
1571 .0
1572 .insert(cx.entity(), formatting_transaction);
1573 });
1574
1575 result?;
1576 }
1577
1578 Ok(project_transaction)
1579 }
1580
1581 async fn format_buffer_locally(
1582 lsp_store: WeakEntity<LspStore>,
1583 buffer: &FormattableBuffer,
1584 formatting_transaction_id: clock::Lamport,
1585 trigger: FormatTrigger,
1586 logger: zlog::Logger,
1587 cx: &mut AsyncApp,
1588 ) -> Result<()> {
1589 let (adapters_and_servers, settings, request_timeout) =
1590 lsp_store.update(cx, |lsp_store, cx| {
1591 buffer.handle.update(cx, |buffer, cx| {
1592 let adapters_and_servers = lsp_store
1593 .as_local()
1594 .unwrap()
1595 .language_servers_for_buffer(buffer, cx)
1596 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1597 .collect::<Vec<_>>();
1598 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1599 let request_timeout = ProjectSettings::get_global(cx)
1600 .global_lsp_settings
1601 .get_request_timeout();
1602 (adapters_and_servers, settings, request_timeout)
1603 })
1604 })?;
1605
1606 // handle whitespace formatting
1607 if settings.remove_trailing_whitespace_on_save {
1608 zlog::trace!(logger => "removing trailing whitespace");
1609 let diff = buffer
1610 .handle
1611 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1612 .await;
1613 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1614 buffer.apply_diff(diff, cx);
1615 })?;
1616 }
1617
1618 if settings.ensure_final_newline_on_save {
1619 zlog::trace!(logger => "ensuring final newline");
1620 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1621 buffer.ensure_final_newline(cx);
1622 })?;
1623 }
1624
1625 // Formatter for `code_actions_on_format` that runs before
1626 // the rest of the formatters
1627 let mut code_actions_on_format_formatters = None;
1628 let should_run_code_actions_on_format = !matches!(
1629 (trigger, &settings.format_on_save),
1630 (FormatTrigger::Save, &FormatOnSave::Off)
1631 );
1632 if should_run_code_actions_on_format {
1633 let have_code_actions_to_run_on_format = settings
1634 .code_actions_on_format
1635 .values()
1636 .any(|enabled| *enabled);
1637 if have_code_actions_to_run_on_format {
1638 zlog::trace!(logger => "going to run code actions on format");
1639 code_actions_on_format_formatters = Some(
1640 settings
1641 .code_actions_on_format
1642 .iter()
1643 .filter_map(|(action, enabled)| enabled.then_some(action))
1644 .cloned()
1645 .map(Formatter::CodeAction)
1646 .collect::<Vec<_>>(),
1647 );
1648 }
1649 }
1650
1651 let formatters = match (trigger, &settings.format_on_save) {
1652 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1653 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1654 settings.formatter.as_ref()
1655 }
1656 };
1657
1658 let formatters = code_actions_on_format_formatters
1659 .iter()
1660 .flatten()
1661 .chain(formatters);
1662
1663 for formatter in formatters {
1664 let formatter = if formatter == &Formatter::Auto {
1665 if settings.prettier.allowed {
1666 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1667 &Formatter::Prettier
1668 } else {
1669 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1670 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1671 }
1672 } else {
1673 formatter
1674 };
1675 if let Err(err) = Self::apply_formatter(
1676 formatter,
1677 &lsp_store,
1678 buffer,
1679 formatting_transaction_id,
1680 &adapters_and_servers,
1681 &settings,
1682 request_timeout,
1683 logger,
1684 cx,
1685 )
1686 .await
1687 {
1688 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1689 }
1690 }
1691
1692 Ok(())
1693 }
1694
1695 async fn apply_formatter(
1696 formatter: &Formatter,
1697 lsp_store: &WeakEntity<LspStore>,
1698 buffer: &FormattableBuffer,
1699 formatting_transaction_id: clock::Lamport,
1700 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1701 settings: &LanguageSettings,
1702 request_timeout: Duration,
1703 logger: zlog::Logger,
1704 cx: &mut AsyncApp,
1705 ) -> anyhow::Result<()> {
1706 match formatter {
1707 Formatter::None => {
1708 zlog::trace!(logger => "skipping formatter 'none'");
1709 return Ok(());
1710 }
1711 Formatter::Auto => {
1712 debug_panic!("Auto resolved above");
1713 return Ok(());
1714 }
1715 Formatter::Prettier => {
1716 let logger = zlog::scoped!(logger => "prettier");
1717 zlog::trace!(logger => "formatting");
1718 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1719
1720 // When selection ranges are provided (via FormatSelections), we pass the
1721 // encompassing UTF-16 range to Prettier so it can scope its formatting.
1722 // After diffing, we filter the resulting edits to only keep those that
1723 // overlap with the original byte-level selection ranges.
1724 let (range_utf16, byte_ranges) = match buffer.ranges.as_ref() {
1725 Some(ranges) if !ranges.is_empty() => {
1726 let (utf16_range, byte_ranges) =
1727 buffer.handle.read_with(cx, |buffer, _cx| {
1728 let snapshot = buffer.snapshot();
1729 let mut min_start_utf16 = OffsetUtf16(usize::MAX);
1730 let mut max_end_utf16 = OffsetUtf16(0);
1731 let mut byte_ranges = Vec::with_capacity(ranges.len());
1732 for range in ranges {
1733 let start_utf16 = range.start.to_offset_utf16(&snapshot);
1734 let end_utf16 = range.end.to_offset_utf16(&snapshot);
1735 min_start_utf16.0 = min_start_utf16.0.min(start_utf16.0);
1736 max_end_utf16.0 = max_end_utf16.0.max(end_utf16.0);
1737
1738 let start_byte = range.start.to_offset(&snapshot);
1739 let end_byte = range.end.to_offset(&snapshot);
1740 byte_ranges.push(start_byte..end_byte);
1741 }
1742 (min_start_utf16..max_end_utf16, byte_ranges)
1743 });
1744 (Some(utf16_range), Some(byte_ranges))
1745 }
1746 _ => (None, None),
1747 };
1748
1749 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1750 lsp_store.prettier_store().unwrap().downgrade()
1751 })?;
1752 let diff = prettier_store::format_with_prettier(
1753 &prettier,
1754 &buffer.handle,
1755 range_utf16,
1756 cx,
1757 )
1758 .await
1759 .transpose()?;
1760 let Some(mut diff) = diff else {
1761 zlog::trace!(logger => "No changes");
1762 return Ok(());
1763 };
1764
1765 if let Some(byte_ranges) = byte_ranges {
1766 diff.edits.retain(|(edit_range, _)| {
1767 byte_ranges.iter().any(|selection_range| {
1768 edit_range.start < selection_range.end
1769 && edit_range.end > selection_range.start
1770 })
1771 });
1772 if diff.edits.is_empty() {
1773 zlog::trace!(logger => "No changes within selection");
1774 return Ok(());
1775 }
1776 }
1777
1778 extend_formatting_transaction(
1779 buffer,
1780 formatting_transaction_id,
1781 cx,
1782 |buffer, cx| {
1783 buffer.apply_diff(diff, cx);
1784 },
1785 )?;
1786 }
1787 Formatter::External { command, arguments } => {
1788 let logger = zlog::scoped!(logger => "command");
1789
1790 if buffer.ranges.is_some() {
1791 zlog::debug!(logger => "External formatter does not support range formatting; skipping");
1792 return Ok(());
1793 }
1794
1795 zlog::trace!(logger => "formatting");
1796 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1797
1798 let diff =
1799 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1800 .await
1801 .with_context(|| {
1802 format!("Failed to format buffer via external command: {}", command)
1803 })?;
1804 let Some(diff) = diff else {
1805 zlog::trace!(logger => "No changes");
1806 return Ok(());
1807 };
1808
1809 extend_formatting_transaction(
1810 buffer,
1811 formatting_transaction_id,
1812 cx,
1813 |buffer, cx| {
1814 buffer.apply_diff(diff, cx);
1815 },
1816 )?;
1817 }
1818 Formatter::LanguageServer(specifier) => {
1819 let logger = zlog::scoped!(logger => "language-server");
1820 zlog::trace!(logger => "formatting");
1821 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1822
1823 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1824 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1825 return Ok(());
1826 };
1827
1828 let language_server = match specifier {
1829 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1830 adapters_and_servers.iter().find_map(|(adapter, server)| {
1831 if adapter.name.0.as_ref() == name {
1832 Some(server.clone())
1833 } else {
1834 None
1835 }
1836 })
1837 }
1838 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1839 .iter()
1840 .find(|(_, server)| Self::server_supports_formatting(server))
1841 .map(|(_, server)| server.clone()),
1842 };
1843
1844 let Some(language_server) = language_server else {
1845 log::debug!(
1846 "No language server found to format buffer '{:?}'. Skipping",
1847 buffer_path_abs.as_path().to_string_lossy()
1848 );
1849 return Ok(());
1850 };
1851
1852 zlog::trace!(
1853 logger =>
1854 "Formatting buffer '{:?}' using language server '{:?}'",
1855 buffer_path_abs.as_path().to_string_lossy(),
1856 language_server.name()
1857 );
1858
1859 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1860 zlog::trace!(logger => "formatting ranges");
1861 Self::format_ranges_via_lsp(
1862 &lsp_store,
1863 &buffer.handle,
1864 ranges,
1865 buffer_path_abs,
1866 &language_server,
1867 &settings,
1868 cx,
1869 )
1870 .await
1871 .context("Failed to format ranges via language server")?
1872 } else {
1873 zlog::trace!(logger => "formatting full");
1874 Self::format_via_lsp(
1875 &lsp_store,
1876 &buffer.handle,
1877 buffer_path_abs,
1878 &language_server,
1879 &settings,
1880 cx,
1881 )
1882 .await
1883 .context("failed to format via language server")?
1884 };
1885
1886 if edits.is_empty() {
1887 zlog::trace!(logger => "No changes");
1888 return Ok(());
1889 }
1890 extend_formatting_transaction(
1891 buffer,
1892 formatting_transaction_id,
1893 cx,
1894 |buffer, cx| {
1895 buffer.edit(edits, None, cx);
1896 },
1897 )?;
1898 }
1899 Formatter::CodeAction(code_action_name) => {
1900 let logger = zlog::scoped!(logger => "code-actions");
1901 zlog::trace!(logger => "formatting");
1902 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1903
1904 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1905 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1906 return Ok(());
1907 };
1908
1909 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1910 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1911
1912 let mut actions_and_servers = Vec::new();
1913
1914 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1915 let actions_result = Self::get_server_code_actions_from_action_kinds(
1916 &lsp_store,
1917 language_server.server_id(),
1918 vec![code_action_kind.clone()],
1919 &buffer.handle,
1920 cx,
1921 )
1922 .await
1923 .with_context(|| {
1924 format!(
1925 "Failed to resolve code action {:?} with language server {}",
1926 code_action_kind,
1927 language_server.name()
1928 )
1929 });
1930 let Ok(actions) = actions_result else {
1931 // note: it may be better to set result to the error and break formatters here
1932 // but for now we try to execute the actions that we can resolve and skip the rest
1933 zlog::error!(
1934 logger =>
1935 "Failed to resolve code action {:?} with language server {}",
1936 code_action_kind,
1937 language_server.name()
1938 );
1939 continue;
1940 };
1941 for action in actions {
1942 actions_and_servers.push((action, index));
1943 }
1944 }
1945
1946 if actions_and_servers.is_empty() {
1947 zlog::warn!(logger => "No code actions were resolved, continuing");
1948 return Ok(());
1949 }
1950
1951 'actions: for (mut action, server_index) in actions_and_servers {
1952 let server = &adapters_and_servers[server_index].1;
1953
1954 let describe_code_action = |action: &CodeAction| {
1955 format!(
1956 "code action '{}' with title \"{}\" on server {}",
1957 action
1958 .lsp_action
1959 .action_kind()
1960 .unwrap_or("unknown".into())
1961 .as_str(),
1962 action.lsp_action.title(),
1963 server.name(),
1964 )
1965 };
1966
1967 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1968
1969 if let Err(err) =
1970 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1971 {
1972 zlog::error!(
1973 logger =>
1974 "Failed to resolve {}. Error: {}",
1975 describe_code_action(&action),
1976 err
1977 );
1978 continue;
1979 }
1980
1981 if let Some(edit) = action.lsp_action.edit().cloned() {
1982 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1983 // but filters out and logs warnings for code actions that require unreasonably
1984 // difficult handling on our part, such as:
1985 // - applying edits that call commands
1986 // which can result in arbitrary workspace edits being sent from the server that
1987 // have no way of being tied back to the command that initiated them (i.e. we
1988 // can't know which edits are part of the format request, or if the server is done sending
1989 // actions in response to the command)
1990 // - actions that create/delete/modify/rename files other than the one we are formatting
1991 // as we then would need to handle such changes correctly in the local history as well
1992 // as the remote history through the ProjectTransaction
1993 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1994 // Supporting these actions is not impossible, but not supported as of yet.
1995 if edit.changes.is_none() && edit.document_changes.is_none() {
1996 zlog::trace!(
1997 logger =>
1998 "No changes for code action. Skipping {}",
1999 describe_code_action(&action),
2000 );
2001 continue;
2002 }
2003
2004 let mut operations = Vec::new();
2005 if let Some(document_changes) = edit.document_changes {
2006 match document_changes {
2007 lsp::DocumentChanges::Edits(edits) => operations.extend(
2008 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
2009 ),
2010 lsp::DocumentChanges::Operations(ops) => operations = ops,
2011 }
2012 } else if let Some(changes) = edit.changes {
2013 operations.extend(changes.into_iter().map(|(uri, edits)| {
2014 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2015 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2016 uri,
2017 version: None,
2018 },
2019 edits: edits.into_iter().map(Edit::Plain).collect(),
2020 })
2021 }));
2022 }
2023
2024 let mut edits = Vec::with_capacity(operations.len());
2025
2026 if operations.is_empty() {
2027 zlog::trace!(
2028 logger =>
2029 "No changes for code action. Skipping {}",
2030 describe_code_action(&action),
2031 );
2032 continue;
2033 }
2034 for operation in operations {
2035 let op = match operation {
2036 lsp::DocumentChangeOperation::Edit(op) => op,
2037 lsp::DocumentChangeOperation::Op(_) => {
2038 zlog::warn!(
2039 logger =>
2040 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
2041 describe_code_action(&action),
2042 );
2043 continue 'actions;
2044 }
2045 };
2046 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2047 zlog::warn!(
2048 logger =>
2049 "Failed to convert URI '{:?}' to file path. Skipping {}",
2050 &op.text_document.uri,
2051 describe_code_action(&action),
2052 );
2053 continue 'actions;
2054 };
2055 if &file_path != buffer_path_abs {
2056 zlog::warn!(
2057 logger =>
2058 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2059 file_path,
2060 buffer_path_abs,
2061 describe_code_action(&action),
2062 );
2063 continue 'actions;
2064 }
2065
2066 let mut lsp_edits = Vec::new();
2067 for edit in op.edits {
2068 match edit {
2069 Edit::Plain(edit) => {
2070 if !lsp_edits.contains(&edit) {
2071 lsp_edits.push(edit);
2072 }
2073 }
2074 Edit::Annotated(edit) => {
2075 if !lsp_edits.contains(&edit.text_edit) {
2076 lsp_edits.push(edit.text_edit);
2077 }
2078 }
2079 Edit::Snippet(_) => {
2080 zlog::warn!(
2081 logger =>
2082 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2083 describe_code_action(&action),
2084 );
2085 continue 'actions;
2086 }
2087 }
2088 }
2089 let edits_result = lsp_store
2090 .update(cx, |lsp_store, cx| {
2091 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2092 &buffer.handle,
2093 lsp_edits,
2094 server.server_id(),
2095 op.text_document.version,
2096 cx,
2097 )
2098 })?
2099 .await;
2100 let Ok(resolved_edits) = edits_result else {
2101 zlog::warn!(
2102 logger =>
2103 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2104 buffer_path_abs.as_path(),
2105 describe_code_action(&action),
2106 );
2107 continue 'actions;
2108 };
2109 edits.extend(resolved_edits);
2110 }
2111
2112 if edits.is_empty() {
2113 zlog::warn!(logger => "No edits resolved from LSP");
2114 continue;
2115 }
2116
2117 extend_formatting_transaction(
2118 buffer,
2119 formatting_transaction_id,
2120 cx,
2121 |buffer, cx| {
2122 zlog::info!(
2123 "Applying edits {edits:?}. Content: {:?}",
2124 buffer.text()
2125 );
2126 buffer.edit(edits, None, cx);
2127 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2128 },
2129 )?;
2130 }
2131
2132 let Some(command) = action.lsp_action.command() else {
2133 continue;
2134 };
2135
2136 zlog::warn!(
2137 logger =>
2138 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2139 &command.command,
2140 );
2141
2142 let server_capabilities = server.capabilities();
2143 let available_commands = server_capabilities
2144 .execute_command_provider
2145 .as_ref()
2146 .map(|options| options.commands.as_slice())
2147 .unwrap_or_default();
2148 if !available_commands.contains(&command.command) {
2149 zlog::warn!(
2150 logger =>
2151 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2152 command.command,
2153 server.name(),
2154 );
2155 continue;
2156 }
2157
2158 extend_formatting_transaction(
2159 buffer,
2160 formatting_transaction_id,
2161 cx,
2162 |_, _| {},
2163 )?;
2164 zlog::info!(logger => "Executing command {}", &command.command);
2165
2166 lsp_store.update(cx, |this, _| {
2167 this.as_local_mut()
2168 .unwrap()
2169 .last_workspace_edits_by_language_server
2170 .remove(&server.server_id());
2171 })?;
2172
2173 let execute_command_result = server
2174 .request::<lsp::request::ExecuteCommand>(
2175 lsp::ExecuteCommandParams {
2176 command: command.command.clone(),
2177 arguments: command.arguments.clone().unwrap_or_default(),
2178 ..Default::default()
2179 },
2180 request_timeout,
2181 )
2182 .await
2183 .into_response();
2184
2185 if execute_command_result.is_err() {
2186 zlog::error!(
2187 logger =>
2188 "Failed to execute command '{}' as part of {}",
2189 &command.command,
2190 describe_code_action(&action),
2191 );
2192 continue 'actions;
2193 }
2194
2195 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2196 this.as_local_mut()
2197 .unwrap()
2198 .last_workspace_edits_by_language_server
2199 .remove(&server.server_id())
2200 .unwrap_or_default()
2201 })?;
2202
2203 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2204 {
2205 zlog::trace!(
2206 logger =>
2207 "Successfully captured {} edits that resulted from command {}",
2208 transaction.edit_ids.len(),
2209 &command.command,
2210 );
2211 let transaction_id_project_transaction = transaction.id;
2212 buffer.handle.update(cx, |buffer, _| {
2213 // it may have been removed from history if push_to_history was
2214 // false in deserialize_workspace_edit. If so push it so we
2215 // can merge it with the format transaction
2216 // and pop the combined transaction off the history stack
2217 // later if push_to_history is false
2218 if buffer.get_transaction(transaction.id).is_none() {
2219 buffer.push_transaction(transaction, Instant::now());
2220 }
2221 buffer.merge_transactions(
2222 transaction_id_project_transaction,
2223 formatting_transaction_id,
2224 );
2225 });
2226 }
2227
2228 if project_transaction_command.0.is_empty() {
2229 continue;
2230 }
2231
2232 let mut extra_buffers = String::new();
2233 for buffer in project_transaction_command.0.keys() {
2234 buffer.read_with(cx, |b, cx| {
2235 let Some(path) = b.project_path(cx) else {
2236 return;
2237 };
2238
2239 if !extra_buffers.is_empty() {
2240 extra_buffers.push_str(", ");
2241 }
2242 extra_buffers.push_str(path.path.as_unix_str());
2243 });
2244 }
2245 zlog::warn!(
2246 logger =>
2247 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2248 &command.command,
2249 extra_buffers,
2250 );
2251 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2252 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2253 // add it so it's included, and merge it into the format transaction when its created later
2254 }
2255 }
2256 }
2257
2258 Ok(())
2259 }
2260
2261 pub async fn format_ranges_via_lsp(
2262 this: &WeakEntity<LspStore>,
2263 buffer_handle: &Entity<Buffer>,
2264 ranges: &[Range<Anchor>],
2265 abs_path: &Path,
2266 language_server: &Arc<LanguageServer>,
2267 settings: &LanguageSettings,
2268 cx: &mut AsyncApp,
2269 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2270 let capabilities = &language_server.capabilities();
2271 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2272 if range_formatting_provider == Some(&OneOf::Left(false)) {
2273 anyhow::bail!(
2274 "{} language server does not support range formatting",
2275 language_server.name()
2276 );
2277 }
2278
2279 let uri = file_path_to_lsp_url(abs_path)?;
2280 let text_document = lsp::TextDocumentIdentifier::new(uri);
2281
2282 let request_timeout = cx.update(|app| {
2283 ProjectSettings::get_global(app)
2284 .global_lsp_settings
2285 .get_request_timeout()
2286 });
2287 let lsp_edits = {
2288 let mut lsp_ranges = Vec::new();
2289 this.update(cx, |_this, cx| {
2290 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2291 // not have been sent to the language server. This seems like a fairly systemic
2292 // issue, though, the resolution probably is not specific to formatting.
2293 //
2294 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2295 // LSP.
2296 let snapshot = buffer_handle.read(cx).snapshot();
2297 for range in ranges {
2298 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2299 }
2300 anyhow::Ok(())
2301 })??;
2302
2303 let mut edits = None;
2304 for range in lsp_ranges {
2305 if let Some(mut edit) = language_server
2306 .request::<lsp::request::RangeFormatting>(
2307 lsp::DocumentRangeFormattingParams {
2308 text_document: text_document.clone(),
2309 range,
2310 options: lsp_command::lsp_formatting_options(settings),
2311 work_done_progress_params: Default::default(),
2312 },
2313 request_timeout,
2314 )
2315 .await
2316 .into_response()?
2317 {
2318 edits.get_or_insert_with(Vec::new).append(&mut edit);
2319 }
2320 }
2321 edits
2322 };
2323
2324 if let Some(lsp_edits) = lsp_edits {
2325 this.update(cx, |this, cx| {
2326 this.as_local_mut().unwrap().edits_from_lsp(
2327 buffer_handle,
2328 lsp_edits,
2329 language_server.server_id(),
2330 None,
2331 cx,
2332 )
2333 })?
2334 .await
2335 } else {
2336 Ok(Vec::with_capacity(0))
2337 }
2338 }
2339
2340 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2341 let capabilities = server.capabilities();
2342 let formatting = capabilities.document_formatting_provider.as_ref();
2343 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2344 || server_capabilities_support_range_formatting(&capabilities)
2345 }
2346
2347 async fn format_via_lsp(
2348 this: &WeakEntity<LspStore>,
2349 buffer: &Entity<Buffer>,
2350 abs_path: &Path,
2351 language_server: &Arc<LanguageServer>,
2352 settings: &LanguageSettings,
2353 cx: &mut AsyncApp,
2354 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2355 let logger = zlog::scoped!("lsp_format");
2356 zlog::debug!(logger => "Formatting via LSP");
2357
2358 let uri = file_path_to_lsp_url(abs_path)?;
2359 let text_document = lsp::TextDocumentIdentifier::new(uri);
2360 let capabilities = &language_server.capabilities();
2361
2362 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2363 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2364
2365 let request_timeout = cx.update(|app| {
2366 ProjectSettings::get_global(app)
2367 .global_lsp_settings
2368 .get_request_timeout()
2369 });
2370
2371 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2372 let _timer = zlog::time!(logger => "format-full");
2373 language_server
2374 .request::<lsp::request::Formatting>(
2375 lsp::DocumentFormattingParams {
2376 text_document,
2377 options: lsp_command::lsp_formatting_options(settings),
2378 work_done_progress_params: Default::default(),
2379 },
2380 request_timeout,
2381 )
2382 .await
2383 .into_response()?
2384 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2385 let _timer = zlog::time!(logger => "format-range");
2386 let buffer_start = lsp::Position::new(0, 0);
2387 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2388 language_server
2389 .request::<lsp::request::RangeFormatting>(
2390 lsp::DocumentRangeFormattingParams {
2391 text_document: text_document.clone(),
2392 range: lsp::Range::new(buffer_start, buffer_end),
2393 options: lsp_command::lsp_formatting_options(settings),
2394 work_done_progress_params: Default::default(),
2395 },
2396 request_timeout,
2397 )
2398 .await
2399 .into_response()?
2400 } else {
2401 None
2402 };
2403
2404 if let Some(lsp_edits) = lsp_edits {
2405 this.update(cx, |this, cx| {
2406 this.as_local_mut().unwrap().edits_from_lsp(
2407 buffer,
2408 lsp_edits,
2409 language_server.server_id(),
2410 None,
2411 cx,
2412 )
2413 })?
2414 .await
2415 } else {
2416 Ok(Vec::with_capacity(0))
2417 }
2418 }
2419
2420 async fn format_via_external_command(
2421 buffer: &FormattableBuffer,
2422 command: &str,
2423 arguments: Option<&[String]>,
2424 cx: &mut AsyncApp,
2425 ) -> Result<Option<Diff>> {
2426 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2427 let file = File::from_dyn(buffer.file())?;
2428 let worktree = file.worktree.read(cx);
2429 let mut worktree_path = worktree.abs_path().to_path_buf();
2430 if worktree.root_entry()?.is_file() {
2431 worktree_path.pop();
2432 }
2433 Some(worktree_path)
2434 });
2435
2436 use util::command::Stdio;
2437 let mut child = util::command::new_command(command);
2438
2439 if let Some(buffer_env) = buffer.env.as_ref() {
2440 child.envs(buffer_env);
2441 }
2442
2443 if let Some(working_dir_path) = working_dir_path {
2444 child.current_dir(working_dir_path);
2445 }
2446
2447 if let Some(arguments) = arguments {
2448 child.args(arguments.iter().map(|arg| {
2449 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2450 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2451 } else {
2452 arg.replace("{buffer_path}", "Untitled")
2453 }
2454 }));
2455 }
2456
2457 let mut child = child
2458 .stdin(Stdio::piped())
2459 .stdout(Stdio::piped())
2460 .stderr(Stdio::piped())
2461 .spawn()?;
2462
2463 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2464 let text = buffer
2465 .handle
2466 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2467 for chunk in text.chunks() {
2468 stdin.write_all(chunk.as_bytes()).await?;
2469 }
2470 stdin.flush().await?;
2471
2472 let output = child.output().await?;
2473 anyhow::ensure!(
2474 output.status.success(),
2475 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2476 output.status.code(),
2477 String::from_utf8_lossy(&output.stdout),
2478 String::from_utf8_lossy(&output.stderr),
2479 );
2480
2481 let stdout = String::from_utf8(output.stdout)?;
2482 Ok(Some(
2483 buffer
2484 .handle
2485 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2486 .await,
2487 ))
2488 }
2489
2490 async fn try_resolve_code_action(
2491 lang_server: &LanguageServer,
2492 action: &mut CodeAction,
2493 request_timeout: Duration,
2494 ) -> anyhow::Result<()> {
2495 match &mut action.lsp_action {
2496 LspAction::Action(lsp_action) => {
2497 if !action.resolved
2498 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2499 && lsp_action.data.is_some()
2500 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2501 {
2502 **lsp_action = lang_server
2503 .request::<lsp::request::CodeActionResolveRequest>(
2504 *lsp_action.clone(),
2505 request_timeout,
2506 )
2507 .await
2508 .into_response()?;
2509 }
2510 }
2511 LspAction::CodeLens(lens) => {
2512 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2513 *lens = lang_server
2514 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2515 .await
2516 .into_response()?;
2517 }
2518 }
2519 LspAction::Command(_) => {}
2520 }
2521
2522 action.resolved = true;
2523 anyhow::Ok(())
2524 }
2525
2526 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2527 let buffer = buffer_handle.read(cx);
2528
2529 let file = buffer.file().cloned();
2530
2531 let Some(file) = File::from_dyn(file.as_ref()) else {
2532 return;
2533 };
2534 if !file.is_local() {
2535 return;
2536 }
2537 let path = ProjectPath::from_file(file, cx);
2538 let worktree_id = file.worktree_id(cx);
2539 let language = buffer.language().cloned();
2540
2541 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2542 for (server_id, diagnostics) in
2543 diagnostics.get(file.path()).cloned().unwrap_or_default()
2544 {
2545 self.update_buffer_diagnostics(
2546 buffer_handle,
2547 server_id,
2548 None,
2549 None,
2550 None,
2551 Vec::new(),
2552 diagnostics,
2553 cx,
2554 )
2555 .log_err();
2556 }
2557 }
2558 let Some(language) = language else {
2559 return;
2560 };
2561 let Some(snapshot) = self
2562 .worktree_store
2563 .read(cx)
2564 .worktree_for_id(worktree_id, cx)
2565 .map(|worktree| worktree.read(cx).snapshot())
2566 else {
2567 return;
2568 };
2569 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2570
2571 for server_id in
2572 self.lsp_tree
2573 .get(path, language.name(), language.manifest(), &delegate, cx)
2574 {
2575 let server = self
2576 .language_servers
2577 .get(&server_id)
2578 .and_then(|server_state| {
2579 if let LanguageServerState::Running { server, .. } = server_state {
2580 Some(server.clone())
2581 } else {
2582 None
2583 }
2584 });
2585 let server = match server {
2586 Some(server) => server,
2587 None => continue,
2588 };
2589
2590 buffer_handle.update(cx, |buffer, cx| {
2591 buffer.set_completion_triggers(
2592 server.server_id(),
2593 server
2594 .capabilities()
2595 .completion_provider
2596 .as_ref()
2597 .and_then(|provider| {
2598 provider
2599 .trigger_characters
2600 .as_ref()
2601 .map(|characters| characters.iter().cloned().collect())
2602 })
2603 .unwrap_or_default(),
2604 cx,
2605 );
2606 });
2607 }
2608 }
2609
2610 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2611 buffer.update(cx, |buffer, cx| {
2612 let Some(language) = buffer.language() else {
2613 return;
2614 };
2615 let path = ProjectPath {
2616 worktree_id: old_file.worktree_id(cx),
2617 path: old_file.path.clone(),
2618 };
2619 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2620 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2621 buffer.set_completion_triggers(server_id, Default::default(), cx);
2622 }
2623 });
2624 }
2625
2626 fn update_buffer_diagnostics(
2627 &mut self,
2628 buffer: &Entity<Buffer>,
2629 server_id: LanguageServerId,
2630 registration_id: Option<Option<SharedString>>,
2631 result_id: Option<SharedString>,
2632 version: Option<i32>,
2633 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2634 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2635 cx: &mut Context<LspStore>,
2636 ) -> Result<()> {
2637 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2638 Ordering::Equal
2639 .then_with(|| b.is_primary.cmp(&a.is_primary))
2640 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2641 .then_with(|| a.severity.cmp(&b.severity))
2642 .then_with(|| a.message.cmp(&b.message))
2643 }
2644
2645 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2646 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2647 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2648
2649 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2650 Ordering::Equal
2651 .then_with(|| a.range.start.cmp(&b.range.start))
2652 .then_with(|| b.range.end.cmp(&a.range.end))
2653 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2654 });
2655
2656 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2657
2658 let edits_since_save = std::cell::LazyCell::new(|| {
2659 let saved_version = buffer.read(cx).saved_version();
2660 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2661 });
2662
2663 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2664
2665 for (new_diagnostic, entry) in diagnostics {
2666 let start;
2667 let end;
2668 if new_diagnostic && entry.diagnostic.is_disk_based {
2669 // Some diagnostics are based on files on disk instead of buffers'
2670 // current contents. Adjust these diagnostics' ranges to reflect
2671 // any unsaved edits.
2672 // Do not alter the reused ones though, as their coordinates were stored as anchors
2673 // and were properly adjusted on reuse.
2674 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2675 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2676 } else {
2677 start = entry.range.start;
2678 end = entry.range.end;
2679 }
2680
2681 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2682 ..snapshot.clip_point_utf16(end, Bias::Right);
2683
2684 // Expand empty ranges by one codepoint
2685 if range.start == range.end {
2686 // This will be go to the next boundary when being clipped
2687 range.end.column += 1;
2688 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2689 if range.start == range.end && range.end.column > 0 {
2690 range.start.column -= 1;
2691 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2692 }
2693 }
2694
2695 sanitized_diagnostics.push(DiagnosticEntry {
2696 range,
2697 diagnostic: entry.diagnostic,
2698 });
2699 }
2700 drop(edits_since_save);
2701
2702 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2703 buffer.update(cx, |buffer, cx| {
2704 if let Some(registration_id) = registration_id {
2705 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2706 self.buffer_pull_diagnostics_result_ids
2707 .entry(server_id)
2708 .or_default()
2709 .entry(registration_id)
2710 .or_default()
2711 .insert(abs_path, result_id);
2712 }
2713 }
2714
2715 buffer.update_diagnostics(server_id, set, cx)
2716 });
2717
2718 Ok(())
2719 }
2720
2721 fn register_language_server_for_invisible_worktree(
2722 &mut self,
2723 worktree: &Entity<Worktree>,
2724 language_server_id: LanguageServerId,
2725 cx: &mut App,
2726 ) {
2727 let worktree = worktree.read(cx);
2728 let worktree_id = worktree.id();
2729 debug_assert!(!worktree.is_visible());
2730 let Some(mut origin_seed) = self
2731 .language_server_ids
2732 .iter()
2733 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2734 else {
2735 return;
2736 };
2737 origin_seed.worktree_id = worktree_id;
2738 self.language_server_ids
2739 .entry(origin_seed)
2740 .or_insert_with(|| UnifiedLanguageServer {
2741 id: language_server_id,
2742 project_roots: Default::default(),
2743 });
2744 }
2745
2746 fn register_buffer_with_language_servers(
2747 &mut self,
2748 buffer_handle: &Entity<Buffer>,
2749 only_register_servers: HashSet<LanguageServerSelector>,
2750 cx: &mut Context<LspStore>,
2751 ) {
2752 let buffer = buffer_handle.read(cx);
2753 let buffer_id = buffer.remote_id();
2754
2755 let Some(file) = File::from_dyn(buffer.file()) else {
2756 return;
2757 };
2758 if !file.is_local() {
2759 return;
2760 }
2761
2762 let abs_path = file.abs_path(cx);
2763 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2764 return;
2765 };
2766 let initial_snapshot = buffer.text_snapshot();
2767 let worktree_id = file.worktree_id(cx);
2768
2769 let Some(language) = buffer.language().cloned() else {
2770 return;
2771 };
2772 let path: Arc<RelPath> = file
2773 .path()
2774 .parent()
2775 .map(Arc::from)
2776 .unwrap_or_else(|| file.path().clone());
2777 let Some(worktree) = self
2778 .worktree_store
2779 .read(cx)
2780 .worktree_for_id(worktree_id, cx)
2781 else {
2782 return;
2783 };
2784 let language_name = language.name();
2785 let (reused, delegate, servers) = self
2786 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2787 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2788 .unwrap_or_else(|| {
2789 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2790 let delegate: Arc<dyn ManifestDelegate> =
2791 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2792
2793 let servers = self
2794 .lsp_tree
2795 .walk(
2796 ProjectPath { worktree_id, path },
2797 language.name(),
2798 language.manifest(),
2799 &delegate,
2800 cx,
2801 )
2802 .collect::<Vec<_>>();
2803 (false, lsp_delegate, servers)
2804 });
2805 let servers_and_adapters = servers
2806 .into_iter()
2807 .filter_map(|server_node| {
2808 if reused && server_node.server_id().is_none() {
2809 return None;
2810 }
2811 if !only_register_servers.is_empty() {
2812 if let Some(server_id) = server_node.server_id()
2813 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2814 {
2815 return None;
2816 }
2817 if let Some(name) = server_node.name()
2818 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2819 {
2820 return None;
2821 }
2822 }
2823
2824 let server_id = server_node.server_id_or_init(|disposition| {
2825 let path = &disposition.path;
2826
2827 {
2828 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2829
2830 let server_id = self.get_or_insert_language_server(
2831 &worktree,
2832 delegate.clone(),
2833 disposition,
2834 &language_name,
2835 cx,
2836 );
2837
2838 if let Some(state) = self.language_servers.get(&server_id)
2839 && let Ok(uri) = uri
2840 {
2841 state.add_workspace_folder(uri);
2842 };
2843 server_id
2844 }
2845 })?;
2846 let server_state = self.language_servers.get(&server_id)?;
2847 if let LanguageServerState::Running {
2848 server, adapter, ..
2849 } = server_state
2850 {
2851 Some((server.clone(), adapter.clone()))
2852 } else {
2853 None
2854 }
2855 })
2856 .collect::<Vec<_>>();
2857 for (server, adapter) in servers_and_adapters {
2858 buffer_handle.update(cx, |buffer, cx| {
2859 buffer.set_completion_triggers(
2860 server.server_id(),
2861 server
2862 .capabilities()
2863 .completion_provider
2864 .as_ref()
2865 .and_then(|provider| {
2866 provider
2867 .trigger_characters
2868 .as_ref()
2869 .map(|characters| characters.iter().cloned().collect())
2870 })
2871 .unwrap_or_default(),
2872 cx,
2873 );
2874 });
2875
2876 let snapshot = LspBufferSnapshot {
2877 version: 0,
2878 snapshot: initial_snapshot.clone(),
2879 };
2880
2881 let mut registered = false;
2882 self.buffer_snapshots
2883 .entry(buffer_id)
2884 .or_default()
2885 .entry(server.server_id())
2886 .or_insert_with(|| {
2887 registered = true;
2888 server.register_buffer(
2889 uri.clone(),
2890 adapter.language_id(&language.name()),
2891 0,
2892 initial_snapshot.text(),
2893 );
2894
2895 vec![snapshot]
2896 });
2897
2898 self.buffers_opened_in_servers
2899 .entry(buffer_id)
2900 .or_default()
2901 .insert(server.server_id());
2902 if registered {
2903 cx.emit(LspStoreEvent::LanguageServerUpdate {
2904 language_server_id: server.server_id(),
2905 name: None,
2906 message: proto::update_language_server::Variant::RegisteredForBuffer(
2907 proto::RegisteredForBuffer {
2908 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2909 buffer_id: buffer_id.to_proto(),
2910 },
2911 ),
2912 });
2913 }
2914 }
2915 }
2916
2917 fn reuse_existing_language_server<'lang_name>(
2918 &self,
2919 server_tree: &LanguageServerTree,
2920 worktree: &Entity<Worktree>,
2921 language_name: &'lang_name LanguageName,
2922 cx: &mut App,
2923 ) -> Option<(
2924 Arc<LocalLspAdapterDelegate>,
2925 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2926 )> {
2927 if worktree.read(cx).is_visible() {
2928 return None;
2929 }
2930
2931 let worktree_store = self.worktree_store.read(cx);
2932 let servers = server_tree
2933 .instances
2934 .iter()
2935 .filter(|(worktree_id, _)| {
2936 worktree_store
2937 .worktree_for_id(**worktree_id, cx)
2938 .is_some_and(|worktree| worktree.read(cx).is_visible())
2939 })
2940 .flat_map(|(worktree_id, servers)| {
2941 servers
2942 .roots
2943 .iter()
2944 .flat_map(|(_, language_servers)| language_servers)
2945 .map(move |(_, (server_node, server_languages))| {
2946 (worktree_id, server_node, server_languages)
2947 })
2948 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2949 .map(|(worktree_id, server_node, _)| {
2950 (
2951 *worktree_id,
2952 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2953 )
2954 })
2955 })
2956 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2957 acc.entry(worktree_id)
2958 .or_insert_with(Vec::new)
2959 .push(server_node);
2960 acc
2961 })
2962 .into_values()
2963 .max_by_key(|servers| servers.len())?;
2964
2965 let worktree_id = worktree.read(cx).id();
2966 let apply = move |tree: &mut LanguageServerTree| {
2967 for server_node in &servers {
2968 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2969 }
2970 servers
2971 };
2972
2973 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2974 Some((delegate, apply))
2975 }
2976
2977 pub(crate) fn unregister_old_buffer_from_language_servers(
2978 &mut self,
2979 buffer: &Entity<Buffer>,
2980 old_file: &File,
2981 cx: &mut App,
2982 ) {
2983 let old_path = match old_file.as_local() {
2984 Some(local) => local.abs_path(cx),
2985 None => return,
2986 };
2987
2988 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2989 debug_panic!("{old_path:?} is not parseable as an URI");
2990 return;
2991 };
2992 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2993 }
2994
2995 pub(crate) fn unregister_buffer_from_language_servers(
2996 &mut self,
2997 buffer: &Entity<Buffer>,
2998 file_url: &lsp::Uri,
2999 cx: &mut App,
3000 ) {
3001 buffer.update(cx, |buffer, cx| {
3002 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
3003
3004 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
3005 if snapshots
3006 .as_mut()
3007 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
3008 {
3009 language_server.unregister_buffer(file_url.clone());
3010 }
3011 }
3012 });
3013 }
3014
3015 fn buffer_snapshot_for_lsp_version(
3016 &mut self,
3017 buffer: &Entity<Buffer>,
3018 server_id: LanguageServerId,
3019 version: Option<i32>,
3020 cx: &App,
3021 ) -> Result<TextBufferSnapshot> {
3022 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
3023
3024 if let Some(version) = version {
3025 let buffer_id = buffer.read(cx).remote_id();
3026 let snapshots = if let Some(snapshots) = self
3027 .buffer_snapshots
3028 .get_mut(&buffer_id)
3029 .and_then(|m| m.get_mut(&server_id))
3030 {
3031 snapshots
3032 } else if version == 0 {
3033 // Some language servers report version 0 even if the buffer hasn't been opened yet.
3034 // We detect this case and treat it as if the version was `None`.
3035 return Ok(buffer.read(cx).text_snapshot());
3036 } else {
3037 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
3038 };
3039
3040 let found_snapshot = snapshots
3041 .binary_search_by_key(&version, |e| e.version)
3042 .map(|ix| snapshots[ix].snapshot.clone())
3043 .map_err(|_| {
3044 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3045 })?;
3046
3047 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3048 Ok(found_snapshot)
3049 } else {
3050 Ok((buffer.read(cx)).text_snapshot())
3051 }
3052 }
3053
3054 async fn get_server_code_actions_from_action_kinds(
3055 lsp_store: &WeakEntity<LspStore>,
3056 language_server_id: LanguageServerId,
3057 code_action_kinds: Vec<lsp::CodeActionKind>,
3058 buffer: &Entity<Buffer>,
3059 cx: &mut AsyncApp,
3060 ) -> Result<Vec<CodeAction>> {
3061 let actions = lsp_store
3062 .update(cx, move |this, cx| {
3063 let request = GetCodeActions {
3064 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3065 kinds: Some(code_action_kinds),
3066 };
3067 let server = LanguageServerToQuery::Other(language_server_id);
3068 this.request_lsp(buffer.clone(), server, request, cx)
3069 })?
3070 .await?;
3071 Ok(actions)
3072 }
3073
3074 pub async fn execute_code_actions_on_server(
3075 lsp_store: &WeakEntity<LspStore>,
3076 language_server: &Arc<LanguageServer>,
3077 actions: Vec<CodeAction>,
3078 push_to_history: bool,
3079 project_transaction: &mut ProjectTransaction,
3080 cx: &mut AsyncApp,
3081 ) -> anyhow::Result<()> {
3082 let request_timeout = cx.update(|app| {
3083 ProjectSettings::get_global(app)
3084 .global_lsp_settings
3085 .get_request_timeout()
3086 });
3087
3088 for mut action in actions {
3089 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3090 .await
3091 .context("resolving a formatting code action")?;
3092
3093 if let Some(edit) = action.lsp_action.edit() {
3094 if edit.changes.is_none() && edit.document_changes.is_none() {
3095 continue;
3096 }
3097
3098 let new = Self::deserialize_workspace_edit(
3099 lsp_store.upgrade().context("project dropped")?,
3100 edit.clone(),
3101 push_to_history,
3102 language_server.clone(),
3103 cx,
3104 )
3105 .await?;
3106 project_transaction.0.extend(new.0);
3107 }
3108
3109 let Some(command) = action.lsp_action.command() else {
3110 continue;
3111 };
3112
3113 let server_capabilities = language_server.capabilities();
3114 let available_commands = server_capabilities
3115 .execute_command_provider
3116 .as_ref()
3117 .map(|options| options.commands.as_slice())
3118 .unwrap_or_default();
3119 if !available_commands.contains(&command.command) {
3120 log::warn!(
3121 "Cannot execute a command {} not listed in the language server capabilities",
3122 command.command
3123 );
3124 continue;
3125 }
3126
3127 lsp_store.update(cx, |lsp_store, _| {
3128 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3129 mode.last_workspace_edits_by_language_server
3130 .remove(&language_server.server_id());
3131 }
3132 })?;
3133
3134 language_server
3135 .request::<lsp::request::ExecuteCommand>(
3136 lsp::ExecuteCommandParams {
3137 command: command.command.clone(),
3138 arguments: command.arguments.clone().unwrap_or_default(),
3139 ..Default::default()
3140 },
3141 request_timeout,
3142 )
3143 .await
3144 .into_response()
3145 .context("execute command")?;
3146
3147 lsp_store.update(cx, |this, _| {
3148 if let LspStoreMode::Local(mode) = &mut this.mode {
3149 project_transaction.0.extend(
3150 mode.last_workspace_edits_by_language_server
3151 .remove(&language_server.server_id())
3152 .unwrap_or_default()
3153 .0,
3154 )
3155 }
3156 })?;
3157 }
3158 Ok(())
3159 }
3160
3161 pub async fn deserialize_text_edits(
3162 this: Entity<LspStore>,
3163 buffer_to_edit: Entity<Buffer>,
3164 edits: Vec<lsp::TextEdit>,
3165 push_to_history: bool,
3166 _: Arc<CachedLspAdapter>,
3167 language_server: Arc<LanguageServer>,
3168 cx: &mut AsyncApp,
3169 ) -> Result<Option<Transaction>> {
3170 let edits = this
3171 .update(cx, |this, cx| {
3172 this.as_local_mut().unwrap().edits_from_lsp(
3173 &buffer_to_edit,
3174 edits,
3175 language_server.server_id(),
3176 None,
3177 cx,
3178 )
3179 })
3180 .await?;
3181
3182 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3183 buffer.finalize_last_transaction();
3184 buffer.start_transaction();
3185 for (range, text) in edits {
3186 buffer.edit([(range, text)], None, cx);
3187 }
3188
3189 if buffer.end_transaction(cx).is_some() {
3190 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3191 if !push_to_history {
3192 buffer.forget_transaction(transaction.id);
3193 }
3194 Some(transaction)
3195 } else {
3196 None
3197 }
3198 });
3199
3200 Ok(transaction)
3201 }
3202
3203 #[allow(clippy::type_complexity)]
3204 pub fn edits_from_lsp(
3205 &mut self,
3206 buffer: &Entity<Buffer>,
3207 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3208 server_id: LanguageServerId,
3209 version: Option<i32>,
3210 cx: &mut Context<LspStore>,
3211 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3212 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3213 cx.background_spawn(async move {
3214 let snapshot = snapshot?;
3215 let mut lsp_edits = lsp_edits
3216 .into_iter()
3217 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3218 .collect::<Vec<_>>();
3219
3220 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3221
3222 let mut lsp_edits = lsp_edits.into_iter().peekable();
3223 let mut edits = Vec::new();
3224 while let Some((range, mut new_text)) = lsp_edits.next() {
3225 // Clip invalid ranges provided by the language server.
3226 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3227 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3228
3229 // Combine any LSP edits that are adjacent.
3230 //
3231 // Also, combine LSP edits that are separated from each other by only
3232 // a newline. This is important because for some code actions,
3233 // Rust-analyzer rewrites the entire buffer via a series of edits that
3234 // are separated by unchanged newline characters.
3235 //
3236 // In order for the diffing logic below to work properly, any edits that
3237 // cancel each other out must be combined into one.
3238 while let Some((next_range, next_text)) = lsp_edits.peek() {
3239 if next_range.start.0 > range.end {
3240 if next_range.start.0.row > range.end.row + 1
3241 || next_range.start.0.column > 0
3242 || snapshot.clip_point_utf16(
3243 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3244 Bias::Left,
3245 ) > range.end
3246 {
3247 break;
3248 }
3249 new_text.push('\n');
3250 }
3251 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3252 new_text.push_str(next_text);
3253 lsp_edits.next();
3254 }
3255
3256 // For multiline edits, perform a diff of the old and new text so that
3257 // we can identify the changes more precisely, preserving the locations
3258 // of any anchors positioned in the unchanged regions.
3259 if range.end.row > range.start.row {
3260 let offset = range.start.to_offset(&snapshot);
3261 let old_text = snapshot.text_for_range(range).collect::<String>();
3262 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3263 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3264 (
3265 snapshot.anchor_after(offset + range.start)
3266 ..snapshot.anchor_before(offset + range.end),
3267 replacement,
3268 )
3269 }));
3270 } else if range.end == range.start {
3271 let anchor = snapshot.anchor_after(range.start);
3272 edits.push((anchor..anchor, new_text.into()));
3273 } else {
3274 let edit_start = snapshot.anchor_after(range.start);
3275 let edit_end = snapshot.anchor_before(range.end);
3276 edits.push((edit_start..edit_end, new_text.into()));
3277 }
3278 }
3279
3280 Ok(edits)
3281 })
3282 }
3283
3284 pub(crate) async fn deserialize_workspace_edit(
3285 this: Entity<LspStore>,
3286 edit: lsp::WorkspaceEdit,
3287 push_to_history: bool,
3288 language_server: Arc<LanguageServer>,
3289 cx: &mut AsyncApp,
3290 ) -> Result<ProjectTransaction> {
3291 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3292
3293 let mut operations = Vec::new();
3294 if let Some(document_changes) = edit.document_changes {
3295 match document_changes {
3296 lsp::DocumentChanges::Edits(edits) => {
3297 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3298 }
3299 lsp::DocumentChanges::Operations(ops) => operations = ops,
3300 }
3301 } else if let Some(changes) = edit.changes {
3302 operations.extend(changes.into_iter().map(|(uri, edits)| {
3303 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3304 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3305 uri,
3306 version: None,
3307 },
3308 edits: edits.into_iter().map(Edit::Plain).collect(),
3309 })
3310 }));
3311 }
3312
3313 let mut project_transaction = ProjectTransaction::default();
3314 for operation in operations {
3315 match operation {
3316 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3317 let abs_path = op
3318 .uri
3319 .to_file_path()
3320 .map_err(|()| anyhow!("can't convert URI to path"))?;
3321
3322 if let Some(parent_path) = abs_path.parent() {
3323 fs.create_dir(parent_path).await?;
3324 }
3325 if abs_path.ends_with("/") {
3326 fs.create_dir(&abs_path).await?;
3327 } else {
3328 fs.create_file(
3329 &abs_path,
3330 op.options
3331 .map(|options| fs::CreateOptions {
3332 overwrite: options.overwrite.unwrap_or(false),
3333 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3334 })
3335 .unwrap_or_default(),
3336 )
3337 .await?;
3338 }
3339 }
3340
3341 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3342 let source_abs_path = op
3343 .old_uri
3344 .to_file_path()
3345 .map_err(|()| anyhow!("can't convert URI to path"))?;
3346 let target_abs_path = op
3347 .new_uri
3348 .to_file_path()
3349 .map_err(|()| anyhow!("can't convert URI to path"))?;
3350
3351 let options = fs::RenameOptions {
3352 overwrite: op
3353 .options
3354 .as_ref()
3355 .and_then(|options| options.overwrite)
3356 .unwrap_or(false),
3357 ignore_if_exists: op
3358 .options
3359 .as_ref()
3360 .and_then(|options| options.ignore_if_exists)
3361 .unwrap_or(false),
3362 create_parents: true,
3363 };
3364
3365 fs.rename(&source_abs_path, &target_abs_path, options)
3366 .await?;
3367 }
3368
3369 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3370 let abs_path = op
3371 .uri
3372 .to_file_path()
3373 .map_err(|()| anyhow!("can't convert URI to path"))?;
3374 let options = op
3375 .options
3376 .map(|options| fs::RemoveOptions {
3377 recursive: options.recursive.unwrap_or(false),
3378 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3379 })
3380 .unwrap_or_default();
3381 if abs_path.ends_with("/") {
3382 fs.remove_dir(&abs_path, options).await?;
3383 } else {
3384 fs.remove_file(&abs_path, options).await?;
3385 }
3386 }
3387
3388 lsp::DocumentChangeOperation::Edit(op) => {
3389 let buffer_to_edit = this
3390 .update(cx, |this, cx| {
3391 this.open_local_buffer_via_lsp(
3392 op.text_document.uri.clone(),
3393 language_server.server_id(),
3394 cx,
3395 )
3396 })
3397 .await?;
3398
3399 let edits = this
3400 .update(cx, |this, cx| {
3401 let path = buffer_to_edit.read(cx).project_path(cx);
3402 let active_entry = this.active_entry;
3403 let is_active_entry = path.is_some_and(|project_path| {
3404 this.worktree_store
3405 .read(cx)
3406 .entry_for_path(&project_path, cx)
3407 .is_some_and(|entry| Some(entry.id) == active_entry)
3408 });
3409 let local = this.as_local_mut().unwrap();
3410
3411 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3412 for edit in op.edits {
3413 match edit {
3414 Edit::Plain(edit) => {
3415 if !edits.contains(&edit) {
3416 edits.push(edit)
3417 }
3418 }
3419 Edit::Annotated(edit) => {
3420 if !edits.contains(&edit.text_edit) {
3421 edits.push(edit.text_edit)
3422 }
3423 }
3424 Edit::Snippet(edit) => {
3425 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3426 else {
3427 continue;
3428 };
3429
3430 if is_active_entry {
3431 snippet_edits.push((edit.range, snippet));
3432 } else {
3433 // Since this buffer is not focused, apply a normal edit.
3434 let new_edit = TextEdit {
3435 range: edit.range,
3436 new_text: snippet.text,
3437 };
3438 if !edits.contains(&new_edit) {
3439 edits.push(new_edit);
3440 }
3441 }
3442 }
3443 }
3444 }
3445 if !snippet_edits.is_empty() {
3446 let buffer_id = buffer_to_edit.read(cx).remote_id();
3447 let version = if let Some(buffer_version) = op.text_document.version
3448 {
3449 local
3450 .buffer_snapshot_for_lsp_version(
3451 &buffer_to_edit,
3452 language_server.server_id(),
3453 Some(buffer_version),
3454 cx,
3455 )
3456 .ok()
3457 .map(|snapshot| snapshot.version)
3458 } else {
3459 Some(buffer_to_edit.read(cx).saved_version().clone())
3460 };
3461
3462 let most_recent_edit =
3463 version.and_then(|version| version.most_recent());
3464 // Check if the edit that triggered that edit has been made by this participant.
3465
3466 if let Some(most_recent_edit) = most_recent_edit {
3467 cx.emit(LspStoreEvent::SnippetEdit {
3468 buffer_id,
3469 edits: snippet_edits,
3470 most_recent_edit,
3471 });
3472 }
3473 }
3474
3475 local.edits_from_lsp(
3476 &buffer_to_edit,
3477 edits,
3478 language_server.server_id(),
3479 op.text_document.version,
3480 cx,
3481 )
3482 })
3483 .await?;
3484
3485 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3486 buffer.finalize_last_transaction();
3487 buffer.start_transaction();
3488 for (range, text) in edits {
3489 buffer.edit([(range, text)], None, cx);
3490 }
3491
3492 buffer.end_transaction(cx).and_then(|transaction_id| {
3493 if push_to_history {
3494 buffer.finalize_last_transaction();
3495 buffer.get_transaction(transaction_id).cloned()
3496 } else {
3497 buffer.forget_transaction(transaction_id)
3498 }
3499 })
3500 });
3501 if let Some(transaction) = transaction {
3502 project_transaction.0.insert(buffer_to_edit, transaction);
3503 }
3504 }
3505 }
3506 }
3507
3508 Ok(project_transaction)
3509 }
3510
3511 async fn on_lsp_workspace_edit(
3512 this: WeakEntity<LspStore>,
3513 params: lsp::ApplyWorkspaceEditParams,
3514 server_id: LanguageServerId,
3515 cx: &mut AsyncApp,
3516 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3517 let this = this.upgrade().context("project project closed")?;
3518 let language_server = this
3519 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3520 .context("language server not found")?;
3521 let transaction = Self::deserialize_workspace_edit(
3522 this.clone(),
3523 params.edit,
3524 true,
3525 language_server.clone(),
3526 cx,
3527 )
3528 .await
3529 .log_err();
3530 this.update(cx, |this, cx| {
3531 if let Some(transaction) = transaction {
3532 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3533
3534 this.as_local_mut()
3535 .unwrap()
3536 .last_workspace_edits_by_language_server
3537 .insert(server_id, transaction);
3538 }
3539 });
3540 Ok(lsp::ApplyWorkspaceEditResponse {
3541 applied: true,
3542 failed_change: None,
3543 failure_reason: None,
3544 })
3545 }
3546
3547 fn remove_worktree(
3548 &mut self,
3549 id_to_remove: WorktreeId,
3550 cx: &mut Context<LspStore>,
3551 ) -> Vec<LanguageServerId> {
3552 self.restricted_worktrees_tasks.remove(&id_to_remove);
3553 self.diagnostics.remove(&id_to_remove);
3554 self.prettier_store.update(cx, |prettier_store, cx| {
3555 prettier_store.remove_worktree(id_to_remove, cx);
3556 });
3557
3558 let mut servers_to_remove = BTreeSet::default();
3559 let mut servers_to_preserve = HashSet::default();
3560 for (seed, state) in &self.language_server_ids {
3561 if seed.worktree_id == id_to_remove {
3562 servers_to_remove.insert(state.id);
3563 } else {
3564 servers_to_preserve.insert(state.id);
3565 }
3566 }
3567 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3568 self.language_server_ids
3569 .retain(|_, state| !servers_to_remove.contains(&state.id));
3570 for server_id_to_remove in &servers_to_remove {
3571 self.language_server_watched_paths
3572 .remove(server_id_to_remove);
3573 self.language_server_paths_watched_for_rename
3574 .remove(server_id_to_remove);
3575 self.last_workspace_edits_by_language_server
3576 .remove(server_id_to_remove);
3577 self.language_servers.remove(server_id_to_remove);
3578 self.buffer_pull_diagnostics_result_ids
3579 .remove(server_id_to_remove);
3580 self.workspace_pull_diagnostics_result_ids
3581 .remove(server_id_to_remove);
3582 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3583 buffer_servers.remove(server_id_to_remove);
3584 }
3585 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3586 }
3587 servers_to_remove.into_iter().collect()
3588 }
3589
3590 fn rebuild_watched_paths_inner<'a>(
3591 &'a self,
3592 language_server_id: LanguageServerId,
3593 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3594 cx: &mut Context<LspStore>,
3595 ) -> LanguageServerWatchedPathsBuilder {
3596 let worktrees = self
3597 .worktree_store
3598 .read(cx)
3599 .worktrees()
3600 .filter_map(|worktree| {
3601 self.language_servers_for_worktree(worktree.read(cx).id())
3602 .find(|server| server.server_id() == language_server_id)
3603 .map(|_| worktree)
3604 })
3605 .collect::<Vec<_>>();
3606
3607 let mut worktree_globs = HashMap::default();
3608 let mut abs_globs = HashMap::default();
3609 log::trace!(
3610 "Processing new watcher paths for language server with id {}",
3611 language_server_id
3612 );
3613
3614 for watcher in watchers {
3615 if let Some((worktree, literal_prefix, pattern)) =
3616 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3617 {
3618 worktree.update(cx, |worktree, _| {
3619 if let Some((tree, glob)) =
3620 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3621 {
3622 tree.add_path_prefix_to_scan(literal_prefix);
3623 worktree_globs
3624 .entry(tree.id())
3625 .or_insert_with(GlobSetBuilder::new)
3626 .add(glob);
3627 }
3628 });
3629 } else {
3630 let (path, pattern) = match &watcher.glob_pattern {
3631 lsp::GlobPattern::String(s) => {
3632 let watcher_path = SanitizedPath::new(s);
3633 let path = glob_literal_prefix(watcher_path.as_path());
3634 let pattern = watcher_path
3635 .as_path()
3636 .strip_prefix(&path)
3637 .map(|p| p.to_string_lossy().into_owned())
3638 .unwrap_or_else(|e| {
3639 debug_panic!(
3640 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3641 s,
3642 path.display(),
3643 e
3644 );
3645 watcher_path.as_path().to_string_lossy().into_owned()
3646 });
3647 (path, pattern)
3648 }
3649 lsp::GlobPattern::Relative(rp) => {
3650 let Ok(mut base_uri) = match &rp.base_uri {
3651 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3652 lsp::OneOf::Right(base_uri) => base_uri,
3653 }
3654 .to_file_path() else {
3655 continue;
3656 };
3657
3658 let path = glob_literal_prefix(Path::new(&rp.pattern));
3659 let pattern = Path::new(&rp.pattern)
3660 .strip_prefix(&path)
3661 .map(|p| p.to_string_lossy().into_owned())
3662 .unwrap_or_else(|e| {
3663 debug_panic!(
3664 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3665 rp.pattern,
3666 path.display(),
3667 e
3668 );
3669 rp.pattern.clone()
3670 });
3671 base_uri.push(path);
3672 (base_uri, pattern)
3673 }
3674 };
3675
3676 if let Some(glob) = Glob::new(&pattern).log_err() {
3677 if !path
3678 .components()
3679 .any(|c| matches!(c, path::Component::Normal(_)))
3680 {
3681 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3682 // rather than adding a new watcher for `/`.
3683 for worktree in &worktrees {
3684 worktree_globs
3685 .entry(worktree.read(cx).id())
3686 .or_insert_with(GlobSetBuilder::new)
3687 .add(glob.clone());
3688 }
3689 } else {
3690 abs_globs
3691 .entry(path.into())
3692 .or_insert_with(GlobSetBuilder::new)
3693 .add(glob);
3694 }
3695 }
3696 }
3697 }
3698
3699 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3700 for (worktree_id, builder) in worktree_globs {
3701 if let Ok(globset) = builder.build() {
3702 watch_builder.watch_worktree(worktree_id, globset);
3703 }
3704 }
3705 for (abs_path, builder) in abs_globs {
3706 if let Ok(globset) = builder.build() {
3707 watch_builder.watch_abs_path(abs_path, globset);
3708 }
3709 }
3710 watch_builder
3711 }
3712
3713 fn worktree_and_path_for_file_watcher(
3714 worktrees: &[Entity<Worktree>],
3715 watcher: &FileSystemWatcher,
3716 cx: &App,
3717 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3718 worktrees.iter().find_map(|worktree| {
3719 let tree = worktree.read(cx);
3720 let worktree_root_path = tree.abs_path();
3721 let path_style = tree.path_style();
3722 match &watcher.glob_pattern {
3723 lsp::GlobPattern::String(s) => {
3724 let watcher_path = SanitizedPath::new(s);
3725 let relative = watcher_path
3726 .as_path()
3727 .strip_prefix(&worktree_root_path)
3728 .ok()?;
3729 let literal_prefix = glob_literal_prefix(relative);
3730 Some((
3731 worktree.clone(),
3732 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3733 relative.to_string_lossy().into_owned(),
3734 ))
3735 }
3736 lsp::GlobPattern::Relative(rp) => {
3737 let base_uri = match &rp.base_uri {
3738 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3739 lsp::OneOf::Right(base_uri) => base_uri,
3740 }
3741 .to_file_path()
3742 .ok()?;
3743 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3744 let mut literal_prefix = relative.to_owned();
3745 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3746 Some((
3747 worktree.clone(),
3748 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3749 rp.pattern.clone(),
3750 ))
3751 }
3752 }
3753 })
3754 }
3755
3756 fn rebuild_watched_paths(
3757 &mut self,
3758 language_server_id: LanguageServerId,
3759 cx: &mut Context<LspStore>,
3760 ) {
3761 let Some(registrations) = self
3762 .language_server_dynamic_registrations
3763 .get(&language_server_id)
3764 else {
3765 return;
3766 };
3767
3768 let watch_builder = self.rebuild_watched_paths_inner(
3769 language_server_id,
3770 registrations.did_change_watched_files.values().flatten(),
3771 cx,
3772 );
3773 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3774 self.language_server_watched_paths
3775 .insert(language_server_id, watcher);
3776
3777 cx.notify();
3778 }
3779
3780 fn on_lsp_did_change_watched_files(
3781 &mut self,
3782 language_server_id: LanguageServerId,
3783 registration_id: &str,
3784 params: DidChangeWatchedFilesRegistrationOptions,
3785 cx: &mut Context<LspStore>,
3786 ) {
3787 let registrations = self
3788 .language_server_dynamic_registrations
3789 .entry(language_server_id)
3790 .or_default();
3791
3792 registrations
3793 .did_change_watched_files
3794 .insert(registration_id.to_string(), params.watchers);
3795
3796 self.rebuild_watched_paths(language_server_id, cx);
3797 }
3798
3799 fn on_lsp_unregister_did_change_watched_files(
3800 &mut self,
3801 language_server_id: LanguageServerId,
3802 registration_id: &str,
3803 cx: &mut Context<LspStore>,
3804 ) {
3805 let registrations = self
3806 .language_server_dynamic_registrations
3807 .entry(language_server_id)
3808 .or_default();
3809
3810 if registrations
3811 .did_change_watched_files
3812 .remove(registration_id)
3813 .is_some()
3814 {
3815 log::info!(
3816 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3817 language_server_id,
3818 registration_id
3819 );
3820 } else {
3821 log::warn!(
3822 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3823 language_server_id,
3824 registration_id
3825 );
3826 }
3827
3828 self.rebuild_watched_paths(language_server_id, cx);
3829 }
3830
3831 async fn initialization_options_for_adapter(
3832 adapter: Arc<dyn LspAdapter>,
3833 delegate: &Arc<dyn LspAdapterDelegate>,
3834 cx: &mut AsyncApp,
3835 ) -> Result<Option<serde_json::Value>> {
3836 let Some(mut initialization_config) =
3837 adapter.clone().initialization_options(delegate, cx).await?
3838 else {
3839 return Ok(None);
3840 };
3841
3842 for other_adapter in delegate.registered_lsp_adapters() {
3843 if other_adapter.name() == adapter.name() {
3844 continue;
3845 }
3846 if let Ok(Some(target_config)) = other_adapter
3847 .clone()
3848 .additional_initialization_options(adapter.name(), delegate)
3849 .await
3850 {
3851 merge_json_value_into(target_config.clone(), &mut initialization_config);
3852 }
3853 }
3854
3855 Ok(Some(initialization_config))
3856 }
3857
3858 async fn workspace_configuration_for_adapter(
3859 adapter: Arc<dyn LspAdapter>,
3860 delegate: &Arc<dyn LspAdapterDelegate>,
3861 toolchain: Option<Toolchain>,
3862 requested_uri: Option<Uri>,
3863 cx: &mut AsyncApp,
3864 ) -> Result<serde_json::Value> {
3865 let mut workspace_config = adapter
3866 .clone()
3867 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3868 .await?;
3869
3870 for other_adapter in delegate.registered_lsp_adapters() {
3871 if other_adapter.name() == adapter.name() {
3872 continue;
3873 }
3874 if let Ok(Some(target_config)) = other_adapter
3875 .clone()
3876 .additional_workspace_configuration(adapter.name(), delegate, cx)
3877 .await
3878 {
3879 merge_json_value_into(target_config.clone(), &mut workspace_config);
3880 }
3881 }
3882
3883 Ok(workspace_config)
3884 }
3885
3886 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3887 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3888 Some(server.clone())
3889 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3890 Some(Arc::clone(server))
3891 } else {
3892 None
3893 }
3894 }
3895}
3896
3897fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3898 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3899 cx.emit(LspStoreEvent::LanguageServerUpdate {
3900 language_server_id: server.server_id(),
3901 name: Some(server.name()),
3902 message: proto::update_language_server::Variant::MetadataUpdated(
3903 proto::ServerMetadataUpdated {
3904 capabilities: Some(capabilities),
3905 binary: Some(proto::LanguageServerBinaryInfo {
3906 path: server.binary().path.to_string_lossy().into_owned(),
3907 arguments: server
3908 .binary()
3909 .arguments
3910 .iter()
3911 .map(|arg| arg.to_string_lossy().into_owned())
3912 .collect(),
3913 }),
3914 configuration: serde_json::to_string(server.configuration()).ok(),
3915 workspace_folders: server
3916 .workspace_folders()
3917 .iter()
3918 .map(|uri| uri.to_string())
3919 .collect(),
3920 },
3921 ),
3922 });
3923 }
3924}
3925
3926#[derive(Debug)]
3927pub struct FormattableBuffer {
3928 handle: Entity<Buffer>,
3929 abs_path: Option<PathBuf>,
3930 env: Option<HashMap<String, String>>,
3931 ranges: Option<Vec<Range<Anchor>>>,
3932}
3933
3934pub struct RemoteLspStore {
3935 upstream_client: Option<AnyProtoClient>,
3936 upstream_project_id: u64,
3937}
3938
3939pub(crate) enum LspStoreMode {
3940 Local(LocalLspStore), // ssh host and collab host
3941 Remote(RemoteLspStore), // collab guest
3942}
3943
3944impl LspStoreMode {
3945 fn is_local(&self) -> bool {
3946 matches!(self, LspStoreMode::Local(_))
3947 }
3948}
3949
3950pub struct LspStore {
3951 mode: LspStoreMode,
3952 last_formatting_failure: Option<String>,
3953 downstream_client: Option<(AnyProtoClient, u64)>,
3954 nonce: u128,
3955 buffer_store: Entity<BufferStore>,
3956 worktree_store: Entity<WorktreeStore>,
3957 pub languages: Arc<LanguageRegistry>,
3958 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3959 active_entry: Option<ProjectEntryId>,
3960 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3961 _maintain_buffer_languages: Task<()>,
3962 diagnostic_summaries:
3963 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3964 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3965 semantic_token_config: SemanticTokenConfig,
3966 lsp_data: HashMap<BufferId, BufferLspData>,
3967 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3968 next_hint_id: Arc<AtomicUsize>,
3969}
3970
3971#[derive(Debug)]
3972pub struct BufferLspData {
3973 buffer_version: Global,
3974 document_colors: Option<DocumentColorData>,
3975 code_lens: Option<CodeLensData>,
3976 semantic_tokens: Option<SemanticTokensData>,
3977 folding_ranges: Option<FoldingRangeData>,
3978 document_symbols: Option<DocumentSymbolsData>,
3979 inlay_hints: BufferInlayHints,
3980 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3981 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3982}
3983
3984#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3985struct LspKey {
3986 request_type: TypeId,
3987 server_queried: Option<LanguageServerId>,
3988}
3989
3990impl BufferLspData {
3991 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3992 Self {
3993 buffer_version: buffer.read(cx).version(),
3994 document_colors: None,
3995 code_lens: None,
3996 semantic_tokens: None,
3997 folding_ranges: None,
3998 document_symbols: None,
3999 inlay_hints: BufferInlayHints::new(buffer, cx),
4000 lsp_requests: HashMap::default(),
4001 chunk_lsp_requests: HashMap::default(),
4002 }
4003 }
4004
4005 fn remove_server_data(&mut self, for_server: LanguageServerId) {
4006 if let Some(document_colors) = &mut self.document_colors {
4007 document_colors.remove_server_data(for_server);
4008 }
4009
4010 if let Some(code_lens) = &mut self.code_lens {
4011 code_lens.remove_server_data(for_server);
4012 }
4013
4014 self.inlay_hints.remove_server_data(for_server);
4015
4016 if let Some(semantic_tokens) = &mut self.semantic_tokens {
4017 semantic_tokens.remove_server_data(for_server);
4018 }
4019
4020 if let Some(folding_ranges) = &mut self.folding_ranges {
4021 folding_ranges.ranges.remove(&for_server);
4022 }
4023
4024 if let Some(document_symbols) = &mut self.document_symbols {
4025 document_symbols.remove_server_data(for_server);
4026 }
4027 }
4028
4029 #[cfg(any(test, feature = "test-support"))]
4030 pub fn inlay_hints(&self) -> &BufferInlayHints {
4031 &self.inlay_hints
4032 }
4033}
4034
4035#[derive(Debug)]
4036pub enum LspStoreEvent {
4037 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4038 LanguageServerRemoved(LanguageServerId),
4039 LanguageServerUpdate {
4040 language_server_id: LanguageServerId,
4041 name: Option<LanguageServerName>,
4042 message: proto::update_language_server::Variant,
4043 },
4044 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4045 LanguageServerPrompt(LanguageServerPromptRequest),
4046 LanguageDetected {
4047 buffer: Entity<Buffer>,
4048 new_language: Option<Arc<Language>>,
4049 },
4050 Notification(String),
4051 RefreshInlayHints {
4052 server_id: LanguageServerId,
4053 request_id: Option<usize>,
4054 },
4055 RefreshSemanticTokens {
4056 server_id: LanguageServerId,
4057 request_id: Option<usize>,
4058 },
4059 RefreshCodeLens,
4060 DiagnosticsUpdated {
4061 server_id: LanguageServerId,
4062 paths: Vec<ProjectPath>,
4063 },
4064 DiskBasedDiagnosticsStarted {
4065 language_server_id: LanguageServerId,
4066 },
4067 DiskBasedDiagnosticsFinished {
4068 language_server_id: LanguageServerId,
4069 },
4070 SnippetEdit {
4071 buffer_id: BufferId,
4072 edits: Vec<(lsp::Range, Snippet)>,
4073 most_recent_edit: clock::Lamport,
4074 },
4075 WorkspaceEditApplied(ProjectTransaction),
4076}
4077
4078#[derive(Clone, Debug, Serialize)]
4079pub struct LanguageServerStatus {
4080 pub name: LanguageServerName,
4081 pub server_version: Option<SharedString>,
4082 pub server_readable_version: Option<SharedString>,
4083 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4084 pub has_pending_diagnostic_updates: bool,
4085 pub progress_tokens: HashSet<ProgressToken>,
4086 pub worktree: Option<WorktreeId>,
4087 pub binary: Option<LanguageServerBinary>,
4088 pub configuration: Option<Value>,
4089 pub workspace_folders: BTreeSet<Uri>,
4090 pub process_id: Option<u32>,
4091}
4092
4093#[derive(Clone, Debug)]
4094struct CoreSymbol {
4095 pub language_server_name: LanguageServerName,
4096 pub source_worktree_id: WorktreeId,
4097 pub source_language_server_id: LanguageServerId,
4098 pub path: SymbolLocation,
4099 pub name: String,
4100 pub kind: lsp::SymbolKind,
4101 pub range: Range<Unclipped<PointUtf16>>,
4102 pub container_name: Option<String>,
4103}
4104
4105#[derive(Clone, Debug, PartialEq, Eq)]
4106pub enum SymbolLocation {
4107 InProject(ProjectPath),
4108 OutsideProject {
4109 abs_path: Arc<Path>,
4110 signature: [u8; 32],
4111 },
4112}
4113
4114impl SymbolLocation {
4115 fn file_name(&self) -> Option<&str> {
4116 match self {
4117 Self::InProject(path) => path.path.file_name(),
4118 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4119 }
4120 }
4121}
4122
4123impl LspStore {
4124 pub fn init(client: &AnyProtoClient) {
4125 client.add_entity_request_handler(Self::handle_lsp_query);
4126 client.add_entity_message_handler(Self::handle_lsp_query_response);
4127 client.add_entity_request_handler(Self::handle_restart_language_servers);
4128 client.add_entity_request_handler(Self::handle_stop_language_servers);
4129 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4130 client.add_entity_message_handler(Self::handle_start_language_server);
4131 client.add_entity_message_handler(Self::handle_update_language_server);
4132 client.add_entity_message_handler(Self::handle_language_server_log);
4133 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4134 client.add_entity_request_handler(Self::handle_format_buffers);
4135 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4136 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4137 client.add_entity_request_handler(Self::handle_apply_code_action);
4138 client.add_entity_request_handler(Self::handle_get_project_symbols);
4139 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4140 client.add_entity_request_handler(Self::handle_get_color_presentation);
4141 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4142 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4143 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4144 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4145 client.add_entity_request_handler(Self::handle_on_type_formatting);
4146 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4147 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4148 client.add_entity_request_handler(Self::handle_rename_project_entry);
4149 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4150 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4151 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4152 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4153 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4154 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4155 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4156
4157 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4158 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4159 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4160 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4161 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4162 client.add_entity_request_handler(
4163 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4164 );
4165 client.add_entity_request_handler(
4166 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4167 );
4168 client.add_entity_request_handler(
4169 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4170 );
4171 }
4172
4173 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4174 match &self.mode {
4175 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4176 _ => None,
4177 }
4178 }
4179
4180 pub fn as_local(&self) -> Option<&LocalLspStore> {
4181 match &self.mode {
4182 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4183 _ => None,
4184 }
4185 }
4186
4187 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4188 match &mut self.mode {
4189 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4190 _ => None,
4191 }
4192 }
4193
4194 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4195 match &self.mode {
4196 LspStoreMode::Remote(RemoteLspStore {
4197 upstream_client: Some(upstream_client),
4198 upstream_project_id,
4199 ..
4200 }) => Some((upstream_client.clone(), *upstream_project_id)),
4201
4202 LspStoreMode::Remote(RemoteLspStore {
4203 upstream_client: None,
4204 ..
4205 }) => None,
4206 LspStoreMode::Local(_) => None,
4207 }
4208 }
4209
4210 pub fn new_local(
4211 buffer_store: Entity<BufferStore>,
4212 worktree_store: Entity<WorktreeStore>,
4213 prettier_store: Entity<PrettierStore>,
4214 toolchain_store: Entity<LocalToolchainStore>,
4215 environment: Entity<ProjectEnvironment>,
4216 manifest_tree: Entity<ManifestTree>,
4217 languages: Arc<LanguageRegistry>,
4218 http_client: Arc<dyn HttpClient>,
4219 fs: Arc<dyn Fs>,
4220 cx: &mut Context<Self>,
4221 ) -> Self {
4222 let yarn = YarnPathStore::new(fs.clone(), cx);
4223 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4224 .detach();
4225 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4226 .detach();
4227 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4228 .detach();
4229 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4230 .detach();
4231 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4232 .detach();
4233 subscribe_to_binary_statuses(&languages, cx).detach();
4234
4235 let _maintain_workspace_config = {
4236 let (sender, receiver) = watch::channel();
4237 (Self::maintain_workspace_config(receiver, cx), sender)
4238 };
4239
4240 Self {
4241 mode: LspStoreMode::Local(LocalLspStore {
4242 weak: cx.weak_entity(),
4243 worktree_store: worktree_store.clone(),
4244
4245 supplementary_language_servers: Default::default(),
4246 languages: languages.clone(),
4247 language_server_ids: Default::default(),
4248 language_servers: Default::default(),
4249 last_workspace_edits_by_language_server: Default::default(),
4250 language_server_watched_paths: Default::default(),
4251 language_server_paths_watched_for_rename: Default::default(),
4252 language_server_dynamic_registrations: Default::default(),
4253 buffers_being_formatted: Default::default(),
4254 buffers_to_refresh_hash_set: HashSet::default(),
4255 buffers_to_refresh_queue: VecDeque::new(),
4256 _background_diagnostics_worker: Task::ready(()).shared(),
4257 buffer_snapshots: Default::default(),
4258 prettier_store,
4259 environment,
4260 http_client,
4261 fs,
4262 yarn,
4263 next_diagnostic_group_id: Default::default(),
4264 diagnostics: Default::default(),
4265 _subscription: cx.on_app_quit(|this, _| {
4266 this.as_local_mut()
4267 .unwrap()
4268 .shutdown_language_servers_on_quit()
4269 }),
4270 lsp_tree: LanguageServerTree::new(
4271 manifest_tree,
4272 languages.clone(),
4273 toolchain_store.clone(),
4274 ),
4275 toolchain_store,
4276 registered_buffers: HashMap::default(),
4277 buffers_opened_in_servers: HashMap::default(),
4278 buffer_pull_diagnostics_result_ids: HashMap::default(),
4279 workspace_pull_diagnostics_result_ids: HashMap::default(),
4280 restricted_worktrees_tasks: HashMap::default(),
4281 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4282 .manifest_file_names(),
4283 }),
4284 last_formatting_failure: None,
4285 downstream_client: None,
4286 buffer_store,
4287 worktree_store,
4288 languages: languages.clone(),
4289 language_server_statuses: Default::default(),
4290 nonce: StdRng::from_os_rng().random(),
4291 diagnostic_summaries: HashMap::default(),
4292 lsp_server_capabilities: HashMap::default(),
4293 semantic_token_config: SemanticTokenConfig::new(cx),
4294 lsp_data: HashMap::default(),
4295 buffer_reload_tasks: HashMap::default(),
4296 next_hint_id: Arc::default(),
4297 active_entry: None,
4298 _maintain_workspace_config,
4299 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4300 }
4301 }
4302
4303 fn send_lsp_proto_request<R: LspCommand>(
4304 &self,
4305 buffer: Entity<Buffer>,
4306 client: AnyProtoClient,
4307 upstream_project_id: u64,
4308 request: R,
4309 cx: &mut Context<LspStore>,
4310 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4311 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4312 return Task::ready(Ok(R::Response::default()));
4313 }
4314 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4315 cx.spawn(async move |this, cx| {
4316 let response = client.request(message).await?;
4317 let this = this.upgrade().context("project dropped")?;
4318 request
4319 .response_from_proto(response, this, buffer, cx.clone())
4320 .await
4321 })
4322 }
4323
4324 pub(super) fn new_remote(
4325 buffer_store: Entity<BufferStore>,
4326 worktree_store: Entity<WorktreeStore>,
4327 languages: Arc<LanguageRegistry>,
4328 upstream_client: AnyProtoClient,
4329 project_id: u64,
4330 cx: &mut Context<Self>,
4331 ) -> Self {
4332 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4333 .detach();
4334 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4335 .detach();
4336 subscribe_to_binary_statuses(&languages, cx).detach();
4337 let _maintain_workspace_config = {
4338 let (sender, receiver) = watch::channel();
4339 (Self::maintain_workspace_config(receiver, cx), sender)
4340 };
4341 Self {
4342 mode: LspStoreMode::Remote(RemoteLspStore {
4343 upstream_client: Some(upstream_client),
4344 upstream_project_id: project_id,
4345 }),
4346 downstream_client: None,
4347 last_formatting_failure: None,
4348 buffer_store,
4349 worktree_store,
4350 languages: languages.clone(),
4351 language_server_statuses: Default::default(),
4352 nonce: StdRng::from_os_rng().random(),
4353 diagnostic_summaries: HashMap::default(),
4354 lsp_server_capabilities: HashMap::default(),
4355 semantic_token_config: SemanticTokenConfig::new(cx),
4356 next_hint_id: Arc::default(),
4357 lsp_data: HashMap::default(),
4358 buffer_reload_tasks: HashMap::default(),
4359 active_entry: None,
4360
4361 _maintain_workspace_config,
4362 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4363 }
4364 }
4365
4366 fn on_buffer_store_event(
4367 &mut self,
4368 _: Entity<BufferStore>,
4369 event: &BufferStoreEvent,
4370 cx: &mut Context<Self>,
4371 ) {
4372 match event {
4373 BufferStoreEvent::BufferAdded(buffer) => {
4374 self.on_buffer_added(buffer, cx).log_err();
4375 }
4376 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4377 let buffer_id = buffer.read(cx).remote_id();
4378 if let Some(local) = self.as_local_mut()
4379 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4380 {
4381 local.reset_buffer(buffer, old_file, cx);
4382
4383 if local.registered_buffers.contains_key(&buffer_id) {
4384 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4385 }
4386 }
4387
4388 self.detect_language_for_buffer(buffer, cx);
4389 if let Some(local) = self.as_local_mut() {
4390 local.initialize_buffer(buffer, cx);
4391 if local.registered_buffers.contains_key(&buffer_id) {
4392 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4393 }
4394 }
4395 }
4396 _ => {}
4397 }
4398 }
4399
4400 fn on_worktree_store_event(
4401 &mut self,
4402 _: Entity<WorktreeStore>,
4403 event: &WorktreeStoreEvent,
4404 cx: &mut Context<Self>,
4405 ) {
4406 match event {
4407 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4408 if !worktree.read(cx).is_local() {
4409 return;
4410 }
4411 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4412 worktree::Event::UpdatedEntries(changes) => {
4413 this.update_local_worktree_language_servers(&worktree, changes, cx);
4414 }
4415 worktree::Event::UpdatedGitRepositories(_)
4416 | worktree::Event::DeletedEntry(_)
4417 | worktree::Event::Deleted
4418 | worktree::Event::UpdatedRootRepoCommonDir { .. } => {}
4419 })
4420 .detach()
4421 }
4422 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4423 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4424 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4425 }
4426 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4427 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4428 }
4429 WorktreeStoreEvent::WorktreeReleased(..)
4430 | WorktreeStoreEvent::WorktreeOrderChanged
4431 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4432 | WorktreeStoreEvent::WorktreeDeletedEntry(..)
4433 | WorktreeStoreEvent::WorktreeUpdatedRootRepoCommonDir(..) => {}
4434 }
4435 }
4436
4437 fn on_prettier_store_event(
4438 &mut self,
4439 _: Entity<PrettierStore>,
4440 event: &PrettierStoreEvent,
4441 cx: &mut Context<Self>,
4442 ) {
4443 match event {
4444 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4445 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4446 }
4447 PrettierStoreEvent::LanguageServerAdded {
4448 new_server_id,
4449 name,
4450 prettier_server,
4451 } => {
4452 self.register_supplementary_language_server(
4453 *new_server_id,
4454 name.clone(),
4455 prettier_server.clone(),
4456 cx,
4457 );
4458 }
4459 }
4460 }
4461
4462 fn on_toolchain_store_event(
4463 &mut self,
4464 _: Entity<LocalToolchainStore>,
4465 event: &ToolchainStoreEvent,
4466 _: &mut Context<Self>,
4467 ) {
4468 if let ToolchainStoreEvent::ToolchainActivated = event {
4469 self.request_workspace_config_refresh()
4470 }
4471 }
4472
4473 fn request_workspace_config_refresh(&mut self) {
4474 *self._maintain_workspace_config.1.borrow_mut() = ();
4475 }
4476
4477 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4478 self.as_local().map(|local| local.prettier_store.clone())
4479 }
4480
4481 fn on_buffer_event(
4482 &mut self,
4483 buffer: Entity<Buffer>,
4484 event: &language::BufferEvent,
4485 cx: &mut Context<Self>,
4486 ) {
4487 match event {
4488 language::BufferEvent::Edited { .. } => {
4489 self.on_buffer_edited(buffer, cx);
4490 }
4491
4492 language::BufferEvent::Saved => {
4493 self.on_buffer_saved(buffer, cx);
4494 }
4495
4496 language::BufferEvent::Reloaded => {
4497 self.on_buffer_reloaded(buffer, cx);
4498 }
4499
4500 _ => {}
4501 }
4502 }
4503
4504 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4505 buffer
4506 .read(cx)
4507 .set_language_registry(self.languages.clone());
4508
4509 cx.subscribe(buffer, |this, buffer, event, cx| {
4510 this.on_buffer_event(buffer, event, cx);
4511 })
4512 .detach();
4513
4514 self.parse_modeline(buffer, cx);
4515 self.detect_language_for_buffer(buffer, cx);
4516 if let Some(local) = self.as_local_mut() {
4517 local.initialize_buffer(buffer, cx);
4518 }
4519
4520 Ok(())
4521 }
4522
4523 pub fn refresh_background_diagnostics_for_buffers(
4524 &mut self,
4525 buffers: HashSet<BufferId>,
4526 cx: &mut Context<Self>,
4527 ) -> Shared<Task<()>> {
4528 let Some(local) = self.as_local_mut() else {
4529 return Task::ready(()).shared();
4530 };
4531 for buffer in buffers {
4532 if local.buffers_to_refresh_hash_set.insert(buffer) {
4533 local.buffers_to_refresh_queue.push_back(buffer);
4534 if local.buffers_to_refresh_queue.len() == 1 {
4535 local._background_diagnostics_worker =
4536 Self::background_diagnostics_worker(cx).shared();
4537 }
4538 }
4539 }
4540
4541 local._background_diagnostics_worker.clone()
4542 }
4543
4544 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4545 let buffer_store = self.buffer_store.clone();
4546 let local = self.as_local_mut()?;
4547 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4548 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4549 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4550 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4551 }
4552 }
4553 None
4554 }
4555
4556 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4557 cx.spawn(async move |this, cx| {
4558 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4559 task.await.log_err();
4560 }
4561 })
4562 }
4563
4564 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4565 if self.parse_modeline(&buffer, cx) {
4566 self.detect_language_for_buffer(&buffer, cx);
4567 }
4568
4569 let buffer_id = buffer.read(cx).remote_id();
4570 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4571 self.buffer_reload_tasks.insert(buffer_id, task);
4572 }
4573
4574 pub(crate) fn register_buffer_with_language_servers(
4575 &mut self,
4576 buffer: &Entity<Buffer>,
4577 only_register_servers: HashSet<LanguageServerSelector>,
4578 ignore_refcounts: bool,
4579 cx: &mut Context<Self>,
4580 ) -> OpenLspBufferHandle {
4581 let buffer_id = buffer.read(cx).remote_id();
4582 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4583 if let Some(local) = self.as_local_mut() {
4584 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4585 if !ignore_refcounts {
4586 *refcount += 1;
4587 }
4588
4589 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4590 // 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
4591 // 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
4592 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4593 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4594 return handle;
4595 };
4596 if !file.is_local() {
4597 return handle;
4598 }
4599
4600 if ignore_refcounts || *refcount == 1 {
4601 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4602 }
4603 if !ignore_refcounts {
4604 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4605 let refcount = {
4606 let local = lsp_store.as_local_mut().unwrap();
4607 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4608 debug_panic!("bad refcounting");
4609 return;
4610 };
4611
4612 *refcount -= 1;
4613 *refcount
4614 };
4615 if refcount == 0 {
4616 lsp_store.lsp_data.remove(&buffer_id);
4617 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4618 let local = lsp_store.as_local_mut().unwrap();
4619 local.registered_buffers.remove(&buffer_id);
4620
4621 local.buffers_opened_in_servers.remove(&buffer_id);
4622 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4623 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4624
4625 let buffer_abs_path = file.abs_path(cx);
4626 for (_, buffer_pull_diagnostics_result_ids) in
4627 &mut local.buffer_pull_diagnostics_result_ids
4628 {
4629 buffer_pull_diagnostics_result_ids.retain(
4630 |_, buffer_result_ids| {
4631 buffer_result_ids.remove(&buffer_abs_path);
4632 !buffer_result_ids.is_empty()
4633 },
4634 );
4635 }
4636
4637 let diagnostic_updates = local
4638 .language_servers
4639 .keys()
4640 .cloned()
4641 .map(|server_id| DocumentDiagnosticsUpdate {
4642 diagnostics: DocumentDiagnostics {
4643 document_abs_path: buffer_abs_path.clone(),
4644 version: None,
4645 diagnostics: Vec::new(),
4646 },
4647 result_id: None,
4648 registration_id: None,
4649 server_id,
4650 disk_based_sources: Cow::Borrowed(&[]),
4651 })
4652 .collect::<Vec<_>>();
4653
4654 lsp_store
4655 .merge_diagnostic_entries(
4656 diagnostic_updates,
4657 |_, diagnostic, _| {
4658 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4659 },
4660 cx,
4661 )
4662 .context("Clearing diagnostics for the closed buffer")
4663 .log_err();
4664 }
4665 }
4666 })
4667 .detach();
4668 }
4669 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4670 let buffer_id = buffer.read(cx).remote_id().to_proto();
4671 cx.background_spawn(async move {
4672 upstream_client
4673 .request(proto::RegisterBufferWithLanguageServers {
4674 project_id: upstream_project_id,
4675 buffer_id,
4676 only_servers: only_register_servers
4677 .into_iter()
4678 .map(|selector| {
4679 let selector = match selector {
4680 LanguageServerSelector::Id(language_server_id) => {
4681 proto::language_server_selector::Selector::ServerId(
4682 language_server_id.to_proto(),
4683 )
4684 }
4685 LanguageServerSelector::Name(language_server_name) => {
4686 proto::language_server_selector::Selector::Name(
4687 language_server_name.to_string(),
4688 )
4689 }
4690 };
4691 proto::LanguageServerSelector {
4692 selector: Some(selector),
4693 }
4694 })
4695 .collect(),
4696 })
4697 .await
4698 })
4699 .detach();
4700 } else {
4701 // Our remote connection got closed
4702 }
4703 handle
4704 }
4705
4706 fn maintain_buffer_languages(
4707 languages: Arc<LanguageRegistry>,
4708 cx: &mut Context<Self>,
4709 ) -> Task<()> {
4710 let mut subscription = languages.subscribe();
4711 let mut prev_reload_count = languages.reload_count();
4712 cx.spawn(async move |this, cx| {
4713 while let Some(()) = subscription.next().await {
4714 if let Some(this) = this.upgrade() {
4715 // If the language registry has been reloaded, then remove and
4716 // re-assign the languages on all open buffers.
4717 let reload_count = languages.reload_count();
4718 if reload_count > prev_reload_count {
4719 prev_reload_count = reload_count;
4720 this.update(cx, |this, cx| {
4721 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4722 for buffer in buffer_store.buffers() {
4723 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4724 {
4725 buffer.update(cx, |buffer, cx| {
4726 buffer.set_language_async(None, cx)
4727 });
4728 if let Some(local) = this.as_local_mut() {
4729 local.reset_buffer(&buffer, &f, cx);
4730
4731 if local
4732 .registered_buffers
4733 .contains_key(&buffer.read(cx).remote_id())
4734 && let Some(file_url) =
4735 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4736 {
4737 local.unregister_buffer_from_language_servers(
4738 &buffer, &file_url, cx,
4739 );
4740 }
4741 }
4742 }
4743 }
4744 });
4745 });
4746 }
4747
4748 this.update(cx, |this, cx| {
4749 let mut plain_text_buffers = Vec::new();
4750 let mut buffers_with_language = Vec::new();
4751 let mut buffers_with_unknown_injections = Vec::new();
4752 for handle in this.buffer_store.read(cx).buffers() {
4753 let buffer = handle.read(cx);
4754 if buffer.language().is_none()
4755 || buffer.language() == Some(&*language::PLAIN_TEXT)
4756 {
4757 plain_text_buffers.push(handle);
4758 } else {
4759 if buffer.contains_unknown_injections() {
4760 buffers_with_unknown_injections.push(handle.clone());
4761 }
4762 buffers_with_language.push(handle);
4763 }
4764 }
4765
4766 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4767 // and reused later in the invisible worktrees.
4768 plain_text_buffers.sort_by_key(|buffer| {
4769 Reverse(
4770 File::from_dyn(buffer.read(cx).file())
4771 .map(|file| file.worktree.read(cx).is_visible()),
4772 )
4773 });
4774
4775 for buffer in plain_text_buffers {
4776 this.detect_language_for_buffer(&buffer, cx);
4777 if let Some(local) = this.as_local_mut() {
4778 local.initialize_buffer(&buffer, cx);
4779 if local
4780 .registered_buffers
4781 .contains_key(&buffer.read(cx).remote_id())
4782 {
4783 local.register_buffer_with_language_servers(
4784 &buffer,
4785 HashSet::default(),
4786 cx,
4787 );
4788 }
4789 }
4790 }
4791
4792 // Also register buffers that already have a language with
4793 // any newly-available language servers (e.g., from extensions
4794 // that finished loading after buffers were restored).
4795 if let Some(local) = this.as_local_mut() {
4796 for buffer in buffers_with_language {
4797 if local
4798 .registered_buffers
4799 .contains_key(&buffer.read(cx).remote_id())
4800 {
4801 local.register_buffer_with_language_servers(
4802 &buffer,
4803 HashSet::default(),
4804 cx,
4805 );
4806 }
4807 }
4808 }
4809
4810 for buffer in buffers_with_unknown_injections {
4811 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4812 }
4813 });
4814 }
4815 }
4816 })
4817 }
4818
4819 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4820 let buffer = buffer_handle.read(cx);
4821 let content = buffer.as_rope();
4822
4823 let modeline_settings = {
4824 let settings_store = cx.global::<SettingsStore>();
4825 let modeline_lines = settings_store
4826 .raw_user_settings()
4827 .and_then(|s| s.content.modeline_lines)
4828 .or(settings_store.raw_default_settings().modeline_lines)
4829 .unwrap_or(5);
4830
4831 const MAX_MODELINE_BYTES: usize = 1024;
4832
4833 let first_bytes =
4834 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4835 let mut first_lines = Vec::new();
4836 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4837 for _ in 0..modeline_lines {
4838 if let Some(line) = lines.next() {
4839 first_lines.push(line.to_string());
4840 } else {
4841 break;
4842 }
4843 }
4844 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4845
4846 let last_start =
4847 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4848 let mut last_lines = Vec::new();
4849 let mut lines = content
4850 .reversed_chunks_in_range(last_start..content.len())
4851 .lines();
4852 for _ in 0..modeline_lines {
4853 if let Some(line) = lines.next() {
4854 last_lines.push(line.to_string());
4855 } else {
4856 break;
4857 }
4858 }
4859 let last_lines_ref: Vec<_> =
4860 last_lines.iter().rev().map(|line| line.as_str()).collect();
4861 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4862 };
4863
4864 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4865
4866 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4867 }
4868
4869 fn detect_language_for_buffer(
4870 &mut self,
4871 buffer_handle: &Entity<Buffer>,
4872 cx: &mut Context<Self>,
4873 ) -> Option<language::AvailableLanguage> {
4874 // If the buffer has a language, set it and start the language server if we haven't already.
4875 let buffer = buffer_handle.read(cx);
4876 let file = buffer.file()?;
4877 let content = buffer.as_rope();
4878 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4879
4880 let available_language = if let Some(ModelineSettings {
4881 mode: Some(mode_name),
4882 ..
4883 }) = modeline_settings
4884 {
4885 self.languages
4886 .available_language_for_modeline_name(mode_name)
4887 } else {
4888 self.languages.language_for_file(file, Some(content), cx)
4889 };
4890 if let Some(available_language) = &available_language {
4891 if let Some(Ok(Ok(new_language))) = self
4892 .languages
4893 .load_language(available_language)
4894 .now_or_never()
4895 {
4896 self.set_language_for_buffer(buffer_handle, new_language, cx);
4897 }
4898 } else {
4899 cx.emit(LspStoreEvent::LanguageDetected {
4900 buffer: buffer_handle.clone(),
4901 new_language: None,
4902 });
4903 }
4904
4905 available_language
4906 }
4907
4908 pub(crate) fn set_language_for_buffer(
4909 &mut self,
4910 buffer_entity: &Entity<Buffer>,
4911 new_language: Arc<Language>,
4912 cx: &mut Context<Self>,
4913 ) {
4914 let buffer = buffer_entity.read(cx);
4915 let buffer_file = buffer.file().cloned();
4916 let buffer_id = buffer.remote_id();
4917 if let Some(local_store) = self.as_local_mut()
4918 && local_store.registered_buffers.contains_key(&buffer_id)
4919 && let Some(abs_path) =
4920 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4921 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4922 {
4923 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4924 }
4925 buffer_entity.update(cx, |buffer, cx| {
4926 if buffer
4927 .language()
4928 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4929 {
4930 buffer.set_language_async(Some(new_language.clone()), cx);
4931 }
4932 });
4933
4934 let settings = LanguageSettings::resolve(
4935 Some(&buffer_entity.read(cx)),
4936 Some(&new_language.name()),
4937 cx,
4938 )
4939 .into_owned();
4940 let buffer_file = File::from_dyn(buffer_file.as_ref());
4941
4942 let worktree_id = if let Some(file) = buffer_file {
4943 let worktree = file.worktree.clone();
4944
4945 if let Some(local) = self.as_local_mut()
4946 && local.registered_buffers.contains_key(&buffer_id)
4947 {
4948 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4949 }
4950 Some(worktree.read(cx).id())
4951 } else {
4952 None
4953 };
4954
4955 if settings.prettier.allowed
4956 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4957 {
4958 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4959 if let Some(prettier_store) = prettier_store {
4960 prettier_store.update(cx, |prettier_store, cx| {
4961 prettier_store.install_default_prettier(
4962 worktree_id,
4963 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4964 cx,
4965 )
4966 })
4967 }
4968 }
4969
4970 cx.emit(LspStoreEvent::LanguageDetected {
4971 buffer: buffer_entity.clone(),
4972 new_language: Some(new_language),
4973 })
4974 }
4975
4976 pub fn buffer_store(&self) -> Entity<BufferStore> {
4977 self.buffer_store.clone()
4978 }
4979
4980 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4981 self.active_entry = active_entry;
4982 }
4983
4984 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4985 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4986 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4987 {
4988 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4989 summaries
4990 .iter()
4991 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4992 });
4993 if let Some(summary) = summaries.next() {
4994 client
4995 .send(proto::UpdateDiagnosticSummary {
4996 project_id: downstream_project_id,
4997 worktree_id: worktree.id().to_proto(),
4998 summary: Some(summary),
4999 more_summaries: summaries.collect(),
5000 })
5001 .log_err();
5002 }
5003 }
5004 }
5005
5006 fn is_capable_for_proto_request<R>(
5007 &self,
5008 buffer: &Entity<Buffer>,
5009 request: &R,
5010 cx: &App,
5011 ) -> bool
5012 where
5013 R: LspCommand,
5014 {
5015 self.check_if_capable_for_proto_request(
5016 buffer,
5017 |capabilities| {
5018 request.check_capabilities(AdapterServerCapabilities {
5019 server_capabilities: capabilities.clone(),
5020 code_action_kinds: None,
5021 })
5022 },
5023 cx,
5024 )
5025 }
5026
5027 fn relevant_server_ids_for_capability_check(
5028 &self,
5029 buffer: &Entity<Buffer>,
5030 cx: &App,
5031 ) -> Vec<LanguageServerId> {
5032 let buffer_id = buffer.read(cx).remote_id();
5033 if let Some(local) = self.as_local() {
5034 return local
5035 .buffers_opened_in_servers
5036 .get(&buffer_id)
5037 .into_iter()
5038 .flatten()
5039 .copied()
5040 .collect();
5041 }
5042
5043 let Some(language) = buffer.read(cx).language().cloned() else {
5044 return Vec::default();
5045 };
5046 let registered_language_servers = self
5047 .languages
5048 .lsp_adapters(&language.name())
5049 .into_iter()
5050 .map(|lsp_adapter| lsp_adapter.name())
5051 .collect::<HashSet<_>>();
5052 self.language_server_statuses
5053 .iter()
5054 .filter_map(|(server_id, server_status)| {
5055 // Include servers that are either registered for this language OR
5056 // available to be loaded (for SSH remote mode where adapters like
5057 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5058 // but only loaded on the server side)
5059 let is_relevant = registered_language_servers.contains(&server_status.name)
5060 || self.languages.is_lsp_adapter_available(&server_status.name);
5061 is_relevant.then_some(*server_id)
5062 })
5063 .collect()
5064 }
5065
5066 fn check_if_any_relevant_server_matches<F>(
5067 &self,
5068 buffer: &Entity<Buffer>,
5069 mut check: F,
5070 cx: &App,
5071 ) -> bool
5072 where
5073 F: FnMut(&LanguageServerStatus, &lsp::ServerCapabilities) -> bool,
5074 {
5075 self.relevant_server_ids_for_capability_check(buffer, cx)
5076 .into_iter()
5077 .filter_map(|server_id| {
5078 Some((
5079 self.language_server_statuses.get(&server_id)?,
5080 self.lsp_server_capabilities.get(&server_id)?,
5081 ))
5082 })
5083 .any(|(server_status, capabilities)| check(server_status, capabilities))
5084 }
5085
5086 fn check_if_capable_for_proto_request<F>(
5087 &self,
5088 buffer: &Entity<Buffer>,
5089 mut check: F,
5090 cx: &App,
5091 ) -> bool
5092 where
5093 F: FnMut(&lsp::ServerCapabilities) -> bool,
5094 {
5095 self.check_if_any_relevant_server_matches(buffer, |_, capabilities| check(capabilities), cx)
5096 }
5097
5098 pub fn supports_range_formatting(&self, buffer: &Entity<Buffer>, cx: &App) -> bool {
5099 let settings = LanguageSettings::for_buffer(buffer.read(cx), cx);
5100 settings.formatter.as_ref().iter().any(|formatter| {
5101 match formatter {
5102 Formatter::None => false,
5103 Formatter::Auto => {
5104 settings.prettier.allowed
5105 || self.check_if_capable_for_proto_request(
5106 buffer,
5107 server_capabilities_support_range_formatting,
5108 cx,
5109 )
5110 }
5111 Formatter::Prettier => true,
5112 Formatter::External { .. } => false,
5113 Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current) => {
5114 self.check_if_capable_for_proto_request(
5115 buffer,
5116 server_capabilities_support_range_formatting,
5117 cx,
5118 )
5119 }
5120 Formatter::LanguageServer(
5121 settings::LanguageServerFormatterSpecifier::Specific { name },
5122 ) => self.check_if_any_relevant_server_matches(
5123 buffer,
5124 |server_status, capabilities| {
5125 server_status.name.0.as_ref() == name
5126 && server_capabilities_support_range_formatting(capabilities)
5127 },
5128 cx,
5129 ),
5130 // `FormatSelections` should only surface when a formatter can honor the
5131 // selected ranges. Code actions can still run as part of formatting, but
5132 // they operate on the whole buffer rather than the selected text.
5133 Formatter::CodeAction(_) => false,
5134 }
5135 })
5136 }
5137
5138 fn all_capable_for_proto_request<F>(
5139 &self,
5140 buffer: &Entity<Buffer>,
5141 mut check: F,
5142 cx: &App,
5143 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
5144 where
5145 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
5146 {
5147 self.relevant_server_ids_for_capability_check(buffer, cx)
5148 .into_iter()
5149 .filter_map(|server_id| {
5150 Some((
5151 server_id,
5152 &self.language_server_statuses.get(&server_id)?.name,
5153 self.lsp_server_capabilities.get(&server_id)?,
5154 ))
5155 })
5156 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5157 .map(|(server_id, server_name, _)| (server_id, server_name.clone()))
5158 .collect()
5159 }
5160
5161 pub fn request_lsp<R>(
5162 &mut self,
5163 buffer: Entity<Buffer>,
5164 server: LanguageServerToQuery,
5165 request: R,
5166 cx: &mut Context<Self>,
5167 ) -> Task<Result<R::Response>>
5168 where
5169 R: LspCommand,
5170 <R::LspRequest as lsp::request::Request>::Result: Send,
5171 <R::LspRequest as lsp::request::Request>::Params: Send,
5172 {
5173 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5174 return self.send_lsp_proto_request(
5175 buffer,
5176 upstream_client,
5177 upstream_project_id,
5178 request,
5179 cx,
5180 );
5181 }
5182
5183 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5184 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5185 local
5186 .language_servers_for_buffer(buffer, cx)
5187 .find(|(_, server)| {
5188 request.check_capabilities(server.adapter_server_capabilities())
5189 })
5190 .map(|(_, server)| server.clone())
5191 }),
5192 LanguageServerToQuery::Other(id) => self
5193 .language_server_for_local_buffer(buffer, id, cx)
5194 .and_then(|(_, server)| {
5195 request
5196 .check_capabilities(server.adapter_server_capabilities())
5197 .then(|| Arc::clone(server))
5198 }),
5199 }) else {
5200 return Task::ready(Ok(Default::default()));
5201 };
5202
5203 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5204
5205 let Some(file) = file else {
5206 return Task::ready(Ok(Default::default()));
5207 };
5208
5209 let lsp_params = match request.to_lsp_params_or_response(
5210 &file.abs_path(cx),
5211 buffer.read(cx),
5212 &language_server,
5213 cx,
5214 ) {
5215 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5216 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5217 Err(err) => {
5218 let message = format!(
5219 "{} via {} failed: {}",
5220 request.display_name(),
5221 language_server.name(),
5222 err
5223 );
5224 // rust-analyzer likes to error with this when its still loading up
5225 if !message.ends_with("content modified") {
5226 log::warn!("{message}");
5227 }
5228 return Task::ready(Err(anyhow!(message)));
5229 }
5230 };
5231
5232 let status = request.status();
5233 let request_timeout = ProjectSettings::get_global(cx)
5234 .global_lsp_settings
5235 .get_request_timeout();
5236
5237 cx.spawn(async move |this, cx| {
5238 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5239
5240 let id = lsp_request.id();
5241 let _cleanup = if status.is_some() {
5242 cx.update(|cx| {
5243 this.update(cx, |this, cx| {
5244 this.on_lsp_work_start(
5245 language_server.server_id(),
5246 ProgressToken::Number(id),
5247 LanguageServerProgress {
5248 is_disk_based_diagnostics_progress: false,
5249 is_cancellable: false,
5250 title: None,
5251 message: status.clone(),
5252 percentage: None,
5253 last_update_at: cx.background_executor().now(),
5254 },
5255 cx,
5256 );
5257 })
5258 })
5259 .log_err();
5260
5261 Some(defer(|| {
5262 cx.update(|cx| {
5263 this.update(cx, |this, cx| {
5264 this.on_lsp_work_end(
5265 language_server.server_id(),
5266 ProgressToken::Number(id),
5267 cx,
5268 );
5269 })
5270 })
5271 .log_err();
5272 }))
5273 } else {
5274 None
5275 };
5276
5277 let result = lsp_request.await.into_response();
5278
5279 let response = result.map_err(|err| {
5280 let message = format!(
5281 "{} via {} failed: {}",
5282 request.display_name(),
5283 language_server.name(),
5284 err
5285 );
5286 // rust-analyzer likes to error with this when its still loading up
5287 if !message.ends_with("content modified") {
5288 log::warn!("{message}");
5289 }
5290 anyhow::anyhow!(message)
5291 })?;
5292
5293 request
5294 .response_from_lsp(
5295 response,
5296 this.upgrade().context("no app context")?,
5297 buffer,
5298 language_server.server_id(),
5299 cx.clone(),
5300 )
5301 .await
5302 })
5303 }
5304
5305 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5306 let mut language_formatters_to_check = Vec::new();
5307 for buffer in self.buffer_store.read(cx).buffers() {
5308 let buffer = buffer.read(cx);
5309 let settings = LanguageSettings::for_buffer(buffer, cx);
5310 if buffer.language().is_some() {
5311 let buffer_file = File::from_dyn(buffer.file());
5312 language_formatters_to_check.push((
5313 buffer_file.map(|f| f.worktree_id(cx)),
5314 settings.into_owned(),
5315 ));
5316 }
5317 }
5318
5319 self.request_workspace_config_refresh();
5320
5321 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5322 prettier_store.update(cx, |prettier_store, cx| {
5323 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5324 })
5325 }
5326
5327 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5328 .global_lsp_settings
5329 .semantic_token_rules
5330 .clone();
5331 self.semantic_token_config
5332 .update_rules(new_semantic_token_rules);
5333 // Always clear cached stylizers so that changes to language-specific
5334 // semantic token rules (e.g. from extension install/uninstall) are
5335 // picked up. Stylizers are recreated lazily, so this is cheap.
5336 self.semantic_token_config.clear_stylizers();
5337
5338 let new_global_semantic_tokens_mode =
5339 all_language_settings(None, cx).defaults.semantic_tokens;
5340 if self
5341 .semantic_token_config
5342 .update_global_mode(new_global_semantic_tokens_mode)
5343 {
5344 self.restart_all_language_servers(cx);
5345 }
5346
5347 cx.notify();
5348 }
5349
5350 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5351 let buffer_store = self.buffer_store.clone();
5352 let Some(local) = self.as_local_mut() else {
5353 return;
5354 };
5355 let mut adapters = BTreeMap::default();
5356 let get_adapter = {
5357 let languages = local.languages.clone();
5358 let environment = local.environment.clone();
5359 let weak = local.weak.clone();
5360 let worktree_store = local.worktree_store.clone();
5361 let http_client = local.http_client.clone();
5362 let fs = local.fs.clone();
5363 move |worktree_id, cx: &mut App| {
5364 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5365 Some(LocalLspAdapterDelegate::new(
5366 languages.clone(),
5367 &environment,
5368 weak.clone(),
5369 &worktree,
5370 http_client.clone(),
5371 fs.clone(),
5372 cx,
5373 ))
5374 }
5375 };
5376
5377 let mut messages_to_report = Vec::new();
5378 let (new_tree, to_stop) = {
5379 let mut rebase = local.lsp_tree.rebase();
5380 let buffers = buffer_store
5381 .read(cx)
5382 .buffers()
5383 .filter_map(|buffer| {
5384 let raw_buffer = buffer.read(cx);
5385 if !local
5386 .registered_buffers
5387 .contains_key(&raw_buffer.remote_id())
5388 {
5389 return None;
5390 }
5391 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5392 let language = raw_buffer.language().cloned()?;
5393 Some((file, language, raw_buffer.remote_id()))
5394 })
5395 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5396 for (file, language, buffer_id) in buffers {
5397 let worktree_id = file.worktree_id(cx);
5398 let Some(worktree) = local
5399 .worktree_store
5400 .read(cx)
5401 .worktree_for_id(worktree_id, cx)
5402 else {
5403 continue;
5404 };
5405
5406 if let Some((_, apply)) = local.reuse_existing_language_server(
5407 rebase.server_tree(),
5408 &worktree,
5409 &language.name(),
5410 cx,
5411 ) {
5412 (apply)(rebase.server_tree());
5413 } else if let Some(lsp_delegate) = adapters
5414 .entry(worktree_id)
5415 .or_insert_with(|| get_adapter(worktree_id, cx))
5416 .clone()
5417 {
5418 let delegate =
5419 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5420 let path = file
5421 .path()
5422 .parent()
5423 .map(Arc::from)
5424 .unwrap_or_else(|| file.path().clone());
5425 let worktree_path = ProjectPath { worktree_id, path };
5426 let abs_path = file.abs_path(cx);
5427 let nodes = rebase
5428 .walk(
5429 worktree_path,
5430 language.name(),
5431 language.manifest(),
5432 delegate.clone(),
5433 cx,
5434 )
5435 .collect::<Vec<_>>();
5436 for node in nodes {
5437 let server_id = node.server_id_or_init(|disposition| {
5438 let path = &disposition.path;
5439 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5440 let key = LanguageServerSeed {
5441 worktree_id,
5442 name: disposition.server_name.clone(),
5443 settings: LanguageServerSeedSettings {
5444 binary: disposition.settings.binary.clone(),
5445 initialization_options: disposition
5446 .settings
5447 .initialization_options
5448 .clone(),
5449 },
5450 toolchain: local.toolchain_store.read(cx).active_toolchain(
5451 path.worktree_id,
5452 &path.path,
5453 language.name(),
5454 ),
5455 };
5456 local.language_server_ids.remove(&key);
5457
5458 let server_id = local.get_or_insert_language_server(
5459 &worktree,
5460 lsp_delegate.clone(),
5461 disposition,
5462 &language.name(),
5463 cx,
5464 );
5465 if let Some(state) = local.language_servers.get(&server_id)
5466 && let Ok(uri) = uri
5467 {
5468 state.add_workspace_folder(uri);
5469 };
5470 server_id
5471 });
5472
5473 if let Some(language_server_id) = server_id {
5474 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5475 language_server_id,
5476 name: node.name(),
5477 message:
5478 proto::update_language_server::Variant::RegisteredForBuffer(
5479 proto::RegisteredForBuffer {
5480 buffer_abs_path: abs_path
5481 .to_string_lossy()
5482 .into_owned(),
5483 buffer_id: buffer_id.to_proto(),
5484 },
5485 ),
5486 });
5487 }
5488 }
5489 } else {
5490 continue;
5491 }
5492 }
5493 rebase.finish()
5494 };
5495 for message in messages_to_report {
5496 cx.emit(message);
5497 }
5498 local.lsp_tree = new_tree;
5499 for (id, _) in to_stop {
5500 self.stop_local_language_server(id, cx).detach();
5501 }
5502 }
5503
5504 pub fn apply_code_action(
5505 &self,
5506 buffer_handle: Entity<Buffer>,
5507 mut action: CodeAction,
5508 push_to_history: bool,
5509 cx: &mut Context<Self>,
5510 ) -> Task<Result<ProjectTransaction>> {
5511 if let Some((upstream_client, project_id)) = self.upstream_client() {
5512 let request = proto::ApplyCodeAction {
5513 project_id,
5514 buffer_id: buffer_handle.read(cx).remote_id().into(),
5515 action: Some(Self::serialize_code_action(&action)),
5516 };
5517 let buffer_store = self.buffer_store();
5518 cx.spawn(async move |_, cx| {
5519 let response = upstream_client
5520 .request(request)
5521 .await?
5522 .transaction
5523 .context("missing transaction")?;
5524
5525 buffer_store
5526 .update(cx, |buffer_store, cx| {
5527 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5528 })
5529 .await
5530 })
5531 } else if self.mode.is_local() {
5532 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5533 let request_timeout = ProjectSettings::get_global(cx)
5534 .global_lsp_settings
5535 .get_request_timeout();
5536 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5537 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5538 }) else {
5539 return Task::ready(Ok(ProjectTransaction::default()));
5540 };
5541
5542 cx.spawn(async move |this, cx| {
5543 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5544 .await
5545 .context("resolving a code action")?;
5546 if let Some(edit) = action.lsp_action.edit()
5547 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5548 return LocalLspStore::deserialize_workspace_edit(
5549 this.upgrade().context("no app present")?,
5550 edit.clone(),
5551 push_to_history,
5552
5553 lang_server.clone(),
5554 cx,
5555 )
5556 .await;
5557 }
5558
5559 let Some(command) = action.lsp_action.command() else {
5560 return Ok(ProjectTransaction::default())
5561 };
5562
5563 let server_capabilities = lang_server.capabilities();
5564 let available_commands = server_capabilities
5565 .execute_command_provider
5566 .as_ref()
5567 .map(|options| options.commands.as_slice())
5568 .unwrap_or_default();
5569
5570 if !available_commands.contains(&command.command) {
5571 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5572 return Ok(ProjectTransaction::default())
5573 }
5574
5575 let request_timeout = cx.update(|app|
5576 ProjectSettings::get_global(app)
5577 .global_lsp_settings
5578 .get_request_timeout()
5579 );
5580
5581 this.update(cx, |this, _| {
5582 this.as_local_mut()
5583 .unwrap()
5584 .last_workspace_edits_by_language_server
5585 .remove(&lang_server.server_id());
5586 })?;
5587
5588 let _result = lang_server
5589 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5590 command: command.command.clone(),
5591 arguments: command.arguments.clone().unwrap_or_default(),
5592 ..lsp::ExecuteCommandParams::default()
5593 }, request_timeout)
5594 .await.into_response()
5595 .context("execute command")?;
5596
5597 return this.update(cx, |this, _| {
5598 this.as_local_mut()
5599 .unwrap()
5600 .last_workspace_edits_by_language_server
5601 .remove(&lang_server.server_id())
5602 .unwrap_or_default()
5603 });
5604 })
5605 } else {
5606 Task::ready(Err(anyhow!("no upstream client and not local")))
5607 }
5608 }
5609
5610 pub fn apply_code_action_kind(
5611 &mut self,
5612 buffers: HashSet<Entity<Buffer>>,
5613 kind: CodeActionKind,
5614 push_to_history: bool,
5615 cx: &mut Context<Self>,
5616 ) -> Task<anyhow::Result<ProjectTransaction>> {
5617 if self.as_local().is_some() {
5618 cx.spawn(async move |lsp_store, cx| {
5619 let buffers = buffers.into_iter().collect::<Vec<_>>();
5620 let result = LocalLspStore::execute_code_action_kind_locally(
5621 lsp_store.clone(),
5622 buffers,
5623 kind,
5624 push_to_history,
5625 cx,
5626 )
5627 .await;
5628 lsp_store.update(cx, |lsp_store, _| {
5629 lsp_store.update_last_formatting_failure(&result);
5630 })?;
5631 result
5632 })
5633 } else if let Some((client, project_id)) = self.upstream_client() {
5634 let buffer_store = self.buffer_store();
5635 cx.spawn(async move |lsp_store, cx| {
5636 let result = client
5637 .request(proto::ApplyCodeActionKind {
5638 project_id,
5639 kind: kind.as_str().to_owned(),
5640 buffer_ids: buffers
5641 .iter()
5642 .map(|buffer| {
5643 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5644 })
5645 .collect(),
5646 })
5647 .await
5648 .and_then(|result| result.transaction.context("missing transaction"));
5649 lsp_store.update(cx, |lsp_store, _| {
5650 lsp_store.update_last_formatting_failure(&result);
5651 })?;
5652
5653 let transaction_response = result?;
5654 buffer_store
5655 .update(cx, |buffer_store, cx| {
5656 buffer_store.deserialize_project_transaction(
5657 transaction_response,
5658 push_to_history,
5659 cx,
5660 )
5661 })
5662 .await
5663 })
5664 } else {
5665 Task::ready(Ok(ProjectTransaction::default()))
5666 }
5667 }
5668
5669 pub fn resolved_hint(
5670 &mut self,
5671 buffer_id: BufferId,
5672 id: InlayId,
5673 cx: &mut Context<Self>,
5674 ) -> Option<ResolvedHint> {
5675 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5676
5677 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5678 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5679 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5680 let (server_id, resolve_data) = match &hint.resolve_state {
5681 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5682 ResolveState::Resolving => {
5683 return Some(ResolvedHint::Resolving(
5684 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5685 ));
5686 }
5687 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5688 };
5689
5690 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5691 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5692 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5693 id,
5694 cx.spawn(async move |lsp_store, cx| {
5695 let resolved_hint = resolve_task.await;
5696 lsp_store
5697 .update(cx, |lsp_store, _| {
5698 if let Some(old_inlay_hint) = lsp_store
5699 .lsp_data
5700 .get_mut(&buffer_id)
5701 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5702 {
5703 match resolved_hint {
5704 Ok(resolved_hint) => {
5705 *old_inlay_hint = resolved_hint;
5706 }
5707 Err(e) => {
5708 old_inlay_hint.resolve_state =
5709 ResolveState::CanResolve(server_id, resolve_data);
5710 log::error!("Inlay hint resolve failed: {e:#}");
5711 }
5712 }
5713 }
5714 })
5715 .ok();
5716 })
5717 .shared(),
5718 );
5719 debug_assert!(
5720 previous_task.is_none(),
5721 "Did not change hint's resolve state after spawning its resolve"
5722 );
5723 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5724 None
5725 }
5726
5727 pub(crate) fn linked_edits(
5728 &mut self,
5729 buffer: &Entity<Buffer>,
5730 position: Anchor,
5731 cx: &mut Context<Self>,
5732 ) -> Task<Result<Vec<Range<Anchor>>>> {
5733 let snapshot = buffer.read(cx).snapshot();
5734 let scope = snapshot.language_scope_at(position);
5735 let Some(server_id) = self
5736 .as_local()
5737 .and_then(|local| {
5738 buffer.update(cx, |buffer, cx| {
5739 local
5740 .language_servers_for_buffer(buffer, cx)
5741 .filter(|(_, server)| {
5742 LinkedEditingRange::check_server_capabilities(server.capabilities())
5743 })
5744 .filter(|(adapter, _)| {
5745 scope
5746 .as_ref()
5747 .map(|scope| scope.language_allowed(&adapter.name))
5748 .unwrap_or(true)
5749 })
5750 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5751 .next()
5752 })
5753 })
5754 .or_else(|| {
5755 self.upstream_client()
5756 .is_some()
5757 .then_some(LanguageServerToQuery::FirstCapable)
5758 })
5759 .filter(|_| {
5760 maybe!({
5761 buffer.read(cx).language_at(position)?;
5762 Some(
5763 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5764 .linked_edits,
5765 )
5766 }) == Some(true)
5767 })
5768 else {
5769 return Task::ready(Ok(Vec::new()));
5770 };
5771
5772 self.request_lsp(
5773 buffer.clone(),
5774 server_id,
5775 LinkedEditingRange { position },
5776 cx,
5777 )
5778 }
5779
5780 fn apply_on_type_formatting(
5781 &mut self,
5782 buffer: Entity<Buffer>,
5783 position: Anchor,
5784 trigger: String,
5785 cx: &mut Context<Self>,
5786 ) -> Task<Result<Option<Transaction>>> {
5787 if let Some((client, project_id)) = self.upstream_client() {
5788 if !self.check_if_capable_for_proto_request(
5789 &buffer,
5790 |capabilities| {
5791 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5792 },
5793 cx,
5794 ) {
5795 return Task::ready(Ok(None));
5796 }
5797 let request = proto::OnTypeFormatting {
5798 project_id,
5799 buffer_id: buffer.read(cx).remote_id().into(),
5800 position: Some(serialize_anchor(&position)),
5801 trigger,
5802 version: serialize_version(&buffer.read(cx).version()),
5803 };
5804 cx.background_spawn(async move {
5805 client
5806 .request(request)
5807 .await?
5808 .transaction
5809 .map(language::proto::deserialize_transaction)
5810 .transpose()
5811 })
5812 } else if let Some(local) = self.as_local_mut() {
5813 let buffer_id = buffer.read(cx).remote_id();
5814 local.buffers_being_formatted.insert(buffer_id);
5815 cx.spawn(async move |this, cx| {
5816 let _cleanup = defer({
5817 let this = this.clone();
5818 let mut cx = cx.clone();
5819 move || {
5820 this.update(&mut cx, |this, _| {
5821 if let Some(local) = this.as_local_mut() {
5822 local.buffers_being_formatted.remove(&buffer_id);
5823 }
5824 })
5825 .ok();
5826 }
5827 });
5828
5829 buffer
5830 .update(cx, |buffer, _| {
5831 buffer.wait_for_edits(Some(position.timestamp()))
5832 })
5833 .await?;
5834 this.update(cx, |this, cx| {
5835 let position = position.to_point_utf16(buffer.read(cx));
5836 this.on_type_format(buffer, position, trigger, false, cx)
5837 })?
5838 .await
5839 })
5840 } else {
5841 Task::ready(Err(anyhow!("No upstream client or local language server")))
5842 }
5843 }
5844
5845 pub fn on_type_format<T: ToPointUtf16>(
5846 &mut self,
5847 buffer: Entity<Buffer>,
5848 position: T,
5849 trigger: String,
5850 push_to_history: bool,
5851 cx: &mut Context<Self>,
5852 ) -> Task<Result<Option<Transaction>>> {
5853 let position = position.to_point_utf16(buffer.read(cx));
5854 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5855 }
5856
5857 fn on_type_format_impl(
5858 &mut self,
5859 buffer: Entity<Buffer>,
5860 position: PointUtf16,
5861 trigger: String,
5862 push_to_history: bool,
5863 cx: &mut Context<Self>,
5864 ) -> Task<Result<Option<Transaction>>> {
5865 let options = buffer.update(cx, |buffer, cx| {
5866 lsp_command::lsp_formatting_options(
5867 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5868 )
5869 });
5870
5871 cx.spawn(async move |this, cx| {
5872 if let Some(waiter) =
5873 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5874 {
5875 waiter.await?;
5876 }
5877 cx.update(|cx| {
5878 this.update(cx, |this, cx| {
5879 this.request_lsp(
5880 buffer.clone(),
5881 LanguageServerToQuery::FirstCapable,
5882 OnTypeFormatting {
5883 position,
5884 trigger,
5885 options,
5886 push_to_history,
5887 },
5888 cx,
5889 )
5890 })
5891 })?
5892 .await
5893 })
5894 }
5895
5896 pub fn definitions(
5897 &mut self,
5898 buffer: &Entity<Buffer>,
5899 position: PointUtf16,
5900 cx: &mut Context<Self>,
5901 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5902 if let Some((upstream_client, project_id)) = self.upstream_client() {
5903 let request = GetDefinitions { position };
5904 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5905 return Task::ready(Ok(None));
5906 }
5907
5908 let request_timeout = ProjectSettings::get_global(cx)
5909 .global_lsp_settings
5910 .get_request_timeout();
5911
5912 let request_task = upstream_client.request_lsp(
5913 project_id,
5914 None,
5915 request_timeout,
5916 cx.background_executor().clone(),
5917 request.to_proto(project_id, buffer.read(cx)),
5918 );
5919 let buffer = buffer.clone();
5920 cx.spawn(async move |weak_lsp_store, cx| {
5921 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5922 return Ok(None);
5923 };
5924 let Some(responses) = request_task.await? else {
5925 return Ok(None);
5926 };
5927 let actions = join_all(responses.payload.into_iter().map(|response| {
5928 GetDefinitions { position }.response_from_proto(
5929 response.response,
5930 lsp_store.clone(),
5931 buffer.clone(),
5932 cx.clone(),
5933 )
5934 }))
5935 .await;
5936
5937 Ok(Some(
5938 actions
5939 .into_iter()
5940 .collect::<Result<Vec<Vec<_>>>>()?
5941 .into_iter()
5942 .flatten()
5943 .dedup()
5944 .collect(),
5945 ))
5946 })
5947 } else {
5948 let definitions_task = self.request_multiple_lsp_locally(
5949 buffer,
5950 Some(position),
5951 GetDefinitions { position },
5952 cx,
5953 );
5954 cx.background_spawn(async move {
5955 Ok(Some(
5956 definitions_task
5957 .await
5958 .into_iter()
5959 .flat_map(|(_, definitions)| definitions)
5960 .dedup()
5961 .collect(),
5962 ))
5963 })
5964 }
5965 }
5966
5967 pub fn declarations(
5968 &mut self,
5969 buffer: &Entity<Buffer>,
5970 position: PointUtf16,
5971 cx: &mut Context<Self>,
5972 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5973 if let Some((upstream_client, project_id)) = self.upstream_client() {
5974 let request = GetDeclarations { position };
5975 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5976 return Task::ready(Ok(None));
5977 }
5978 let request_timeout = ProjectSettings::get_global(cx)
5979 .global_lsp_settings
5980 .get_request_timeout();
5981 let request_task = upstream_client.request_lsp(
5982 project_id,
5983 None,
5984 request_timeout,
5985 cx.background_executor().clone(),
5986 request.to_proto(project_id, buffer.read(cx)),
5987 );
5988 let buffer = buffer.clone();
5989 cx.spawn(async move |weak_lsp_store, cx| {
5990 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5991 return Ok(None);
5992 };
5993 let Some(responses) = request_task.await? else {
5994 return Ok(None);
5995 };
5996 let actions = join_all(responses.payload.into_iter().map(|response| {
5997 GetDeclarations { position }.response_from_proto(
5998 response.response,
5999 lsp_store.clone(),
6000 buffer.clone(),
6001 cx.clone(),
6002 )
6003 }))
6004 .await;
6005
6006 Ok(Some(
6007 actions
6008 .into_iter()
6009 .collect::<Result<Vec<Vec<_>>>>()?
6010 .into_iter()
6011 .flatten()
6012 .dedup()
6013 .collect(),
6014 ))
6015 })
6016 } else {
6017 let declarations_task = self.request_multiple_lsp_locally(
6018 buffer,
6019 Some(position),
6020 GetDeclarations { position },
6021 cx,
6022 );
6023 cx.background_spawn(async move {
6024 Ok(Some(
6025 declarations_task
6026 .await
6027 .into_iter()
6028 .flat_map(|(_, declarations)| declarations)
6029 .dedup()
6030 .collect(),
6031 ))
6032 })
6033 }
6034 }
6035
6036 pub fn type_definitions(
6037 &mut self,
6038 buffer: &Entity<Buffer>,
6039 position: PointUtf16,
6040 cx: &mut Context<Self>,
6041 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6042 if let Some((upstream_client, project_id)) = self.upstream_client() {
6043 let request = GetTypeDefinitions { position };
6044 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6045 return Task::ready(Ok(None));
6046 }
6047 let request_timeout = ProjectSettings::get_global(cx)
6048 .global_lsp_settings
6049 .get_request_timeout();
6050 let request_task = upstream_client.request_lsp(
6051 project_id,
6052 None,
6053 request_timeout,
6054 cx.background_executor().clone(),
6055 request.to_proto(project_id, buffer.read(cx)),
6056 );
6057 let buffer = buffer.clone();
6058 cx.spawn(async move |weak_lsp_store, cx| {
6059 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6060 return Ok(None);
6061 };
6062 let Some(responses) = request_task.await? else {
6063 return Ok(None);
6064 };
6065 let actions = join_all(responses.payload.into_iter().map(|response| {
6066 GetTypeDefinitions { position }.response_from_proto(
6067 response.response,
6068 lsp_store.clone(),
6069 buffer.clone(),
6070 cx.clone(),
6071 )
6072 }))
6073 .await;
6074
6075 Ok(Some(
6076 actions
6077 .into_iter()
6078 .collect::<Result<Vec<Vec<_>>>>()?
6079 .into_iter()
6080 .flatten()
6081 .dedup()
6082 .collect(),
6083 ))
6084 })
6085 } else {
6086 let type_definitions_task = self.request_multiple_lsp_locally(
6087 buffer,
6088 Some(position),
6089 GetTypeDefinitions { position },
6090 cx,
6091 );
6092 cx.background_spawn(async move {
6093 Ok(Some(
6094 type_definitions_task
6095 .await
6096 .into_iter()
6097 .flat_map(|(_, type_definitions)| type_definitions)
6098 .dedup()
6099 .collect(),
6100 ))
6101 })
6102 }
6103 }
6104
6105 pub fn implementations(
6106 &mut self,
6107 buffer: &Entity<Buffer>,
6108 position: PointUtf16,
6109 cx: &mut Context<Self>,
6110 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6111 if let Some((upstream_client, project_id)) = self.upstream_client() {
6112 let request = GetImplementations { position };
6113 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6114 return Task::ready(Ok(None));
6115 }
6116
6117 let request_timeout = ProjectSettings::get_global(cx)
6118 .global_lsp_settings
6119 .get_request_timeout();
6120 let request_task = upstream_client.request_lsp(
6121 project_id,
6122 None,
6123 request_timeout,
6124 cx.background_executor().clone(),
6125 request.to_proto(project_id, buffer.read(cx)),
6126 );
6127 let buffer = buffer.clone();
6128 cx.spawn(async move |weak_lsp_store, cx| {
6129 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6130 return Ok(None);
6131 };
6132 let Some(responses) = request_task.await? else {
6133 return Ok(None);
6134 };
6135 let actions = join_all(responses.payload.into_iter().map(|response| {
6136 GetImplementations { position }.response_from_proto(
6137 response.response,
6138 lsp_store.clone(),
6139 buffer.clone(),
6140 cx.clone(),
6141 )
6142 }))
6143 .await;
6144
6145 Ok(Some(
6146 actions
6147 .into_iter()
6148 .collect::<Result<Vec<Vec<_>>>>()?
6149 .into_iter()
6150 .flatten()
6151 .dedup()
6152 .collect(),
6153 ))
6154 })
6155 } else {
6156 let implementations_task = self.request_multiple_lsp_locally(
6157 buffer,
6158 Some(position),
6159 GetImplementations { position },
6160 cx,
6161 );
6162 cx.background_spawn(async move {
6163 Ok(Some(
6164 implementations_task
6165 .await
6166 .into_iter()
6167 .flat_map(|(_, implementations)| implementations)
6168 .dedup()
6169 .collect(),
6170 ))
6171 })
6172 }
6173 }
6174
6175 pub fn references(
6176 &mut self,
6177 buffer: &Entity<Buffer>,
6178 position: PointUtf16,
6179 cx: &mut Context<Self>,
6180 ) -> Task<Result<Option<Vec<Location>>>> {
6181 if let Some((upstream_client, project_id)) = self.upstream_client() {
6182 let request = GetReferences { position };
6183 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6184 return Task::ready(Ok(None));
6185 }
6186
6187 let request_timeout = ProjectSettings::get_global(cx)
6188 .global_lsp_settings
6189 .get_request_timeout();
6190 let request_task = upstream_client.request_lsp(
6191 project_id,
6192 None,
6193 request_timeout,
6194 cx.background_executor().clone(),
6195 request.to_proto(project_id, buffer.read(cx)),
6196 );
6197 let buffer = buffer.clone();
6198 cx.spawn(async move |weak_lsp_store, cx| {
6199 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6200 return Ok(None);
6201 };
6202 let Some(responses) = request_task.await? else {
6203 return Ok(None);
6204 };
6205
6206 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6207 GetReferences { position }.response_from_proto(
6208 lsp_response.response,
6209 lsp_store.clone(),
6210 buffer.clone(),
6211 cx.clone(),
6212 )
6213 }))
6214 .await
6215 .into_iter()
6216 .collect::<Result<Vec<Vec<_>>>>()?
6217 .into_iter()
6218 .flatten()
6219 .dedup()
6220 .collect();
6221 Ok(Some(locations))
6222 })
6223 } else {
6224 let references_task = self.request_multiple_lsp_locally(
6225 buffer,
6226 Some(position),
6227 GetReferences { position },
6228 cx,
6229 );
6230 cx.background_spawn(async move {
6231 Ok(Some(
6232 references_task
6233 .await
6234 .into_iter()
6235 .flat_map(|(_, references)| references)
6236 .dedup()
6237 .collect(),
6238 ))
6239 })
6240 }
6241 }
6242
6243 pub fn code_actions(
6244 &mut self,
6245 buffer: &Entity<Buffer>,
6246 range: Range<Anchor>,
6247 kinds: Option<Vec<CodeActionKind>>,
6248 cx: &mut Context<Self>,
6249 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6250 if let Some((upstream_client, project_id)) = self.upstream_client() {
6251 let request = GetCodeActions {
6252 range: range.clone(),
6253 kinds: kinds.clone(),
6254 };
6255 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6256 return Task::ready(Ok(None));
6257 }
6258 let request_timeout = ProjectSettings::get_global(cx)
6259 .global_lsp_settings
6260 .get_request_timeout();
6261 let request_task = upstream_client.request_lsp(
6262 project_id,
6263 None,
6264 request_timeout,
6265 cx.background_executor().clone(),
6266 request.to_proto(project_id, buffer.read(cx)),
6267 );
6268 let buffer = buffer.clone();
6269 cx.spawn(async move |weak_lsp_store, cx| {
6270 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6271 return Ok(None);
6272 };
6273 let Some(responses) = request_task.await? else {
6274 return Ok(None);
6275 };
6276 let actions = join_all(responses.payload.into_iter().map(|response| {
6277 GetCodeActions {
6278 range: range.clone(),
6279 kinds: kinds.clone(),
6280 }
6281 .response_from_proto(
6282 response.response,
6283 lsp_store.clone(),
6284 buffer.clone(),
6285 cx.clone(),
6286 )
6287 }))
6288 .await;
6289
6290 Ok(Some(
6291 actions
6292 .into_iter()
6293 .collect::<Result<Vec<Vec<_>>>>()?
6294 .into_iter()
6295 .flatten()
6296 .collect(),
6297 ))
6298 })
6299 } else {
6300 let all_actions_task = self.request_multiple_lsp_locally(
6301 buffer,
6302 Some(range.start),
6303 GetCodeActions { range, kinds },
6304 cx,
6305 );
6306 cx.background_spawn(async move {
6307 Ok(Some(
6308 all_actions_task
6309 .await
6310 .into_iter()
6311 .flat_map(|(_, actions)| actions)
6312 .collect(),
6313 ))
6314 })
6315 }
6316 }
6317
6318 #[inline(never)]
6319 pub fn completions(
6320 &self,
6321 buffer: &Entity<Buffer>,
6322 position: PointUtf16,
6323 context: CompletionContext,
6324 cx: &mut Context<Self>,
6325 ) -> Task<Result<Vec<CompletionResponse>>> {
6326 let language_registry = self.languages.clone();
6327
6328 if let Some((upstream_client, project_id)) = self.upstream_client() {
6329 let snapshot = buffer.read(cx).snapshot();
6330 let offset = position.to_offset(&snapshot);
6331 let scope = snapshot.language_scope_at(offset);
6332 let capable_lsps = self.all_capable_for_proto_request(
6333 buffer,
6334 |server_name, capabilities| {
6335 capabilities.completion_provider.is_some()
6336 && scope
6337 .as_ref()
6338 .map(|scope| scope.language_allowed(server_name))
6339 .unwrap_or(true)
6340 },
6341 cx,
6342 );
6343 if capable_lsps.is_empty() {
6344 return Task::ready(Ok(Vec::new()));
6345 }
6346
6347 let language = buffer.read(cx).language().cloned();
6348
6349 let buffer = buffer.clone();
6350
6351 cx.spawn(async move |this, cx| {
6352 let requests = join_all(
6353 capable_lsps
6354 .into_iter()
6355 .map(|(id, server_name)| {
6356 let request = GetCompletions {
6357 position,
6358 context: context.clone(),
6359 server_id: Some(id),
6360 };
6361 let buffer = buffer.clone();
6362 let language = language.clone();
6363 let lsp_adapter = language.as_ref().and_then(|language| {
6364 let adapters = language_registry.lsp_adapters(&language.name());
6365 adapters
6366 .iter()
6367 .find(|adapter| adapter.name() == server_name)
6368 .or_else(|| adapters.first())
6369 .cloned()
6370 });
6371 let upstream_client = upstream_client.clone();
6372 let response = this
6373 .update(cx, |this, cx| {
6374 this.send_lsp_proto_request(
6375 buffer,
6376 upstream_client,
6377 project_id,
6378 request,
6379 cx,
6380 )
6381 })
6382 .log_err();
6383 async move {
6384 let response = response?.await.log_err()?;
6385
6386 let completions = populate_labels_for_completions(
6387 response.completions,
6388 language,
6389 lsp_adapter,
6390 )
6391 .await;
6392
6393 Some(CompletionResponse {
6394 completions,
6395 display_options: CompletionDisplayOptions::default(),
6396 is_incomplete: response.is_incomplete,
6397 })
6398 }
6399 })
6400 .collect::<Vec<_>>(),
6401 );
6402 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6403 })
6404 } else if let Some(local) = self.as_local() {
6405 let snapshot = buffer.read(cx).snapshot();
6406 let offset = position.to_offset(&snapshot);
6407 let scope = snapshot.language_scope_at(offset);
6408 let language = snapshot.language().cloned();
6409 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6410 .completions
6411 .clone();
6412 if !completion_settings.lsp {
6413 return Task::ready(Ok(Vec::new()));
6414 }
6415
6416 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6417 local
6418 .language_servers_for_buffer(buffer, cx)
6419 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6420 .filter(|(adapter, _)| {
6421 scope
6422 .as_ref()
6423 .map(|scope| scope.language_allowed(&adapter.name))
6424 .unwrap_or(true)
6425 })
6426 .map(|(_, server)| server.server_id())
6427 .collect()
6428 });
6429
6430 let buffer = buffer.clone();
6431 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6432 let lsp_timeout = if lsp_timeout > 0 {
6433 Some(Duration::from_millis(lsp_timeout))
6434 } else {
6435 None
6436 };
6437 cx.spawn(async move |this, cx| {
6438 let mut tasks = Vec::with_capacity(server_ids.len());
6439 this.update(cx, |lsp_store, cx| {
6440 for server_id in server_ids {
6441 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6442 let lsp_timeout = lsp_timeout
6443 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6444 let mut timeout = cx.background_spawn(async move {
6445 match lsp_timeout {
6446 Some(lsp_timeout) => {
6447 lsp_timeout.await;
6448 true
6449 },
6450 None => false,
6451 }
6452 }).fuse();
6453 let mut lsp_request = lsp_store.request_lsp(
6454 buffer.clone(),
6455 LanguageServerToQuery::Other(server_id),
6456 GetCompletions {
6457 position,
6458 context: context.clone(),
6459 server_id: Some(server_id),
6460 },
6461 cx,
6462 ).fuse();
6463 let new_task = cx.background_spawn(async move {
6464 select_biased! {
6465 response = lsp_request => anyhow::Ok(Some(response?)),
6466 timeout_happened = timeout => {
6467 if timeout_happened {
6468 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6469 Ok(None)
6470 } else {
6471 let completions = lsp_request.await?;
6472 Ok(Some(completions))
6473 }
6474 },
6475 }
6476 });
6477 tasks.push((lsp_adapter, new_task));
6478 }
6479 })?;
6480
6481 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6482 let completion_response = task.await.ok()??;
6483 let completions = populate_labels_for_completions(
6484 completion_response.completions,
6485 language.clone(),
6486 lsp_adapter,
6487 )
6488 .await;
6489 Some(CompletionResponse {
6490 completions,
6491 display_options: CompletionDisplayOptions::default(),
6492 is_incomplete: completion_response.is_incomplete,
6493 })
6494 });
6495
6496 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6497
6498 Ok(responses.into_iter().flatten().collect())
6499 })
6500 } else {
6501 Task::ready(Err(anyhow!("No upstream client or local language server")))
6502 }
6503 }
6504
6505 pub fn resolve_completions(
6506 &self,
6507 buffer: Entity<Buffer>,
6508 completion_indices: Vec<usize>,
6509 completions: Rc<RefCell<Box<[Completion]>>>,
6510 cx: &mut Context<Self>,
6511 ) -> Task<Result<bool>> {
6512 let client = self.upstream_client();
6513 let buffer_id = buffer.read(cx).remote_id();
6514 let buffer_snapshot = buffer.read(cx).snapshot();
6515
6516 if !self.check_if_capable_for_proto_request(
6517 &buffer,
6518 GetCompletions::can_resolve_completions,
6519 cx,
6520 ) {
6521 return Task::ready(Ok(false));
6522 }
6523 cx.spawn(async move |lsp_store, cx| {
6524 let request_timeout = cx.update(|app| {
6525 ProjectSettings::get_global(app)
6526 .global_lsp_settings
6527 .get_request_timeout()
6528 });
6529
6530 let mut did_resolve = false;
6531 if let Some((client, project_id)) = client {
6532 for completion_index in completion_indices {
6533 let server_id = {
6534 let completion = &completions.borrow()[completion_index];
6535 completion.source.server_id()
6536 };
6537 if let Some(server_id) = server_id {
6538 if Self::resolve_completion_remote(
6539 project_id,
6540 server_id,
6541 buffer_id,
6542 completions.clone(),
6543 completion_index,
6544 client.clone(),
6545 )
6546 .await
6547 .log_err()
6548 .is_some()
6549 {
6550 did_resolve = true;
6551 }
6552 } else {
6553 resolve_word_completion(
6554 &buffer_snapshot,
6555 &mut completions.borrow_mut()[completion_index],
6556 );
6557 }
6558 }
6559 } else {
6560 for completion_index in completion_indices {
6561 let server_id = {
6562 let completion = &completions.borrow()[completion_index];
6563 completion.source.server_id()
6564 };
6565 if let Some(server_id) = server_id {
6566 let server_and_adapter = lsp_store
6567 .read_with(cx, |lsp_store, _| {
6568 let server = lsp_store.language_server_for_id(server_id)?;
6569 let adapter =
6570 lsp_store.language_server_adapter_for_id(server.server_id())?;
6571 Some((server, adapter))
6572 })
6573 .ok()
6574 .flatten();
6575 let Some((server, adapter)) = server_and_adapter else {
6576 continue;
6577 };
6578
6579 let resolved = Self::resolve_completion_local(
6580 server,
6581 completions.clone(),
6582 completion_index,
6583 request_timeout,
6584 )
6585 .await
6586 .log_err()
6587 .is_some();
6588 if resolved {
6589 Self::regenerate_completion_labels(
6590 adapter,
6591 &buffer_snapshot,
6592 completions.clone(),
6593 completion_index,
6594 )
6595 .await
6596 .log_err();
6597 did_resolve = true;
6598 }
6599 } else {
6600 resolve_word_completion(
6601 &buffer_snapshot,
6602 &mut completions.borrow_mut()[completion_index],
6603 );
6604 }
6605 }
6606 }
6607
6608 Ok(did_resolve)
6609 })
6610 }
6611
6612 async fn resolve_completion_local(
6613 server: Arc<lsp::LanguageServer>,
6614 completions: Rc<RefCell<Box<[Completion]>>>,
6615 completion_index: usize,
6616 request_timeout: Duration,
6617 ) -> Result<()> {
6618 let server_id = server.server_id();
6619 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6620 return Ok(());
6621 }
6622
6623 let request = {
6624 let completion = &completions.borrow()[completion_index];
6625 match &completion.source {
6626 CompletionSource::Lsp {
6627 lsp_completion,
6628 resolved,
6629 server_id: completion_server_id,
6630 ..
6631 } => {
6632 if *resolved {
6633 return Ok(());
6634 }
6635 anyhow::ensure!(
6636 server_id == *completion_server_id,
6637 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6638 );
6639 server.request::<lsp::request::ResolveCompletionItem>(
6640 *lsp_completion.clone(),
6641 request_timeout,
6642 )
6643 }
6644 CompletionSource::BufferWord { .. }
6645 | CompletionSource::Dap { .. }
6646 | CompletionSource::Custom => {
6647 return Ok(());
6648 }
6649 }
6650 };
6651 let resolved_completion = request
6652 .await
6653 .into_response()
6654 .context("resolve completion")?;
6655
6656 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6657 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6658
6659 let mut completions = completions.borrow_mut();
6660 let completion = &mut completions[completion_index];
6661 if let CompletionSource::Lsp {
6662 lsp_completion,
6663 resolved,
6664 server_id: completion_server_id,
6665 ..
6666 } = &mut completion.source
6667 {
6668 if *resolved {
6669 return Ok(());
6670 }
6671 anyhow::ensure!(
6672 server_id == *completion_server_id,
6673 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6674 );
6675 **lsp_completion = resolved_completion;
6676 *resolved = true;
6677 }
6678 Ok(())
6679 }
6680
6681 async fn regenerate_completion_labels(
6682 adapter: Arc<CachedLspAdapter>,
6683 snapshot: &BufferSnapshot,
6684 completions: Rc<RefCell<Box<[Completion]>>>,
6685 completion_index: usize,
6686 ) -> Result<()> {
6687 let completion_item = completions.borrow()[completion_index]
6688 .source
6689 .lsp_completion(true)
6690 .map(Cow::into_owned);
6691 if let Some(lsp_documentation) = completion_item
6692 .as_ref()
6693 .and_then(|completion_item| completion_item.documentation.clone())
6694 {
6695 let mut completions = completions.borrow_mut();
6696 let completion = &mut completions[completion_index];
6697 completion.documentation = Some(lsp_documentation.into());
6698 } else {
6699 let mut completions = completions.borrow_mut();
6700 let completion = &mut completions[completion_index];
6701 completion.documentation = Some(CompletionDocumentation::Undocumented);
6702 }
6703
6704 let mut new_label = match completion_item {
6705 Some(completion_item) => {
6706 // Some language servers always return `detail` lazily via resolve, regardless of
6707 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6708 // See: https://github.com/yioneko/vtsls/issues/213
6709 let language = snapshot.language();
6710 match language {
6711 Some(language) => {
6712 adapter
6713 .labels_for_completions(
6714 std::slice::from_ref(&completion_item),
6715 language,
6716 )
6717 .await?
6718 }
6719 None => Vec::new(),
6720 }
6721 .pop()
6722 .flatten()
6723 .unwrap_or_else(|| {
6724 CodeLabel::fallback_for_completion(
6725 &completion_item,
6726 language.map(|language| language.as_ref()),
6727 )
6728 })
6729 }
6730 None => CodeLabel::plain(
6731 completions.borrow()[completion_index].new_text.clone(),
6732 None,
6733 ),
6734 };
6735 ensure_uniform_list_compatible_label(&mut new_label);
6736
6737 let mut completions = completions.borrow_mut();
6738 let completion = &mut completions[completion_index];
6739 if completion.label.filter_text() == new_label.filter_text() {
6740 completion.label = new_label;
6741 } else {
6742 log::error!(
6743 "Resolved completion changed display label from {} to {}. \
6744 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6745 completion.label.text(),
6746 new_label.text(),
6747 completion.label.filter_text(),
6748 new_label.filter_text()
6749 );
6750 }
6751
6752 Ok(())
6753 }
6754
6755 async fn resolve_completion_remote(
6756 project_id: u64,
6757 server_id: LanguageServerId,
6758 buffer_id: BufferId,
6759 completions: Rc<RefCell<Box<[Completion]>>>,
6760 completion_index: usize,
6761 client: AnyProtoClient,
6762 ) -> Result<()> {
6763 let lsp_completion = {
6764 let completion = &completions.borrow()[completion_index];
6765 match &completion.source {
6766 CompletionSource::Lsp {
6767 lsp_completion,
6768 resolved,
6769 server_id: completion_server_id,
6770 ..
6771 } => {
6772 anyhow::ensure!(
6773 server_id == *completion_server_id,
6774 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6775 );
6776 if *resolved {
6777 return Ok(());
6778 }
6779 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6780 }
6781 CompletionSource::Custom
6782 | CompletionSource::Dap { .. }
6783 | CompletionSource::BufferWord { .. } => {
6784 return Ok(());
6785 }
6786 }
6787 };
6788 let request = proto::ResolveCompletionDocumentation {
6789 project_id,
6790 language_server_id: server_id.0 as u64,
6791 lsp_completion,
6792 buffer_id: buffer_id.into(),
6793 };
6794
6795 let response = client
6796 .request(request)
6797 .await
6798 .context("completion documentation resolve proto request")?;
6799 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6800
6801 let documentation = if response.documentation.is_empty() {
6802 CompletionDocumentation::Undocumented
6803 } else if response.documentation_is_markdown {
6804 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6805 } else if response.documentation.lines().count() <= 1 {
6806 CompletionDocumentation::SingleLine(response.documentation.into())
6807 } else {
6808 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6809 };
6810
6811 let mut completions = completions.borrow_mut();
6812 let completion = &mut completions[completion_index];
6813 completion.documentation = Some(documentation);
6814 if let CompletionSource::Lsp {
6815 insert_range,
6816 lsp_completion,
6817 resolved,
6818 server_id: completion_server_id,
6819 lsp_defaults: _,
6820 } = &mut completion.source
6821 {
6822 let completion_insert_range = response
6823 .old_insert_start
6824 .and_then(deserialize_anchor)
6825 .zip(response.old_insert_end.and_then(deserialize_anchor));
6826 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6827
6828 if *resolved {
6829 return Ok(());
6830 }
6831 anyhow::ensure!(
6832 server_id == *completion_server_id,
6833 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6834 );
6835 **lsp_completion = resolved_lsp_completion;
6836 *resolved = true;
6837 }
6838
6839 let replace_range = response
6840 .old_replace_start
6841 .and_then(deserialize_anchor)
6842 .zip(response.old_replace_end.and_then(deserialize_anchor));
6843 if let Some((old_replace_start, old_replace_end)) = replace_range
6844 && !response.new_text.is_empty()
6845 {
6846 completion.new_text = response.new_text;
6847 completion.replace_range = old_replace_start..old_replace_end;
6848 }
6849
6850 Ok(())
6851 }
6852
6853 pub fn apply_additional_edits_for_completion(
6854 &self,
6855 buffer_handle: Entity<Buffer>,
6856 completions: Rc<RefCell<Box<[Completion]>>>,
6857 completion_index: usize,
6858 push_to_history: bool,
6859 all_commit_ranges: Vec<Range<language::Anchor>>,
6860 cx: &mut Context<Self>,
6861 ) -> Task<Result<Option<Transaction>>> {
6862 if let Some((client, project_id)) = self.upstream_client() {
6863 let buffer = buffer_handle.read(cx);
6864 let buffer_id = buffer.remote_id();
6865 cx.spawn(async move |_, cx| {
6866 let request = {
6867 let completion = completions.borrow()[completion_index].clone();
6868 proto::ApplyCompletionAdditionalEdits {
6869 project_id,
6870 buffer_id: buffer_id.into(),
6871 completion: Some(Self::serialize_completion(&CoreCompletion {
6872 replace_range: completion.replace_range,
6873 new_text: completion.new_text,
6874 source: completion.source,
6875 })),
6876 all_commit_ranges: all_commit_ranges
6877 .iter()
6878 .cloned()
6879 .map(language::proto::serialize_anchor_range)
6880 .collect(),
6881 }
6882 };
6883
6884 let Some(transaction) = client.request(request).await?.transaction else {
6885 return Ok(None);
6886 };
6887
6888 let transaction = language::proto::deserialize_transaction(transaction)?;
6889 buffer_handle
6890 .update(cx, |buffer, _| {
6891 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6892 })
6893 .await?;
6894 if push_to_history {
6895 buffer_handle.update(cx, |buffer, _| {
6896 buffer.push_transaction(transaction.clone(), Instant::now());
6897 buffer.finalize_last_transaction();
6898 });
6899 }
6900 Ok(Some(transaction))
6901 })
6902 } else {
6903 let request_timeout = ProjectSettings::get_global(cx)
6904 .global_lsp_settings
6905 .get_request_timeout();
6906
6907 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6908 let completion = &completions.borrow()[completion_index];
6909 let server_id = completion.source.server_id()?;
6910 Some(
6911 self.language_server_for_local_buffer(buffer, server_id, cx)?
6912 .1
6913 .clone(),
6914 )
6915 }) else {
6916 return Task::ready(Ok(None));
6917 };
6918
6919 cx.spawn(async move |this, cx| {
6920 Self::resolve_completion_local(
6921 server.clone(),
6922 completions.clone(),
6923 completion_index,
6924 request_timeout,
6925 )
6926 .await
6927 .context("resolving completion")?;
6928 let completion = completions.borrow()[completion_index].clone();
6929 let additional_text_edits = completion
6930 .source
6931 .lsp_completion(true)
6932 .as_ref()
6933 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6934 if let Some(edits) = additional_text_edits {
6935 let edits = this
6936 .update(cx, |this, cx| {
6937 this.as_local_mut().unwrap().edits_from_lsp(
6938 &buffer_handle,
6939 edits,
6940 server.server_id(),
6941 None,
6942 cx,
6943 )
6944 })?
6945 .await?;
6946
6947 buffer_handle.update(cx, |buffer, cx| {
6948 buffer.finalize_last_transaction();
6949 buffer.start_transaction();
6950
6951 for (range, text) in edits {
6952 let primary = &completion.replace_range;
6953
6954 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6955 // and the primary completion is just an insertion (empty range), then this is likely
6956 // an auto-import scenario and should not be considered overlapping
6957 // https://github.com/zed-industries/zed/issues/26136
6958 let is_file_start_auto_import = {
6959 let snapshot = buffer.snapshot();
6960 let primary_start_point = primary.start.to_point(&snapshot);
6961 let range_start_point = range.start.to_point(&snapshot);
6962
6963 let result = primary_start_point.row == 0
6964 && primary_start_point.column == 0
6965 && range_start_point.row == 0
6966 && range_start_point.column == 0;
6967
6968 result
6969 };
6970
6971 let has_overlap = if is_file_start_auto_import {
6972 false
6973 } else {
6974 all_commit_ranges.iter().any(|commit_range| {
6975 let start_within =
6976 commit_range.start.cmp(&range.start, buffer).is_le()
6977 && commit_range.end.cmp(&range.start, buffer).is_ge();
6978 let end_within =
6979 range.start.cmp(&commit_range.end, buffer).is_le()
6980 && range.end.cmp(&commit_range.end, buffer).is_ge();
6981 start_within || end_within
6982 })
6983 };
6984
6985 //Skip additional edits which overlap with the primary completion edit
6986 //https://github.com/zed-industries/zed/pull/1871
6987 if !has_overlap {
6988 buffer.edit([(range, text)], None, cx);
6989 }
6990 }
6991
6992 let transaction = if buffer.end_transaction(cx).is_some() {
6993 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6994 if !push_to_history {
6995 buffer.forget_transaction(transaction.id);
6996 }
6997 Some(transaction)
6998 } else {
6999 None
7000 };
7001 Ok(transaction)
7002 })
7003 } else {
7004 Ok(None)
7005 }
7006 })
7007 }
7008 }
7009
7010 pub fn pull_diagnostics(
7011 &mut self,
7012 buffer: Entity<Buffer>,
7013 cx: &mut Context<Self>,
7014 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
7015 let buffer_id = buffer.read(cx).remote_id();
7016
7017 if let Some((client, upstream_project_id)) = self.upstream_client() {
7018 let mut suitable_capabilities = None;
7019 // Are we capable for proto request?
7020 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
7021 &buffer,
7022 |capabilities| {
7023 if let Some(caps) = &capabilities.diagnostic_provider {
7024 suitable_capabilities = Some(caps.clone());
7025 true
7026 } else {
7027 false
7028 }
7029 },
7030 cx,
7031 );
7032 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
7033 let Some(dynamic_caps) = suitable_capabilities else {
7034 return Task::ready(Ok(None));
7035 };
7036 assert!(any_server_has_diagnostics_provider);
7037
7038 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
7039 let request = GetDocumentDiagnostics {
7040 previous_result_id: None,
7041 identifier,
7042 registration_id: None,
7043 };
7044 let request_timeout = ProjectSettings::get_global(cx)
7045 .global_lsp_settings
7046 .get_request_timeout();
7047 let request_task = client.request_lsp(
7048 upstream_project_id,
7049 None,
7050 request_timeout,
7051 cx.background_executor().clone(),
7052 request.to_proto(upstream_project_id, buffer.read(cx)),
7053 );
7054 cx.background_spawn(async move {
7055 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
7056 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
7057 // Do not attempt to further process the dummy responses here.
7058 let _response = request_task.await?;
7059 Ok(None)
7060 })
7061 } else {
7062 let servers = buffer.update(cx, |buffer, cx| {
7063 self.running_language_servers_for_local_buffer(buffer, cx)
7064 .map(|(_, server)| server.clone())
7065 .collect::<Vec<_>>()
7066 });
7067
7068 let pull_diagnostics = servers
7069 .into_iter()
7070 .flat_map(|server| {
7071 let result = maybe!({
7072 let local = self.as_local()?;
7073 let server_id = server.server_id();
7074 let providers_with_identifiers = local
7075 .language_server_dynamic_registrations
7076 .get(&server_id)
7077 .into_iter()
7078 .flat_map(|registrations| registrations.diagnostics.clone())
7079 .collect::<Vec<_>>();
7080 Some(
7081 providers_with_identifiers
7082 .into_iter()
7083 .map(|(registration_id, dynamic_caps)| {
7084 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
7085 let registration_id = registration_id.map(SharedString::from);
7086 let result_id = self.result_id_for_buffer_pull(
7087 server_id,
7088 buffer_id,
7089 ®istration_id,
7090 cx,
7091 );
7092 self.request_lsp(
7093 buffer.clone(),
7094 LanguageServerToQuery::Other(server_id),
7095 GetDocumentDiagnostics {
7096 previous_result_id: result_id,
7097 registration_id,
7098 identifier,
7099 },
7100 cx,
7101 )
7102 })
7103 .collect::<Vec<_>>(),
7104 )
7105 });
7106
7107 result.unwrap_or_default()
7108 })
7109 .collect::<Vec<_>>();
7110
7111 cx.background_spawn(async move {
7112 let mut responses = Vec::new();
7113 for diagnostics in join_all(pull_diagnostics).await {
7114 responses.extend(diagnostics?);
7115 }
7116 Ok(Some(responses))
7117 })
7118 }
7119 }
7120
7121 pub fn applicable_inlay_chunks(
7122 &mut self,
7123 buffer: &Entity<Buffer>,
7124 ranges: &[Range<text::Anchor>],
7125 cx: &mut Context<Self>,
7126 ) -> Vec<Range<BufferRow>> {
7127 let buffer_snapshot = buffer.read(cx).snapshot();
7128 let ranges = ranges
7129 .iter()
7130 .map(|range| range.to_point(&buffer_snapshot))
7131 .collect::<Vec<_>>();
7132
7133 self.latest_lsp_data(buffer, cx)
7134 .inlay_hints
7135 .applicable_chunks(ranges.as_slice())
7136 .map(|chunk| chunk.row_range())
7137 .collect()
7138 }
7139
7140 pub fn invalidate_inlay_hints<'a>(
7141 &'a mut self,
7142 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7143 ) {
7144 for buffer_id in for_buffers {
7145 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7146 lsp_data.inlay_hints.clear();
7147 }
7148 }
7149 }
7150
7151 pub fn inlay_hints(
7152 &mut self,
7153 invalidate: InvalidationStrategy,
7154 buffer: Entity<Buffer>,
7155 ranges: Vec<Range<text::Anchor>>,
7156 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7157 cx: &mut Context<Self>,
7158 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7159 let next_hint_id = self.next_hint_id.clone();
7160 let lsp_data = self.latest_lsp_data(&buffer, cx);
7161 let query_version = lsp_data.buffer_version.clone();
7162 let mut lsp_refresh_requested = false;
7163 let for_server = if let InvalidationStrategy::RefreshRequested {
7164 server_id,
7165 request_id,
7166 } = invalidate
7167 {
7168 let invalidated = lsp_data
7169 .inlay_hints
7170 .invalidate_for_server_refresh(server_id, request_id);
7171 lsp_refresh_requested = invalidated;
7172 Some(server_id)
7173 } else {
7174 None
7175 };
7176 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7177 let known_chunks = known_chunks
7178 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7179 .map(|(_, known_chunks)| known_chunks)
7180 .unwrap_or_default();
7181
7182 let buffer_snapshot = buffer.read(cx).snapshot();
7183 let ranges = ranges
7184 .iter()
7185 .map(|range| range.to_point(&buffer_snapshot))
7186 .collect::<Vec<_>>();
7187
7188 let mut hint_fetch_tasks = Vec::new();
7189 let mut cached_inlay_hints = None;
7190 let mut ranges_to_query = None;
7191 let applicable_chunks = existing_inlay_hints
7192 .applicable_chunks(ranges.as_slice())
7193 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7194 .collect::<Vec<_>>();
7195 if applicable_chunks.is_empty() {
7196 return HashMap::default();
7197 }
7198
7199 for row_chunk in applicable_chunks {
7200 match (
7201 existing_inlay_hints
7202 .cached_hints(&row_chunk)
7203 .filter(|_| !lsp_refresh_requested)
7204 .cloned(),
7205 existing_inlay_hints
7206 .fetched_hints(&row_chunk)
7207 .as_ref()
7208 .filter(|_| !lsp_refresh_requested)
7209 .cloned(),
7210 ) {
7211 (None, None) => {
7212 let chunk_range = row_chunk.anchor_range();
7213 ranges_to_query
7214 .get_or_insert_with(Vec::new)
7215 .push((row_chunk, chunk_range));
7216 }
7217 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7218 (Some(cached_hints), None) => {
7219 for (server_id, cached_hints) in cached_hints {
7220 if for_server.is_none_or(|for_server| for_server == server_id) {
7221 cached_inlay_hints
7222 .get_or_insert_with(HashMap::default)
7223 .entry(row_chunk.row_range())
7224 .or_insert_with(HashMap::default)
7225 .entry(server_id)
7226 .or_insert_with(Vec::new)
7227 .extend(cached_hints);
7228 }
7229 }
7230 }
7231 (Some(cached_hints), Some(fetched_hints)) => {
7232 hint_fetch_tasks.push((row_chunk, fetched_hints));
7233 for (server_id, cached_hints) in cached_hints {
7234 if for_server.is_none_or(|for_server| for_server == server_id) {
7235 cached_inlay_hints
7236 .get_or_insert_with(HashMap::default)
7237 .entry(row_chunk.row_range())
7238 .or_insert_with(HashMap::default)
7239 .entry(server_id)
7240 .or_insert_with(Vec::new)
7241 .extend(cached_hints);
7242 }
7243 }
7244 }
7245 }
7246 }
7247
7248 if hint_fetch_tasks.is_empty()
7249 && ranges_to_query
7250 .as_ref()
7251 .is_none_or(|ranges| ranges.is_empty())
7252 && let Some(cached_inlay_hints) = cached_inlay_hints
7253 {
7254 cached_inlay_hints
7255 .into_iter()
7256 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7257 .collect()
7258 } else {
7259 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7260 // When a server refresh was requested, other servers' cached hints
7261 // are unaffected by the refresh and must be included in the result.
7262 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7263 // removes all visible hints but only adds back the requesting
7264 // server's new hints, permanently losing other servers' hints.
7265 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7266 lsp_data
7267 .inlay_hints
7268 .cached_hints(&chunk)
7269 .cloned()
7270 .unwrap_or_default()
7271 } else {
7272 HashMap::default()
7273 };
7274
7275 let next_hint_id = next_hint_id.clone();
7276 let buffer = buffer.clone();
7277 let query_version = query_version.clone();
7278 let new_inlay_hints = cx
7279 .spawn(async move |lsp_store, cx| {
7280 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7281 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7282 })?;
7283 new_fetch_task
7284 .await
7285 .and_then(|new_hints_by_server| {
7286 lsp_store.update(cx, |lsp_store, cx| {
7287 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7288 let update_cache = lsp_data.buffer_version == query_version;
7289 if new_hints_by_server.is_empty() {
7290 if update_cache {
7291 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7292 }
7293 other_servers_cached
7294 } else {
7295 let mut result = other_servers_cached;
7296 for (server_id, new_hints) in new_hints_by_server {
7297 let new_hints = new_hints
7298 .into_iter()
7299 .map(|new_hint| {
7300 (
7301 InlayId::Hint(next_hint_id.fetch_add(
7302 1,
7303 atomic::Ordering::AcqRel,
7304 )),
7305 new_hint,
7306 )
7307 })
7308 .collect::<Vec<_>>();
7309 if update_cache {
7310 lsp_data.inlay_hints.insert_new_hints(
7311 chunk,
7312 server_id,
7313 new_hints.clone(),
7314 );
7315 }
7316 result.insert(server_id, new_hints);
7317 }
7318 result
7319 }
7320 })
7321 })
7322 .map_err(Arc::new)
7323 })
7324 .shared();
7325
7326 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7327 *fetch_task = Some(new_inlay_hints.clone());
7328 hint_fetch_tasks.push((chunk, new_inlay_hints));
7329 }
7330
7331 cached_inlay_hints
7332 .unwrap_or_default()
7333 .into_iter()
7334 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7335 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7336 (
7337 chunk.row_range(),
7338 cx.spawn(async move |_, _| {
7339 hints_fetch.await.map_err(|e| {
7340 if e.error_code() != ErrorCode::Internal {
7341 anyhow!(e.error_code())
7342 } else {
7343 anyhow!("{e:#}")
7344 }
7345 })
7346 }),
7347 )
7348 }))
7349 .collect()
7350 }
7351 }
7352
7353 fn fetch_inlay_hints(
7354 &mut self,
7355 for_server: Option<LanguageServerId>,
7356 buffer: &Entity<Buffer>,
7357 range: Range<Anchor>,
7358 cx: &mut Context<Self>,
7359 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7360 let request = InlayHints {
7361 range: range.clone(),
7362 };
7363 if let Some((upstream_client, project_id)) = self.upstream_client() {
7364 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7365 return Task::ready(Ok(HashMap::default()));
7366 }
7367 let request_timeout = ProjectSettings::get_global(cx)
7368 .global_lsp_settings
7369 .get_request_timeout();
7370 let request_task = upstream_client.request_lsp(
7371 project_id,
7372 for_server.map(|id| id.to_proto()),
7373 request_timeout,
7374 cx.background_executor().clone(),
7375 request.to_proto(project_id, buffer.read(cx)),
7376 );
7377 let buffer = buffer.clone();
7378 cx.spawn(async move |weak_lsp_store, cx| {
7379 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7380 return Ok(HashMap::default());
7381 };
7382 let Some(responses) = request_task.await? else {
7383 return Ok(HashMap::default());
7384 };
7385
7386 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7387 let lsp_store = lsp_store.clone();
7388 let buffer = buffer.clone();
7389 let cx = cx.clone();
7390 let request = request.clone();
7391 async move {
7392 (
7393 LanguageServerId::from_proto(response.server_id),
7394 request
7395 .response_from_proto(response.response, lsp_store, buffer, cx)
7396 .await,
7397 )
7398 }
7399 }))
7400 .await;
7401
7402 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7403 let mut has_errors = false;
7404 let inlay_hints = inlay_hints
7405 .into_iter()
7406 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7407 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7408 Err(e) => {
7409 has_errors = true;
7410 log::error!("{e:#}");
7411 None
7412 }
7413 })
7414 .map(|(server_id, mut new_hints)| {
7415 new_hints.retain(|hint| {
7416 hint.position.is_valid(&buffer_snapshot)
7417 && range.start.is_valid(&buffer_snapshot)
7418 && range.end.is_valid(&buffer_snapshot)
7419 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7420 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7421 });
7422 (server_id, new_hints)
7423 })
7424 .collect::<HashMap<_, _>>();
7425 anyhow::ensure!(
7426 !has_errors || !inlay_hints.is_empty(),
7427 "Failed to fetch inlay hints"
7428 );
7429 Ok(inlay_hints)
7430 })
7431 } else {
7432 let inlay_hints_task = match for_server {
7433 Some(server_id) => {
7434 let server_task = self.request_lsp(
7435 buffer.clone(),
7436 LanguageServerToQuery::Other(server_id),
7437 request,
7438 cx,
7439 );
7440 cx.background_spawn(async move {
7441 let mut responses = Vec::new();
7442 match server_task.await {
7443 Ok(response) => responses.push((server_id, response)),
7444 // rust-analyzer likes to error with this when its still loading up
7445 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7446 Err(e) => log::error!(
7447 "Error handling response for inlay hints request: {e:#}"
7448 ),
7449 }
7450 responses
7451 })
7452 }
7453 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7454 };
7455 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7456 cx.background_spawn(async move {
7457 Ok(inlay_hints_task
7458 .await
7459 .into_iter()
7460 .map(|(server_id, mut new_hints)| {
7461 new_hints.retain(|hint| {
7462 hint.position.is_valid(&buffer_snapshot)
7463 && range.start.is_valid(&buffer_snapshot)
7464 && range.end.is_valid(&buffer_snapshot)
7465 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7466 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7467 });
7468 (server_id, new_hints)
7469 })
7470 .collect())
7471 })
7472 }
7473 }
7474
7475 fn diagnostic_registration_exists(
7476 &self,
7477 server_id: LanguageServerId,
7478 registration_id: &Option<SharedString>,
7479 ) -> bool {
7480 let Some(local) = self.as_local() else {
7481 return false;
7482 };
7483 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7484 else {
7485 return false;
7486 };
7487 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7488 registrations.diagnostics.contains_key(®istration_key)
7489 }
7490
7491 pub fn pull_diagnostics_for_buffer(
7492 &mut self,
7493 buffer: Entity<Buffer>,
7494 cx: &mut Context<Self>,
7495 ) -> Task<anyhow::Result<()>> {
7496 let diagnostics = self.pull_diagnostics(buffer, cx);
7497 cx.spawn(async move |lsp_store, cx| {
7498 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7499 return Ok(());
7500 };
7501 lsp_store.update(cx, |lsp_store, cx| {
7502 if lsp_store.as_local().is_none() {
7503 return;
7504 }
7505
7506 let mut unchanged_buffers = HashMap::default();
7507 let server_diagnostics_updates = diagnostics
7508 .into_iter()
7509 .filter_map(|diagnostics_set| match diagnostics_set {
7510 LspPullDiagnostics::Response {
7511 server_id,
7512 uri,
7513 diagnostics,
7514 registration_id,
7515 } => Some((server_id, uri, diagnostics, registration_id)),
7516 LspPullDiagnostics::Default => None,
7517 })
7518 .filter(|(server_id, _, _, registration_id)| {
7519 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7520 })
7521 .fold(
7522 HashMap::default(),
7523 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7524 let (result_id, diagnostics) = match diagnostics {
7525 PulledDiagnostics::Unchanged { result_id } => {
7526 unchanged_buffers
7527 .entry(new_registration_id.clone())
7528 .or_insert_with(HashSet::default)
7529 .insert(uri.clone());
7530 (Some(result_id), Vec::new())
7531 }
7532 PulledDiagnostics::Changed {
7533 result_id,
7534 diagnostics,
7535 } => (result_id, diagnostics),
7536 };
7537 let disk_based_sources = Cow::Owned(
7538 lsp_store
7539 .language_server_adapter_for_id(server_id)
7540 .as_ref()
7541 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7542 .unwrap_or(&[])
7543 .to_vec(),
7544 );
7545 acc.entry(server_id)
7546 .or_insert_with(HashMap::default)
7547 .entry(new_registration_id.clone())
7548 .or_insert_with(Vec::new)
7549 .push(DocumentDiagnosticsUpdate {
7550 server_id,
7551 diagnostics: lsp::PublishDiagnosticsParams {
7552 uri,
7553 diagnostics,
7554 version: None,
7555 },
7556 result_id: result_id.map(SharedString::new),
7557 disk_based_sources,
7558 registration_id: new_registration_id,
7559 });
7560 acc
7561 },
7562 );
7563
7564 for diagnostic_updates in server_diagnostics_updates.into_values() {
7565 for (registration_id, diagnostic_updates) in diagnostic_updates {
7566 lsp_store
7567 .merge_lsp_diagnostics(
7568 DiagnosticSourceKind::Pulled,
7569 diagnostic_updates,
7570 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7571 DiagnosticSourceKind::Pulled => {
7572 old_diagnostic.registration_id != registration_id
7573 || unchanged_buffers
7574 .get(&old_diagnostic.registration_id)
7575 .is_some_and(|unchanged_buffers| {
7576 unchanged_buffers.contains(&document_uri)
7577 })
7578 }
7579 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7580 true
7581 }
7582 },
7583 cx,
7584 )
7585 .log_err();
7586 }
7587 }
7588 })
7589 })
7590 }
7591
7592 pub fn signature_help<T: ToPointUtf16>(
7593 &mut self,
7594 buffer: &Entity<Buffer>,
7595 position: T,
7596 cx: &mut Context<Self>,
7597 ) -> Task<Option<Vec<SignatureHelp>>> {
7598 let position = position.to_point_utf16(buffer.read(cx));
7599
7600 if let Some((client, upstream_project_id)) = self.upstream_client() {
7601 let request = GetSignatureHelp { position };
7602 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7603 return Task::ready(None);
7604 }
7605 let request_timeout = ProjectSettings::get_global(cx)
7606 .global_lsp_settings
7607 .get_request_timeout();
7608 let request_task = client.request_lsp(
7609 upstream_project_id,
7610 None,
7611 request_timeout,
7612 cx.background_executor().clone(),
7613 request.to_proto(upstream_project_id, buffer.read(cx)),
7614 );
7615 let buffer = buffer.clone();
7616 cx.spawn(async move |weak_lsp_store, cx| {
7617 let lsp_store = weak_lsp_store.upgrade()?;
7618 let signatures = join_all(
7619 request_task
7620 .await
7621 .log_err()
7622 .flatten()
7623 .map(|response| response.payload)
7624 .unwrap_or_default()
7625 .into_iter()
7626 .map(|response| {
7627 let response = GetSignatureHelp { position }.response_from_proto(
7628 response.response,
7629 lsp_store.clone(),
7630 buffer.clone(),
7631 cx.clone(),
7632 );
7633 async move { response.await.log_err().flatten() }
7634 }),
7635 )
7636 .await
7637 .into_iter()
7638 .flatten()
7639 .collect();
7640 Some(signatures)
7641 })
7642 } else {
7643 let all_actions_task = self.request_multiple_lsp_locally(
7644 buffer,
7645 Some(position),
7646 GetSignatureHelp { position },
7647 cx,
7648 );
7649 cx.background_spawn(async move {
7650 Some(
7651 all_actions_task
7652 .await
7653 .into_iter()
7654 .flat_map(|(_, actions)| actions)
7655 .collect::<Vec<_>>(),
7656 )
7657 })
7658 }
7659 }
7660
7661 pub fn hover(
7662 &mut self,
7663 buffer: &Entity<Buffer>,
7664 position: PointUtf16,
7665 cx: &mut Context<Self>,
7666 ) -> Task<Option<Vec<Hover>>> {
7667 if let Some((client, upstream_project_id)) = self.upstream_client() {
7668 let request = GetHover { position };
7669 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7670 return Task::ready(None);
7671 }
7672 let request_timeout = ProjectSettings::get_global(cx)
7673 .global_lsp_settings
7674 .get_request_timeout();
7675 let request_task = client.request_lsp(
7676 upstream_project_id,
7677 None,
7678 request_timeout,
7679 cx.background_executor().clone(),
7680 request.to_proto(upstream_project_id, buffer.read(cx)),
7681 );
7682 let buffer = buffer.clone();
7683 cx.spawn(async move |weak_lsp_store, cx| {
7684 let lsp_store = weak_lsp_store.upgrade()?;
7685 let hovers = join_all(
7686 request_task
7687 .await
7688 .log_err()
7689 .flatten()
7690 .map(|response| response.payload)
7691 .unwrap_or_default()
7692 .into_iter()
7693 .map(|response| {
7694 let response = GetHover { position }.response_from_proto(
7695 response.response,
7696 lsp_store.clone(),
7697 buffer.clone(),
7698 cx.clone(),
7699 );
7700 async move {
7701 response
7702 .await
7703 .log_err()
7704 .flatten()
7705 .and_then(remove_empty_hover_blocks)
7706 }
7707 }),
7708 )
7709 .await
7710 .into_iter()
7711 .flatten()
7712 .collect();
7713 Some(hovers)
7714 })
7715 } else {
7716 let all_actions_task = self.request_multiple_lsp_locally(
7717 buffer,
7718 Some(position),
7719 GetHover { position },
7720 cx,
7721 );
7722 cx.background_spawn(async move {
7723 Some(
7724 all_actions_task
7725 .await
7726 .into_iter()
7727 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7728 .collect::<Vec<Hover>>(),
7729 )
7730 })
7731 }
7732 }
7733
7734 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7735 let language_registry = self.languages.clone();
7736
7737 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7738 let request = upstream_client.request(proto::GetProjectSymbols {
7739 project_id: *project_id,
7740 query: query.to_string(),
7741 });
7742 cx.foreground_executor().spawn(async move {
7743 let response = request.await?;
7744 let mut symbols = Vec::new();
7745 let core_symbols = response
7746 .symbols
7747 .into_iter()
7748 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7749 .collect::<Vec<_>>();
7750 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7751 .await;
7752 Ok(symbols)
7753 })
7754 } else if let Some(local) = self.as_local() {
7755 struct WorkspaceSymbolsResult {
7756 server_id: LanguageServerId,
7757 lsp_adapter: Arc<CachedLspAdapter>,
7758 worktree: WeakEntity<Worktree>,
7759 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7760 }
7761
7762 let mut requests = Vec::new();
7763 let mut requested_servers = BTreeSet::new();
7764 let request_timeout = ProjectSettings::get_global(cx)
7765 .global_lsp_settings
7766 .get_request_timeout();
7767
7768 for (seed, state) in local.language_server_ids.iter() {
7769 let Some(worktree_handle) = self
7770 .worktree_store
7771 .read(cx)
7772 .worktree_for_id(seed.worktree_id, cx)
7773 else {
7774 continue;
7775 };
7776
7777 let worktree = worktree_handle.read(cx);
7778 if !worktree.is_visible() {
7779 continue;
7780 }
7781
7782 if !requested_servers.insert(state.id) {
7783 continue;
7784 }
7785
7786 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7787 Some(LanguageServerState::Running {
7788 adapter, server, ..
7789 }) => (adapter.clone(), server),
7790
7791 _ => continue,
7792 };
7793
7794 let supports_workspace_symbol_request =
7795 match server.capabilities().workspace_symbol_provider {
7796 Some(OneOf::Left(supported)) => supported,
7797 Some(OneOf::Right(_)) => true,
7798 None => false,
7799 };
7800
7801 if !supports_workspace_symbol_request {
7802 continue;
7803 }
7804
7805 let worktree_handle = worktree_handle.clone();
7806 let server_id = server.server_id();
7807 requests.push(
7808 server
7809 .request::<lsp::request::WorkspaceSymbolRequest>(
7810 lsp::WorkspaceSymbolParams {
7811 query: query.to_string(),
7812 ..Default::default()
7813 },
7814 request_timeout,
7815 )
7816 .map(move |response| {
7817 let lsp_symbols = response
7818 .into_response()
7819 .context("workspace symbols request")
7820 .log_err()
7821 .flatten()
7822 .map(|symbol_response| match symbol_response {
7823 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7824 flat_responses
7825 .into_iter()
7826 .map(|lsp_symbol| {
7827 (
7828 lsp_symbol.name,
7829 lsp_symbol.kind,
7830 lsp_symbol.location,
7831 lsp_symbol.container_name,
7832 )
7833 })
7834 .collect::<Vec<_>>()
7835 }
7836 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7837 nested_responses
7838 .into_iter()
7839 .filter_map(|lsp_symbol| {
7840 let location = match lsp_symbol.location {
7841 OneOf::Left(location) => location,
7842 OneOf::Right(_) => {
7843 log::error!(
7844 "Unexpected: client capabilities \
7845 forbid symbol resolutions in \
7846 workspace.symbol.resolveSupport"
7847 );
7848 return None;
7849 }
7850 };
7851 Some((
7852 lsp_symbol.name,
7853 lsp_symbol.kind,
7854 location,
7855 lsp_symbol.container_name,
7856 ))
7857 })
7858 .collect::<Vec<_>>()
7859 }
7860 })
7861 .unwrap_or_default();
7862
7863 WorkspaceSymbolsResult {
7864 server_id,
7865 lsp_adapter,
7866 worktree: worktree_handle.downgrade(),
7867 lsp_symbols,
7868 }
7869 }),
7870 );
7871 }
7872
7873 cx.spawn(async move |this, cx| {
7874 let responses = futures::future::join_all(requests).await;
7875 let this = match this.upgrade() {
7876 Some(this) => this,
7877 None => return Ok(Vec::new()),
7878 };
7879
7880 let mut symbols = Vec::new();
7881 for result in responses {
7882 let core_symbols = this.update(cx, |this, cx| {
7883 result
7884 .lsp_symbols
7885 .into_iter()
7886 .filter_map(
7887 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7888 let abs_path = symbol_location.uri.to_file_path().ok()?;
7889 let source_worktree = result.worktree.upgrade()?;
7890 let source_worktree_id = source_worktree.read(cx).id();
7891
7892 let path = if let Some((tree, rel_path)) =
7893 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7894 {
7895 let worktree_id = tree.read(cx).id();
7896 SymbolLocation::InProject(ProjectPath {
7897 worktree_id,
7898 path: rel_path,
7899 })
7900 } else {
7901 SymbolLocation::OutsideProject {
7902 signature: this.symbol_signature(&abs_path),
7903 abs_path: abs_path.into(),
7904 }
7905 };
7906
7907 Some(CoreSymbol {
7908 source_language_server_id: result.server_id,
7909 language_server_name: result.lsp_adapter.name.clone(),
7910 source_worktree_id,
7911 path,
7912 kind: symbol_kind,
7913 name: collapse_newlines(&symbol_name, "↵ "),
7914 range: range_from_lsp(symbol_location.range),
7915 container_name: container_name
7916 .map(|c| collapse_newlines(&c, "↵ ")),
7917 })
7918 },
7919 )
7920 .collect::<Vec<_>>()
7921 });
7922
7923 populate_labels_for_symbols(
7924 core_symbols,
7925 &language_registry,
7926 Some(result.lsp_adapter),
7927 &mut symbols,
7928 )
7929 .await;
7930 }
7931
7932 Ok(symbols)
7933 })
7934 } else {
7935 Task::ready(Err(anyhow!("No upstream client or local language server")))
7936 }
7937 }
7938
7939 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7940 let mut summary = DiagnosticSummary::default();
7941 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7942 summary.error_count += path_summary.error_count;
7943 summary.warning_count += path_summary.warning_count;
7944 }
7945 summary
7946 }
7947
7948 /// Returns the diagnostic summary for a specific project path.
7949 pub fn diagnostic_summary_for_path(
7950 &self,
7951 project_path: &ProjectPath,
7952 _: &App,
7953 ) -> DiagnosticSummary {
7954 if let Some(summaries) = self
7955 .diagnostic_summaries
7956 .get(&project_path.worktree_id)
7957 .and_then(|map| map.get(&project_path.path))
7958 {
7959 let (error_count, warning_count) = summaries.iter().fold(
7960 (0, 0),
7961 |(error_count, warning_count), (_language_server_id, summary)| {
7962 (
7963 error_count + summary.error_count,
7964 warning_count + summary.warning_count,
7965 )
7966 },
7967 );
7968
7969 DiagnosticSummary {
7970 error_count,
7971 warning_count,
7972 }
7973 } else {
7974 DiagnosticSummary::default()
7975 }
7976 }
7977
7978 pub fn diagnostic_summaries<'a>(
7979 &'a self,
7980 include_ignored: bool,
7981 cx: &'a App,
7982 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7983 self.worktree_store
7984 .read(cx)
7985 .visible_worktrees(cx)
7986 .filter_map(|worktree| {
7987 let worktree = worktree.read(cx);
7988 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7989 })
7990 .flat_map(move |(worktree, summaries)| {
7991 let worktree_id = worktree.id();
7992 summaries
7993 .iter()
7994 .filter(move |(path, _)| {
7995 include_ignored
7996 || worktree
7997 .entry_for_path(path.as_ref())
7998 .is_some_and(|entry| !entry.is_ignored)
7999 })
8000 .flat_map(move |(path, summaries)| {
8001 summaries.iter().map(move |(server_id, summary)| {
8002 (
8003 ProjectPath {
8004 worktree_id,
8005 path: path.clone(),
8006 },
8007 *server_id,
8008 *summary,
8009 )
8010 })
8011 })
8012 })
8013 }
8014
8015 pub fn on_buffer_edited(
8016 &mut self,
8017 buffer: Entity<Buffer>,
8018 cx: &mut Context<Self>,
8019 ) -> Option<()> {
8020 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
8021 Some(
8022 self.as_local()?
8023 .language_servers_for_buffer(buffer, cx)
8024 .map(|i| i.1.clone())
8025 .collect(),
8026 )
8027 })?;
8028
8029 let buffer = buffer.read(cx);
8030 let file = File::from_dyn(buffer.file())?;
8031 let abs_path = file.as_local()?.abs_path(cx);
8032 let uri = lsp::Uri::from_file_path(&abs_path)
8033 .ok()
8034 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
8035 .log_err()?;
8036 let next_snapshot = buffer.text_snapshot();
8037 for language_server in language_servers {
8038 let language_server = language_server.clone();
8039
8040 let buffer_snapshots = self
8041 .as_local_mut()?
8042 .buffer_snapshots
8043 .get_mut(&buffer.remote_id())
8044 .and_then(|m| m.get_mut(&language_server.server_id()))?;
8045 let previous_snapshot = buffer_snapshots.last()?;
8046
8047 let build_incremental_change = || {
8048 buffer
8049 .edits_since::<Dimensions<PointUtf16, usize>>(
8050 previous_snapshot.snapshot.version(),
8051 )
8052 .map(|edit| {
8053 let edit_start = edit.new.start.0;
8054 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8055 let new_text = next_snapshot
8056 .text_for_range(edit.new.start.1..edit.new.end.1)
8057 .collect();
8058 lsp::TextDocumentContentChangeEvent {
8059 range: Some(lsp::Range::new(
8060 point_to_lsp(edit_start),
8061 point_to_lsp(edit_end),
8062 )),
8063 range_length: None,
8064 text: new_text,
8065 }
8066 })
8067 .collect()
8068 };
8069
8070 let document_sync_kind = language_server
8071 .capabilities()
8072 .text_document_sync
8073 .as_ref()
8074 .and_then(|sync| match sync {
8075 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8076 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8077 });
8078
8079 let content_changes: Vec<_> = match document_sync_kind {
8080 Some(lsp::TextDocumentSyncKind::FULL) => {
8081 vec![lsp::TextDocumentContentChangeEvent {
8082 range: None,
8083 range_length: None,
8084 text: next_snapshot.text(),
8085 }]
8086 }
8087 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8088 _ => {
8089 #[cfg(any(test, feature = "test-support"))]
8090 {
8091 build_incremental_change()
8092 }
8093
8094 #[cfg(not(any(test, feature = "test-support")))]
8095 {
8096 continue;
8097 }
8098 }
8099 };
8100
8101 let next_version = previous_snapshot.version + 1;
8102 buffer_snapshots.push(LspBufferSnapshot {
8103 version: next_version,
8104 snapshot: next_snapshot.clone(),
8105 });
8106
8107 language_server
8108 .notify::<lsp::notification::DidChangeTextDocument>(
8109 lsp::DidChangeTextDocumentParams {
8110 text_document: lsp::VersionedTextDocumentIdentifier::new(
8111 uri.clone(),
8112 next_version,
8113 ),
8114 content_changes,
8115 },
8116 )
8117 .ok();
8118 self.pull_workspace_diagnostics(language_server.server_id());
8119 }
8120
8121 None
8122 }
8123
8124 pub fn on_buffer_saved(
8125 &mut self,
8126 buffer: Entity<Buffer>,
8127 cx: &mut Context<Self>,
8128 ) -> Option<()> {
8129 let file = File::from_dyn(buffer.read(cx).file())?;
8130 let worktree_id = file.worktree_id(cx);
8131 let abs_path = file.as_local()?.abs_path(cx);
8132 let text_document = lsp::TextDocumentIdentifier {
8133 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8134 };
8135 let local = self.as_local()?;
8136
8137 for server in local.language_servers_for_worktree(worktree_id) {
8138 if let Some(include_text) = include_text(server.as_ref()) {
8139 let text = if include_text {
8140 Some(buffer.read(cx).text())
8141 } else {
8142 None
8143 };
8144 server
8145 .notify::<lsp::notification::DidSaveTextDocument>(
8146 lsp::DidSaveTextDocumentParams {
8147 text_document: text_document.clone(),
8148 text,
8149 },
8150 )
8151 .ok();
8152 }
8153 }
8154
8155 let language_servers = buffer.update(cx, |buffer, cx| {
8156 local.language_server_ids_for_buffer(buffer, cx)
8157 });
8158 for language_server_id in language_servers {
8159 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8160 }
8161
8162 None
8163 }
8164
8165 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8166 maybe!(async move {
8167 let mut refreshed_servers = HashSet::default();
8168 let servers = lsp_store
8169 .update(cx, |lsp_store, cx| {
8170 let local = lsp_store.as_local()?;
8171
8172 let servers = local
8173 .language_server_ids
8174 .iter()
8175 .filter_map(|(seed, state)| {
8176 let worktree = lsp_store
8177 .worktree_store
8178 .read(cx)
8179 .worktree_for_id(seed.worktree_id, cx);
8180 let delegate: Arc<dyn LspAdapterDelegate> =
8181 worktree.map(|worktree| {
8182 LocalLspAdapterDelegate::new(
8183 local.languages.clone(),
8184 &local.environment,
8185 cx.weak_entity(),
8186 &worktree,
8187 local.http_client.clone(),
8188 local.fs.clone(),
8189 cx,
8190 )
8191 })?;
8192 let server_id = state.id;
8193
8194 let states = local.language_servers.get(&server_id)?;
8195
8196 match states {
8197 LanguageServerState::Starting { .. } => None,
8198 LanguageServerState::Running {
8199 adapter, server, ..
8200 } => {
8201 let adapter = adapter.clone();
8202 let server = server.clone();
8203 refreshed_servers.insert(server.name());
8204 let toolchain = seed.toolchain.clone();
8205 Some(cx.spawn(async move |_, cx| {
8206 let settings =
8207 LocalLspStore::workspace_configuration_for_adapter(
8208 adapter.adapter.clone(),
8209 &delegate,
8210 toolchain,
8211 None,
8212 cx,
8213 )
8214 .await
8215 .ok()?;
8216 server
8217 .notify::<lsp::notification::DidChangeConfiguration>(
8218 lsp::DidChangeConfigurationParams { settings },
8219 )
8220 .ok()?;
8221 Some(())
8222 }))
8223 }
8224 }
8225 })
8226 .collect::<Vec<_>>();
8227
8228 Some(servers)
8229 })
8230 .ok()
8231 .flatten()?;
8232
8233 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8234 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8235 // to stop and unregister its language server wrapper.
8236 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8237 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8238 let _: Vec<Option<()>> = join_all(servers).await;
8239
8240 Some(())
8241 })
8242 .await;
8243 }
8244
8245 fn maintain_workspace_config(
8246 external_refresh_requests: watch::Receiver<()>,
8247 cx: &mut Context<Self>,
8248 ) -> Task<Result<()>> {
8249 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8250 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8251
8252 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8253 *settings_changed_tx.borrow_mut() = ();
8254 });
8255
8256 let mut joint_future =
8257 futures::stream::select(settings_changed_rx, external_refresh_requests);
8258 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8259 // - 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).
8260 // - 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.
8261 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8262 // - 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,
8263 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8264 cx.spawn(async move |this, cx| {
8265 while let Some(()) = joint_future.next().await {
8266 this.update(cx, |this, cx| {
8267 this.refresh_server_tree(cx);
8268 })
8269 .ok();
8270
8271 Self::refresh_workspace_configurations(&this, cx).await;
8272 }
8273
8274 drop(settings_observation);
8275 anyhow::Ok(())
8276 })
8277 }
8278
8279 pub fn running_language_servers_for_local_buffer<'a>(
8280 &'a self,
8281 buffer: &Buffer,
8282 cx: &mut App,
8283 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8284 let local = self.as_local();
8285 let language_server_ids = local
8286 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8287 .unwrap_or_default();
8288
8289 language_server_ids
8290 .into_iter()
8291 .filter_map(
8292 move |server_id| match local?.language_servers.get(&server_id)? {
8293 LanguageServerState::Running {
8294 adapter, server, ..
8295 } => Some((adapter, server)),
8296 _ => None,
8297 },
8298 )
8299 }
8300
8301 pub fn language_servers_for_local_buffer(
8302 &self,
8303 buffer: &Buffer,
8304 cx: &mut App,
8305 ) -> Vec<LanguageServerId> {
8306 let local = self.as_local();
8307 local
8308 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8309 .unwrap_or_default()
8310 }
8311
8312 pub fn language_server_for_local_buffer<'a>(
8313 &'a self,
8314 buffer: &'a Buffer,
8315 server_id: LanguageServerId,
8316 cx: &'a mut App,
8317 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8318 self.as_local()?
8319 .language_servers_for_buffer(buffer, cx)
8320 .find(|(_, s)| s.server_id() == server_id)
8321 }
8322
8323 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8324 self.diagnostic_summaries.remove(&id_to_remove);
8325 if let Some(local) = self.as_local_mut() {
8326 let to_remove = local.remove_worktree(id_to_remove, cx);
8327 for server in to_remove {
8328 self.language_server_statuses.remove(&server);
8329 }
8330 }
8331 }
8332
8333 fn invalidate_diagnostic_summaries_for_removed_entries(
8334 &mut self,
8335 worktree_id: WorktreeId,
8336 changes: &UpdatedEntriesSet,
8337 cx: &mut Context<Self>,
8338 ) {
8339 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8340 return;
8341 };
8342
8343 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8344 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8345 let downstream = self.downstream_client.clone();
8346
8347 for (path, _, _) in changes
8348 .iter()
8349 .filter(|(_, _, change)| *change == PathChange::Removed)
8350 {
8351 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8352 for (server_id, _) in &summaries_by_server_id {
8353 cleared_server_ids.insert(*server_id);
8354 if let Some((client, project_id)) = &downstream {
8355 client
8356 .send(proto::UpdateDiagnosticSummary {
8357 project_id: *project_id,
8358 worktree_id: worktree_id.to_proto(),
8359 summary: Some(proto::DiagnosticSummary {
8360 path: path.as_ref().to_proto(),
8361 language_server_id: server_id.0 as u64,
8362 error_count: 0,
8363 warning_count: 0,
8364 }),
8365 more_summaries: Vec::new(),
8366 })
8367 .ok();
8368 }
8369 }
8370 cleared_paths.push(ProjectPath {
8371 worktree_id,
8372 path: path.clone(),
8373 });
8374 }
8375 }
8376
8377 if !cleared_paths.is_empty() {
8378 for server_id in cleared_server_ids {
8379 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8380 server_id,
8381 paths: cleared_paths.clone(),
8382 });
8383 }
8384 }
8385 }
8386
8387 pub fn shared(
8388 &mut self,
8389 project_id: u64,
8390 downstream_client: AnyProtoClient,
8391 _: &mut Context<Self>,
8392 ) {
8393 self.downstream_client = Some((downstream_client.clone(), project_id));
8394
8395 for (server_id, status) in &self.language_server_statuses {
8396 if let Some(server) = self.language_server_for_id(*server_id) {
8397 downstream_client
8398 .send(proto::StartLanguageServer {
8399 project_id,
8400 server: Some(proto::LanguageServer {
8401 id: server_id.to_proto(),
8402 name: status.name.to_string(),
8403 worktree_id: status.worktree.map(|id| id.to_proto()),
8404 }),
8405 capabilities: serde_json::to_string(&server.capabilities())
8406 .expect("serializing server LSP capabilities"),
8407 })
8408 .log_err();
8409 }
8410 }
8411 }
8412
8413 pub fn disconnected_from_host(&mut self) {
8414 self.downstream_client.take();
8415 }
8416
8417 pub fn disconnected_from_ssh_remote(&mut self) {
8418 if let LspStoreMode::Remote(RemoteLspStore {
8419 upstream_client, ..
8420 }) = &mut self.mode
8421 {
8422 upstream_client.take();
8423 }
8424 }
8425
8426 pub(crate) fn set_language_server_statuses_from_proto(
8427 &mut self,
8428 project: WeakEntity<Project>,
8429 language_servers: Vec<proto::LanguageServer>,
8430 server_capabilities: Vec<String>,
8431 cx: &mut Context<Self>,
8432 ) {
8433 let lsp_logs = cx
8434 .try_global::<GlobalLogStore>()
8435 .map(|lsp_store| lsp_store.0.clone());
8436
8437 self.language_server_statuses = language_servers
8438 .into_iter()
8439 .zip(server_capabilities)
8440 .map(|(server, server_capabilities)| {
8441 let server_id = LanguageServerId(server.id as usize);
8442 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8443 self.lsp_server_capabilities
8444 .insert(server_id, server_capabilities);
8445 }
8446
8447 let name = LanguageServerName::from_proto(server.name);
8448 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8449
8450 if let Some(lsp_logs) = &lsp_logs {
8451 lsp_logs.update(cx, |lsp_logs, cx| {
8452 lsp_logs.add_language_server(
8453 // Only remote clients get their language servers set from proto
8454 LanguageServerKind::Remote {
8455 project: project.clone(),
8456 },
8457 server_id,
8458 Some(name.clone()),
8459 worktree,
8460 None,
8461 cx,
8462 );
8463 });
8464 }
8465
8466 (
8467 server_id,
8468 LanguageServerStatus {
8469 name,
8470 server_version: None,
8471 server_readable_version: None,
8472 pending_work: Default::default(),
8473 has_pending_diagnostic_updates: false,
8474 progress_tokens: Default::default(),
8475 worktree,
8476 binary: None,
8477 configuration: None,
8478 workspace_folders: BTreeSet::new(),
8479 process_id: None,
8480 },
8481 )
8482 })
8483 .collect();
8484 }
8485
8486 #[cfg(feature = "test-support")]
8487 pub fn update_diagnostic_entries(
8488 &mut self,
8489 server_id: LanguageServerId,
8490 abs_path: PathBuf,
8491 result_id: Option<SharedString>,
8492 version: Option<i32>,
8493 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8494 cx: &mut Context<Self>,
8495 ) -> anyhow::Result<()> {
8496 self.merge_diagnostic_entries(
8497 vec![DocumentDiagnosticsUpdate {
8498 diagnostics: DocumentDiagnostics {
8499 diagnostics,
8500 document_abs_path: abs_path,
8501 version,
8502 },
8503 result_id,
8504 server_id,
8505 disk_based_sources: Cow::Borrowed(&[]),
8506 registration_id: None,
8507 }],
8508 |_, _, _| false,
8509 cx,
8510 )?;
8511 Ok(())
8512 }
8513
8514 pub fn merge_diagnostic_entries<'a>(
8515 &mut self,
8516 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8517 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8518 cx: &mut Context<Self>,
8519 ) -> anyhow::Result<()> {
8520 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8521 let mut updated_diagnostics_paths = HashMap::default();
8522 for mut update in diagnostic_updates {
8523 let abs_path = &update.diagnostics.document_abs_path;
8524 let server_id = update.server_id;
8525 let Some((worktree, relative_path)) =
8526 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8527 else {
8528 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8529 return Ok(());
8530 };
8531
8532 let worktree_id = worktree.read(cx).id();
8533 let project_path = ProjectPath {
8534 worktree_id,
8535 path: relative_path,
8536 };
8537
8538 let document_uri = lsp::Uri::from_file_path(abs_path)
8539 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8540 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8541 let snapshot = buffer_handle.read(cx).snapshot();
8542 let buffer = buffer_handle.read(cx);
8543 let reused_diagnostics = buffer
8544 .buffer_diagnostics(Some(server_id))
8545 .iter()
8546 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8547 .map(|v| {
8548 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8549 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8550 DiagnosticEntry {
8551 range: start..end,
8552 diagnostic: v.diagnostic.clone(),
8553 }
8554 })
8555 .collect::<Vec<_>>();
8556
8557 self.as_local_mut()
8558 .context("cannot merge diagnostics on a remote LspStore")?
8559 .update_buffer_diagnostics(
8560 &buffer_handle,
8561 server_id,
8562 Some(update.registration_id),
8563 update.result_id,
8564 update.diagnostics.version,
8565 update.diagnostics.diagnostics.clone(),
8566 reused_diagnostics.clone(),
8567 cx,
8568 )?;
8569
8570 update.diagnostics.diagnostics.extend(reused_diagnostics);
8571 } else if let Some(local) = self.as_local() {
8572 let reused_diagnostics = local
8573 .diagnostics
8574 .get(&worktree_id)
8575 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8576 .and_then(|diagnostics_by_server_id| {
8577 diagnostics_by_server_id
8578 .binary_search_by_key(&server_id, |e| e.0)
8579 .ok()
8580 .map(|ix| &diagnostics_by_server_id[ix].1)
8581 })
8582 .into_iter()
8583 .flatten()
8584 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8585
8586 update
8587 .diagnostics
8588 .diagnostics
8589 .extend(reused_diagnostics.cloned());
8590 }
8591
8592 let updated = worktree.update(cx, |worktree, cx| {
8593 self.update_worktree_diagnostics(
8594 worktree.id(),
8595 server_id,
8596 project_path.path.clone(),
8597 update.diagnostics.diagnostics,
8598 cx,
8599 )
8600 })?;
8601 match updated {
8602 ControlFlow::Continue(new_summary) => {
8603 if let Some((project_id, new_summary)) = new_summary {
8604 match &mut diagnostics_summary {
8605 Some(diagnostics_summary) => {
8606 diagnostics_summary
8607 .more_summaries
8608 .push(proto::DiagnosticSummary {
8609 path: project_path.path.as_ref().to_proto(),
8610 language_server_id: server_id.0 as u64,
8611 error_count: new_summary.error_count,
8612 warning_count: new_summary.warning_count,
8613 })
8614 }
8615 None => {
8616 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8617 project_id,
8618 worktree_id: worktree_id.to_proto(),
8619 summary: Some(proto::DiagnosticSummary {
8620 path: project_path.path.as_ref().to_proto(),
8621 language_server_id: server_id.0 as u64,
8622 error_count: new_summary.error_count,
8623 warning_count: new_summary.warning_count,
8624 }),
8625 more_summaries: Vec::new(),
8626 })
8627 }
8628 }
8629 }
8630 updated_diagnostics_paths
8631 .entry(server_id)
8632 .or_insert_with(Vec::new)
8633 .push(project_path);
8634 }
8635 ControlFlow::Break(()) => {}
8636 }
8637 }
8638
8639 if let Some((diagnostics_summary, (downstream_client, _))) =
8640 diagnostics_summary.zip(self.downstream_client.as_ref())
8641 {
8642 downstream_client.send(diagnostics_summary).log_err();
8643 }
8644 for (server_id, paths) in updated_diagnostics_paths {
8645 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8646 }
8647 Ok(())
8648 }
8649
8650 fn update_worktree_diagnostics(
8651 &mut self,
8652 worktree_id: WorktreeId,
8653 server_id: LanguageServerId,
8654 path_in_worktree: Arc<RelPath>,
8655 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8656 _: &mut Context<Worktree>,
8657 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8658 let local = match &mut self.mode {
8659 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8660 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8661 };
8662
8663 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8664 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8665 let summaries_by_server_id = summaries_for_tree
8666 .entry(path_in_worktree.clone())
8667 .or_default();
8668
8669 let old_summary = summaries_by_server_id
8670 .remove(&server_id)
8671 .unwrap_or_default();
8672
8673 let new_summary = DiagnosticSummary::new(&diagnostics);
8674 if diagnostics.is_empty() {
8675 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8676 {
8677 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8678 diagnostics_by_server_id.remove(ix);
8679 }
8680 if diagnostics_by_server_id.is_empty() {
8681 diagnostics_for_tree.remove(&path_in_worktree);
8682 }
8683 }
8684 } else {
8685 summaries_by_server_id.insert(server_id, new_summary);
8686 let diagnostics_by_server_id = diagnostics_for_tree
8687 .entry(path_in_worktree.clone())
8688 .or_default();
8689 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8690 Ok(ix) => {
8691 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8692 }
8693 Err(ix) => {
8694 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8695 }
8696 }
8697 }
8698
8699 if !old_summary.is_empty() || !new_summary.is_empty() {
8700 if let Some((_, project_id)) = &self.downstream_client {
8701 Ok(ControlFlow::Continue(Some((
8702 *project_id,
8703 proto::DiagnosticSummary {
8704 path: path_in_worktree.to_proto(),
8705 language_server_id: server_id.0 as u64,
8706 error_count: new_summary.error_count as u32,
8707 warning_count: new_summary.warning_count as u32,
8708 },
8709 ))))
8710 } else {
8711 Ok(ControlFlow::Continue(None))
8712 }
8713 } else {
8714 Ok(ControlFlow::Break(()))
8715 }
8716 }
8717
8718 pub fn open_buffer_for_symbol(
8719 &mut self,
8720 symbol: &Symbol,
8721 cx: &mut Context<Self>,
8722 ) -> Task<Result<Entity<Buffer>>> {
8723 if let Some((client, project_id)) = self.upstream_client() {
8724 let request = client.request(proto::OpenBufferForSymbol {
8725 project_id,
8726 symbol: Some(Self::serialize_symbol(symbol)),
8727 });
8728 cx.spawn(async move |this, cx| {
8729 let response = request.await?;
8730 let buffer_id = BufferId::new(response.buffer_id)?;
8731 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8732 .await
8733 })
8734 } else if let Some(local) = self.as_local() {
8735 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8736 seed.worktree_id == symbol.source_worktree_id
8737 && state.id == symbol.source_language_server_id
8738 && symbol.language_server_name == seed.name
8739 });
8740 if !is_valid {
8741 return Task::ready(Err(anyhow!(
8742 "language server for worktree and language not found"
8743 )));
8744 };
8745
8746 let symbol_abs_path = match &symbol.path {
8747 SymbolLocation::InProject(project_path) => self
8748 .worktree_store
8749 .read(cx)
8750 .absolutize(&project_path, cx)
8751 .context("no such worktree"),
8752 SymbolLocation::OutsideProject {
8753 abs_path,
8754 signature: _,
8755 } => Ok(abs_path.to_path_buf()),
8756 };
8757 let symbol_abs_path = match symbol_abs_path {
8758 Ok(abs_path) => abs_path,
8759 Err(err) => return Task::ready(Err(err)),
8760 };
8761 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8762 uri
8763 } else {
8764 return Task::ready(Err(anyhow!("invalid symbol path")));
8765 };
8766
8767 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8768 } else {
8769 Task::ready(Err(anyhow!("no upstream client or local store")))
8770 }
8771 }
8772
8773 pub(crate) fn open_local_buffer_via_lsp(
8774 &mut self,
8775 abs_path: lsp::Uri,
8776 language_server_id: LanguageServerId,
8777 cx: &mut Context<Self>,
8778 ) -> Task<Result<Entity<Buffer>>> {
8779 let path_style = self.worktree_store.read(cx).path_style();
8780 cx.spawn(async move |lsp_store, cx| {
8781 // Escape percent-encoded string.
8782 let current_scheme = abs_path.scheme().to_owned();
8783 // Uri is immutable, so we can't modify the scheme
8784
8785 let abs_path = abs_path
8786 .to_file_path_ext(path_style)
8787 .map_err(|()| anyhow!("can't convert URI to path"))?;
8788 let p = abs_path.clone();
8789 let yarn_worktree = lsp_store
8790 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8791 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8792 cx.spawn(async move |this, cx| {
8793 let t = this
8794 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8795 .ok()?;
8796 t.await
8797 })
8798 }),
8799 None => Task::ready(None),
8800 })?
8801 .await;
8802 let (worktree_root_target, known_relative_path) =
8803 if let Some((zip_root, relative_path)) = yarn_worktree {
8804 (zip_root, Some(relative_path))
8805 } else {
8806 (Arc::<Path>::from(abs_path.as_path()), None)
8807 };
8808 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8809 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8810 worktree_store.find_worktree(&worktree_root_target, cx)
8811 })
8812 })?;
8813 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8814 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8815 (result.0, relative_path, None)
8816 } else {
8817 let worktree = lsp_store
8818 .update(cx, |lsp_store, cx| {
8819 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8820 worktree_store.create_worktree(&worktree_root_target, false, cx)
8821 })
8822 })?
8823 .await?;
8824 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8825 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8826 lsp_store
8827 .update(cx, |lsp_store, cx| {
8828 if let Some(local) = lsp_store.as_local_mut() {
8829 local.register_language_server_for_invisible_worktree(
8830 &worktree,
8831 language_server_id,
8832 cx,
8833 )
8834 }
8835 match lsp_store.language_server_statuses.get(&language_server_id) {
8836 Some(status) => status.worktree,
8837 None => None,
8838 }
8839 })
8840 .ok()
8841 .flatten()
8842 .zip(Some(worktree_root.clone()))
8843 } else {
8844 None
8845 };
8846 let relative_path = if let Some(known_path) = known_relative_path {
8847 known_path
8848 } else {
8849 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8850 .into_arc()
8851 };
8852 (worktree, relative_path, source_ws)
8853 };
8854 let project_path = ProjectPath {
8855 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8856 path: relative_path,
8857 };
8858 let buffer = lsp_store
8859 .update(cx, |lsp_store, cx| {
8860 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8861 buffer_store.open_buffer(project_path, cx)
8862 })
8863 })?
8864 .await?;
8865 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8866 if let Some((source_ws, worktree_root)) = source_ws {
8867 buffer.update(cx, |buffer, cx| {
8868 let settings = WorktreeSettings::get(
8869 Some(
8870 (&ProjectPath {
8871 worktree_id: source_ws,
8872 path: Arc::from(RelPath::empty()),
8873 })
8874 .into(),
8875 ),
8876 cx,
8877 );
8878 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8879 if is_read_only {
8880 buffer.set_capability(Capability::ReadOnly, cx);
8881 }
8882 });
8883 }
8884 Ok(buffer)
8885 })
8886 }
8887
8888 fn local_lsp_servers_for_buffer(
8889 &self,
8890 buffer: &Entity<Buffer>,
8891 cx: &mut Context<Self>,
8892 ) -> Vec<LanguageServerId> {
8893 let Some(local) = self.as_local() else {
8894 return Vec::new();
8895 };
8896
8897 let snapshot = buffer.read(cx).snapshot();
8898
8899 buffer.update(cx, |buffer, cx| {
8900 local
8901 .language_servers_for_buffer(buffer, cx)
8902 .map(|(_, server)| server.server_id())
8903 .filter(|server_id| {
8904 self.as_local().is_none_or(|local| {
8905 local
8906 .buffers_opened_in_servers
8907 .get(&snapshot.remote_id())
8908 .is_some_and(|servers| servers.contains(server_id))
8909 })
8910 })
8911 .collect()
8912 })
8913 }
8914
8915 fn request_multiple_lsp_locally<P, R>(
8916 &mut self,
8917 buffer: &Entity<Buffer>,
8918 position: Option<P>,
8919 request: R,
8920 cx: &mut Context<Self>,
8921 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8922 where
8923 P: ToOffset,
8924 R: LspCommand + Clone,
8925 <R::LspRequest as lsp::request::Request>::Result: Send,
8926 <R::LspRequest as lsp::request::Request>::Params: Send,
8927 {
8928 let Some(local) = self.as_local() else {
8929 return Task::ready(Vec::new());
8930 };
8931
8932 let snapshot = buffer.read(cx).snapshot();
8933 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8934
8935 let server_ids = buffer.update(cx, |buffer, cx| {
8936 local
8937 .language_servers_for_buffer(buffer, cx)
8938 .filter(|(adapter, _)| {
8939 scope
8940 .as_ref()
8941 .map(|scope| scope.language_allowed(&adapter.name))
8942 .unwrap_or(true)
8943 })
8944 .map(|(_, server)| server.server_id())
8945 .filter(|server_id| {
8946 self.as_local().is_none_or(|local| {
8947 local
8948 .buffers_opened_in_servers
8949 .get(&snapshot.remote_id())
8950 .is_some_and(|servers| servers.contains(server_id))
8951 })
8952 })
8953 .collect::<Vec<_>>()
8954 });
8955
8956 let mut response_results = server_ids
8957 .into_iter()
8958 .map(|server_id| {
8959 let task = self.request_lsp(
8960 buffer.clone(),
8961 LanguageServerToQuery::Other(server_id),
8962 request.clone(),
8963 cx,
8964 );
8965 async move { (server_id, task.await) }
8966 })
8967 .collect::<FuturesUnordered<_>>();
8968
8969 cx.background_spawn(async move {
8970 let mut responses = Vec::with_capacity(response_results.len());
8971 while let Some((server_id, response_result)) = response_results.next().await {
8972 match response_result {
8973 Ok(response) => responses.push((server_id, response)),
8974 // rust-analyzer likes to error with this when its still loading up
8975 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8976 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8977 }
8978 }
8979 responses
8980 })
8981 }
8982
8983 async fn handle_lsp_get_completions(
8984 this: Entity<Self>,
8985 envelope: TypedEnvelope<proto::GetCompletions>,
8986 mut cx: AsyncApp,
8987 ) -> Result<proto::GetCompletionsResponse> {
8988 let sender_id = envelope.original_sender_id().unwrap_or_default();
8989
8990 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8991 let buffer_handle = this.update(&mut cx, |this, cx| {
8992 this.buffer_store.read(cx).get_existing(buffer_id)
8993 })?;
8994 let request = GetCompletions::from_proto(
8995 envelope.payload,
8996 this.clone(),
8997 buffer_handle.clone(),
8998 cx.clone(),
8999 )
9000 .await?;
9001
9002 let server_to_query = match request.server_id {
9003 Some(server_id) => LanguageServerToQuery::Other(server_id),
9004 None => LanguageServerToQuery::FirstCapable,
9005 };
9006
9007 let response = this
9008 .update(&mut cx, |this, cx| {
9009 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
9010 })
9011 .await?;
9012 this.update(&mut cx, |this, cx| {
9013 Ok(GetCompletions::response_to_proto(
9014 response,
9015 this,
9016 sender_id,
9017 &buffer_handle.read(cx).version(),
9018 cx,
9019 ))
9020 })
9021 }
9022
9023 async fn handle_lsp_command<T: LspCommand>(
9024 this: Entity<Self>,
9025 envelope: TypedEnvelope<T::ProtoRequest>,
9026 mut cx: AsyncApp,
9027 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
9028 where
9029 <T::LspRequest as lsp::request::Request>::Params: Send,
9030 <T::LspRequest as lsp::request::Request>::Result: Send,
9031 {
9032 let sender_id = envelope.original_sender_id().unwrap_or_default();
9033 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
9034 let buffer_handle = this.update(&mut cx, |this, cx| {
9035 this.buffer_store.read(cx).get_existing(buffer_id)
9036 })?;
9037 let request = T::from_proto(
9038 envelope.payload,
9039 this.clone(),
9040 buffer_handle.clone(),
9041 cx.clone(),
9042 )
9043 .await?;
9044 let response = this
9045 .update(&mut cx, |this, cx| {
9046 this.request_lsp(
9047 buffer_handle.clone(),
9048 LanguageServerToQuery::FirstCapable,
9049 request,
9050 cx,
9051 )
9052 })
9053 .await?;
9054 this.update(&mut cx, |this, cx| {
9055 Ok(T::response_to_proto(
9056 response,
9057 this,
9058 sender_id,
9059 &buffer_handle.read(cx).version(),
9060 cx,
9061 ))
9062 })
9063 }
9064
9065 async fn handle_lsp_query(
9066 lsp_store: Entity<Self>,
9067 envelope: TypedEnvelope<proto::LspQuery>,
9068 mut cx: AsyncApp,
9069 ) -> Result<proto::Ack> {
9070 use proto::lsp_query::Request;
9071 let sender_id = envelope.original_sender_id().unwrap_or_default();
9072 let lsp_query = envelope.payload;
9073 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
9074 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
9075 match lsp_query.request.context("invalid LSP query request")? {
9076 Request::GetReferences(get_references) => {
9077 let position = get_references.position.clone().and_then(deserialize_anchor);
9078 Self::query_lsp_locally::<GetReferences>(
9079 lsp_store,
9080 server_id,
9081 sender_id,
9082 lsp_request_id,
9083 get_references,
9084 position,
9085 &mut cx,
9086 )
9087 .await?;
9088 }
9089 Request::GetDocumentColor(get_document_color) => {
9090 Self::query_lsp_locally::<GetDocumentColor>(
9091 lsp_store,
9092 server_id,
9093 sender_id,
9094 lsp_request_id,
9095 get_document_color,
9096 None,
9097 &mut cx,
9098 )
9099 .await?;
9100 }
9101 Request::GetFoldingRanges(get_folding_ranges) => {
9102 Self::query_lsp_locally::<GetFoldingRanges>(
9103 lsp_store,
9104 server_id,
9105 sender_id,
9106 lsp_request_id,
9107 get_folding_ranges,
9108 None,
9109 &mut cx,
9110 )
9111 .await?;
9112 }
9113 Request::GetDocumentSymbols(get_document_symbols) => {
9114 Self::query_lsp_locally::<GetDocumentSymbols>(
9115 lsp_store,
9116 server_id,
9117 sender_id,
9118 lsp_request_id,
9119 get_document_symbols,
9120 None,
9121 &mut cx,
9122 )
9123 .await?;
9124 }
9125 Request::GetHover(get_hover) => {
9126 let position = get_hover.position.clone().and_then(deserialize_anchor);
9127 Self::query_lsp_locally::<GetHover>(
9128 lsp_store,
9129 server_id,
9130 sender_id,
9131 lsp_request_id,
9132 get_hover,
9133 position,
9134 &mut cx,
9135 )
9136 .await?;
9137 }
9138 Request::GetCodeActions(get_code_actions) => {
9139 Self::query_lsp_locally::<GetCodeActions>(
9140 lsp_store,
9141 server_id,
9142 sender_id,
9143 lsp_request_id,
9144 get_code_actions,
9145 None,
9146 &mut cx,
9147 )
9148 .await?;
9149 }
9150 Request::GetSignatureHelp(get_signature_help) => {
9151 let position = get_signature_help
9152 .position
9153 .clone()
9154 .and_then(deserialize_anchor);
9155 Self::query_lsp_locally::<GetSignatureHelp>(
9156 lsp_store,
9157 server_id,
9158 sender_id,
9159 lsp_request_id,
9160 get_signature_help,
9161 position,
9162 &mut cx,
9163 )
9164 .await?;
9165 }
9166 Request::GetCodeLens(get_code_lens) => {
9167 Self::query_lsp_locally::<GetCodeLens>(
9168 lsp_store,
9169 server_id,
9170 sender_id,
9171 lsp_request_id,
9172 get_code_lens,
9173 None,
9174 &mut cx,
9175 )
9176 .await?;
9177 }
9178 Request::GetDefinition(get_definition) => {
9179 let position = get_definition.position.clone().and_then(deserialize_anchor);
9180 Self::query_lsp_locally::<GetDefinitions>(
9181 lsp_store,
9182 server_id,
9183 sender_id,
9184 lsp_request_id,
9185 get_definition,
9186 position,
9187 &mut cx,
9188 )
9189 .await?;
9190 }
9191 Request::GetDeclaration(get_declaration) => {
9192 let position = get_declaration
9193 .position
9194 .clone()
9195 .and_then(deserialize_anchor);
9196 Self::query_lsp_locally::<GetDeclarations>(
9197 lsp_store,
9198 server_id,
9199 sender_id,
9200 lsp_request_id,
9201 get_declaration,
9202 position,
9203 &mut cx,
9204 )
9205 .await?;
9206 }
9207 Request::GetTypeDefinition(get_type_definition) => {
9208 let position = get_type_definition
9209 .position
9210 .clone()
9211 .and_then(deserialize_anchor);
9212 Self::query_lsp_locally::<GetTypeDefinitions>(
9213 lsp_store,
9214 server_id,
9215 sender_id,
9216 lsp_request_id,
9217 get_type_definition,
9218 position,
9219 &mut cx,
9220 )
9221 .await?;
9222 }
9223 Request::GetImplementation(get_implementation) => {
9224 let position = get_implementation
9225 .position
9226 .clone()
9227 .and_then(deserialize_anchor);
9228 Self::query_lsp_locally::<GetImplementations>(
9229 lsp_store,
9230 server_id,
9231 sender_id,
9232 lsp_request_id,
9233 get_implementation,
9234 position,
9235 &mut cx,
9236 )
9237 .await?;
9238 }
9239 Request::InlayHints(inlay_hints) => {
9240 let query_start = inlay_hints
9241 .start
9242 .clone()
9243 .and_then(deserialize_anchor)
9244 .context("invalid inlay hints range start")?;
9245 let query_end = inlay_hints
9246 .end
9247 .clone()
9248 .and_then(deserialize_anchor)
9249 .context("invalid inlay hints range end")?;
9250 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9251 &lsp_store,
9252 server_id,
9253 lsp_request_id,
9254 &inlay_hints,
9255 query_start..query_end,
9256 &mut cx,
9257 )
9258 .await
9259 .context("preparing inlay hints request")?;
9260 Self::query_lsp_locally::<InlayHints>(
9261 lsp_store,
9262 server_id,
9263 sender_id,
9264 lsp_request_id,
9265 inlay_hints,
9266 None,
9267 &mut cx,
9268 )
9269 .await
9270 .context("querying for inlay hints")?
9271 }
9272 //////////////////////////////
9273 // Below are LSP queries that need to fetch more data,
9274 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9275 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9276 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9277 &lsp_store,
9278 &get_document_diagnostics,
9279 &mut cx,
9280 )
9281 .await?;
9282 lsp_store.update(&mut cx, |lsp_store, cx| {
9283 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9284 let key = LspKey {
9285 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9286 server_queried: server_id,
9287 };
9288 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9289 ) {
9290 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9291 lsp_requests.clear();
9292 };
9293 }
9294
9295 lsp_data.lsp_requests.entry(key).or_default().insert(
9296 lsp_request_id,
9297 cx.spawn(async move |lsp_store, cx| {
9298 let diagnostics_pull = lsp_store
9299 .update(cx, |lsp_store, cx| {
9300 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9301 })
9302 .ok();
9303 if let Some(diagnostics_pull) = diagnostics_pull {
9304 match diagnostics_pull.await {
9305 Ok(()) => {}
9306 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9307 };
9308 }
9309 }),
9310 );
9311 });
9312 }
9313 Request::SemanticTokens(semantic_tokens) => {
9314 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9315 &lsp_store,
9316 &semantic_tokens,
9317 &mut cx,
9318 )
9319 .await?;
9320 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9321 lsp_store.update(&mut cx, |lsp_store, cx| {
9322 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9323 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9324 let key = LspKey {
9325 request_type: TypeId::of::<SemanticTokensFull>(),
9326 server_queried: server_id,
9327 };
9328 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9329 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9330 lsp_requests.clear();
9331 };
9332 }
9333
9334 lsp_data.lsp_requests.entry(key).or_default().insert(
9335 lsp_request_id,
9336 cx.spawn(async move |lsp_store, cx| {
9337 let tokens_fetch = lsp_store
9338 .update(cx, |lsp_store, cx| {
9339 lsp_store
9340 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9341 })
9342 .ok();
9343 if let Some(tokens_fetch) = tokens_fetch {
9344 let new_tokens = tokens_fetch.await;
9345 if let Some(new_tokens) = new_tokens {
9346 lsp_store
9347 .update(cx, |lsp_store, cx| {
9348 let response = new_tokens
9349 .into_iter()
9350 .map(|(server_id, response)| {
9351 (
9352 server_id.to_proto(),
9353 SemanticTokensFull::response_to_proto(
9354 response,
9355 lsp_store,
9356 sender_id,
9357 &buffer_version,
9358 cx,
9359 ),
9360 )
9361 })
9362 .collect::<HashMap<_, _>>();
9363 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9364 project_id,
9365 lsp_request_id,
9366 response,
9367 ) {
9368 Ok(()) => {}
9369 Err(e) => {
9370 log::error!(
9371 "Failed to send semantic tokens LSP response: {e:#}",
9372 )
9373 }
9374 }
9375 })
9376 .ok();
9377 }
9378 }
9379 }),
9380 );
9381 }
9382 });
9383 }
9384 }
9385 Ok(proto::Ack {})
9386 }
9387
9388 async fn handle_lsp_query_response(
9389 lsp_store: Entity<Self>,
9390 envelope: TypedEnvelope<proto::LspQueryResponse>,
9391 cx: AsyncApp,
9392 ) -> Result<()> {
9393 lsp_store.read_with(&cx, |lsp_store, _| {
9394 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9395 upstream_client.handle_lsp_response(envelope.clone());
9396 }
9397 });
9398 Ok(())
9399 }
9400
9401 async fn handle_apply_code_action(
9402 this: Entity<Self>,
9403 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9404 mut cx: AsyncApp,
9405 ) -> Result<proto::ApplyCodeActionResponse> {
9406 let sender_id = envelope.original_sender_id().unwrap_or_default();
9407 let action =
9408 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9409 let apply_code_action = this.update(&mut cx, |this, cx| {
9410 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9411 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9412 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9413 })?;
9414
9415 let project_transaction = apply_code_action.await?;
9416 let project_transaction = this.update(&mut cx, |this, cx| {
9417 this.buffer_store.update(cx, |buffer_store, cx| {
9418 buffer_store.serialize_project_transaction_for_peer(
9419 project_transaction,
9420 sender_id,
9421 cx,
9422 )
9423 })
9424 });
9425 Ok(proto::ApplyCodeActionResponse {
9426 transaction: Some(project_transaction),
9427 })
9428 }
9429
9430 async fn handle_register_buffer_with_language_servers(
9431 this: Entity<Self>,
9432 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9433 mut cx: AsyncApp,
9434 ) -> Result<proto::Ack> {
9435 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9436 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9437 this.update(&mut cx, |this, cx| {
9438 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9439 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9440 project_id: upstream_project_id,
9441 buffer_id: buffer_id.to_proto(),
9442 only_servers: envelope.payload.only_servers,
9443 });
9444 }
9445
9446 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9447 anyhow::bail!("buffer is not open");
9448 };
9449
9450 let handle = this.register_buffer_with_language_servers(
9451 &buffer,
9452 envelope
9453 .payload
9454 .only_servers
9455 .into_iter()
9456 .filter_map(|selector| {
9457 Some(match selector.selector? {
9458 proto::language_server_selector::Selector::ServerId(server_id) => {
9459 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9460 }
9461 proto::language_server_selector::Selector::Name(name) => {
9462 LanguageServerSelector::Name(LanguageServerName(
9463 SharedString::from(name),
9464 ))
9465 }
9466 })
9467 })
9468 .collect(),
9469 false,
9470 cx,
9471 );
9472 // Pull diagnostics for the buffer even if it was already registered.
9473 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9474 // but it's unclear if we need it.
9475 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9476 .detach();
9477 this.buffer_store().update(cx, |buffer_store, _| {
9478 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9479 });
9480
9481 Ok(())
9482 })?;
9483 Ok(proto::Ack {})
9484 }
9485
9486 async fn handle_rename_project_entry(
9487 this: Entity<Self>,
9488 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9489 mut cx: AsyncApp,
9490 ) -> Result<proto::ProjectEntryResponse> {
9491 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9492 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9493 let new_path =
9494 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9495
9496 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9497 .update(&mut cx, |this, cx| {
9498 let (worktree, entry) = this
9499 .worktree_store
9500 .read(cx)
9501 .worktree_and_entry_for_id(entry_id, cx)?;
9502 let new_worktree = this
9503 .worktree_store
9504 .read(cx)
9505 .worktree_for_id(new_worktree_id, cx)?;
9506 Some((
9507 this.worktree_store.clone(),
9508 worktree,
9509 new_worktree,
9510 entry.clone(),
9511 ))
9512 })
9513 .context("worktree not found")?;
9514 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9515 (worktree.absolutize(&old_entry.path), worktree.id())
9516 });
9517 let new_abs_path =
9518 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9519
9520 let _transaction = Self::will_rename_entry(
9521 this.downgrade(),
9522 old_worktree_id,
9523 &old_abs_path,
9524 &new_abs_path,
9525 old_entry.is_dir(),
9526 cx.clone(),
9527 )
9528 .await;
9529 let response = WorktreeStore::handle_rename_project_entry(
9530 worktree_store,
9531 envelope.payload,
9532 cx.clone(),
9533 )
9534 .await;
9535 this.read_with(&cx, |this, _| {
9536 this.did_rename_entry(
9537 old_worktree_id,
9538 &old_abs_path,
9539 &new_abs_path,
9540 old_entry.is_dir(),
9541 );
9542 });
9543 response
9544 }
9545
9546 async fn handle_update_diagnostic_summary(
9547 this: Entity<Self>,
9548 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9549 mut cx: AsyncApp,
9550 ) -> Result<()> {
9551 this.update(&mut cx, |lsp_store, cx| {
9552 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9553 let mut updated_diagnostics_paths = HashMap::default();
9554 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9555 for message_summary in envelope
9556 .payload
9557 .summary
9558 .into_iter()
9559 .chain(envelope.payload.more_summaries)
9560 {
9561 let project_path = ProjectPath {
9562 worktree_id,
9563 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9564 };
9565 let path = project_path.path.clone();
9566 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9567 let summary = DiagnosticSummary {
9568 error_count: message_summary.error_count as usize,
9569 warning_count: message_summary.warning_count as usize,
9570 };
9571
9572 if summary.is_empty() {
9573 if let Some(worktree_summaries) =
9574 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9575 && let Some(summaries) = worktree_summaries.get_mut(&path)
9576 {
9577 summaries.remove(&server_id);
9578 if summaries.is_empty() {
9579 worktree_summaries.remove(&path);
9580 }
9581 }
9582 } else {
9583 lsp_store
9584 .diagnostic_summaries
9585 .entry(worktree_id)
9586 .or_default()
9587 .entry(path)
9588 .or_default()
9589 .insert(server_id, summary);
9590 }
9591
9592 if let Some((_, project_id)) = &lsp_store.downstream_client {
9593 match &mut diagnostics_summary {
9594 Some(diagnostics_summary) => {
9595 diagnostics_summary
9596 .more_summaries
9597 .push(proto::DiagnosticSummary {
9598 path: project_path.path.as_ref().to_proto(),
9599 language_server_id: server_id.0 as u64,
9600 error_count: summary.error_count as u32,
9601 warning_count: summary.warning_count as u32,
9602 })
9603 }
9604 None => {
9605 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9606 project_id: *project_id,
9607 worktree_id: worktree_id.to_proto(),
9608 summary: Some(proto::DiagnosticSummary {
9609 path: project_path.path.as_ref().to_proto(),
9610 language_server_id: server_id.0 as u64,
9611 error_count: summary.error_count as u32,
9612 warning_count: summary.warning_count as u32,
9613 }),
9614 more_summaries: Vec::new(),
9615 })
9616 }
9617 }
9618 }
9619 updated_diagnostics_paths
9620 .entry(server_id)
9621 .or_insert_with(Vec::new)
9622 .push(project_path);
9623 }
9624
9625 if let Some((diagnostics_summary, (downstream_client, _))) =
9626 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9627 {
9628 downstream_client.send(diagnostics_summary).log_err();
9629 }
9630 for (server_id, paths) in updated_diagnostics_paths {
9631 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9632 }
9633 Ok(())
9634 })
9635 }
9636
9637 async fn handle_start_language_server(
9638 lsp_store: Entity<Self>,
9639 envelope: TypedEnvelope<proto::StartLanguageServer>,
9640 mut cx: AsyncApp,
9641 ) -> Result<()> {
9642 let server = envelope.payload.server.context("invalid server")?;
9643 let server_capabilities =
9644 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9645 .with_context(|| {
9646 format!(
9647 "incorrect server capabilities {}",
9648 envelope.payload.capabilities
9649 )
9650 })?;
9651 lsp_store.update(&mut cx, |lsp_store, cx| {
9652 let server_id = LanguageServerId(server.id as usize);
9653 let server_name = LanguageServerName::from_proto(server.name.clone());
9654 lsp_store
9655 .lsp_server_capabilities
9656 .insert(server_id, server_capabilities);
9657 lsp_store.language_server_statuses.insert(
9658 server_id,
9659 LanguageServerStatus {
9660 name: server_name.clone(),
9661 server_version: None,
9662 server_readable_version: None,
9663 pending_work: Default::default(),
9664 has_pending_diagnostic_updates: false,
9665 progress_tokens: Default::default(),
9666 worktree: server.worktree_id.map(WorktreeId::from_proto),
9667 binary: None,
9668 configuration: None,
9669 workspace_folders: BTreeSet::new(),
9670 process_id: None,
9671 },
9672 );
9673 cx.emit(LspStoreEvent::LanguageServerAdded(
9674 server_id,
9675 server_name,
9676 server.worktree_id.map(WorktreeId::from_proto),
9677 ));
9678 cx.notify();
9679 });
9680 Ok(())
9681 }
9682
9683 async fn handle_update_language_server(
9684 lsp_store: Entity<Self>,
9685 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9686 mut cx: AsyncApp,
9687 ) -> Result<()> {
9688 lsp_store.update(&mut cx, |lsp_store, cx| {
9689 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9690
9691 match envelope.payload.variant.context("invalid variant")? {
9692 proto::update_language_server::Variant::WorkStart(payload) => {
9693 lsp_store.on_lsp_work_start(
9694 language_server_id,
9695 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9696 .context("invalid progress token value")?,
9697 LanguageServerProgress {
9698 title: payload.title,
9699 is_disk_based_diagnostics_progress: false,
9700 is_cancellable: payload.is_cancellable.unwrap_or(false),
9701 message: payload.message,
9702 percentage: payload.percentage.map(|p| p as usize),
9703 last_update_at: cx.background_executor().now(),
9704 },
9705 cx,
9706 );
9707 }
9708 proto::update_language_server::Variant::WorkProgress(payload) => {
9709 lsp_store.on_lsp_work_progress(
9710 language_server_id,
9711 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9712 .context("invalid progress token value")?,
9713 LanguageServerProgress {
9714 title: None,
9715 is_disk_based_diagnostics_progress: false,
9716 is_cancellable: payload.is_cancellable.unwrap_or(false),
9717 message: payload.message,
9718 percentage: payload.percentage.map(|p| p as usize),
9719 last_update_at: cx.background_executor().now(),
9720 },
9721 cx,
9722 );
9723 }
9724
9725 proto::update_language_server::Variant::WorkEnd(payload) => {
9726 lsp_store.on_lsp_work_end(
9727 language_server_id,
9728 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9729 .context("invalid progress token value")?,
9730 cx,
9731 );
9732 }
9733
9734 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9735 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9736 }
9737
9738 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9739 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9740 }
9741
9742 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9743 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9744 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9745 cx.emit(LspStoreEvent::LanguageServerUpdate {
9746 language_server_id,
9747 name: envelope
9748 .payload
9749 .server_name
9750 .map(SharedString::new)
9751 .map(LanguageServerName),
9752 message: non_lsp,
9753 });
9754 }
9755 }
9756
9757 Ok(())
9758 })
9759 }
9760
9761 async fn handle_language_server_log(
9762 this: Entity<Self>,
9763 envelope: TypedEnvelope<proto::LanguageServerLog>,
9764 mut cx: AsyncApp,
9765 ) -> Result<()> {
9766 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9767 let log_type = envelope
9768 .payload
9769 .log_type
9770 .map(LanguageServerLogType::from_proto)
9771 .context("invalid language server log type")?;
9772
9773 let message = envelope.payload.message;
9774
9775 this.update(&mut cx, |_, cx| {
9776 cx.emit(LspStoreEvent::LanguageServerLog(
9777 language_server_id,
9778 log_type,
9779 message,
9780 ));
9781 });
9782 Ok(())
9783 }
9784
9785 async fn handle_lsp_ext_cancel_flycheck(
9786 lsp_store: Entity<Self>,
9787 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9788 cx: AsyncApp,
9789 ) -> Result<proto::Ack> {
9790 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9791 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9792 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9793 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9794 } else {
9795 None
9796 }
9797 });
9798 if let Some(task) = task {
9799 task.context("handling lsp ext cancel flycheck")?;
9800 }
9801
9802 Ok(proto::Ack {})
9803 }
9804
9805 async fn handle_lsp_ext_run_flycheck(
9806 lsp_store: Entity<Self>,
9807 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9808 mut cx: AsyncApp,
9809 ) -> Result<proto::Ack> {
9810 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9811 lsp_store.update(&mut cx, |lsp_store, cx| {
9812 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9813 let text_document = if envelope.payload.current_file_only {
9814 let buffer_id = envelope
9815 .payload
9816 .buffer_id
9817 .map(|id| BufferId::new(id))
9818 .transpose()?;
9819 buffer_id
9820 .and_then(|buffer_id| {
9821 lsp_store
9822 .buffer_store()
9823 .read(cx)
9824 .get(buffer_id)
9825 .and_then(|buffer| {
9826 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9827 })
9828 .map(|path| make_text_document_identifier(&path))
9829 })
9830 .transpose()?
9831 } else {
9832 None
9833 };
9834 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9835 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9836 )?;
9837 }
9838 anyhow::Ok(())
9839 })?;
9840
9841 Ok(proto::Ack {})
9842 }
9843
9844 async fn handle_lsp_ext_clear_flycheck(
9845 lsp_store: Entity<Self>,
9846 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9847 cx: AsyncApp,
9848 ) -> Result<proto::Ack> {
9849 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9850 lsp_store.read_with(&cx, |lsp_store, _| {
9851 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9852 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9853 } else {
9854 None
9855 }
9856 });
9857
9858 Ok(proto::Ack {})
9859 }
9860
9861 pub fn disk_based_diagnostics_started(
9862 &mut self,
9863 language_server_id: LanguageServerId,
9864 cx: &mut Context<Self>,
9865 ) {
9866 if let Some(language_server_status) =
9867 self.language_server_statuses.get_mut(&language_server_id)
9868 {
9869 language_server_status.has_pending_diagnostic_updates = true;
9870 }
9871
9872 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9873 cx.emit(LspStoreEvent::LanguageServerUpdate {
9874 language_server_id,
9875 name: self
9876 .language_server_adapter_for_id(language_server_id)
9877 .map(|adapter| adapter.name()),
9878 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9879 Default::default(),
9880 ),
9881 })
9882 }
9883
9884 pub fn disk_based_diagnostics_finished(
9885 &mut self,
9886 language_server_id: LanguageServerId,
9887 cx: &mut Context<Self>,
9888 ) {
9889 if let Some(language_server_status) =
9890 self.language_server_statuses.get_mut(&language_server_id)
9891 {
9892 language_server_status.has_pending_diagnostic_updates = false;
9893 }
9894
9895 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9896 cx.emit(LspStoreEvent::LanguageServerUpdate {
9897 language_server_id,
9898 name: self
9899 .language_server_adapter_for_id(language_server_id)
9900 .map(|adapter| adapter.name()),
9901 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9902 Default::default(),
9903 ),
9904 })
9905 }
9906
9907 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9908 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9909 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9910 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9911 // the language server might take some time to publish diagnostics.
9912 fn simulate_disk_based_diagnostics_events_if_needed(
9913 &mut self,
9914 language_server_id: LanguageServerId,
9915 cx: &mut Context<Self>,
9916 ) {
9917 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9918
9919 let Some(LanguageServerState::Running {
9920 simulate_disk_based_diagnostics_completion,
9921 adapter,
9922 ..
9923 }) = self
9924 .as_local_mut()
9925 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9926 else {
9927 return;
9928 };
9929
9930 if adapter.disk_based_diagnostics_progress_token.is_some() {
9931 return;
9932 }
9933
9934 let prev_task =
9935 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9936 cx.background_executor()
9937 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9938 .await;
9939
9940 this.update(cx, |this, cx| {
9941 this.disk_based_diagnostics_finished(language_server_id, cx);
9942
9943 if let Some(LanguageServerState::Running {
9944 simulate_disk_based_diagnostics_completion,
9945 ..
9946 }) = this.as_local_mut().and_then(|local_store| {
9947 local_store.language_servers.get_mut(&language_server_id)
9948 }) {
9949 *simulate_disk_based_diagnostics_completion = None;
9950 }
9951 })
9952 .ok();
9953 }));
9954
9955 if prev_task.is_none() {
9956 self.disk_based_diagnostics_started(language_server_id, cx);
9957 }
9958 }
9959
9960 pub fn language_server_statuses(
9961 &self,
9962 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9963 self.language_server_statuses
9964 .iter()
9965 .map(|(key, value)| (*key, value))
9966 }
9967
9968 pub(super) fn did_rename_entry(
9969 &self,
9970 worktree_id: WorktreeId,
9971 old_path: &Path,
9972 new_path: &Path,
9973 is_dir: bool,
9974 ) {
9975 maybe!({
9976 let local_store = self.as_local()?;
9977
9978 let old_uri = lsp::Uri::from_file_path(old_path)
9979 .ok()
9980 .map(|uri| uri.to_string())?;
9981 let new_uri = lsp::Uri::from_file_path(new_path)
9982 .ok()
9983 .map(|uri| uri.to_string())?;
9984
9985 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9986 let Some(filter) = local_store
9987 .language_server_paths_watched_for_rename
9988 .get(&language_server.server_id())
9989 else {
9990 continue;
9991 };
9992
9993 if filter.should_send_did_rename(&old_uri, is_dir) {
9994 language_server
9995 .notify::<DidRenameFiles>(RenameFilesParams {
9996 files: vec![FileRename {
9997 old_uri: old_uri.clone(),
9998 new_uri: new_uri.clone(),
9999 }],
10000 })
10001 .ok();
10002 }
10003 }
10004 Some(())
10005 });
10006 }
10007
10008 pub(super) fn will_rename_entry(
10009 this: WeakEntity<Self>,
10010 worktree_id: WorktreeId,
10011 old_path: &Path,
10012 new_path: &Path,
10013 is_dir: bool,
10014 cx: AsyncApp,
10015 ) -> Task<ProjectTransaction> {
10016 let old_uri = lsp::Uri::from_file_path(old_path)
10017 .ok()
10018 .map(|uri| uri.to_string());
10019 let new_uri = lsp::Uri::from_file_path(new_path)
10020 .ok()
10021 .map(|uri| uri.to_string());
10022 cx.spawn(async move |cx| {
10023 let mut tasks = vec![];
10024 this.update(cx, |this, cx| {
10025 let local_store = this.as_local()?;
10026 let old_uri = old_uri?;
10027 let new_uri = new_uri?;
10028 for language_server in local_store.language_servers_for_worktree(worktree_id) {
10029 let Some(filter) = local_store
10030 .language_server_paths_watched_for_rename
10031 .get(&language_server.server_id())
10032 else {
10033 continue;
10034 };
10035
10036 if !filter.should_send_will_rename(&old_uri, is_dir) {
10037 continue;
10038 }
10039 let request_timeout = ProjectSettings::get_global(cx)
10040 .global_lsp_settings
10041 .get_request_timeout();
10042
10043 let apply_edit = cx.spawn({
10044 let old_uri = old_uri.clone();
10045 let new_uri = new_uri.clone();
10046 let language_server = language_server.clone();
10047 async move |this, cx| {
10048 let edit = language_server
10049 .request::<WillRenameFiles>(
10050 RenameFilesParams {
10051 files: vec![FileRename { old_uri, new_uri }],
10052 },
10053 request_timeout,
10054 )
10055 .await
10056 .into_response()
10057 .context("will rename files")
10058 .log_err()
10059 .flatten()?;
10060
10061 LocalLspStore::deserialize_workspace_edit(
10062 this.upgrade()?,
10063 edit,
10064 false,
10065 language_server.clone(),
10066 cx,
10067 )
10068 .await
10069 .ok()
10070 }
10071 });
10072 tasks.push(apply_edit);
10073 }
10074 Some(())
10075 })
10076 .ok()
10077 .flatten();
10078 let mut merged_transaction = ProjectTransaction::default();
10079 for task in tasks {
10080 // Await on tasks sequentially so that the order of application of edits is deterministic
10081 // (at least with regards to the order of registration of language servers)
10082 if let Some(transaction) = task.await {
10083 for (buffer, buffer_transaction) in transaction.0 {
10084 merged_transaction.0.insert(buffer, buffer_transaction);
10085 }
10086 }
10087 }
10088 merged_transaction
10089 })
10090 }
10091
10092 fn lsp_notify_abs_paths_changed(
10093 &mut self,
10094 server_id: LanguageServerId,
10095 changes: Vec<PathEvent>,
10096 ) {
10097 maybe!({
10098 let server = self.language_server_for_id(server_id)?;
10099 let changes = changes
10100 .into_iter()
10101 .filter_map(|event| {
10102 let typ = match event.kind? {
10103 PathEventKind::Created => lsp::FileChangeType::CREATED,
10104 PathEventKind::Removed => lsp::FileChangeType::DELETED,
10105 PathEventKind::Changed | PathEventKind::Rescan => {
10106 lsp::FileChangeType::CHANGED
10107 }
10108 };
10109 Some(lsp::FileEvent {
10110 uri: file_path_to_lsp_url(&event.path).log_err()?,
10111 typ,
10112 })
10113 })
10114 .collect::<Vec<_>>();
10115 if !changes.is_empty() {
10116 server
10117 .notify::<lsp::notification::DidChangeWatchedFiles>(
10118 lsp::DidChangeWatchedFilesParams { changes },
10119 )
10120 .ok();
10121 }
10122 Some(())
10123 });
10124 }
10125
10126 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10127 self.as_local()?.language_server_for_id(id)
10128 }
10129
10130 fn on_lsp_progress(
10131 &mut self,
10132 progress_params: lsp::ProgressParams,
10133 language_server_id: LanguageServerId,
10134 disk_based_diagnostics_progress_token: Option<String>,
10135 cx: &mut Context<Self>,
10136 ) {
10137 match progress_params.value {
10138 lsp::ProgressParamsValue::WorkDone(progress) => {
10139 self.handle_work_done_progress(
10140 progress,
10141 language_server_id,
10142 disk_based_diagnostics_progress_token,
10143 ProgressToken::from_lsp(progress_params.token),
10144 cx,
10145 );
10146 }
10147 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10148 let registration_id = match progress_params.token {
10149 lsp::NumberOrString::Number(_) => None,
10150 lsp::NumberOrString::String(token) => token
10151 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10152 .map(|(_, id)| id.to_owned()),
10153 };
10154 if let Some(LanguageServerState::Running {
10155 workspace_diagnostics_refresh_tasks,
10156 ..
10157 }) = self
10158 .as_local_mut()
10159 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10160 && let Some(workspace_diagnostics) =
10161 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10162 {
10163 workspace_diagnostics.progress_tx.try_send(()).ok();
10164 self.apply_workspace_diagnostic_report(
10165 language_server_id,
10166 report,
10167 registration_id.map(SharedString::from),
10168 cx,
10169 )
10170 }
10171 }
10172 }
10173 }
10174
10175 fn handle_work_done_progress(
10176 &mut self,
10177 progress: lsp::WorkDoneProgress,
10178 language_server_id: LanguageServerId,
10179 disk_based_diagnostics_progress_token: Option<String>,
10180 token: ProgressToken,
10181 cx: &mut Context<Self>,
10182 ) {
10183 let language_server_status =
10184 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10185 status
10186 } else {
10187 return;
10188 };
10189
10190 if !language_server_status.progress_tokens.contains(&token) {
10191 return;
10192 }
10193
10194 let is_disk_based_diagnostics_progress =
10195 if let (Some(disk_based_token), ProgressToken::String(token)) =
10196 (&disk_based_diagnostics_progress_token, &token)
10197 {
10198 token.starts_with(disk_based_token)
10199 } else {
10200 false
10201 };
10202
10203 match progress {
10204 lsp::WorkDoneProgress::Begin(report) => {
10205 if is_disk_based_diagnostics_progress {
10206 self.disk_based_diagnostics_started(language_server_id, cx);
10207 }
10208 self.on_lsp_work_start(
10209 language_server_id,
10210 token.clone(),
10211 LanguageServerProgress {
10212 title: Some(report.title),
10213 is_disk_based_diagnostics_progress,
10214 is_cancellable: report.cancellable.unwrap_or(false),
10215 message: report.message.clone(),
10216 percentage: report.percentage.map(|p| p as usize),
10217 last_update_at: cx.background_executor().now(),
10218 },
10219 cx,
10220 );
10221 }
10222 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10223 language_server_id,
10224 token,
10225 LanguageServerProgress {
10226 title: None,
10227 is_disk_based_diagnostics_progress,
10228 is_cancellable: report.cancellable.unwrap_or(false),
10229 message: report.message,
10230 percentage: report.percentage.map(|p| p as usize),
10231 last_update_at: cx.background_executor().now(),
10232 },
10233 cx,
10234 ),
10235 lsp::WorkDoneProgress::End(_) => {
10236 language_server_status.progress_tokens.remove(&token);
10237 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10238 if is_disk_based_diagnostics_progress {
10239 self.disk_based_diagnostics_finished(language_server_id, cx);
10240 }
10241 }
10242 }
10243 }
10244
10245 fn on_lsp_work_start(
10246 &mut self,
10247 language_server_id: LanguageServerId,
10248 token: ProgressToken,
10249 progress: LanguageServerProgress,
10250 cx: &mut Context<Self>,
10251 ) {
10252 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10253 status.pending_work.insert(token.clone(), progress.clone());
10254 cx.notify();
10255 }
10256 cx.emit(LspStoreEvent::LanguageServerUpdate {
10257 language_server_id,
10258 name: self
10259 .language_server_adapter_for_id(language_server_id)
10260 .map(|adapter| adapter.name()),
10261 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10262 token: Some(token.to_proto()),
10263 title: progress.title,
10264 message: progress.message,
10265 percentage: progress.percentage.map(|p| p as u32),
10266 is_cancellable: Some(progress.is_cancellable),
10267 }),
10268 })
10269 }
10270
10271 fn on_lsp_work_progress(
10272 &mut self,
10273 language_server_id: LanguageServerId,
10274 token: ProgressToken,
10275 progress: LanguageServerProgress,
10276 cx: &mut Context<Self>,
10277 ) {
10278 let mut did_update = false;
10279 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10280 match status.pending_work.entry(token.clone()) {
10281 btree_map::Entry::Vacant(entry) => {
10282 entry.insert(progress.clone());
10283 did_update = true;
10284 }
10285 btree_map::Entry::Occupied(mut entry) => {
10286 let entry = entry.get_mut();
10287 if (progress.last_update_at - entry.last_update_at)
10288 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10289 {
10290 entry.last_update_at = progress.last_update_at;
10291 if progress.message.is_some() {
10292 entry.message = progress.message.clone();
10293 }
10294 if progress.percentage.is_some() {
10295 entry.percentage = progress.percentage;
10296 }
10297 if progress.is_cancellable != entry.is_cancellable {
10298 entry.is_cancellable = progress.is_cancellable;
10299 }
10300 did_update = true;
10301 }
10302 }
10303 }
10304 }
10305
10306 if did_update {
10307 cx.emit(LspStoreEvent::LanguageServerUpdate {
10308 language_server_id,
10309 name: self
10310 .language_server_adapter_for_id(language_server_id)
10311 .map(|adapter| adapter.name()),
10312 message: proto::update_language_server::Variant::WorkProgress(
10313 proto::LspWorkProgress {
10314 token: Some(token.to_proto()),
10315 message: progress.message,
10316 percentage: progress.percentage.map(|p| p as u32),
10317 is_cancellable: Some(progress.is_cancellable),
10318 },
10319 ),
10320 })
10321 }
10322 }
10323
10324 fn on_lsp_work_end(
10325 &mut self,
10326 language_server_id: LanguageServerId,
10327 token: ProgressToken,
10328 cx: &mut Context<Self>,
10329 ) {
10330 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10331 if let Some(work) = status.pending_work.remove(&token)
10332 && !work.is_disk_based_diagnostics_progress
10333 {
10334 cx.emit(LspStoreEvent::RefreshInlayHints {
10335 server_id: language_server_id,
10336 request_id: None,
10337 });
10338 }
10339 cx.notify();
10340 }
10341
10342 cx.emit(LspStoreEvent::LanguageServerUpdate {
10343 language_server_id,
10344 name: self
10345 .language_server_adapter_for_id(language_server_id)
10346 .map(|adapter| adapter.name()),
10347 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10348 token: Some(token.to_proto()),
10349 }),
10350 })
10351 }
10352
10353 pub async fn handle_resolve_completion_documentation(
10354 this: Entity<Self>,
10355 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10356 mut cx: AsyncApp,
10357 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10358 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10359
10360 let completion = this
10361 .read_with(&cx, |this, cx| {
10362 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10363 let server = this
10364 .language_server_for_id(id)
10365 .with_context(|| format!("No language server {id}"))?;
10366
10367 let request_timeout = ProjectSettings::get_global(cx)
10368 .global_lsp_settings
10369 .get_request_timeout();
10370
10371 anyhow::Ok(cx.background_spawn(async move {
10372 let can_resolve = server
10373 .capabilities()
10374 .completion_provider
10375 .as_ref()
10376 .and_then(|options| options.resolve_provider)
10377 .unwrap_or(false);
10378 if can_resolve {
10379 server
10380 .request::<lsp::request::ResolveCompletionItem>(
10381 lsp_completion,
10382 request_timeout,
10383 )
10384 .await
10385 .into_response()
10386 .context("resolve completion item")
10387 } else {
10388 anyhow::Ok(lsp_completion)
10389 }
10390 }))
10391 })?
10392 .await?;
10393
10394 let mut documentation_is_markdown = false;
10395 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10396 let documentation = match completion.documentation {
10397 Some(lsp::Documentation::String(text)) => text,
10398
10399 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10400 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10401 value
10402 }
10403
10404 _ => String::new(),
10405 };
10406
10407 // If we have a new buffer_id, that means we're talking to a new client
10408 // and want to check for new text_edits in the completion too.
10409 let mut old_replace_start = None;
10410 let mut old_replace_end = None;
10411 let mut old_insert_start = None;
10412 let mut old_insert_end = None;
10413 let mut new_text = String::default();
10414 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10415 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10416 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10417 anyhow::Ok(buffer.read(cx).snapshot())
10418 })?;
10419
10420 if let Some(text_edit) = completion.text_edit.as_ref() {
10421 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10422
10423 if let Some(mut edit) = edit {
10424 LineEnding::normalize(&mut edit.new_text);
10425
10426 new_text = edit.new_text;
10427 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10428 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10429 if let Some(insert_range) = edit.insert_range {
10430 old_insert_start = Some(serialize_anchor(&insert_range.start));
10431 old_insert_end = Some(serialize_anchor(&insert_range.end));
10432 }
10433 }
10434 }
10435 }
10436
10437 Ok(proto::ResolveCompletionDocumentationResponse {
10438 documentation,
10439 documentation_is_markdown,
10440 old_replace_start,
10441 old_replace_end,
10442 new_text,
10443 lsp_completion,
10444 old_insert_start,
10445 old_insert_end,
10446 })
10447 }
10448
10449 async fn handle_on_type_formatting(
10450 this: Entity<Self>,
10451 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10452 mut cx: AsyncApp,
10453 ) -> Result<proto::OnTypeFormattingResponse> {
10454 let on_type_formatting = this.update(&mut cx, |this, cx| {
10455 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10456 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10457 let position = envelope
10458 .payload
10459 .position
10460 .and_then(deserialize_anchor)
10461 .context("invalid position")?;
10462 anyhow::Ok(this.apply_on_type_formatting(
10463 buffer,
10464 position,
10465 envelope.payload.trigger.clone(),
10466 cx,
10467 ))
10468 })?;
10469
10470 let transaction = on_type_formatting
10471 .await?
10472 .as_ref()
10473 .map(language::proto::serialize_transaction);
10474 Ok(proto::OnTypeFormattingResponse { transaction })
10475 }
10476
10477 async fn handle_pull_workspace_diagnostics(
10478 lsp_store: Entity<Self>,
10479 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10480 mut cx: AsyncApp,
10481 ) -> Result<proto::Ack> {
10482 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10483 lsp_store.update(&mut cx, |lsp_store, _| {
10484 lsp_store.pull_workspace_diagnostics(server_id);
10485 });
10486 Ok(proto::Ack {})
10487 }
10488
10489 async fn handle_open_buffer_for_symbol(
10490 this: Entity<Self>,
10491 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10492 mut cx: AsyncApp,
10493 ) -> Result<proto::OpenBufferForSymbolResponse> {
10494 let peer_id = envelope.original_sender_id().unwrap_or_default();
10495 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10496 let symbol = Self::deserialize_symbol(symbol)?;
10497 this.read_with(&cx, |this, _| {
10498 if let SymbolLocation::OutsideProject {
10499 abs_path,
10500 signature,
10501 } = &symbol.path
10502 {
10503 let new_signature = this.symbol_signature(&abs_path);
10504 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10505 }
10506 Ok(())
10507 })?;
10508 let buffer = this
10509 .update(&mut cx, |this, cx| {
10510 this.open_buffer_for_symbol(
10511 &Symbol {
10512 language_server_name: symbol.language_server_name,
10513 source_worktree_id: symbol.source_worktree_id,
10514 source_language_server_id: symbol.source_language_server_id,
10515 path: symbol.path,
10516 name: symbol.name,
10517 kind: symbol.kind,
10518 range: symbol.range,
10519 label: CodeLabel::default(),
10520 container_name: symbol.container_name,
10521 },
10522 cx,
10523 )
10524 })
10525 .await?;
10526
10527 this.update(&mut cx, |this, cx| {
10528 let is_private = buffer
10529 .read(cx)
10530 .file()
10531 .map(|f| f.is_private())
10532 .unwrap_or_default();
10533 if is_private {
10534 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10535 } else {
10536 this.buffer_store
10537 .update(cx, |buffer_store, cx| {
10538 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10539 })
10540 .detach_and_log_err(cx);
10541 let buffer_id = buffer.read(cx).remote_id().to_proto();
10542 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10543 }
10544 })
10545 }
10546
10547 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10548 let mut hasher = Sha256::new();
10549 hasher.update(abs_path.to_string_lossy().as_bytes());
10550 hasher.update(self.nonce.to_be_bytes());
10551 hasher.finalize().as_slice().try_into().unwrap()
10552 }
10553
10554 pub async fn handle_get_project_symbols(
10555 this: Entity<Self>,
10556 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10557 mut cx: AsyncApp,
10558 ) -> Result<proto::GetProjectSymbolsResponse> {
10559 let symbols = this
10560 .update(&mut cx, |this, cx| {
10561 this.symbols(&envelope.payload.query, cx)
10562 })
10563 .await?;
10564
10565 Ok(proto::GetProjectSymbolsResponse {
10566 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10567 })
10568 }
10569
10570 pub async fn handle_restart_language_servers(
10571 this: Entity<Self>,
10572 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10573 mut cx: AsyncApp,
10574 ) -> Result<proto::Ack> {
10575 this.update(&mut cx, |lsp_store, cx| {
10576 let buffers =
10577 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10578 lsp_store.restart_language_servers_for_buffers(
10579 buffers,
10580 envelope
10581 .payload
10582 .only_servers
10583 .into_iter()
10584 .filter_map(|selector| {
10585 Some(match selector.selector? {
10586 proto::language_server_selector::Selector::ServerId(server_id) => {
10587 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10588 }
10589 proto::language_server_selector::Selector::Name(name) => {
10590 LanguageServerSelector::Name(LanguageServerName(
10591 SharedString::from(name),
10592 ))
10593 }
10594 })
10595 })
10596 .collect(),
10597 cx,
10598 );
10599 });
10600
10601 Ok(proto::Ack {})
10602 }
10603
10604 pub async fn handle_stop_language_servers(
10605 lsp_store: Entity<Self>,
10606 envelope: TypedEnvelope<proto::StopLanguageServers>,
10607 mut cx: AsyncApp,
10608 ) -> Result<proto::Ack> {
10609 lsp_store.update(&mut cx, |lsp_store, cx| {
10610 if envelope.payload.all
10611 && envelope.payload.also_servers.is_empty()
10612 && envelope.payload.buffer_ids.is_empty()
10613 {
10614 lsp_store.stop_all_language_servers(cx);
10615 } else {
10616 let buffers =
10617 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10618 lsp_store
10619 .stop_language_servers_for_buffers(
10620 buffers,
10621 envelope
10622 .payload
10623 .also_servers
10624 .into_iter()
10625 .filter_map(|selector| {
10626 Some(match selector.selector? {
10627 proto::language_server_selector::Selector::ServerId(
10628 server_id,
10629 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10630 server_id,
10631 )),
10632 proto::language_server_selector::Selector::Name(name) => {
10633 LanguageServerSelector::Name(LanguageServerName(
10634 SharedString::from(name),
10635 ))
10636 }
10637 })
10638 })
10639 .collect(),
10640 cx,
10641 )
10642 .detach_and_log_err(cx);
10643 }
10644 });
10645
10646 Ok(proto::Ack {})
10647 }
10648
10649 pub async fn handle_cancel_language_server_work(
10650 lsp_store: Entity<Self>,
10651 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10652 mut cx: AsyncApp,
10653 ) -> Result<proto::Ack> {
10654 lsp_store.update(&mut cx, |lsp_store, cx| {
10655 if let Some(work) = envelope.payload.work {
10656 match work {
10657 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10658 let buffers =
10659 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10660 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10661 }
10662 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10663 let server_id = LanguageServerId::from_proto(work.language_server_id);
10664 let token = work
10665 .token
10666 .map(|token| {
10667 ProgressToken::from_proto(token)
10668 .context("invalid work progress token")
10669 })
10670 .transpose()?;
10671 lsp_store.cancel_language_server_work(server_id, token, cx);
10672 }
10673 }
10674 }
10675 anyhow::Ok(())
10676 })?;
10677
10678 Ok(proto::Ack {})
10679 }
10680
10681 fn buffer_ids_to_buffers(
10682 &mut self,
10683 buffer_ids: impl Iterator<Item = u64>,
10684 cx: &mut Context<Self>,
10685 ) -> Vec<Entity<Buffer>> {
10686 buffer_ids
10687 .into_iter()
10688 .flat_map(|buffer_id| {
10689 self.buffer_store
10690 .read(cx)
10691 .get(BufferId::new(buffer_id).log_err()?)
10692 })
10693 .collect::<Vec<_>>()
10694 }
10695
10696 async fn handle_apply_additional_edits_for_completion(
10697 this: Entity<Self>,
10698 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10699 mut cx: AsyncApp,
10700 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10701 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10702 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10703 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10704 let completion = Self::deserialize_completion(
10705 envelope.payload.completion.context("invalid completion")?,
10706 )?;
10707 let all_commit_ranges = envelope
10708 .payload
10709 .all_commit_ranges
10710 .into_iter()
10711 .map(language::proto::deserialize_anchor_range)
10712 .collect::<Result<Vec<_>, _>>()?;
10713 anyhow::Ok((buffer, completion, all_commit_ranges))
10714 })?;
10715
10716 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10717 this.apply_additional_edits_for_completion(
10718 buffer,
10719 Rc::new(RefCell::new(Box::new([Completion {
10720 replace_range: completion.replace_range,
10721 new_text: completion.new_text,
10722 source: completion.source,
10723 documentation: None,
10724 label: CodeLabel::default(),
10725 match_start: None,
10726 snippet_deduplication_key: None,
10727 insert_text_mode: None,
10728 icon_path: None,
10729 confirm: None,
10730 }]))),
10731 0,
10732 false,
10733 all_commit_ranges,
10734 cx,
10735 )
10736 });
10737
10738 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10739 transaction: apply_additional_edits
10740 .await?
10741 .as_ref()
10742 .map(language::proto::serialize_transaction),
10743 })
10744 }
10745
10746 pub fn last_formatting_failure(&self) -> Option<&str> {
10747 self.last_formatting_failure.as_deref()
10748 }
10749
10750 pub fn reset_last_formatting_failure(&mut self) {
10751 self.last_formatting_failure = None;
10752 }
10753
10754 pub fn environment_for_buffer(
10755 &self,
10756 buffer: &Entity<Buffer>,
10757 cx: &mut Context<Self>,
10758 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10759 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10760 environment.update(cx, |env, cx| {
10761 env.buffer_environment(buffer, &self.worktree_store, cx)
10762 })
10763 } else {
10764 Task::ready(None).shared()
10765 }
10766 }
10767
10768 pub fn format(
10769 &mut self,
10770 buffers: HashSet<Entity<Buffer>>,
10771 target: LspFormatTarget,
10772 push_to_history: bool,
10773 trigger: FormatTrigger,
10774 cx: &mut Context<Self>,
10775 ) -> Task<anyhow::Result<ProjectTransaction>> {
10776 let logger = zlog::scoped!("format");
10777 if self.as_local().is_some() {
10778 zlog::trace!(logger => "Formatting locally");
10779 let logger = zlog::scoped!(logger => "local");
10780 let buffers = buffers
10781 .into_iter()
10782 .map(|buffer_handle| {
10783 let buffer = buffer_handle.read(cx);
10784 let buffer_abs_path = File::from_dyn(buffer.file())
10785 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10786
10787 (buffer_handle, buffer_abs_path, buffer.remote_id())
10788 })
10789 .collect::<Vec<_>>();
10790
10791 cx.spawn(async move |lsp_store, cx| {
10792 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10793
10794 for (handle, abs_path, id) in buffers {
10795 let env = lsp_store
10796 .update(cx, |lsp_store, cx| {
10797 lsp_store.environment_for_buffer(&handle, cx)
10798 })?
10799 .await;
10800
10801 let ranges = match &target {
10802 LspFormatTarget::Buffers => None,
10803 LspFormatTarget::Ranges(ranges) => {
10804 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10805 }
10806 };
10807
10808 formattable_buffers.push(FormattableBuffer {
10809 handle,
10810 abs_path,
10811 env,
10812 ranges,
10813 });
10814 }
10815 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10816
10817 let format_timer = zlog::time!(logger => "Formatting buffers");
10818 let result = LocalLspStore::format_locally(
10819 lsp_store.clone(),
10820 formattable_buffers,
10821 push_to_history,
10822 trigger,
10823 logger,
10824 cx,
10825 )
10826 .await;
10827 format_timer.end();
10828
10829 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10830
10831 lsp_store.update(cx, |lsp_store, _| {
10832 lsp_store.update_last_formatting_failure(&result);
10833 })?;
10834
10835 result
10836 })
10837 } else if let Some((client, project_id)) = self.upstream_client() {
10838 zlog::trace!(logger => "Formatting remotely");
10839 let logger = zlog::scoped!(logger => "remote");
10840
10841 let buffer_ranges = match &target {
10842 LspFormatTarget::Buffers => Vec::new(),
10843 LspFormatTarget::Ranges(ranges) => ranges
10844 .iter()
10845 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10846 buffer_id: buffer_id.to_proto(),
10847 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10848 })
10849 .collect(),
10850 };
10851
10852 let buffer_store = self.buffer_store();
10853 cx.spawn(async move |lsp_store, cx| {
10854 zlog::trace!(logger => "Sending remote format request");
10855 let request_timer = zlog::time!(logger => "remote format request");
10856 let result = client
10857 .request(proto::FormatBuffers {
10858 project_id,
10859 trigger: trigger as i32,
10860 buffer_ids: buffers
10861 .iter()
10862 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10863 .collect(),
10864 buffer_ranges,
10865 })
10866 .await
10867 .and_then(|result| result.transaction.context("missing transaction"));
10868 request_timer.end();
10869
10870 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10871
10872 lsp_store.update(cx, |lsp_store, _| {
10873 lsp_store.update_last_formatting_failure(&result);
10874 })?;
10875
10876 let transaction_response = result?;
10877 let _timer = zlog::time!(logger => "deserializing project transaction");
10878 buffer_store
10879 .update(cx, |buffer_store, cx| {
10880 buffer_store.deserialize_project_transaction(
10881 transaction_response,
10882 push_to_history,
10883 cx,
10884 )
10885 })
10886 .await
10887 })
10888 } else {
10889 zlog::trace!(logger => "Not formatting");
10890 Task::ready(Ok(ProjectTransaction::default()))
10891 }
10892 }
10893
10894 async fn handle_format_buffers(
10895 this: Entity<Self>,
10896 envelope: TypedEnvelope<proto::FormatBuffers>,
10897 mut cx: AsyncApp,
10898 ) -> Result<proto::FormatBuffersResponse> {
10899 let sender_id = envelope.original_sender_id().unwrap_or_default();
10900 let format = this.update(&mut cx, |this, cx| {
10901 let mut buffers = HashSet::default();
10902 for buffer_id in &envelope.payload.buffer_ids {
10903 let buffer_id = BufferId::new(*buffer_id)?;
10904 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10905 }
10906
10907 let target = if envelope.payload.buffer_ranges.is_empty() {
10908 LspFormatTarget::Buffers
10909 } else {
10910 let mut ranges_map = BTreeMap::new();
10911 for buffer_range in &envelope.payload.buffer_ranges {
10912 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10913 let ranges: Result<Vec<_>> = buffer_range
10914 .ranges
10915 .iter()
10916 .map(|range| {
10917 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10918 })
10919 .collect();
10920 ranges_map.insert(buffer_id, ranges?);
10921 }
10922 LspFormatTarget::Ranges(ranges_map)
10923 };
10924
10925 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10926 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10927 })?;
10928
10929 let project_transaction = format.await?;
10930 let project_transaction = this.update(&mut cx, |this, cx| {
10931 this.buffer_store.update(cx, |buffer_store, cx| {
10932 buffer_store.serialize_project_transaction_for_peer(
10933 project_transaction,
10934 sender_id,
10935 cx,
10936 )
10937 })
10938 });
10939 Ok(proto::FormatBuffersResponse {
10940 transaction: Some(project_transaction),
10941 })
10942 }
10943
10944 async fn handle_apply_code_action_kind(
10945 this: Entity<Self>,
10946 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10947 mut cx: AsyncApp,
10948 ) -> Result<proto::ApplyCodeActionKindResponse> {
10949 let sender_id = envelope.original_sender_id().unwrap_or_default();
10950 let format = this.update(&mut cx, |this, cx| {
10951 let mut buffers = HashSet::default();
10952 for buffer_id in &envelope.payload.buffer_ids {
10953 let buffer_id = BufferId::new(*buffer_id)?;
10954 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10955 }
10956 let kind = match envelope.payload.kind.as_str() {
10957 "" => CodeActionKind::EMPTY,
10958 "quickfix" => CodeActionKind::QUICKFIX,
10959 "refactor" => CodeActionKind::REFACTOR,
10960 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10961 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10962 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10963 "source" => CodeActionKind::SOURCE,
10964 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10965 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10966 _ => anyhow::bail!(
10967 "Invalid code action kind {}",
10968 envelope.payload.kind.as_str()
10969 ),
10970 };
10971 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10972 })?;
10973
10974 let project_transaction = format.await?;
10975 let project_transaction = this.update(&mut cx, |this, cx| {
10976 this.buffer_store.update(cx, |buffer_store, cx| {
10977 buffer_store.serialize_project_transaction_for_peer(
10978 project_transaction,
10979 sender_id,
10980 cx,
10981 )
10982 })
10983 });
10984 Ok(proto::ApplyCodeActionKindResponse {
10985 transaction: Some(project_transaction),
10986 })
10987 }
10988
10989 async fn shutdown_language_server(
10990 server_state: Option<LanguageServerState>,
10991 name: LanguageServerName,
10992 cx: &mut AsyncApp,
10993 ) {
10994 let server = match server_state {
10995 Some(LanguageServerState::Starting { startup, .. }) => {
10996 let mut timer = cx
10997 .background_executor()
10998 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10999 .fuse();
11000
11001 select! {
11002 server = startup.fuse() => server,
11003 () = timer => {
11004 log::info!("timeout waiting for language server {name} to finish launching before stopping");
11005 None
11006 },
11007 }
11008 }
11009
11010 Some(LanguageServerState::Running { server, .. }) => Some(server),
11011
11012 None => None,
11013 };
11014
11015 let Some(server) = server else { return };
11016 if let Some(shutdown) = server.shutdown() {
11017 shutdown.await;
11018 }
11019 }
11020
11021 // Returns a list of all of the worktrees which no longer have a language server and the root path
11022 // for the stopped server
11023 fn stop_local_language_server(
11024 &mut self,
11025 server_id: LanguageServerId,
11026 cx: &mut Context<Self>,
11027 ) -> Task<()> {
11028 let local = match &mut self.mode {
11029 LspStoreMode::Local(local) => local,
11030 _ => {
11031 return Task::ready(());
11032 }
11033 };
11034
11035 // Remove this server ID from all entries in the given worktree.
11036 local
11037 .language_server_ids
11038 .retain(|_, state| state.id != server_id);
11039 self.buffer_store.update(cx, |buffer_store, cx| {
11040 for buffer in buffer_store.buffers() {
11041 buffer.update(cx, |buffer, cx| {
11042 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
11043 buffer.set_completion_triggers(server_id, Default::default(), cx);
11044 });
11045 }
11046 });
11047
11048 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
11049 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
11050 summaries.retain(|path, summaries_by_server_id| {
11051 if summaries_by_server_id.remove(&server_id).is_some() {
11052 if let Some((client, project_id)) = self.downstream_client.clone() {
11053 client
11054 .send(proto::UpdateDiagnosticSummary {
11055 project_id,
11056 worktree_id: worktree_id.to_proto(),
11057 summary: Some(proto::DiagnosticSummary {
11058 path: path.as_ref().to_proto(),
11059 language_server_id: server_id.0 as u64,
11060 error_count: 0,
11061 warning_count: 0,
11062 }),
11063 more_summaries: Vec::new(),
11064 })
11065 .log_err();
11066 }
11067 cleared_paths.push(ProjectPath {
11068 worktree_id: *worktree_id,
11069 path: path.clone(),
11070 });
11071 !summaries_by_server_id.is_empty()
11072 } else {
11073 true
11074 }
11075 });
11076 }
11077 if !cleared_paths.is_empty() {
11078 cx.emit(LspStoreEvent::DiagnosticsUpdated {
11079 server_id,
11080 paths: cleared_paths,
11081 });
11082 }
11083
11084 let local = self.as_local_mut().unwrap();
11085 for diagnostics in local.diagnostics.values_mut() {
11086 diagnostics.retain(|_, diagnostics_by_server_id| {
11087 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11088 diagnostics_by_server_id.remove(ix);
11089 !diagnostics_by_server_id.is_empty()
11090 } else {
11091 true
11092 }
11093 });
11094 }
11095 local.language_server_watched_paths.remove(&server_id);
11096
11097 let server_state = local.language_servers.remove(&server_id);
11098 self.cleanup_lsp_data(server_id);
11099 let name = self
11100 .language_server_statuses
11101 .remove(&server_id)
11102 .map(|status| status.name)
11103 .or_else(|| {
11104 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11105 Some(adapter.name())
11106 } else {
11107 None
11108 }
11109 });
11110
11111 if let Some(name) = name {
11112 log::info!("stopping language server {name}");
11113 self.languages
11114 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11115 cx.notify();
11116
11117 return cx.spawn(async move |lsp_store, cx| {
11118 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11119 lsp_store
11120 .update(cx, |lsp_store, cx| {
11121 lsp_store
11122 .languages
11123 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11124 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11125 cx.notify();
11126 })
11127 .ok();
11128 });
11129 }
11130
11131 if server_state.is_some() {
11132 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11133 }
11134 Task::ready(())
11135 }
11136
11137 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11138 self.shutdown_all_language_servers(cx).detach();
11139 }
11140
11141 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11142 if let Some((client, project_id)) = self.upstream_client() {
11143 let request = client.request(proto::StopLanguageServers {
11144 project_id,
11145 buffer_ids: Vec::new(),
11146 also_servers: Vec::new(),
11147 all: true,
11148 });
11149 cx.background_spawn(async move {
11150 request.await.ok();
11151 })
11152 } else {
11153 let Some(local) = self.as_local_mut() else {
11154 return Task::ready(());
11155 };
11156 let language_servers_to_stop = local
11157 .language_server_ids
11158 .values()
11159 .map(|state| state.id)
11160 .collect();
11161 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11162 let tasks = language_servers_to_stop
11163 .into_iter()
11164 .map(|server| self.stop_local_language_server(server, cx))
11165 .collect::<Vec<_>>();
11166 cx.background_spawn(async move {
11167 futures::future::join_all(tasks).await;
11168 })
11169 }
11170 }
11171
11172 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11173 let buffers = self.buffer_store.read(cx).buffers().collect();
11174 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
11175 }
11176
11177 pub fn restart_language_servers_for_buffers(
11178 &mut self,
11179 buffers: Vec<Entity<Buffer>>,
11180 only_restart_servers: HashSet<LanguageServerSelector>,
11181 cx: &mut Context<Self>,
11182 ) {
11183 if let Some((client, project_id)) = self.upstream_client() {
11184 let request = client.request(proto::RestartLanguageServers {
11185 project_id,
11186 buffer_ids: buffers
11187 .into_iter()
11188 .map(|b| b.read(cx).remote_id().to_proto())
11189 .collect(),
11190 only_servers: only_restart_servers
11191 .into_iter()
11192 .map(|selector| {
11193 let selector = match selector {
11194 LanguageServerSelector::Id(language_server_id) => {
11195 proto::language_server_selector::Selector::ServerId(
11196 language_server_id.to_proto(),
11197 )
11198 }
11199 LanguageServerSelector::Name(language_server_name) => {
11200 proto::language_server_selector::Selector::Name(
11201 language_server_name.to_string(),
11202 )
11203 }
11204 };
11205 proto::LanguageServerSelector {
11206 selector: Some(selector),
11207 }
11208 })
11209 .collect(),
11210 all: false,
11211 });
11212 cx.background_spawn(request).detach_and_log_err(cx);
11213 } else {
11214 let stop_task = if only_restart_servers.is_empty() {
11215 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11216 } else {
11217 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11218 };
11219 cx.spawn(async move |lsp_store, cx| {
11220 stop_task.await;
11221 lsp_store.update(cx, |lsp_store, cx| {
11222 for buffer in buffers {
11223 lsp_store.register_buffer_with_language_servers(
11224 &buffer,
11225 only_restart_servers.clone(),
11226 true,
11227 cx,
11228 );
11229 }
11230 })
11231 })
11232 .detach();
11233 }
11234 }
11235
11236 pub fn stop_language_servers_for_buffers(
11237 &mut self,
11238 buffers: Vec<Entity<Buffer>>,
11239 also_stop_servers: HashSet<LanguageServerSelector>,
11240 cx: &mut Context<Self>,
11241 ) -> Task<Result<()>> {
11242 if let Some((client, project_id)) = self.upstream_client() {
11243 let request = client.request(proto::StopLanguageServers {
11244 project_id,
11245 buffer_ids: buffers
11246 .into_iter()
11247 .map(|b| b.read(cx).remote_id().to_proto())
11248 .collect(),
11249 also_servers: also_stop_servers
11250 .into_iter()
11251 .map(|selector| {
11252 let selector = match selector {
11253 LanguageServerSelector::Id(language_server_id) => {
11254 proto::language_server_selector::Selector::ServerId(
11255 language_server_id.to_proto(),
11256 )
11257 }
11258 LanguageServerSelector::Name(language_server_name) => {
11259 proto::language_server_selector::Selector::Name(
11260 language_server_name.to_string(),
11261 )
11262 }
11263 };
11264 proto::LanguageServerSelector {
11265 selector: Some(selector),
11266 }
11267 })
11268 .collect(),
11269 all: false,
11270 });
11271 cx.background_spawn(async move {
11272 let _ = request.await?;
11273 Ok(())
11274 })
11275 } else {
11276 let task =
11277 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11278 cx.background_spawn(async move {
11279 task.await;
11280 Ok(())
11281 })
11282 }
11283 }
11284
11285 fn stop_local_language_servers_for_buffers(
11286 &mut self,
11287 buffers: &[Entity<Buffer>],
11288 also_stop_servers: HashSet<LanguageServerSelector>,
11289 cx: &mut Context<Self>,
11290 ) -> Task<()> {
11291 let Some(local) = self.as_local_mut() else {
11292 return Task::ready(());
11293 };
11294 let mut language_server_names_to_stop = BTreeSet::default();
11295 let mut language_servers_to_stop = also_stop_servers
11296 .into_iter()
11297 .flat_map(|selector| match selector {
11298 LanguageServerSelector::Id(id) => Some(id),
11299 LanguageServerSelector::Name(name) => {
11300 language_server_names_to_stop.insert(name);
11301 None
11302 }
11303 })
11304 .collect::<BTreeSet<_>>();
11305
11306 let mut covered_worktrees = HashSet::default();
11307 for buffer in buffers {
11308 buffer.update(cx, |buffer, cx| {
11309 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11310 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11311 && covered_worktrees.insert(worktree_id)
11312 {
11313 language_server_names_to_stop.retain(|name| {
11314 let old_ids_count = language_servers_to_stop.len();
11315 let all_language_servers_with_this_name = local
11316 .language_server_ids
11317 .iter()
11318 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11319 language_servers_to_stop.extend(all_language_servers_with_this_name);
11320 old_ids_count == language_servers_to_stop.len()
11321 });
11322 }
11323 });
11324 }
11325 for name in language_server_names_to_stop {
11326 language_servers_to_stop.extend(
11327 local
11328 .language_server_ids
11329 .iter()
11330 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11331 );
11332 }
11333
11334 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11335 let tasks = language_servers_to_stop
11336 .into_iter()
11337 .map(|server| self.stop_local_language_server(server, cx))
11338 .collect::<Vec<_>>();
11339
11340 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11341 }
11342
11343 #[cfg(any(test, feature = "test-support"))]
11344 pub fn update_diagnostics(
11345 &mut self,
11346 server_id: LanguageServerId,
11347 diagnostics: lsp::PublishDiagnosticsParams,
11348 result_id: Option<SharedString>,
11349 source_kind: DiagnosticSourceKind,
11350 disk_based_sources: &[String],
11351 cx: &mut Context<Self>,
11352 ) -> Result<()> {
11353 self.merge_lsp_diagnostics(
11354 source_kind,
11355 vec![DocumentDiagnosticsUpdate {
11356 diagnostics,
11357 result_id,
11358 server_id,
11359 disk_based_sources: Cow::Borrowed(disk_based_sources),
11360 registration_id: None,
11361 }],
11362 |_, _, _| false,
11363 cx,
11364 )
11365 }
11366
11367 pub fn merge_lsp_diagnostics(
11368 &mut self,
11369 source_kind: DiagnosticSourceKind,
11370 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11371 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11372 cx: &mut Context<Self>,
11373 ) -> Result<()> {
11374 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11375 let updates = lsp_diagnostics
11376 .into_iter()
11377 .filter_map(|update| {
11378 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11379 Some(DocumentDiagnosticsUpdate {
11380 diagnostics: self.lsp_to_document_diagnostics(
11381 abs_path,
11382 source_kind,
11383 update.server_id,
11384 update.diagnostics,
11385 &update.disk_based_sources,
11386 update.registration_id.clone(),
11387 ),
11388 result_id: update.result_id,
11389 server_id: update.server_id,
11390 disk_based_sources: update.disk_based_sources,
11391 registration_id: update.registration_id,
11392 })
11393 })
11394 .collect();
11395 self.merge_diagnostic_entries(updates, merge, cx)?;
11396 Ok(())
11397 }
11398
11399 fn lsp_to_document_diagnostics(
11400 &mut self,
11401 document_abs_path: PathBuf,
11402 source_kind: DiagnosticSourceKind,
11403 server_id: LanguageServerId,
11404 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11405 disk_based_sources: &[String],
11406 registration_id: Option<SharedString>,
11407 ) -> DocumentDiagnostics {
11408 let mut diagnostics = Vec::default();
11409 let mut primary_diagnostic_group_ids = HashMap::default();
11410 let mut sources_by_group_id = HashMap::default();
11411 let mut supporting_diagnostics = HashMap::default();
11412
11413 let adapter = self.language_server_adapter_for_id(server_id);
11414
11415 // Ensure that primary diagnostics are always the most severe
11416 lsp_diagnostics
11417 .diagnostics
11418 .sort_by_key(|item| item.severity);
11419
11420 for diagnostic in &lsp_diagnostics.diagnostics {
11421 let source = diagnostic.source.as_ref();
11422 let range = range_from_lsp(diagnostic.range);
11423 let is_supporting = diagnostic
11424 .related_information
11425 .as_ref()
11426 .is_some_and(|infos| {
11427 infos.iter().any(|info| {
11428 primary_diagnostic_group_ids.contains_key(&(
11429 source,
11430 diagnostic.code.clone(),
11431 range_from_lsp(info.location.range),
11432 ))
11433 })
11434 });
11435
11436 let is_unnecessary = diagnostic
11437 .tags
11438 .as_ref()
11439 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11440
11441 let underline = self
11442 .language_server_adapter_for_id(server_id)
11443 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11444
11445 if is_supporting {
11446 supporting_diagnostics.insert(
11447 (source, diagnostic.code.clone(), range),
11448 (diagnostic.severity, is_unnecessary),
11449 );
11450 } else {
11451 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11452 let is_disk_based =
11453 source.is_some_and(|source| disk_based_sources.contains(source));
11454
11455 sources_by_group_id.insert(group_id, source);
11456 primary_diagnostic_group_ids
11457 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11458
11459 diagnostics.push(DiagnosticEntry {
11460 range,
11461 diagnostic: Diagnostic {
11462 source: diagnostic.source.clone(),
11463 source_kind,
11464 code: diagnostic.code.clone(),
11465 code_description: diagnostic
11466 .code_description
11467 .as_ref()
11468 .and_then(|d| d.href.clone()),
11469 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11470 markdown: adapter.as_ref().and_then(|adapter| {
11471 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11472 }),
11473 message: diagnostic.message.trim().to_string(),
11474 group_id,
11475 is_primary: true,
11476 is_disk_based,
11477 is_unnecessary,
11478 underline,
11479 data: diagnostic.data.clone(),
11480 registration_id: registration_id.clone(),
11481 },
11482 });
11483 if let Some(infos) = &diagnostic.related_information {
11484 for info in infos {
11485 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11486 let range = range_from_lsp(info.location.range);
11487 diagnostics.push(DiagnosticEntry {
11488 range,
11489 diagnostic: Diagnostic {
11490 source: diagnostic.source.clone(),
11491 source_kind,
11492 code: diagnostic.code.clone(),
11493 code_description: diagnostic
11494 .code_description
11495 .as_ref()
11496 .and_then(|d| d.href.clone()),
11497 severity: DiagnosticSeverity::INFORMATION,
11498 markdown: adapter.as_ref().and_then(|adapter| {
11499 adapter.diagnostic_message_to_markdown(&info.message)
11500 }),
11501 message: info.message.trim().to_string(),
11502 group_id,
11503 is_primary: false,
11504 is_disk_based,
11505 is_unnecessary: false,
11506 underline,
11507 data: diagnostic.data.clone(),
11508 registration_id: registration_id.clone(),
11509 },
11510 });
11511 }
11512 }
11513 }
11514 }
11515 }
11516
11517 for entry in &mut diagnostics {
11518 let diagnostic = &mut entry.diagnostic;
11519 if !diagnostic.is_primary {
11520 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11521 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11522 source,
11523 diagnostic.code.clone(),
11524 entry.range.clone(),
11525 )) {
11526 if let Some(severity) = severity {
11527 diagnostic.severity = severity;
11528 }
11529 diagnostic.is_unnecessary = is_unnecessary;
11530 }
11531 }
11532 }
11533
11534 DocumentDiagnostics {
11535 diagnostics,
11536 document_abs_path,
11537 version: lsp_diagnostics.version,
11538 }
11539 }
11540
11541 fn insert_newly_running_language_server(
11542 &mut self,
11543 adapter: Arc<CachedLspAdapter>,
11544 language_server: Arc<LanguageServer>,
11545 server_id: LanguageServerId,
11546 key: LanguageServerSeed,
11547 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11548 cx: &mut Context<Self>,
11549 ) {
11550 let Some(local) = self.as_local_mut() else {
11551 return;
11552 };
11553 // If the language server for this key doesn't match the server id, don't store the
11554 // server. Which will cause it to be dropped, killing the process
11555 if local
11556 .language_server_ids
11557 .get(&key)
11558 .map(|state| state.id != server_id)
11559 .unwrap_or(false)
11560 {
11561 return;
11562 }
11563
11564 // Update language_servers collection with Running variant of LanguageServerState
11565 // indicating that the server is up and running and ready
11566 let workspace_folders = workspace_folders.lock().clone();
11567 language_server.set_workspace_folders(workspace_folders);
11568
11569 let workspace_diagnostics_refresh_tasks = language_server
11570 .capabilities()
11571 .diagnostic_provider
11572 .and_then(|provider| {
11573 local
11574 .language_server_dynamic_registrations
11575 .entry(server_id)
11576 .or_default()
11577 .diagnostics
11578 .entry(None)
11579 .or_insert(provider.clone());
11580 let workspace_refresher =
11581 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11582
11583 Some((None, workspace_refresher))
11584 })
11585 .into_iter()
11586 .collect();
11587 local.language_servers.insert(
11588 server_id,
11589 LanguageServerState::Running {
11590 workspace_diagnostics_refresh_tasks,
11591 adapter: adapter.clone(),
11592 server: language_server.clone(),
11593 simulate_disk_based_diagnostics_completion: None,
11594 },
11595 );
11596 local
11597 .languages
11598 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11599 if let Some(file_ops_caps) = language_server
11600 .capabilities()
11601 .workspace
11602 .as_ref()
11603 .and_then(|ws| ws.file_operations.as_ref())
11604 {
11605 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11606 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11607 if did_rename_caps.or(will_rename_caps).is_some() {
11608 let watcher = RenamePathsWatchedForServer::default()
11609 .with_did_rename_patterns(did_rename_caps)
11610 .with_will_rename_patterns(will_rename_caps);
11611 local
11612 .language_server_paths_watched_for_rename
11613 .insert(server_id, watcher);
11614 }
11615 }
11616
11617 self.language_server_statuses.insert(
11618 server_id,
11619 LanguageServerStatus {
11620 name: language_server.name(),
11621 server_version: language_server.version(),
11622 server_readable_version: language_server.readable_version(),
11623 pending_work: Default::default(),
11624 has_pending_diagnostic_updates: false,
11625 progress_tokens: Default::default(),
11626 worktree: Some(key.worktree_id),
11627 binary: Some(language_server.binary().clone()),
11628 configuration: Some(language_server.configuration().clone()),
11629 workspace_folders: language_server.workspace_folders(),
11630 process_id: language_server.process_id(),
11631 },
11632 );
11633
11634 cx.emit(LspStoreEvent::LanguageServerAdded(
11635 server_id,
11636 language_server.name(),
11637 Some(key.worktree_id),
11638 ));
11639
11640 let server_capabilities = language_server.capabilities();
11641 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11642 downstream_client
11643 .send(proto::StartLanguageServer {
11644 project_id: *project_id,
11645 server: Some(proto::LanguageServer {
11646 id: server_id.to_proto(),
11647 name: language_server.name().to_string(),
11648 worktree_id: Some(key.worktree_id.to_proto()),
11649 }),
11650 capabilities: serde_json::to_string(&server_capabilities)
11651 .expect("serializing server LSP capabilities"),
11652 })
11653 .log_err();
11654 }
11655 self.lsp_server_capabilities
11656 .insert(server_id, server_capabilities);
11657
11658 // Tell the language server about every open buffer in the worktree that matches the language.
11659 // Also check for buffers in worktrees that reused this server
11660 let mut worktrees_using_server = vec![key.worktree_id];
11661 if let Some(local) = self.as_local() {
11662 // Find all worktrees that have this server in their language server tree
11663 for (worktree_id, servers) in &local.lsp_tree.instances {
11664 if *worktree_id != key.worktree_id {
11665 for server_map in servers.roots.values() {
11666 if server_map
11667 .values()
11668 .any(|(node, _)| node.id() == Some(server_id))
11669 {
11670 worktrees_using_server.push(*worktree_id);
11671 }
11672 }
11673 }
11674 }
11675 }
11676
11677 let mut buffer_paths_registered = Vec::new();
11678 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11679 let mut lsp_adapters = HashMap::default();
11680 for buffer_handle in buffer_store.buffers() {
11681 let buffer = buffer_handle.read(cx);
11682 let file = match File::from_dyn(buffer.file()) {
11683 Some(file) => file,
11684 None => continue,
11685 };
11686 let language = match buffer.language() {
11687 Some(language) => language,
11688 None => continue,
11689 };
11690
11691 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11692 || !lsp_adapters
11693 .entry(language.name())
11694 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11695 .iter()
11696 .any(|a| a.name == key.name)
11697 {
11698 continue;
11699 }
11700 // didOpen
11701 let file = match file.as_local() {
11702 Some(file) => file,
11703 None => continue,
11704 };
11705
11706 let local = self.as_local_mut().unwrap();
11707
11708 let buffer_id = buffer.remote_id();
11709 if local.registered_buffers.contains_key(&buffer_id) {
11710 let abs_path = file.abs_path(cx);
11711 let uri = match lsp::Uri::from_file_path(&abs_path) {
11712 Ok(uri) => uri,
11713 Err(()) => {
11714 log::error!("failed to convert path to URI: {:?}", abs_path);
11715 continue;
11716 }
11717 };
11718
11719 let versions = local
11720 .buffer_snapshots
11721 .entry(buffer_id)
11722 .or_default()
11723 .entry(server_id)
11724 .and_modify(|_| {
11725 assert!(
11726 false,
11727 "There should not be an existing snapshot for a newly inserted buffer"
11728 )
11729 })
11730 .or_insert_with(|| {
11731 vec![LspBufferSnapshot {
11732 version: 0,
11733 snapshot: buffer.text_snapshot(),
11734 }]
11735 });
11736
11737 let snapshot = versions.last().unwrap();
11738 let version = snapshot.version;
11739 let initial_snapshot = &snapshot.snapshot;
11740 language_server.register_buffer(
11741 uri,
11742 adapter.language_id(&language.name()),
11743 version,
11744 initial_snapshot.text(),
11745 );
11746 buffer_paths_registered.push((buffer_id, abs_path));
11747 local
11748 .buffers_opened_in_servers
11749 .entry(buffer_id)
11750 .or_default()
11751 .insert(server_id);
11752 }
11753 buffer_handle.update(cx, |buffer, cx| {
11754 buffer.set_completion_triggers(
11755 server_id,
11756 language_server
11757 .capabilities()
11758 .completion_provider
11759 .as_ref()
11760 .and_then(|provider| {
11761 provider
11762 .trigger_characters
11763 .as_ref()
11764 .map(|characters| characters.iter().cloned().collect())
11765 })
11766 .unwrap_or_default(),
11767 cx,
11768 )
11769 });
11770 }
11771 });
11772
11773 for (buffer_id, abs_path) in buffer_paths_registered {
11774 cx.emit(LspStoreEvent::LanguageServerUpdate {
11775 language_server_id: server_id,
11776 name: Some(adapter.name()),
11777 message: proto::update_language_server::Variant::RegisteredForBuffer(
11778 proto::RegisteredForBuffer {
11779 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11780 buffer_id: buffer_id.to_proto(),
11781 },
11782 ),
11783 });
11784 }
11785
11786 cx.notify();
11787 }
11788
11789 pub fn language_servers_running_disk_based_diagnostics(
11790 &self,
11791 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11792 self.language_server_statuses
11793 .iter()
11794 .filter_map(|(id, status)| {
11795 if status.has_pending_diagnostic_updates {
11796 Some(*id)
11797 } else {
11798 None
11799 }
11800 })
11801 }
11802
11803 pub(crate) fn cancel_language_server_work_for_buffers(
11804 &mut self,
11805 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11806 cx: &mut Context<Self>,
11807 ) {
11808 if let Some((client, project_id)) = self.upstream_client() {
11809 let request = client.request(proto::CancelLanguageServerWork {
11810 project_id,
11811 work: Some(proto::cancel_language_server_work::Work::Buffers(
11812 proto::cancel_language_server_work::Buffers {
11813 buffer_ids: buffers
11814 .into_iter()
11815 .map(|b| b.read(cx).remote_id().to_proto())
11816 .collect(),
11817 },
11818 )),
11819 });
11820 cx.background_spawn(request).detach_and_log_err(cx);
11821 } else if let Some(local) = self.as_local() {
11822 let servers = buffers
11823 .into_iter()
11824 .flat_map(|buffer| {
11825 buffer.update(cx, |buffer, cx| {
11826 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11827 })
11828 })
11829 .collect::<HashSet<_>>();
11830 for server_id in servers {
11831 self.cancel_language_server_work(server_id, None, cx);
11832 }
11833 }
11834 }
11835
11836 pub(crate) fn cancel_language_server_work(
11837 &mut self,
11838 server_id: LanguageServerId,
11839 token_to_cancel: Option<ProgressToken>,
11840 cx: &mut Context<Self>,
11841 ) {
11842 if let Some(local) = self.as_local() {
11843 let status = self.language_server_statuses.get(&server_id);
11844 let server = local.language_servers.get(&server_id);
11845 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11846 {
11847 for (token, progress) in &status.pending_work {
11848 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11849 && token != token_to_cancel
11850 {
11851 continue;
11852 }
11853 if progress.is_cancellable {
11854 server
11855 .notify::<lsp::notification::WorkDoneProgressCancel>(
11856 WorkDoneProgressCancelParams {
11857 token: token.to_lsp(),
11858 },
11859 )
11860 .ok();
11861 }
11862 }
11863 }
11864 } else if let Some((client, project_id)) = self.upstream_client() {
11865 let request = client.request(proto::CancelLanguageServerWork {
11866 project_id,
11867 work: Some(
11868 proto::cancel_language_server_work::Work::LanguageServerWork(
11869 proto::cancel_language_server_work::LanguageServerWork {
11870 language_server_id: server_id.to_proto(),
11871 token: token_to_cancel.map(|token| token.to_proto()),
11872 },
11873 ),
11874 ),
11875 });
11876 cx.background_spawn(request).detach_and_log_err(cx);
11877 }
11878 }
11879
11880 fn register_supplementary_language_server(
11881 &mut self,
11882 id: LanguageServerId,
11883 name: LanguageServerName,
11884 server: Arc<LanguageServer>,
11885 cx: &mut Context<Self>,
11886 ) {
11887 if let Some(local) = self.as_local_mut() {
11888 local
11889 .supplementary_language_servers
11890 .insert(id, (name.clone(), server));
11891 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11892 }
11893 }
11894
11895 fn unregister_supplementary_language_server(
11896 &mut self,
11897 id: LanguageServerId,
11898 cx: &mut Context<Self>,
11899 ) {
11900 if let Some(local) = self.as_local_mut() {
11901 local.supplementary_language_servers.remove(&id);
11902 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11903 }
11904 }
11905
11906 pub(crate) fn supplementary_language_servers(
11907 &self,
11908 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11909 self.as_local().into_iter().flat_map(|local| {
11910 local
11911 .supplementary_language_servers
11912 .iter()
11913 .map(|(id, (name, _))| (*id, name.clone()))
11914 })
11915 }
11916
11917 pub fn language_server_adapter_for_id(
11918 &self,
11919 id: LanguageServerId,
11920 ) -> Option<Arc<CachedLspAdapter>> {
11921 self.as_local()
11922 .and_then(|local| local.language_servers.get(&id))
11923 .and_then(|language_server_state| match language_server_state {
11924 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11925 _ => None,
11926 })
11927 }
11928
11929 pub(super) fn update_local_worktree_language_servers(
11930 &mut self,
11931 worktree_handle: &Entity<Worktree>,
11932 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11933 cx: &mut Context<Self>,
11934 ) {
11935 if changes.is_empty() {
11936 return;
11937 }
11938
11939 let Some(local) = self.as_local() else { return };
11940
11941 local.prettier_store.update(cx, |prettier_store, cx| {
11942 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11943 });
11944
11945 let worktree_id = worktree_handle.read(cx).id();
11946 let mut language_server_ids = local
11947 .language_server_ids
11948 .iter()
11949 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11950 .collect::<Vec<_>>();
11951 language_server_ids.sort();
11952 language_server_ids.dedup();
11953
11954 // let abs_path = worktree_handle.read(cx).abs_path();
11955 for server_id in &language_server_ids {
11956 if let Some(LanguageServerState::Running { server, .. }) =
11957 local.language_servers.get(server_id)
11958 && let Some(watched_paths) = local
11959 .language_server_watched_paths
11960 .get(server_id)
11961 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11962 {
11963 let params = lsp::DidChangeWatchedFilesParams {
11964 changes: changes
11965 .iter()
11966 .filter_map(|(path, _, change)| {
11967 if !watched_paths.is_match(path.as_std_path()) {
11968 return None;
11969 }
11970 let typ = match change {
11971 PathChange::Loaded => return None,
11972 PathChange::Added => lsp::FileChangeType::CREATED,
11973 PathChange::Removed => lsp::FileChangeType::DELETED,
11974 PathChange::Updated => lsp::FileChangeType::CHANGED,
11975 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11976 };
11977 let uri = lsp::Uri::from_file_path(
11978 worktree_handle.read(cx).absolutize(&path),
11979 )
11980 .ok()?;
11981 Some(lsp::FileEvent { uri, typ })
11982 })
11983 .collect(),
11984 };
11985 if !params.changes.is_empty() {
11986 server
11987 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11988 .ok();
11989 }
11990 }
11991 }
11992 for (path, _, _) in changes {
11993 if let Some(file_name) = path.file_name()
11994 && local.watched_manifest_filenames.contains(file_name)
11995 {
11996 self.request_workspace_config_refresh();
11997 break;
11998 }
11999 }
12000 }
12001
12002 pub fn wait_for_remote_buffer(
12003 &mut self,
12004 id: BufferId,
12005 cx: &mut Context<Self>,
12006 ) -> Task<Result<Entity<Buffer>>> {
12007 self.buffer_store.update(cx, |buffer_store, cx| {
12008 buffer_store.wait_for_remote_buffer(id, cx)
12009 })
12010 }
12011
12012 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
12013 let mut result = proto::Symbol {
12014 language_server_name: symbol.language_server_name.0.to_string(),
12015 source_worktree_id: symbol.source_worktree_id.to_proto(),
12016 language_server_id: symbol.source_language_server_id.to_proto(),
12017 name: symbol.name.clone(),
12018 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
12019 start: Some(proto::PointUtf16 {
12020 row: symbol.range.start.0.row,
12021 column: symbol.range.start.0.column,
12022 }),
12023 end: Some(proto::PointUtf16 {
12024 row: symbol.range.end.0.row,
12025 column: symbol.range.end.0.column,
12026 }),
12027 worktree_id: Default::default(),
12028 path: Default::default(),
12029 signature: Default::default(),
12030 container_name: symbol.container_name.clone(),
12031 };
12032 match &symbol.path {
12033 SymbolLocation::InProject(path) => {
12034 result.worktree_id = path.worktree_id.to_proto();
12035 result.path = path.path.to_proto();
12036 }
12037 SymbolLocation::OutsideProject {
12038 abs_path,
12039 signature,
12040 } => {
12041 result.path = abs_path.to_string_lossy().into_owned();
12042 result.signature = signature.to_vec();
12043 }
12044 }
12045 result
12046 }
12047
12048 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
12049 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
12050 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
12051 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
12052
12053 let path = if serialized_symbol.signature.is_empty() {
12054 SymbolLocation::InProject(ProjectPath {
12055 worktree_id,
12056 path: RelPath::from_proto(&serialized_symbol.path)
12057 .context("invalid symbol path")?,
12058 })
12059 } else {
12060 SymbolLocation::OutsideProject {
12061 abs_path: Path::new(&serialized_symbol.path).into(),
12062 signature: serialized_symbol
12063 .signature
12064 .try_into()
12065 .map_err(|_| anyhow!("invalid signature"))?,
12066 }
12067 };
12068
12069 let start = serialized_symbol.start.context("invalid start")?;
12070 let end = serialized_symbol.end.context("invalid end")?;
12071 Ok(CoreSymbol {
12072 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
12073 source_worktree_id,
12074 source_language_server_id: LanguageServerId::from_proto(
12075 serialized_symbol.language_server_id,
12076 ),
12077 path,
12078 name: serialized_symbol.name,
12079 range: Unclipped(PointUtf16::new(start.row, start.column))
12080 ..Unclipped(PointUtf16::new(end.row, end.column)),
12081 kind,
12082 container_name: serialized_symbol.container_name,
12083 })
12084 }
12085
12086 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12087 let mut serialized_completion = proto::Completion {
12088 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12089 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12090 new_text: completion.new_text.clone(),
12091 ..proto::Completion::default()
12092 };
12093 match &completion.source {
12094 CompletionSource::Lsp {
12095 insert_range,
12096 server_id,
12097 lsp_completion,
12098 lsp_defaults,
12099 resolved,
12100 } => {
12101 let (old_insert_start, old_insert_end) = insert_range
12102 .as_ref()
12103 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12104 .unzip();
12105
12106 serialized_completion.old_insert_start = old_insert_start;
12107 serialized_completion.old_insert_end = old_insert_end;
12108 serialized_completion.source = proto::completion::Source::Lsp as i32;
12109 serialized_completion.server_id = server_id.0 as u64;
12110 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12111 serialized_completion.lsp_defaults = lsp_defaults
12112 .as_deref()
12113 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12114 serialized_completion.resolved = *resolved;
12115 }
12116 CompletionSource::BufferWord {
12117 word_range,
12118 resolved,
12119 } => {
12120 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12121 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12122 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12123 serialized_completion.resolved = *resolved;
12124 }
12125 CompletionSource::Custom => {
12126 serialized_completion.source = proto::completion::Source::Custom as i32;
12127 serialized_completion.resolved = true;
12128 }
12129 CompletionSource::Dap { sort_text } => {
12130 serialized_completion.source = proto::completion::Source::Dap as i32;
12131 serialized_completion.sort_text = Some(sort_text.clone());
12132 }
12133 }
12134
12135 serialized_completion
12136 }
12137
12138 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12139 let old_replace_start = completion
12140 .old_replace_start
12141 .and_then(deserialize_anchor)
12142 .context("invalid old start")?;
12143 let old_replace_end = completion
12144 .old_replace_end
12145 .and_then(deserialize_anchor)
12146 .context("invalid old end")?;
12147 let insert_range = {
12148 match completion.old_insert_start.zip(completion.old_insert_end) {
12149 Some((start, end)) => {
12150 let start = deserialize_anchor(start).context("invalid insert old start")?;
12151 let end = deserialize_anchor(end).context("invalid insert old end")?;
12152 Some(start..end)
12153 }
12154 None => None,
12155 }
12156 };
12157 Ok(CoreCompletion {
12158 replace_range: old_replace_start..old_replace_end,
12159 new_text: completion.new_text,
12160 source: match proto::completion::Source::from_i32(completion.source) {
12161 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12162 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12163 insert_range,
12164 server_id: LanguageServerId::from_proto(completion.server_id),
12165 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12166 lsp_defaults: completion
12167 .lsp_defaults
12168 .as_deref()
12169 .map(serde_json::from_slice)
12170 .transpose()?,
12171 resolved: completion.resolved,
12172 },
12173 Some(proto::completion::Source::BufferWord) => {
12174 let word_range = completion
12175 .buffer_word_start
12176 .and_then(deserialize_anchor)
12177 .context("invalid buffer word start")?
12178 ..completion
12179 .buffer_word_end
12180 .and_then(deserialize_anchor)
12181 .context("invalid buffer word end")?;
12182 CompletionSource::BufferWord {
12183 word_range,
12184 resolved: completion.resolved,
12185 }
12186 }
12187 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12188 sort_text: completion
12189 .sort_text
12190 .context("expected sort text to exist")?,
12191 },
12192 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12193 },
12194 })
12195 }
12196
12197 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12198 let (kind, lsp_action) = match &action.lsp_action {
12199 LspAction::Action(code_action) => (
12200 proto::code_action::Kind::Action as i32,
12201 serde_json::to_vec(code_action).unwrap(),
12202 ),
12203 LspAction::Command(command) => (
12204 proto::code_action::Kind::Command as i32,
12205 serde_json::to_vec(command).unwrap(),
12206 ),
12207 LspAction::CodeLens(code_lens) => (
12208 proto::code_action::Kind::CodeLens as i32,
12209 serde_json::to_vec(code_lens).unwrap(),
12210 ),
12211 };
12212
12213 proto::CodeAction {
12214 server_id: action.server_id.0 as u64,
12215 start: Some(serialize_anchor(&action.range.start)),
12216 end: Some(serialize_anchor(&action.range.end)),
12217 lsp_action,
12218 kind,
12219 resolved: action.resolved,
12220 }
12221 }
12222
12223 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12224 let start = action
12225 .start
12226 .and_then(deserialize_anchor)
12227 .context("invalid start")?;
12228 let end = action
12229 .end
12230 .and_then(deserialize_anchor)
12231 .context("invalid end")?;
12232 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12233 Some(proto::code_action::Kind::Action) => {
12234 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12235 }
12236 Some(proto::code_action::Kind::Command) => {
12237 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12238 }
12239 Some(proto::code_action::Kind::CodeLens) => {
12240 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12241 }
12242 None => anyhow::bail!("Unknown action kind {}", action.kind),
12243 };
12244 Ok(CodeAction {
12245 server_id: LanguageServerId(action.server_id as usize),
12246 range: start..end,
12247 resolved: action.resolved,
12248 lsp_action,
12249 })
12250 }
12251
12252 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12253 match &formatting_result {
12254 Ok(_) => self.last_formatting_failure = None,
12255 Err(error) => {
12256 let error_string = format!("{error:#}");
12257 log::error!("Formatting failed: {error_string}");
12258 self.last_formatting_failure
12259 .replace(error_string.lines().join(" "));
12260 }
12261 }
12262 }
12263
12264 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12265 self.lsp_server_capabilities.remove(&for_server);
12266 self.semantic_token_config.remove_server_data(for_server);
12267 for lsp_data in self.lsp_data.values_mut() {
12268 lsp_data.remove_server_data(for_server);
12269 }
12270 if let Some(local) = self.as_local_mut() {
12271 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12272 local
12273 .workspace_pull_diagnostics_result_ids
12274 .remove(&for_server);
12275 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12276 buffer_servers.remove(&for_server);
12277 }
12278 }
12279 }
12280
12281 pub fn result_id_for_buffer_pull(
12282 &self,
12283 server_id: LanguageServerId,
12284 buffer_id: BufferId,
12285 registration_id: &Option<SharedString>,
12286 cx: &App,
12287 ) -> Option<SharedString> {
12288 let abs_path = self
12289 .buffer_store
12290 .read(cx)
12291 .get(buffer_id)
12292 .and_then(|b| File::from_dyn(b.read(cx).file()))
12293 .map(|f| f.abs_path(cx))?;
12294 self.as_local()?
12295 .buffer_pull_diagnostics_result_ids
12296 .get(&server_id)?
12297 .get(registration_id)?
12298 .get(&abs_path)?
12299 .clone()
12300 }
12301
12302 /// Gets all result_ids for a workspace diagnostics pull request.
12303 /// 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.
12304 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12305 pub fn result_ids_for_workspace_refresh(
12306 &self,
12307 server_id: LanguageServerId,
12308 registration_id: &Option<SharedString>,
12309 ) -> HashMap<PathBuf, SharedString> {
12310 let Some(local) = self.as_local() else {
12311 return HashMap::default();
12312 };
12313 local
12314 .workspace_pull_diagnostics_result_ids
12315 .get(&server_id)
12316 .into_iter()
12317 .filter_map(|diagnostics| diagnostics.get(registration_id))
12318 .flatten()
12319 .filter_map(|(abs_path, result_id)| {
12320 let result_id = local
12321 .buffer_pull_diagnostics_result_ids
12322 .get(&server_id)
12323 .and_then(|buffer_ids_result_ids| {
12324 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12325 })
12326 .cloned()
12327 .flatten()
12328 .or_else(|| result_id.clone())?;
12329 Some((abs_path.clone(), result_id))
12330 })
12331 .collect()
12332 }
12333
12334 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12335 if let Some(LanguageServerState::Running {
12336 workspace_diagnostics_refresh_tasks,
12337 ..
12338 }) = self
12339 .as_local_mut()
12340 .and_then(|local| local.language_servers.get_mut(&server_id))
12341 {
12342 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12343 diagnostics.refresh_tx.try_send(()).ok();
12344 }
12345 }
12346 }
12347
12348 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12349 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12350 /// which requires refreshing both workspace and document diagnostics.
12351 pub fn pull_document_diagnostics_for_server(
12352 &mut self,
12353 server_id: LanguageServerId,
12354 source_buffer_id: Option<BufferId>,
12355 cx: &mut Context<Self>,
12356 ) -> Shared<Task<()>> {
12357 let Some(local) = self.as_local_mut() else {
12358 return Task::ready(()).shared();
12359 };
12360 let mut buffers_to_refresh = HashSet::default();
12361 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12362 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12363 buffers_to_refresh.insert(*buffer_id);
12364 }
12365 }
12366
12367 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12368 }
12369
12370 pub fn pull_document_diagnostics_for_buffer_edit(
12371 &mut self,
12372 buffer_id: BufferId,
12373 cx: &mut Context<Self>,
12374 ) {
12375 let Some(local) = self.as_local_mut() else {
12376 return;
12377 };
12378 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12379 else {
12380 return;
12381 };
12382 for server_id in languages_servers {
12383 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12384 }
12385 }
12386
12387 fn apply_workspace_diagnostic_report(
12388 &mut self,
12389 server_id: LanguageServerId,
12390 report: lsp::WorkspaceDiagnosticReportResult,
12391 registration_id: Option<SharedString>,
12392 cx: &mut Context<Self>,
12393 ) {
12394 let mut workspace_diagnostics =
12395 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12396 report,
12397 server_id,
12398 registration_id,
12399 );
12400 workspace_diagnostics.retain(|d| match &d.diagnostics {
12401 LspPullDiagnostics::Response {
12402 server_id,
12403 registration_id,
12404 ..
12405 } => self.diagnostic_registration_exists(*server_id, registration_id),
12406 LspPullDiagnostics::Default => false,
12407 });
12408 let mut unchanged_buffers = HashMap::default();
12409 let workspace_diagnostics_updates = workspace_diagnostics
12410 .into_iter()
12411 .filter_map(
12412 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12413 LspPullDiagnostics::Response {
12414 server_id,
12415 uri,
12416 diagnostics,
12417 registration_id,
12418 } => Some((
12419 server_id,
12420 uri,
12421 diagnostics,
12422 workspace_diagnostics.version,
12423 registration_id,
12424 )),
12425 LspPullDiagnostics::Default => None,
12426 },
12427 )
12428 .fold(
12429 HashMap::default(),
12430 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12431 let (result_id, diagnostics) = match diagnostics {
12432 PulledDiagnostics::Unchanged { result_id } => {
12433 unchanged_buffers
12434 .entry(new_registration_id.clone())
12435 .or_insert_with(HashSet::default)
12436 .insert(uri.clone());
12437 (Some(result_id), Vec::new())
12438 }
12439 PulledDiagnostics::Changed {
12440 result_id,
12441 diagnostics,
12442 } => (result_id, diagnostics),
12443 };
12444 let disk_based_sources = Cow::Owned(
12445 self.language_server_adapter_for_id(server_id)
12446 .as_ref()
12447 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12448 .unwrap_or(&[])
12449 .to_vec(),
12450 );
12451
12452 let Some(abs_path) = uri.to_file_path().ok() else {
12453 return acc;
12454 };
12455 let Some((worktree, relative_path)) =
12456 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12457 else {
12458 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12459 return acc;
12460 };
12461 let worktree_id = worktree.read(cx).id();
12462 let project_path = ProjectPath {
12463 worktree_id,
12464 path: relative_path,
12465 };
12466 if let Some(local_lsp_store) = self.as_local_mut() {
12467 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12468 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12469 }
12470 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12471 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12472 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12473 acc.entry(server_id)
12474 .or_insert_with(HashMap::default)
12475 .entry(new_registration_id.clone())
12476 .or_insert_with(Vec::new)
12477 .push(DocumentDiagnosticsUpdate {
12478 server_id,
12479 diagnostics: lsp::PublishDiagnosticsParams {
12480 uri,
12481 diagnostics,
12482 version,
12483 },
12484 result_id: result_id.map(SharedString::new),
12485 disk_based_sources,
12486 registration_id: new_registration_id,
12487 });
12488 }
12489 acc
12490 },
12491 );
12492
12493 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12494 for (registration_id, diagnostic_updates) in diagnostic_updates {
12495 self.merge_lsp_diagnostics(
12496 DiagnosticSourceKind::Pulled,
12497 diagnostic_updates,
12498 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12499 DiagnosticSourceKind::Pulled => {
12500 old_diagnostic.registration_id != registration_id
12501 || unchanged_buffers
12502 .get(&old_diagnostic.registration_id)
12503 .is_some_and(|unchanged_buffers| {
12504 unchanged_buffers.contains(&document_uri)
12505 })
12506 }
12507 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12508 },
12509 cx,
12510 )
12511 .log_err();
12512 }
12513 }
12514 }
12515
12516 fn register_server_capabilities(
12517 &mut self,
12518 server_id: LanguageServerId,
12519 params: lsp::RegistrationParams,
12520 cx: &mut Context<Self>,
12521 ) -> anyhow::Result<()> {
12522 let server = self
12523 .language_server_for_id(server_id)
12524 .with_context(|| format!("no server {server_id} found"))?;
12525 for reg in params.registrations {
12526 match reg.method.as_str() {
12527 "workspace/didChangeWatchedFiles" => {
12528 if let Some(options) = reg.register_options {
12529 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12530 let caps = serde_json::from_value(options)?;
12531 local_lsp_store
12532 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12533 true
12534 } else {
12535 false
12536 };
12537 if notify {
12538 notify_server_capabilities_updated(&server, cx);
12539 }
12540 }
12541 }
12542 "workspace/didChangeConfiguration" => {
12543 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12544 }
12545 "workspace/didChangeWorkspaceFolders" => {
12546 // In this case register options is an empty object, we can ignore it
12547 let caps = lsp::WorkspaceFoldersServerCapabilities {
12548 supported: Some(true),
12549 change_notifications: Some(OneOf::Right(reg.id)),
12550 };
12551 server.update_capabilities(|capabilities| {
12552 capabilities
12553 .workspace
12554 .get_or_insert_default()
12555 .workspace_folders = Some(caps);
12556 });
12557 notify_server_capabilities_updated(&server, cx);
12558 }
12559 "workspace/symbol" => {
12560 let options = parse_register_capabilities(reg)?;
12561 server.update_capabilities(|capabilities| {
12562 capabilities.workspace_symbol_provider = Some(options);
12563 });
12564 notify_server_capabilities_updated(&server, cx);
12565 }
12566 "workspace/fileOperations" => {
12567 if let Some(options) = reg.register_options {
12568 let caps = serde_json::from_value(options)?;
12569 server.update_capabilities(|capabilities| {
12570 capabilities
12571 .workspace
12572 .get_or_insert_default()
12573 .file_operations = Some(caps);
12574 });
12575 notify_server_capabilities_updated(&server, cx);
12576 }
12577 }
12578 "workspace/executeCommand" => {
12579 if let Some(options) = reg.register_options {
12580 let options = serde_json::from_value(options)?;
12581 server.update_capabilities(|capabilities| {
12582 capabilities.execute_command_provider = Some(options);
12583 });
12584 notify_server_capabilities_updated(&server, cx);
12585 }
12586 }
12587 "textDocument/rangeFormatting" => {
12588 let options = parse_register_capabilities(reg)?;
12589 server.update_capabilities(|capabilities| {
12590 capabilities.document_range_formatting_provider = Some(options);
12591 });
12592 notify_server_capabilities_updated(&server, cx);
12593 }
12594 "textDocument/onTypeFormatting" => {
12595 if let Some(options) = reg
12596 .register_options
12597 .map(serde_json::from_value)
12598 .transpose()?
12599 {
12600 server.update_capabilities(|capabilities| {
12601 capabilities.document_on_type_formatting_provider = Some(options);
12602 });
12603 notify_server_capabilities_updated(&server, cx);
12604 }
12605 }
12606 "textDocument/formatting" => {
12607 let options = parse_register_capabilities(reg)?;
12608 server.update_capabilities(|capabilities| {
12609 capabilities.document_formatting_provider = Some(options);
12610 });
12611 notify_server_capabilities_updated(&server, cx);
12612 }
12613 "textDocument/rename" => {
12614 let options = parse_register_capabilities(reg)?;
12615 server.update_capabilities(|capabilities| {
12616 capabilities.rename_provider = Some(options);
12617 });
12618 notify_server_capabilities_updated(&server, cx);
12619 }
12620 "textDocument/inlayHint" => {
12621 let options = parse_register_capabilities(reg)?;
12622 server.update_capabilities(|capabilities| {
12623 capabilities.inlay_hint_provider = Some(options);
12624 });
12625 notify_server_capabilities_updated(&server, cx);
12626 }
12627 "textDocument/documentSymbol" => {
12628 let options = parse_register_capabilities(reg)?;
12629 server.update_capabilities(|capabilities| {
12630 capabilities.document_symbol_provider = Some(options);
12631 });
12632 notify_server_capabilities_updated(&server, cx);
12633 }
12634 "textDocument/codeAction" => {
12635 let options = parse_register_capabilities(reg)?;
12636 let provider = match options {
12637 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12638 OneOf::Right(caps) => caps,
12639 };
12640 server.update_capabilities(|capabilities| {
12641 capabilities.code_action_provider = Some(provider);
12642 });
12643 notify_server_capabilities_updated(&server, cx);
12644 }
12645 "textDocument/definition" => {
12646 let options = parse_register_capabilities(reg)?;
12647 server.update_capabilities(|capabilities| {
12648 capabilities.definition_provider = Some(options);
12649 });
12650 notify_server_capabilities_updated(&server, cx);
12651 }
12652 "textDocument/completion" => {
12653 if let Some(caps) = reg
12654 .register_options
12655 .map(serde_json::from_value::<CompletionOptions>)
12656 .transpose()?
12657 {
12658 server.update_capabilities(|capabilities| {
12659 capabilities.completion_provider = Some(caps.clone());
12660 });
12661
12662 if let Some(local) = self.as_local() {
12663 let mut buffers_with_language_server = Vec::new();
12664 for handle in self.buffer_store.read(cx).buffers() {
12665 let buffer_id = handle.read(cx).remote_id();
12666 if local
12667 .buffers_opened_in_servers
12668 .get(&buffer_id)
12669 .filter(|s| s.contains(&server_id))
12670 .is_some()
12671 {
12672 buffers_with_language_server.push(handle);
12673 }
12674 }
12675 let triggers = caps
12676 .trigger_characters
12677 .unwrap_or_default()
12678 .into_iter()
12679 .collect::<BTreeSet<_>>();
12680 for handle in buffers_with_language_server {
12681 let triggers = triggers.clone();
12682 let _ = handle.update(cx, move |buffer, cx| {
12683 buffer.set_completion_triggers(server_id, triggers, cx);
12684 });
12685 }
12686 }
12687 notify_server_capabilities_updated(&server, cx);
12688 }
12689 }
12690 "textDocument/hover" => {
12691 let options = parse_register_capabilities(reg)?;
12692 let provider = match options {
12693 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12694 OneOf::Right(caps) => caps,
12695 };
12696 server.update_capabilities(|capabilities| {
12697 capabilities.hover_provider = Some(provider);
12698 });
12699 notify_server_capabilities_updated(&server, cx);
12700 }
12701 "textDocument/signatureHelp" => {
12702 if let Some(caps) = reg
12703 .register_options
12704 .map(serde_json::from_value)
12705 .transpose()?
12706 {
12707 server.update_capabilities(|capabilities| {
12708 capabilities.signature_help_provider = Some(caps);
12709 });
12710 notify_server_capabilities_updated(&server, cx);
12711 }
12712 }
12713 "textDocument/didChange" => {
12714 if let Some(sync_kind) = reg
12715 .register_options
12716 .and_then(|opts| opts.get("syncKind").cloned())
12717 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12718 .transpose()?
12719 {
12720 server.update_capabilities(|capabilities| {
12721 let mut sync_options =
12722 Self::take_text_document_sync_options(capabilities);
12723 sync_options.change = Some(sync_kind);
12724 capabilities.text_document_sync =
12725 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12726 });
12727 notify_server_capabilities_updated(&server, cx);
12728 }
12729 }
12730 "textDocument/didSave" => {
12731 if let Some(include_text) = reg
12732 .register_options
12733 .map(|opts| {
12734 let transpose = opts
12735 .get("includeText")
12736 .cloned()
12737 .map(serde_json::from_value::<Option<bool>>)
12738 .transpose();
12739 match transpose {
12740 Ok(value) => Ok(value.flatten()),
12741 Err(e) => Err(e),
12742 }
12743 })
12744 .transpose()?
12745 {
12746 server.update_capabilities(|capabilities| {
12747 let mut sync_options =
12748 Self::take_text_document_sync_options(capabilities);
12749 sync_options.save =
12750 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12751 include_text,
12752 }));
12753 capabilities.text_document_sync =
12754 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12755 });
12756 notify_server_capabilities_updated(&server, cx);
12757 }
12758 }
12759 "textDocument/codeLens" => {
12760 if let Some(caps) = reg
12761 .register_options
12762 .map(serde_json::from_value)
12763 .transpose()?
12764 {
12765 server.update_capabilities(|capabilities| {
12766 capabilities.code_lens_provider = Some(caps);
12767 });
12768 notify_server_capabilities_updated(&server, cx);
12769 }
12770 }
12771 "textDocument/diagnostic" => {
12772 if let Some(caps) = reg
12773 .register_options
12774 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12775 .transpose()?
12776 {
12777 let local = self
12778 .as_local_mut()
12779 .context("Expected LSP Store to be local")?;
12780 let state = local
12781 .language_servers
12782 .get_mut(&server_id)
12783 .context("Could not obtain Language Servers state")?;
12784 local
12785 .language_server_dynamic_registrations
12786 .entry(server_id)
12787 .or_default()
12788 .diagnostics
12789 .insert(Some(reg.id.clone()), caps.clone());
12790
12791 let supports_workspace_diagnostics =
12792 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12793 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12794 diagnostic_options.workspace_diagnostics
12795 }
12796 DiagnosticServerCapabilities::RegistrationOptions(
12797 diagnostic_registration_options,
12798 ) => {
12799 diagnostic_registration_options
12800 .diagnostic_options
12801 .workspace_diagnostics
12802 }
12803 };
12804
12805 if supports_workspace_diagnostics(&caps) {
12806 if let LanguageServerState::Running {
12807 workspace_diagnostics_refresh_tasks,
12808 ..
12809 } = state
12810 && let Some(task) = lsp_workspace_diagnostics_refresh(
12811 Some(reg.id.clone()),
12812 caps.clone(),
12813 server.clone(),
12814 cx,
12815 )
12816 {
12817 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12818 }
12819 }
12820
12821 server.update_capabilities(|capabilities| {
12822 capabilities.diagnostic_provider = Some(caps);
12823 });
12824
12825 notify_server_capabilities_updated(&server, cx);
12826
12827 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12828 }
12829 }
12830 "textDocument/documentColor" => {
12831 let options = parse_register_capabilities(reg)?;
12832 let provider = match options {
12833 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12834 OneOf::Right(caps) => caps,
12835 };
12836 server.update_capabilities(|capabilities| {
12837 capabilities.color_provider = Some(provider);
12838 });
12839 notify_server_capabilities_updated(&server, cx);
12840 }
12841 "textDocument/foldingRange" => {
12842 let options = parse_register_capabilities(reg)?;
12843 let provider = match options {
12844 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12845 OneOf::Right(caps) => caps,
12846 };
12847 server.update_capabilities(|capabilities| {
12848 capabilities.folding_range_provider = Some(provider);
12849 });
12850 notify_server_capabilities_updated(&server, cx);
12851 }
12852 _ => log::warn!("unhandled capability registration: {reg:?}"),
12853 }
12854 }
12855
12856 Ok(())
12857 }
12858
12859 fn unregister_server_capabilities(
12860 &mut self,
12861 server_id: LanguageServerId,
12862 params: lsp::UnregistrationParams,
12863 cx: &mut Context<Self>,
12864 ) -> anyhow::Result<()> {
12865 let server = self
12866 .language_server_for_id(server_id)
12867 .with_context(|| format!("no server {server_id} found"))?;
12868 for unreg in params.unregisterations.iter() {
12869 match unreg.method.as_str() {
12870 "workspace/didChangeWatchedFiles" => {
12871 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12872 local_lsp_store
12873 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12874 true
12875 } else {
12876 false
12877 };
12878 if notify {
12879 notify_server_capabilities_updated(&server, cx);
12880 }
12881 }
12882 "workspace/didChangeConfiguration" => {
12883 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12884 }
12885 "workspace/didChangeWorkspaceFolders" => {
12886 server.update_capabilities(|capabilities| {
12887 capabilities
12888 .workspace
12889 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12890 workspace_folders: None,
12891 file_operations: None,
12892 })
12893 .workspace_folders = None;
12894 });
12895 notify_server_capabilities_updated(&server, cx);
12896 }
12897 "workspace/symbol" => {
12898 server.update_capabilities(|capabilities| {
12899 capabilities.workspace_symbol_provider = None
12900 });
12901 notify_server_capabilities_updated(&server, cx);
12902 }
12903 "workspace/fileOperations" => {
12904 server.update_capabilities(|capabilities| {
12905 capabilities
12906 .workspace
12907 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12908 workspace_folders: None,
12909 file_operations: None,
12910 })
12911 .file_operations = None;
12912 });
12913 notify_server_capabilities_updated(&server, cx);
12914 }
12915 "workspace/executeCommand" => {
12916 server.update_capabilities(|capabilities| {
12917 capabilities.execute_command_provider = None;
12918 });
12919 notify_server_capabilities_updated(&server, cx);
12920 }
12921 "textDocument/rangeFormatting" => {
12922 server.update_capabilities(|capabilities| {
12923 capabilities.document_range_formatting_provider = None
12924 });
12925 notify_server_capabilities_updated(&server, cx);
12926 }
12927 "textDocument/onTypeFormatting" => {
12928 server.update_capabilities(|capabilities| {
12929 capabilities.document_on_type_formatting_provider = None;
12930 });
12931 notify_server_capabilities_updated(&server, cx);
12932 }
12933 "textDocument/formatting" => {
12934 server.update_capabilities(|capabilities| {
12935 capabilities.document_formatting_provider = None;
12936 });
12937 notify_server_capabilities_updated(&server, cx);
12938 }
12939 "textDocument/rename" => {
12940 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12941 notify_server_capabilities_updated(&server, cx);
12942 }
12943 "textDocument/codeAction" => {
12944 server.update_capabilities(|capabilities| {
12945 capabilities.code_action_provider = None;
12946 });
12947 notify_server_capabilities_updated(&server, cx);
12948 }
12949 "textDocument/definition" => {
12950 server.update_capabilities(|capabilities| {
12951 capabilities.definition_provider = None;
12952 });
12953 notify_server_capabilities_updated(&server, cx);
12954 }
12955 "textDocument/completion" => {
12956 server.update_capabilities(|capabilities| {
12957 capabilities.completion_provider = None;
12958 });
12959 notify_server_capabilities_updated(&server, cx);
12960 }
12961 "textDocument/hover" => {
12962 server.update_capabilities(|capabilities| {
12963 capabilities.hover_provider = None;
12964 });
12965 notify_server_capabilities_updated(&server, cx);
12966 }
12967 "textDocument/signatureHelp" => {
12968 server.update_capabilities(|capabilities| {
12969 capabilities.signature_help_provider = None;
12970 });
12971 notify_server_capabilities_updated(&server, cx);
12972 }
12973 "textDocument/didChange" => {
12974 server.update_capabilities(|capabilities| {
12975 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12976 sync_options.change = None;
12977 capabilities.text_document_sync =
12978 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12979 });
12980 notify_server_capabilities_updated(&server, cx);
12981 }
12982 "textDocument/didSave" => {
12983 server.update_capabilities(|capabilities| {
12984 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12985 sync_options.save = None;
12986 capabilities.text_document_sync =
12987 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12988 });
12989 notify_server_capabilities_updated(&server, cx);
12990 }
12991 "textDocument/codeLens" => {
12992 server.update_capabilities(|capabilities| {
12993 capabilities.code_lens_provider = None;
12994 });
12995 notify_server_capabilities_updated(&server, cx);
12996 }
12997 "textDocument/diagnostic" => {
12998 let local = self
12999 .as_local_mut()
13000 .context("Expected LSP Store to be local")?;
13001
13002 let state = local
13003 .language_servers
13004 .get_mut(&server_id)
13005 .context("Could not obtain Language Servers state")?;
13006 let registrations = local
13007 .language_server_dynamic_registrations
13008 .get_mut(&server_id)
13009 .with_context(|| {
13010 format!("Expected dynamic registration to exist for server {server_id}")
13011 })?;
13012 registrations.diagnostics
13013 .remove(&Some(unreg.id.clone()))
13014 .with_context(|| format!(
13015 "Attempted to unregister non-existent diagnostic registration with ID {}",
13016 unreg.id)
13017 )?;
13018 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
13019
13020 if let LanguageServerState::Running {
13021 workspace_diagnostics_refresh_tasks,
13022 ..
13023 } = state
13024 {
13025 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
13026 }
13027
13028 self.clear_unregistered_diagnostics(
13029 server_id,
13030 SharedString::from(unreg.id.clone()),
13031 cx,
13032 )?;
13033
13034 if removed_last_diagnostic_provider {
13035 server.update_capabilities(|capabilities| {
13036 debug_assert!(capabilities.diagnostic_provider.is_some());
13037 capabilities.diagnostic_provider = None;
13038 });
13039 }
13040
13041 notify_server_capabilities_updated(&server, cx);
13042 }
13043 "textDocument/documentColor" => {
13044 server.update_capabilities(|capabilities| {
13045 capabilities.color_provider = None;
13046 });
13047 notify_server_capabilities_updated(&server, cx);
13048 }
13049 "textDocument/foldingRange" => {
13050 server.update_capabilities(|capabilities| {
13051 capabilities.folding_range_provider = None;
13052 });
13053 notify_server_capabilities_updated(&server, cx);
13054 }
13055 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
13056 }
13057 }
13058
13059 Ok(())
13060 }
13061
13062 fn clear_unregistered_diagnostics(
13063 &mut self,
13064 server_id: LanguageServerId,
13065 cleared_registration_id: SharedString,
13066 cx: &mut Context<Self>,
13067 ) -> anyhow::Result<()> {
13068 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
13069
13070 self.buffer_store.update(cx, |buffer_store, cx| {
13071 for buffer_handle in buffer_store.buffers() {
13072 let buffer = buffer_handle.read(cx);
13073 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
13074 let Some(abs_path) = abs_path else {
13075 continue;
13076 };
13077 affected_abs_paths.insert(abs_path);
13078 }
13079 });
13080
13081 let local = self.as_local().context("Expected LSP Store to be local")?;
13082 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13083 let Some(worktree) = self
13084 .worktree_store
13085 .read(cx)
13086 .worktree_for_id(*worktree_id, cx)
13087 else {
13088 continue;
13089 };
13090
13091 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13092 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13093 let has_matching_registration =
13094 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13095 entry.diagnostic.registration_id.as_ref()
13096 == Some(&cleared_registration_id)
13097 });
13098 if has_matching_registration {
13099 let abs_path = worktree.read(cx).absolutize(rel_path);
13100 affected_abs_paths.insert(abs_path);
13101 }
13102 }
13103 }
13104 }
13105
13106 if affected_abs_paths.is_empty() {
13107 return Ok(());
13108 }
13109
13110 // Send a fake diagnostic update which clears the state for the registration ID
13111 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13112 affected_abs_paths
13113 .into_iter()
13114 .map(|abs_path| DocumentDiagnosticsUpdate {
13115 diagnostics: DocumentDiagnostics {
13116 diagnostics: Vec::new(),
13117 document_abs_path: abs_path,
13118 version: None,
13119 },
13120 result_id: None,
13121 registration_id: Some(cleared_registration_id.clone()),
13122 server_id,
13123 disk_based_sources: Cow::Borrowed(&[]),
13124 })
13125 .collect();
13126
13127 let merge_registration_id = cleared_registration_id.clone();
13128 self.merge_diagnostic_entries(
13129 clears,
13130 move |_, diagnostic, _| {
13131 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13132 diagnostic.registration_id != Some(merge_registration_id.clone())
13133 } else {
13134 true
13135 }
13136 },
13137 cx,
13138 )?;
13139
13140 Ok(())
13141 }
13142
13143 async fn deduplicate_range_based_lsp_requests<T>(
13144 lsp_store: &Entity<Self>,
13145 server_id: Option<LanguageServerId>,
13146 lsp_request_id: LspRequestId,
13147 proto_request: &T::ProtoRequest,
13148 range: Range<Anchor>,
13149 cx: &mut AsyncApp,
13150 ) -> Result<()>
13151 where
13152 T: LspCommand,
13153 T::ProtoRequest: proto::LspRequestMessage,
13154 {
13155 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13156 let version = deserialize_version(proto_request.buffer_version());
13157 let buffer = lsp_store.update(cx, |this, cx| {
13158 this.buffer_store.read(cx).get_existing(buffer_id)
13159 })?;
13160 buffer
13161 .update(cx, |buffer, _| buffer.wait_for_version(version))
13162 .await?;
13163 lsp_store.update(cx, |lsp_store, cx| {
13164 let buffer_snapshot = buffer.read(cx).snapshot();
13165 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13166 let chunks_queried_for = lsp_data
13167 .inlay_hints
13168 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13169 .collect::<Vec<_>>();
13170 match chunks_queried_for.as_slice() {
13171 &[chunk] => {
13172 let key = LspKey {
13173 request_type: TypeId::of::<T>(),
13174 server_queried: server_id,
13175 };
13176 let previous_request = lsp_data
13177 .chunk_lsp_requests
13178 .entry(key)
13179 .or_default()
13180 .insert(chunk, lsp_request_id);
13181 if let Some((previous_request, running_requests)) =
13182 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13183 {
13184 running_requests.remove(&previous_request);
13185 }
13186 }
13187 _ambiguous_chunks => {
13188 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13189 // there, a buffer version-based check will be performed and outdated requests discarded.
13190 }
13191 }
13192 anyhow::Ok(())
13193 })?;
13194
13195 Ok(())
13196 }
13197
13198 async fn query_lsp_locally<T>(
13199 lsp_store: Entity<Self>,
13200 for_server_id: Option<LanguageServerId>,
13201 sender_id: proto::PeerId,
13202 lsp_request_id: LspRequestId,
13203 proto_request: T::ProtoRequest,
13204 position: Option<Anchor>,
13205 cx: &mut AsyncApp,
13206 ) -> Result<()>
13207 where
13208 T: LspCommand + Clone,
13209 T::ProtoRequest: proto::LspRequestMessage,
13210 <T::ProtoRequest as proto::RequestMessage>::Response:
13211 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13212 {
13213 let (buffer_version, buffer) =
13214 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13215 let request =
13216 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13217 let key = LspKey {
13218 request_type: TypeId::of::<T>(),
13219 server_queried: for_server_id,
13220 };
13221 lsp_store.update(cx, |lsp_store, cx| {
13222 let request_task = match for_server_id {
13223 Some(server_id) => {
13224 let server_task = lsp_store.request_lsp(
13225 buffer.clone(),
13226 LanguageServerToQuery::Other(server_id),
13227 request.clone(),
13228 cx,
13229 );
13230 cx.background_spawn(async move {
13231 let mut responses = Vec::new();
13232 match server_task.await {
13233 Ok(response) => responses.push((server_id, response)),
13234 // rust-analyzer likes to error with this when its still loading up
13235 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13236 Err(e) => log::error!(
13237 "Error handling response for request {request:?}: {e:#}"
13238 ),
13239 }
13240 responses
13241 })
13242 }
13243 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13244 };
13245 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13246 if T::ProtoRequest::stop_previous_requests() {
13247 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13248 lsp_requests.clear();
13249 }
13250 }
13251 lsp_data.lsp_requests.entry(key).or_default().insert(
13252 lsp_request_id,
13253 cx.spawn(async move |lsp_store, cx| {
13254 let response = request_task.await;
13255 lsp_store
13256 .update(cx, |lsp_store, cx| {
13257 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13258 {
13259 let response = response
13260 .into_iter()
13261 .map(|(server_id, response)| {
13262 (
13263 server_id.to_proto(),
13264 T::response_to_proto(
13265 response,
13266 lsp_store,
13267 sender_id,
13268 &buffer_version,
13269 cx,
13270 )
13271 .into(),
13272 )
13273 })
13274 .collect::<HashMap<_, _>>();
13275 match client.send_lsp_response::<T::ProtoRequest>(
13276 project_id,
13277 lsp_request_id,
13278 response,
13279 ) {
13280 Ok(()) => {}
13281 Err(e) => {
13282 log::error!("Failed to send LSP response: {e:#}",)
13283 }
13284 }
13285 }
13286 })
13287 .ok();
13288 }),
13289 );
13290 });
13291 Ok(())
13292 }
13293
13294 async fn wait_for_buffer_version<T>(
13295 lsp_store: &Entity<Self>,
13296 proto_request: &T::ProtoRequest,
13297 cx: &mut AsyncApp,
13298 ) -> Result<(Global, Entity<Buffer>)>
13299 where
13300 T: LspCommand,
13301 T::ProtoRequest: proto::LspRequestMessage,
13302 {
13303 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13304 let version = deserialize_version(proto_request.buffer_version());
13305 let buffer = lsp_store.update(cx, |this, cx| {
13306 this.buffer_store.read(cx).get_existing(buffer_id)
13307 })?;
13308 buffer
13309 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13310 .await?;
13311 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13312 Ok((buffer_version, buffer))
13313 }
13314
13315 fn take_text_document_sync_options(
13316 capabilities: &mut lsp::ServerCapabilities,
13317 ) -> lsp::TextDocumentSyncOptions {
13318 match capabilities.text_document_sync.take() {
13319 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13320 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13321 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13322 sync_options.change = Some(sync_kind);
13323 sync_options
13324 }
13325 None => lsp::TextDocumentSyncOptions::default(),
13326 }
13327 }
13328
13329 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13330 self.downstream_client.clone()
13331 }
13332
13333 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13334 self.worktree_store.clone()
13335 }
13336
13337 /// Gets what's stored in the LSP data for the given buffer.
13338 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13339 self.lsp_data.get_mut(&buffer_id)
13340 }
13341
13342 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13343 /// new [`BufferLspData`] will be created to replace the previous state.
13344 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13345 let (buffer_id, buffer_version) =
13346 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13347 let lsp_data = self
13348 .lsp_data
13349 .entry(buffer_id)
13350 .or_insert_with(|| BufferLspData::new(buffer, cx));
13351 if buffer_version.changed_since(&lsp_data.buffer_version) {
13352 // To send delta requests for semantic tokens, the previous tokens
13353 // need to be kept between buffer changes.
13354 let semantic_tokens = lsp_data.semantic_tokens.take();
13355 *lsp_data = BufferLspData::new(buffer, cx);
13356 lsp_data.semantic_tokens = semantic_tokens;
13357 }
13358 lsp_data
13359 }
13360}
13361
13362// Registration with registerOptions as null, should fallback to true.
13363// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13364fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13365 reg: lsp::Registration,
13366) -> Result<OneOf<bool, T>> {
13367 Ok(match reg.register_options {
13368 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13369 None => OneOf::Left(true),
13370 })
13371}
13372
13373fn server_capabilities_support_range_formatting(capabilities: &lsp::ServerCapabilities) -> bool {
13374 matches!(
13375 capabilities.document_range_formatting_provider.as_ref(),
13376 Some(provider) if *provider != OneOf::Left(false)
13377 )
13378}
13379
13380fn subscribe_to_binary_statuses(
13381 languages: &Arc<LanguageRegistry>,
13382 cx: &mut Context<'_, LspStore>,
13383) -> Task<()> {
13384 let mut server_statuses = languages.language_server_binary_statuses();
13385 cx.spawn(async move |lsp_store, cx| {
13386 while let Some((server_name, binary_status)) = server_statuses.next().await {
13387 if lsp_store
13388 .update(cx, |_, cx| {
13389 let mut message = None;
13390 let binary_status = match binary_status {
13391 BinaryStatus::None => proto::ServerBinaryStatus::None,
13392 BinaryStatus::CheckingForUpdate => {
13393 proto::ServerBinaryStatus::CheckingForUpdate
13394 }
13395 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13396 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13397 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13398 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13399 BinaryStatus::Failed { error } => {
13400 message = Some(error);
13401 proto::ServerBinaryStatus::Failed
13402 }
13403 };
13404 cx.emit(LspStoreEvent::LanguageServerUpdate {
13405 // Binary updates are about the binary that might not have any language server id at that point.
13406 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13407 language_server_id: LanguageServerId(0),
13408 name: Some(server_name),
13409 message: proto::update_language_server::Variant::StatusUpdate(
13410 proto::StatusUpdate {
13411 message,
13412 status: Some(proto::status_update::Status::Binary(
13413 binary_status as i32,
13414 )),
13415 },
13416 ),
13417 });
13418 })
13419 .is_err()
13420 {
13421 break;
13422 }
13423 }
13424 })
13425}
13426
13427fn lsp_workspace_diagnostics_refresh(
13428 registration_id: Option<String>,
13429 options: DiagnosticServerCapabilities,
13430 server: Arc<LanguageServer>,
13431 cx: &mut Context<'_, LspStore>,
13432) -> Option<WorkspaceRefreshTask> {
13433 let identifier = workspace_diagnostic_identifier(&options)?;
13434 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13435
13436 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13437 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13438 refresh_tx.try_send(()).ok();
13439
13440 let request_timeout = ProjectSettings::get_global(cx)
13441 .global_lsp_settings
13442 .get_request_timeout();
13443
13444 // 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.
13445 // This allows users to increase the duration if need be
13446 let timeout = if request_timeout != Duration::ZERO {
13447 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13448 } else {
13449 request_timeout
13450 };
13451
13452 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13453 let mut attempts = 0;
13454 let max_attempts = 50;
13455 let mut requests = 0;
13456
13457 loop {
13458 let Some(()) = refresh_rx.recv().await else {
13459 return;
13460 };
13461
13462 'request: loop {
13463 requests += 1;
13464 if attempts > max_attempts {
13465 log::error!(
13466 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13467 );
13468 return;
13469 }
13470 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13471 cx.background_executor()
13472 .timer(Duration::from_millis(backoff_millis))
13473 .await;
13474 attempts += 1;
13475
13476 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13477 lsp_store
13478 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13479 .into_iter()
13480 .filter_map(|(abs_path, result_id)| {
13481 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13482 Some(lsp::PreviousResultId {
13483 uri,
13484 value: result_id.to_string(),
13485 })
13486 })
13487 .collect()
13488 }) else {
13489 return;
13490 };
13491
13492 let token = if let Some(registration_id) = ®istration_id {
13493 format!(
13494 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13495 server.server_id(),
13496 )
13497 } else {
13498 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13499 };
13500
13501 progress_rx.try_recv().ok();
13502 let timer = server.request_timer(timeout).fuse();
13503 let progress = pin!(progress_rx.recv().fuse());
13504 let response_result = server
13505 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13506 lsp::WorkspaceDiagnosticParams {
13507 previous_result_ids,
13508 identifier: identifier.clone(),
13509 work_done_progress_params: Default::default(),
13510 partial_result_params: lsp::PartialResultParams {
13511 partial_result_token: Some(lsp::ProgressToken::String(token)),
13512 },
13513 },
13514 select(timer, progress).then(|either| match either {
13515 Either::Left((message, ..)) => ready(message).left_future(),
13516 Either::Right(..) => pending::<String>().right_future(),
13517 }),
13518 )
13519 .await;
13520
13521 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13522 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13523 match response_result {
13524 ConnectionResult::Timeout => {
13525 log::error!("Timeout during workspace diagnostics pull");
13526 continue 'request;
13527 }
13528 ConnectionResult::ConnectionReset => {
13529 log::error!("Server closed a workspace diagnostics pull request");
13530 continue 'request;
13531 }
13532 ConnectionResult::Result(Err(e)) => {
13533 log::error!("Error during workspace diagnostics pull: {e:#}");
13534 break 'request;
13535 }
13536 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13537 attempts = 0;
13538 if lsp_store
13539 .update(cx, |lsp_store, cx| {
13540 lsp_store.apply_workspace_diagnostic_report(
13541 server.server_id(),
13542 pulled_diagnostics,
13543 registration_id_shared.clone(),
13544 cx,
13545 )
13546 })
13547 .is_err()
13548 {
13549 return;
13550 }
13551 break 'request;
13552 }
13553 }
13554 }
13555 }
13556 });
13557
13558 Some(WorkspaceRefreshTask {
13559 refresh_tx,
13560 progress_tx,
13561 task: workspace_query_language_server,
13562 })
13563}
13564
13565fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13566 match &options {
13567 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13568 .identifier
13569 .as_deref()
13570 .map(SharedString::new),
13571 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13572 let diagnostic_options = ®istration_options.diagnostic_options;
13573 diagnostic_options
13574 .identifier
13575 .as_deref()
13576 .map(SharedString::new)
13577 }
13578 }
13579}
13580
13581fn workspace_diagnostic_identifier(
13582 options: &DiagnosticServerCapabilities,
13583) -> Option<Option<String>> {
13584 match &options {
13585 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13586 if !diagnostic_options.workspace_diagnostics {
13587 return None;
13588 }
13589 Some(diagnostic_options.identifier.clone())
13590 }
13591 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13592 let diagnostic_options = ®istration_options.diagnostic_options;
13593 if !diagnostic_options.workspace_diagnostics {
13594 return None;
13595 }
13596 Some(diagnostic_options.identifier.clone())
13597 }
13598 }
13599}
13600
13601fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13602 let CompletionSource::BufferWord {
13603 word_range,
13604 resolved,
13605 } = &mut completion.source
13606 else {
13607 return;
13608 };
13609 if *resolved {
13610 return;
13611 }
13612
13613 if completion.new_text
13614 != snapshot
13615 .text_for_range(word_range.clone())
13616 .collect::<String>()
13617 {
13618 return;
13619 }
13620
13621 let mut offset = 0;
13622 for chunk in snapshot.chunks(
13623 word_range.clone(),
13624 LanguageAwareStyling {
13625 tree_sitter: true,
13626 diagnostics: true,
13627 },
13628 ) {
13629 let end_offset = offset + chunk.text.len();
13630 if let Some(highlight_id) = chunk.syntax_highlight_id {
13631 completion
13632 .label
13633 .runs
13634 .push((offset..end_offset, highlight_id));
13635 }
13636 offset = end_offset;
13637 }
13638 *resolved = true;
13639}
13640
13641impl EventEmitter<LspStoreEvent> for LspStore {}
13642
13643fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13644 hover
13645 .contents
13646 .retain(|hover_block| !hover_block.text.trim().is_empty());
13647 if hover.contents.is_empty() {
13648 None
13649 } else {
13650 Some(hover)
13651 }
13652}
13653
13654async fn populate_labels_for_completions(
13655 new_completions: Vec<CoreCompletion>,
13656 language: Option<Arc<Language>>,
13657 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13658) -> Vec<Completion> {
13659 let lsp_completions = new_completions
13660 .iter()
13661 .filter_map(|new_completion| {
13662 new_completion
13663 .source
13664 .lsp_completion(true)
13665 .map(|lsp_completion| lsp_completion.into_owned())
13666 })
13667 .collect::<Vec<_>>();
13668
13669 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13670 lsp_adapter
13671 .labels_for_completions(&lsp_completions, language)
13672 .await
13673 .log_err()
13674 .unwrap_or_default()
13675 } else {
13676 Vec::new()
13677 }
13678 .into_iter()
13679 .fuse();
13680
13681 let mut completions = Vec::new();
13682 for completion in new_completions {
13683 match completion.source.lsp_completion(true) {
13684 Some(lsp_completion) => {
13685 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13686
13687 let mut label = labels.next().flatten().unwrap_or_else(|| {
13688 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13689 });
13690 ensure_uniform_list_compatible_label(&mut label);
13691 completions.push(Completion {
13692 label,
13693 documentation,
13694 replace_range: completion.replace_range,
13695 new_text: completion.new_text,
13696 insert_text_mode: lsp_completion.insert_text_mode,
13697 source: completion.source,
13698 icon_path: None,
13699 confirm: None,
13700 match_start: None,
13701 snippet_deduplication_key: None,
13702 });
13703 }
13704 None => {
13705 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13706 ensure_uniform_list_compatible_label(&mut label);
13707 completions.push(Completion {
13708 label,
13709 documentation: None,
13710 replace_range: completion.replace_range,
13711 new_text: completion.new_text,
13712 source: completion.source,
13713 insert_text_mode: None,
13714 icon_path: None,
13715 confirm: None,
13716 match_start: None,
13717 snippet_deduplication_key: None,
13718 });
13719 }
13720 }
13721 }
13722 completions
13723}
13724
13725#[derive(Debug)]
13726pub enum LanguageServerToQuery {
13727 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13728 FirstCapable,
13729 /// Query a specific language server.
13730 Other(LanguageServerId),
13731}
13732
13733#[derive(Default)]
13734struct RenamePathsWatchedForServer {
13735 did_rename: Vec<RenameActionPredicate>,
13736 will_rename: Vec<RenameActionPredicate>,
13737}
13738
13739impl RenamePathsWatchedForServer {
13740 fn with_did_rename_patterns(
13741 mut self,
13742 did_rename: Option<&FileOperationRegistrationOptions>,
13743 ) -> Self {
13744 if let Some(did_rename) = did_rename {
13745 self.did_rename = did_rename
13746 .filters
13747 .iter()
13748 .filter_map(|filter| filter.try_into().log_err())
13749 .collect();
13750 }
13751 self
13752 }
13753 fn with_will_rename_patterns(
13754 mut self,
13755 will_rename: Option<&FileOperationRegistrationOptions>,
13756 ) -> Self {
13757 if let Some(will_rename) = will_rename {
13758 self.will_rename = will_rename
13759 .filters
13760 .iter()
13761 .filter_map(|filter| filter.try_into().log_err())
13762 .collect();
13763 }
13764 self
13765 }
13766
13767 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13768 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13769 }
13770 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13771 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13772 }
13773}
13774
13775impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13776 type Error = globset::Error;
13777 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13778 Ok(Self {
13779 kind: ops.pattern.matches.clone(),
13780 glob: GlobBuilder::new(&ops.pattern.glob)
13781 .case_insensitive(
13782 ops.pattern
13783 .options
13784 .as_ref()
13785 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13786 )
13787 .build()?
13788 .compile_matcher(),
13789 })
13790 }
13791}
13792struct RenameActionPredicate {
13793 glob: GlobMatcher,
13794 kind: Option<FileOperationPatternKind>,
13795}
13796
13797impl RenameActionPredicate {
13798 // Returns true if language server should be notified
13799 fn eval(&self, path: &str, is_dir: bool) -> bool {
13800 self.kind.as_ref().is_none_or(|kind| {
13801 let expected_kind = if is_dir {
13802 FileOperationPatternKind::Folder
13803 } else {
13804 FileOperationPatternKind::File
13805 };
13806 kind == &expected_kind
13807 }) && self.glob.is_match(path)
13808 }
13809}
13810
13811#[derive(Default)]
13812struct LanguageServerWatchedPaths {
13813 worktree_paths: HashMap<WorktreeId, GlobSet>,
13814 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13815}
13816
13817#[derive(Default)]
13818struct LanguageServerWatchedPathsBuilder {
13819 worktree_paths: HashMap<WorktreeId, GlobSet>,
13820 abs_paths: HashMap<Arc<Path>, GlobSet>,
13821}
13822
13823impl LanguageServerWatchedPathsBuilder {
13824 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13825 self.worktree_paths.insert(worktree_id, glob_set);
13826 }
13827 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13828 self.abs_paths.insert(path, glob_set);
13829 }
13830 fn build(
13831 self,
13832 fs: Arc<dyn Fs>,
13833 language_server_id: LanguageServerId,
13834 cx: &mut Context<LspStore>,
13835 ) -> LanguageServerWatchedPaths {
13836 let lsp_store = cx.weak_entity();
13837
13838 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13839 let abs_paths = self
13840 .abs_paths
13841 .into_iter()
13842 .map(|(abs_path, globset)| {
13843 let task = cx.spawn({
13844 let abs_path = abs_path.clone();
13845 let fs = fs.clone();
13846
13847 let lsp_store = lsp_store.clone();
13848 async move |_, cx| {
13849 maybe!(async move {
13850 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13851 while let Some(update) = push_updates.0.next().await {
13852 let action = lsp_store
13853 .update(cx, |this, _| {
13854 let Some(local) = this.as_local() else {
13855 return ControlFlow::Break(());
13856 };
13857 let Some(watcher) = local
13858 .language_server_watched_paths
13859 .get(&language_server_id)
13860 else {
13861 return ControlFlow::Break(());
13862 };
13863 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13864 "Watched abs path is not registered with a watcher",
13865 );
13866 let matching_entries = update
13867 .into_iter()
13868 .filter(|event| globs.is_match(&event.path))
13869 .collect::<Vec<_>>();
13870 this.lsp_notify_abs_paths_changed(
13871 language_server_id,
13872 matching_entries,
13873 );
13874 ControlFlow::Continue(())
13875 })
13876 .ok()?;
13877
13878 if action.is_break() {
13879 break;
13880 }
13881 }
13882 Some(())
13883 })
13884 .await;
13885 }
13886 });
13887 (abs_path, (globset, task))
13888 })
13889 .collect();
13890 LanguageServerWatchedPaths {
13891 worktree_paths: self.worktree_paths,
13892 abs_paths,
13893 }
13894 }
13895}
13896
13897struct LspBufferSnapshot {
13898 version: i32,
13899 snapshot: TextBufferSnapshot,
13900}
13901
13902/// A prompt requested by LSP server.
13903#[derive(Clone, Debug)]
13904pub struct LanguageServerPromptRequest {
13905 pub id: usize,
13906 pub level: PromptLevel,
13907 pub message: String,
13908 pub actions: Vec<MessageActionItem>,
13909 pub lsp_name: String,
13910 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13911}
13912
13913impl LanguageServerPromptRequest {
13914 pub fn new(
13915 level: PromptLevel,
13916 message: String,
13917 actions: Vec<MessageActionItem>,
13918 lsp_name: String,
13919 response_channel: smol::channel::Sender<MessageActionItem>,
13920 ) -> Self {
13921 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13922 LanguageServerPromptRequest {
13923 id,
13924 level,
13925 message,
13926 actions,
13927 lsp_name,
13928 response_channel,
13929 }
13930 }
13931 pub async fn respond(self, index: usize) -> Option<()> {
13932 if let Some(response) = self.actions.into_iter().nth(index) {
13933 self.response_channel.send(response).await.ok()
13934 } else {
13935 None
13936 }
13937 }
13938
13939 #[cfg(any(test, feature = "test-support"))]
13940 pub fn test(
13941 level: PromptLevel,
13942 message: String,
13943 actions: Vec<MessageActionItem>,
13944 lsp_name: String,
13945 ) -> Self {
13946 let (tx, _rx) = smol::channel::unbounded();
13947 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13948 }
13949}
13950impl PartialEq for LanguageServerPromptRequest {
13951 fn eq(&self, other: &Self) -> bool {
13952 self.message == other.message && self.actions == other.actions
13953 }
13954}
13955
13956#[derive(Clone, Debug, PartialEq)]
13957pub enum LanguageServerLogType {
13958 Log(MessageType),
13959 Trace { verbose_info: Option<String> },
13960 Rpc { received: bool },
13961}
13962
13963impl LanguageServerLogType {
13964 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13965 match self {
13966 Self::Log(log_type) => {
13967 use proto::log_message::LogLevel;
13968 let level = match *log_type {
13969 MessageType::ERROR => LogLevel::Error,
13970 MessageType::WARNING => LogLevel::Warning,
13971 MessageType::INFO => LogLevel::Info,
13972 MessageType::LOG => LogLevel::Log,
13973 other => {
13974 log::warn!("Unknown lsp log message type: {other:?}");
13975 LogLevel::Log
13976 }
13977 };
13978 proto::language_server_log::LogType::Log(proto::LogMessage {
13979 level: level as i32,
13980 })
13981 }
13982 Self::Trace { verbose_info } => {
13983 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13984 verbose_info: verbose_info.to_owned(),
13985 })
13986 }
13987 Self::Rpc { received } => {
13988 let kind = if *received {
13989 proto::rpc_message::Kind::Received
13990 } else {
13991 proto::rpc_message::Kind::Sent
13992 };
13993 let kind = kind as i32;
13994 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13995 }
13996 }
13997 }
13998
13999 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
14000 use proto::log_message::LogLevel;
14001 use proto::rpc_message;
14002 match log_type {
14003 proto::language_server_log::LogType::Log(message_type) => Self::Log(
14004 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
14005 LogLevel::Error => MessageType::ERROR,
14006 LogLevel::Warning => MessageType::WARNING,
14007 LogLevel::Info => MessageType::INFO,
14008 LogLevel::Log => MessageType::LOG,
14009 },
14010 ),
14011 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
14012 verbose_info: trace_message.verbose_info,
14013 },
14014 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
14015 received: match rpc_message::Kind::from_i32(message.kind)
14016 .unwrap_or(rpc_message::Kind::Received)
14017 {
14018 rpc_message::Kind::Received => true,
14019 rpc_message::Kind::Sent => false,
14020 },
14021 },
14022 }
14023 }
14024}
14025
14026pub struct WorkspaceRefreshTask {
14027 refresh_tx: mpsc::Sender<()>,
14028 progress_tx: mpsc::Sender<()>,
14029 #[allow(dead_code)]
14030 task: Task<()>,
14031}
14032
14033pub enum LanguageServerState {
14034 Starting {
14035 startup: Task<Option<Arc<LanguageServer>>>,
14036 /// List of language servers that will be added to the workspace once it's initialization completes.
14037 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
14038 },
14039
14040 Running {
14041 adapter: Arc<CachedLspAdapter>,
14042 server: Arc<LanguageServer>,
14043 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
14044 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
14045 },
14046}
14047
14048impl LanguageServerState {
14049 fn add_workspace_folder(&self, uri: Uri) {
14050 match self {
14051 LanguageServerState::Starting {
14052 pending_workspace_folders,
14053 ..
14054 } => {
14055 pending_workspace_folders.lock().insert(uri);
14056 }
14057 LanguageServerState::Running { server, .. } => {
14058 server.add_workspace_folder(uri);
14059 }
14060 }
14061 }
14062 fn _remove_workspace_folder(&self, uri: Uri) {
14063 match self {
14064 LanguageServerState::Starting {
14065 pending_workspace_folders,
14066 ..
14067 } => {
14068 pending_workspace_folders.lock().remove(&uri);
14069 }
14070 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
14071 }
14072 }
14073}
14074
14075impl std::fmt::Debug for LanguageServerState {
14076 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14077 match self {
14078 LanguageServerState::Starting { .. } => {
14079 f.debug_struct("LanguageServerState::Starting").finish()
14080 }
14081 LanguageServerState::Running { .. } => {
14082 f.debug_struct("LanguageServerState::Running").finish()
14083 }
14084 }
14085 }
14086}
14087
14088#[derive(Clone, Debug, Serialize)]
14089pub struct LanguageServerProgress {
14090 pub is_disk_based_diagnostics_progress: bool,
14091 pub is_cancellable: bool,
14092 pub title: Option<String>,
14093 pub message: Option<String>,
14094 pub percentage: Option<usize>,
14095 #[serde(skip_serializing)]
14096 pub last_update_at: Instant,
14097}
14098
14099#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14100pub struct DiagnosticSummary {
14101 pub error_count: usize,
14102 pub warning_count: usize,
14103}
14104
14105impl DiagnosticSummary {
14106 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14107 let mut this = Self {
14108 error_count: 0,
14109 warning_count: 0,
14110 };
14111
14112 for entry in diagnostics {
14113 if entry.diagnostic.is_primary {
14114 match entry.diagnostic.severity {
14115 DiagnosticSeverity::ERROR => this.error_count += 1,
14116 DiagnosticSeverity::WARNING => this.warning_count += 1,
14117 _ => {}
14118 }
14119 }
14120 }
14121
14122 this
14123 }
14124
14125 pub fn is_empty(&self) -> bool {
14126 self.error_count == 0 && self.warning_count == 0
14127 }
14128
14129 pub fn to_proto(
14130 self,
14131 language_server_id: LanguageServerId,
14132 path: &RelPath,
14133 ) -> proto::DiagnosticSummary {
14134 proto::DiagnosticSummary {
14135 path: path.to_proto(),
14136 language_server_id: language_server_id.0 as u64,
14137 error_count: self.error_count as u32,
14138 warning_count: self.warning_count as u32,
14139 }
14140 }
14141}
14142
14143#[derive(Clone, Debug)]
14144pub enum CompletionDocumentation {
14145 /// There is no documentation for this completion.
14146 Undocumented,
14147 /// A single line of documentation.
14148 SingleLine(SharedString),
14149 /// Multiple lines of plain text documentation.
14150 MultiLinePlainText(SharedString),
14151 /// Markdown documentation.
14152 MultiLineMarkdown(SharedString),
14153 /// Both single line and multiple lines of plain text documentation.
14154 SingleLineAndMultiLinePlainText {
14155 single_line: SharedString,
14156 plain_text: Option<SharedString>,
14157 },
14158}
14159
14160impl CompletionDocumentation {
14161 #[cfg(any(test, feature = "test-support"))]
14162 pub fn text(&self) -> SharedString {
14163 match self {
14164 CompletionDocumentation::Undocumented => "".into(),
14165 CompletionDocumentation::SingleLine(s) => s.clone(),
14166 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14167 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14168 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14169 single_line.clone()
14170 }
14171 }
14172 }
14173}
14174
14175impl From<lsp::Documentation> for CompletionDocumentation {
14176 fn from(docs: lsp::Documentation) -> Self {
14177 match docs {
14178 lsp::Documentation::String(text) => {
14179 if text.lines().count() <= 1 {
14180 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14181 } else {
14182 CompletionDocumentation::MultiLinePlainText(text.into())
14183 }
14184 }
14185
14186 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14187 lsp::MarkupKind::PlainText => {
14188 if value.lines().count() <= 1 {
14189 CompletionDocumentation::SingleLine(value.into())
14190 } else {
14191 CompletionDocumentation::MultiLinePlainText(value.into())
14192 }
14193 }
14194
14195 lsp::MarkupKind::Markdown => {
14196 CompletionDocumentation::MultiLineMarkdown(value.into())
14197 }
14198 },
14199 }
14200 }
14201}
14202
14203pub enum ResolvedHint {
14204 Resolved(InlayHint),
14205 Resolving(Shared<Task<()>>),
14206}
14207
14208pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14209 glob.components()
14210 .take_while(|component| match component {
14211 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14212 _ => true,
14213 })
14214 .collect()
14215}
14216
14217pub struct SshLspAdapter {
14218 name: LanguageServerName,
14219 binary: LanguageServerBinary,
14220 initialization_options: Option<String>,
14221 code_action_kinds: Option<Vec<CodeActionKind>>,
14222}
14223
14224impl SshLspAdapter {
14225 pub fn new(
14226 name: LanguageServerName,
14227 binary: LanguageServerBinary,
14228 initialization_options: Option<String>,
14229 code_action_kinds: Option<String>,
14230 ) -> Self {
14231 Self {
14232 name,
14233 binary,
14234 initialization_options,
14235 code_action_kinds: code_action_kinds
14236 .as_ref()
14237 .and_then(|c| serde_json::from_str(c).ok()),
14238 }
14239 }
14240}
14241
14242impl LspInstaller for SshLspAdapter {
14243 type BinaryVersion = ();
14244 async fn check_if_user_installed(
14245 &self,
14246 _: &dyn LspAdapterDelegate,
14247 _: Option<Toolchain>,
14248 _: &AsyncApp,
14249 ) -> Option<LanguageServerBinary> {
14250 Some(self.binary.clone())
14251 }
14252
14253 async fn cached_server_binary(
14254 &self,
14255 _: PathBuf,
14256 _: &dyn LspAdapterDelegate,
14257 ) -> Option<LanguageServerBinary> {
14258 None
14259 }
14260
14261 async fn fetch_latest_server_version(
14262 &self,
14263 _: &dyn LspAdapterDelegate,
14264 _: bool,
14265 _: &mut AsyncApp,
14266 ) -> Result<()> {
14267 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14268 }
14269
14270 async fn fetch_server_binary(
14271 &self,
14272 _: (),
14273 _: PathBuf,
14274 _: &dyn LspAdapterDelegate,
14275 ) -> Result<LanguageServerBinary> {
14276 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14277 }
14278}
14279
14280#[async_trait(?Send)]
14281impl LspAdapter for SshLspAdapter {
14282 fn name(&self) -> LanguageServerName {
14283 self.name.clone()
14284 }
14285
14286 async fn initialization_options(
14287 self: Arc<Self>,
14288 _: &Arc<dyn LspAdapterDelegate>,
14289 _: &mut AsyncApp,
14290 ) -> Result<Option<serde_json::Value>> {
14291 let Some(options) = &self.initialization_options else {
14292 return Ok(None);
14293 };
14294 let result = serde_json::from_str(options)?;
14295 Ok(result)
14296 }
14297
14298 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14299 self.code_action_kinds.clone()
14300 }
14301}
14302
14303pub fn language_server_settings<'a>(
14304 delegate: &'a dyn LspAdapterDelegate,
14305 language: &LanguageServerName,
14306 cx: &'a App,
14307) -> Option<&'a LspSettings> {
14308 language_server_settings_for(
14309 SettingsLocation {
14310 worktree_id: delegate.worktree_id(),
14311 path: RelPath::empty(),
14312 },
14313 language,
14314 cx,
14315 )
14316}
14317
14318pub fn language_server_settings_for<'a>(
14319 location: SettingsLocation<'a>,
14320 language: &LanguageServerName,
14321 cx: &'a App,
14322) -> Option<&'a LspSettings> {
14323 ProjectSettings::get(Some(location), cx).lsp.get(language)
14324}
14325
14326pub struct LocalLspAdapterDelegate {
14327 lsp_store: WeakEntity<LspStore>,
14328 worktree: worktree::Snapshot,
14329 fs: Arc<dyn Fs>,
14330 http_client: Arc<dyn HttpClient>,
14331 language_registry: Arc<LanguageRegistry>,
14332 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14333}
14334
14335impl LocalLspAdapterDelegate {
14336 pub fn new(
14337 language_registry: Arc<LanguageRegistry>,
14338 environment: &Entity<ProjectEnvironment>,
14339 lsp_store: WeakEntity<LspStore>,
14340 worktree: &Entity<Worktree>,
14341 http_client: Arc<dyn HttpClient>,
14342 fs: Arc<dyn Fs>,
14343 cx: &mut App,
14344 ) -> Arc<Self> {
14345 let load_shell_env_task =
14346 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14347
14348 Arc::new(Self {
14349 lsp_store,
14350 worktree: worktree.read(cx).snapshot(),
14351 fs,
14352 http_client,
14353 language_registry,
14354 load_shell_env_task,
14355 })
14356 }
14357
14358 pub fn from_local_lsp(
14359 local: &LocalLspStore,
14360 worktree: &Entity<Worktree>,
14361 cx: &mut App,
14362 ) -> Arc<Self> {
14363 Self::new(
14364 local.languages.clone(),
14365 &local.environment,
14366 local.weak.clone(),
14367 worktree,
14368 local.http_client.clone(),
14369 local.fs.clone(),
14370 cx,
14371 )
14372 }
14373}
14374
14375#[async_trait]
14376impl LspAdapterDelegate for LocalLspAdapterDelegate {
14377 fn show_notification(&self, message: &str, cx: &mut App) {
14378 self.lsp_store
14379 .update(cx, |_, cx| {
14380 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14381 })
14382 .ok();
14383 }
14384
14385 fn http_client(&self) -> Arc<dyn HttpClient> {
14386 self.http_client.clone()
14387 }
14388
14389 fn worktree_id(&self) -> WorktreeId {
14390 self.worktree.id()
14391 }
14392
14393 fn worktree_root_path(&self) -> &Path {
14394 self.worktree.abs_path().as_ref()
14395 }
14396
14397 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14398 self.worktree.resolve_relative_path(path)
14399 }
14400
14401 async fn shell_env(&self) -> HashMap<String, String> {
14402 let task = self.load_shell_env_task.clone();
14403 task.await.unwrap_or_default()
14404 }
14405
14406 async fn npm_package_installed_version(
14407 &self,
14408 package_name: &str,
14409 ) -> Result<Option<(PathBuf, Version)>> {
14410 let local_package_directory = self.worktree_root_path();
14411 let node_modules_directory = local_package_directory.join("node_modules");
14412
14413 if let Some(version) =
14414 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14415 {
14416 return Ok(Some((node_modules_directory, version)));
14417 }
14418 let Some(npm) = self.which("npm".as_ref()).await else {
14419 log::warn!(
14420 "Failed to find npm executable for {:?}",
14421 local_package_directory
14422 );
14423 return Ok(None);
14424 };
14425
14426 let env = self.shell_env().await;
14427 let output = util::command::new_command(&npm)
14428 .args(["root", "-g"])
14429 .envs(env)
14430 .current_dir(local_package_directory)
14431 .output()
14432 .await?;
14433 let global_node_modules =
14434 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14435
14436 if let Some(version) =
14437 read_package_installed_version(global_node_modules.clone(), package_name).await?
14438 {
14439 return Ok(Some((global_node_modules, version)));
14440 }
14441 return Ok(None);
14442 }
14443
14444 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14445 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14446 if self.fs.is_file(&worktree_abs_path).await {
14447 worktree_abs_path.pop();
14448 }
14449
14450 let env = self.shell_env().await;
14451
14452 let shell_path = env.get("PATH").cloned();
14453
14454 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14455 }
14456
14457 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14458 let mut working_dir = self.worktree_root_path().to_path_buf();
14459 if self.fs.is_file(&working_dir).await {
14460 working_dir.pop();
14461 }
14462 let output = util::command::new_command(&command.path)
14463 .args(command.arguments)
14464 .envs(command.env.clone().unwrap_or_default())
14465 .current_dir(working_dir)
14466 .output()
14467 .await?;
14468
14469 anyhow::ensure!(
14470 output.status.success(),
14471 "{}, stdout: {:?}, stderr: {:?}",
14472 output.status,
14473 String::from_utf8_lossy(&output.stdout),
14474 String::from_utf8_lossy(&output.stderr)
14475 );
14476 Ok(())
14477 }
14478
14479 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14480 self.language_registry
14481 .update_lsp_binary_status(server_name, status);
14482 }
14483
14484 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14485 self.language_registry
14486 .all_lsp_adapters()
14487 .into_iter()
14488 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14489 .collect()
14490 }
14491
14492 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14493 let dir = self.language_registry.language_server_download_dir(name)?;
14494
14495 if !dir.exists() {
14496 smol::fs::create_dir_all(&dir)
14497 .await
14498 .context("failed to create container directory")
14499 .log_err()?;
14500 }
14501
14502 Some(dir)
14503 }
14504
14505 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14506 let entry = self
14507 .worktree
14508 .entry_for_path(path)
14509 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14510 let abs_path = self.worktree.absolutize(&entry.path);
14511 self.fs.load(&abs_path).await
14512 }
14513}
14514
14515async fn populate_labels_for_symbols(
14516 symbols: Vec<CoreSymbol>,
14517 language_registry: &Arc<LanguageRegistry>,
14518 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14519 output: &mut Vec<Symbol>,
14520) {
14521 #[allow(clippy::mutable_key_type)]
14522 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14523
14524 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14525 for symbol in symbols {
14526 let Some(file_name) = symbol.path.file_name() else {
14527 continue;
14528 };
14529 let language = language_registry
14530 .load_language_for_file_path(Path::new(file_name))
14531 .await
14532 .ok()
14533 .or_else(|| {
14534 unknown_paths.insert(file_name.into());
14535 None
14536 });
14537 symbols_by_language
14538 .entry(language)
14539 .or_default()
14540 .push(symbol);
14541 }
14542
14543 for unknown_path in unknown_paths {
14544 log::info!("no language found for symbol in file {unknown_path:?}");
14545 }
14546
14547 let mut label_params = Vec::new();
14548 for (language, mut symbols) in symbols_by_language {
14549 label_params.clear();
14550 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14551 name: mem::take(&mut symbol.name),
14552 kind: symbol.kind,
14553 container_name: symbol.container_name.take(),
14554 }));
14555
14556 let mut labels = Vec::new();
14557 if let Some(language) = language {
14558 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14559 language_registry
14560 .lsp_adapters(&language.name())
14561 .first()
14562 .cloned()
14563 });
14564 if let Some(lsp_adapter) = lsp_adapter {
14565 labels = lsp_adapter
14566 .labels_for_symbols(&label_params, &language)
14567 .await
14568 .log_err()
14569 .unwrap_or_default();
14570 }
14571 }
14572
14573 for (
14574 (
14575 symbol,
14576 language::Symbol {
14577 name,
14578 container_name,
14579 ..
14580 },
14581 ),
14582 label,
14583 ) in symbols
14584 .into_iter()
14585 .zip(label_params.drain(..))
14586 .zip(labels.into_iter().chain(iter::repeat(None)))
14587 {
14588 output.push(Symbol {
14589 language_server_name: symbol.language_server_name,
14590 source_worktree_id: symbol.source_worktree_id,
14591 source_language_server_id: symbol.source_language_server_id,
14592 path: symbol.path,
14593 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14594 name,
14595 kind: symbol.kind,
14596 range: symbol.range,
14597 container_name,
14598 });
14599 }
14600 }
14601}
14602
14603pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14604 text.lines()
14605 .map(|line| line.trim())
14606 .filter(|line| !line.is_empty())
14607 .join(separator)
14608}
14609
14610fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14611 match server.capabilities().text_document_sync.as_ref()? {
14612 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14613 // Server wants didSave but didn't specify includeText.
14614 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14615 // Server doesn't want didSave at all.
14616 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14617 // Server provided SaveOptions.
14618 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14619 Some(save_options.include_text.unwrap_or(false))
14620 }
14621 },
14622 // We do not have any save info. Kind affects didChange only.
14623 lsp::TextDocumentSyncCapability::Kind(_) => None,
14624 }
14625}
14626
14627/// Completion items are displayed in a `UniformList`.
14628/// Usually, those items are single-line strings, but in LSP responses,
14629/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14630/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14631/// 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,
14632/// breaking the completions menu presentation.
14633///
14634/// 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.
14635pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14636 let mut new_text = String::with_capacity(label.text.len());
14637 let mut offset_map = vec![0; label.text.len() + 1];
14638 let mut last_char_was_space = false;
14639 let mut new_idx = 0;
14640 let chars = label.text.char_indices().fuse();
14641 let mut newlines_removed = false;
14642
14643 for (idx, c) in chars {
14644 offset_map[idx] = new_idx;
14645
14646 match c {
14647 '\n' if last_char_was_space => {
14648 newlines_removed = true;
14649 }
14650 '\t' | ' ' if last_char_was_space => {}
14651 '\n' if !last_char_was_space => {
14652 new_text.push(' ');
14653 new_idx += 1;
14654 last_char_was_space = true;
14655 newlines_removed = true;
14656 }
14657 ' ' | '\t' => {
14658 new_text.push(' ');
14659 new_idx += 1;
14660 last_char_was_space = true;
14661 }
14662 _ => {
14663 new_text.push(c);
14664 new_idx += c.len_utf8();
14665 last_char_was_space = false;
14666 }
14667 }
14668 }
14669 offset_map[label.text.len()] = new_idx;
14670
14671 // Only modify the label if newlines were removed.
14672 if !newlines_removed {
14673 return;
14674 }
14675
14676 let last_index = new_idx;
14677 let mut run_ranges_errors = Vec::new();
14678 label.runs.retain_mut(|(range, _)| {
14679 match offset_map.get(range.start) {
14680 Some(&start) => range.start = start,
14681 None => {
14682 run_ranges_errors.push(range.clone());
14683 return false;
14684 }
14685 }
14686
14687 match offset_map.get(range.end) {
14688 Some(&end) => range.end = end,
14689 None => {
14690 run_ranges_errors.push(range.clone());
14691 range.end = last_index;
14692 }
14693 }
14694 true
14695 });
14696 if !run_ranges_errors.is_empty() {
14697 log::error!(
14698 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14699 label.text
14700 );
14701 }
14702
14703 let mut wrong_filter_range = None;
14704 if label.filter_range == (0..label.text.len()) {
14705 label.filter_range = 0..new_text.len();
14706 } else {
14707 let mut original_filter_range = Some(label.filter_range.clone());
14708 match offset_map.get(label.filter_range.start) {
14709 Some(&start) => label.filter_range.start = start,
14710 None => {
14711 wrong_filter_range = original_filter_range.take();
14712 label.filter_range.start = last_index;
14713 }
14714 }
14715
14716 match offset_map.get(label.filter_range.end) {
14717 Some(&end) => label.filter_range.end = end,
14718 None => {
14719 wrong_filter_range = original_filter_range.take();
14720 label.filter_range.end = last_index;
14721 }
14722 }
14723 }
14724 if let Some(wrong_filter_range) = wrong_filter_range {
14725 log::error!(
14726 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14727 label.text
14728 );
14729 }
14730
14731 label.text = new_text;
14732}
14733
14734/// Apply edits to the buffer that will become part of the formatting transaction.
14735/// Fails if the buffer has been edited since the start of that transaction.
14736fn extend_formatting_transaction(
14737 buffer: &FormattableBuffer,
14738 formatting_transaction_id: text::TransactionId,
14739 cx: &mut AsyncApp,
14740 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14741) -> anyhow::Result<()> {
14742 buffer.handle.update(cx, |buffer, cx| {
14743 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14744 if last_transaction_id != Some(formatting_transaction_id) {
14745 anyhow::bail!("Buffer edited while formatting. Aborting")
14746 }
14747 buffer.start_transaction();
14748 operation(buffer, cx);
14749 if let Some(transaction_id) = buffer.end_transaction(cx) {
14750 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14751 }
14752 Ok(())
14753 })
14754}