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 all_language_servers_stopped: bool,
335 stopped_language_servers: HashSet<LanguageServerName>,
336
337 buffers_to_refresh_hash_set: HashSet<BufferId>,
338 buffers_to_refresh_queue: VecDeque<BufferId>,
339 _background_diagnostics_worker: Shared<Task<()>>,
340}
341
342impl LocalLspStore {
343 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
344 pub fn running_language_server_for_id(
345 &self,
346 id: LanguageServerId,
347 ) -> Option<&Arc<LanguageServer>> {
348 let language_server_state = self.language_servers.get(&id)?;
349
350 match language_server_state {
351 LanguageServerState::Running { server, .. } => Some(server),
352 LanguageServerState::Starting { .. } => None,
353 }
354 }
355
356 fn get_or_insert_language_server(
357 &mut self,
358 worktree_handle: &Entity<Worktree>,
359 delegate: Arc<LocalLspAdapterDelegate>,
360 disposition: &Arc<LaunchDisposition>,
361 language_name: &LanguageName,
362 cx: &mut App,
363 ) -> LanguageServerId {
364 let key = LanguageServerSeed {
365 worktree_id: worktree_handle.read(cx).id(),
366 name: disposition.server_name.clone(),
367 settings: LanguageServerSeedSettings {
368 binary: disposition.settings.binary.clone(),
369 initialization_options: disposition.settings.initialization_options.clone(),
370 },
371 toolchain: disposition.toolchain.clone(),
372 };
373 if let Some(state) = self.language_server_ids.get_mut(&key) {
374 state.project_roots.insert(disposition.path.path.clone());
375 state.id
376 } else {
377 let adapter = self
378 .languages
379 .lsp_adapters(language_name)
380 .into_iter()
381 .find(|adapter| adapter.name() == disposition.server_name)
382 .expect("To find LSP adapter");
383 let new_language_server_id = self.start_language_server(
384 worktree_handle,
385 delegate,
386 adapter,
387 disposition.settings.clone(),
388 key.clone(),
389 language_name.clone(),
390 cx,
391 );
392 if let Some(state) = self.language_server_ids.get_mut(&key) {
393 state.project_roots.insert(disposition.path.path.clone());
394 } else {
395 debug_assert!(
396 false,
397 "Expected `start_language_server` to ensure that `key` exists in a map"
398 );
399 }
400 new_language_server_id
401 }
402 }
403
404 fn start_language_server(
405 &mut self,
406 worktree_handle: &Entity<Worktree>,
407 delegate: Arc<LocalLspAdapterDelegate>,
408 adapter: Arc<CachedLspAdapter>,
409 settings: Arc<LspSettings>,
410 key: LanguageServerSeed,
411 language_name: LanguageName,
412 cx: &mut App,
413 ) -> LanguageServerId {
414 let worktree = worktree_handle.read(cx);
415
416 let worktree_id = worktree.id();
417 let worktree_abs_path = worktree.abs_path();
418 let toolchain = key.toolchain.clone();
419 let override_options = settings.initialization_options.clone();
420
421 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
422
423 let server_id = self.languages.next_language_server_id();
424 log::trace!(
425 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
426 adapter.name.0
427 );
428
429 let wait_until_worktree_trust =
430 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
431 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
432 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
433 });
434 if can_trust {
435 self.restricted_worktrees_tasks.remove(&worktree_id);
436 None
437 } else {
438 match self.restricted_worktrees_tasks.entry(worktree_id) {
439 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
440 hash_map::Entry::Vacant(v) => {
441 let (mut tx, rx) = watch::channel::<bool>();
442 let lsp_store = self.weak.clone();
443 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
444 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
445 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
446 tx.blocking_send(true).ok();
447 lsp_store
448 .update(cx, |lsp_store, _| {
449 if let Some(local_lsp_store) =
450 lsp_store.as_local_mut()
451 {
452 local_lsp_store
453 .restricted_worktrees_tasks
454 .remove(&worktree_id);
455 }
456 })
457 .ok();
458 }
459 }
460 });
461 v.insert((subscription, rx.clone()));
462 Some(rx)
463 }
464 }
465 }
466 });
467 let update_binary_status = wait_until_worktree_trust.is_none();
468
469 let binary = self.get_language_server_binary(
470 worktree_abs_path.clone(),
471 adapter.clone(),
472 settings,
473 toolchain.clone(),
474 delegate.clone(),
475 true,
476 wait_until_worktree_trust,
477 cx,
478 );
479 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
480
481 let pending_server = cx.spawn({
482 let adapter = adapter.clone();
483 let server_name = adapter.name.clone();
484 let stderr_capture = stderr_capture.clone();
485 #[cfg(any(test, feature = "test-support"))]
486 let lsp_store = self.weak.clone();
487 let pending_workspace_folders = pending_workspace_folders.clone();
488 async move |cx| {
489 let binary = binary.await?;
490 #[cfg(any(test, feature = "test-support"))]
491 if let Some(server) = lsp_store
492 .update(&mut cx.clone(), |this, cx| {
493 this.languages.create_fake_language_server(
494 server_id,
495 &server_name,
496 binary.clone(),
497 &mut cx.to_async(),
498 )
499 })
500 .ok()
501 .flatten()
502 {
503 return Ok(server);
504 }
505
506 let code_action_kinds = adapter.code_action_kinds();
507 lsp::LanguageServer::new(
508 stderr_capture,
509 server_id,
510 server_name,
511 binary,
512 &worktree_abs_path,
513 code_action_kinds,
514 Some(pending_workspace_folders),
515 cx,
516 )
517 }
518 });
519
520 let startup = {
521 let server_name = adapter.name.0.clone();
522 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
523 let key = key.clone();
524 let adapter = adapter.clone();
525 let lsp_store = self.weak.clone();
526 let pending_workspace_folders = pending_workspace_folders.clone();
527 let pull_diagnostics = ProjectSettings::get_global(cx)
528 .diagnostics
529 .lsp_pull_diagnostics
530 .enabled;
531 let settings_location = SettingsLocation {
532 worktree_id,
533 path: RelPath::empty(),
534 };
535 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
536 .language(Some(settings_location), Some(&language_name), cx)
537 .semantic_tokens
538 .use_tree_sitter();
539 cx.spawn(async move |cx| {
540 let result = async {
541 let language_server = pending_server.await?;
542
543 let workspace_config = Self::workspace_configuration_for_adapter(
544 adapter.adapter.clone(),
545 &delegate,
546 toolchain,
547 None,
548 cx,
549 )
550 .await?;
551
552 let mut initialization_options = Self::initialization_options_for_adapter(
553 adapter.adapter.clone(),
554 &delegate,
555 cx,
556 )
557 .await?;
558
559 match (&mut initialization_options, override_options) {
560 (Some(initialization_options), Some(override_options)) => {
561 merge_json_value_into(override_options, initialization_options);
562 }
563 (None, override_options) => initialization_options = override_options,
564 _ => {}
565 }
566
567 let initialization_params = cx.update(|cx| {
568 let mut params = language_server.default_initialize_params(
569 pull_diagnostics,
570 augments_syntax_tokens,
571 cx,
572 );
573 params.initialization_options = initialization_options;
574 adapter.adapter.prepare_initialize_params(params, cx)
575 })?;
576
577 Self::setup_lsp_messages(
578 lsp_store.clone(),
579 &language_server,
580 delegate.clone(),
581 adapter.clone(),
582 );
583
584 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
585 settings: workspace_config,
586 };
587 let language_server = cx
588 .update(|cx| {
589 let request_timeout = ProjectSettings::get_global(cx)
590 .global_lsp_settings
591 .get_request_timeout();
592
593 language_server.initialize(
594 initialization_params,
595 Arc::new(did_change_configuration_params.clone()),
596 request_timeout,
597 cx,
598 )
599 })
600 .await
601 .inspect_err(|_| {
602 if let Some(lsp_store) = lsp_store.upgrade() {
603 lsp_store.update(cx, |lsp_store, cx| {
604 lsp_store.cleanup_lsp_data(server_id);
605 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
606 });
607 }
608 })?;
609
610 language_server.notify::<lsp::notification::DidChangeConfiguration>(
611 did_change_configuration_params,
612 )?;
613
614 anyhow::Ok(language_server)
615 }
616 .await;
617
618 match result {
619 Ok(server) => {
620 lsp_store
621 .update(cx, |lsp_store, cx| {
622 lsp_store.insert_newly_running_language_server(
623 adapter,
624 server.clone(),
625 server_id,
626 key,
627 pending_workspace_folders,
628 cx,
629 );
630 })
631 .ok();
632 stderr_capture.lock().take();
633 Some(server)
634 }
635
636 Err(err) => {
637 let log = stderr_capture.lock().take().unwrap_or_default();
638 delegate.update_status(
639 adapter.name(),
640 BinaryStatus::Failed {
641 error: if log.is_empty() {
642 format!("{err:#}")
643 } else {
644 format!("{err:#}\n-- stderr --\n{log}")
645 },
646 },
647 );
648 log::error!(
649 "Failed to start language server {server_name:?}: {}",
650 redact_command(&format!("{err:?}"))
651 );
652 if !log.is_empty() {
653 log::error!("server stderr: {}", redact_command(&log));
654 }
655 None
656 }
657 }
658 })
659 };
660 let state = LanguageServerState::Starting {
661 startup,
662 pending_workspace_folders,
663 };
664
665 if update_binary_status {
666 self.languages
667 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
668 }
669
670 self.language_servers.insert(server_id, state);
671 self.language_server_ids
672 .entry(key)
673 .or_insert(UnifiedLanguageServer {
674 id: server_id,
675 project_roots: Default::default(),
676 });
677 server_id
678 }
679
680 fn get_language_server_binary(
681 &self,
682 worktree_abs_path: Arc<Path>,
683 adapter: Arc<CachedLspAdapter>,
684 settings: Arc<LspSettings>,
685 toolchain: Option<Toolchain>,
686 delegate: Arc<dyn LspAdapterDelegate>,
687 allow_binary_download: bool,
688 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
689 cx: &mut App,
690 ) -> Task<Result<LanguageServerBinary>> {
691 if let Some(settings) = &settings.binary
692 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
693 {
694 let settings = settings.clone();
695 let languages = self.languages.clone();
696 return cx.background_spawn(async move {
697 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
698 let already_trusted = *wait_until_worktree_trust.borrow();
699 if !already_trusted {
700 log::info!(
701 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
702 adapter.name(),
703 );
704 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
705 if worktree_trusted {
706 break;
707 }
708 }
709 log::info!(
710 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
711 adapter.name(),
712 );
713 }
714 languages
715 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
716 }
717 let mut env = delegate.shell_env().await;
718 env.extend(settings.env.unwrap_or_default());
719
720 Ok(LanguageServerBinary {
721 path: delegate.resolve_relative_path(path),
722 env: Some(env),
723 arguments: settings
724 .arguments
725 .unwrap_or_default()
726 .iter()
727 .map(Into::into)
728 .collect(),
729 })
730 });
731 }
732 let lsp_binary_options = LanguageServerBinaryOptions {
733 allow_path_lookup: !settings
734 .binary
735 .as_ref()
736 .and_then(|b| b.ignore_system_version)
737 .unwrap_or_default(),
738 allow_binary_download,
739 pre_release: settings
740 .fetch
741 .as_ref()
742 .and_then(|f| f.pre_release)
743 .unwrap_or(false),
744 };
745
746 cx.spawn(async move |cx| {
747 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
748 let already_trusted = *wait_until_worktree_trust.borrow();
749 if !already_trusted {
750 log::info!(
751 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
752 adapter.name(),
753 );
754 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
755 if worktree_trusted {
756 break;
757 }
758 }
759 log::info!(
760 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
761 adapter.name(),
762 );
763 }
764 }
765
766 let (existing_binary, maybe_download_binary) = adapter
767 .clone()
768 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
769 .await
770 .await;
771
772 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
773
774 let mut binary = match (existing_binary, maybe_download_binary) {
775 (binary, None) => binary?,
776 (Err(_), Some(downloader)) => downloader.await?,
777 (Ok(existing_binary), Some(downloader)) => {
778 let mut download_timeout = cx
779 .background_executor()
780 .timer(SERVER_DOWNLOAD_TIMEOUT)
781 .fuse();
782 let mut downloader = downloader.fuse();
783 futures::select! {
784 _ = download_timeout => {
785 // Return existing binary and kick the existing work to the background.
786 cx.spawn(async move |_| downloader.await).detach();
787 Ok(existing_binary)
788 },
789 downloaded_or_existing_binary = downloader => {
790 // If download fails, this results in the existing binary.
791 downloaded_or_existing_binary
792 }
793 }?
794 }
795 };
796 let mut shell_env = delegate.shell_env().await;
797
798 shell_env.extend(binary.env.unwrap_or_default());
799
800 if let Some(settings) = settings.binary.as_ref() {
801 if let Some(arguments) = &settings.arguments {
802 binary.arguments = arguments.iter().map(Into::into).collect();
803 }
804 if let Some(env) = &settings.env {
805 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
806 }
807 }
808
809 binary.env = Some(shell_env);
810 Ok(binary)
811 })
812 }
813
814 fn setup_lsp_messages(
815 lsp_store: WeakEntity<LspStore>,
816 language_server: &LanguageServer,
817 delegate: Arc<dyn LspAdapterDelegate>,
818 adapter: Arc<CachedLspAdapter>,
819 ) {
820 let name = language_server.name();
821 let server_id = language_server.server_id();
822 language_server
823 .on_notification::<lsp::notification::PublishDiagnostics, _>({
824 let adapter = adapter.clone();
825 let this = lsp_store.clone();
826 move |mut params, cx| {
827 let adapter = adapter.clone();
828 if let Some(this) = this.upgrade() {
829 this.update(cx, |this, cx| {
830 adapter.process_diagnostics(&mut params, server_id);
831
832 this.merge_lsp_diagnostics(
833 DiagnosticSourceKind::Pushed,
834 vec![DocumentDiagnosticsUpdate {
835 server_id,
836 diagnostics: params,
837 result_id: None,
838 disk_based_sources: Cow::Borrowed(
839 &adapter.disk_based_diagnostic_sources,
840 ),
841 registration_id: None,
842 }],
843 |_, diagnostic, _cx| match diagnostic.source_kind {
844 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
845 adapter.retain_old_diagnostic(diagnostic)
846 }
847 DiagnosticSourceKind::Pulled => true,
848 },
849 cx,
850 )
851 .log_err();
852 });
853 }
854 }
855 })
856 .detach();
857 language_server
858 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
859 let adapter = adapter.adapter.clone();
860 let delegate = delegate.clone();
861 let this = lsp_store.clone();
862 move |params, cx| {
863 let adapter = adapter.clone();
864 let delegate = delegate.clone();
865 let this = this.clone();
866 let mut cx = cx.clone();
867 async move {
868 let toolchain_for_id = this
869 .update(&mut cx, |this, _| {
870 this.as_local()?.language_server_ids.iter().find_map(
871 |(seed, value)| {
872 (value.id == server_id).then(|| seed.toolchain.clone())
873 },
874 )
875 })?
876 .context("Expected the LSP store to be in a local mode")?;
877
878 let mut scope_uri_to_workspace_config = BTreeMap::new();
879 for item in ¶ms.items {
880 let scope_uri = item.scope_uri.clone();
881 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
882 scope_uri_to_workspace_config.entry(scope_uri.clone())
883 else {
884 // We've already queried workspace configuration of this URI.
885 continue;
886 };
887 let workspace_config = Self::workspace_configuration_for_adapter(
888 adapter.clone(),
889 &delegate,
890 toolchain_for_id.clone(),
891 scope_uri,
892 &mut cx,
893 )
894 .await?;
895 new_scope_uri.insert(workspace_config);
896 }
897
898 Ok(params
899 .items
900 .into_iter()
901 .filter_map(|item| {
902 let workspace_config =
903 scope_uri_to_workspace_config.get(&item.scope_uri)?;
904 if let Some(section) = &item.section {
905 Some(
906 workspace_config
907 .get(section)
908 .cloned()
909 .unwrap_or(serde_json::Value::Null),
910 )
911 } else {
912 Some(workspace_config.clone())
913 }
914 })
915 .collect())
916 }
917 }
918 })
919 .detach();
920
921 language_server
922 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
923 let this = lsp_store.clone();
924 move |_, cx| {
925 let this = this.clone();
926 let cx = cx.clone();
927 async move {
928 let Some(server) =
929 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
930 else {
931 return Ok(None);
932 };
933 let root = server.workspace_folders();
934 Ok(Some(
935 root.into_iter()
936 .map(|uri| WorkspaceFolder {
937 uri,
938 name: Default::default(),
939 })
940 .collect(),
941 ))
942 }
943 }
944 })
945 .detach();
946 // Even though we don't have handling for these requests, respond to them to
947 // avoid stalling any language server like `gopls` which waits for a response
948 // to these requests when initializing.
949 language_server
950 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
951 let this = lsp_store.clone();
952 move |params, cx| {
953 let this = this.clone();
954 let mut cx = cx.clone();
955 async move {
956 this.update(&mut cx, |this, _| {
957 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
958 {
959 status
960 .progress_tokens
961 .insert(ProgressToken::from_lsp(params.token));
962 }
963 })?;
964
965 Ok(())
966 }
967 }
968 })
969 .detach();
970
971 language_server
972 .on_request::<lsp::request::RegisterCapability, _, _>({
973 let lsp_store = lsp_store.clone();
974 move |params, cx| {
975 let lsp_store = lsp_store.clone();
976 let mut cx = cx.clone();
977 async move {
978 lsp_store
979 .update(&mut cx, |lsp_store, cx| {
980 if lsp_store.as_local().is_some() {
981 match lsp_store
982 .register_server_capabilities(server_id, params, cx)
983 {
984 Ok(()) => {}
985 Err(e) => {
986 log::error!(
987 "Failed to register server capabilities: {e:#}"
988 );
989 }
990 };
991 }
992 })
993 .ok();
994 Ok(())
995 }
996 }
997 })
998 .detach();
999
1000 language_server
1001 .on_request::<lsp::request::UnregisterCapability, _, _>({
1002 let lsp_store = lsp_store.clone();
1003 move |params, cx| {
1004 let lsp_store = lsp_store.clone();
1005 let mut cx = cx.clone();
1006 async move {
1007 lsp_store
1008 .update(&mut cx, |lsp_store, cx| {
1009 if lsp_store.as_local().is_some() {
1010 match lsp_store
1011 .unregister_server_capabilities(server_id, params, cx)
1012 {
1013 Ok(()) => {}
1014 Err(e) => {
1015 log::error!(
1016 "Failed to unregister server capabilities: {e:#}"
1017 );
1018 }
1019 }
1020 }
1021 })
1022 .ok();
1023 Ok(())
1024 }
1025 }
1026 })
1027 .detach();
1028
1029 language_server
1030 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1031 let this = lsp_store.clone();
1032 move |params, cx| {
1033 let mut cx = cx.clone();
1034 let this = this.clone();
1035 async move {
1036 LocalLspStore::on_lsp_workspace_edit(
1037 this.clone(),
1038 params,
1039 server_id,
1040 &mut cx,
1041 )
1042 .await
1043 }
1044 }
1045 })
1046 .detach();
1047
1048 language_server
1049 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1050 let lsp_store = lsp_store.clone();
1051 let request_id = Arc::new(AtomicUsize::new(0));
1052 move |(), cx| {
1053 let lsp_store = lsp_store.clone();
1054 let request_id = request_id.clone();
1055 let mut cx = cx.clone();
1056 async move {
1057 lsp_store
1058 .update(&mut cx, |lsp_store, cx| {
1059 let request_id =
1060 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1061 cx.emit(LspStoreEvent::RefreshInlayHints {
1062 server_id,
1063 request_id,
1064 });
1065 lsp_store
1066 .downstream_client
1067 .as_ref()
1068 .map(|(client, project_id)| {
1069 client.send(proto::RefreshInlayHints {
1070 project_id: *project_id,
1071 server_id: server_id.to_proto(),
1072 request_id: request_id.map(|id| id as u64),
1073 })
1074 })
1075 })?
1076 .transpose()?;
1077 Ok(())
1078 }
1079 }
1080 })
1081 .detach();
1082
1083 language_server
1084 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1085 let this = lsp_store.clone();
1086 move |(), cx| {
1087 let this = this.clone();
1088 let mut cx = cx.clone();
1089 async move {
1090 this.update(&mut cx, |this, cx| {
1091 cx.emit(LspStoreEvent::RefreshCodeLens);
1092 this.downstream_client.as_ref().map(|(client, project_id)| {
1093 client.send(proto::RefreshCodeLens {
1094 project_id: *project_id,
1095 })
1096 })
1097 })?
1098 .transpose()?;
1099 Ok(())
1100 }
1101 }
1102 })
1103 .detach();
1104
1105 language_server
1106 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1107 let lsp_store = lsp_store.clone();
1108 let request_id = Arc::new(AtomicUsize::new(0));
1109 move |(), cx| {
1110 let lsp_store = lsp_store.clone();
1111 let request_id = request_id.clone();
1112 let mut cx = cx.clone();
1113 async move {
1114 lsp_store
1115 .update(&mut cx, |lsp_store, cx| {
1116 let request_id =
1117 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1118 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1119 server_id,
1120 request_id,
1121 });
1122 lsp_store
1123 .downstream_client
1124 .as_ref()
1125 .map(|(client, project_id)| {
1126 client.send(proto::RefreshSemanticTokens {
1127 project_id: *project_id,
1128 server_id: server_id.to_proto(),
1129 request_id: request_id.map(|id| id as u64),
1130 })
1131 })
1132 })?
1133 .transpose()?;
1134 Ok(())
1135 }
1136 }
1137 })
1138 .detach();
1139
1140 language_server
1141 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1142 let this = lsp_store.clone();
1143 move |(), cx| {
1144 let this = this.clone();
1145 let mut cx = cx.clone();
1146 async move {
1147 this.update(&mut cx, |lsp_store, cx| {
1148 lsp_store.pull_workspace_diagnostics(server_id);
1149 lsp_store
1150 .downstream_client
1151 .as_ref()
1152 .map(|(client, project_id)| {
1153 client.send(proto::PullWorkspaceDiagnostics {
1154 project_id: *project_id,
1155 server_id: server_id.to_proto(),
1156 })
1157 })
1158 .transpose()?;
1159 anyhow::Ok(
1160 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1161 )
1162 })??
1163 .await;
1164 Ok(())
1165 }
1166 }
1167 })
1168 .detach();
1169
1170 language_server
1171 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1172 let this = lsp_store.clone();
1173 let name = name.to_string();
1174 let adapter = adapter.clone();
1175 move |params, cx| {
1176 let this = this.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 let mut cx = cx.clone();
1180 async move {
1181 let actions = params.actions.unwrap_or_default();
1182 let message = params.message.clone();
1183 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1184 let level = match params.typ {
1185 lsp::MessageType::ERROR => PromptLevel::Critical,
1186 lsp::MessageType::WARNING => PromptLevel::Warning,
1187 _ => PromptLevel::Info,
1188 };
1189 let request = LanguageServerPromptRequest::new(
1190 level,
1191 params.message,
1192 actions,
1193 name.clone(),
1194 tx,
1195 );
1196
1197 let did_update = this
1198 .update(&mut cx, |_, cx| {
1199 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1200 })
1201 .is_ok();
1202 if did_update {
1203 let response = rx.recv().await.ok();
1204 if let Some(ref selected_action) = response {
1205 let context = language::PromptResponseContext {
1206 message,
1207 selected_action: selected_action.clone(),
1208 };
1209 adapter.process_prompt_response(&context, &mut cx)
1210 }
1211
1212 Ok(response)
1213 } else {
1214 Ok(None)
1215 }
1216 }
1217 }
1218 })
1219 .detach();
1220 language_server
1221 .on_notification::<lsp::notification::ShowMessage, _>({
1222 let this = lsp_store.clone();
1223 let name = name.to_string();
1224 move |params, cx| {
1225 let this = this.clone();
1226 let name = name.to_string();
1227 let mut cx = cx.clone();
1228
1229 let (tx, _) = smol::channel::bounded(1);
1230 let level = match params.typ {
1231 lsp::MessageType::ERROR => PromptLevel::Critical,
1232 lsp::MessageType::WARNING => PromptLevel::Warning,
1233 _ => PromptLevel::Info,
1234 };
1235 let request =
1236 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1237
1238 let _ = this.update(&mut cx, |_, cx| {
1239 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1240 });
1241 }
1242 })
1243 .detach();
1244
1245 let disk_based_diagnostics_progress_token =
1246 adapter.disk_based_diagnostics_progress_token.clone();
1247
1248 language_server
1249 .on_notification::<lsp::notification::Progress, _>({
1250 let this = lsp_store.clone();
1251 move |params, cx| {
1252 if let Some(this) = this.upgrade() {
1253 this.update(cx, |this, cx| {
1254 this.on_lsp_progress(
1255 params,
1256 server_id,
1257 disk_based_diagnostics_progress_token.clone(),
1258 cx,
1259 );
1260 });
1261 }
1262 }
1263 })
1264 .detach();
1265
1266 language_server
1267 .on_notification::<lsp::notification::LogMessage, _>({
1268 let this = lsp_store.clone();
1269 move |params, cx| {
1270 if let Some(this) = this.upgrade() {
1271 this.update(cx, |_, cx| {
1272 cx.emit(LspStoreEvent::LanguageServerLog(
1273 server_id,
1274 LanguageServerLogType::Log(params.typ),
1275 params.message,
1276 ));
1277 });
1278 }
1279 }
1280 })
1281 .detach();
1282
1283 language_server
1284 .on_notification::<lsp::notification::LogTrace, _>({
1285 let this = lsp_store.clone();
1286 move |params, cx| {
1287 let mut cx = cx.clone();
1288 if let Some(this) = this.upgrade() {
1289 this.update(&mut cx, |_, cx| {
1290 cx.emit(LspStoreEvent::LanguageServerLog(
1291 server_id,
1292 LanguageServerLogType::Trace {
1293 verbose_info: params.verbose,
1294 },
1295 params.message,
1296 ));
1297 });
1298 }
1299 }
1300 })
1301 .detach();
1302
1303 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1304 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1305 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1306 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1307 }
1308
1309 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1310 let shutdown_futures = self
1311 .language_servers
1312 .drain()
1313 .map(|(_, server_state)| Self::shutdown_server(server_state))
1314 .collect::<Vec<_>>();
1315
1316 async move {
1317 join_all(shutdown_futures).await;
1318 }
1319 }
1320
1321 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1322 match server_state {
1323 LanguageServerState::Running { server, .. } => {
1324 if let Some(shutdown) = server.shutdown() {
1325 shutdown.await;
1326 }
1327 }
1328 LanguageServerState::Starting { startup, .. } => {
1329 if let Some(server) = startup.await
1330 && let Some(shutdown) = server.shutdown()
1331 {
1332 shutdown.await;
1333 }
1334 }
1335 }
1336 Ok(())
1337 }
1338
1339 fn language_servers_for_worktree(
1340 &self,
1341 worktree_id: WorktreeId,
1342 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1343 self.language_server_ids
1344 .iter()
1345 .filter_map(move |(seed, state)| {
1346 if seed.worktree_id != worktree_id {
1347 return None;
1348 }
1349
1350 if let Some(LanguageServerState::Running { server, .. }) =
1351 self.language_servers.get(&state.id)
1352 {
1353 Some(server)
1354 } else {
1355 None
1356 }
1357 })
1358 }
1359
1360 fn language_server_ids_for_project_path(
1361 &self,
1362 project_path: ProjectPath,
1363 language: &Language,
1364 cx: &mut App,
1365 ) -> Vec<LanguageServerId> {
1366 let Some(worktree) = self
1367 .worktree_store
1368 .read(cx)
1369 .worktree_for_id(project_path.worktree_id, cx)
1370 else {
1371 return Vec::new();
1372 };
1373 let delegate: Arc<dyn ManifestDelegate> =
1374 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1375
1376 self.lsp_tree
1377 .get(
1378 project_path,
1379 language.name(),
1380 language.manifest(),
1381 &delegate,
1382 cx,
1383 )
1384 .collect::<Vec<_>>()
1385 }
1386
1387 fn language_server_ids_for_buffer(
1388 &self,
1389 buffer: &Buffer,
1390 cx: &mut App,
1391 ) -> Vec<LanguageServerId> {
1392 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1393 let worktree_id = file.worktree_id(cx);
1394
1395 let path: Arc<RelPath> = file
1396 .path()
1397 .parent()
1398 .map(Arc::from)
1399 .unwrap_or_else(|| file.path().clone());
1400 let worktree_path = ProjectPath { worktree_id, path };
1401 self.language_server_ids_for_project_path(worktree_path, language, cx)
1402 } else {
1403 Vec::new()
1404 }
1405 }
1406
1407 fn language_servers_for_buffer<'a>(
1408 &'a self,
1409 buffer: &'a Buffer,
1410 cx: &'a mut App,
1411 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1412 self.language_server_ids_for_buffer(buffer, cx)
1413 .into_iter()
1414 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1415 LanguageServerState::Running {
1416 adapter, server, ..
1417 } => Some((adapter, server)),
1418 _ => None,
1419 })
1420 }
1421
1422 async fn execute_code_action_kind_locally(
1423 lsp_store: WeakEntity<LspStore>,
1424 mut buffers: Vec<Entity<Buffer>>,
1425 kind: CodeActionKind,
1426 push_to_history: bool,
1427 cx: &mut AsyncApp,
1428 ) -> anyhow::Result<ProjectTransaction> {
1429 // Do not allow multiple concurrent code actions requests for the
1430 // same buffer.
1431 lsp_store.update(cx, |this, cx| {
1432 let this = this.as_local_mut().unwrap();
1433 buffers.retain(|buffer| {
1434 this.buffers_being_formatted
1435 .insert(buffer.read(cx).remote_id())
1436 });
1437 })?;
1438 let _cleanup = defer({
1439 let this = lsp_store.clone();
1440 let mut cx = cx.clone();
1441 let buffers = &buffers;
1442 move || {
1443 this.update(&mut cx, |this, cx| {
1444 let this = this.as_local_mut().unwrap();
1445 for buffer in buffers {
1446 this.buffers_being_formatted
1447 .remove(&buffer.read(cx).remote_id());
1448 }
1449 })
1450 .ok();
1451 }
1452 });
1453 let mut project_transaction = ProjectTransaction::default();
1454
1455 for buffer in &buffers {
1456 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1457 buffer.update(cx, |buffer, cx| {
1458 lsp_store
1459 .as_local()
1460 .unwrap()
1461 .language_servers_for_buffer(buffer, cx)
1462 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1463 .collect::<Vec<_>>()
1464 })
1465 })?;
1466 for (_, language_server) in adapters_and_servers.iter() {
1467 let actions = Self::get_server_code_actions_from_action_kinds(
1468 &lsp_store,
1469 language_server.server_id(),
1470 vec![kind.clone()],
1471 buffer,
1472 cx,
1473 )
1474 .await?;
1475 Self::execute_code_actions_on_server(
1476 &lsp_store,
1477 language_server,
1478 actions,
1479 push_to_history,
1480 &mut project_transaction,
1481 cx,
1482 )
1483 .await?;
1484 }
1485 }
1486 Ok(project_transaction)
1487 }
1488
1489 async fn format_locally(
1490 lsp_store: WeakEntity<LspStore>,
1491 mut buffers: Vec<FormattableBuffer>,
1492 push_to_history: bool,
1493 trigger: FormatTrigger,
1494 logger: zlog::Logger,
1495 cx: &mut AsyncApp,
1496 ) -> anyhow::Result<ProjectTransaction> {
1497 // Do not allow multiple concurrent formatting requests for the
1498 // same buffer.
1499 lsp_store.update(cx, |this, cx| {
1500 let this = this.as_local_mut().unwrap();
1501 buffers.retain(|buffer| {
1502 this.buffers_being_formatted
1503 .insert(buffer.handle.read(cx).remote_id())
1504 });
1505 })?;
1506
1507 let _cleanup = defer({
1508 let this = lsp_store.clone();
1509 let mut cx = cx.clone();
1510 let buffers = &buffers;
1511 move || {
1512 this.update(&mut cx, |this, cx| {
1513 let this = this.as_local_mut().unwrap();
1514 for buffer in buffers {
1515 this.buffers_being_formatted
1516 .remove(&buffer.handle.read(cx).remote_id());
1517 }
1518 })
1519 .ok();
1520 }
1521 });
1522
1523 let mut project_transaction = ProjectTransaction::default();
1524
1525 for buffer in &buffers {
1526 zlog::debug!(
1527 logger =>
1528 "formatting buffer '{:?}'",
1529 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1530 );
1531 // Create an empty transaction to hold all of the formatting edits.
1532 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1533 // ensure no transactions created while formatting are
1534 // grouped with the previous transaction in the history
1535 // based on the transaction group interval
1536 buffer.finalize_last_transaction();
1537 buffer
1538 .start_transaction()
1539 .context("transaction already open")?;
1540 buffer.end_transaction(cx);
1541 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1542 buffer.finalize_last_transaction();
1543 anyhow::Ok(transaction_id)
1544 })?;
1545
1546 let result = Self::format_buffer_locally(
1547 lsp_store.clone(),
1548 buffer,
1549 formatting_transaction_id,
1550 trigger,
1551 logger,
1552 cx,
1553 )
1554 .await;
1555
1556 buffer.handle.update(cx, |buffer, cx| {
1557 let Some(formatting_transaction) =
1558 buffer.get_transaction(formatting_transaction_id).cloned()
1559 else {
1560 zlog::warn!(logger => "no formatting transaction");
1561 return;
1562 };
1563 if formatting_transaction.edit_ids.is_empty() {
1564 zlog::debug!(logger => "no changes made while formatting");
1565 buffer.forget_transaction(formatting_transaction_id);
1566 return;
1567 }
1568 if !push_to_history {
1569 zlog::trace!(logger => "forgetting format transaction");
1570 buffer.forget_transaction(formatting_transaction.id);
1571 }
1572 project_transaction
1573 .0
1574 .insert(cx.entity(), formatting_transaction);
1575 });
1576
1577 result?;
1578 }
1579
1580 Ok(project_transaction)
1581 }
1582
1583 async fn format_buffer_locally(
1584 lsp_store: WeakEntity<LspStore>,
1585 buffer: &FormattableBuffer,
1586 formatting_transaction_id: clock::Lamport,
1587 trigger: FormatTrigger,
1588 logger: zlog::Logger,
1589 cx: &mut AsyncApp,
1590 ) -> Result<()> {
1591 let (adapters_and_servers, settings, request_timeout) =
1592 lsp_store.update(cx, |lsp_store, cx| {
1593 buffer.handle.update(cx, |buffer, cx| {
1594 let adapters_and_servers = lsp_store
1595 .as_local()
1596 .unwrap()
1597 .language_servers_for_buffer(buffer, cx)
1598 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1599 .collect::<Vec<_>>();
1600 let settings = LanguageSettings::for_buffer(buffer, cx).into_owned();
1601 let request_timeout = ProjectSettings::get_global(cx)
1602 .global_lsp_settings
1603 .get_request_timeout();
1604 (adapters_and_servers, settings, request_timeout)
1605 })
1606 })?;
1607
1608 // handle whitespace formatting
1609 if settings.remove_trailing_whitespace_on_save {
1610 zlog::trace!(logger => "removing trailing whitespace");
1611 let diff = buffer
1612 .handle
1613 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1614 .await;
1615 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1616 buffer.apply_diff(diff, cx);
1617 })?;
1618 }
1619
1620 if settings.ensure_final_newline_on_save {
1621 zlog::trace!(logger => "ensuring final newline");
1622 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1623 buffer.ensure_final_newline(cx);
1624 })?;
1625 }
1626
1627 // Formatter for `code_actions_on_format` that runs before
1628 // the rest of the formatters
1629 let mut code_actions_on_format_formatters = None;
1630 let should_run_code_actions_on_format = !matches!(
1631 (trigger, &settings.format_on_save),
1632 (FormatTrigger::Save, &FormatOnSave::Off)
1633 );
1634 if should_run_code_actions_on_format {
1635 let have_code_actions_to_run_on_format = settings
1636 .code_actions_on_format
1637 .values()
1638 .any(|enabled| *enabled);
1639 if have_code_actions_to_run_on_format {
1640 zlog::trace!(logger => "going to run code actions on format");
1641 code_actions_on_format_formatters = Some(
1642 settings
1643 .code_actions_on_format
1644 .iter()
1645 .filter_map(|(action, enabled)| enabled.then_some(action))
1646 .cloned()
1647 .map(Formatter::CodeAction)
1648 .collect::<Vec<_>>(),
1649 );
1650 }
1651 }
1652
1653 let formatters = match (trigger, &settings.format_on_save) {
1654 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1655 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1656 settings.formatter.as_ref()
1657 }
1658 };
1659
1660 let formatters = code_actions_on_format_formatters
1661 .iter()
1662 .flatten()
1663 .chain(formatters);
1664
1665 for formatter in formatters {
1666 let formatter = if formatter == &Formatter::Auto {
1667 if settings.prettier.allowed {
1668 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1669 &Formatter::Prettier
1670 } else {
1671 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1672 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1673 }
1674 } else {
1675 formatter
1676 };
1677 if let Err(err) = Self::apply_formatter(
1678 formatter,
1679 &lsp_store,
1680 buffer,
1681 formatting_transaction_id,
1682 &adapters_and_servers,
1683 &settings,
1684 request_timeout,
1685 logger,
1686 cx,
1687 )
1688 .await
1689 {
1690 zlog::error!(logger => "Formatter failed, skipping: {err:#}");
1691 }
1692 }
1693
1694 Ok(())
1695 }
1696
1697 async fn apply_formatter(
1698 formatter: &Formatter,
1699 lsp_store: &WeakEntity<LspStore>,
1700 buffer: &FormattableBuffer,
1701 formatting_transaction_id: clock::Lamport,
1702 adapters_and_servers: &[(Arc<CachedLspAdapter>, Arc<LanguageServer>)],
1703 settings: &LanguageSettings,
1704 request_timeout: Duration,
1705 logger: zlog::Logger,
1706 cx: &mut AsyncApp,
1707 ) -> anyhow::Result<()> {
1708 match formatter {
1709 Formatter::None => {
1710 zlog::trace!(logger => "skipping formatter 'none'");
1711 return Ok(());
1712 }
1713 Formatter::Auto => {
1714 debug_panic!("Auto resolved above");
1715 return Ok(());
1716 }
1717 Formatter::Prettier => {
1718 let logger = zlog::scoped!(logger => "prettier");
1719 zlog::trace!(logger => "formatting");
1720 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1721
1722 // When selection ranges are provided (via FormatSelections), we pass the
1723 // encompassing UTF-16 range to Prettier so it can scope its formatting.
1724 // After diffing, we filter the resulting edits to only keep those that
1725 // overlap with the original byte-level selection ranges.
1726 let (range_utf16, byte_ranges) = match buffer.ranges.as_ref() {
1727 Some(ranges) if !ranges.is_empty() => {
1728 let (utf16_range, byte_ranges) =
1729 buffer.handle.read_with(cx, |buffer, _cx| {
1730 let snapshot = buffer.snapshot();
1731 let mut min_start_utf16 = OffsetUtf16(usize::MAX);
1732 let mut max_end_utf16 = OffsetUtf16(0);
1733 let mut byte_ranges = Vec::with_capacity(ranges.len());
1734 for range in ranges {
1735 let start_utf16 = range.start.to_offset_utf16(&snapshot);
1736 let end_utf16 = range.end.to_offset_utf16(&snapshot);
1737 min_start_utf16.0 = min_start_utf16.0.min(start_utf16.0);
1738 max_end_utf16.0 = max_end_utf16.0.max(end_utf16.0);
1739
1740 let start_byte = range.start.to_offset(&snapshot);
1741 let end_byte = range.end.to_offset(&snapshot);
1742 byte_ranges.push(start_byte..end_byte);
1743 }
1744 (min_start_utf16..max_end_utf16, byte_ranges)
1745 });
1746 (Some(utf16_range), Some(byte_ranges))
1747 }
1748 _ => (None, None),
1749 };
1750
1751 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1752 lsp_store.prettier_store().unwrap().downgrade()
1753 })?;
1754 let diff = prettier_store::format_with_prettier(
1755 &prettier,
1756 &buffer.handle,
1757 range_utf16,
1758 cx,
1759 )
1760 .await
1761 .transpose()?;
1762 let Some(mut diff) = diff else {
1763 zlog::trace!(logger => "No changes");
1764 return Ok(());
1765 };
1766
1767 if let Some(byte_ranges) = byte_ranges {
1768 diff.edits.retain(|(edit_range, _)| {
1769 byte_ranges.iter().any(|selection_range| {
1770 edit_range.start < selection_range.end
1771 && edit_range.end > selection_range.start
1772 })
1773 });
1774 if diff.edits.is_empty() {
1775 zlog::trace!(logger => "No changes within selection");
1776 return Ok(());
1777 }
1778 }
1779
1780 extend_formatting_transaction(
1781 buffer,
1782 formatting_transaction_id,
1783 cx,
1784 |buffer, cx| {
1785 buffer.apply_diff(diff, cx);
1786 },
1787 )?;
1788 }
1789 Formatter::External { command, arguments } => {
1790 let logger = zlog::scoped!(logger => "command");
1791
1792 if buffer.ranges.is_some() {
1793 zlog::debug!(logger => "External formatter does not support range formatting; skipping");
1794 return Ok(());
1795 }
1796
1797 zlog::trace!(logger => "formatting");
1798 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1799
1800 let diff =
1801 Self::format_via_external_command(buffer, &command, arguments.as_deref(), cx)
1802 .await
1803 .with_context(|| {
1804 format!("Failed to format buffer via external command: {}", command)
1805 })?;
1806 let Some(diff) = diff else {
1807 zlog::trace!(logger => "No changes");
1808 return Ok(());
1809 };
1810
1811 extend_formatting_transaction(
1812 buffer,
1813 formatting_transaction_id,
1814 cx,
1815 |buffer, cx| {
1816 buffer.apply_diff(diff, cx);
1817 },
1818 )?;
1819 }
1820 Formatter::LanguageServer(specifier) => {
1821 let logger = zlog::scoped!(logger => "language-server");
1822 zlog::trace!(logger => "formatting");
1823 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1824
1825 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1826 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1827 return Ok(());
1828 };
1829
1830 let language_server = match specifier {
1831 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1832 adapters_and_servers.iter().find_map(|(adapter, server)| {
1833 if adapter.name.0.as_ref() == name {
1834 Some(server.clone())
1835 } else {
1836 None
1837 }
1838 })
1839 }
1840 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1841 .iter()
1842 .find(|(_, server)| Self::server_supports_formatting(server))
1843 .map(|(_, server)| server.clone()),
1844 };
1845
1846 let Some(language_server) = language_server else {
1847 log::debug!(
1848 "No language server found to format buffer '{:?}'. Skipping",
1849 buffer_path_abs.as_path().to_string_lossy()
1850 );
1851 return Ok(());
1852 };
1853
1854 zlog::trace!(
1855 logger =>
1856 "Formatting buffer '{:?}' using language server '{:?}'",
1857 buffer_path_abs.as_path().to_string_lossy(),
1858 language_server.name()
1859 );
1860
1861 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1862 zlog::trace!(logger => "formatting ranges");
1863 Self::format_ranges_via_lsp(
1864 &lsp_store,
1865 &buffer.handle,
1866 ranges,
1867 buffer_path_abs,
1868 &language_server,
1869 &settings,
1870 cx,
1871 )
1872 .await
1873 .context("Failed to format ranges via language server")?
1874 } else {
1875 zlog::trace!(logger => "formatting full");
1876 Self::format_via_lsp(
1877 &lsp_store,
1878 &buffer.handle,
1879 buffer_path_abs,
1880 &language_server,
1881 &settings,
1882 cx,
1883 )
1884 .await
1885 .context("failed to format via language server")?
1886 };
1887
1888 if edits.is_empty() {
1889 zlog::trace!(logger => "No changes");
1890 return Ok(());
1891 }
1892 extend_formatting_transaction(
1893 buffer,
1894 formatting_transaction_id,
1895 cx,
1896 |buffer, cx| {
1897 buffer.edit(edits, None, cx);
1898 },
1899 )?;
1900 }
1901 Formatter::CodeAction(code_action_name) => {
1902 let logger = zlog::scoped!(logger => "code-actions");
1903 zlog::trace!(logger => "formatting");
1904 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1905
1906 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1907 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1908 return Ok(());
1909 };
1910
1911 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1912 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1913
1914 let mut actions_and_servers = Vec::new();
1915
1916 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1917 let actions_result = Self::get_server_code_actions_from_action_kinds(
1918 &lsp_store,
1919 language_server.server_id(),
1920 vec![code_action_kind.clone()],
1921 &buffer.handle,
1922 cx,
1923 )
1924 .await
1925 .with_context(|| {
1926 format!(
1927 "Failed to resolve code action {:?} with language server {}",
1928 code_action_kind,
1929 language_server.name()
1930 )
1931 });
1932 let Ok(actions) = actions_result else {
1933 // note: it may be better to set result to the error and break formatters here
1934 // but for now we try to execute the actions that we can resolve and skip the rest
1935 zlog::error!(
1936 logger =>
1937 "Failed to resolve code action {:?} with language server {}",
1938 code_action_kind,
1939 language_server.name()
1940 );
1941 continue;
1942 };
1943 for action in actions {
1944 actions_and_servers.push((action, index));
1945 }
1946 }
1947
1948 if actions_and_servers.is_empty() {
1949 zlog::warn!(logger => "No code actions were resolved, continuing");
1950 return Ok(());
1951 }
1952
1953 'actions: for (mut action, server_index) in actions_and_servers {
1954 let server = &adapters_and_servers[server_index].1;
1955
1956 let describe_code_action = |action: &CodeAction| {
1957 format!(
1958 "code action '{}' with title \"{}\" on server {}",
1959 action
1960 .lsp_action
1961 .action_kind()
1962 .unwrap_or("unknown".into())
1963 .as_str(),
1964 action.lsp_action.title(),
1965 server.name(),
1966 )
1967 };
1968
1969 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1970
1971 if let Err(err) =
1972 Self::try_resolve_code_action(server, &mut action, request_timeout).await
1973 {
1974 zlog::error!(
1975 logger =>
1976 "Failed to resolve {}. Error: {}",
1977 describe_code_action(&action),
1978 err
1979 );
1980 continue;
1981 }
1982
1983 if let Some(edit) = action.lsp_action.edit().cloned() {
1984 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1985 // but filters out and logs warnings for code actions that require unreasonably
1986 // difficult handling on our part, such as:
1987 // - applying edits that call commands
1988 // which can result in arbitrary workspace edits being sent from the server that
1989 // have no way of being tied back to the command that initiated them (i.e. we
1990 // can't know which edits are part of the format request, or if the server is done sending
1991 // actions in response to the command)
1992 // - actions that create/delete/modify/rename files other than the one we are formatting
1993 // as we then would need to handle such changes correctly in the local history as well
1994 // as the remote history through the ProjectTransaction
1995 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1996 // Supporting these actions is not impossible, but not supported as of yet.
1997 if edit.changes.is_none() && edit.document_changes.is_none() {
1998 zlog::trace!(
1999 logger =>
2000 "No changes for code action. Skipping {}",
2001 describe_code_action(&action),
2002 );
2003 continue;
2004 }
2005
2006 let mut operations = Vec::new();
2007 if let Some(document_changes) = edit.document_changes {
2008 match document_changes {
2009 lsp::DocumentChanges::Edits(edits) => operations.extend(
2010 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
2011 ),
2012 lsp::DocumentChanges::Operations(ops) => operations = ops,
2013 }
2014 } else if let Some(changes) = edit.changes {
2015 operations.extend(changes.into_iter().map(|(uri, edits)| {
2016 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
2017 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
2018 uri,
2019 version: None,
2020 },
2021 edits: edits.into_iter().map(Edit::Plain).collect(),
2022 })
2023 }));
2024 }
2025
2026 let mut edits = Vec::with_capacity(operations.len());
2027
2028 if operations.is_empty() {
2029 zlog::trace!(
2030 logger =>
2031 "No changes for code action. Skipping {}",
2032 describe_code_action(&action),
2033 );
2034 continue;
2035 }
2036 for operation in operations {
2037 let op = match operation {
2038 lsp::DocumentChangeOperation::Edit(op) => op,
2039 lsp::DocumentChangeOperation::Op(_) => {
2040 zlog::warn!(
2041 logger =>
2042 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
2043 describe_code_action(&action),
2044 );
2045 continue 'actions;
2046 }
2047 };
2048 let Ok(file_path) = op.text_document.uri.to_file_path() else {
2049 zlog::warn!(
2050 logger =>
2051 "Failed to convert URI '{:?}' to file path. Skipping {}",
2052 &op.text_document.uri,
2053 describe_code_action(&action),
2054 );
2055 continue 'actions;
2056 };
2057 if &file_path != buffer_path_abs {
2058 zlog::warn!(
2059 logger =>
2060 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2061 file_path,
2062 buffer_path_abs,
2063 describe_code_action(&action),
2064 );
2065 continue 'actions;
2066 }
2067
2068 let mut lsp_edits = Vec::new();
2069 for edit in op.edits {
2070 match edit {
2071 Edit::Plain(edit) => {
2072 if !lsp_edits.contains(&edit) {
2073 lsp_edits.push(edit);
2074 }
2075 }
2076 Edit::Annotated(edit) => {
2077 if !lsp_edits.contains(&edit.text_edit) {
2078 lsp_edits.push(edit.text_edit);
2079 }
2080 }
2081 Edit::Snippet(_) => {
2082 zlog::warn!(
2083 logger =>
2084 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2085 describe_code_action(&action),
2086 );
2087 continue 'actions;
2088 }
2089 }
2090 }
2091 let edits_result = lsp_store
2092 .update(cx, |lsp_store, cx| {
2093 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2094 &buffer.handle,
2095 lsp_edits,
2096 server.server_id(),
2097 op.text_document.version,
2098 cx,
2099 )
2100 })?
2101 .await;
2102 let Ok(resolved_edits) = edits_result else {
2103 zlog::warn!(
2104 logger =>
2105 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2106 buffer_path_abs.as_path(),
2107 describe_code_action(&action),
2108 );
2109 continue 'actions;
2110 };
2111 edits.extend(resolved_edits);
2112 }
2113
2114 if edits.is_empty() {
2115 zlog::warn!(logger => "No edits resolved from LSP");
2116 continue;
2117 }
2118
2119 extend_formatting_transaction(
2120 buffer,
2121 formatting_transaction_id,
2122 cx,
2123 |buffer, cx| {
2124 zlog::info!(
2125 "Applying edits {edits:?}. Content: {:?}",
2126 buffer.text()
2127 );
2128 buffer.edit(edits, None, cx);
2129 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2130 },
2131 )?;
2132 }
2133
2134 let Some(command) = action.lsp_action.command() else {
2135 continue;
2136 };
2137
2138 zlog::warn!(
2139 logger =>
2140 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2141 &command.command,
2142 );
2143
2144 let server_capabilities = server.capabilities();
2145 let available_commands = server_capabilities
2146 .execute_command_provider
2147 .as_ref()
2148 .map(|options| options.commands.as_slice())
2149 .unwrap_or_default();
2150 if !available_commands.contains(&command.command) {
2151 zlog::warn!(
2152 logger =>
2153 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2154 command.command,
2155 server.name(),
2156 );
2157 continue;
2158 }
2159
2160 extend_formatting_transaction(
2161 buffer,
2162 formatting_transaction_id,
2163 cx,
2164 |_, _| {},
2165 )?;
2166 zlog::info!(logger => "Executing command {}", &command.command);
2167
2168 lsp_store.update(cx, |this, _| {
2169 this.as_local_mut()
2170 .unwrap()
2171 .last_workspace_edits_by_language_server
2172 .remove(&server.server_id());
2173 })?;
2174
2175 let execute_command_result = server
2176 .request::<lsp::request::ExecuteCommand>(
2177 lsp::ExecuteCommandParams {
2178 command: command.command.clone(),
2179 arguments: command.arguments.clone().unwrap_or_default(),
2180 ..Default::default()
2181 },
2182 request_timeout,
2183 )
2184 .await
2185 .into_response();
2186
2187 if execute_command_result.is_err() {
2188 zlog::error!(
2189 logger =>
2190 "Failed to execute command '{}' as part of {}",
2191 &command.command,
2192 describe_code_action(&action),
2193 );
2194 continue 'actions;
2195 }
2196
2197 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2198 this.as_local_mut()
2199 .unwrap()
2200 .last_workspace_edits_by_language_server
2201 .remove(&server.server_id())
2202 .unwrap_or_default()
2203 })?;
2204
2205 if let Some(transaction) = project_transaction_command.0.remove(&buffer.handle)
2206 {
2207 zlog::trace!(
2208 logger =>
2209 "Successfully captured {} edits that resulted from command {}",
2210 transaction.edit_ids.len(),
2211 &command.command,
2212 );
2213 let transaction_id_project_transaction = transaction.id;
2214 buffer.handle.update(cx, |buffer, _| {
2215 // it may have been removed from history if push_to_history was
2216 // false in deserialize_workspace_edit. If so push it so we
2217 // can merge it with the format transaction
2218 // and pop the combined transaction off the history stack
2219 // later if push_to_history is false
2220 if buffer.get_transaction(transaction.id).is_none() {
2221 buffer.push_transaction(transaction, Instant::now());
2222 }
2223 buffer.merge_transactions(
2224 transaction_id_project_transaction,
2225 formatting_transaction_id,
2226 );
2227 });
2228 }
2229
2230 if project_transaction_command.0.is_empty() {
2231 continue;
2232 }
2233
2234 let mut extra_buffers = String::new();
2235 for buffer in project_transaction_command.0.keys() {
2236 buffer.read_with(cx, |b, cx| {
2237 let Some(path) = b.project_path(cx) else {
2238 return;
2239 };
2240
2241 if !extra_buffers.is_empty() {
2242 extra_buffers.push_str(", ");
2243 }
2244 extra_buffers.push_str(path.path.as_unix_str());
2245 });
2246 }
2247 zlog::warn!(
2248 logger =>
2249 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2250 &command.command,
2251 extra_buffers,
2252 );
2253 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2254 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2255 // add it so it's included, and merge it into the format transaction when its created later
2256 }
2257 }
2258 }
2259
2260 Ok(())
2261 }
2262
2263 pub async fn format_ranges_via_lsp(
2264 this: &WeakEntity<LspStore>,
2265 buffer_handle: &Entity<Buffer>,
2266 ranges: &[Range<Anchor>],
2267 abs_path: &Path,
2268 language_server: &Arc<LanguageServer>,
2269 settings: &LanguageSettings,
2270 cx: &mut AsyncApp,
2271 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2272 let capabilities = &language_server.capabilities();
2273 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2274 if range_formatting_provider == Some(&OneOf::Left(false)) {
2275 anyhow::bail!(
2276 "{} language server does not support range formatting",
2277 language_server.name()
2278 );
2279 }
2280
2281 let uri = file_path_to_lsp_url(abs_path)?;
2282 let text_document = lsp::TextDocumentIdentifier::new(uri);
2283
2284 let request_timeout = cx.update(|app| {
2285 ProjectSettings::get_global(app)
2286 .global_lsp_settings
2287 .get_request_timeout()
2288 });
2289 let lsp_edits = {
2290 let mut lsp_ranges = Vec::new();
2291 this.update(cx, |_this, cx| {
2292 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2293 // not have been sent to the language server. This seems like a fairly systemic
2294 // issue, though, the resolution probably is not specific to formatting.
2295 //
2296 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2297 // LSP.
2298 let snapshot = buffer_handle.read(cx).snapshot();
2299 for range in ranges {
2300 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2301 }
2302 anyhow::Ok(())
2303 })??;
2304
2305 let mut edits = None;
2306 for range in lsp_ranges {
2307 if let Some(mut edit) = language_server
2308 .request::<lsp::request::RangeFormatting>(
2309 lsp::DocumentRangeFormattingParams {
2310 text_document: text_document.clone(),
2311 range,
2312 options: lsp_command::lsp_formatting_options(settings),
2313 work_done_progress_params: Default::default(),
2314 },
2315 request_timeout,
2316 )
2317 .await
2318 .into_response()?
2319 {
2320 edits.get_or_insert_with(Vec::new).append(&mut edit);
2321 }
2322 }
2323 edits
2324 };
2325
2326 if let Some(lsp_edits) = lsp_edits {
2327 this.update(cx, |this, cx| {
2328 this.as_local_mut().unwrap().edits_from_lsp(
2329 buffer_handle,
2330 lsp_edits,
2331 language_server.server_id(),
2332 None,
2333 cx,
2334 )
2335 })?
2336 .await
2337 } else {
2338 Ok(Vec::with_capacity(0))
2339 }
2340 }
2341
2342 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2343 let capabilities = server.capabilities();
2344 let formatting = capabilities.document_formatting_provider.as_ref();
2345 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2346 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2347 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2348 }
2349
2350 async fn format_via_lsp(
2351 this: &WeakEntity<LspStore>,
2352 buffer: &Entity<Buffer>,
2353 abs_path: &Path,
2354 language_server: &Arc<LanguageServer>,
2355 settings: &LanguageSettings,
2356 cx: &mut AsyncApp,
2357 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2358 let logger = zlog::scoped!("lsp_format");
2359 zlog::debug!(logger => "Formatting via LSP");
2360
2361 let uri = file_path_to_lsp_url(abs_path)?;
2362 let text_document = lsp::TextDocumentIdentifier::new(uri);
2363 let capabilities = &language_server.capabilities();
2364
2365 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2366 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2367
2368 let request_timeout = cx.update(|app| {
2369 ProjectSettings::get_global(app)
2370 .global_lsp_settings
2371 .get_request_timeout()
2372 });
2373
2374 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2375 let _timer = zlog::time!(logger => "format-full");
2376 language_server
2377 .request::<lsp::request::Formatting>(
2378 lsp::DocumentFormattingParams {
2379 text_document,
2380 options: lsp_command::lsp_formatting_options(settings),
2381 work_done_progress_params: Default::default(),
2382 },
2383 request_timeout,
2384 )
2385 .await
2386 .into_response()?
2387 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2388 let _timer = zlog::time!(logger => "format-range");
2389 let buffer_start = lsp::Position::new(0, 0);
2390 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2391 language_server
2392 .request::<lsp::request::RangeFormatting>(
2393 lsp::DocumentRangeFormattingParams {
2394 text_document: text_document.clone(),
2395 range: lsp::Range::new(buffer_start, buffer_end),
2396 options: lsp_command::lsp_formatting_options(settings),
2397 work_done_progress_params: Default::default(),
2398 },
2399 request_timeout,
2400 )
2401 .await
2402 .into_response()?
2403 } else {
2404 None
2405 };
2406
2407 if let Some(lsp_edits) = lsp_edits {
2408 this.update(cx, |this, cx| {
2409 this.as_local_mut().unwrap().edits_from_lsp(
2410 buffer,
2411 lsp_edits,
2412 language_server.server_id(),
2413 None,
2414 cx,
2415 )
2416 })?
2417 .await
2418 } else {
2419 Ok(Vec::with_capacity(0))
2420 }
2421 }
2422
2423 async fn format_via_external_command(
2424 buffer: &FormattableBuffer,
2425 command: &str,
2426 arguments: Option<&[String]>,
2427 cx: &mut AsyncApp,
2428 ) -> Result<Option<Diff>> {
2429 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2430 let file = File::from_dyn(buffer.file())?;
2431 let worktree = file.worktree.read(cx);
2432 let mut worktree_path = worktree.abs_path().to_path_buf();
2433 if worktree.root_entry()?.is_file() {
2434 worktree_path.pop();
2435 }
2436 Some(worktree_path)
2437 });
2438
2439 use util::command::Stdio;
2440 let mut child = util::command::new_command(command);
2441
2442 if let Some(buffer_env) = buffer.env.as_ref() {
2443 child.envs(buffer_env);
2444 }
2445
2446 if let Some(working_dir_path) = working_dir_path {
2447 child.current_dir(working_dir_path);
2448 }
2449
2450 if let Some(arguments) = arguments {
2451 child.args(arguments.iter().map(|arg| {
2452 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2453 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2454 } else {
2455 arg.replace("{buffer_path}", "Untitled")
2456 }
2457 }));
2458 }
2459
2460 let mut child = child
2461 .stdin(Stdio::piped())
2462 .stdout(Stdio::piped())
2463 .stderr(Stdio::piped())
2464 .spawn()?;
2465
2466 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2467 let text = buffer
2468 .handle
2469 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2470 for chunk in text.chunks() {
2471 stdin.write_all(chunk.as_bytes()).await?;
2472 }
2473 stdin.flush().await?;
2474
2475 let output = child.output().await?;
2476 anyhow::ensure!(
2477 output.status.success(),
2478 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2479 output.status.code(),
2480 String::from_utf8_lossy(&output.stdout),
2481 String::from_utf8_lossy(&output.stderr),
2482 );
2483
2484 let stdout = String::from_utf8(output.stdout)?;
2485 Ok(Some(
2486 buffer
2487 .handle
2488 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2489 .await,
2490 ))
2491 }
2492
2493 async fn try_resolve_code_action(
2494 lang_server: &LanguageServer,
2495 action: &mut CodeAction,
2496 request_timeout: Duration,
2497 ) -> anyhow::Result<()> {
2498 match &mut action.lsp_action {
2499 LspAction::Action(lsp_action) => {
2500 if !action.resolved
2501 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2502 && lsp_action.data.is_some()
2503 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2504 {
2505 **lsp_action = lang_server
2506 .request::<lsp::request::CodeActionResolveRequest>(
2507 *lsp_action.clone(),
2508 request_timeout,
2509 )
2510 .await
2511 .into_response()?;
2512 }
2513 }
2514 LspAction::CodeLens(lens) => {
2515 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2516 *lens = lang_server
2517 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2518 .await
2519 .into_response()?;
2520 }
2521 }
2522 LspAction::Command(_) => {}
2523 }
2524
2525 action.resolved = true;
2526 anyhow::Ok(())
2527 }
2528
2529 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2530 let buffer = buffer_handle.read(cx);
2531
2532 let file = buffer.file().cloned();
2533
2534 let Some(file) = File::from_dyn(file.as_ref()) else {
2535 return;
2536 };
2537 if !file.is_local() {
2538 return;
2539 }
2540 let path = ProjectPath::from_file(file, cx);
2541 let worktree_id = file.worktree_id(cx);
2542 let language = buffer.language().cloned();
2543
2544 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2545 for (server_id, diagnostics) in
2546 diagnostics.get(file.path()).cloned().unwrap_or_default()
2547 {
2548 self.update_buffer_diagnostics(
2549 buffer_handle,
2550 server_id,
2551 None,
2552 None,
2553 None,
2554 Vec::new(),
2555 diagnostics,
2556 cx,
2557 )
2558 .log_err();
2559 }
2560 }
2561 let Some(language) = language else {
2562 return;
2563 };
2564 let Some(snapshot) = self
2565 .worktree_store
2566 .read(cx)
2567 .worktree_for_id(worktree_id, cx)
2568 .map(|worktree| worktree.read(cx).snapshot())
2569 else {
2570 return;
2571 };
2572 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2573
2574 for server_id in
2575 self.lsp_tree
2576 .get(path, language.name(), language.manifest(), &delegate, cx)
2577 {
2578 let server = self
2579 .language_servers
2580 .get(&server_id)
2581 .and_then(|server_state| {
2582 if let LanguageServerState::Running { server, .. } = server_state {
2583 Some(server.clone())
2584 } else {
2585 None
2586 }
2587 });
2588 let server = match server {
2589 Some(server) => server,
2590 None => continue,
2591 };
2592
2593 buffer_handle.update(cx, |buffer, cx| {
2594 buffer.set_completion_triggers(
2595 server.server_id(),
2596 server
2597 .capabilities()
2598 .completion_provider
2599 .as_ref()
2600 .and_then(|provider| {
2601 provider
2602 .trigger_characters
2603 .as_ref()
2604 .map(|characters| characters.iter().cloned().collect())
2605 })
2606 .unwrap_or_default(),
2607 cx,
2608 );
2609 });
2610 }
2611 }
2612
2613 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2614 buffer.update(cx, |buffer, cx| {
2615 let Some(language) = buffer.language() else {
2616 return;
2617 };
2618 let path = ProjectPath {
2619 worktree_id: old_file.worktree_id(cx),
2620 path: old_file.path.clone(),
2621 };
2622 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2623 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2624 buffer.set_completion_triggers(server_id, Default::default(), cx);
2625 }
2626 });
2627 }
2628
2629 fn update_buffer_diagnostics(
2630 &mut self,
2631 buffer: &Entity<Buffer>,
2632 server_id: LanguageServerId,
2633 registration_id: Option<Option<SharedString>>,
2634 result_id: Option<SharedString>,
2635 version: Option<i32>,
2636 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2637 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2638 cx: &mut Context<LspStore>,
2639 ) -> Result<()> {
2640 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2641 Ordering::Equal
2642 .then_with(|| b.is_primary.cmp(&a.is_primary))
2643 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2644 .then_with(|| a.severity.cmp(&b.severity))
2645 .then_with(|| a.message.cmp(&b.message))
2646 }
2647
2648 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2649 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2650 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2651
2652 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2653 Ordering::Equal
2654 .then_with(|| a.range.start.cmp(&b.range.start))
2655 .then_with(|| b.range.end.cmp(&a.range.end))
2656 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2657 });
2658
2659 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2660
2661 let edits_since_save = std::cell::LazyCell::new(|| {
2662 let saved_version = buffer.read(cx).saved_version();
2663 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2664 });
2665
2666 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2667
2668 for (new_diagnostic, entry) in diagnostics {
2669 let start;
2670 let end;
2671 if new_diagnostic && entry.diagnostic.is_disk_based {
2672 // Some diagnostics are based on files on disk instead of buffers'
2673 // current contents. Adjust these diagnostics' ranges to reflect
2674 // any unsaved edits.
2675 // Do not alter the reused ones though, as their coordinates were stored as anchors
2676 // and were properly adjusted on reuse.
2677 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2678 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2679 } else {
2680 start = entry.range.start;
2681 end = entry.range.end;
2682 }
2683
2684 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2685 ..snapshot.clip_point_utf16(end, Bias::Right);
2686
2687 // Expand empty ranges by one codepoint
2688 if range.start == range.end {
2689 // This will be go to the next boundary when being clipped
2690 range.end.column += 1;
2691 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2692 if range.start == range.end && range.end.column > 0 {
2693 range.start.column -= 1;
2694 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2695 }
2696 }
2697
2698 sanitized_diagnostics.push(DiagnosticEntry {
2699 range,
2700 diagnostic: entry.diagnostic,
2701 });
2702 }
2703 drop(edits_since_save);
2704
2705 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2706 buffer.update(cx, |buffer, cx| {
2707 if let Some(registration_id) = registration_id {
2708 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2709 self.buffer_pull_diagnostics_result_ids
2710 .entry(server_id)
2711 .or_default()
2712 .entry(registration_id)
2713 .or_default()
2714 .insert(abs_path, result_id);
2715 }
2716 }
2717
2718 buffer.update_diagnostics(server_id, set, cx)
2719 });
2720
2721 Ok(())
2722 }
2723
2724 fn register_language_server_for_invisible_worktree(
2725 &mut self,
2726 worktree: &Entity<Worktree>,
2727 language_server_id: LanguageServerId,
2728 cx: &mut App,
2729 ) {
2730 let worktree = worktree.read(cx);
2731 let worktree_id = worktree.id();
2732 debug_assert!(!worktree.is_visible());
2733 let Some(mut origin_seed) = self
2734 .language_server_ids
2735 .iter()
2736 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2737 else {
2738 return;
2739 };
2740 origin_seed.worktree_id = worktree_id;
2741 self.language_server_ids
2742 .entry(origin_seed)
2743 .or_insert_with(|| UnifiedLanguageServer {
2744 id: language_server_id,
2745 project_roots: Default::default(),
2746 });
2747 }
2748
2749 fn register_buffer_with_language_servers(
2750 &mut self,
2751 buffer_handle: &Entity<Buffer>,
2752 only_register_servers: HashSet<LanguageServerSelector>,
2753 cx: &mut Context<LspStore>,
2754 ) {
2755 if self.all_language_servers_stopped {
2756 return;
2757 }
2758 let buffer = buffer_handle.read(cx);
2759 let buffer_id = buffer.remote_id();
2760
2761 let Some(file) = File::from_dyn(buffer.file()) else {
2762 return;
2763 };
2764 if !file.is_local() {
2765 return;
2766 }
2767
2768 let abs_path = file.abs_path(cx);
2769 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2770 return;
2771 };
2772 let initial_snapshot = buffer.text_snapshot();
2773 let worktree_id = file.worktree_id(cx);
2774
2775 let Some(language) = buffer.language().cloned() else {
2776 return;
2777 };
2778 let path: Arc<RelPath> = file
2779 .path()
2780 .parent()
2781 .map(Arc::from)
2782 .unwrap_or_else(|| file.path().clone());
2783 let Some(worktree) = self
2784 .worktree_store
2785 .read(cx)
2786 .worktree_for_id(worktree_id, cx)
2787 else {
2788 return;
2789 };
2790 let language_name = language.name();
2791 let (reused, delegate, servers) = self
2792 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2793 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2794 .unwrap_or_else(|| {
2795 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2796 let delegate: Arc<dyn ManifestDelegate> =
2797 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2798
2799 let servers = self
2800 .lsp_tree
2801 .walk(
2802 ProjectPath { worktree_id, path },
2803 language.name(),
2804 language.manifest(),
2805 &delegate,
2806 cx,
2807 )
2808 .collect::<Vec<_>>();
2809 (false, lsp_delegate, servers)
2810 });
2811 let servers_and_adapters = servers
2812 .into_iter()
2813 .filter_map(|server_node| {
2814 if reused && server_node.server_id().is_none() {
2815 return None;
2816 }
2817 if let Some(name) = server_node.name()
2818 && self.stopped_language_servers.contains(&name)
2819 {
2820 return None;
2821 }
2822 if !only_register_servers.is_empty() {
2823 if let Some(server_id) = server_node.server_id()
2824 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2825 {
2826 return None;
2827 }
2828 if let Some(name) = server_node.name()
2829 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2830 {
2831 return None;
2832 }
2833 }
2834
2835 let server_id = server_node.server_id_or_init(|disposition| {
2836 let path = &disposition.path;
2837
2838 {
2839 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2840
2841 let server_id = self.get_or_insert_language_server(
2842 &worktree,
2843 delegate.clone(),
2844 disposition,
2845 &language_name,
2846 cx,
2847 );
2848
2849 if let Some(state) = self.language_servers.get(&server_id)
2850 && let Ok(uri) = uri
2851 {
2852 state.add_workspace_folder(uri);
2853 };
2854 server_id
2855 }
2856 })?;
2857 let server_state = self.language_servers.get(&server_id)?;
2858 if let LanguageServerState::Running {
2859 server, adapter, ..
2860 } = server_state
2861 {
2862 Some((server.clone(), adapter.clone()))
2863 } else {
2864 None
2865 }
2866 })
2867 .collect::<Vec<_>>();
2868 for (server, adapter) in servers_and_adapters {
2869 buffer_handle.update(cx, |buffer, cx| {
2870 buffer.set_completion_triggers(
2871 server.server_id(),
2872 server
2873 .capabilities()
2874 .completion_provider
2875 .as_ref()
2876 .and_then(|provider| {
2877 provider
2878 .trigger_characters
2879 .as_ref()
2880 .map(|characters| characters.iter().cloned().collect())
2881 })
2882 .unwrap_or_default(),
2883 cx,
2884 );
2885 });
2886
2887 let snapshot = LspBufferSnapshot {
2888 version: 0,
2889 snapshot: initial_snapshot.clone(),
2890 };
2891
2892 let mut registered = false;
2893 self.buffer_snapshots
2894 .entry(buffer_id)
2895 .or_default()
2896 .entry(server.server_id())
2897 .or_insert_with(|| {
2898 registered = true;
2899 server.register_buffer(
2900 uri.clone(),
2901 adapter.language_id(&language.name()),
2902 0,
2903 initial_snapshot.text(),
2904 );
2905
2906 vec![snapshot]
2907 });
2908
2909 self.buffers_opened_in_servers
2910 .entry(buffer_id)
2911 .or_default()
2912 .insert(server.server_id());
2913 if registered {
2914 cx.emit(LspStoreEvent::LanguageServerUpdate {
2915 language_server_id: server.server_id(),
2916 name: None,
2917 message: proto::update_language_server::Variant::RegisteredForBuffer(
2918 proto::RegisteredForBuffer {
2919 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2920 buffer_id: buffer_id.to_proto(),
2921 },
2922 ),
2923 });
2924 }
2925 }
2926 }
2927
2928 fn reuse_existing_language_server<'lang_name>(
2929 &self,
2930 server_tree: &LanguageServerTree,
2931 worktree: &Entity<Worktree>,
2932 language_name: &'lang_name LanguageName,
2933 cx: &mut App,
2934 ) -> Option<(
2935 Arc<LocalLspAdapterDelegate>,
2936 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2937 )> {
2938 if worktree.read(cx).is_visible() {
2939 return None;
2940 }
2941
2942 let worktree_store = self.worktree_store.read(cx);
2943 let servers = server_tree
2944 .instances
2945 .iter()
2946 .filter(|(worktree_id, _)| {
2947 worktree_store
2948 .worktree_for_id(**worktree_id, cx)
2949 .is_some_and(|worktree| worktree.read(cx).is_visible())
2950 })
2951 .flat_map(|(worktree_id, servers)| {
2952 servers
2953 .roots
2954 .iter()
2955 .flat_map(|(_, language_servers)| language_servers)
2956 .map(move |(_, (server_node, server_languages))| {
2957 (worktree_id, server_node, server_languages)
2958 })
2959 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2960 .map(|(worktree_id, server_node, _)| {
2961 (
2962 *worktree_id,
2963 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2964 )
2965 })
2966 })
2967 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2968 acc.entry(worktree_id)
2969 .or_insert_with(Vec::new)
2970 .push(server_node);
2971 acc
2972 })
2973 .into_values()
2974 .max_by_key(|servers| servers.len())?;
2975
2976 let worktree_id = worktree.read(cx).id();
2977 let apply = move |tree: &mut LanguageServerTree| {
2978 for server_node in &servers {
2979 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2980 }
2981 servers
2982 };
2983
2984 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2985 Some((delegate, apply))
2986 }
2987
2988 pub(crate) fn unregister_old_buffer_from_language_servers(
2989 &mut self,
2990 buffer: &Entity<Buffer>,
2991 old_file: &File,
2992 cx: &mut App,
2993 ) {
2994 let old_path = match old_file.as_local() {
2995 Some(local) => local.abs_path(cx),
2996 None => return,
2997 };
2998
2999 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
3000 debug_panic!("{old_path:?} is not parseable as an URI");
3001 return;
3002 };
3003 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
3004 }
3005
3006 pub(crate) fn unregister_buffer_from_language_servers(
3007 &mut self,
3008 buffer: &Entity<Buffer>,
3009 file_url: &lsp::Uri,
3010 cx: &mut App,
3011 ) {
3012 buffer.update(cx, |buffer, cx| {
3013 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
3014
3015 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
3016 if snapshots
3017 .as_mut()
3018 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
3019 {
3020 language_server.unregister_buffer(file_url.clone());
3021 }
3022 }
3023 });
3024 }
3025
3026 fn buffer_snapshot_for_lsp_version(
3027 &mut self,
3028 buffer: &Entity<Buffer>,
3029 server_id: LanguageServerId,
3030 version: Option<i32>,
3031 cx: &App,
3032 ) -> Result<TextBufferSnapshot> {
3033 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
3034
3035 if let Some(version) = version {
3036 let buffer_id = buffer.read(cx).remote_id();
3037 let snapshots = if let Some(snapshots) = self
3038 .buffer_snapshots
3039 .get_mut(&buffer_id)
3040 .and_then(|m| m.get_mut(&server_id))
3041 {
3042 snapshots
3043 } else if version == 0 {
3044 // Some language servers report version 0 even if the buffer hasn't been opened yet.
3045 // We detect this case and treat it as if the version was `None`.
3046 return Ok(buffer.read(cx).text_snapshot());
3047 } else {
3048 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
3049 };
3050
3051 let found_snapshot = snapshots
3052 .binary_search_by_key(&version, |e| e.version)
3053 .map(|ix| snapshots[ix].snapshot.clone())
3054 .map_err(|_| {
3055 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
3056 })?;
3057
3058 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3059 Ok(found_snapshot)
3060 } else {
3061 Ok((buffer.read(cx)).text_snapshot())
3062 }
3063 }
3064
3065 async fn get_server_code_actions_from_action_kinds(
3066 lsp_store: &WeakEntity<LspStore>,
3067 language_server_id: LanguageServerId,
3068 code_action_kinds: Vec<lsp::CodeActionKind>,
3069 buffer: &Entity<Buffer>,
3070 cx: &mut AsyncApp,
3071 ) -> Result<Vec<CodeAction>> {
3072 let actions = lsp_store
3073 .update(cx, move |this, cx| {
3074 let request = GetCodeActions {
3075 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3076 kinds: Some(code_action_kinds),
3077 };
3078 let server = LanguageServerToQuery::Other(language_server_id);
3079 this.request_lsp(buffer.clone(), server, request, cx)
3080 })?
3081 .await?;
3082 Ok(actions)
3083 }
3084
3085 pub async fn execute_code_actions_on_server(
3086 lsp_store: &WeakEntity<LspStore>,
3087 language_server: &Arc<LanguageServer>,
3088 actions: Vec<CodeAction>,
3089 push_to_history: bool,
3090 project_transaction: &mut ProjectTransaction,
3091 cx: &mut AsyncApp,
3092 ) -> anyhow::Result<()> {
3093 let request_timeout = cx.update(|app| {
3094 ProjectSettings::get_global(app)
3095 .global_lsp_settings
3096 .get_request_timeout()
3097 });
3098
3099 for mut action in actions {
3100 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3101 .await
3102 .context("resolving a formatting code action")?;
3103
3104 if let Some(edit) = action.lsp_action.edit() {
3105 if edit.changes.is_none() && edit.document_changes.is_none() {
3106 continue;
3107 }
3108
3109 let new = Self::deserialize_workspace_edit(
3110 lsp_store.upgrade().context("project dropped")?,
3111 edit.clone(),
3112 push_to_history,
3113 language_server.clone(),
3114 cx,
3115 )
3116 .await?;
3117 project_transaction.0.extend(new.0);
3118 }
3119
3120 let Some(command) = action.lsp_action.command() else {
3121 continue;
3122 };
3123
3124 let server_capabilities = language_server.capabilities();
3125 let available_commands = server_capabilities
3126 .execute_command_provider
3127 .as_ref()
3128 .map(|options| options.commands.as_slice())
3129 .unwrap_or_default();
3130 if !available_commands.contains(&command.command) {
3131 log::warn!(
3132 "Cannot execute a command {} not listed in the language server capabilities",
3133 command.command
3134 );
3135 continue;
3136 }
3137
3138 lsp_store.update(cx, |lsp_store, _| {
3139 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3140 mode.last_workspace_edits_by_language_server
3141 .remove(&language_server.server_id());
3142 }
3143 })?;
3144
3145 language_server
3146 .request::<lsp::request::ExecuteCommand>(
3147 lsp::ExecuteCommandParams {
3148 command: command.command.clone(),
3149 arguments: command.arguments.clone().unwrap_or_default(),
3150 ..Default::default()
3151 },
3152 request_timeout,
3153 )
3154 .await
3155 .into_response()
3156 .context("execute command")?;
3157
3158 lsp_store.update(cx, |this, _| {
3159 if let LspStoreMode::Local(mode) = &mut this.mode {
3160 project_transaction.0.extend(
3161 mode.last_workspace_edits_by_language_server
3162 .remove(&language_server.server_id())
3163 .unwrap_or_default()
3164 .0,
3165 )
3166 }
3167 })?;
3168 }
3169 Ok(())
3170 }
3171
3172 pub async fn deserialize_text_edits(
3173 this: Entity<LspStore>,
3174 buffer_to_edit: Entity<Buffer>,
3175 edits: Vec<lsp::TextEdit>,
3176 push_to_history: bool,
3177 _: Arc<CachedLspAdapter>,
3178 language_server: Arc<LanguageServer>,
3179 cx: &mut AsyncApp,
3180 ) -> Result<Option<Transaction>> {
3181 let edits = this
3182 .update(cx, |this, cx| {
3183 this.as_local_mut().unwrap().edits_from_lsp(
3184 &buffer_to_edit,
3185 edits,
3186 language_server.server_id(),
3187 None,
3188 cx,
3189 )
3190 })
3191 .await?;
3192
3193 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3194 buffer.finalize_last_transaction();
3195 buffer.start_transaction();
3196 for (range, text) in edits {
3197 buffer.edit([(range, text)], None, cx);
3198 }
3199
3200 if buffer.end_transaction(cx).is_some() {
3201 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3202 if !push_to_history {
3203 buffer.forget_transaction(transaction.id);
3204 }
3205 Some(transaction)
3206 } else {
3207 None
3208 }
3209 });
3210
3211 Ok(transaction)
3212 }
3213
3214 #[allow(clippy::type_complexity)]
3215 pub fn edits_from_lsp(
3216 &mut self,
3217 buffer: &Entity<Buffer>,
3218 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3219 server_id: LanguageServerId,
3220 version: Option<i32>,
3221 cx: &mut Context<LspStore>,
3222 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3223 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3224 cx.background_spawn(async move {
3225 let snapshot = snapshot?;
3226 let mut lsp_edits = lsp_edits
3227 .into_iter()
3228 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3229 .collect::<Vec<_>>();
3230
3231 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3232
3233 let mut lsp_edits = lsp_edits.into_iter().peekable();
3234 let mut edits = Vec::new();
3235 while let Some((range, mut new_text)) = lsp_edits.next() {
3236 // Clip invalid ranges provided by the language server.
3237 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3238 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3239
3240 // Combine any LSP edits that are adjacent.
3241 //
3242 // Also, combine LSP edits that are separated from each other by only
3243 // a newline. This is important because for some code actions,
3244 // Rust-analyzer rewrites the entire buffer via a series of edits that
3245 // are separated by unchanged newline characters.
3246 //
3247 // In order for the diffing logic below to work properly, any edits that
3248 // cancel each other out must be combined into one.
3249 while let Some((next_range, next_text)) = lsp_edits.peek() {
3250 if next_range.start.0 > range.end {
3251 if next_range.start.0.row > range.end.row + 1
3252 || next_range.start.0.column > 0
3253 || snapshot.clip_point_utf16(
3254 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3255 Bias::Left,
3256 ) > range.end
3257 {
3258 break;
3259 }
3260 new_text.push('\n');
3261 }
3262 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3263 new_text.push_str(next_text);
3264 lsp_edits.next();
3265 }
3266
3267 // For multiline edits, perform a diff of the old and new text so that
3268 // we can identify the changes more precisely, preserving the locations
3269 // of any anchors positioned in the unchanged regions.
3270 if range.end.row > range.start.row {
3271 let offset = range.start.to_offset(&snapshot);
3272 let old_text = snapshot.text_for_range(range).collect::<String>();
3273 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3274 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3275 (
3276 snapshot.anchor_after(offset + range.start)
3277 ..snapshot.anchor_before(offset + range.end),
3278 replacement,
3279 )
3280 }));
3281 } else if range.end == range.start {
3282 let anchor = snapshot.anchor_after(range.start);
3283 edits.push((anchor..anchor, new_text.into()));
3284 } else {
3285 let edit_start = snapshot.anchor_after(range.start);
3286 let edit_end = snapshot.anchor_before(range.end);
3287 edits.push((edit_start..edit_end, new_text.into()));
3288 }
3289 }
3290
3291 Ok(edits)
3292 })
3293 }
3294
3295 pub(crate) async fn deserialize_workspace_edit(
3296 this: Entity<LspStore>,
3297 edit: lsp::WorkspaceEdit,
3298 push_to_history: bool,
3299 language_server: Arc<LanguageServer>,
3300 cx: &mut AsyncApp,
3301 ) -> Result<ProjectTransaction> {
3302 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3303
3304 let mut operations = Vec::new();
3305 if let Some(document_changes) = edit.document_changes {
3306 match document_changes {
3307 lsp::DocumentChanges::Edits(edits) => {
3308 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3309 }
3310 lsp::DocumentChanges::Operations(ops) => operations = ops,
3311 }
3312 } else if let Some(changes) = edit.changes {
3313 operations.extend(changes.into_iter().map(|(uri, edits)| {
3314 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3315 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3316 uri,
3317 version: None,
3318 },
3319 edits: edits.into_iter().map(Edit::Plain).collect(),
3320 })
3321 }));
3322 }
3323
3324 let mut project_transaction = ProjectTransaction::default();
3325 for operation in operations {
3326 match operation {
3327 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3328 let abs_path = op
3329 .uri
3330 .to_file_path()
3331 .map_err(|()| anyhow!("can't convert URI to path"))?;
3332
3333 if let Some(parent_path) = abs_path.parent() {
3334 fs.create_dir(parent_path).await?;
3335 }
3336 if abs_path.ends_with("/") {
3337 fs.create_dir(&abs_path).await?;
3338 } else {
3339 fs.create_file(
3340 &abs_path,
3341 op.options
3342 .map(|options| fs::CreateOptions {
3343 overwrite: options.overwrite.unwrap_or(false),
3344 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3345 })
3346 .unwrap_or_default(),
3347 )
3348 .await?;
3349 }
3350 }
3351
3352 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3353 let source_abs_path = op
3354 .old_uri
3355 .to_file_path()
3356 .map_err(|()| anyhow!("can't convert URI to path"))?;
3357 let target_abs_path = op
3358 .new_uri
3359 .to_file_path()
3360 .map_err(|()| anyhow!("can't convert URI to path"))?;
3361
3362 let options = fs::RenameOptions {
3363 overwrite: op
3364 .options
3365 .as_ref()
3366 .and_then(|options| options.overwrite)
3367 .unwrap_or(false),
3368 ignore_if_exists: op
3369 .options
3370 .as_ref()
3371 .and_then(|options| options.ignore_if_exists)
3372 .unwrap_or(false),
3373 create_parents: true,
3374 };
3375
3376 fs.rename(&source_abs_path, &target_abs_path, options)
3377 .await?;
3378 }
3379
3380 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3381 let abs_path = op
3382 .uri
3383 .to_file_path()
3384 .map_err(|()| anyhow!("can't convert URI to path"))?;
3385 let options = op
3386 .options
3387 .map(|options| fs::RemoveOptions {
3388 recursive: options.recursive.unwrap_or(false),
3389 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3390 })
3391 .unwrap_or_default();
3392 if abs_path.ends_with("/") {
3393 fs.remove_dir(&abs_path, options).await?;
3394 } else {
3395 fs.remove_file(&abs_path, options).await?;
3396 }
3397 }
3398
3399 lsp::DocumentChangeOperation::Edit(op) => {
3400 let buffer_to_edit = this
3401 .update(cx, |this, cx| {
3402 this.open_local_buffer_via_lsp(
3403 op.text_document.uri.clone(),
3404 language_server.server_id(),
3405 cx,
3406 )
3407 })
3408 .await?;
3409
3410 let edits = this
3411 .update(cx, |this, cx| {
3412 let path = buffer_to_edit.read(cx).project_path(cx);
3413 let active_entry = this.active_entry;
3414 let is_active_entry = path.is_some_and(|project_path| {
3415 this.worktree_store
3416 .read(cx)
3417 .entry_for_path(&project_path, cx)
3418 .is_some_and(|entry| Some(entry.id) == active_entry)
3419 });
3420 let local = this.as_local_mut().unwrap();
3421
3422 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3423 for edit in op.edits {
3424 match edit {
3425 Edit::Plain(edit) => {
3426 if !edits.contains(&edit) {
3427 edits.push(edit)
3428 }
3429 }
3430 Edit::Annotated(edit) => {
3431 if !edits.contains(&edit.text_edit) {
3432 edits.push(edit.text_edit)
3433 }
3434 }
3435 Edit::Snippet(edit) => {
3436 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3437 else {
3438 continue;
3439 };
3440
3441 if is_active_entry {
3442 snippet_edits.push((edit.range, snippet));
3443 } else {
3444 // Since this buffer is not focused, apply a normal edit.
3445 let new_edit = TextEdit {
3446 range: edit.range,
3447 new_text: snippet.text,
3448 };
3449 if !edits.contains(&new_edit) {
3450 edits.push(new_edit);
3451 }
3452 }
3453 }
3454 }
3455 }
3456 if !snippet_edits.is_empty() {
3457 let buffer_id = buffer_to_edit.read(cx).remote_id();
3458 let version = if let Some(buffer_version) = op.text_document.version
3459 {
3460 local
3461 .buffer_snapshot_for_lsp_version(
3462 &buffer_to_edit,
3463 language_server.server_id(),
3464 Some(buffer_version),
3465 cx,
3466 )
3467 .ok()
3468 .map(|snapshot| snapshot.version)
3469 } else {
3470 Some(buffer_to_edit.read(cx).saved_version().clone())
3471 };
3472
3473 let most_recent_edit =
3474 version.and_then(|version| version.most_recent());
3475 // Check if the edit that triggered that edit has been made by this participant.
3476
3477 if let Some(most_recent_edit) = most_recent_edit {
3478 cx.emit(LspStoreEvent::SnippetEdit {
3479 buffer_id,
3480 edits: snippet_edits,
3481 most_recent_edit,
3482 });
3483 }
3484 }
3485
3486 local.edits_from_lsp(
3487 &buffer_to_edit,
3488 edits,
3489 language_server.server_id(),
3490 op.text_document.version,
3491 cx,
3492 )
3493 })
3494 .await?;
3495
3496 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3497 buffer.finalize_last_transaction();
3498 buffer.start_transaction();
3499 for (range, text) in edits {
3500 buffer.edit([(range, text)], None, cx);
3501 }
3502
3503 buffer.end_transaction(cx).and_then(|transaction_id| {
3504 if push_to_history {
3505 buffer.finalize_last_transaction();
3506 buffer.get_transaction(transaction_id).cloned()
3507 } else {
3508 buffer.forget_transaction(transaction_id)
3509 }
3510 })
3511 });
3512 if let Some(transaction) = transaction {
3513 project_transaction.0.insert(buffer_to_edit, transaction);
3514 }
3515 }
3516 }
3517 }
3518
3519 Ok(project_transaction)
3520 }
3521
3522 async fn on_lsp_workspace_edit(
3523 this: WeakEntity<LspStore>,
3524 params: lsp::ApplyWorkspaceEditParams,
3525 server_id: LanguageServerId,
3526 cx: &mut AsyncApp,
3527 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3528 let this = this.upgrade().context("project project closed")?;
3529 let language_server = this
3530 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3531 .context("language server not found")?;
3532 let transaction = Self::deserialize_workspace_edit(
3533 this.clone(),
3534 params.edit,
3535 true,
3536 language_server.clone(),
3537 cx,
3538 )
3539 .await
3540 .log_err();
3541 this.update(cx, |this, cx| {
3542 if let Some(transaction) = transaction {
3543 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3544
3545 this.as_local_mut()
3546 .unwrap()
3547 .last_workspace_edits_by_language_server
3548 .insert(server_id, transaction);
3549 }
3550 });
3551 Ok(lsp::ApplyWorkspaceEditResponse {
3552 applied: true,
3553 failed_change: None,
3554 failure_reason: None,
3555 })
3556 }
3557
3558 fn remove_worktree(
3559 &mut self,
3560 id_to_remove: WorktreeId,
3561 cx: &mut Context<LspStore>,
3562 ) -> Vec<LanguageServerId> {
3563 self.restricted_worktrees_tasks.remove(&id_to_remove);
3564 self.diagnostics.remove(&id_to_remove);
3565 self.prettier_store.update(cx, |prettier_store, cx| {
3566 prettier_store.remove_worktree(id_to_remove, cx);
3567 });
3568
3569 let mut servers_to_remove = BTreeSet::default();
3570 let mut servers_to_preserve = HashSet::default();
3571 for (seed, state) in &self.language_server_ids {
3572 if seed.worktree_id == id_to_remove {
3573 servers_to_remove.insert(state.id);
3574 } else {
3575 servers_to_preserve.insert(state.id);
3576 }
3577 }
3578 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3579 self.language_server_ids
3580 .retain(|_, state| !servers_to_remove.contains(&state.id));
3581 for server_id_to_remove in &servers_to_remove {
3582 self.language_server_watched_paths
3583 .remove(server_id_to_remove);
3584 self.language_server_paths_watched_for_rename
3585 .remove(server_id_to_remove);
3586 self.last_workspace_edits_by_language_server
3587 .remove(server_id_to_remove);
3588 self.language_servers.remove(server_id_to_remove);
3589 self.buffer_pull_diagnostics_result_ids
3590 .remove(server_id_to_remove);
3591 self.workspace_pull_diagnostics_result_ids
3592 .remove(server_id_to_remove);
3593 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3594 buffer_servers.remove(server_id_to_remove);
3595 }
3596 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3597 }
3598 servers_to_remove.into_iter().collect()
3599 }
3600
3601 fn rebuild_watched_paths_inner<'a>(
3602 &'a self,
3603 language_server_id: LanguageServerId,
3604 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3605 cx: &mut Context<LspStore>,
3606 ) -> LanguageServerWatchedPathsBuilder {
3607 let worktrees = self
3608 .worktree_store
3609 .read(cx)
3610 .worktrees()
3611 .filter_map(|worktree| {
3612 self.language_servers_for_worktree(worktree.read(cx).id())
3613 .find(|server| server.server_id() == language_server_id)
3614 .map(|_| worktree)
3615 })
3616 .collect::<Vec<_>>();
3617
3618 let mut worktree_globs = HashMap::default();
3619 let mut abs_globs = HashMap::default();
3620 log::trace!(
3621 "Processing new watcher paths for language server with id {}",
3622 language_server_id
3623 );
3624
3625 for watcher in watchers {
3626 if let Some((worktree, literal_prefix, pattern)) =
3627 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3628 {
3629 worktree.update(cx, |worktree, _| {
3630 if let Some((tree, glob)) =
3631 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3632 {
3633 tree.add_path_prefix_to_scan(literal_prefix);
3634 worktree_globs
3635 .entry(tree.id())
3636 .or_insert_with(GlobSetBuilder::new)
3637 .add(glob);
3638 }
3639 });
3640 } else {
3641 let (path, pattern) = match &watcher.glob_pattern {
3642 lsp::GlobPattern::String(s) => {
3643 let watcher_path = SanitizedPath::new(s);
3644 let path = glob_literal_prefix(watcher_path.as_path());
3645 let pattern = watcher_path
3646 .as_path()
3647 .strip_prefix(&path)
3648 .map(|p| p.to_string_lossy().into_owned())
3649 .unwrap_or_else(|e| {
3650 debug_panic!(
3651 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3652 s,
3653 path.display(),
3654 e
3655 );
3656 watcher_path.as_path().to_string_lossy().into_owned()
3657 });
3658 (path, pattern)
3659 }
3660 lsp::GlobPattern::Relative(rp) => {
3661 let Ok(mut base_uri) = match &rp.base_uri {
3662 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3663 lsp::OneOf::Right(base_uri) => base_uri,
3664 }
3665 .to_file_path() else {
3666 continue;
3667 };
3668
3669 let path = glob_literal_prefix(Path::new(&rp.pattern));
3670 let pattern = Path::new(&rp.pattern)
3671 .strip_prefix(&path)
3672 .map(|p| p.to_string_lossy().into_owned())
3673 .unwrap_or_else(|e| {
3674 debug_panic!(
3675 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3676 rp.pattern,
3677 path.display(),
3678 e
3679 );
3680 rp.pattern.clone()
3681 });
3682 base_uri.push(path);
3683 (base_uri, pattern)
3684 }
3685 };
3686
3687 if let Some(glob) = Glob::new(&pattern).log_err() {
3688 if !path
3689 .components()
3690 .any(|c| matches!(c, path::Component::Normal(_)))
3691 {
3692 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3693 // rather than adding a new watcher for `/`.
3694 for worktree in &worktrees {
3695 worktree_globs
3696 .entry(worktree.read(cx).id())
3697 .or_insert_with(GlobSetBuilder::new)
3698 .add(glob.clone());
3699 }
3700 } else {
3701 abs_globs
3702 .entry(path.into())
3703 .or_insert_with(GlobSetBuilder::new)
3704 .add(glob);
3705 }
3706 }
3707 }
3708 }
3709
3710 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3711 for (worktree_id, builder) in worktree_globs {
3712 if let Ok(globset) = builder.build() {
3713 watch_builder.watch_worktree(worktree_id, globset);
3714 }
3715 }
3716 for (abs_path, builder) in abs_globs {
3717 if let Ok(globset) = builder.build() {
3718 watch_builder.watch_abs_path(abs_path, globset);
3719 }
3720 }
3721 watch_builder
3722 }
3723
3724 fn worktree_and_path_for_file_watcher(
3725 worktrees: &[Entity<Worktree>],
3726 watcher: &FileSystemWatcher,
3727 cx: &App,
3728 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3729 worktrees.iter().find_map(|worktree| {
3730 let tree = worktree.read(cx);
3731 let worktree_root_path = tree.abs_path();
3732 let path_style = tree.path_style();
3733 match &watcher.glob_pattern {
3734 lsp::GlobPattern::String(s) => {
3735 let watcher_path = SanitizedPath::new(s);
3736 let relative = watcher_path
3737 .as_path()
3738 .strip_prefix(&worktree_root_path)
3739 .ok()?;
3740 let literal_prefix = glob_literal_prefix(relative);
3741 Some((
3742 worktree.clone(),
3743 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3744 relative.to_string_lossy().into_owned(),
3745 ))
3746 }
3747 lsp::GlobPattern::Relative(rp) => {
3748 let base_uri = match &rp.base_uri {
3749 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3750 lsp::OneOf::Right(base_uri) => base_uri,
3751 }
3752 .to_file_path()
3753 .ok()?;
3754 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3755 let mut literal_prefix = relative.to_owned();
3756 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3757 Some((
3758 worktree.clone(),
3759 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3760 rp.pattern.clone(),
3761 ))
3762 }
3763 }
3764 })
3765 }
3766
3767 fn rebuild_watched_paths(
3768 &mut self,
3769 language_server_id: LanguageServerId,
3770 cx: &mut Context<LspStore>,
3771 ) {
3772 let Some(registrations) = self
3773 .language_server_dynamic_registrations
3774 .get(&language_server_id)
3775 else {
3776 return;
3777 };
3778
3779 let watch_builder = self.rebuild_watched_paths_inner(
3780 language_server_id,
3781 registrations.did_change_watched_files.values().flatten(),
3782 cx,
3783 );
3784 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3785 self.language_server_watched_paths
3786 .insert(language_server_id, watcher);
3787
3788 cx.notify();
3789 }
3790
3791 fn on_lsp_did_change_watched_files(
3792 &mut self,
3793 language_server_id: LanguageServerId,
3794 registration_id: &str,
3795 params: DidChangeWatchedFilesRegistrationOptions,
3796 cx: &mut Context<LspStore>,
3797 ) {
3798 let registrations = self
3799 .language_server_dynamic_registrations
3800 .entry(language_server_id)
3801 .or_default();
3802
3803 registrations
3804 .did_change_watched_files
3805 .insert(registration_id.to_string(), params.watchers);
3806
3807 self.rebuild_watched_paths(language_server_id, cx);
3808 }
3809
3810 fn on_lsp_unregister_did_change_watched_files(
3811 &mut self,
3812 language_server_id: LanguageServerId,
3813 registration_id: &str,
3814 cx: &mut Context<LspStore>,
3815 ) {
3816 let registrations = self
3817 .language_server_dynamic_registrations
3818 .entry(language_server_id)
3819 .or_default();
3820
3821 if registrations
3822 .did_change_watched_files
3823 .remove(registration_id)
3824 .is_some()
3825 {
3826 log::info!(
3827 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3828 language_server_id,
3829 registration_id
3830 );
3831 } else {
3832 log::warn!(
3833 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3834 language_server_id,
3835 registration_id
3836 );
3837 }
3838
3839 self.rebuild_watched_paths(language_server_id, cx);
3840 }
3841
3842 async fn initialization_options_for_adapter(
3843 adapter: Arc<dyn LspAdapter>,
3844 delegate: &Arc<dyn LspAdapterDelegate>,
3845 cx: &mut AsyncApp,
3846 ) -> Result<Option<serde_json::Value>> {
3847 let Some(mut initialization_config) =
3848 adapter.clone().initialization_options(delegate, cx).await?
3849 else {
3850 return Ok(None);
3851 };
3852
3853 for other_adapter in delegate.registered_lsp_adapters() {
3854 if other_adapter.name() == adapter.name() {
3855 continue;
3856 }
3857 if let Ok(Some(target_config)) = other_adapter
3858 .clone()
3859 .additional_initialization_options(adapter.name(), delegate)
3860 .await
3861 {
3862 merge_json_value_into(target_config.clone(), &mut initialization_config);
3863 }
3864 }
3865
3866 Ok(Some(initialization_config))
3867 }
3868
3869 async fn workspace_configuration_for_adapter(
3870 adapter: Arc<dyn LspAdapter>,
3871 delegate: &Arc<dyn LspAdapterDelegate>,
3872 toolchain: Option<Toolchain>,
3873 requested_uri: Option<Uri>,
3874 cx: &mut AsyncApp,
3875 ) -> Result<serde_json::Value> {
3876 let mut workspace_config = adapter
3877 .clone()
3878 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3879 .await?;
3880
3881 for other_adapter in delegate.registered_lsp_adapters() {
3882 if other_adapter.name() == adapter.name() {
3883 continue;
3884 }
3885 if let Ok(Some(target_config)) = other_adapter
3886 .clone()
3887 .additional_workspace_configuration(adapter.name(), delegate, cx)
3888 .await
3889 {
3890 merge_json_value_into(target_config.clone(), &mut workspace_config);
3891 }
3892 }
3893
3894 Ok(workspace_config)
3895 }
3896
3897 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3898 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3899 Some(server.clone())
3900 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3901 Some(Arc::clone(server))
3902 } else {
3903 None
3904 }
3905 }
3906}
3907
3908fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3909 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3910 cx.emit(LspStoreEvent::LanguageServerUpdate {
3911 language_server_id: server.server_id(),
3912 name: Some(server.name()),
3913 message: proto::update_language_server::Variant::MetadataUpdated(
3914 proto::ServerMetadataUpdated {
3915 capabilities: Some(capabilities),
3916 binary: Some(proto::LanguageServerBinaryInfo {
3917 path: server.binary().path.to_string_lossy().into_owned(),
3918 arguments: server
3919 .binary()
3920 .arguments
3921 .iter()
3922 .map(|arg| arg.to_string_lossy().into_owned())
3923 .collect(),
3924 }),
3925 configuration: serde_json::to_string(server.configuration()).ok(),
3926 workspace_folders: server
3927 .workspace_folders()
3928 .iter()
3929 .map(|uri| uri.to_string())
3930 .collect(),
3931 },
3932 ),
3933 });
3934 }
3935}
3936
3937#[derive(Debug)]
3938pub struct FormattableBuffer {
3939 handle: Entity<Buffer>,
3940 abs_path: Option<PathBuf>,
3941 env: Option<HashMap<String, String>>,
3942 ranges: Option<Vec<Range<Anchor>>>,
3943}
3944
3945pub struct RemoteLspStore {
3946 upstream_client: Option<AnyProtoClient>,
3947 upstream_project_id: u64,
3948}
3949
3950pub(crate) enum LspStoreMode {
3951 Local(LocalLspStore), // ssh host and collab host
3952 Remote(RemoteLspStore), // collab guest
3953}
3954
3955impl LspStoreMode {
3956 fn is_local(&self) -> bool {
3957 matches!(self, LspStoreMode::Local(_))
3958 }
3959}
3960
3961pub struct LspStore {
3962 mode: LspStoreMode,
3963 last_formatting_failure: Option<String>,
3964 downstream_client: Option<(AnyProtoClient, u64)>,
3965 nonce: u128,
3966 buffer_store: Entity<BufferStore>,
3967 worktree_store: Entity<WorktreeStore>,
3968 pub languages: Arc<LanguageRegistry>,
3969 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3970 active_entry: Option<ProjectEntryId>,
3971 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3972 _maintain_buffer_languages: Task<()>,
3973 diagnostic_summaries:
3974 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3975 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3976 semantic_token_config: SemanticTokenConfig,
3977 lsp_data: HashMap<BufferId, BufferLspData>,
3978 buffer_reload_tasks: HashMap<BufferId, Task<anyhow::Result<()>>>,
3979 next_hint_id: Arc<AtomicUsize>,
3980}
3981
3982#[derive(Debug)]
3983pub struct BufferLspData {
3984 buffer_version: Global,
3985 document_colors: Option<DocumentColorData>,
3986 code_lens: Option<CodeLensData>,
3987 semantic_tokens: Option<SemanticTokensData>,
3988 folding_ranges: Option<FoldingRangeData>,
3989 document_symbols: Option<DocumentSymbolsData>,
3990 inlay_hints: BufferInlayHints,
3991 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3992 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3993}
3994
3995#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3996struct LspKey {
3997 request_type: TypeId,
3998 server_queried: Option<LanguageServerId>,
3999}
4000
4001impl BufferLspData {
4002 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
4003 Self {
4004 buffer_version: buffer.read(cx).version(),
4005 document_colors: None,
4006 code_lens: None,
4007 semantic_tokens: None,
4008 folding_ranges: None,
4009 document_symbols: None,
4010 inlay_hints: BufferInlayHints::new(buffer, cx),
4011 lsp_requests: HashMap::default(),
4012 chunk_lsp_requests: HashMap::default(),
4013 }
4014 }
4015
4016 fn remove_server_data(&mut self, for_server: LanguageServerId) {
4017 if let Some(document_colors) = &mut self.document_colors {
4018 document_colors.remove_server_data(for_server);
4019 }
4020
4021 if let Some(code_lens) = &mut self.code_lens {
4022 code_lens.remove_server_data(for_server);
4023 }
4024
4025 self.inlay_hints.remove_server_data(for_server);
4026
4027 if let Some(semantic_tokens) = &mut self.semantic_tokens {
4028 semantic_tokens.remove_server_data(for_server);
4029 }
4030
4031 if let Some(folding_ranges) = &mut self.folding_ranges {
4032 folding_ranges.ranges.remove(&for_server);
4033 }
4034
4035 if let Some(document_symbols) = &mut self.document_symbols {
4036 document_symbols.remove_server_data(for_server);
4037 }
4038 }
4039
4040 #[cfg(any(test, feature = "test-support"))]
4041 pub fn inlay_hints(&self) -> &BufferInlayHints {
4042 &self.inlay_hints
4043 }
4044}
4045
4046#[derive(Debug)]
4047pub enum LspStoreEvent {
4048 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
4049 LanguageServerRemoved(LanguageServerId),
4050 LanguageServerUpdate {
4051 language_server_id: LanguageServerId,
4052 name: Option<LanguageServerName>,
4053 message: proto::update_language_server::Variant,
4054 },
4055 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
4056 LanguageServerPrompt(LanguageServerPromptRequest),
4057 LanguageDetected {
4058 buffer: Entity<Buffer>,
4059 new_language: Option<Arc<Language>>,
4060 },
4061 Notification(String),
4062 RefreshInlayHints {
4063 server_id: LanguageServerId,
4064 request_id: Option<usize>,
4065 },
4066 RefreshSemanticTokens {
4067 server_id: LanguageServerId,
4068 request_id: Option<usize>,
4069 },
4070 RefreshCodeLens,
4071 DiagnosticsUpdated {
4072 server_id: LanguageServerId,
4073 paths: Vec<ProjectPath>,
4074 },
4075 DiskBasedDiagnosticsStarted {
4076 language_server_id: LanguageServerId,
4077 },
4078 DiskBasedDiagnosticsFinished {
4079 language_server_id: LanguageServerId,
4080 },
4081 SnippetEdit {
4082 buffer_id: BufferId,
4083 edits: Vec<(lsp::Range, Snippet)>,
4084 most_recent_edit: clock::Lamport,
4085 },
4086 WorkspaceEditApplied(ProjectTransaction),
4087}
4088
4089#[derive(Clone, Debug, Serialize)]
4090pub struct LanguageServerStatus {
4091 pub name: LanguageServerName,
4092 pub server_version: Option<SharedString>,
4093 pub server_readable_version: Option<SharedString>,
4094 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4095 pub has_pending_diagnostic_updates: bool,
4096 pub progress_tokens: HashSet<ProgressToken>,
4097 pub worktree: Option<WorktreeId>,
4098 pub binary: Option<LanguageServerBinary>,
4099 pub configuration: Option<Value>,
4100 pub workspace_folders: BTreeSet<Uri>,
4101 pub process_id: Option<u32>,
4102}
4103
4104#[derive(Clone, Debug)]
4105struct CoreSymbol {
4106 pub language_server_name: LanguageServerName,
4107 pub source_worktree_id: WorktreeId,
4108 pub source_language_server_id: LanguageServerId,
4109 pub path: SymbolLocation,
4110 pub name: String,
4111 pub kind: lsp::SymbolKind,
4112 pub range: Range<Unclipped<PointUtf16>>,
4113 pub container_name: Option<String>,
4114}
4115
4116#[derive(Clone, Debug, PartialEq, Eq)]
4117pub enum SymbolLocation {
4118 InProject(ProjectPath),
4119 OutsideProject {
4120 abs_path: Arc<Path>,
4121 signature: [u8; 32],
4122 },
4123}
4124
4125impl SymbolLocation {
4126 fn file_name(&self) -> Option<&str> {
4127 match self {
4128 Self::InProject(path) => path.path.file_name(),
4129 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4130 }
4131 }
4132}
4133
4134impl LspStore {
4135 pub fn init(client: &AnyProtoClient) {
4136 client.add_entity_request_handler(Self::handle_lsp_query);
4137 client.add_entity_message_handler(Self::handle_lsp_query_response);
4138 client.add_entity_request_handler(Self::handle_restart_language_servers);
4139 client.add_entity_request_handler(Self::handle_stop_language_servers);
4140 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4141 client.add_entity_message_handler(Self::handle_start_language_server);
4142 client.add_entity_message_handler(Self::handle_update_language_server);
4143 client.add_entity_message_handler(Self::handle_language_server_log);
4144 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4145 client.add_entity_request_handler(Self::handle_format_buffers);
4146 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4147 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4148 client.add_entity_request_handler(Self::handle_apply_code_action);
4149 client.add_entity_request_handler(Self::handle_get_project_symbols);
4150 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4151 client.add_entity_request_handler(Self::handle_get_color_presentation);
4152 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4153 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4154 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4155 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4156 client.add_entity_request_handler(Self::handle_on_type_formatting);
4157 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4158 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4159 client.add_entity_request_handler(Self::handle_rename_project_entry);
4160 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4161 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4162 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4163 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4164 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4165 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4166 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4167
4168 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4169 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4170 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4171 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4172 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4173 client.add_entity_request_handler(
4174 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4175 );
4176 client.add_entity_request_handler(
4177 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4178 );
4179 client.add_entity_request_handler(
4180 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4181 );
4182 }
4183
4184 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4185 match &self.mode {
4186 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4187 _ => None,
4188 }
4189 }
4190
4191 pub fn as_local(&self) -> Option<&LocalLspStore> {
4192 match &self.mode {
4193 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4194 _ => None,
4195 }
4196 }
4197
4198 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4199 match &mut self.mode {
4200 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4201 _ => None,
4202 }
4203 }
4204
4205 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4206 match &self.mode {
4207 LspStoreMode::Remote(RemoteLspStore {
4208 upstream_client: Some(upstream_client),
4209 upstream_project_id,
4210 ..
4211 }) => Some((upstream_client.clone(), *upstream_project_id)),
4212
4213 LspStoreMode::Remote(RemoteLspStore {
4214 upstream_client: None,
4215 ..
4216 }) => None,
4217 LspStoreMode::Local(_) => None,
4218 }
4219 }
4220
4221 pub fn new_local(
4222 buffer_store: Entity<BufferStore>,
4223 worktree_store: Entity<WorktreeStore>,
4224 prettier_store: Entity<PrettierStore>,
4225 toolchain_store: Entity<LocalToolchainStore>,
4226 environment: Entity<ProjectEnvironment>,
4227 manifest_tree: Entity<ManifestTree>,
4228 languages: Arc<LanguageRegistry>,
4229 http_client: Arc<dyn HttpClient>,
4230 fs: Arc<dyn Fs>,
4231 cx: &mut Context<Self>,
4232 ) -> Self {
4233 let yarn = YarnPathStore::new(fs.clone(), cx);
4234 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4235 .detach();
4236 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4237 .detach();
4238 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4239 .detach();
4240 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4241 .detach();
4242 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4243 .detach();
4244 subscribe_to_binary_statuses(&languages, cx).detach();
4245
4246 let _maintain_workspace_config = {
4247 let (sender, receiver) = watch::channel();
4248 (Self::maintain_workspace_config(receiver, cx), sender)
4249 };
4250
4251 Self {
4252 mode: LspStoreMode::Local(LocalLspStore {
4253 weak: cx.weak_entity(),
4254 worktree_store: worktree_store.clone(),
4255
4256 supplementary_language_servers: Default::default(),
4257 languages: languages.clone(),
4258 language_server_ids: Default::default(),
4259 language_servers: Default::default(),
4260 last_workspace_edits_by_language_server: Default::default(),
4261 language_server_watched_paths: Default::default(),
4262 language_server_paths_watched_for_rename: Default::default(),
4263 language_server_dynamic_registrations: Default::default(),
4264 buffers_being_formatted: Default::default(),
4265 buffers_to_refresh_hash_set: HashSet::default(),
4266 buffers_to_refresh_queue: VecDeque::new(),
4267 _background_diagnostics_worker: Task::ready(()).shared(),
4268 buffer_snapshots: Default::default(),
4269 prettier_store,
4270 environment,
4271 http_client,
4272 fs,
4273 yarn,
4274 next_diagnostic_group_id: Default::default(),
4275 diagnostics: Default::default(),
4276 _subscription: cx.on_app_quit(|this, _| {
4277 this.as_local_mut()
4278 .unwrap()
4279 .shutdown_language_servers_on_quit()
4280 }),
4281 lsp_tree: LanguageServerTree::new(
4282 manifest_tree,
4283 languages.clone(),
4284 toolchain_store.clone(),
4285 ),
4286 toolchain_store,
4287 registered_buffers: HashMap::default(),
4288 buffers_opened_in_servers: HashMap::default(),
4289 buffer_pull_diagnostics_result_ids: HashMap::default(),
4290 workspace_pull_diagnostics_result_ids: HashMap::default(),
4291 restricted_worktrees_tasks: HashMap::default(),
4292 all_language_servers_stopped: false,
4293 stopped_language_servers: HashSet::default(),
4294 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4295 .manifest_file_names(),
4296 }),
4297 last_formatting_failure: None,
4298 downstream_client: None,
4299 buffer_store,
4300 worktree_store,
4301 languages: languages.clone(),
4302 language_server_statuses: Default::default(),
4303 nonce: StdRng::from_os_rng().random(),
4304 diagnostic_summaries: HashMap::default(),
4305 lsp_server_capabilities: HashMap::default(),
4306 semantic_token_config: SemanticTokenConfig::new(cx),
4307 lsp_data: HashMap::default(),
4308 buffer_reload_tasks: HashMap::default(),
4309 next_hint_id: Arc::default(),
4310 active_entry: None,
4311 _maintain_workspace_config,
4312 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4313 }
4314 }
4315
4316 fn send_lsp_proto_request<R: LspCommand>(
4317 &self,
4318 buffer: Entity<Buffer>,
4319 client: AnyProtoClient,
4320 upstream_project_id: u64,
4321 request: R,
4322 cx: &mut Context<LspStore>,
4323 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4324 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4325 return Task::ready(Ok(R::Response::default()));
4326 }
4327 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4328 cx.spawn(async move |this, cx| {
4329 let response = client.request(message).await?;
4330 let this = this.upgrade().context("project dropped")?;
4331 request
4332 .response_from_proto(response, this, buffer, cx.clone())
4333 .await
4334 })
4335 }
4336
4337 pub(super) fn new_remote(
4338 buffer_store: Entity<BufferStore>,
4339 worktree_store: Entity<WorktreeStore>,
4340 languages: Arc<LanguageRegistry>,
4341 upstream_client: AnyProtoClient,
4342 project_id: u64,
4343 cx: &mut Context<Self>,
4344 ) -> Self {
4345 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4346 .detach();
4347 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4348 .detach();
4349 subscribe_to_binary_statuses(&languages, cx).detach();
4350 let _maintain_workspace_config = {
4351 let (sender, receiver) = watch::channel();
4352 (Self::maintain_workspace_config(receiver, cx), sender)
4353 };
4354 Self {
4355 mode: LspStoreMode::Remote(RemoteLspStore {
4356 upstream_client: Some(upstream_client),
4357 upstream_project_id: project_id,
4358 }),
4359 downstream_client: None,
4360 last_formatting_failure: None,
4361 buffer_store,
4362 worktree_store,
4363 languages: languages.clone(),
4364 language_server_statuses: Default::default(),
4365 nonce: StdRng::from_os_rng().random(),
4366 diagnostic_summaries: HashMap::default(),
4367 lsp_server_capabilities: HashMap::default(),
4368 semantic_token_config: SemanticTokenConfig::new(cx),
4369 next_hint_id: Arc::default(),
4370 lsp_data: HashMap::default(),
4371 buffer_reload_tasks: HashMap::default(),
4372 active_entry: None,
4373
4374 _maintain_workspace_config,
4375 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4376 }
4377 }
4378
4379 fn on_buffer_store_event(
4380 &mut self,
4381 _: Entity<BufferStore>,
4382 event: &BufferStoreEvent,
4383 cx: &mut Context<Self>,
4384 ) {
4385 match event {
4386 BufferStoreEvent::BufferAdded(buffer) => {
4387 self.on_buffer_added(buffer, cx).log_err();
4388 }
4389 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4390 let buffer_id = buffer.read(cx).remote_id();
4391 if let Some(local) = self.as_local_mut()
4392 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4393 {
4394 local.reset_buffer(buffer, old_file, cx);
4395
4396 if local.registered_buffers.contains_key(&buffer_id) {
4397 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4398 }
4399 }
4400
4401 self.detect_language_for_buffer(buffer, cx);
4402 if let Some(local) = self.as_local_mut() {
4403 local.initialize_buffer(buffer, cx);
4404 if local.registered_buffers.contains_key(&buffer_id) {
4405 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4406 }
4407 }
4408 }
4409 _ => {}
4410 }
4411 }
4412
4413 fn on_worktree_store_event(
4414 &mut self,
4415 _: Entity<WorktreeStore>,
4416 event: &WorktreeStoreEvent,
4417 cx: &mut Context<Self>,
4418 ) {
4419 match event {
4420 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4421 if !worktree.read(cx).is_local() {
4422 return;
4423 }
4424 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4425 worktree::Event::UpdatedEntries(changes) => {
4426 this.update_local_worktree_language_servers(&worktree, changes, cx);
4427 }
4428 worktree::Event::UpdatedGitRepositories(_)
4429 | worktree::Event::DeletedEntry(_)
4430 | worktree::Event::Deleted
4431 | worktree::Event::UpdatedRootRepoCommonDir => {}
4432 })
4433 .detach()
4434 }
4435 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4436 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4437 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4438 }
4439 WorktreeStoreEvent::WorktreeUpdatedEntries(worktree_id, changes) => {
4440 self.invalidate_diagnostic_summaries_for_removed_entries(*worktree_id, changes, cx);
4441 }
4442 WorktreeStoreEvent::WorktreeReleased(..)
4443 | WorktreeStoreEvent::WorktreeOrderChanged
4444 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4445 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4446 }
4447 }
4448
4449 fn on_prettier_store_event(
4450 &mut self,
4451 _: Entity<PrettierStore>,
4452 event: &PrettierStoreEvent,
4453 cx: &mut Context<Self>,
4454 ) {
4455 match event {
4456 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4457 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4458 }
4459 PrettierStoreEvent::LanguageServerAdded {
4460 new_server_id,
4461 name,
4462 prettier_server,
4463 } => {
4464 self.register_supplementary_language_server(
4465 *new_server_id,
4466 name.clone(),
4467 prettier_server.clone(),
4468 cx,
4469 );
4470 }
4471 }
4472 }
4473
4474 fn on_toolchain_store_event(
4475 &mut self,
4476 _: Entity<LocalToolchainStore>,
4477 event: &ToolchainStoreEvent,
4478 _: &mut Context<Self>,
4479 ) {
4480 if let ToolchainStoreEvent::ToolchainActivated = event {
4481 self.request_workspace_config_refresh()
4482 }
4483 }
4484
4485 fn request_workspace_config_refresh(&mut self) {
4486 *self._maintain_workspace_config.1.borrow_mut() = ();
4487 }
4488
4489 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4490 self.as_local().map(|local| local.prettier_store.clone())
4491 }
4492
4493 fn on_buffer_event(
4494 &mut self,
4495 buffer: Entity<Buffer>,
4496 event: &language::BufferEvent,
4497 cx: &mut Context<Self>,
4498 ) {
4499 match event {
4500 language::BufferEvent::Edited { .. } => {
4501 self.on_buffer_edited(buffer, cx);
4502 }
4503
4504 language::BufferEvent::Saved => {
4505 self.on_buffer_saved(buffer, cx);
4506 }
4507
4508 language::BufferEvent::Reloaded => {
4509 self.on_buffer_reloaded(buffer, cx);
4510 }
4511
4512 _ => {}
4513 }
4514 }
4515
4516 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4517 buffer
4518 .read(cx)
4519 .set_language_registry(self.languages.clone());
4520
4521 cx.subscribe(buffer, |this, buffer, event, cx| {
4522 this.on_buffer_event(buffer, event, cx);
4523 })
4524 .detach();
4525
4526 self.parse_modeline(buffer, cx);
4527 self.detect_language_for_buffer(buffer, cx);
4528 if let Some(local) = self.as_local_mut() {
4529 local.initialize_buffer(buffer, cx);
4530 }
4531
4532 Ok(())
4533 }
4534
4535 pub fn refresh_background_diagnostics_for_buffers(
4536 &mut self,
4537 buffers: HashSet<BufferId>,
4538 cx: &mut Context<Self>,
4539 ) -> Shared<Task<()>> {
4540 let Some(local) = self.as_local_mut() else {
4541 return Task::ready(()).shared();
4542 };
4543 for buffer in buffers {
4544 if local.buffers_to_refresh_hash_set.insert(buffer) {
4545 local.buffers_to_refresh_queue.push_back(buffer);
4546 if local.buffers_to_refresh_queue.len() == 1 {
4547 local._background_diagnostics_worker =
4548 Self::background_diagnostics_worker(cx).shared();
4549 }
4550 }
4551 }
4552
4553 local._background_diagnostics_worker.clone()
4554 }
4555
4556 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4557 let buffer_store = self.buffer_store.clone();
4558 let local = self.as_local_mut()?;
4559 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4560 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4561 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4562 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4563 }
4564 }
4565 None
4566 }
4567
4568 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4569 cx.spawn(async move |this, cx| {
4570 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4571 task.await.log_err();
4572 }
4573 })
4574 }
4575
4576 fn on_buffer_reloaded(&mut self, buffer: Entity<Buffer>, cx: &mut Context<Self>) {
4577 if self.parse_modeline(&buffer, cx) {
4578 self.detect_language_for_buffer(&buffer, cx);
4579 }
4580
4581 let buffer_id = buffer.read(cx).remote_id();
4582 let task = self.pull_diagnostics_for_buffer(buffer, cx);
4583 self.buffer_reload_tasks.insert(buffer_id, task);
4584 }
4585
4586 pub(crate) fn register_buffer_with_language_servers(
4587 &mut self,
4588 buffer: &Entity<Buffer>,
4589 only_register_servers: HashSet<LanguageServerSelector>,
4590 ignore_refcounts: bool,
4591 cx: &mut Context<Self>,
4592 ) -> OpenLspBufferHandle {
4593 let buffer_id = buffer.read(cx).remote_id();
4594 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4595 if let Some(local) = self.as_local_mut() {
4596 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4597 if !ignore_refcounts {
4598 *refcount += 1;
4599 }
4600
4601 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4602 // 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
4603 // 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
4604 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4605 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4606 return handle;
4607 };
4608 if !file.is_local() {
4609 return handle;
4610 }
4611
4612 if ignore_refcounts || *refcount == 1 {
4613 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4614 }
4615 if !ignore_refcounts {
4616 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4617 let refcount = {
4618 let local = lsp_store.as_local_mut().unwrap();
4619 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4620 debug_panic!("bad refcounting");
4621 return;
4622 };
4623
4624 *refcount -= 1;
4625 *refcount
4626 };
4627 if refcount == 0 {
4628 lsp_store.lsp_data.remove(&buffer_id);
4629 lsp_store.buffer_reload_tasks.remove(&buffer_id);
4630 let local = lsp_store.as_local_mut().unwrap();
4631 local.registered_buffers.remove(&buffer_id);
4632
4633 local.buffers_opened_in_servers.remove(&buffer_id);
4634 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4635 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4636
4637 let buffer_abs_path = file.abs_path(cx);
4638 for (_, buffer_pull_diagnostics_result_ids) in
4639 &mut local.buffer_pull_diagnostics_result_ids
4640 {
4641 buffer_pull_diagnostics_result_ids.retain(
4642 |_, buffer_result_ids| {
4643 buffer_result_ids.remove(&buffer_abs_path);
4644 !buffer_result_ids.is_empty()
4645 },
4646 );
4647 }
4648
4649 let diagnostic_updates = local
4650 .language_servers
4651 .keys()
4652 .cloned()
4653 .map(|server_id| DocumentDiagnosticsUpdate {
4654 diagnostics: DocumentDiagnostics {
4655 document_abs_path: buffer_abs_path.clone(),
4656 version: None,
4657 diagnostics: Vec::new(),
4658 },
4659 result_id: None,
4660 registration_id: None,
4661 server_id,
4662 disk_based_sources: Cow::Borrowed(&[]),
4663 })
4664 .collect::<Vec<_>>();
4665
4666 lsp_store
4667 .merge_diagnostic_entries(
4668 diagnostic_updates,
4669 |_, diagnostic, _| {
4670 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4671 },
4672 cx,
4673 )
4674 .context("Clearing diagnostics for the closed buffer")
4675 .log_err();
4676 }
4677 }
4678 })
4679 .detach();
4680 }
4681 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4682 let buffer_id = buffer.read(cx).remote_id().to_proto();
4683 cx.background_spawn(async move {
4684 upstream_client
4685 .request(proto::RegisterBufferWithLanguageServers {
4686 project_id: upstream_project_id,
4687 buffer_id,
4688 only_servers: only_register_servers
4689 .into_iter()
4690 .map(|selector| {
4691 let selector = match selector {
4692 LanguageServerSelector::Id(language_server_id) => {
4693 proto::language_server_selector::Selector::ServerId(
4694 language_server_id.to_proto(),
4695 )
4696 }
4697 LanguageServerSelector::Name(language_server_name) => {
4698 proto::language_server_selector::Selector::Name(
4699 language_server_name.to_string(),
4700 )
4701 }
4702 };
4703 proto::LanguageServerSelector {
4704 selector: Some(selector),
4705 }
4706 })
4707 .collect(),
4708 })
4709 .await
4710 })
4711 .detach();
4712 } else {
4713 // Our remote connection got closed
4714 }
4715 handle
4716 }
4717
4718 fn maintain_buffer_languages(
4719 languages: Arc<LanguageRegistry>,
4720 cx: &mut Context<Self>,
4721 ) -> Task<()> {
4722 let mut subscription = languages.subscribe();
4723 let mut prev_reload_count = languages.reload_count();
4724 cx.spawn(async move |this, cx| {
4725 while let Some(()) = subscription.next().await {
4726 if let Some(this) = this.upgrade() {
4727 // If the language registry has been reloaded, then remove and
4728 // re-assign the languages on all open buffers.
4729 let reload_count = languages.reload_count();
4730 if reload_count > prev_reload_count {
4731 prev_reload_count = reload_count;
4732 this.update(cx, |this, cx| {
4733 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4734 for buffer in buffer_store.buffers() {
4735 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4736 {
4737 buffer.update(cx, |buffer, cx| {
4738 buffer.set_language_async(None, cx)
4739 });
4740 if let Some(local) = this.as_local_mut() {
4741 local.reset_buffer(&buffer, &f, cx);
4742
4743 if local
4744 .registered_buffers
4745 .contains_key(&buffer.read(cx).remote_id())
4746 && let Some(file_url) =
4747 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4748 {
4749 local.unregister_buffer_from_language_servers(
4750 &buffer, &file_url, cx,
4751 );
4752 }
4753 }
4754 }
4755 }
4756 });
4757 });
4758 }
4759
4760 this.update(cx, |this, cx| {
4761 let mut plain_text_buffers = Vec::new();
4762 let mut buffers_with_unknown_injections = Vec::new();
4763 for handle in this.buffer_store.read(cx).buffers() {
4764 let buffer = handle.read(cx);
4765 if buffer.language().is_none()
4766 || buffer.language() == Some(&*language::PLAIN_TEXT)
4767 {
4768 plain_text_buffers.push(handle);
4769 } else if buffer.contains_unknown_injections() {
4770 buffers_with_unknown_injections.push(handle);
4771 }
4772 }
4773
4774 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4775 // and reused later in the invisible worktrees.
4776 plain_text_buffers.sort_by_key(|buffer| {
4777 Reverse(
4778 File::from_dyn(buffer.read(cx).file())
4779 .map(|file| file.worktree.read(cx).is_visible()),
4780 )
4781 });
4782
4783 for buffer in plain_text_buffers {
4784 this.detect_language_for_buffer(&buffer, cx);
4785 if let Some(local) = this.as_local_mut() {
4786 local.initialize_buffer(&buffer, cx);
4787 if local
4788 .registered_buffers
4789 .contains_key(&buffer.read(cx).remote_id())
4790 {
4791 local.register_buffer_with_language_servers(
4792 &buffer,
4793 HashSet::default(),
4794 cx,
4795 );
4796 }
4797 }
4798 }
4799
4800 for buffer in buffers_with_unknown_injections {
4801 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4802 }
4803 });
4804 }
4805 }
4806 })
4807 }
4808
4809 fn parse_modeline(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<Self>) -> bool {
4810 let buffer = buffer_handle.read(cx);
4811 let content = buffer.as_rope();
4812
4813 let modeline_settings = {
4814 let settings_store = cx.global::<SettingsStore>();
4815 let modeline_lines = settings_store
4816 .raw_user_settings()
4817 .and_then(|s| s.content.modeline_lines)
4818 .or(settings_store.raw_default_settings().modeline_lines)
4819 .unwrap_or(5);
4820
4821 const MAX_MODELINE_BYTES: usize = 1024;
4822
4823 let first_bytes =
4824 content.clip_offset(content.len().min(MAX_MODELINE_BYTES), Bias::Left);
4825 let mut first_lines = Vec::new();
4826 let mut lines = content.chunks_in_range(0..first_bytes).lines();
4827 for _ in 0..modeline_lines {
4828 if let Some(line) = lines.next() {
4829 first_lines.push(line.to_string());
4830 } else {
4831 break;
4832 }
4833 }
4834 let first_lines_ref: Vec<_> = first_lines.iter().map(|line| line.as_str()).collect();
4835
4836 let last_start =
4837 content.clip_offset(content.len().saturating_sub(MAX_MODELINE_BYTES), Bias::Left);
4838 let mut last_lines = Vec::new();
4839 let mut lines = content
4840 .reversed_chunks_in_range(last_start..content.len())
4841 .lines();
4842 for _ in 0..modeline_lines {
4843 if let Some(line) = lines.next() {
4844 last_lines.push(line.to_string());
4845 } else {
4846 break;
4847 }
4848 }
4849 let last_lines_ref: Vec<_> =
4850 last_lines.iter().rev().map(|line| line.as_str()).collect();
4851 modeline::parse_modeline(&first_lines_ref, &last_lines_ref)
4852 };
4853
4854 log::debug!("Parsed modeline settings: {:?}", modeline_settings);
4855
4856 buffer_handle.update(cx, |buffer, _cx| buffer.set_modeline(modeline_settings))
4857 }
4858
4859 fn detect_language_for_buffer(
4860 &mut self,
4861 buffer_handle: &Entity<Buffer>,
4862 cx: &mut Context<Self>,
4863 ) -> Option<language::AvailableLanguage> {
4864 // If the buffer has a language, set it and start the language server if we haven't already.
4865 let buffer = buffer_handle.read(cx);
4866 let file = buffer.file()?;
4867 let content = buffer.as_rope();
4868 let modeline_settings = buffer.modeline().map(Arc::as_ref);
4869
4870 let available_language = if let Some(ModelineSettings {
4871 mode: Some(mode_name),
4872 ..
4873 }) = modeline_settings
4874 {
4875 self.languages
4876 .available_language_for_modeline_name(mode_name)
4877 } else {
4878 self.languages.language_for_file(file, Some(content), cx)
4879 };
4880 if let Some(available_language) = &available_language {
4881 if let Some(Ok(Ok(new_language))) = self
4882 .languages
4883 .load_language(available_language)
4884 .now_or_never()
4885 {
4886 self.set_language_for_buffer(buffer_handle, new_language, cx);
4887 }
4888 } else {
4889 cx.emit(LspStoreEvent::LanguageDetected {
4890 buffer: buffer_handle.clone(),
4891 new_language: None,
4892 });
4893 }
4894
4895 available_language
4896 }
4897
4898 pub(crate) fn set_language_for_buffer(
4899 &mut self,
4900 buffer_entity: &Entity<Buffer>,
4901 new_language: Arc<Language>,
4902 cx: &mut Context<Self>,
4903 ) {
4904 let buffer = buffer_entity.read(cx);
4905 let buffer_file = buffer.file().cloned();
4906 let buffer_id = buffer.remote_id();
4907 if let Some(local_store) = self.as_local_mut()
4908 && local_store.registered_buffers.contains_key(&buffer_id)
4909 && let Some(abs_path) =
4910 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4911 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4912 {
4913 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4914 }
4915 buffer_entity.update(cx, |buffer, cx| {
4916 if buffer
4917 .language()
4918 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4919 {
4920 buffer.set_language_async(Some(new_language.clone()), cx);
4921 }
4922 });
4923
4924 let settings = LanguageSettings::resolve(
4925 Some(&buffer_entity.read(cx)),
4926 Some(&new_language.name()),
4927 cx,
4928 )
4929 .into_owned();
4930 let buffer_file = File::from_dyn(buffer_file.as_ref());
4931
4932 let worktree_id = if let Some(file) = buffer_file {
4933 let worktree = file.worktree.clone();
4934
4935 if let Some(local) = self.as_local_mut()
4936 && local.registered_buffers.contains_key(&buffer_id)
4937 {
4938 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4939 }
4940 Some(worktree.read(cx).id())
4941 } else {
4942 None
4943 };
4944
4945 if settings.prettier.allowed
4946 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4947 {
4948 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4949 if let Some(prettier_store) = prettier_store {
4950 prettier_store.update(cx, |prettier_store, cx| {
4951 prettier_store.install_default_prettier(
4952 worktree_id,
4953 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4954 cx,
4955 )
4956 })
4957 }
4958 }
4959
4960 cx.emit(LspStoreEvent::LanguageDetected {
4961 buffer: buffer_entity.clone(),
4962 new_language: Some(new_language),
4963 })
4964 }
4965
4966 pub fn buffer_store(&self) -> Entity<BufferStore> {
4967 self.buffer_store.clone()
4968 }
4969
4970 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4971 self.active_entry = active_entry;
4972 }
4973
4974 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4975 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4976 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4977 {
4978 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4979 summaries
4980 .iter()
4981 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4982 });
4983 if let Some(summary) = summaries.next() {
4984 client
4985 .send(proto::UpdateDiagnosticSummary {
4986 project_id: downstream_project_id,
4987 worktree_id: worktree.id().to_proto(),
4988 summary: Some(summary),
4989 more_summaries: summaries.collect(),
4990 })
4991 .log_err();
4992 }
4993 }
4994 }
4995
4996 fn is_capable_for_proto_request<R>(
4997 &self,
4998 buffer: &Entity<Buffer>,
4999 request: &R,
5000 cx: &App,
5001 ) -> bool
5002 where
5003 R: LspCommand,
5004 {
5005 self.check_if_capable_for_proto_request(
5006 buffer,
5007 |capabilities| {
5008 request.check_capabilities(AdapterServerCapabilities {
5009 server_capabilities: capabilities.clone(),
5010 code_action_kinds: None,
5011 })
5012 },
5013 cx,
5014 )
5015 }
5016
5017 fn check_if_capable_for_proto_request<F>(
5018 &self,
5019 buffer: &Entity<Buffer>,
5020 check: F,
5021 cx: &App,
5022 ) -> bool
5023 where
5024 F: FnMut(&lsp::ServerCapabilities) -> bool,
5025 {
5026 let Some(language) = buffer.read(cx).language().cloned() else {
5027 return false;
5028 };
5029 let registered_language_servers = self
5030 .languages
5031 .lsp_adapters(&language.name())
5032 .into_iter()
5033 .map(|lsp_adapter| lsp_adapter.name())
5034 .collect::<HashSet<_>>();
5035 self.language_server_statuses
5036 .iter()
5037 .filter_map(|(server_id, server_status)| {
5038 // Include servers that are either registered for this language OR
5039 // available to be loaded (for SSH remote mode where adapters like
5040 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5041 // but only loaded on the server side)
5042 let is_relevant = registered_language_servers.contains(&server_status.name)
5043 || self.languages.is_lsp_adapter_available(&server_status.name);
5044 is_relevant.then_some(server_id)
5045 })
5046 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
5047 .any(check)
5048 }
5049
5050 fn all_capable_for_proto_request<F>(
5051 &self,
5052 buffer: &Entity<Buffer>,
5053 mut check: F,
5054 cx: &App,
5055 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
5056 where
5057 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
5058 {
5059 let Some(language) = buffer.read(cx).language().cloned() else {
5060 return Vec::default();
5061 };
5062 let registered_language_servers = self
5063 .languages
5064 .lsp_adapters(&language.name())
5065 .into_iter()
5066 .map(|lsp_adapter| lsp_adapter.name())
5067 .collect::<HashSet<_>>();
5068 self.language_server_statuses
5069 .iter()
5070 .filter_map(|(server_id, server_status)| {
5071 // Include servers that are either registered for this language OR
5072 // available to be loaded (for SSH remote mode where adapters like
5073 // ty/pylsp/pyright are registered via register_available_lsp_adapter
5074 // but only loaded on the server side)
5075 let is_relevant = registered_language_servers.contains(&server_status.name)
5076 || self.languages.is_lsp_adapter_available(&server_status.name);
5077 is_relevant.then_some((server_id, &server_status.name))
5078 })
5079 .filter_map(|(server_id, server_name)| {
5080 self.lsp_server_capabilities
5081 .get(server_id)
5082 .map(|c| (server_id, server_name, c))
5083 })
5084 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
5085 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
5086 .collect()
5087 }
5088
5089 pub fn request_lsp<R>(
5090 &mut self,
5091 buffer: Entity<Buffer>,
5092 server: LanguageServerToQuery,
5093 request: R,
5094 cx: &mut Context<Self>,
5095 ) -> Task<Result<R::Response>>
5096 where
5097 R: LspCommand,
5098 <R::LspRequest as lsp::request::Request>::Result: Send,
5099 <R::LspRequest as lsp::request::Request>::Params: Send,
5100 {
5101 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
5102 return self.send_lsp_proto_request(
5103 buffer,
5104 upstream_client,
5105 upstream_project_id,
5106 request,
5107 cx,
5108 );
5109 }
5110
5111 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
5112 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
5113 local
5114 .language_servers_for_buffer(buffer, cx)
5115 .find(|(_, server)| {
5116 request.check_capabilities(server.adapter_server_capabilities())
5117 })
5118 .map(|(_, server)| server.clone())
5119 }),
5120 LanguageServerToQuery::Other(id) => self
5121 .language_server_for_local_buffer(buffer, id, cx)
5122 .and_then(|(_, server)| {
5123 request
5124 .check_capabilities(server.adapter_server_capabilities())
5125 .then(|| Arc::clone(server))
5126 }),
5127 }) else {
5128 return Task::ready(Ok(Default::default()));
5129 };
5130
5131 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5132
5133 let Some(file) = file else {
5134 return Task::ready(Ok(Default::default()));
5135 };
5136
5137 let lsp_params = match request.to_lsp_params_or_response(
5138 &file.abs_path(cx),
5139 buffer.read(cx),
5140 &language_server,
5141 cx,
5142 ) {
5143 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5144 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5145 Err(err) => {
5146 let message = format!(
5147 "{} via {} failed: {}",
5148 request.display_name(),
5149 language_server.name(),
5150 err
5151 );
5152 // rust-analyzer likes to error with this when its still loading up
5153 if !message.ends_with("content modified") {
5154 log::warn!("{message}");
5155 }
5156 return Task::ready(Err(anyhow!(message)));
5157 }
5158 };
5159
5160 let status = request.status();
5161 let request_timeout = ProjectSettings::get_global(cx)
5162 .global_lsp_settings
5163 .get_request_timeout();
5164
5165 cx.spawn(async move |this, cx| {
5166 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5167
5168 let id = lsp_request.id();
5169 let _cleanup = if status.is_some() {
5170 cx.update(|cx| {
5171 this.update(cx, |this, cx| {
5172 this.on_lsp_work_start(
5173 language_server.server_id(),
5174 ProgressToken::Number(id),
5175 LanguageServerProgress {
5176 is_disk_based_diagnostics_progress: false,
5177 is_cancellable: false,
5178 title: None,
5179 message: status.clone(),
5180 percentage: None,
5181 last_update_at: cx.background_executor().now(),
5182 },
5183 cx,
5184 );
5185 })
5186 })
5187 .log_err();
5188
5189 Some(defer(|| {
5190 cx.update(|cx| {
5191 this.update(cx, |this, cx| {
5192 this.on_lsp_work_end(
5193 language_server.server_id(),
5194 ProgressToken::Number(id),
5195 cx,
5196 );
5197 })
5198 })
5199 .log_err();
5200 }))
5201 } else {
5202 None
5203 };
5204
5205 let result = lsp_request.await.into_response();
5206
5207 let response = result.map_err(|err| {
5208 let message = format!(
5209 "{} via {} failed: {}",
5210 request.display_name(),
5211 language_server.name(),
5212 err
5213 );
5214 // rust-analyzer likes to error with this when its still loading up
5215 if !message.ends_with("content modified") {
5216 log::warn!("{message}");
5217 }
5218 anyhow::anyhow!(message)
5219 })?;
5220
5221 request
5222 .response_from_lsp(
5223 response,
5224 this.upgrade().context("no app context")?,
5225 buffer,
5226 language_server.server_id(),
5227 cx.clone(),
5228 )
5229 .await
5230 })
5231 }
5232
5233 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5234 let mut language_formatters_to_check = Vec::new();
5235 for buffer in self.buffer_store.read(cx).buffers() {
5236 let buffer = buffer.read(cx);
5237 let settings = LanguageSettings::for_buffer(buffer, cx);
5238 if buffer.language().is_some() {
5239 let buffer_file = File::from_dyn(buffer.file());
5240 language_formatters_to_check.push((
5241 buffer_file.map(|f| f.worktree_id(cx)),
5242 settings.into_owned(),
5243 ));
5244 }
5245 }
5246
5247 self.request_workspace_config_refresh();
5248
5249 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5250 prettier_store.update(cx, |prettier_store, cx| {
5251 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5252 })
5253 }
5254
5255 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5256 .global_lsp_settings
5257 .semantic_token_rules
5258 .clone();
5259 self.semantic_token_config
5260 .update_rules(new_semantic_token_rules);
5261 // Always clear cached stylizers so that changes to language-specific
5262 // semantic token rules (e.g. from extension install/uninstall) are
5263 // picked up. Stylizers are recreated lazily, so this is cheap.
5264 self.semantic_token_config.clear_stylizers();
5265
5266 let new_global_semantic_tokens_mode =
5267 all_language_settings(None, cx).defaults.semantic_tokens;
5268 if self
5269 .semantic_token_config
5270 .update_global_mode(new_global_semantic_tokens_mode)
5271 {
5272 let all_stopped = self
5273 .as_local()
5274 .is_some_and(|local| local.all_language_servers_stopped);
5275 if !all_stopped {
5276 // Restart servers without clearing per-server stopped status.
5277 // Individually-stopped servers will be skipped by the guard in
5278 // register_buffer_with_language_servers.
5279 let buffers = self.buffer_store.read(cx).buffers().collect();
5280 self.restart_language_servers_for_buffers(buffers, HashSet::default(), false, cx);
5281 }
5282 }
5283
5284 cx.notify();
5285 }
5286
5287 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5288 let buffer_store = self.buffer_store.clone();
5289 let Some(local) = self.as_local_mut() else {
5290 return;
5291 };
5292 if local.all_language_servers_stopped {
5293 return;
5294 }
5295 let stopped_language_servers = local.stopped_language_servers.clone();
5296 let mut adapters = BTreeMap::default();
5297 let get_adapter = {
5298 let languages = local.languages.clone();
5299 let environment = local.environment.clone();
5300 let weak = local.weak.clone();
5301 let worktree_store = local.worktree_store.clone();
5302 let http_client = local.http_client.clone();
5303 let fs = local.fs.clone();
5304 move |worktree_id, cx: &mut App| {
5305 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5306 Some(LocalLspAdapterDelegate::new(
5307 languages.clone(),
5308 &environment,
5309 weak.clone(),
5310 &worktree,
5311 http_client.clone(),
5312 fs.clone(),
5313 cx,
5314 ))
5315 }
5316 };
5317
5318 let mut messages_to_report = Vec::new();
5319 let (new_tree, to_stop) = {
5320 let mut rebase = local.lsp_tree.rebase();
5321 let buffers = buffer_store
5322 .read(cx)
5323 .buffers()
5324 .filter_map(|buffer| {
5325 let raw_buffer = buffer.read(cx);
5326 if !local
5327 .registered_buffers
5328 .contains_key(&raw_buffer.remote_id())
5329 {
5330 return None;
5331 }
5332 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5333 let language = raw_buffer.language().cloned()?;
5334 Some((file, language, raw_buffer.remote_id()))
5335 })
5336 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5337 for (file, language, buffer_id) in buffers {
5338 let worktree_id = file.worktree_id(cx);
5339 let Some(worktree) = local
5340 .worktree_store
5341 .read(cx)
5342 .worktree_for_id(worktree_id, cx)
5343 else {
5344 continue;
5345 };
5346
5347 if let Some((_, apply)) = local.reuse_existing_language_server(
5348 rebase.server_tree(),
5349 &worktree,
5350 &language.name(),
5351 cx,
5352 ) {
5353 (apply)(rebase.server_tree());
5354 } else if let Some(lsp_delegate) = adapters
5355 .entry(worktree_id)
5356 .or_insert_with(|| get_adapter(worktree_id, cx))
5357 .clone()
5358 {
5359 let delegate =
5360 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5361 let path = file
5362 .path()
5363 .parent()
5364 .map(Arc::from)
5365 .unwrap_or_else(|| file.path().clone());
5366 let worktree_path = ProjectPath { worktree_id, path };
5367 let abs_path = file.abs_path(cx);
5368 let nodes = rebase
5369 .walk(
5370 worktree_path,
5371 language.name(),
5372 language.manifest(),
5373 delegate.clone(),
5374 cx,
5375 )
5376 .collect::<Vec<_>>();
5377 for node in nodes {
5378 if let Some(name) = node.name()
5379 && stopped_language_servers.contains(&name)
5380 {
5381 continue;
5382 }
5383 let server_id = node.server_id_or_init(|disposition| {
5384 let path = &disposition.path;
5385 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5386 let key = LanguageServerSeed {
5387 worktree_id,
5388 name: disposition.server_name.clone(),
5389 settings: LanguageServerSeedSettings {
5390 binary: disposition.settings.binary.clone(),
5391 initialization_options: disposition
5392 .settings
5393 .initialization_options
5394 .clone(),
5395 },
5396 toolchain: local.toolchain_store.read(cx).active_toolchain(
5397 path.worktree_id,
5398 &path.path,
5399 language.name(),
5400 ),
5401 };
5402 local.language_server_ids.remove(&key);
5403
5404 let server_id = local.get_or_insert_language_server(
5405 &worktree,
5406 lsp_delegate.clone(),
5407 disposition,
5408 &language.name(),
5409 cx,
5410 );
5411 if let Some(state) = local.language_servers.get(&server_id)
5412 && let Ok(uri) = uri
5413 {
5414 state.add_workspace_folder(uri);
5415 };
5416 server_id
5417 });
5418
5419 if let Some(language_server_id) = server_id {
5420 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5421 language_server_id,
5422 name: node.name(),
5423 message:
5424 proto::update_language_server::Variant::RegisteredForBuffer(
5425 proto::RegisteredForBuffer {
5426 buffer_abs_path: abs_path
5427 .to_string_lossy()
5428 .into_owned(),
5429 buffer_id: buffer_id.to_proto(),
5430 },
5431 ),
5432 });
5433 }
5434 }
5435 } else {
5436 continue;
5437 }
5438 }
5439 rebase.finish()
5440 };
5441 for message in messages_to_report {
5442 cx.emit(message);
5443 }
5444 local.lsp_tree = new_tree;
5445 for (id, _) in to_stop {
5446 self.stop_local_language_server(id, cx).detach();
5447 }
5448 }
5449
5450 pub fn apply_code_action(
5451 &self,
5452 buffer_handle: Entity<Buffer>,
5453 mut action: CodeAction,
5454 push_to_history: bool,
5455 cx: &mut Context<Self>,
5456 ) -> Task<Result<ProjectTransaction>> {
5457 if let Some((upstream_client, project_id)) = self.upstream_client() {
5458 let request = proto::ApplyCodeAction {
5459 project_id,
5460 buffer_id: buffer_handle.read(cx).remote_id().into(),
5461 action: Some(Self::serialize_code_action(&action)),
5462 };
5463 let buffer_store = self.buffer_store();
5464 cx.spawn(async move |_, cx| {
5465 let response = upstream_client
5466 .request(request)
5467 .await?
5468 .transaction
5469 .context("missing transaction")?;
5470
5471 buffer_store
5472 .update(cx, |buffer_store, cx| {
5473 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5474 })
5475 .await
5476 })
5477 } else if self.mode.is_local() {
5478 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5479 let request_timeout = ProjectSettings::get_global(cx)
5480 .global_lsp_settings
5481 .get_request_timeout();
5482 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5483 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5484 }) else {
5485 return Task::ready(Ok(ProjectTransaction::default()));
5486 };
5487
5488 cx.spawn(async move |this, cx| {
5489 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5490 .await
5491 .context("resolving a code action")?;
5492 if let Some(edit) = action.lsp_action.edit()
5493 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5494 return LocalLspStore::deserialize_workspace_edit(
5495 this.upgrade().context("no app present")?,
5496 edit.clone(),
5497 push_to_history,
5498
5499 lang_server.clone(),
5500 cx,
5501 )
5502 .await;
5503 }
5504
5505 let Some(command) = action.lsp_action.command() else {
5506 return Ok(ProjectTransaction::default())
5507 };
5508
5509 let server_capabilities = lang_server.capabilities();
5510 let available_commands = server_capabilities
5511 .execute_command_provider
5512 .as_ref()
5513 .map(|options| options.commands.as_slice())
5514 .unwrap_or_default();
5515
5516 if !available_commands.contains(&command.command) {
5517 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5518 return Ok(ProjectTransaction::default())
5519 }
5520
5521 let request_timeout = cx.update(|app|
5522 ProjectSettings::get_global(app)
5523 .global_lsp_settings
5524 .get_request_timeout()
5525 );
5526
5527 this.update(cx, |this, _| {
5528 this.as_local_mut()
5529 .unwrap()
5530 .last_workspace_edits_by_language_server
5531 .remove(&lang_server.server_id());
5532 })?;
5533
5534 let _result = lang_server
5535 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5536 command: command.command.clone(),
5537 arguments: command.arguments.clone().unwrap_or_default(),
5538 ..lsp::ExecuteCommandParams::default()
5539 }, request_timeout)
5540 .await.into_response()
5541 .context("execute command")?;
5542
5543 return this.update(cx, |this, _| {
5544 this.as_local_mut()
5545 .unwrap()
5546 .last_workspace_edits_by_language_server
5547 .remove(&lang_server.server_id())
5548 .unwrap_or_default()
5549 });
5550 })
5551 } else {
5552 Task::ready(Err(anyhow!("no upstream client and not local")))
5553 }
5554 }
5555
5556 pub fn apply_code_action_kind(
5557 &mut self,
5558 buffers: HashSet<Entity<Buffer>>,
5559 kind: CodeActionKind,
5560 push_to_history: bool,
5561 cx: &mut Context<Self>,
5562 ) -> Task<anyhow::Result<ProjectTransaction>> {
5563 if self.as_local().is_some() {
5564 cx.spawn(async move |lsp_store, cx| {
5565 let buffers = buffers.into_iter().collect::<Vec<_>>();
5566 let result = LocalLspStore::execute_code_action_kind_locally(
5567 lsp_store.clone(),
5568 buffers,
5569 kind,
5570 push_to_history,
5571 cx,
5572 )
5573 .await;
5574 lsp_store.update(cx, |lsp_store, _| {
5575 lsp_store.update_last_formatting_failure(&result);
5576 })?;
5577 result
5578 })
5579 } else if let Some((client, project_id)) = self.upstream_client() {
5580 let buffer_store = self.buffer_store();
5581 cx.spawn(async move |lsp_store, cx| {
5582 let result = client
5583 .request(proto::ApplyCodeActionKind {
5584 project_id,
5585 kind: kind.as_str().to_owned(),
5586 buffer_ids: buffers
5587 .iter()
5588 .map(|buffer| {
5589 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5590 })
5591 .collect(),
5592 })
5593 .await
5594 .and_then(|result| result.transaction.context("missing transaction"));
5595 lsp_store.update(cx, |lsp_store, _| {
5596 lsp_store.update_last_formatting_failure(&result);
5597 })?;
5598
5599 let transaction_response = result?;
5600 buffer_store
5601 .update(cx, |buffer_store, cx| {
5602 buffer_store.deserialize_project_transaction(
5603 transaction_response,
5604 push_to_history,
5605 cx,
5606 )
5607 })
5608 .await
5609 })
5610 } else {
5611 Task::ready(Ok(ProjectTransaction::default()))
5612 }
5613 }
5614
5615 pub fn resolved_hint(
5616 &mut self,
5617 buffer_id: BufferId,
5618 id: InlayId,
5619 cx: &mut Context<Self>,
5620 ) -> Option<ResolvedHint> {
5621 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5622
5623 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5624 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5625 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5626 let (server_id, resolve_data) = match &hint.resolve_state {
5627 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5628 ResolveState::Resolving => {
5629 return Some(ResolvedHint::Resolving(
5630 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5631 ));
5632 }
5633 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5634 };
5635
5636 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5637 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5638 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5639 id,
5640 cx.spawn(async move |lsp_store, cx| {
5641 let resolved_hint = resolve_task.await;
5642 lsp_store
5643 .update(cx, |lsp_store, _| {
5644 if let Some(old_inlay_hint) = lsp_store
5645 .lsp_data
5646 .get_mut(&buffer_id)
5647 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5648 {
5649 match resolved_hint {
5650 Ok(resolved_hint) => {
5651 *old_inlay_hint = resolved_hint;
5652 }
5653 Err(e) => {
5654 old_inlay_hint.resolve_state =
5655 ResolveState::CanResolve(server_id, resolve_data);
5656 log::error!("Inlay hint resolve failed: {e:#}");
5657 }
5658 }
5659 }
5660 })
5661 .ok();
5662 })
5663 .shared(),
5664 );
5665 debug_assert!(
5666 previous_task.is_none(),
5667 "Did not change hint's resolve state after spawning its resolve"
5668 );
5669 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5670 None
5671 }
5672
5673 pub(crate) fn linked_edits(
5674 &mut self,
5675 buffer: &Entity<Buffer>,
5676 position: Anchor,
5677 cx: &mut Context<Self>,
5678 ) -> Task<Result<Vec<Range<Anchor>>>> {
5679 let snapshot = buffer.read(cx).snapshot();
5680 let scope = snapshot.language_scope_at(position);
5681 let Some(server_id) = self
5682 .as_local()
5683 .and_then(|local| {
5684 buffer.update(cx, |buffer, cx| {
5685 local
5686 .language_servers_for_buffer(buffer, cx)
5687 .filter(|(_, server)| {
5688 LinkedEditingRange::check_server_capabilities(server.capabilities())
5689 })
5690 .filter(|(adapter, _)| {
5691 scope
5692 .as_ref()
5693 .map(|scope| scope.language_allowed(&adapter.name))
5694 .unwrap_or(true)
5695 })
5696 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5697 .next()
5698 })
5699 })
5700 .or_else(|| {
5701 self.upstream_client()
5702 .is_some()
5703 .then_some(LanguageServerToQuery::FirstCapable)
5704 })
5705 .filter(|_| {
5706 maybe!({
5707 buffer.read(cx).language_at(position)?;
5708 Some(
5709 LanguageSettings::for_buffer_at(&buffer.read(cx), position, cx)
5710 .linked_edits,
5711 )
5712 }) == Some(true)
5713 })
5714 else {
5715 return Task::ready(Ok(Vec::new()));
5716 };
5717
5718 self.request_lsp(
5719 buffer.clone(),
5720 server_id,
5721 LinkedEditingRange { position },
5722 cx,
5723 )
5724 }
5725
5726 fn apply_on_type_formatting(
5727 &mut self,
5728 buffer: Entity<Buffer>,
5729 position: Anchor,
5730 trigger: String,
5731 cx: &mut Context<Self>,
5732 ) -> Task<Result<Option<Transaction>>> {
5733 if let Some((client, project_id)) = self.upstream_client() {
5734 if !self.check_if_capable_for_proto_request(
5735 &buffer,
5736 |capabilities| {
5737 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5738 },
5739 cx,
5740 ) {
5741 return Task::ready(Ok(None));
5742 }
5743 let request = proto::OnTypeFormatting {
5744 project_id,
5745 buffer_id: buffer.read(cx).remote_id().into(),
5746 position: Some(serialize_anchor(&position)),
5747 trigger,
5748 version: serialize_version(&buffer.read(cx).version()),
5749 };
5750 cx.background_spawn(async move {
5751 client
5752 .request(request)
5753 .await?
5754 .transaction
5755 .map(language::proto::deserialize_transaction)
5756 .transpose()
5757 })
5758 } else if let Some(local) = self.as_local_mut() {
5759 let buffer_id = buffer.read(cx).remote_id();
5760 local.buffers_being_formatted.insert(buffer_id);
5761 cx.spawn(async move |this, cx| {
5762 let _cleanup = defer({
5763 let this = this.clone();
5764 let mut cx = cx.clone();
5765 move || {
5766 this.update(&mut cx, |this, _| {
5767 if let Some(local) = this.as_local_mut() {
5768 local.buffers_being_formatted.remove(&buffer_id);
5769 }
5770 })
5771 .ok();
5772 }
5773 });
5774
5775 buffer
5776 .update(cx, |buffer, _| {
5777 buffer.wait_for_edits(Some(position.timestamp()))
5778 })
5779 .await?;
5780 this.update(cx, |this, cx| {
5781 let position = position.to_point_utf16(buffer.read(cx));
5782 this.on_type_format(buffer, position, trigger, false, cx)
5783 })?
5784 .await
5785 })
5786 } else {
5787 Task::ready(Err(anyhow!("No upstream client or local language server")))
5788 }
5789 }
5790
5791 pub fn on_type_format<T: ToPointUtf16>(
5792 &mut self,
5793 buffer: Entity<Buffer>,
5794 position: T,
5795 trigger: String,
5796 push_to_history: bool,
5797 cx: &mut Context<Self>,
5798 ) -> Task<Result<Option<Transaction>>> {
5799 let position = position.to_point_utf16(buffer.read(cx));
5800 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5801 }
5802
5803 fn on_type_format_impl(
5804 &mut self,
5805 buffer: Entity<Buffer>,
5806 position: PointUtf16,
5807 trigger: String,
5808 push_to_history: bool,
5809 cx: &mut Context<Self>,
5810 ) -> Task<Result<Option<Transaction>>> {
5811 let options = buffer.update(cx, |buffer, cx| {
5812 lsp_command::lsp_formatting_options(
5813 LanguageSettings::for_buffer_at(buffer, position, cx).as_ref(),
5814 )
5815 });
5816
5817 cx.spawn(async move |this, cx| {
5818 if let Some(waiter) =
5819 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5820 {
5821 waiter.await?;
5822 }
5823 cx.update(|cx| {
5824 this.update(cx, |this, cx| {
5825 this.request_lsp(
5826 buffer.clone(),
5827 LanguageServerToQuery::FirstCapable,
5828 OnTypeFormatting {
5829 position,
5830 trigger,
5831 options,
5832 push_to_history,
5833 },
5834 cx,
5835 )
5836 })
5837 })?
5838 .await
5839 })
5840 }
5841
5842 pub fn definitions(
5843 &mut self,
5844 buffer: &Entity<Buffer>,
5845 position: PointUtf16,
5846 cx: &mut Context<Self>,
5847 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5848 if let Some((upstream_client, project_id)) = self.upstream_client() {
5849 let request = GetDefinitions { position };
5850 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5851 return Task::ready(Ok(None));
5852 }
5853
5854 let request_timeout = ProjectSettings::get_global(cx)
5855 .global_lsp_settings
5856 .get_request_timeout();
5857
5858 let request_task = upstream_client.request_lsp(
5859 project_id,
5860 None,
5861 request_timeout,
5862 cx.background_executor().clone(),
5863 request.to_proto(project_id, buffer.read(cx)),
5864 );
5865 let buffer = buffer.clone();
5866 cx.spawn(async move |weak_lsp_store, cx| {
5867 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5868 return Ok(None);
5869 };
5870 let Some(responses) = request_task.await? else {
5871 return Ok(None);
5872 };
5873 let actions = join_all(responses.payload.into_iter().map(|response| {
5874 GetDefinitions { position }.response_from_proto(
5875 response.response,
5876 lsp_store.clone(),
5877 buffer.clone(),
5878 cx.clone(),
5879 )
5880 }))
5881 .await;
5882
5883 Ok(Some(
5884 actions
5885 .into_iter()
5886 .collect::<Result<Vec<Vec<_>>>>()?
5887 .into_iter()
5888 .flatten()
5889 .dedup()
5890 .collect(),
5891 ))
5892 })
5893 } else {
5894 let definitions_task = self.request_multiple_lsp_locally(
5895 buffer,
5896 Some(position),
5897 GetDefinitions { position },
5898 cx,
5899 );
5900 cx.background_spawn(async move {
5901 Ok(Some(
5902 definitions_task
5903 .await
5904 .into_iter()
5905 .flat_map(|(_, definitions)| definitions)
5906 .dedup()
5907 .collect(),
5908 ))
5909 })
5910 }
5911 }
5912
5913 pub fn declarations(
5914 &mut self,
5915 buffer: &Entity<Buffer>,
5916 position: PointUtf16,
5917 cx: &mut Context<Self>,
5918 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5919 if let Some((upstream_client, project_id)) = self.upstream_client() {
5920 let request = GetDeclarations { position };
5921 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5922 return Task::ready(Ok(None));
5923 }
5924 let request_timeout = ProjectSettings::get_global(cx)
5925 .global_lsp_settings
5926 .get_request_timeout();
5927 let request_task = upstream_client.request_lsp(
5928 project_id,
5929 None,
5930 request_timeout,
5931 cx.background_executor().clone(),
5932 request.to_proto(project_id, buffer.read(cx)),
5933 );
5934 let buffer = buffer.clone();
5935 cx.spawn(async move |weak_lsp_store, cx| {
5936 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5937 return Ok(None);
5938 };
5939 let Some(responses) = request_task.await? else {
5940 return Ok(None);
5941 };
5942 let actions = join_all(responses.payload.into_iter().map(|response| {
5943 GetDeclarations { position }.response_from_proto(
5944 response.response,
5945 lsp_store.clone(),
5946 buffer.clone(),
5947 cx.clone(),
5948 )
5949 }))
5950 .await;
5951
5952 Ok(Some(
5953 actions
5954 .into_iter()
5955 .collect::<Result<Vec<Vec<_>>>>()?
5956 .into_iter()
5957 .flatten()
5958 .dedup()
5959 .collect(),
5960 ))
5961 })
5962 } else {
5963 let declarations_task = self.request_multiple_lsp_locally(
5964 buffer,
5965 Some(position),
5966 GetDeclarations { position },
5967 cx,
5968 );
5969 cx.background_spawn(async move {
5970 Ok(Some(
5971 declarations_task
5972 .await
5973 .into_iter()
5974 .flat_map(|(_, declarations)| declarations)
5975 .dedup()
5976 .collect(),
5977 ))
5978 })
5979 }
5980 }
5981
5982 pub fn type_definitions(
5983 &mut self,
5984 buffer: &Entity<Buffer>,
5985 position: PointUtf16,
5986 cx: &mut Context<Self>,
5987 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5988 if let Some((upstream_client, project_id)) = self.upstream_client() {
5989 let request = GetTypeDefinitions { position };
5990 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5991 return Task::ready(Ok(None));
5992 }
5993 let request_timeout = ProjectSettings::get_global(cx)
5994 .global_lsp_settings
5995 .get_request_timeout();
5996 let request_task = upstream_client.request_lsp(
5997 project_id,
5998 None,
5999 request_timeout,
6000 cx.background_executor().clone(),
6001 request.to_proto(project_id, buffer.read(cx)),
6002 );
6003 let buffer = buffer.clone();
6004 cx.spawn(async move |weak_lsp_store, cx| {
6005 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6006 return Ok(None);
6007 };
6008 let Some(responses) = request_task.await? else {
6009 return Ok(None);
6010 };
6011 let actions = join_all(responses.payload.into_iter().map(|response| {
6012 GetTypeDefinitions { position }.response_from_proto(
6013 response.response,
6014 lsp_store.clone(),
6015 buffer.clone(),
6016 cx.clone(),
6017 )
6018 }))
6019 .await;
6020
6021 Ok(Some(
6022 actions
6023 .into_iter()
6024 .collect::<Result<Vec<Vec<_>>>>()?
6025 .into_iter()
6026 .flatten()
6027 .dedup()
6028 .collect(),
6029 ))
6030 })
6031 } else {
6032 let type_definitions_task = self.request_multiple_lsp_locally(
6033 buffer,
6034 Some(position),
6035 GetTypeDefinitions { position },
6036 cx,
6037 );
6038 cx.background_spawn(async move {
6039 Ok(Some(
6040 type_definitions_task
6041 .await
6042 .into_iter()
6043 .flat_map(|(_, type_definitions)| type_definitions)
6044 .dedup()
6045 .collect(),
6046 ))
6047 })
6048 }
6049 }
6050
6051 pub fn implementations(
6052 &mut self,
6053 buffer: &Entity<Buffer>,
6054 position: PointUtf16,
6055 cx: &mut Context<Self>,
6056 ) -> Task<Result<Option<Vec<LocationLink>>>> {
6057 if let Some((upstream_client, project_id)) = self.upstream_client() {
6058 let request = GetImplementations { position };
6059 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6060 return Task::ready(Ok(None));
6061 }
6062
6063 let request_timeout = ProjectSettings::get_global(cx)
6064 .global_lsp_settings
6065 .get_request_timeout();
6066 let request_task = upstream_client.request_lsp(
6067 project_id,
6068 None,
6069 request_timeout,
6070 cx.background_executor().clone(),
6071 request.to_proto(project_id, buffer.read(cx)),
6072 );
6073 let buffer = buffer.clone();
6074 cx.spawn(async move |weak_lsp_store, cx| {
6075 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6076 return Ok(None);
6077 };
6078 let Some(responses) = request_task.await? else {
6079 return Ok(None);
6080 };
6081 let actions = join_all(responses.payload.into_iter().map(|response| {
6082 GetImplementations { position }.response_from_proto(
6083 response.response,
6084 lsp_store.clone(),
6085 buffer.clone(),
6086 cx.clone(),
6087 )
6088 }))
6089 .await;
6090
6091 Ok(Some(
6092 actions
6093 .into_iter()
6094 .collect::<Result<Vec<Vec<_>>>>()?
6095 .into_iter()
6096 .flatten()
6097 .dedup()
6098 .collect(),
6099 ))
6100 })
6101 } else {
6102 let implementations_task = self.request_multiple_lsp_locally(
6103 buffer,
6104 Some(position),
6105 GetImplementations { position },
6106 cx,
6107 );
6108 cx.background_spawn(async move {
6109 Ok(Some(
6110 implementations_task
6111 .await
6112 .into_iter()
6113 .flat_map(|(_, implementations)| implementations)
6114 .dedup()
6115 .collect(),
6116 ))
6117 })
6118 }
6119 }
6120
6121 pub fn references(
6122 &mut self,
6123 buffer: &Entity<Buffer>,
6124 position: PointUtf16,
6125 cx: &mut Context<Self>,
6126 ) -> Task<Result<Option<Vec<Location>>>> {
6127 if let Some((upstream_client, project_id)) = self.upstream_client() {
6128 let request = GetReferences { position };
6129 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6130 return Task::ready(Ok(None));
6131 }
6132
6133 let request_timeout = ProjectSettings::get_global(cx)
6134 .global_lsp_settings
6135 .get_request_timeout();
6136 let request_task = upstream_client.request_lsp(
6137 project_id,
6138 None,
6139 request_timeout,
6140 cx.background_executor().clone(),
6141 request.to_proto(project_id, buffer.read(cx)),
6142 );
6143 let buffer = buffer.clone();
6144 cx.spawn(async move |weak_lsp_store, cx| {
6145 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6146 return Ok(None);
6147 };
6148 let Some(responses) = request_task.await? else {
6149 return Ok(None);
6150 };
6151
6152 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6153 GetReferences { position }.response_from_proto(
6154 lsp_response.response,
6155 lsp_store.clone(),
6156 buffer.clone(),
6157 cx.clone(),
6158 )
6159 }))
6160 .await
6161 .into_iter()
6162 .collect::<Result<Vec<Vec<_>>>>()?
6163 .into_iter()
6164 .flatten()
6165 .dedup()
6166 .collect();
6167 Ok(Some(locations))
6168 })
6169 } else {
6170 let references_task = self.request_multiple_lsp_locally(
6171 buffer,
6172 Some(position),
6173 GetReferences { position },
6174 cx,
6175 );
6176 cx.background_spawn(async move {
6177 Ok(Some(
6178 references_task
6179 .await
6180 .into_iter()
6181 .flat_map(|(_, references)| references)
6182 .dedup()
6183 .collect(),
6184 ))
6185 })
6186 }
6187 }
6188
6189 pub fn code_actions(
6190 &mut self,
6191 buffer: &Entity<Buffer>,
6192 range: Range<Anchor>,
6193 kinds: Option<Vec<CodeActionKind>>,
6194 cx: &mut Context<Self>,
6195 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6196 if let Some((upstream_client, project_id)) = self.upstream_client() {
6197 let request = GetCodeActions {
6198 range: range.clone(),
6199 kinds: kinds.clone(),
6200 };
6201 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6202 return Task::ready(Ok(None));
6203 }
6204 let request_timeout = ProjectSettings::get_global(cx)
6205 .global_lsp_settings
6206 .get_request_timeout();
6207 let request_task = upstream_client.request_lsp(
6208 project_id,
6209 None,
6210 request_timeout,
6211 cx.background_executor().clone(),
6212 request.to_proto(project_id, buffer.read(cx)),
6213 );
6214 let buffer = buffer.clone();
6215 cx.spawn(async move |weak_lsp_store, cx| {
6216 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6217 return Ok(None);
6218 };
6219 let Some(responses) = request_task.await? else {
6220 return Ok(None);
6221 };
6222 let actions = join_all(responses.payload.into_iter().map(|response| {
6223 GetCodeActions {
6224 range: range.clone(),
6225 kinds: kinds.clone(),
6226 }
6227 .response_from_proto(
6228 response.response,
6229 lsp_store.clone(),
6230 buffer.clone(),
6231 cx.clone(),
6232 )
6233 }))
6234 .await;
6235
6236 Ok(Some(
6237 actions
6238 .into_iter()
6239 .collect::<Result<Vec<Vec<_>>>>()?
6240 .into_iter()
6241 .flatten()
6242 .collect(),
6243 ))
6244 })
6245 } else {
6246 let all_actions_task = self.request_multiple_lsp_locally(
6247 buffer,
6248 Some(range.start),
6249 GetCodeActions { range, kinds },
6250 cx,
6251 );
6252 cx.background_spawn(async move {
6253 Ok(Some(
6254 all_actions_task
6255 .await
6256 .into_iter()
6257 .flat_map(|(_, actions)| actions)
6258 .collect(),
6259 ))
6260 })
6261 }
6262 }
6263
6264 #[inline(never)]
6265 pub fn completions(
6266 &self,
6267 buffer: &Entity<Buffer>,
6268 position: PointUtf16,
6269 context: CompletionContext,
6270 cx: &mut Context<Self>,
6271 ) -> Task<Result<Vec<CompletionResponse>>> {
6272 let language_registry = self.languages.clone();
6273
6274 if let Some((upstream_client, project_id)) = self.upstream_client() {
6275 let snapshot = buffer.read(cx).snapshot();
6276 let offset = position.to_offset(&snapshot);
6277 let scope = snapshot.language_scope_at(offset);
6278 let capable_lsps = self.all_capable_for_proto_request(
6279 buffer,
6280 |server_name, capabilities| {
6281 capabilities.completion_provider.is_some()
6282 && scope
6283 .as_ref()
6284 .map(|scope| scope.language_allowed(server_name))
6285 .unwrap_or(true)
6286 },
6287 cx,
6288 );
6289 if capable_lsps.is_empty() {
6290 return Task::ready(Ok(Vec::new()));
6291 }
6292
6293 let language = buffer.read(cx).language().cloned();
6294
6295 let buffer = buffer.clone();
6296
6297 cx.spawn(async move |this, cx| {
6298 let requests = join_all(
6299 capable_lsps
6300 .into_iter()
6301 .map(|(id, server_name)| {
6302 let request = GetCompletions {
6303 position,
6304 context: context.clone(),
6305 server_id: Some(id),
6306 };
6307 let buffer = buffer.clone();
6308 let language = language.clone();
6309 let lsp_adapter = language.as_ref().and_then(|language| {
6310 let adapters = language_registry.lsp_adapters(&language.name());
6311 adapters
6312 .iter()
6313 .find(|adapter| adapter.name() == server_name)
6314 .or_else(|| adapters.first())
6315 .cloned()
6316 });
6317 let upstream_client = upstream_client.clone();
6318 let response = this
6319 .update(cx, |this, cx| {
6320 this.send_lsp_proto_request(
6321 buffer,
6322 upstream_client,
6323 project_id,
6324 request,
6325 cx,
6326 )
6327 })
6328 .log_err();
6329 async move {
6330 let response = response?.await.log_err()?;
6331
6332 let completions = populate_labels_for_completions(
6333 response.completions,
6334 language,
6335 lsp_adapter,
6336 )
6337 .await;
6338
6339 Some(CompletionResponse {
6340 completions,
6341 display_options: CompletionDisplayOptions::default(),
6342 is_incomplete: response.is_incomplete,
6343 })
6344 }
6345 })
6346 .collect::<Vec<_>>(),
6347 );
6348 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6349 })
6350 } else if let Some(local) = self.as_local() {
6351 let snapshot = buffer.read(cx).snapshot();
6352 let offset = position.to_offset(&snapshot);
6353 let scope = snapshot.language_scope_at(offset);
6354 let language = snapshot.language().cloned();
6355 let completion_settings = LanguageSettings::for_buffer(&buffer.read(cx), cx)
6356 .completions
6357 .clone();
6358 if !completion_settings.lsp {
6359 return Task::ready(Ok(Vec::new()));
6360 }
6361
6362 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6363 local
6364 .language_servers_for_buffer(buffer, cx)
6365 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6366 .filter(|(adapter, _)| {
6367 scope
6368 .as_ref()
6369 .map(|scope| scope.language_allowed(&adapter.name))
6370 .unwrap_or(true)
6371 })
6372 .map(|(_, server)| server.server_id())
6373 .collect()
6374 });
6375
6376 let buffer = buffer.clone();
6377 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6378 let lsp_timeout = if lsp_timeout > 0 {
6379 Some(Duration::from_millis(lsp_timeout))
6380 } else {
6381 None
6382 };
6383 cx.spawn(async move |this, cx| {
6384 let mut tasks = Vec::with_capacity(server_ids.len());
6385 this.update(cx, |lsp_store, cx| {
6386 for server_id in server_ids {
6387 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6388 let lsp_timeout = lsp_timeout
6389 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6390 let mut timeout = cx.background_spawn(async move {
6391 match lsp_timeout {
6392 Some(lsp_timeout) => {
6393 lsp_timeout.await;
6394 true
6395 },
6396 None => false,
6397 }
6398 }).fuse();
6399 let mut lsp_request = lsp_store.request_lsp(
6400 buffer.clone(),
6401 LanguageServerToQuery::Other(server_id),
6402 GetCompletions {
6403 position,
6404 context: context.clone(),
6405 server_id: Some(server_id),
6406 },
6407 cx,
6408 ).fuse();
6409 let new_task = cx.background_spawn(async move {
6410 select_biased! {
6411 response = lsp_request => anyhow::Ok(Some(response?)),
6412 timeout_happened = timeout => {
6413 if timeout_happened {
6414 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6415 Ok(None)
6416 } else {
6417 let completions = lsp_request.await?;
6418 Ok(Some(completions))
6419 }
6420 },
6421 }
6422 });
6423 tasks.push((lsp_adapter, new_task));
6424 }
6425 })?;
6426
6427 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6428 let completion_response = task.await.ok()??;
6429 let completions = populate_labels_for_completions(
6430 completion_response.completions,
6431 language.clone(),
6432 lsp_adapter,
6433 )
6434 .await;
6435 Some(CompletionResponse {
6436 completions,
6437 display_options: CompletionDisplayOptions::default(),
6438 is_incomplete: completion_response.is_incomplete,
6439 })
6440 });
6441
6442 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6443
6444 Ok(responses.into_iter().flatten().collect())
6445 })
6446 } else {
6447 Task::ready(Err(anyhow!("No upstream client or local language server")))
6448 }
6449 }
6450
6451 pub fn resolve_completions(
6452 &self,
6453 buffer: Entity<Buffer>,
6454 completion_indices: Vec<usize>,
6455 completions: Rc<RefCell<Box<[Completion]>>>,
6456 cx: &mut Context<Self>,
6457 ) -> Task<Result<bool>> {
6458 let client = self.upstream_client();
6459 let buffer_id = buffer.read(cx).remote_id();
6460 let buffer_snapshot = buffer.read(cx).snapshot();
6461
6462 if !self.check_if_capable_for_proto_request(
6463 &buffer,
6464 GetCompletions::can_resolve_completions,
6465 cx,
6466 ) {
6467 return Task::ready(Ok(false));
6468 }
6469 cx.spawn(async move |lsp_store, cx| {
6470 let request_timeout = cx.update(|app| {
6471 ProjectSettings::get_global(app)
6472 .global_lsp_settings
6473 .get_request_timeout()
6474 });
6475
6476 let mut did_resolve = false;
6477 if let Some((client, project_id)) = client {
6478 for completion_index in completion_indices {
6479 let server_id = {
6480 let completion = &completions.borrow()[completion_index];
6481 completion.source.server_id()
6482 };
6483 if let Some(server_id) = server_id {
6484 if Self::resolve_completion_remote(
6485 project_id,
6486 server_id,
6487 buffer_id,
6488 completions.clone(),
6489 completion_index,
6490 client.clone(),
6491 )
6492 .await
6493 .log_err()
6494 .is_some()
6495 {
6496 did_resolve = true;
6497 }
6498 } else {
6499 resolve_word_completion(
6500 &buffer_snapshot,
6501 &mut completions.borrow_mut()[completion_index],
6502 );
6503 }
6504 }
6505 } else {
6506 for completion_index in completion_indices {
6507 let server_id = {
6508 let completion = &completions.borrow()[completion_index];
6509 completion.source.server_id()
6510 };
6511 if let Some(server_id) = server_id {
6512 let server_and_adapter = lsp_store
6513 .read_with(cx, |lsp_store, _| {
6514 let server = lsp_store.language_server_for_id(server_id)?;
6515 let adapter =
6516 lsp_store.language_server_adapter_for_id(server.server_id())?;
6517 Some((server, adapter))
6518 })
6519 .ok()
6520 .flatten();
6521 let Some((server, adapter)) = server_and_adapter else {
6522 continue;
6523 };
6524
6525 let resolved = Self::resolve_completion_local(
6526 server,
6527 completions.clone(),
6528 completion_index,
6529 request_timeout,
6530 )
6531 .await
6532 .log_err()
6533 .is_some();
6534 if resolved {
6535 Self::regenerate_completion_labels(
6536 adapter,
6537 &buffer_snapshot,
6538 completions.clone(),
6539 completion_index,
6540 )
6541 .await
6542 .log_err();
6543 did_resolve = true;
6544 }
6545 } else {
6546 resolve_word_completion(
6547 &buffer_snapshot,
6548 &mut completions.borrow_mut()[completion_index],
6549 );
6550 }
6551 }
6552 }
6553
6554 Ok(did_resolve)
6555 })
6556 }
6557
6558 async fn resolve_completion_local(
6559 server: Arc<lsp::LanguageServer>,
6560 completions: Rc<RefCell<Box<[Completion]>>>,
6561 completion_index: usize,
6562 request_timeout: Duration,
6563 ) -> Result<()> {
6564 let server_id = server.server_id();
6565 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6566 return Ok(());
6567 }
6568
6569 let request = {
6570 let completion = &completions.borrow()[completion_index];
6571 match &completion.source {
6572 CompletionSource::Lsp {
6573 lsp_completion,
6574 resolved,
6575 server_id: completion_server_id,
6576 ..
6577 } => {
6578 if *resolved {
6579 return Ok(());
6580 }
6581 anyhow::ensure!(
6582 server_id == *completion_server_id,
6583 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6584 );
6585 server.request::<lsp::request::ResolveCompletionItem>(
6586 *lsp_completion.clone(),
6587 request_timeout,
6588 )
6589 }
6590 CompletionSource::BufferWord { .. }
6591 | CompletionSource::Dap { .. }
6592 | CompletionSource::Custom => {
6593 return Ok(());
6594 }
6595 }
6596 };
6597 let resolved_completion = request
6598 .await
6599 .into_response()
6600 .context("resolve completion")?;
6601
6602 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6603 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6604
6605 let mut completions = completions.borrow_mut();
6606 let completion = &mut completions[completion_index];
6607 if let CompletionSource::Lsp {
6608 lsp_completion,
6609 resolved,
6610 server_id: completion_server_id,
6611 ..
6612 } = &mut completion.source
6613 {
6614 if *resolved {
6615 return Ok(());
6616 }
6617 anyhow::ensure!(
6618 server_id == *completion_server_id,
6619 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6620 );
6621 **lsp_completion = resolved_completion;
6622 *resolved = true;
6623 }
6624 Ok(())
6625 }
6626
6627 async fn regenerate_completion_labels(
6628 adapter: Arc<CachedLspAdapter>,
6629 snapshot: &BufferSnapshot,
6630 completions: Rc<RefCell<Box<[Completion]>>>,
6631 completion_index: usize,
6632 ) -> Result<()> {
6633 let completion_item = completions.borrow()[completion_index]
6634 .source
6635 .lsp_completion(true)
6636 .map(Cow::into_owned);
6637 if let Some(lsp_documentation) = completion_item
6638 .as_ref()
6639 .and_then(|completion_item| completion_item.documentation.clone())
6640 {
6641 let mut completions = completions.borrow_mut();
6642 let completion = &mut completions[completion_index];
6643 completion.documentation = Some(lsp_documentation.into());
6644 } else {
6645 let mut completions = completions.borrow_mut();
6646 let completion = &mut completions[completion_index];
6647 completion.documentation = Some(CompletionDocumentation::Undocumented);
6648 }
6649
6650 let mut new_label = match completion_item {
6651 Some(completion_item) => {
6652 // Some language servers always return `detail` lazily via resolve, regardless of
6653 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6654 // See: https://github.com/yioneko/vtsls/issues/213
6655 let language = snapshot.language();
6656 match language {
6657 Some(language) => {
6658 adapter
6659 .labels_for_completions(
6660 std::slice::from_ref(&completion_item),
6661 language,
6662 )
6663 .await?
6664 }
6665 None => Vec::new(),
6666 }
6667 .pop()
6668 .flatten()
6669 .unwrap_or_else(|| {
6670 CodeLabel::fallback_for_completion(
6671 &completion_item,
6672 language.map(|language| language.as_ref()),
6673 )
6674 })
6675 }
6676 None => CodeLabel::plain(
6677 completions.borrow()[completion_index].new_text.clone(),
6678 None,
6679 ),
6680 };
6681 ensure_uniform_list_compatible_label(&mut new_label);
6682
6683 let mut completions = completions.borrow_mut();
6684 let completion = &mut completions[completion_index];
6685 if completion.label.filter_text() == new_label.filter_text() {
6686 completion.label = new_label;
6687 } else {
6688 log::error!(
6689 "Resolved completion changed display label from {} to {}. \
6690 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6691 completion.label.text(),
6692 new_label.text(),
6693 completion.label.filter_text(),
6694 new_label.filter_text()
6695 );
6696 }
6697
6698 Ok(())
6699 }
6700
6701 async fn resolve_completion_remote(
6702 project_id: u64,
6703 server_id: LanguageServerId,
6704 buffer_id: BufferId,
6705 completions: Rc<RefCell<Box<[Completion]>>>,
6706 completion_index: usize,
6707 client: AnyProtoClient,
6708 ) -> Result<()> {
6709 let lsp_completion = {
6710 let completion = &completions.borrow()[completion_index];
6711 match &completion.source {
6712 CompletionSource::Lsp {
6713 lsp_completion,
6714 resolved,
6715 server_id: completion_server_id,
6716 ..
6717 } => {
6718 anyhow::ensure!(
6719 server_id == *completion_server_id,
6720 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6721 );
6722 if *resolved {
6723 return Ok(());
6724 }
6725 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6726 }
6727 CompletionSource::Custom
6728 | CompletionSource::Dap { .. }
6729 | CompletionSource::BufferWord { .. } => {
6730 return Ok(());
6731 }
6732 }
6733 };
6734 let request = proto::ResolveCompletionDocumentation {
6735 project_id,
6736 language_server_id: server_id.0 as u64,
6737 lsp_completion,
6738 buffer_id: buffer_id.into(),
6739 };
6740
6741 let response = client
6742 .request(request)
6743 .await
6744 .context("completion documentation resolve proto request")?;
6745 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6746
6747 let documentation = if response.documentation.is_empty() {
6748 CompletionDocumentation::Undocumented
6749 } else if response.documentation_is_markdown {
6750 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6751 } else if response.documentation.lines().count() <= 1 {
6752 CompletionDocumentation::SingleLine(response.documentation.into())
6753 } else {
6754 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6755 };
6756
6757 let mut completions = completions.borrow_mut();
6758 let completion = &mut completions[completion_index];
6759 completion.documentation = Some(documentation);
6760 if let CompletionSource::Lsp {
6761 insert_range,
6762 lsp_completion,
6763 resolved,
6764 server_id: completion_server_id,
6765 lsp_defaults: _,
6766 } = &mut completion.source
6767 {
6768 let completion_insert_range = response
6769 .old_insert_start
6770 .and_then(deserialize_anchor)
6771 .zip(response.old_insert_end.and_then(deserialize_anchor));
6772 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6773
6774 if *resolved {
6775 return Ok(());
6776 }
6777 anyhow::ensure!(
6778 server_id == *completion_server_id,
6779 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6780 );
6781 **lsp_completion = resolved_lsp_completion;
6782 *resolved = true;
6783 }
6784
6785 let replace_range = response
6786 .old_replace_start
6787 .and_then(deserialize_anchor)
6788 .zip(response.old_replace_end.and_then(deserialize_anchor));
6789 if let Some((old_replace_start, old_replace_end)) = replace_range
6790 && !response.new_text.is_empty()
6791 {
6792 completion.new_text = response.new_text;
6793 completion.replace_range = old_replace_start..old_replace_end;
6794 }
6795
6796 Ok(())
6797 }
6798
6799 pub fn apply_additional_edits_for_completion(
6800 &self,
6801 buffer_handle: Entity<Buffer>,
6802 completions: Rc<RefCell<Box<[Completion]>>>,
6803 completion_index: usize,
6804 push_to_history: bool,
6805 all_commit_ranges: Vec<Range<language::Anchor>>,
6806 cx: &mut Context<Self>,
6807 ) -> Task<Result<Option<Transaction>>> {
6808 if let Some((client, project_id)) = self.upstream_client() {
6809 let buffer = buffer_handle.read(cx);
6810 let buffer_id = buffer.remote_id();
6811 cx.spawn(async move |_, cx| {
6812 let request = {
6813 let completion = completions.borrow()[completion_index].clone();
6814 proto::ApplyCompletionAdditionalEdits {
6815 project_id,
6816 buffer_id: buffer_id.into(),
6817 completion: Some(Self::serialize_completion(&CoreCompletion {
6818 replace_range: completion.replace_range,
6819 new_text: completion.new_text,
6820 source: completion.source,
6821 })),
6822 all_commit_ranges: all_commit_ranges
6823 .iter()
6824 .cloned()
6825 .map(language::proto::serialize_anchor_range)
6826 .collect(),
6827 }
6828 };
6829
6830 let Some(transaction) = client.request(request).await?.transaction else {
6831 return Ok(None);
6832 };
6833
6834 let transaction = language::proto::deserialize_transaction(transaction)?;
6835 buffer_handle
6836 .update(cx, |buffer, _| {
6837 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6838 })
6839 .await?;
6840 if push_to_history {
6841 buffer_handle.update(cx, |buffer, _| {
6842 buffer.push_transaction(transaction.clone(), Instant::now());
6843 buffer.finalize_last_transaction();
6844 });
6845 }
6846 Ok(Some(transaction))
6847 })
6848 } else {
6849 let request_timeout = ProjectSettings::get_global(cx)
6850 .global_lsp_settings
6851 .get_request_timeout();
6852
6853 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6854 let completion = &completions.borrow()[completion_index];
6855 let server_id = completion.source.server_id()?;
6856 Some(
6857 self.language_server_for_local_buffer(buffer, server_id, cx)?
6858 .1
6859 .clone(),
6860 )
6861 }) else {
6862 return Task::ready(Ok(None));
6863 };
6864
6865 cx.spawn(async move |this, cx| {
6866 Self::resolve_completion_local(
6867 server.clone(),
6868 completions.clone(),
6869 completion_index,
6870 request_timeout,
6871 )
6872 .await
6873 .context("resolving completion")?;
6874 let completion = completions.borrow()[completion_index].clone();
6875 let additional_text_edits = completion
6876 .source
6877 .lsp_completion(true)
6878 .as_ref()
6879 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6880 if let Some(edits) = additional_text_edits {
6881 let edits = this
6882 .update(cx, |this, cx| {
6883 this.as_local_mut().unwrap().edits_from_lsp(
6884 &buffer_handle,
6885 edits,
6886 server.server_id(),
6887 None,
6888 cx,
6889 )
6890 })?
6891 .await?;
6892
6893 buffer_handle.update(cx, |buffer, cx| {
6894 buffer.finalize_last_transaction();
6895 buffer.start_transaction();
6896
6897 for (range, text) in edits {
6898 let primary = &completion.replace_range;
6899
6900 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6901 // and the primary completion is just an insertion (empty range), then this is likely
6902 // an auto-import scenario and should not be considered overlapping
6903 // https://github.com/zed-industries/zed/issues/26136
6904 let is_file_start_auto_import = {
6905 let snapshot = buffer.snapshot();
6906 let primary_start_point = primary.start.to_point(&snapshot);
6907 let range_start_point = range.start.to_point(&snapshot);
6908
6909 let result = primary_start_point.row == 0
6910 && primary_start_point.column == 0
6911 && range_start_point.row == 0
6912 && range_start_point.column == 0;
6913
6914 result
6915 };
6916
6917 let has_overlap = if is_file_start_auto_import {
6918 false
6919 } else {
6920 all_commit_ranges.iter().any(|commit_range| {
6921 let start_within =
6922 commit_range.start.cmp(&range.start, buffer).is_le()
6923 && commit_range.end.cmp(&range.start, buffer).is_ge();
6924 let end_within =
6925 range.start.cmp(&commit_range.end, buffer).is_le()
6926 && range.end.cmp(&commit_range.end, buffer).is_ge();
6927 start_within || end_within
6928 })
6929 };
6930
6931 //Skip additional edits which overlap with the primary completion edit
6932 //https://github.com/zed-industries/zed/pull/1871
6933 if !has_overlap {
6934 buffer.edit([(range, text)], None, cx);
6935 }
6936 }
6937
6938 let transaction = if buffer.end_transaction(cx).is_some() {
6939 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6940 if !push_to_history {
6941 buffer.forget_transaction(transaction.id);
6942 }
6943 Some(transaction)
6944 } else {
6945 None
6946 };
6947 Ok(transaction)
6948 })
6949 } else {
6950 Ok(None)
6951 }
6952 })
6953 }
6954 }
6955
6956 pub fn pull_diagnostics(
6957 &mut self,
6958 buffer: Entity<Buffer>,
6959 cx: &mut Context<Self>,
6960 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6961 let buffer_id = buffer.read(cx).remote_id();
6962
6963 if let Some((client, upstream_project_id)) = self.upstream_client() {
6964 let mut suitable_capabilities = None;
6965 // Are we capable for proto request?
6966 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6967 &buffer,
6968 |capabilities| {
6969 if let Some(caps) = &capabilities.diagnostic_provider {
6970 suitable_capabilities = Some(caps.clone());
6971 true
6972 } else {
6973 false
6974 }
6975 },
6976 cx,
6977 );
6978 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6979 let Some(dynamic_caps) = suitable_capabilities else {
6980 return Task::ready(Ok(None));
6981 };
6982 assert!(any_server_has_diagnostics_provider);
6983
6984 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6985 let request = GetDocumentDiagnostics {
6986 previous_result_id: None,
6987 identifier,
6988 registration_id: None,
6989 };
6990 let request_timeout = ProjectSettings::get_global(cx)
6991 .global_lsp_settings
6992 .get_request_timeout();
6993 let request_task = client.request_lsp(
6994 upstream_project_id,
6995 None,
6996 request_timeout,
6997 cx.background_executor().clone(),
6998 request.to_proto(upstream_project_id, buffer.read(cx)),
6999 );
7000 cx.background_spawn(async move {
7001 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
7002 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
7003 // Do not attempt to further process the dummy responses here.
7004 let _response = request_task.await?;
7005 Ok(None)
7006 })
7007 } else {
7008 let servers = buffer.update(cx, |buffer, cx| {
7009 self.running_language_servers_for_local_buffer(buffer, cx)
7010 .map(|(_, server)| server.clone())
7011 .collect::<Vec<_>>()
7012 });
7013
7014 let pull_diagnostics = servers
7015 .into_iter()
7016 .flat_map(|server| {
7017 let result = maybe!({
7018 let local = self.as_local()?;
7019 let server_id = server.server_id();
7020 let providers_with_identifiers = local
7021 .language_server_dynamic_registrations
7022 .get(&server_id)
7023 .into_iter()
7024 .flat_map(|registrations| registrations.diagnostics.clone())
7025 .collect::<Vec<_>>();
7026 Some(
7027 providers_with_identifiers
7028 .into_iter()
7029 .map(|(registration_id, dynamic_caps)| {
7030 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
7031 let registration_id = registration_id.map(SharedString::from);
7032 let result_id = self.result_id_for_buffer_pull(
7033 server_id,
7034 buffer_id,
7035 ®istration_id,
7036 cx,
7037 );
7038 self.request_lsp(
7039 buffer.clone(),
7040 LanguageServerToQuery::Other(server_id),
7041 GetDocumentDiagnostics {
7042 previous_result_id: result_id,
7043 registration_id,
7044 identifier,
7045 },
7046 cx,
7047 )
7048 })
7049 .collect::<Vec<_>>(),
7050 )
7051 });
7052
7053 result.unwrap_or_default()
7054 })
7055 .collect::<Vec<_>>();
7056
7057 cx.background_spawn(async move {
7058 let mut responses = Vec::new();
7059 for diagnostics in join_all(pull_diagnostics).await {
7060 responses.extend(diagnostics?);
7061 }
7062 Ok(Some(responses))
7063 })
7064 }
7065 }
7066
7067 pub fn applicable_inlay_chunks(
7068 &mut self,
7069 buffer: &Entity<Buffer>,
7070 ranges: &[Range<text::Anchor>],
7071 cx: &mut Context<Self>,
7072 ) -> Vec<Range<BufferRow>> {
7073 let buffer_snapshot = buffer.read(cx).snapshot();
7074 let ranges = ranges
7075 .iter()
7076 .map(|range| range.to_point(&buffer_snapshot))
7077 .collect::<Vec<_>>();
7078
7079 self.latest_lsp_data(buffer, cx)
7080 .inlay_hints
7081 .applicable_chunks(ranges.as_slice())
7082 .map(|chunk| chunk.row_range())
7083 .collect()
7084 }
7085
7086 pub fn invalidate_inlay_hints<'a>(
7087 &'a mut self,
7088 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
7089 ) {
7090 for buffer_id in for_buffers {
7091 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
7092 lsp_data.inlay_hints.clear();
7093 }
7094 }
7095 }
7096
7097 pub fn inlay_hints(
7098 &mut self,
7099 invalidate: InvalidationStrategy,
7100 buffer: Entity<Buffer>,
7101 ranges: Vec<Range<text::Anchor>>,
7102 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
7103 cx: &mut Context<Self>,
7104 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
7105 let next_hint_id = self.next_hint_id.clone();
7106 let lsp_data = self.latest_lsp_data(&buffer, cx);
7107 let query_version = lsp_data.buffer_version.clone();
7108 let mut lsp_refresh_requested = false;
7109 let for_server = if let InvalidationStrategy::RefreshRequested {
7110 server_id,
7111 request_id,
7112 } = invalidate
7113 {
7114 let invalidated = lsp_data
7115 .inlay_hints
7116 .invalidate_for_server_refresh(server_id, request_id);
7117 lsp_refresh_requested = invalidated;
7118 Some(server_id)
7119 } else {
7120 None
7121 };
7122 let existing_inlay_hints = &mut lsp_data.inlay_hints;
7123 let known_chunks = known_chunks
7124 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
7125 .map(|(_, known_chunks)| known_chunks)
7126 .unwrap_or_default();
7127
7128 let buffer_snapshot = buffer.read(cx).snapshot();
7129 let ranges = ranges
7130 .iter()
7131 .map(|range| range.to_point(&buffer_snapshot))
7132 .collect::<Vec<_>>();
7133
7134 let mut hint_fetch_tasks = Vec::new();
7135 let mut cached_inlay_hints = None;
7136 let mut ranges_to_query = None;
7137 let applicable_chunks = existing_inlay_hints
7138 .applicable_chunks(ranges.as_slice())
7139 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7140 .collect::<Vec<_>>();
7141 if applicable_chunks.is_empty() {
7142 return HashMap::default();
7143 }
7144
7145 for row_chunk in applicable_chunks {
7146 match (
7147 existing_inlay_hints
7148 .cached_hints(&row_chunk)
7149 .filter(|_| !lsp_refresh_requested)
7150 .cloned(),
7151 existing_inlay_hints
7152 .fetched_hints(&row_chunk)
7153 .as_ref()
7154 .filter(|_| !lsp_refresh_requested)
7155 .cloned(),
7156 ) {
7157 (None, None) => {
7158 let chunk_range = row_chunk.anchor_range();
7159 ranges_to_query
7160 .get_or_insert_with(Vec::new)
7161 .push((row_chunk, chunk_range));
7162 }
7163 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7164 (Some(cached_hints), None) => {
7165 for (server_id, cached_hints) in cached_hints {
7166 if for_server.is_none_or(|for_server| for_server == server_id) {
7167 cached_inlay_hints
7168 .get_or_insert_with(HashMap::default)
7169 .entry(row_chunk.row_range())
7170 .or_insert_with(HashMap::default)
7171 .entry(server_id)
7172 .or_insert_with(Vec::new)
7173 .extend(cached_hints);
7174 }
7175 }
7176 }
7177 (Some(cached_hints), Some(fetched_hints)) => {
7178 hint_fetch_tasks.push((row_chunk, fetched_hints));
7179 for (server_id, cached_hints) in cached_hints {
7180 if for_server.is_none_or(|for_server| for_server == server_id) {
7181 cached_inlay_hints
7182 .get_or_insert_with(HashMap::default)
7183 .entry(row_chunk.row_range())
7184 .or_insert_with(HashMap::default)
7185 .entry(server_id)
7186 .or_insert_with(Vec::new)
7187 .extend(cached_hints);
7188 }
7189 }
7190 }
7191 }
7192 }
7193
7194 if hint_fetch_tasks.is_empty()
7195 && ranges_to_query
7196 .as_ref()
7197 .is_none_or(|ranges| ranges.is_empty())
7198 && let Some(cached_inlay_hints) = cached_inlay_hints
7199 {
7200 cached_inlay_hints
7201 .into_iter()
7202 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7203 .collect()
7204 } else {
7205 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7206 // When a server refresh was requested, other servers' cached hints
7207 // are unaffected by the refresh and must be included in the result.
7208 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7209 // removes all visible hints but only adds back the requesting
7210 // server's new hints, permanently losing other servers' hints.
7211 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7212 lsp_data
7213 .inlay_hints
7214 .cached_hints(&chunk)
7215 .cloned()
7216 .unwrap_or_default()
7217 } else {
7218 HashMap::default()
7219 };
7220
7221 let next_hint_id = next_hint_id.clone();
7222 let buffer = buffer.clone();
7223 let query_version = query_version.clone();
7224 let new_inlay_hints = cx
7225 .spawn(async move |lsp_store, cx| {
7226 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7227 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7228 })?;
7229 new_fetch_task
7230 .await
7231 .and_then(|new_hints_by_server| {
7232 lsp_store.update(cx, |lsp_store, cx| {
7233 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7234 let update_cache = lsp_data.buffer_version == query_version;
7235 if new_hints_by_server.is_empty() {
7236 if update_cache {
7237 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7238 }
7239 other_servers_cached
7240 } else {
7241 let mut result = other_servers_cached;
7242 for (server_id, new_hints) in new_hints_by_server {
7243 let new_hints = new_hints
7244 .into_iter()
7245 .map(|new_hint| {
7246 (
7247 InlayId::Hint(next_hint_id.fetch_add(
7248 1,
7249 atomic::Ordering::AcqRel,
7250 )),
7251 new_hint,
7252 )
7253 })
7254 .collect::<Vec<_>>();
7255 if update_cache {
7256 lsp_data.inlay_hints.insert_new_hints(
7257 chunk,
7258 server_id,
7259 new_hints.clone(),
7260 );
7261 }
7262 result.insert(server_id, new_hints);
7263 }
7264 result
7265 }
7266 })
7267 })
7268 .map_err(Arc::new)
7269 })
7270 .shared();
7271
7272 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7273 *fetch_task = Some(new_inlay_hints.clone());
7274 hint_fetch_tasks.push((chunk, new_inlay_hints));
7275 }
7276
7277 cached_inlay_hints
7278 .unwrap_or_default()
7279 .into_iter()
7280 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7281 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7282 (
7283 chunk.row_range(),
7284 cx.spawn(async move |_, _| {
7285 hints_fetch.await.map_err(|e| {
7286 if e.error_code() != ErrorCode::Internal {
7287 anyhow!(e.error_code())
7288 } else {
7289 anyhow!("{e:#}")
7290 }
7291 })
7292 }),
7293 )
7294 }))
7295 .collect()
7296 }
7297 }
7298
7299 fn fetch_inlay_hints(
7300 &mut self,
7301 for_server: Option<LanguageServerId>,
7302 buffer: &Entity<Buffer>,
7303 range: Range<Anchor>,
7304 cx: &mut Context<Self>,
7305 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7306 let request = InlayHints {
7307 range: range.clone(),
7308 };
7309 if let Some((upstream_client, project_id)) = self.upstream_client() {
7310 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7311 return Task::ready(Ok(HashMap::default()));
7312 }
7313 let request_timeout = ProjectSettings::get_global(cx)
7314 .global_lsp_settings
7315 .get_request_timeout();
7316 let request_task = upstream_client.request_lsp(
7317 project_id,
7318 for_server.map(|id| id.to_proto()),
7319 request_timeout,
7320 cx.background_executor().clone(),
7321 request.to_proto(project_id, buffer.read(cx)),
7322 );
7323 let buffer = buffer.clone();
7324 cx.spawn(async move |weak_lsp_store, cx| {
7325 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7326 return Ok(HashMap::default());
7327 };
7328 let Some(responses) = request_task.await? else {
7329 return Ok(HashMap::default());
7330 };
7331
7332 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7333 let lsp_store = lsp_store.clone();
7334 let buffer = buffer.clone();
7335 let cx = cx.clone();
7336 let request = request.clone();
7337 async move {
7338 (
7339 LanguageServerId::from_proto(response.server_id),
7340 request
7341 .response_from_proto(response.response, lsp_store, buffer, cx)
7342 .await,
7343 )
7344 }
7345 }))
7346 .await;
7347
7348 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7349 let mut has_errors = false;
7350 let inlay_hints = inlay_hints
7351 .into_iter()
7352 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7353 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7354 Err(e) => {
7355 has_errors = true;
7356 log::error!("{e:#}");
7357 None
7358 }
7359 })
7360 .map(|(server_id, mut new_hints)| {
7361 new_hints.retain(|hint| {
7362 hint.position.is_valid(&buffer_snapshot)
7363 && range.start.is_valid(&buffer_snapshot)
7364 && range.end.is_valid(&buffer_snapshot)
7365 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7366 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7367 });
7368 (server_id, new_hints)
7369 })
7370 .collect::<HashMap<_, _>>();
7371 anyhow::ensure!(
7372 !has_errors || !inlay_hints.is_empty(),
7373 "Failed to fetch inlay hints"
7374 );
7375 Ok(inlay_hints)
7376 })
7377 } else {
7378 let inlay_hints_task = match for_server {
7379 Some(server_id) => {
7380 let server_task = self.request_lsp(
7381 buffer.clone(),
7382 LanguageServerToQuery::Other(server_id),
7383 request,
7384 cx,
7385 );
7386 cx.background_spawn(async move {
7387 let mut responses = Vec::new();
7388 match server_task.await {
7389 Ok(response) => responses.push((server_id, response)),
7390 // rust-analyzer likes to error with this when its still loading up
7391 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7392 Err(e) => log::error!(
7393 "Error handling response for inlay hints request: {e:#}"
7394 ),
7395 }
7396 responses
7397 })
7398 }
7399 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7400 };
7401 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7402 cx.background_spawn(async move {
7403 Ok(inlay_hints_task
7404 .await
7405 .into_iter()
7406 .map(|(server_id, mut new_hints)| {
7407 new_hints.retain(|hint| {
7408 hint.position.is_valid(&buffer_snapshot)
7409 && range.start.is_valid(&buffer_snapshot)
7410 && range.end.is_valid(&buffer_snapshot)
7411 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7412 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7413 });
7414 (server_id, new_hints)
7415 })
7416 .collect())
7417 })
7418 }
7419 }
7420
7421 fn diagnostic_registration_exists(
7422 &self,
7423 server_id: LanguageServerId,
7424 registration_id: &Option<SharedString>,
7425 ) -> bool {
7426 let Some(local) = self.as_local() else {
7427 return false;
7428 };
7429 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7430 else {
7431 return false;
7432 };
7433 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7434 registrations.diagnostics.contains_key(®istration_key)
7435 }
7436
7437 pub fn pull_diagnostics_for_buffer(
7438 &mut self,
7439 buffer: Entity<Buffer>,
7440 cx: &mut Context<Self>,
7441 ) -> Task<anyhow::Result<()>> {
7442 let diagnostics = self.pull_diagnostics(buffer, cx);
7443 cx.spawn(async move |lsp_store, cx| {
7444 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7445 return Ok(());
7446 };
7447 lsp_store.update(cx, |lsp_store, cx| {
7448 if lsp_store.as_local().is_none() {
7449 return;
7450 }
7451
7452 let mut unchanged_buffers = HashMap::default();
7453 let server_diagnostics_updates = diagnostics
7454 .into_iter()
7455 .filter_map(|diagnostics_set| match diagnostics_set {
7456 LspPullDiagnostics::Response {
7457 server_id,
7458 uri,
7459 diagnostics,
7460 registration_id,
7461 } => Some((server_id, uri, diagnostics, registration_id)),
7462 LspPullDiagnostics::Default => None,
7463 })
7464 .filter(|(server_id, _, _, registration_id)| {
7465 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7466 })
7467 .fold(
7468 HashMap::default(),
7469 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7470 let (result_id, diagnostics) = match diagnostics {
7471 PulledDiagnostics::Unchanged { result_id } => {
7472 unchanged_buffers
7473 .entry(new_registration_id.clone())
7474 .or_insert_with(HashSet::default)
7475 .insert(uri.clone());
7476 (Some(result_id), Vec::new())
7477 }
7478 PulledDiagnostics::Changed {
7479 result_id,
7480 diagnostics,
7481 } => (result_id, diagnostics),
7482 };
7483 let disk_based_sources = Cow::Owned(
7484 lsp_store
7485 .language_server_adapter_for_id(server_id)
7486 .as_ref()
7487 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7488 .unwrap_or(&[])
7489 .to_vec(),
7490 );
7491 acc.entry(server_id)
7492 .or_insert_with(HashMap::default)
7493 .entry(new_registration_id.clone())
7494 .or_insert_with(Vec::new)
7495 .push(DocumentDiagnosticsUpdate {
7496 server_id,
7497 diagnostics: lsp::PublishDiagnosticsParams {
7498 uri,
7499 diagnostics,
7500 version: None,
7501 },
7502 result_id: result_id.map(SharedString::new),
7503 disk_based_sources,
7504 registration_id: new_registration_id,
7505 });
7506 acc
7507 },
7508 );
7509
7510 for diagnostic_updates in server_diagnostics_updates.into_values() {
7511 for (registration_id, diagnostic_updates) in diagnostic_updates {
7512 lsp_store
7513 .merge_lsp_diagnostics(
7514 DiagnosticSourceKind::Pulled,
7515 diagnostic_updates,
7516 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7517 DiagnosticSourceKind::Pulled => {
7518 old_diagnostic.registration_id != registration_id
7519 || unchanged_buffers
7520 .get(&old_diagnostic.registration_id)
7521 .is_some_and(|unchanged_buffers| {
7522 unchanged_buffers.contains(&document_uri)
7523 })
7524 }
7525 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7526 true
7527 }
7528 },
7529 cx,
7530 )
7531 .log_err();
7532 }
7533 }
7534 })
7535 })
7536 }
7537
7538 pub fn signature_help<T: ToPointUtf16>(
7539 &mut self,
7540 buffer: &Entity<Buffer>,
7541 position: T,
7542 cx: &mut Context<Self>,
7543 ) -> Task<Option<Vec<SignatureHelp>>> {
7544 let position = position.to_point_utf16(buffer.read(cx));
7545
7546 if let Some((client, upstream_project_id)) = self.upstream_client() {
7547 let request = GetSignatureHelp { position };
7548 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7549 return Task::ready(None);
7550 }
7551 let request_timeout = ProjectSettings::get_global(cx)
7552 .global_lsp_settings
7553 .get_request_timeout();
7554 let request_task = client.request_lsp(
7555 upstream_project_id,
7556 None,
7557 request_timeout,
7558 cx.background_executor().clone(),
7559 request.to_proto(upstream_project_id, buffer.read(cx)),
7560 );
7561 let buffer = buffer.clone();
7562 cx.spawn(async move |weak_lsp_store, cx| {
7563 let lsp_store = weak_lsp_store.upgrade()?;
7564 let signatures = join_all(
7565 request_task
7566 .await
7567 .log_err()
7568 .flatten()
7569 .map(|response| response.payload)
7570 .unwrap_or_default()
7571 .into_iter()
7572 .map(|response| {
7573 let response = GetSignatureHelp { position }.response_from_proto(
7574 response.response,
7575 lsp_store.clone(),
7576 buffer.clone(),
7577 cx.clone(),
7578 );
7579 async move { response.await.log_err().flatten() }
7580 }),
7581 )
7582 .await
7583 .into_iter()
7584 .flatten()
7585 .collect();
7586 Some(signatures)
7587 })
7588 } else {
7589 let all_actions_task = self.request_multiple_lsp_locally(
7590 buffer,
7591 Some(position),
7592 GetSignatureHelp { position },
7593 cx,
7594 );
7595 cx.background_spawn(async move {
7596 Some(
7597 all_actions_task
7598 .await
7599 .into_iter()
7600 .flat_map(|(_, actions)| actions)
7601 .collect::<Vec<_>>(),
7602 )
7603 })
7604 }
7605 }
7606
7607 pub fn hover(
7608 &mut self,
7609 buffer: &Entity<Buffer>,
7610 position: PointUtf16,
7611 cx: &mut Context<Self>,
7612 ) -> Task<Option<Vec<Hover>>> {
7613 if let Some((client, upstream_project_id)) = self.upstream_client() {
7614 let request = GetHover { position };
7615 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7616 return Task::ready(None);
7617 }
7618 let request_timeout = ProjectSettings::get_global(cx)
7619 .global_lsp_settings
7620 .get_request_timeout();
7621 let request_task = client.request_lsp(
7622 upstream_project_id,
7623 None,
7624 request_timeout,
7625 cx.background_executor().clone(),
7626 request.to_proto(upstream_project_id, buffer.read(cx)),
7627 );
7628 let buffer = buffer.clone();
7629 cx.spawn(async move |weak_lsp_store, cx| {
7630 let lsp_store = weak_lsp_store.upgrade()?;
7631 let hovers = join_all(
7632 request_task
7633 .await
7634 .log_err()
7635 .flatten()
7636 .map(|response| response.payload)
7637 .unwrap_or_default()
7638 .into_iter()
7639 .map(|response| {
7640 let response = GetHover { position }.response_from_proto(
7641 response.response,
7642 lsp_store.clone(),
7643 buffer.clone(),
7644 cx.clone(),
7645 );
7646 async move {
7647 response
7648 .await
7649 .log_err()
7650 .flatten()
7651 .and_then(remove_empty_hover_blocks)
7652 }
7653 }),
7654 )
7655 .await
7656 .into_iter()
7657 .flatten()
7658 .collect();
7659 Some(hovers)
7660 })
7661 } else {
7662 let all_actions_task = self.request_multiple_lsp_locally(
7663 buffer,
7664 Some(position),
7665 GetHover { position },
7666 cx,
7667 );
7668 cx.background_spawn(async move {
7669 Some(
7670 all_actions_task
7671 .await
7672 .into_iter()
7673 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7674 .collect::<Vec<Hover>>(),
7675 )
7676 })
7677 }
7678 }
7679
7680 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7681 let language_registry = self.languages.clone();
7682
7683 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7684 let request = upstream_client.request(proto::GetProjectSymbols {
7685 project_id: *project_id,
7686 query: query.to_string(),
7687 });
7688 cx.foreground_executor().spawn(async move {
7689 let response = request.await?;
7690 let mut symbols = Vec::new();
7691 let core_symbols = response
7692 .symbols
7693 .into_iter()
7694 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7695 .collect::<Vec<_>>();
7696 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7697 .await;
7698 Ok(symbols)
7699 })
7700 } else if let Some(local) = self.as_local() {
7701 struct WorkspaceSymbolsResult {
7702 server_id: LanguageServerId,
7703 lsp_adapter: Arc<CachedLspAdapter>,
7704 worktree: WeakEntity<Worktree>,
7705 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7706 }
7707
7708 let mut requests = Vec::new();
7709 let mut requested_servers = BTreeSet::new();
7710 let request_timeout = ProjectSettings::get_global(cx)
7711 .global_lsp_settings
7712 .get_request_timeout();
7713
7714 for (seed, state) in local.language_server_ids.iter() {
7715 let Some(worktree_handle) = self
7716 .worktree_store
7717 .read(cx)
7718 .worktree_for_id(seed.worktree_id, cx)
7719 else {
7720 continue;
7721 };
7722
7723 let worktree = worktree_handle.read(cx);
7724 if !worktree.is_visible() {
7725 continue;
7726 }
7727
7728 if !requested_servers.insert(state.id) {
7729 continue;
7730 }
7731
7732 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7733 Some(LanguageServerState::Running {
7734 adapter, server, ..
7735 }) => (adapter.clone(), server),
7736
7737 _ => continue,
7738 };
7739
7740 let supports_workspace_symbol_request =
7741 match server.capabilities().workspace_symbol_provider {
7742 Some(OneOf::Left(supported)) => supported,
7743 Some(OneOf::Right(_)) => true,
7744 None => false,
7745 };
7746
7747 if !supports_workspace_symbol_request {
7748 continue;
7749 }
7750
7751 let worktree_handle = worktree_handle.clone();
7752 let server_id = server.server_id();
7753 requests.push(
7754 server
7755 .request::<lsp::request::WorkspaceSymbolRequest>(
7756 lsp::WorkspaceSymbolParams {
7757 query: query.to_string(),
7758 ..Default::default()
7759 },
7760 request_timeout,
7761 )
7762 .map(move |response| {
7763 let lsp_symbols = response
7764 .into_response()
7765 .context("workspace symbols request")
7766 .log_err()
7767 .flatten()
7768 .map(|symbol_response| match symbol_response {
7769 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7770 flat_responses
7771 .into_iter()
7772 .map(|lsp_symbol| {
7773 (
7774 lsp_symbol.name,
7775 lsp_symbol.kind,
7776 lsp_symbol.location,
7777 lsp_symbol.container_name,
7778 )
7779 })
7780 .collect::<Vec<_>>()
7781 }
7782 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7783 nested_responses
7784 .into_iter()
7785 .filter_map(|lsp_symbol| {
7786 let location = match lsp_symbol.location {
7787 OneOf::Left(location) => location,
7788 OneOf::Right(_) => {
7789 log::error!(
7790 "Unexpected: client capabilities \
7791 forbid symbol resolutions in \
7792 workspace.symbol.resolveSupport"
7793 );
7794 return None;
7795 }
7796 };
7797 Some((
7798 lsp_symbol.name,
7799 lsp_symbol.kind,
7800 location,
7801 lsp_symbol.container_name,
7802 ))
7803 })
7804 .collect::<Vec<_>>()
7805 }
7806 })
7807 .unwrap_or_default();
7808
7809 WorkspaceSymbolsResult {
7810 server_id,
7811 lsp_adapter,
7812 worktree: worktree_handle.downgrade(),
7813 lsp_symbols,
7814 }
7815 }),
7816 );
7817 }
7818
7819 cx.spawn(async move |this, cx| {
7820 let responses = futures::future::join_all(requests).await;
7821 let this = match this.upgrade() {
7822 Some(this) => this,
7823 None => return Ok(Vec::new()),
7824 };
7825
7826 let mut symbols = Vec::new();
7827 for result in responses {
7828 let core_symbols = this.update(cx, |this, cx| {
7829 result
7830 .lsp_symbols
7831 .into_iter()
7832 .filter_map(
7833 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7834 let abs_path = symbol_location.uri.to_file_path().ok()?;
7835 let source_worktree = result.worktree.upgrade()?;
7836 let source_worktree_id = source_worktree.read(cx).id();
7837
7838 let path = if let Some((tree, rel_path)) =
7839 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7840 {
7841 let worktree_id = tree.read(cx).id();
7842 SymbolLocation::InProject(ProjectPath {
7843 worktree_id,
7844 path: rel_path,
7845 })
7846 } else {
7847 SymbolLocation::OutsideProject {
7848 signature: this.symbol_signature(&abs_path),
7849 abs_path: abs_path.into(),
7850 }
7851 };
7852
7853 Some(CoreSymbol {
7854 source_language_server_id: result.server_id,
7855 language_server_name: result.lsp_adapter.name.clone(),
7856 source_worktree_id,
7857 path,
7858 kind: symbol_kind,
7859 name: collapse_newlines(&symbol_name, "↵ "),
7860 range: range_from_lsp(symbol_location.range),
7861 container_name: container_name
7862 .map(|c| collapse_newlines(&c, "↵ ")),
7863 })
7864 },
7865 )
7866 .collect::<Vec<_>>()
7867 });
7868
7869 populate_labels_for_symbols(
7870 core_symbols,
7871 &language_registry,
7872 Some(result.lsp_adapter),
7873 &mut symbols,
7874 )
7875 .await;
7876 }
7877
7878 Ok(symbols)
7879 })
7880 } else {
7881 Task::ready(Err(anyhow!("No upstream client or local language server")))
7882 }
7883 }
7884
7885 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7886 let mut summary = DiagnosticSummary::default();
7887 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7888 summary.error_count += path_summary.error_count;
7889 summary.warning_count += path_summary.warning_count;
7890 }
7891 summary
7892 }
7893
7894 /// Returns the diagnostic summary for a specific project path.
7895 pub fn diagnostic_summary_for_path(
7896 &self,
7897 project_path: &ProjectPath,
7898 _: &App,
7899 ) -> DiagnosticSummary {
7900 if let Some(summaries) = self
7901 .diagnostic_summaries
7902 .get(&project_path.worktree_id)
7903 .and_then(|map| map.get(&project_path.path))
7904 {
7905 let (error_count, warning_count) = summaries.iter().fold(
7906 (0, 0),
7907 |(error_count, warning_count), (_language_server_id, summary)| {
7908 (
7909 error_count + summary.error_count,
7910 warning_count + summary.warning_count,
7911 )
7912 },
7913 );
7914
7915 DiagnosticSummary {
7916 error_count,
7917 warning_count,
7918 }
7919 } else {
7920 DiagnosticSummary::default()
7921 }
7922 }
7923
7924 pub fn diagnostic_summaries<'a>(
7925 &'a self,
7926 include_ignored: bool,
7927 cx: &'a App,
7928 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7929 self.worktree_store
7930 .read(cx)
7931 .visible_worktrees(cx)
7932 .filter_map(|worktree| {
7933 let worktree = worktree.read(cx);
7934 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7935 })
7936 .flat_map(move |(worktree, summaries)| {
7937 let worktree_id = worktree.id();
7938 summaries
7939 .iter()
7940 .filter(move |(path, _)| {
7941 include_ignored
7942 || worktree
7943 .entry_for_path(path.as_ref())
7944 .is_some_and(|entry| !entry.is_ignored)
7945 })
7946 .flat_map(move |(path, summaries)| {
7947 summaries.iter().map(move |(server_id, summary)| {
7948 (
7949 ProjectPath {
7950 worktree_id,
7951 path: path.clone(),
7952 },
7953 *server_id,
7954 *summary,
7955 )
7956 })
7957 })
7958 })
7959 }
7960
7961 pub fn on_buffer_edited(
7962 &mut self,
7963 buffer: Entity<Buffer>,
7964 cx: &mut Context<Self>,
7965 ) -> Option<()> {
7966 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7967 Some(
7968 self.as_local()?
7969 .language_servers_for_buffer(buffer, cx)
7970 .map(|i| i.1.clone())
7971 .collect(),
7972 )
7973 })?;
7974
7975 let buffer = buffer.read(cx);
7976 let file = File::from_dyn(buffer.file())?;
7977 let abs_path = file.as_local()?.abs_path(cx);
7978 let uri = lsp::Uri::from_file_path(&abs_path)
7979 .ok()
7980 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7981 .log_err()?;
7982 let next_snapshot = buffer.text_snapshot();
7983 for language_server in language_servers {
7984 let language_server = language_server.clone();
7985
7986 let buffer_snapshots = self
7987 .as_local_mut()?
7988 .buffer_snapshots
7989 .get_mut(&buffer.remote_id())
7990 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7991 let previous_snapshot = buffer_snapshots.last()?;
7992
7993 let build_incremental_change = || {
7994 buffer
7995 .edits_since::<Dimensions<PointUtf16, usize>>(
7996 previous_snapshot.snapshot.version(),
7997 )
7998 .map(|edit| {
7999 let edit_start = edit.new.start.0;
8000 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
8001 let new_text = next_snapshot
8002 .text_for_range(edit.new.start.1..edit.new.end.1)
8003 .collect();
8004 lsp::TextDocumentContentChangeEvent {
8005 range: Some(lsp::Range::new(
8006 point_to_lsp(edit_start),
8007 point_to_lsp(edit_end),
8008 )),
8009 range_length: None,
8010 text: new_text,
8011 }
8012 })
8013 .collect()
8014 };
8015
8016 let document_sync_kind = language_server
8017 .capabilities()
8018 .text_document_sync
8019 .as_ref()
8020 .and_then(|sync| match sync {
8021 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
8022 lsp::TextDocumentSyncCapability::Options(options) => options.change,
8023 });
8024
8025 let content_changes: Vec<_> = match document_sync_kind {
8026 Some(lsp::TextDocumentSyncKind::FULL) => {
8027 vec![lsp::TextDocumentContentChangeEvent {
8028 range: None,
8029 range_length: None,
8030 text: next_snapshot.text(),
8031 }]
8032 }
8033 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
8034 _ => {
8035 #[cfg(any(test, feature = "test-support"))]
8036 {
8037 build_incremental_change()
8038 }
8039
8040 #[cfg(not(any(test, feature = "test-support")))]
8041 {
8042 continue;
8043 }
8044 }
8045 };
8046
8047 let next_version = previous_snapshot.version + 1;
8048 buffer_snapshots.push(LspBufferSnapshot {
8049 version: next_version,
8050 snapshot: next_snapshot.clone(),
8051 });
8052
8053 language_server
8054 .notify::<lsp::notification::DidChangeTextDocument>(
8055 lsp::DidChangeTextDocumentParams {
8056 text_document: lsp::VersionedTextDocumentIdentifier::new(
8057 uri.clone(),
8058 next_version,
8059 ),
8060 content_changes,
8061 },
8062 )
8063 .ok();
8064 self.pull_workspace_diagnostics(language_server.server_id());
8065 }
8066
8067 None
8068 }
8069
8070 pub fn on_buffer_saved(
8071 &mut self,
8072 buffer: Entity<Buffer>,
8073 cx: &mut Context<Self>,
8074 ) -> Option<()> {
8075 let file = File::from_dyn(buffer.read(cx).file())?;
8076 let worktree_id = file.worktree_id(cx);
8077 let abs_path = file.as_local()?.abs_path(cx);
8078 let text_document = lsp::TextDocumentIdentifier {
8079 uri: file_path_to_lsp_url(&abs_path).log_err()?,
8080 };
8081 let local = self.as_local()?;
8082
8083 for server in local.language_servers_for_worktree(worktree_id) {
8084 if let Some(include_text) = include_text(server.as_ref()) {
8085 let text = if include_text {
8086 Some(buffer.read(cx).text())
8087 } else {
8088 None
8089 };
8090 server
8091 .notify::<lsp::notification::DidSaveTextDocument>(
8092 lsp::DidSaveTextDocumentParams {
8093 text_document: text_document.clone(),
8094 text,
8095 },
8096 )
8097 .ok();
8098 }
8099 }
8100
8101 let language_servers = buffer.update(cx, |buffer, cx| {
8102 local.language_server_ids_for_buffer(buffer, cx)
8103 });
8104 for language_server_id in language_servers {
8105 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
8106 }
8107
8108 None
8109 }
8110
8111 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
8112 maybe!(async move {
8113 let mut refreshed_servers = HashSet::default();
8114 let servers = lsp_store
8115 .update(cx, |lsp_store, cx| {
8116 let local = lsp_store.as_local()?;
8117
8118 let servers = local
8119 .language_server_ids
8120 .iter()
8121 .filter_map(|(seed, state)| {
8122 let worktree = lsp_store
8123 .worktree_store
8124 .read(cx)
8125 .worktree_for_id(seed.worktree_id, cx);
8126 let delegate: Arc<dyn LspAdapterDelegate> =
8127 worktree.map(|worktree| {
8128 LocalLspAdapterDelegate::new(
8129 local.languages.clone(),
8130 &local.environment,
8131 cx.weak_entity(),
8132 &worktree,
8133 local.http_client.clone(),
8134 local.fs.clone(),
8135 cx,
8136 )
8137 })?;
8138 let server_id = state.id;
8139
8140 let states = local.language_servers.get(&server_id)?;
8141
8142 match states {
8143 LanguageServerState::Starting { .. } => None,
8144 LanguageServerState::Running {
8145 adapter, server, ..
8146 } => {
8147 let adapter = adapter.clone();
8148 let server = server.clone();
8149 refreshed_servers.insert(server.name());
8150 let toolchain = seed.toolchain.clone();
8151 Some(cx.spawn(async move |_, cx| {
8152 let settings =
8153 LocalLspStore::workspace_configuration_for_adapter(
8154 adapter.adapter.clone(),
8155 &delegate,
8156 toolchain,
8157 None,
8158 cx,
8159 )
8160 .await
8161 .ok()?;
8162 server
8163 .notify::<lsp::notification::DidChangeConfiguration>(
8164 lsp::DidChangeConfigurationParams { settings },
8165 )
8166 .ok()?;
8167 Some(())
8168 }))
8169 }
8170 }
8171 })
8172 .collect::<Vec<_>>();
8173
8174 Some(servers)
8175 })
8176 .ok()
8177 .flatten()?;
8178
8179 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8180 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8181 // to stop and unregister its language server wrapper.
8182 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8183 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8184 let _: Vec<Option<()>> = join_all(servers).await;
8185
8186 Some(())
8187 })
8188 .await;
8189 }
8190
8191 fn maintain_workspace_config(
8192 external_refresh_requests: watch::Receiver<()>,
8193 cx: &mut Context<Self>,
8194 ) -> Task<Result<()>> {
8195 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8196 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8197
8198 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8199 *settings_changed_tx.borrow_mut() = ();
8200 });
8201
8202 let mut joint_future =
8203 futures::stream::select(settings_changed_rx, external_refresh_requests);
8204 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8205 // - 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).
8206 // - 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.
8207 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8208 // - 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,
8209 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8210 cx.spawn(async move |this, cx| {
8211 while let Some(()) = joint_future.next().await {
8212 this.update(cx, |this, cx| {
8213 this.refresh_server_tree(cx);
8214 })
8215 .ok();
8216
8217 Self::refresh_workspace_configurations(&this, cx).await;
8218 }
8219
8220 drop(settings_observation);
8221 anyhow::Ok(())
8222 })
8223 }
8224
8225 pub fn running_language_servers_for_local_buffer<'a>(
8226 &'a self,
8227 buffer: &Buffer,
8228 cx: &mut App,
8229 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8230 let local = self.as_local();
8231 let language_server_ids = local
8232 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8233 .unwrap_or_default();
8234
8235 language_server_ids
8236 .into_iter()
8237 .filter_map(
8238 move |server_id| match local?.language_servers.get(&server_id)? {
8239 LanguageServerState::Running {
8240 adapter, server, ..
8241 } => Some((adapter, server)),
8242 _ => None,
8243 },
8244 )
8245 }
8246
8247 pub fn language_servers_for_local_buffer(
8248 &self,
8249 buffer: &Buffer,
8250 cx: &mut App,
8251 ) -> Vec<LanguageServerId> {
8252 let local = self.as_local();
8253 local
8254 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8255 .unwrap_or_default()
8256 }
8257
8258 pub fn language_server_for_local_buffer<'a>(
8259 &'a self,
8260 buffer: &'a Buffer,
8261 server_id: LanguageServerId,
8262 cx: &'a mut App,
8263 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8264 self.as_local()?
8265 .language_servers_for_buffer(buffer, cx)
8266 .find(|(_, s)| s.server_id() == server_id)
8267 }
8268
8269 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8270 self.diagnostic_summaries.remove(&id_to_remove);
8271 if let Some(local) = self.as_local_mut() {
8272 let to_remove = local.remove_worktree(id_to_remove, cx);
8273 for server in to_remove {
8274 self.language_server_statuses.remove(&server);
8275 }
8276 }
8277 }
8278
8279 fn invalidate_diagnostic_summaries_for_removed_entries(
8280 &mut self,
8281 worktree_id: WorktreeId,
8282 changes: &UpdatedEntriesSet,
8283 cx: &mut Context<Self>,
8284 ) {
8285 let Some(summaries_for_tree) = self.diagnostic_summaries.get_mut(&worktree_id) else {
8286 return;
8287 };
8288
8289 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
8290 let mut cleared_server_ids: HashSet<LanguageServerId> = HashSet::default();
8291 let downstream = self.downstream_client.clone();
8292
8293 for (path, _, _) in changes
8294 .iter()
8295 .filter(|(_, _, change)| *change == PathChange::Removed)
8296 {
8297 if let Some(summaries_by_server_id) = summaries_for_tree.remove(path) {
8298 for (server_id, _) in &summaries_by_server_id {
8299 cleared_server_ids.insert(*server_id);
8300 if let Some((client, project_id)) = &downstream {
8301 client
8302 .send(proto::UpdateDiagnosticSummary {
8303 project_id: *project_id,
8304 worktree_id: worktree_id.to_proto(),
8305 summary: Some(proto::DiagnosticSummary {
8306 path: path.as_ref().to_proto(),
8307 language_server_id: server_id.0 as u64,
8308 error_count: 0,
8309 warning_count: 0,
8310 }),
8311 more_summaries: Vec::new(),
8312 })
8313 .ok();
8314 }
8315 }
8316 cleared_paths.push(ProjectPath {
8317 worktree_id,
8318 path: path.clone(),
8319 });
8320 }
8321 }
8322
8323 if !cleared_paths.is_empty() {
8324 for server_id in cleared_server_ids {
8325 cx.emit(LspStoreEvent::DiagnosticsUpdated {
8326 server_id,
8327 paths: cleared_paths.clone(),
8328 });
8329 }
8330 }
8331 }
8332
8333 pub fn shared(
8334 &mut self,
8335 project_id: u64,
8336 downstream_client: AnyProtoClient,
8337 _: &mut Context<Self>,
8338 ) {
8339 self.downstream_client = Some((downstream_client.clone(), project_id));
8340
8341 for (server_id, status) in &self.language_server_statuses {
8342 if let Some(server) = self.language_server_for_id(*server_id) {
8343 downstream_client
8344 .send(proto::StartLanguageServer {
8345 project_id,
8346 server: Some(proto::LanguageServer {
8347 id: server_id.to_proto(),
8348 name: status.name.to_string(),
8349 worktree_id: status.worktree.map(|id| id.to_proto()),
8350 }),
8351 capabilities: serde_json::to_string(&server.capabilities())
8352 .expect("serializing server LSP capabilities"),
8353 })
8354 .log_err();
8355 }
8356 }
8357 }
8358
8359 pub fn disconnected_from_host(&mut self) {
8360 self.downstream_client.take();
8361 }
8362
8363 pub fn disconnected_from_ssh_remote(&mut self) {
8364 if let LspStoreMode::Remote(RemoteLspStore {
8365 upstream_client, ..
8366 }) = &mut self.mode
8367 {
8368 upstream_client.take();
8369 }
8370 }
8371
8372 pub(crate) fn set_language_server_statuses_from_proto(
8373 &mut self,
8374 project: WeakEntity<Project>,
8375 language_servers: Vec<proto::LanguageServer>,
8376 server_capabilities: Vec<String>,
8377 cx: &mut Context<Self>,
8378 ) {
8379 let lsp_logs = cx
8380 .try_global::<GlobalLogStore>()
8381 .map(|lsp_store| lsp_store.0.clone());
8382
8383 self.language_server_statuses = language_servers
8384 .into_iter()
8385 .zip(server_capabilities)
8386 .map(|(server, server_capabilities)| {
8387 let server_id = LanguageServerId(server.id as usize);
8388 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8389 self.lsp_server_capabilities
8390 .insert(server_id, server_capabilities);
8391 }
8392
8393 let name = LanguageServerName::from_proto(server.name);
8394 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8395
8396 if let Some(lsp_logs) = &lsp_logs {
8397 lsp_logs.update(cx, |lsp_logs, cx| {
8398 lsp_logs.add_language_server(
8399 // Only remote clients get their language servers set from proto
8400 LanguageServerKind::Remote {
8401 project: project.clone(),
8402 },
8403 server_id,
8404 Some(name.clone()),
8405 worktree,
8406 None,
8407 cx,
8408 );
8409 });
8410 }
8411
8412 (
8413 server_id,
8414 LanguageServerStatus {
8415 name,
8416 server_version: None,
8417 server_readable_version: None,
8418 pending_work: Default::default(),
8419 has_pending_diagnostic_updates: false,
8420 progress_tokens: Default::default(),
8421 worktree,
8422 binary: None,
8423 configuration: None,
8424 workspace_folders: BTreeSet::new(),
8425 process_id: None,
8426 },
8427 )
8428 })
8429 .collect();
8430 }
8431
8432 #[cfg(feature = "test-support")]
8433 pub fn update_diagnostic_entries(
8434 &mut self,
8435 server_id: LanguageServerId,
8436 abs_path: PathBuf,
8437 result_id: Option<SharedString>,
8438 version: Option<i32>,
8439 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8440 cx: &mut Context<Self>,
8441 ) -> anyhow::Result<()> {
8442 self.merge_diagnostic_entries(
8443 vec![DocumentDiagnosticsUpdate {
8444 diagnostics: DocumentDiagnostics {
8445 diagnostics,
8446 document_abs_path: abs_path,
8447 version,
8448 },
8449 result_id,
8450 server_id,
8451 disk_based_sources: Cow::Borrowed(&[]),
8452 registration_id: None,
8453 }],
8454 |_, _, _| false,
8455 cx,
8456 )?;
8457 Ok(())
8458 }
8459
8460 pub fn merge_diagnostic_entries<'a>(
8461 &mut self,
8462 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8463 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8464 cx: &mut Context<Self>,
8465 ) -> anyhow::Result<()> {
8466 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8467 let mut updated_diagnostics_paths = HashMap::default();
8468 for mut update in diagnostic_updates {
8469 let abs_path = &update.diagnostics.document_abs_path;
8470 let server_id = update.server_id;
8471 let Some((worktree, relative_path)) =
8472 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8473 else {
8474 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8475 return Ok(());
8476 };
8477
8478 let worktree_id = worktree.read(cx).id();
8479 let project_path = ProjectPath {
8480 worktree_id,
8481 path: relative_path,
8482 };
8483
8484 let document_uri = lsp::Uri::from_file_path(abs_path)
8485 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8486 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8487 let snapshot = buffer_handle.read(cx).snapshot();
8488 let buffer = buffer_handle.read(cx);
8489 let reused_diagnostics = buffer
8490 .buffer_diagnostics(Some(server_id))
8491 .iter()
8492 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8493 .map(|v| {
8494 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8495 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8496 DiagnosticEntry {
8497 range: start..end,
8498 diagnostic: v.diagnostic.clone(),
8499 }
8500 })
8501 .collect::<Vec<_>>();
8502
8503 self.as_local_mut()
8504 .context("cannot merge diagnostics on a remote LspStore")?
8505 .update_buffer_diagnostics(
8506 &buffer_handle,
8507 server_id,
8508 Some(update.registration_id),
8509 update.result_id,
8510 update.diagnostics.version,
8511 update.diagnostics.diagnostics.clone(),
8512 reused_diagnostics.clone(),
8513 cx,
8514 )?;
8515
8516 update.diagnostics.diagnostics.extend(reused_diagnostics);
8517 } else if let Some(local) = self.as_local() {
8518 let reused_diagnostics = local
8519 .diagnostics
8520 .get(&worktree_id)
8521 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8522 .and_then(|diagnostics_by_server_id| {
8523 diagnostics_by_server_id
8524 .binary_search_by_key(&server_id, |e| e.0)
8525 .ok()
8526 .map(|ix| &diagnostics_by_server_id[ix].1)
8527 })
8528 .into_iter()
8529 .flatten()
8530 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8531
8532 update
8533 .diagnostics
8534 .diagnostics
8535 .extend(reused_diagnostics.cloned());
8536 }
8537
8538 let updated = worktree.update(cx, |worktree, cx| {
8539 self.update_worktree_diagnostics(
8540 worktree.id(),
8541 server_id,
8542 project_path.path.clone(),
8543 update.diagnostics.diagnostics,
8544 cx,
8545 )
8546 })?;
8547 match updated {
8548 ControlFlow::Continue(new_summary) => {
8549 if let Some((project_id, new_summary)) = new_summary {
8550 match &mut diagnostics_summary {
8551 Some(diagnostics_summary) => {
8552 diagnostics_summary
8553 .more_summaries
8554 .push(proto::DiagnosticSummary {
8555 path: project_path.path.as_ref().to_proto(),
8556 language_server_id: server_id.0 as u64,
8557 error_count: new_summary.error_count,
8558 warning_count: new_summary.warning_count,
8559 })
8560 }
8561 None => {
8562 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8563 project_id,
8564 worktree_id: worktree_id.to_proto(),
8565 summary: Some(proto::DiagnosticSummary {
8566 path: project_path.path.as_ref().to_proto(),
8567 language_server_id: server_id.0 as u64,
8568 error_count: new_summary.error_count,
8569 warning_count: new_summary.warning_count,
8570 }),
8571 more_summaries: Vec::new(),
8572 })
8573 }
8574 }
8575 }
8576 updated_diagnostics_paths
8577 .entry(server_id)
8578 .or_insert_with(Vec::new)
8579 .push(project_path);
8580 }
8581 ControlFlow::Break(()) => {}
8582 }
8583 }
8584
8585 if let Some((diagnostics_summary, (downstream_client, _))) =
8586 diagnostics_summary.zip(self.downstream_client.as_ref())
8587 {
8588 downstream_client.send(diagnostics_summary).log_err();
8589 }
8590 for (server_id, paths) in updated_diagnostics_paths {
8591 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8592 }
8593 Ok(())
8594 }
8595
8596 fn update_worktree_diagnostics(
8597 &mut self,
8598 worktree_id: WorktreeId,
8599 server_id: LanguageServerId,
8600 path_in_worktree: Arc<RelPath>,
8601 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8602 _: &mut Context<Worktree>,
8603 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8604 let local = match &mut self.mode {
8605 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8606 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8607 };
8608
8609 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8610 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8611 let summaries_by_server_id = summaries_for_tree
8612 .entry(path_in_worktree.clone())
8613 .or_default();
8614
8615 let old_summary = summaries_by_server_id
8616 .remove(&server_id)
8617 .unwrap_or_default();
8618
8619 let new_summary = DiagnosticSummary::new(&diagnostics);
8620 if diagnostics.is_empty() {
8621 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8622 {
8623 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8624 diagnostics_by_server_id.remove(ix);
8625 }
8626 if diagnostics_by_server_id.is_empty() {
8627 diagnostics_for_tree.remove(&path_in_worktree);
8628 }
8629 }
8630 } else {
8631 summaries_by_server_id.insert(server_id, new_summary);
8632 let diagnostics_by_server_id = diagnostics_for_tree
8633 .entry(path_in_worktree.clone())
8634 .or_default();
8635 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8636 Ok(ix) => {
8637 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8638 }
8639 Err(ix) => {
8640 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8641 }
8642 }
8643 }
8644
8645 if !old_summary.is_empty() || !new_summary.is_empty() {
8646 if let Some((_, project_id)) = &self.downstream_client {
8647 Ok(ControlFlow::Continue(Some((
8648 *project_id,
8649 proto::DiagnosticSummary {
8650 path: path_in_worktree.to_proto(),
8651 language_server_id: server_id.0 as u64,
8652 error_count: new_summary.error_count as u32,
8653 warning_count: new_summary.warning_count as u32,
8654 },
8655 ))))
8656 } else {
8657 Ok(ControlFlow::Continue(None))
8658 }
8659 } else {
8660 Ok(ControlFlow::Break(()))
8661 }
8662 }
8663
8664 pub fn open_buffer_for_symbol(
8665 &mut self,
8666 symbol: &Symbol,
8667 cx: &mut Context<Self>,
8668 ) -> Task<Result<Entity<Buffer>>> {
8669 if let Some((client, project_id)) = self.upstream_client() {
8670 let request = client.request(proto::OpenBufferForSymbol {
8671 project_id,
8672 symbol: Some(Self::serialize_symbol(symbol)),
8673 });
8674 cx.spawn(async move |this, cx| {
8675 let response = request.await?;
8676 let buffer_id = BufferId::new(response.buffer_id)?;
8677 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8678 .await
8679 })
8680 } else if let Some(local) = self.as_local() {
8681 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8682 seed.worktree_id == symbol.source_worktree_id
8683 && state.id == symbol.source_language_server_id
8684 && symbol.language_server_name == seed.name
8685 });
8686 if !is_valid {
8687 return Task::ready(Err(anyhow!(
8688 "language server for worktree and language not found"
8689 )));
8690 };
8691
8692 let symbol_abs_path = match &symbol.path {
8693 SymbolLocation::InProject(project_path) => self
8694 .worktree_store
8695 .read(cx)
8696 .absolutize(&project_path, cx)
8697 .context("no such worktree"),
8698 SymbolLocation::OutsideProject {
8699 abs_path,
8700 signature: _,
8701 } => Ok(abs_path.to_path_buf()),
8702 };
8703 let symbol_abs_path = match symbol_abs_path {
8704 Ok(abs_path) => abs_path,
8705 Err(err) => return Task::ready(Err(err)),
8706 };
8707 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8708 uri
8709 } else {
8710 return Task::ready(Err(anyhow!("invalid symbol path")));
8711 };
8712
8713 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8714 } else {
8715 Task::ready(Err(anyhow!("no upstream client or local store")))
8716 }
8717 }
8718
8719 pub(crate) fn open_local_buffer_via_lsp(
8720 &mut self,
8721 abs_path: lsp::Uri,
8722 language_server_id: LanguageServerId,
8723 cx: &mut Context<Self>,
8724 ) -> Task<Result<Entity<Buffer>>> {
8725 let path_style = self.worktree_store.read(cx).path_style();
8726 cx.spawn(async move |lsp_store, cx| {
8727 // Escape percent-encoded string.
8728 let current_scheme = abs_path.scheme().to_owned();
8729 // Uri is immutable, so we can't modify the scheme
8730
8731 let abs_path = abs_path
8732 .to_file_path_ext(path_style)
8733 .map_err(|()| anyhow!("can't convert URI to path"))?;
8734 let p = abs_path.clone();
8735 let yarn_worktree = lsp_store
8736 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8737 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8738 cx.spawn(async move |this, cx| {
8739 let t = this
8740 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8741 .ok()?;
8742 t.await
8743 })
8744 }),
8745 None => Task::ready(None),
8746 })?
8747 .await;
8748 let (worktree_root_target, known_relative_path) =
8749 if let Some((zip_root, relative_path)) = yarn_worktree {
8750 (zip_root, Some(relative_path))
8751 } else {
8752 (Arc::<Path>::from(abs_path.as_path()), None)
8753 };
8754 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8755 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8756 worktree_store.find_worktree(&worktree_root_target, cx)
8757 })
8758 })?;
8759 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8760 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8761 (result.0, relative_path, None)
8762 } else {
8763 let worktree = lsp_store
8764 .update(cx, |lsp_store, cx| {
8765 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8766 worktree_store.create_worktree(&worktree_root_target, false, cx)
8767 })
8768 })?
8769 .await?;
8770 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8771 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8772 lsp_store
8773 .update(cx, |lsp_store, cx| {
8774 if let Some(local) = lsp_store.as_local_mut() {
8775 local.register_language_server_for_invisible_worktree(
8776 &worktree,
8777 language_server_id,
8778 cx,
8779 )
8780 }
8781 match lsp_store.language_server_statuses.get(&language_server_id) {
8782 Some(status) => status.worktree,
8783 None => None,
8784 }
8785 })
8786 .ok()
8787 .flatten()
8788 .zip(Some(worktree_root.clone()))
8789 } else {
8790 None
8791 };
8792 let relative_path = if let Some(known_path) = known_relative_path {
8793 known_path
8794 } else {
8795 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8796 .into_arc()
8797 };
8798 (worktree, relative_path, source_ws)
8799 };
8800 let project_path = ProjectPath {
8801 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8802 path: relative_path,
8803 };
8804 let buffer = lsp_store
8805 .update(cx, |lsp_store, cx| {
8806 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8807 buffer_store.open_buffer(project_path, cx)
8808 })
8809 })?
8810 .await?;
8811 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8812 if let Some((source_ws, worktree_root)) = source_ws {
8813 buffer.update(cx, |buffer, cx| {
8814 let settings = WorktreeSettings::get(
8815 Some(
8816 (&ProjectPath {
8817 worktree_id: source_ws,
8818 path: Arc::from(RelPath::empty()),
8819 })
8820 .into(),
8821 ),
8822 cx,
8823 );
8824 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8825 if is_read_only {
8826 buffer.set_capability(Capability::ReadOnly, cx);
8827 }
8828 });
8829 }
8830 Ok(buffer)
8831 })
8832 }
8833
8834 fn local_lsp_servers_for_buffer(
8835 &self,
8836 buffer: &Entity<Buffer>,
8837 cx: &mut Context<Self>,
8838 ) -> Vec<LanguageServerId> {
8839 let Some(local) = self.as_local() else {
8840 return Vec::new();
8841 };
8842
8843 let snapshot = buffer.read(cx).snapshot();
8844
8845 buffer.update(cx, |buffer, cx| {
8846 local
8847 .language_servers_for_buffer(buffer, cx)
8848 .map(|(_, server)| server.server_id())
8849 .filter(|server_id| {
8850 self.as_local().is_none_or(|local| {
8851 local
8852 .buffers_opened_in_servers
8853 .get(&snapshot.remote_id())
8854 .is_some_and(|servers| servers.contains(server_id))
8855 })
8856 })
8857 .collect()
8858 })
8859 }
8860
8861 fn request_multiple_lsp_locally<P, R>(
8862 &mut self,
8863 buffer: &Entity<Buffer>,
8864 position: Option<P>,
8865 request: R,
8866 cx: &mut Context<Self>,
8867 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8868 where
8869 P: ToOffset,
8870 R: LspCommand + Clone,
8871 <R::LspRequest as lsp::request::Request>::Result: Send,
8872 <R::LspRequest as lsp::request::Request>::Params: Send,
8873 {
8874 let Some(local) = self.as_local() else {
8875 return Task::ready(Vec::new());
8876 };
8877
8878 let snapshot = buffer.read(cx).snapshot();
8879 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8880
8881 let server_ids = buffer.update(cx, |buffer, cx| {
8882 local
8883 .language_servers_for_buffer(buffer, cx)
8884 .filter(|(adapter, _)| {
8885 scope
8886 .as_ref()
8887 .map(|scope| scope.language_allowed(&adapter.name))
8888 .unwrap_or(true)
8889 })
8890 .map(|(_, server)| server.server_id())
8891 .filter(|server_id| {
8892 self.as_local().is_none_or(|local| {
8893 local
8894 .buffers_opened_in_servers
8895 .get(&snapshot.remote_id())
8896 .is_some_and(|servers| servers.contains(server_id))
8897 })
8898 })
8899 .collect::<Vec<_>>()
8900 });
8901
8902 let mut response_results = server_ids
8903 .into_iter()
8904 .map(|server_id| {
8905 let task = self.request_lsp(
8906 buffer.clone(),
8907 LanguageServerToQuery::Other(server_id),
8908 request.clone(),
8909 cx,
8910 );
8911 async move { (server_id, task.await) }
8912 })
8913 .collect::<FuturesUnordered<_>>();
8914
8915 cx.background_spawn(async move {
8916 let mut responses = Vec::with_capacity(response_results.len());
8917 while let Some((server_id, response_result)) = response_results.next().await {
8918 match response_result {
8919 Ok(response) => responses.push((server_id, response)),
8920 // rust-analyzer likes to error with this when its still loading up
8921 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8922 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8923 }
8924 }
8925 responses
8926 })
8927 }
8928
8929 async fn handle_lsp_get_completions(
8930 this: Entity<Self>,
8931 envelope: TypedEnvelope<proto::GetCompletions>,
8932 mut cx: AsyncApp,
8933 ) -> Result<proto::GetCompletionsResponse> {
8934 let sender_id = envelope.original_sender_id().unwrap_or_default();
8935
8936 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8937 let buffer_handle = this.update(&mut cx, |this, cx| {
8938 this.buffer_store.read(cx).get_existing(buffer_id)
8939 })?;
8940 let request = GetCompletions::from_proto(
8941 envelope.payload,
8942 this.clone(),
8943 buffer_handle.clone(),
8944 cx.clone(),
8945 )
8946 .await?;
8947
8948 let server_to_query = match request.server_id {
8949 Some(server_id) => LanguageServerToQuery::Other(server_id),
8950 None => LanguageServerToQuery::FirstCapable,
8951 };
8952
8953 let response = this
8954 .update(&mut cx, |this, cx| {
8955 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8956 })
8957 .await?;
8958 this.update(&mut cx, |this, cx| {
8959 Ok(GetCompletions::response_to_proto(
8960 response,
8961 this,
8962 sender_id,
8963 &buffer_handle.read(cx).version(),
8964 cx,
8965 ))
8966 })
8967 }
8968
8969 async fn handle_lsp_command<T: LspCommand>(
8970 this: Entity<Self>,
8971 envelope: TypedEnvelope<T::ProtoRequest>,
8972 mut cx: AsyncApp,
8973 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8974 where
8975 <T::LspRequest as lsp::request::Request>::Params: Send,
8976 <T::LspRequest as lsp::request::Request>::Result: Send,
8977 {
8978 let sender_id = envelope.original_sender_id().unwrap_or_default();
8979 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8980 let buffer_handle = this.update(&mut cx, |this, cx| {
8981 this.buffer_store.read(cx).get_existing(buffer_id)
8982 })?;
8983 let request = T::from_proto(
8984 envelope.payload,
8985 this.clone(),
8986 buffer_handle.clone(),
8987 cx.clone(),
8988 )
8989 .await?;
8990 let response = this
8991 .update(&mut cx, |this, cx| {
8992 this.request_lsp(
8993 buffer_handle.clone(),
8994 LanguageServerToQuery::FirstCapable,
8995 request,
8996 cx,
8997 )
8998 })
8999 .await?;
9000 this.update(&mut cx, |this, cx| {
9001 Ok(T::response_to_proto(
9002 response,
9003 this,
9004 sender_id,
9005 &buffer_handle.read(cx).version(),
9006 cx,
9007 ))
9008 })
9009 }
9010
9011 async fn handle_lsp_query(
9012 lsp_store: Entity<Self>,
9013 envelope: TypedEnvelope<proto::LspQuery>,
9014 mut cx: AsyncApp,
9015 ) -> Result<proto::Ack> {
9016 use proto::lsp_query::Request;
9017 let sender_id = envelope.original_sender_id().unwrap_or_default();
9018 let lsp_query = envelope.payload;
9019 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
9020 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
9021 match lsp_query.request.context("invalid LSP query request")? {
9022 Request::GetReferences(get_references) => {
9023 let position = get_references.position.clone().and_then(deserialize_anchor);
9024 Self::query_lsp_locally::<GetReferences>(
9025 lsp_store,
9026 server_id,
9027 sender_id,
9028 lsp_request_id,
9029 get_references,
9030 position,
9031 &mut cx,
9032 )
9033 .await?;
9034 }
9035 Request::GetDocumentColor(get_document_color) => {
9036 Self::query_lsp_locally::<GetDocumentColor>(
9037 lsp_store,
9038 server_id,
9039 sender_id,
9040 lsp_request_id,
9041 get_document_color,
9042 None,
9043 &mut cx,
9044 )
9045 .await?;
9046 }
9047 Request::GetFoldingRanges(get_folding_ranges) => {
9048 Self::query_lsp_locally::<GetFoldingRanges>(
9049 lsp_store,
9050 server_id,
9051 sender_id,
9052 lsp_request_id,
9053 get_folding_ranges,
9054 None,
9055 &mut cx,
9056 )
9057 .await?;
9058 }
9059 Request::GetDocumentSymbols(get_document_symbols) => {
9060 Self::query_lsp_locally::<GetDocumentSymbols>(
9061 lsp_store,
9062 server_id,
9063 sender_id,
9064 lsp_request_id,
9065 get_document_symbols,
9066 None,
9067 &mut cx,
9068 )
9069 .await?;
9070 }
9071 Request::GetHover(get_hover) => {
9072 let position = get_hover.position.clone().and_then(deserialize_anchor);
9073 Self::query_lsp_locally::<GetHover>(
9074 lsp_store,
9075 server_id,
9076 sender_id,
9077 lsp_request_id,
9078 get_hover,
9079 position,
9080 &mut cx,
9081 )
9082 .await?;
9083 }
9084 Request::GetCodeActions(get_code_actions) => {
9085 Self::query_lsp_locally::<GetCodeActions>(
9086 lsp_store,
9087 server_id,
9088 sender_id,
9089 lsp_request_id,
9090 get_code_actions,
9091 None,
9092 &mut cx,
9093 )
9094 .await?;
9095 }
9096 Request::GetSignatureHelp(get_signature_help) => {
9097 let position = get_signature_help
9098 .position
9099 .clone()
9100 .and_then(deserialize_anchor);
9101 Self::query_lsp_locally::<GetSignatureHelp>(
9102 lsp_store,
9103 server_id,
9104 sender_id,
9105 lsp_request_id,
9106 get_signature_help,
9107 position,
9108 &mut cx,
9109 )
9110 .await?;
9111 }
9112 Request::GetCodeLens(get_code_lens) => {
9113 Self::query_lsp_locally::<GetCodeLens>(
9114 lsp_store,
9115 server_id,
9116 sender_id,
9117 lsp_request_id,
9118 get_code_lens,
9119 None,
9120 &mut cx,
9121 )
9122 .await?;
9123 }
9124 Request::GetDefinition(get_definition) => {
9125 let position = get_definition.position.clone().and_then(deserialize_anchor);
9126 Self::query_lsp_locally::<GetDefinitions>(
9127 lsp_store,
9128 server_id,
9129 sender_id,
9130 lsp_request_id,
9131 get_definition,
9132 position,
9133 &mut cx,
9134 )
9135 .await?;
9136 }
9137 Request::GetDeclaration(get_declaration) => {
9138 let position = get_declaration
9139 .position
9140 .clone()
9141 .and_then(deserialize_anchor);
9142 Self::query_lsp_locally::<GetDeclarations>(
9143 lsp_store,
9144 server_id,
9145 sender_id,
9146 lsp_request_id,
9147 get_declaration,
9148 position,
9149 &mut cx,
9150 )
9151 .await?;
9152 }
9153 Request::GetTypeDefinition(get_type_definition) => {
9154 let position = get_type_definition
9155 .position
9156 .clone()
9157 .and_then(deserialize_anchor);
9158 Self::query_lsp_locally::<GetTypeDefinitions>(
9159 lsp_store,
9160 server_id,
9161 sender_id,
9162 lsp_request_id,
9163 get_type_definition,
9164 position,
9165 &mut cx,
9166 )
9167 .await?;
9168 }
9169 Request::GetImplementation(get_implementation) => {
9170 let position = get_implementation
9171 .position
9172 .clone()
9173 .and_then(deserialize_anchor);
9174 Self::query_lsp_locally::<GetImplementations>(
9175 lsp_store,
9176 server_id,
9177 sender_id,
9178 lsp_request_id,
9179 get_implementation,
9180 position,
9181 &mut cx,
9182 )
9183 .await?;
9184 }
9185 Request::InlayHints(inlay_hints) => {
9186 let query_start = inlay_hints
9187 .start
9188 .clone()
9189 .and_then(deserialize_anchor)
9190 .context("invalid inlay hints range start")?;
9191 let query_end = inlay_hints
9192 .end
9193 .clone()
9194 .and_then(deserialize_anchor)
9195 .context("invalid inlay hints range end")?;
9196 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9197 &lsp_store,
9198 server_id,
9199 lsp_request_id,
9200 &inlay_hints,
9201 query_start..query_end,
9202 &mut cx,
9203 )
9204 .await
9205 .context("preparing inlay hints request")?;
9206 Self::query_lsp_locally::<InlayHints>(
9207 lsp_store,
9208 server_id,
9209 sender_id,
9210 lsp_request_id,
9211 inlay_hints,
9212 None,
9213 &mut cx,
9214 )
9215 .await
9216 .context("querying for inlay hints")?
9217 }
9218 //////////////////////////////
9219 // Below are LSP queries that need to fetch more data,
9220 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9221 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9222 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9223 &lsp_store,
9224 &get_document_diagnostics,
9225 &mut cx,
9226 )
9227 .await?;
9228 lsp_store.update(&mut cx, |lsp_store, cx| {
9229 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9230 let key = LspKey {
9231 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9232 server_queried: server_id,
9233 };
9234 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9235 ) {
9236 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9237 lsp_requests.clear();
9238 };
9239 }
9240
9241 lsp_data.lsp_requests.entry(key).or_default().insert(
9242 lsp_request_id,
9243 cx.spawn(async move |lsp_store, cx| {
9244 let diagnostics_pull = lsp_store
9245 .update(cx, |lsp_store, cx| {
9246 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9247 })
9248 .ok();
9249 if let Some(diagnostics_pull) = diagnostics_pull {
9250 match diagnostics_pull.await {
9251 Ok(()) => {}
9252 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9253 };
9254 }
9255 }),
9256 );
9257 });
9258 }
9259 Request::SemanticTokens(semantic_tokens) => {
9260 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9261 &lsp_store,
9262 &semantic_tokens,
9263 &mut cx,
9264 )
9265 .await?;
9266 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9267 lsp_store.update(&mut cx, |lsp_store, cx| {
9268 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9269 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9270 let key = LspKey {
9271 request_type: TypeId::of::<SemanticTokensFull>(),
9272 server_queried: server_id,
9273 };
9274 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9275 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9276 lsp_requests.clear();
9277 };
9278 }
9279
9280 lsp_data.lsp_requests.entry(key).or_default().insert(
9281 lsp_request_id,
9282 cx.spawn(async move |lsp_store, cx| {
9283 let tokens_fetch = lsp_store
9284 .update(cx, |lsp_store, cx| {
9285 lsp_store
9286 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9287 })
9288 .ok();
9289 if let Some(tokens_fetch) = tokens_fetch {
9290 let new_tokens = tokens_fetch.await;
9291 if let Some(new_tokens) = new_tokens {
9292 lsp_store
9293 .update(cx, |lsp_store, cx| {
9294 let response = new_tokens
9295 .into_iter()
9296 .map(|(server_id, response)| {
9297 (
9298 server_id.to_proto(),
9299 SemanticTokensFull::response_to_proto(
9300 response,
9301 lsp_store,
9302 sender_id,
9303 &buffer_version,
9304 cx,
9305 ),
9306 )
9307 })
9308 .collect::<HashMap<_, _>>();
9309 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9310 project_id,
9311 lsp_request_id,
9312 response,
9313 ) {
9314 Ok(()) => {}
9315 Err(e) => {
9316 log::error!(
9317 "Failed to send semantic tokens LSP response: {e:#}",
9318 )
9319 }
9320 }
9321 })
9322 .ok();
9323 }
9324 }
9325 }),
9326 );
9327 }
9328 });
9329 }
9330 }
9331 Ok(proto::Ack {})
9332 }
9333
9334 async fn handle_lsp_query_response(
9335 lsp_store: Entity<Self>,
9336 envelope: TypedEnvelope<proto::LspQueryResponse>,
9337 cx: AsyncApp,
9338 ) -> Result<()> {
9339 lsp_store.read_with(&cx, |lsp_store, _| {
9340 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9341 upstream_client.handle_lsp_response(envelope.clone());
9342 }
9343 });
9344 Ok(())
9345 }
9346
9347 async fn handle_apply_code_action(
9348 this: Entity<Self>,
9349 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9350 mut cx: AsyncApp,
9351 ) -> Result<proto::ApplyCodeActionResponse> {
9352 let sender_id = envelope.original_sender_id().unwrap_or_default();
9353 let action =
9354 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9355 let apply_code_action = this.update(&mut cx, |this, cx| {
9356 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9357 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9358 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9359 })?;
9360
9361 let project_transaction = apply_code_action.await?;
9362 let project_transaction = this.update(&mut cx, |this, cx| {
9363 this.buffer_store.update(cx, |buffer_store, cx| {
9364 buffer_store.serialize_project_transaction_for_peer(
9365 project_transaction,
9366 sender_id,
9367 cx,
9368 )
9369 })
9370 });
9371 Ok(proto::ApplyCodeActionResponse {
9372 transaction: Some(project_transaction),
9373 })
9374 }
9375
9376 async fn handle_register_buffer_with_language_servers(
9377 this: Entity<Self>,
9378 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9379 mut cx: AsyncApp,
9380 ) -> Result<proto::Ack> {
9381 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9382 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9383 this.update(&mut cx, |this, cx| {
9384 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9385 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9386 project_id: upstream_project_id,
9387 buffer_id: buffer_id.to_proto(),
9388 only_servers: envelope.payload.only_servers,
9389 });
9390 }
9391
9392 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9393 anyhow::bail!("buffer is not open");
9394 };
9395
9396 let handle = this.register_buffer_with_language_servers(
9397 &buffer,
9398 envelope
9399 .payload
9400 .only_servers
9401 .into_iter()
9402 .filter_map(|selector| {
9403 Some(match selector.selector? {
9404 proto::language_server_selector::Selector::ServerId(server_id) => {
9405 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9406 }
9407 proto::language_server_selector::Selector::Name(name) => {
9408 LanguageServerSelector::Name(LanguageServerName(
9409 SharedString::from(name),
9410 ))
9411 }
9412 })
9413 })
9414 .collect(),
9415 false,
9416 cx,
9417 );
9418 // Pull diagnostics for the buffer even if it was already registered.
9419 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9420 // but it's unclear if we need it.
9421 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9422 .detach();
9423 this.buffer_store().update(cx, |buffer_store, _| {
9424 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9425 });
9426
9427 Ok(())
9428 })?;
9429 Ok(proto::Ack {})
9430 }
9431
9432 async fn handle_rename_project_entry(
9433 this: Entity<Self>,
9434 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9435 mut cx: AsyncApp,
9436 ) -> Result<proto::ProjectEntryResponse> {
9437 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9438 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9439 let new_path =
9440 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9441
9442 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9443 .update(&mut cx, |this, cx| {
9444 let (worktree, entry) = this
9445 .worktree_store
9446 .read(cx)
9447 .worktree_and_entry_for_id(entry_id, cx)?;
9448 let new_worktree = this
9449 .worktree_store
9450 .read(cx)
9451 .worktree_for_id(new_worktree_id, cx)?;
9452 Some((
9453 this.worktree_store.clone(),
9454 worktree,
9455 new_worktree,
9456 entry.clone(),
9457 ))
9458 })
9459 .context("worktree not found")?;
9460 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9461 (worktree.absolutize(&old_entry.path), worktree.id())
9462 });
9463 let new_abs_path =
9464 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9465
9466 let _transaction = Self::will_rename_entry(
9467 this.downgrade(),
9468 old_worktree_id,
9469 &old_abs_path,
9470 &new_abs_path,
9471 old_entry.is_dir(),
9472 cx.clone(),
9473 )
9474 .await;
9475 let response = WorktreeStore::handle_rename_project_entry(
9476 worktree_store,
9477 envelope.payload,
9478 cx.clone(),
9479 )
9480 .await;
9481 this.read_with(&cx, |this, _| {
9482 this.did_rename_entry(
9483 old_worktree_id,
9484 &old_abs_path,
9485 &new_abs_path,
9486 old_entry.is_dir(),
9487 );
9488 });
9489 response
9490 }
9491
9492 async fn handle_update_diagnostic_summary(
9493 this: Entity<Self>,
9494 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9495 mut cx: AsyncApp,
9496 ) -> Result<()> {
9497 this.update(&mut cx, |lsp_store, cx| {
9498 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9499 let mut updated_diagnostics_paths = HashMap::default();
9500 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9501 for message_summary in envelope
9502 .payload
9503 .summary
9504 .into_iter()
9505 .chain(envelope.payload.more_summaries)
9506 {
9507 let project_path = ProjectPath {
9508 worktree_id,
9509 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9510 };
9511 let path = project_path.path.clone();
9512 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9513 let summary = DiagnosticSummary {
9514 error_count: message_summary.error_count as usize,
9515 warning_count: message_summary.warning_count as usize,
9516 };
9517
9518 if summary.is_empty() {
9519 if let Some(worktree_summaries) =
9520 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9521 && let Some(summaries) = worktree_summaries.get_mut(&path)
9522 {
9523 summaries.remove(&server_id);
9524 if summaries.is_empty() {
9525 worktree_summaries.remove(&path);
9526 }
9527 }
9528 } else {
9529 lsp_store
9530 .diagnostic_summaries
9531 .entry(worktree_id)
9532 .or_default()
9533 .entry(path)
9534 .or_default()
9535 .insert(server_id, summary);
9536 }
9537
9538 if let Some((_, project_id)) = &lsp_store.downstream_client {
9539 match &mut diagnostics_summary {
9540 Some(diagnostics_summary) => {
9541 diagnostics_summary
9542 .more_summaries
9543 .push(proto::DiagnosticSummary {
9544 path: project_path.path.as_ref().to_proto(),
9545 language_server_id: server_id.0 as u64,
9546 error_count: summary.error_count as u32,
9547 warning_count: summary.warning_count as u32,
9548 })
9549 }
9550 None => {
9551 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9552 project_id: *project_id,
9553 worktree_id: worktree_id.to_proto(),
9554 summary: Some(proto::DiagnosticSummary {
9555 path: project_path.path.as_ref().to_proto(),
9556 language_server_id: server_id.0 as u64,
9557 error_count: summary.error_count as u32,
9558 warning_count: summary.warning_count as u32,
9559 }),
9560 more_summaries: Vec::new(),
9561 })
9562 }
9563 }
9564 }
9565 updated_diagnostics_paths
9566 .entry(server_id)
9567 .or_insert_with(Vec::new)
9568 .push(project_path);
9569 }
9570
9571 if let Some((diagnostics_summary, (downstream_client, _))) =
9572 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9573 {
9574 downstream_client.send(diagnostics_summary).log_err();
9575 }
9576 for (server_id, paths) in updated_diagnostics_paths {
9577 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9578 }
9579 Ok(())
9580 })
9581 }
9582
9583 async fn handle_start_language_server(
9584 lsp_store: Entity<Self>,
9585 envelope: TypedEnvelope<proto::StartLanguageServer>,
9586 mut cx: AsyncApp,
9587 ) -> Result<()> {
9588 let server = envelope.payload.server.context("invalid server")?;
9589 let server_capabilities =
9590 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9591 .with_context(|| {
9592 format!(
9593 "incorrect server capabilities {}",
9594 envelope.payload.capabilities
9595 )
9596 })?;
9597 lsp_store.update(&mut cx, |lsp_store, cx| {
9598 let server_id = LanguageServerId(server.id as usize);
9599 let server_name = LanguageServerName::from_proto(server.name.clone());
9600 lsp_store
9601 .lsp_server_capabilities
9602 .insert(server_id, server_capabilities);
9603 lsp_store.language_server_statuses.insert(
9604 server_id,
9605 LanguageServerStatus {
9606 name: server_name.clone(),
9607 server_version: None,
9608 server_readable_version: None,
9609 pending_work: Default::default(),
9610 has_pending_diagnostic_updates: false,
9611 progress_tokens: Default::default(),
9612 worktree: server.worktree_id.map(WorktreeId::from_proto),
9613 binary: None,
9614 configuration: None,
9615 workspace_folders: BTreeSet::new(),
9616 process_id: None,
9617 },
9618 );
9619 cx.emit(LspStoreEvent::LanguageServerAdded(
9620 server_id,
9621 server_name,
9622 server.worktree_id.map(WorktreeId::from_proto),
9623 ));
9624 cx.notify();
9625 });
9626 Ok(())
9627 }
9628
9629 async fn handle_update_language_server(
9630 lsp_store: Entity<Self>,
9631 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9632 mut cx: AsyncApp,
9633 ) -> Result<()> {
9634 lsp_store.update(&mut cx, |lsp_store, cx| {
9635 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9636
9637 match envelope.payload.variant.context("invalid variant")? {
9638 proto::update_language_server::Variant::WorkStart(payload) => {
9639 lsp_store.on_lsp_work_start(
9640 language_server_id,
9641 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9642 .context("invalid progress token value")?,
9643 LanguageServerProgress {
9644 title: payload.title,
9645 is_disk_based_diagnostics_progress: false,
9646 is_cancellable: payload.is_cancellable.unwrap_or(false),
9647 message: payload.message,
9648 percentage: payload.percentage.map(|p| p as usize),
9649 last_update_at: cx.background_executor().now(),
9650 },
9651 cx,
9652 );
9653 }
9654 proto::update_language_server::Variant::WorkProgress(payload) => {
9655 lsp_store.on_lsp_work_progress(
9656 language_server_id,
9657 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9658 .context("invalid progress token value")?,
9659 LanguageServerProgress {
9660 title: None,
9661 is_disk_based_diagnostics_progress: false,
9662 is_cancellable: payload.is_cancellable.unwrap_or(false),
9663 message: payload.message,
9664 percentage: payload.percentage.map(|p| p as usize),
9665 last_update_at: cx.background_executor().now(),
9666 },
9667 cx,
9668 );
9669 }
9670
9671 proto::update_language_server::Variant::WorkEnd(payload) => {
9672 lsp_store.on_lsp_work_end(
9673 language_server_id,
9674 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9675 .context("invalid progress token value")?,
9676 cx,
9677 );
9678 }
9679
9680 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9681 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9682 }
9683
9684 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9685 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9686 }
9687
9688 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9689 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9690 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9691 cx.emit(LspStoreEvent::LanguageServerUpdate {
9692 language_server_id,
9693 name: envelope
9694 .payload
9695 .server_name
9696 .map(SharedString::new)
9697 .map(LanguageServerName),
9698 message: non_lsp,
9699 });
9700 }
9701 }
9702
9703 Ok(())
9704 })
9705 }
9706
9707 async fn handle_language_server_log(
9708 this: Entity<Self>,
9709 envelope: TypedEnvelope<proto::LanguageServerLog>,
9710 mut cx: AsyncApp,
9711 ) -> Result<()> {
9712 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9713 let log_type = envelope
9714 .payload
9715 .log_type
9716 .map(LanguageServerLogType::from_proto)
9717 .context("invalid language server log type")?;
9718
9719 let message = envelope.payload.message;
9720
9721 this.update(&mut cx, |_, cx| {
9722 cx.emit(LspStoreEvent::LanguageServerLog(
9723 language_server_id,
9724 log_type,
9725 message,
9726 ));
9727 });
9728 Ok(())
9729 }
9730
9731 async fn handle_lsp_ext_cancel_flycheck(
9732 lsp_store: Entity<Self>,
9733 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9734 cx: AsyncApp,
9735 ) -> Result<proto::Ack> {
9736 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9737 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9738 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9739 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9740 } else {
9741 None
9742 }
9743 });
9744 if let Some(task) = task {
9745 task.context("handling lsp ext cancel flycheck")?;
9746 }
9747
9748 Ok(proto::Ack {})
9749 }
9750
9751 async fn handle_lsp_ext_run_flycheck(
9752 lsp_store: Entity<Self>,
9753 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9754 mut cx: AsyncApp,
9755 ) -> Result<proto::Ack> {
9756 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9757 lsp_store.update(&mut cx, |lsp_store, cx| {
9758 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9759 let text_document = if envelope.payload.current_file_only {
9760 let buffer_id = envelope
9761 .payload
9762 .buffer_id
9763 .map(|id| BufferId::new(id))
9764 .transpose()?;
9765 buffer_id
9766 .and_then(|buffer_id| {
9767 lsp_store
9768 .buffer_store()
9769 .read(cx)
9770 .get(buffer_id)
9771 .and_then(|buffer| {
9772 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9773 })
9774 .map(|path| make_text_document_identifier(&path))
9775 })
9776 .transpose()?
9777 } else {
9778 None
9779 };
9780 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9781 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9782 )?;
9783 }
9784 anyhow::Ok(())
9785 })?;
9786
9787 Ok(proto::Ack {})
9788 }
9789
9790 async fn handle_lsp_ext_clear_flycheck(
9791 lsp_store: Entity<Self>,
9792 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9793 cx: AsyncApp,
9794 ) -> Result<proto::Ack> {
9795 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9796 lsp_store.read_with(&cx, |lsp_store, _| {
9797 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9798 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9799 } else {
9800 None
9801 }
9802 });
9803
9804 Ok(proto::Ack {})
9805 }
9806
9807 pub fn disk_based_diagnostics_started(
9808 &mut self,
9809 language_server_id: LanguageServerId,
9810 cx: &mut Context<Self>,
9811 ) {
9812 if let Some(language_server_status) =
9813 self.language_server_statuses.get_mut(&language_server_id)
9814 {
9815 language_server_status.has_pending_diagnostic_updates = true;
9816 }
9817
9818 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9819 cx.emit(LspStoreEvent::LanguageServerUpdate {
9820 language_server_id,
9821 name: self
9822 .language_server_adapter_for_id(language_server_id)
9823 .map(|adapter| adapter.name()),
9824 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9825 Default::default(),
9826 ),
9827 })
9828 }
9829
9830 pub fn disk_based_diagnostics_finished(
9831 &mut self,
9832 language_server_id: LanguageServerId,
9833 cx: &mut Context<Self>,
9834 ) {
9835 if let Some(language_server_status) =
9836 self.language_server_statuses.get_mut(&language_server_id)
9837 {
9838 language_server_status.has_pending_diagnostic_updates = false;
9839 }
9840
9841 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9842 cx.emit(LspStoreEvent::LanguageServerUpdate {
9843 language_server_id,
9844 name: self
9845 .language_server_adapter_for_id(language_server_id)
9846 .map(|adapter| adapter.name()),
9847 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9848 Default::default(),
9849 ),
9850 })
9851 }
9852
9853 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9854 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9855 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9856 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9857 // the language server might take some time to publish diagnostics.
9858 fn simulate_disk_based_diagnostics_events_if_needed(
9859 &mut self,
9860 language_server_id: LanguageServerId,
9861 cx: &mut Context<Self>,
9862 ) {
9863 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9864
9865 let Some(LanguageServerState::Running {
9866 simulate_disk_based_diagnostics_completion,
9867 adapter,
9868 ..
9869 }) = self
9870 .as_local_mut()
9871 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9872 else {
9873 return;
9874 };
9875
9876 if adapter.disk_based_diagnostics_progress_token.is_some() {
9877 return;
9878 }
9879
9880 let prev_task =
9881 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9882 cx.background_executor()
9883 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9884 .await;
9885
9886 this.update(cx, |this, cx| {
9887 this.disk_based_diagnostics_finished(language_server_id, cx);
9888
9889 if let Some(LanguageServerState::Running {
9890 simulate_disk_based_diagnostics_completion,
9891 ..
9892 }) = this.as_local_mut().and_then(|local_store| {
9893 local_store.language_servers.get_mut(&language_server_id)
9894 }) {
9895 *simulate_disk_based_diagnostics_completion = None;
9896 }
9897 })
9898 .ok();
9899 }));
9900
9901 if prev_task.is_none() {
9902 self.disk_based_diagnostics_started(language_server_id, cx);
9903 }
9904 }
9905
9906 pub fn language_server_statuses(
9907 &self,
9908 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9909 self.language_server_statuses
9910 .iter()
9911 .map(|(key, value)| (*key, value))
9912 }
9913
9914 pub(super) fn did_rename_entry(
9915 &self,
9916 worktree_id: WorktreeId,
9917 old_path: &Path,
9918 new_path: &Path,
9919 is_dir: bool,
9920 ) {
9921 maybe!({
9922 let local_store = self.as_local()?;
9923
9924 let old_uri = lsp::Uri::from_file_path(old_path)
9925 .ok()
9926 .map(|uri| uri.to_string())?;
9927 let new_uri = lsp::Uri::from_file_path(new_path)
9928 .ok()
9929 .map(|uri| uri.to_string())?;
9930
9931 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9932 let Some(filter) = local_store
9933 .language_server_paths_watched_for_rename
9934 .get(&language_server.server_id())
9935 else {
9936 continue;
9937 };
9938
9939 if filter.should_send_did_rename(&old_uri, is_dir) {
9940 language_server
9941 .notify::<DidRenameFiles>(RenameFilesParams {
9942 files: vec![FileRename {
9943 old_uri: old_uri.clone(),
9944 new_uri: new_uri.clone(),
9945 }],
9946 })
9947 .ok();
9948 }
9949 }
9950 Some(())
9951 });
9952 }
9953
9954 pub(super) fn will_rename_entry(
9955 this: WeakEntity<Self>,
9956 worktree_id: WorktreeId,
9957 old_path: &Path,
9958 new_path: &Path,
9959 is_dir: bool,
9960 cx: AsyncApp,
9961 ) -> Task<ProjectTransaction> {
9962 let old_uri = lsp::Uri::from_file_path(old_path)
9963 .ok()
9964 .map(|uri| uri.to_string());
9965 let new_uri = lsp::Uri::from_file_path(new_path)
9966 .ok()
9967 .map(|uri| uri.to_string());
9968 cx.spawn(async move |cx| {
9969 let mut tasks = vec![];
9970 this.update(cx, |this, cx| {
9971 let local_store = this.as_local()?;
9972 let old_uri = old_uri?;
9973 let new_uri = new_uri?;
9974 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9975 let Some(filter) = local_store
9976 .language_server_paths_watched_for_rename
9977 .get(&language_server.server_id())
9978 else {
9979 continue;
9980 };
9981
9982 if !filter.should_send_will_rename(&old_uri, is_dir) {
9983 continue;
9984 }
9985 let request_timeout = ProjectSettings::get_global(cx)
9986 .global_lsp_settings
9987 .get_request_timeout();
9988
9989 let apply_edit = cx.spawn({
9990 let old_uri = old_uri.clone();
9991 let new_uri = new_uri.clone();
9992 let language_server = language_server.clone();
9993 async move |this, cx| {
9994 let edit = language_server
9995 .request::<WillRenameFiles>(
9996 RenameFilesParams {
9997 files: vec![FileRename { old_uri, new_uri }],
9998 },
9999 request_timeout,
10000 )
10001 .await
10002 .into_response()
10003 .context("will rename files")
10004 .log_err()
10005 .flatten()?;
10006
10007 LocalLspStore::deserialize_workspace_edit(
10008 this.upgrade()?,
10009 edit,
10010 false,
10011 language_server.clone(),
10012 cx,
10013 )
10014 .await
10015 .ok()
10016 }
10017 });
10018 tasks.push(apply_edit);
10019 }
10020 Some(())
10021 })
10022 .ok()
10023 .flatten();
10024 let mut merged_transaction = ProjectTransaction::default();
10025 for task in tasks {
10026 // Await on tasks sequentially so that the order of application of edits is deterministic
10027 // (at least with regards to the order of registration of language servers)
10028 if let Some(transaction) = task.await {
10029 for (buffer, buffer_transaction) in transaction.0 {
10030 merged_transaction.0.insert(buffer, buffer_transaction);
10031 }
10032 }
10033 }
10034 merged_transaction
10035 })
10036 }
10037
10038 fn lsp_notify_abs_paths_changed(
10039 &mut self,
10040 server_id: LanguageServerId,
10041 changes: Vec<PathEvent>,
10042 ) {
10043 maybe!({
10044 let server = self.language_server_for_id(server_id)?;
10045 let changes = changes
10046 .into_iter()
10047 .filter_map(|event| {
10048 let typ = match event.kind? {
10049 PathEventKind::Created => lsp::FileChangeType::CREATED,
10050 PathEventKind::Removed => lsp::FileChangeType::DELETED,
10051 PathEventKind::Changed | PathEventKind::Rescan => {
10052 lsp::FileChangeType::CHANGED
10053 }
10054 };
10055 Some(lsp::FileEvent {
10056 uri: file_path_to_lsp_url(&event.path).log_err()?,
10057 typ,
10058 })
10059 })
10060 .collect::<Vec<_>>();
10061 if !changes.is_empty() {
10062 server
10063 .notify::<lsp::notification::DidChangeWatchedFiles>(
10064 lsp::DidChangeWatchedFilesParams { changes },
10065 )
10066 .ok();
10067 }
10068 Some(())
10069 });
10070 }
10071
10072 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
10073 self.as_local()?.language_server_for_id(id)
10074 }
10075
10076 fn on_lsp_progress(
10077 &mut self,
10078 progress_params: lsp::ProgressParams,
10079 language_server_id: LanguageServerId,
10080 disk_based_diagnostics_progress_token: Option<String>,
10081 cx: &mut Context<Self>,
10082 ) {
10083 match progress_params.value {
10084 lsp::ProgressParamsValue::WorkDone(progress) => {
10085 self.handle_work_done_progress(
10086 progress,
10087 language_server_id,
10088 disk_based_diagnostics_progress_token,
10089 ProgressToken::from_lsp(progress_params.token),
10090 cx,
10091 );
10092 }
10093 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
10094 let registration_id = match progress_params.token {
10095 lsp::NumberOrString::Number(_) => None,
10096 lsp::NumberOrString::String(token) => token
10097 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
10098 .map(|(_, id)| id.to_owned()),
10099 };
10100 if let Some(LanguageServerState::Running {
10101 workspace_diagnostics_refresh_tasks,
10102 ..
10103 }) = self
10104 .as_local_mut()
10105 .and_then(|local| local.language_servers.get_mut(&language_server_id))
10106 && let Some(workspace_diagnostics) =
10107 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
10108 {
10109 workspace_diagnostics.progress_tx.try_send(()).ok();
10110 self.apply_workspace_diagnostic_report(
10111 language_server_id,
10112 report,
10113 registration_id.map(SharedString::from),
10114 cx,
10115 )
10116 }
10117 }
10118 }
10119 }
10120
10121 fn handle_work_done_progress(
10122 &mut self,
10123 progress: lsp::WorkDoneProgress,
10124 language_server_id: LanguageServerId,
10125 disk_based_diagnostics_progress_token: Option<String>,
10126 token: ProgressToken,
10127 cx: &mut Context<Self>,
10128 ) {
10129 let language_server_status =
10130 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10131 status
10132 } else {
10133 return;
10134 };
10135
10136 if !language_server_status.progress_tokens.contains(&token) {
10137 return;
10138 }
10139
10140 let is_disk_based_diagnostics_progress =
10141 if let (Some(disk_based_token), ProgressToken::String(token)) =
10142 (&disk_based_diagnostics_progress_token, &token)
10143 {
10144 token.starts_with(disk_based_token)
10145 } else {
10146 false
10147 };
10148
10149 match progress {
10150 lsp::WorkDoneProgress::Begin(report) => {
10151 if is_disk_based_diagnostics_progress {
10152 self.disk_based_diagnostics_started(language_server_id, cx);
10153 }
10154 self.on_lsp_work_start(
10155 language_server_id,
10156 token.clone(),
10157 LanguageServerProgress {
10158 title: Some(report.title),
10159 is_disk_based_diagnostics_progress,
10160 is_cancellable: report.cancellable.unwrap_or(false),
10161 message: report.message.clone(),
10162 percentage: report.percentage.map(|p| p as usize),
10163 last_update_at: cx.background_executor().now(),
10164 },
10165 cx,
10166 );
10167 }
10168 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
10169 language_server_id,
10170 token,
10171 LanguageServerProgress {
10172 title: None,
10173 is_disk_based_diagnostics_progress,
10174 is_cancellable: report.cancellable.unwrap_or(false),
10175 message: report.message,
10176 percentage: report.percentage.map(|p| p as usize),
10177 last_update_at: cx.background_executor().now(),
10178 },
10179 cx,
10180 ),
10181 lsp::WorkDoneProgress::End(_) => {
10182 language_server_status.progress_tokens.remove(&token);
10183 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10184 if is_disk_based_diagnostics_progress {
10185 self.disk_based_diagnostics_finished(language_server_id, cx);
10186 }
10187 }
10188 }
10189 }
10190
10191 fn on_lsp_work_start(
10192 &mut self,
10193 language_server_id: LanguageServerId,
10194 token: ProgressToken,
10195 progress: LanguageServerProgress,
10196 cx: &mut Context<Self>,
10197 ) {
10198 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10199 status.pending_work.insert(token.clone(), progress.clone());
10200 cx.notify();
10201 }
10202 cx.emit(LspStoreEvent::LanguageServerUpdate {
10203 language_server_id,
10204 name: self
10205 .language_server_adapter_for_id(language_server_id)
10206 .map(|adapter| adapter.name()),
10207 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10208 token: Some(token.to_proto()),
10209 title: progress.title,
10210 message: progress.message,
10211 percentage: progress.percentage.map(|p| p as u32),
10212 is_cancellable: Some(progress.is_cancellable),
10213 }),
10214 })
10215 }
10216
10217 fn on_lsp_work_progress(
10218 &mut self,
10219 language_server_id: LanguageServerId,
10220 token: ProgressToken,
10221 progress: LanguageServerProgress,
10222 cx: &mut Context<Self>,
10223 ) {
10224 let mut did_update = false;
10225 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10226 match status.pending_work.entry(token.clone()) {
10227 btree_map::Entry::Vacant(entry) => {
10228 entry.insert(progress.clone());
10229 did_update = true;
10230 }
10231 btree_map::Entry::Occupied(mut entry) => {
10232 let entry = entry.get_mut();
10233 if (progress.last_update_at - entry.last_update_at)
10234 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10235 {
10236 entry.last_update_at = progress.last_update_at;
10237 if progress.message.is_some() {
10238 entry.message = progress.message.clone();
10239 }
10240 if progress.percentage.is_some() {
10241 entry.percentage = progress.percentage;
10242 }
10243 if progress.is_cancellable != entry.is_cancellable {
10244 entry.is_cancellable = progress.is_cancellable;
10245 }
10246 did_update = true;
10247 }
10248 }
10249 }
10250 }
10251
10252 if did_update {
10253 cx.emit(LspStoreEvent::LanguageServerUpdate {
10254 language_server_id,
10255 name: self
10256 .language_server_adapter_for_id(language_server_id)
10257 .map(|adapter| adapter.name()),
10258 message: proto::update_language_server::Variant::WorkProgress(
10259 proto::LspWorkProgress {
10260 token: Some(token.to_proto()),
10261 message: progress.message,
10262 percentage: progress.percentage.map(|p| p as u32),
10263 is_cancellable: Some(progress.is_cancellable),
10264 },
10265 ),
10266 })
10267 }
10268 }
10269
10270 fn on_lsp_work_end(
10271 &mut self,
10272 language_server_id: LanguageServerId,
10273 token: ProgressToken,
10274 cx: &mut Context<Self>,
10275 ) {
10276 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10277 if let Some(work) = status.pending_work.remove(&token)
10278 && !work.is_disk_based_diagnostics_progress
10279 {
10280 cx.emit(LspStoreEvent::RefreshInlayHints {
10281 server_id: language_server_id,
10282 request_id: None,
10283 });
10284 }
10285 cx.notify();
10286 }
10287
10288 cx.emit(LspStoreEvent::LanguageServerUpdate {
10289 language_server_id,
10290 name: self
10291 .language_server_adapter_for_id(language_server_id)
10292 .map(|adapter| adapter.name()),
10293 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10294 token: Some(token.to_proto()),
10295 }),
10296 })
10297 }
10298
10299 pub async fn handle_resolve_completion_documentation(
10300 this: Entity<Self>,
10301 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10302 mut cx: AsyncApp,
10303 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10304 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10305
10306 let completion = this
10307 .read_with(&cx, |this, cx| {
10308 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10309 let server = this
10310 .language_server_for_id(id)
10311 .with_context(|| format!("No language server {id}"))?;
10312
10313 let request_timeout = ProjectSettings::get_global(cx)
10314 .global_lsp_settings
10315 .get_request_timeout();
10316
10317 anyhow::Ok(cx.background_spawn(async move {
10318 let can_resolve = server
10319 .capabilities()
10320 .completion_provider
10321 .as_ref()
10322 .and_then(|options| options.resolve_provider)
10323 .unwrap_or(false);
10324 if can_resolve {
10325 server
10326 .request::<lsp::request::ResolveCompletionItem>(
10327 lsp_completion,
10328 request_timeout,
10329 )
10330 .await
10331 .into_response()
10332 .context("resolve completion item")
10333 } else {
10334 anyhow::Ok(lsp_completion)
10335 }
10336 }))
10337 })?
10338 .await?;
10339
10340 let mut documentation_is_markdown = false;
10341 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10342 let documentation = match completion.documentation {
10343 Some(lsp::Documentation::String(text)) => text,
10344
10345 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10346 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10347 value
10348 }
10349
10350 _ => String::new(),
10351 };
10352
10353 // If we have a new buffer_id, that means we're talking to a new client
10354 // and want to check for new text_edits in the completion too.
10355 let mut old_replace_start = None;
10356 let mut old_replace_end = None;
10357 let mut old_insert_start = None;
10358 let mut old_insert_end = None;
10359 let mut new_text = String::default();
10360 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10361 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10362 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10363 anyhow::Ok(buffer.read(cx).snapshot())
10364 })?;
10365
10366 if let Some(text_edit) = completion.text_edit.as_ref() {
10367 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10368
10369 if let Some(mut edit) = edit {
10370 LineEnding::normalize(&mut edit.new_text);
10371
10372 new_text = edit.new_text;
10373 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10374 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10375 if let Some(insert_range) = edit.insert_range {
10376 old_insert_start = Some(serialize_anchor(&insert_range.start));
10377 old_insert_end = Some(serialize_anchor(&insert_range.end));
10378 }
10379 }
10380 }
10381 }
10382
10383 Ok(proto::ResolveCompletionDocumentationResponse {
10384 documentation,
10385 documentation_is_markdown,
10386 old_replace_start,
10387 old_replace_end,
10388 new_text,
10389 lsp_completion,
10390 old_insert_start,
10391 old_insert_end,
10392 })
10393 }
10394
10395 async fn handle_on_type_formatting(
10396 this: Entity<Self>,
10397 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10398 mut cx: AsyncApp,
10399 ) -> Result<proto::OnTypeFormattingResponse> {
10400 let on_type_formatting = this.update(&mut cx, |this, cx| {
10401 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10402 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10403 let position = envelope
10404 .payload
10405 .position
10406 .and_then(deserialize_anchor)
10407 .context("invalid position")?;
10408 anyhow::Ok(this.apply_on_type_formatting(
10409 buffer,
10410 position,
10411 envelope.payload.trigger.clone(),
10412 cx,
10413 ))
10414 })?;
10415
10416 let transaction = on_type_formatting
10417 .await?
10418 .as_ref()
10419 .map(language::proto::serialize_transaction);
10420 Ok(proto::OnTypeFormattingResponse { transaction })
10421 }
10422
10423 async fn handle_pull_workspace_diagnostics(
10424 lsp_store: Entity<Self>,
10425 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10426 mut cx: AsyncApp,
10427 ) -> Result<proto::Ack> {
10428 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10429 lsp_store.update(&mut cx, |lsp_store, _| {
10430 lsp_store.pull_workspace_diagnostics(server_id);
10431 });
10432 Ok(proto::Ack {})
10433 }
10434
10435 async fn handle_open_buffer_for_symbol(
10436 this: Entity<Self>,
10437 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10438 mut cx: AsyncApp,
10439 ) -> Result<proto::OpenBufferForSymbolResponse> {
10440 let peer_id = envelope.original_sender_id().unwrap_or_default();
10441 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10442 let symbol = Self::deserialize_symbol(symbol)?;
10443 this.read_with(&cx, |this, _| {
10444 if let SymbolLocation::OutsideProject {
10445 abs_path,
10446 signature,
10447 } = &symbol.path
10448 {
10449 let new_signature = this.symbol_signature(&abs_path);
10450 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10451 }
10452 Ok(())
10453 })?;
10454 let buffer = this
10455 .update(&mut cx, |this, cx| {
10456 this.open_buffer_for_symbol(
10457 &Symbol {
10458 language_server_name: symbol.language_server_name,
10459 source_worktree_id: symbol.source_worktree_id,
10460 source_language_server_id: symbol.source_language_server_id,
10461 path: symbol.path,
10462 name: symbol.name,
10463 kind: symbol.kind,
10464 range: symbol.range,
10465 label: CodeLabel::default(),
10466 container_name: symbol.container_name,
10467 },
10468 cx,
10469 )
10470 })
10471 .await?;
10472
10473 this.update(&mut cx, |this, cx| {
10474 let is_private = buffer
10475 .read(cx)
10476 .file()
10477 .map(|f| f.is_private())
10478 .unwrap_or_default();
10479 if is_private {
10480 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10481 } else {
10482 this.buffer_store
10483 .update(cx, |buffer_store, cx| {
10484 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10485 })
10486 .detach_and_log_err(cx);
10487 let buffer_id = buffer.read(cx).remote_id().to_proto();
10488 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10489 }
10490 })
10491 }
10492
10493 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10494 let mut hasher = Sha256::new();
10495 hasher.update(abs_path.to_string_lossy().as_bytes());
10496 hasher.update(self.nonce.to_be_bytes());
10497 hasher.finalize().as_slice().try_into().unwrap()
10498 }
10499
10500 pub async fn handle_get_project_symbols(
10501 this: Entity<Self>,
10502 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10503 mut cx: AsyncApp,
10504 ) -> Result<proto::GetProjectSymbolsResponse> {
10505 let symbols = this
10506 .update(&mut cx, |this, cx| {
10507 this.symbols(&envelope.payload.query, cx)
10508 })
10509 .await?;
10510
10511 Ok(proto::GetProjectSymbolsResponse {
10512 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10513 })
10514 }
10515
10516 pub async fn handle_restart_language_servers(
10517 this: Entity<Self>,
10518 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10519 mut cx: AsyncApp,
10520 ) -> Result<proto::Ack> {
10521 this.update(&mut cx, |lsp_store, cx| {
10522 let buffers =
10523 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10524 lsp_store.restart_language_servers_for_buffers(
10525 buffers,
10526 envelope
10527 .payload
10528 .only_servers
10529 .into_iter()
10530 .filter_map(|selector| {
10531 Some(match selector.selector? {
10532 proto::language_server_selector::Selector::ServerId(server_id) => {
10533 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10534 }
10535 proto::language_server_selector::Selector::Name(name) => {
10536 LanguageServerSelector::Name(LanguageServerName(
10537 SharedString::from(name),
10538 ))
10539 }
10540 })
10541 })
10542 .collect(),
10543 true,
10544 cx,
10545 );
10546 });
10547
10548 Ok(proto::Ack {})
10549 }
10550
10551 pub async fn handle_stop_language_servers(
10552 lsp_store: Entity<Self>,
10553 envelope: TypedEnvelope<proto::StopLanguageServers>,
10554 mut cx: AsyncApp,
10555 ) -> Result<proto::Ack> {
10556 lsp_store.update(&mut cx, |lsp_store, cx| {
10557 if envelope.payload.all
10558 && envelope.payload.also_servers.is_empty()
10559 && envelope.payload.buffer_ids.is_empty()
10560 {
10561 lsp_store.stop_all_language_servers(cx);
10562 } else {
10563 let buffers =
10564 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10565 lsp_store
10566 .stop_language_servers_for_buffers(
10567 buffers,
10568 envelope
10569 .payload
10570 .also_servers
10571 .into_iter()
10572 .filter_map(|selector| {
10573 Some(match selector.selector? {
10574 proto::language_server_selector::Selector::ServerId(
10575 server_id,
10576 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10577 server_id,
10578 )),
10579 proto::language_server_selector::Selector::Name(name) => {
10580 LanguageServerSelector::Name(LanguageServerName(
10581 SharedString::from(name),
10582 ))
10583 }
10584 })
10585 })
10586 .collect(),
10587 cx,
10588 )
10589 .detach_and_log_err(cx);
10590 }
10591 });
10592
10593 Ok(proto::Ack {})
10594 }
10595
10596 pub async fn handle_cancel_language_server_work(
10597 lsp_store: Entity<Self>,
10598 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10599 mut cx: AsyncApp,
10600 ) -> Result<proto::Ack> {
10601 lsp_store.update(&mut cx, |lsp_store, cx| {
10602 if let Some(work) = envelope.payload.work {
10603 match work {
10604 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10605 let buffers =
10606 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10607 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10608 }
10609 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10610 let server_id = LanguageServerId::from_proto(work.language_server_id);
10611 let token = work
10612 .token
10613 .map(|token| {
10614 ProgressToken::from_proto(token)
10615 .context("invalid work progress token")
10616 })
10617 .transpose()?;
10618 lsp_store.cancel_language_server_work(server_id, token, cx);
10619 }
10620 }
10621 }
10622 anyhow::Ok(())
10623 })?;
10624
10625 Ok(proto::Ack {})
10626 }
10627
10628 fn buffer_ids_to_buffers(
10629 &mut self,
10630 buffer_ids: impl Iterator<Item = u64>,
10631 cx: &mut Context<Self>,
10632 ) -> Vec<Entity<Buffer>> {
10633 buffer_ids
10634 .into_iter()
10635 .flat_map(|buffer_id| {
10636 self.buffer_store
10637 .read(cx)
10638 .get(BufferId::new(buffer_id).log_err()?)
10639 })
10640 .collect::<Vec<_>>()
10641 }
10642
10643 async fn handle_apply_additional_edits_for_completion(
10644 this: Entity<Self>,
10645 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10646 mut cx: AsyncApp,
10647 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10648 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10649 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10650 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10651 let completion = Self::deserialize_completion(
10652 envelope.payload.completion.context("invalid completion")?,
10653 )?;
10654 let all_commit_ranges = envelope
10655 .payload
10656 .all_commit_ranges
10657 .into_iter()
10658 .map(language::proto::deserialize_anchor_range)
10659 .collect::<Result<Vec<_>, _>>()?;
10660 anyhow::Ok((buffer, completion, all_commit_ranges))
10661 })?;
10662
10663 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10664 this.apply_additional_edits_for_completion(
10665 buffer,
10666 Rc::new(RefCell::new(Box::new([Completion {
10667 replace_range: completion.replace_range,
10668 new_text: completion.new_text,
10669 source: completion.source,
10670 documentation: None,
10671 label: CodeLabel::default(),
10672 match_start: None,
10673 snippet_deduplication_key: None,
10674 insert_text_mode: None,
10675 icon_path: None,
10676 confirm: None,
10677 }]))),
10678 0,
10679 false,
10680 all_commit_ranges,
10681 cx,
10682 )
10683 });
10684
10685 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10686 transaction: apply_additional_edits
10687 .await?
10688 .as_ref()
10689 .map(language::proto::serialize_transaction),
10690 })
10691 }
10692
10693 pub fn last_formatting_failure(&self) -> Option<&str> {
10694 self.last_formatting_failure.as_deref()
10695 }
10696
10697 pub fn reset_last_formatting_failure(&mut self) {
10698 self.last_formatting_failure = None;
10699 }
10700
10701 pub fn environment_for_buffer(
10702 &self,
10703 buffer: &Entity<Buffer>,
10704 cx: &mut Context<Self>,
10705 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10706 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10707 environment.update(cx, |env, cx| {
10708 env.buffer_environment(buffer, &self.worktree_store, cx)
10709 })
10710 } else {
10711 Task::ready(None).shared()
10712 }
10713 }
10714
10715 pub fn format(
10716 &mut self,
10717 buffers: HashSet<Entity<Buffer>>,
10718 target: LspFormatTarget,
10719 push_to_history: bool,
10720 trigger: FormatTrigger,
10721 cx: &mut Context<Self>,
10722 ) -> Task<anyhow::Result<ProjectTransaction>> {
10723 let logger = zlog::scoped!("format");
10724 if self.as_local().is_some() {
10725 zlog::trace!(logger => "Formatting locally");
10726 let logger = zlog::scoped!(logger => "local");
10727 let buffers = buffers
10728 .into_iter()
10729 .map(|buffer_handle| {
10730 let buffer = buffer_handle.read(cx);
10731 let buffer_abs_path = File::from_dyn(buffer.file())
10732 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10733
10734 (buffer_handle, buffer_abs_path, buffer.remote_id())
10735 })
10736 .collect::<Vec<_>>();
10737
10738 cx.spawn(async move |lsp_store, cx| {
10739 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10740
10741 for (handle, abs_path, id) in buffers {
10742 let env = lsp_store
10743 .update(cx, |lsp_store, cx| {
10744 lsp_store.environment_for_buffer(&handle, cx)
10745 })?
10746 .await;
10747
10748 let ranges = match &target {
10749 LspFormatTarget::Buffers => None,
10750 LspFormatTarget::Ranges(ranges) => {
10751 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10752 }
10753 };
10754
10755 formattable_buffers.push(FormattableBuffer {
10756 handle,
10757 abs_path,
10758 env,
10759 ranges,
10760 });
10761 }
10762 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10763
10764 let format_timer = zlog::time!(logger => "Formatting buffers");
10765 let result = LocalLspStore::format_locally(
10766 lsp_store.clone(),
10767 formattable_buffers,
10768 push_to_history,
10769 trigger,
10770 logger,
10771 cx,
10772 )
10773 .await;
10774 format_timer.end();
10775
10776 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10777
10778 lsp_store.update(cx, |lsp_store, _| {
10779 lsp_store.update_last_formatting_failure(&result);
10780 })?;
10781
10782 result
10783 })
10784 } else if let Some((client, project_id)) = self.upstream_client() {
10785 zlog::trace!(logger => "Formatting remotely");
10786 let logger = zlog::scoped!(logger => "remote");
10787
10788 let buffer_ranges = match &target {
10789 LspFormatTarget::Buffers => Vec::new(),
10790 LspFormatTarget::Ranges(ranges) => ranges
10791 .iter()
10792 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10793 buffer_id: buffer_id.to_proto(),
10794 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10795 })
10796 .collect(),
10797 };
10798
10799 let buffer_store = self.buffer_store();
10800 cx.spawn(async move |lsp_store, cx| {
10801 zlog::trace!(logger => "Sending remote format request");
10802 let request_timer = zlog::time!(logger => "remote format request");
10803 let result = client
10804 .request(proto::FormatBuffers {
10805 project_id,
10806 trigger: trigger as i32,
10807 buffer_ids: buffers
10808 .iter()
10809 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10810 .collect(),
10811 buffer_ranges,
10812 })
10813 .await
10814 .and_then(|result| result.transaction.context("missing transaction"));
10815 request_timer.end();
10816
10817 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10818
10819 lsp_store.update(cx, |lsp_store, _| {
10820 lsp_store.update_last_formatting_failure(&result);
10821 })?;
10822
10823 let transaction_response = result?;
10824 let _timer = zlog::time!(logger => "deserializing project transaction");
10825 buffer_store
10826 .update(cx, |buffer_store, cx| {
10827 buffer_store.deserialize_project_transaction(
10828 transaction_response,
10829 push_to_history,
10830 cx,
10831 )
10832 })
10833 .await
10834 })
10835 } else {
10836 zlog::trace!(logger => "Not formatting");
10837 Task::ready(Ok(ProjectTransaction::default()))
10838 }
10839 }
10840
10841 async fn handle_format_buffers(
10842 this: Entity<Self>,
10843 envelope: TypedEnvelope<proto::FormatBuffers>,
10844 mut cx: AsyncApp,
10845 ) -> Result<proto::FormatBuffersResponse> {
10846 let sender_id = envelope.original_sender_id().unwrap_or_default();
10847 let format = this.update(&mut cx, |this, cx| {
10848 let mut buffers = HashSet::default();
10849 for buffer_id in &envelope.payload.buffer_ids {
10850 let buffer_id = BufferId::new(*buffer_id)?;
10851 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10852 }
10853
10854 let target = if envelope.payload.buffer_ranges.is_empty() {
10855 LspFormatTarget::Buffers
10856 } else {
10857 let mut ranges_map = BTreeMap::new();
10858 for buffer_range in &envelope.payload.buffer_ranges {
10859 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10860 let ranges: Result<Vec<_>> = buffer_range
10861 .ranges
10862 .iter()
10863 .map(|range| {
10864 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10865 })
10866 .collect();
10867 ranges_map.insert(buffer_id, ranges?);
10868 }
10869 LspFormatTarget::Ranges(ranges_map)
10870 };
10871
10872 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10873 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10874 })?;
10875
10876 let project_transaction = format.await?;
10877 let project_transaction = this.update(&mut cx, |this, cx| {
10878 this.buffer_store.update(cx, |buffer_store, cx| {
10879 buffer_store.serialize_project_transaction_for_peer(
10880 project_transaction,
10881 sender_id,
10882 cx,
10883 )
10884 })
10885 });
10886 Ok(proto::FormatBuffersResponse {
10887 transaction: Some(project_transaction),
10888 })
10889 }
10890
10891 async fn handle_apply_code_action_kind(
10892 this: Entity<Self>,
10893 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10894 mut cx: AsyncApp,
10895 ) -> Result<proto::ApplyCodeActionKindResponse> {
10896 let sender_id = envelope.original_sender_id().unwrap_or_default();
10897 let format = this.update(&mut cx, |this, cx| {
10898 let mut buffers = HashSet::default();
10899 for buffer_id in &envelope.payload.buffer_ids {
10900 let buffer_id = BufferId::new(*buffer_id)?;
10901 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10902 }
10903 let kind = match envelope.payload.kind.as_str() {
10904 "" => CodeActionKind::EMPTY,
10905 "quickfix" => CodeActionKind::QUICKFIX,
10906 "refactor" => CodeActionKind::REFACTOR,
10907 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10908 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10909 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10910 "source" => CodeActionKind::SOURCE,
10911 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10912 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10913 _ => anyhow::bail!(
10914 "Invalid code action kind {}",
10915 envelope.payload.kind.as_str()
10916 ),
10917 };
10918 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10919 })?;
10920
10921 let project_transaction = format.await?;
10922 let project_transaction = this.update(&mut cx, |this, cx| {
10923 this.buffer_store.update(cx, |buffer_store, cx| {
10924 buffer_store.serialize_project_transaction_for_peer(
10925 project_transaction,
10926 sender_id,
10927 cx,
10928 )
10929 })
10930 });
10931 Ok(proto::ApplyCodeActionKindResponse {
10932 transaction: Some(project_transaction),
10933 })
10934 }
10935
10936 async fn shutdown_language_server(
10937 server_state: Option<LanguageServerState>,
10938 name: LanguageServerName,
10939 cx: &mut AsyncApp,
10940 ) {
10941 let server = match server_state {
10942 Some(LanguageServerState::Starting { startup, .. }) => {
10943 let mut timer = cx
10944 .background_executor()
10945 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10946 .fuse();
10947
10948 select! {
10949 server = startup.fuse() => server,
10950 () = timer => {
10951 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10952 None
10953 },
10954 }
10955 }
10956
10957 Some(LanguageServerState::Running { server, .. }) => Some(server),
10958
10959 None => None,
10960 };
10961
10962 let Some(server) = server else { return };
10963 if let Some(shutdown) = server.shutdown() {
10964 shutdown.await;
10965 }
10966 }
10967
10968 // Returns a list of all of the worktrees which no longer have a language server and the root path
10969 // for the stopped server
10970 fn stop_local_language_server(
10971 &mut self,
10972 server_id: LanguageServerId,
10973 cx: &mut Context<Self>,
10974 ) -> Task<()> {
10975 let local = match &mut self.mode {
10976 LspStoreMode::Local(local) => local,
10977 _ => {
10978 return Task::ready(());
10979 }
10980 };
10981
10982 // Remove this server ID from all entries in the given worktree.
10983 local
10984 .language_server_ids
10985 .retain(|_, state| state.id != server_id);
10986 self.buffer_store.update(cx, |buffer_store, cx| {
10987 for buffer in buffer_store.buffers() {
10988 buffer.update(cx, |buffer, cx| {
10989 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10990 buffer.set_completion_triggers(server_id, Default::default(), cx);
10991 });
10992 }
10993 });
10994
10995 let mut cleared_paths: Vec<ProjectPath> = Vec::new();
10996 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10997 summaries.retain(|path, summaries_by_server_id| {
10998 if summaries_by_server_id.remove(&server_id).is_some() {
10999 if let Some((client, project_id)) = self.downstream_client.clone() {
11000 client
11001 .send(proto::UpdateDiagnosticSummary {
11002 project_id,
11003 worktree_id: worktree_id.to_proto(),
11004 summary: Some(proto::DiagnosticSummary {
11005 path: path.as_ref().to_proto(),
11006 language_server_id: server_id.0 as u64,
11007 error_count: 0,
11008 warning_count: 0,
11009 }),
11010 more_summaries: Vec::new(),
11011 })
11012 .log_err();
11013 }
11014 cleared_paths.push(ProjectPath {
11015 worktree_id: *worktree_id,
11016 path: path.clone(),
11017 });
11018 !summaries_by_server_id.is_empty()
11019 } else {
11020 true
11021 }
11022 });
11023 }
11024 if !cleared_paths.is_empty() {
11025 cx.emit(LspStoreEvent::DiagnosticsUpdated {
11026 server_id,
11027 paths: cleared_paths,
11028 });
11029 }
11030
11031 let local = self.as_local_mut().unwrap();
11032 for diagnostics in local.diagnostics.values_mut() {
11033 diagnostics.retain(|_, diagnostics_by_server_id| {
11034 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
11035 diagnostics_by_server_id.remove(ix);
11036 !diagnostics_by_server_id.is_empty()
11037 } else {
11038 true
11039 }
11040 });
11041 }
11042 local.language_server_watched_paths.remove(&server_id);
11043
11044 let server_state = local.language_servers.remove(&server_id);
11045 self.cleanup_lsp_data(server_id);
11046 let name = self
11047 .language_server_statuses
11048 .remove(&server_id)
11049 .map(|status| status.name)
11050 .or_else(|| {
11051 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
11052 Some(adapter.name())
11053 } else {
11054 None
11055 }
11056 });
11057
11058 if let Some(name) = name {
11059 log::info!("stopping language server {name}");
11060 self.languages
11061 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
11062 cx.notify();
11063
11064 return cx.spawn(async move |lsp_store, cx| {
11065 Self::shutdown_language_server(server_state, name.clone(), cx).await;
11066 lsp_store
11067 .update(cx, |lsp_store, cx| {
11068 lsp_store
11069 .languages
11070 .update_lsp_binary_status(name, BinaryStatus::Stopped);
11071 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11072 cx.notify();
11073 })
11074 .ok();
11075 });
11076 }
11077
11078 if server_state.is_some() {
11079 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
11080 }
11081 Task::ready(())
11082 }
11083
11084 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
11085 if let Some(local) = self.as_local_mut() {
11086 local.all_language_servers_stopped = true;
11087 }
11088 self.shutdown_all_language_servers(cx).detach();
11089 }
11090
11091 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
11092 if let Some((client, project_id)) = self.upstream_client() {
11093 let request = client.request(proto::StopLanguageServers {
11094 project_id,
11095 buffer_ids: Vec::new(),
11096 also_servers: Vec::new(),
11097 all: true,
11098 });
11099 cx.background_spawn(async move {
11100 request.await.ok();
11101 })
11102 } else {
11103 let Some(local) = self.as_local_mut() else {
11104 return Task::ready(());
11105 };
11106 let language_servers_to_stop = local
11107 .language_server_ids
11108 .values()
11109 .map(|state| state.id)
11110 .collect();
11111 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11112 let tasks = language_servers_to_stop
11113 .into_iter()
11114 .map(|server| self.stop_local_language_server(server, cx))
11115 .collect::<Vec<_>>();
11116 cx.background_spawn(async move {
11117 futures::future::join_all(tasks).await;
11118 })
11119 }
11120 }
11121
11122 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
11123 if let Some(local) = self.as_local_mut() {
11124 local.all_language_servers_stopped = false;
11125 local.stopped_language_servers.clear();
11126 }
11127 let buffers = self.buffer_store.read(cx).buffers().collect();
11128 self.restart_language_servers_for_buffers(buffers, HashSet::default(), true, cx);
11129 }
11130
11131 pub fn restart_language_servers_for_buffers(
11132 &mut self,
11133 buffers: Vec<Entity<Buffer>>,
11134 only_restart_servers: HashSet<LanguageServerSelector>,
11135 clear_stopped: bool,
11136 cx: &mut Context<Self>,
11137 ) {
11138 if let Some((client, project_id)) = self.upstream_client() {
11139 let request = client.request(proto::RestartLanguageServers {
11140 project_id,
11141 buffer_ids: buffers
11142 .into_iter()
11143 .map(|b| b.read(cx).remote_id().to_proto())
11144 .collect(),
11145 only_servers: only_restart_servers
11146 .into_iter()
11147 .map(|selector| {
11148 let selector = match selector {
11149 LanguageServerSelector::Id(language_server_id) => {
11150 proto::language_server_selector::Selector::ServerId(
11151 language_server_id.to_proto(),
11152 )
11153 }
11154 LanguageServerSelector::Name(language_server_name) => {
11155 proto::language_server_selector::Selector::Name(
11156 language_server_name.to_string(),
11157 )
11158 }
11159 };
11160 proto::LanguageServerSelector {
11161 selector: Some(selector),
11162 }
11163 })
11164 .collect(),
11165 all: false,
11166 });
11167 cx.background_spawn(request).detach_and_log_err(cx);
11168 } else {
11169 let (stopped_names, stop_task) = if only_restart_servers.is_empty() {
11170 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
11171 } else {
11172 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
11173 };
11174 cx.spawn(async move |lsp_store, cx| {
11175 stop_task.await;
11176 lsp_store.update(cx, |lsp_store, cx| {
11177 if clear_stopped {
11178 if let Some(local) = lsp_store.as_local_mut() {
11179 for name in &stopped_names {
11180 local.stopped_language_servers.remove(name);
11181 }
11182 }
11183 }
11184 for buffer in buffers {
11185 lsp_store.register_buffer_with_language_servers(
11186 &buffer,
11187 only_restart_servers.clone(),
11188 true,
11189 cx,
11190 );
11191 }
11192 })
11193 })
11194 .detach();
11195 }
11196 }
11197
11198 pub fn stop_language_servers_for_buffers(
11199 &mut self,
11200 buffers: Vec<Entity<Buffer>>,
11201 also_stop_servers: HashSet<LanguageServerSelector>,
11202 cx: &mut Context<Self>,
11203 ) -> Task<Result<()>> {
11204 if let Some((client, project_id)) = self.upstream_client() {
11205 let request = client.request(proto::StopLanguageServers {
11206 project_id,
11207 buffer_ids: buffers
11208 .into_iter()
11209 .map(|b| b.read(cx).remote_id().to_proto())
11210 .collect(),
11211 also_servers: also_stop_servers
11212 .into_iter()
11213 .map(|selector| {
11214 let selector = match selector {
11215 LanguageServerSelector::Id(language_server_id) => {
11216 proto::language_server_selector::Selector::ServerId(
11217 language_server_id.to_proto(),
11218 )
11219 }
11220 LanguageServerSelector::Name(language_server_name) => {
11221 proto::language_server_selector::Selector::Name(
11222 language_server_name.to_string(),
11223 )
11224 }
11225 };
11226 proto::LanguageServerSelector {
11227 selector: Some(selector),
11228 }
11229 })
11230 .collect(),
11231 all: false,
11232 });
11233 cx.background_spawn(async move {
11234 let _ = request.await?;
11235 Ok(())
11236 })
11237 } else {
11238 let (stopped_names, task) =
11239 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11240 if let Some(local) = self.as_local_mut() {
11241 local.stopped_language_servers.extend(stopped_names);
11242 }
11243 cx.background_spawn(async move {
11244 task.await;
11245 Ok(())
11246 })
11247 }
11248 }
11249
11250 fn stop_local_language_servers_for_buffers(
11251 &mut self,
11252 buffers: &[Entity<Buffer>],
11253 also_stop_servers: HashSet<LanguageServerSelector>,
11254 cx: &mut Context<Self>,
11255 ) -> (HashSet<LanguageServerName>, Task<()>) {
11256 let Some(local) = self.as_local_mut() else {
11257 return (HashSet::default(), Task::ready(()));
11258 };
11259 let mut language_server_names_to_stop = BTreeSet::default();
11260 let mut language_servers_to_stop = also_stop_servers
11261 .into_iter()
11262 .flat_map(|selector| match selector {
11263 LanguageServerSelector::Id(id) => Some(id),
11264 LanguageServerSelector::Name(name) => {
11265 language_server_names_to_stop.insert(name);
11266 None
11267 }
11268 })
11269 .collect::<BTreeSet<_>>();
11270
11271 let mut covered_worktrees = HashSet::default();
11272 for buffer in buffers {
11273 buffer.update(cx, |buffer, cx| {
11274 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11275 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11276 && covered_worktrees.insert(worktree_id)
11277 {
11278 language_server_names_to_stop.retain(|name| {
11279 let old_ids_count = language_servers_to_stop.len();
11280 let all_language_servers_with_this_name = local
11281 .language_server_ids
11282 .iter()
11283 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11284 language_servers_to_stop.extend(all_language_servers_with_this_name);
11285 old_ids_count == language_servers_to_stop.len()
11286 });
11287 }
11288 });
11289 }
11290 for name in language_server_names_to_stop {
11291 language_servers_to_stop.extend(
11292 local
11293 .language_server_ids
11294 .iter()
11295 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11296 );
11297 }
11298
11299 let stopped_names: HashSet<LanguageServerName> = language_servers_to_stop
11300 .iter()
11301 .filter_map(|id| {
11302 local
11303 .language_server_ids
11304 .iter()
11305 .find(|(_, state)| state.id == *id)
11306 .map(|(seed, _)| seed.name.clone())
11307 })
11308 .collect();
11309
11310 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11311 let tasks = language_servers_to_stop
11312 .into_iter()
11313 .map(|server| self.stop_local_language_server(server, cx))
11314 .collect::<Vec<_>>();
11315
11316 (
11317 stopped_names,
11318 cx.background_spawn(futures::future::join_all(tasks).map(|_| ())),
11319 )
11320 }
11321
11322 #[cfg(any(test, feature = "test-support"))]
11323 pub fn update_diagnostics(
11324 &mut self,
11325 server_id: LanguageServerId,
11326 diagnostics: lsp::PublishDiagnosticsParams,
11327 result_id: Option<SharedString>,
11328 source_kind: DiagnosticSourceKind,
11329 disk_based_sources: &[String],
11330 cx: &mut Context<Self>,
11331 ) -> Result<()> {
11332 self.merge_lsp_diagnostics(
11333 source_kind,
11334 vec![DocumentDiagnosticsUpdate {
11335 diagnostics,
11336 result_id,
11337 server_id,
11338 disk_based_sources: Cow::Borrowed(disk_based_sources),
11339 registration_id: None,
11340 }],
11341 |_, _, _| false,
11342 cx,
11343 )
11344 }
11345
11346 pub fn merge_lsp_diagnostics(
11347 &mut self,
11348 source_kind: DiagnosticSourceKind,
11349 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11350 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11351 cx: &mut Context<Self>,
11352 ) -> Result<()> {
11353 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11354 let updates = lsp_diagnostics
11355 .into_iter()
11356 .filter_map(|update| {
11357 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11358 Some(DocumentDiagnosticsUpdate {
11359 diagnostics: self.lsp_to_document_diagnostics(
11360 abs_path,
11361 source_kind,
11362 update.server_id,
11363 update.diagnostics,
11364 &update.disk_based_sources,
11365 update.registration_id.clone(),
11366 ),
11367 result_id: update.result_id,
11368 server_id: update.server_id,
11369 disk_based_sources: update.disk_based_sources,
11370 registration_id: update.registration_id,
11371 })
11372 })
11373 .collect();
11374 self.merge_diagnostic_entries(updates, merge, cx)?;
11375 Ok(())
11376 }
11377
11378 fn lsp_to_document_diagnostics(
11379 &mut self,
11380 document_abs_path: PathBuf,
11381 source_kind: DiagnosticSourceKind,
11382 server_id: LanguageServerId,
11383 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11384 disk_based_sources: &[String],
11385 registration_id: Option<SharedString>,
11386 ) -> DocumentDiagnostics {
11387 let mut diagnostics = Vec::default();
11388 let mut primary_diagnostic_group_ids = HashMap::default();
11389 let mut sources_by_group_id = HashMap::default();
11390 let mut supporting_diagnostics = HashMap::default();
11391
11392 let adapter = self.language_server_adapter_for_id(server_id);
11393
11394 // Ensure that primary diagnostics are always the most severe
11395 lsp_diagnostics
11396 .diagnostics
11397 .sort_by_key(|item| item.severity);
11398
11399 for diagnostic in &lsp_diagnostics.diagnostics {
11400 let source = diagnostic.source.as_ref();
11401 let range = range_from_lsp(diagnostic.range);
11402 let is_supporting = diagnostic
11403 .related_information
11404 .as_ref()
11405 .is_some_and(|infos| {
11406 infos.iter().any(|info| {
11407 primary_diagnostic_group_ids.contains_key(&(
11408 source,
11409 diagnostic.code.clone(),
11410 range_from_lsp(info.location.range),
11411 ))
11412 })
11413 });
11414
11415 let is_unnecessary = diagnostic
11416 .tags
11417 .as_ref()
11418 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11419
11420 let underline = self
11421 .language_server_adapter_for_id(server_id)
11422 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11423
11424 if is_supporting {
11425 supporting_diagnostics.insert(
11426 (source, diagnostic.code.clone(), range),
11427 (diagnostic.severity, is_unnecessary),
11428 );
11429 } else {
11430 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11431 let is_disk_based =
11432 source.is_some_and(|source| disk_based_sources.contains(source));
11433
11434 sources_by_group_id.insert(group_id, source);
11435 primary_diagnostic_group_ids
11436 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11437
11438 diagnostics.push(DiagnosticEntry {
11439 range,
11440 diagnostic: Diagnostic {
11441 source: diagnostic.source.clone(),
11442 source_kind,
11443 code: diagnostic.code.clone(),
11444 code_description: diagnostic
11445 .code_description
11446 .as_ref()
11447 .and_then(|d| d.href.clone()),
11448 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11449 markdown: adapter.as_ref().and_then(|adapter| {
11450 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11451 }),
11452 message: diagnostic.message.trim().to_string(),
11453 group_id,
11454 is_primary: true,
11455 is_disk_based,
11456 is_unnecessary,
11457 underline,
11458 data: diagnostic.data.clone(),
11459 registration_id: registration_id.clone(),
11460 },
11461 });
11462 if let Some(infos) = &diagnostic.related_information {
11463 for info in infos {
11464 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11465 let range = range_from_lsp(info.location.range);
11466 diagnostics.push(DiagnosticEntry {
11467 range,
11468 diagnostic: Diagnostic {
11469 source: diagnostic.source.clone(),
11470 source_kind,
11471 code: diagnostic.code.clone(),
11472 code_description: diagnostic
11473 .code_description
11474 .as_ref()
11475 .and_then(|d| d.href.clone()),
11476 severity: DiagnosticSeverity::INFORMATION,
11477 markdown: adapter.as_ref().and_then(|adapter| {
11478 adapter.diagnostic_message_to_markdown(&info.message)
11479 }),
11480 message: info.message.trim().to_string(),
11481 group_id,
11482 is_primary: false,
11483 is_disk_based,
11484 is_unnecessary: false,
11485 underline,
11486 data: diagnostic.data.clone(),
11487 registration_id: registration_id.clone(),
11488 },
11489 });
11490 }
11491 }
11492 }
11493 }
11494 }
11495
11496 for entry in &mut diagnostics {
11497 let diagnostic = &mut entry.diagnostic;
11498 if !diagnostic.is_primary {
11499 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11500 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11501 source,
11502 diagnostic.code.clone(),
11503 entry.range.clone(),
11504 )) {
11505 if let Some(severity) = severity {
11506 diagnostic.severity = severity;
11507 }
11508 diagnostic.is_unnecessary = is_unnecessary;
11509 }
11510 }
11511 }
11512
11513 DocumentDiagnostics {
11514 diagnostics,
11515 document_abs_path,
11516 version: lsp_diagnostics.version,
11517 }
11518 }
11519
11520 fn insert_newly_running_language_server(
11521 &mut self,
11522 adapter: Arc<CachedLspAdapter>,
11523 language_server: Arc<LanguageServer>,
11524 server_id: LanguageServerId,
11525 key: LanguageServerSeed,
11526 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11527 cx: &mut Context<Self>,
11528 ) {
11529 let Some(local) = self.as_local_mut() else {
11530 return;
11531 };
11532 // If the language server for this key doesn't match the server id, don't store the
11533 // server. Which will cause it to be dropped, killing the process
11534 if local
11535 .language_server_ids
11536 .get(&key)
11537 .map(|state| state.id != server_id)
11538 .unwrap_or(false)
11539 {
11540 return;
11541 }
11542
11543 // Update language_servers collection with Running variant of LanguageServerState
11544 // indicating that the server is up and running and ready
11545 let workspace_folders = workspace_folders.lock().clone();
11546 language_server.set_workspace_folders(workspace_folders);
11547
11548 let workspace_diagnostics_refresh_tasks = language_server
11549 .capabilities()
11550 .diagnostic_provider
11551 .and_then(|provider| {
11552 local
11553 .language_server_dynamic_registrations
11554 .entry(server_id)
11555 .or_default()
11556 .diagnostics
11557 .entry(None)
11558 .or_insert(provider.clone());
11559 let workspace_refresher =
11560 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11561
11562 Some((None, workspace_refresher))
11563 })
11564 .into_iter()
11565 .collect();
11566 local.language_servers.insert(
11567 server_id,
11568 LanguageServerState::Running {
11569 workspace_diagnostics_refresh_tasks,
11570 adapter: adapter.clone(),
11571 server: language_server.clone(),
11572 simulate_disk_based_diagnostics_completion: None,
11573 },
11574 );
11575 local
11576 .languages
11577 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11578 if let Some(file_ops_caps) = language_server
11579 .capabilities()
11580 .workspace
11581 .as_ref()
11582 .and_then(|ws| ws.file_operations.as_ref())
11583 {
11584 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11585 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11586 if did_rename_caps.or(will_rename_caps).is_some() {
11587 let watcher = RenamePathsWatchedForServer::default()
11588 .with_did_rename_patterns(did_rename_caps)
11589 .with_will_rename_patterns(will_rename_caps);
11590 local
11591 .language_server_paths_watched_for_rename
11592 .insert(server_id, watcher);
11593 }
11594 }
11595
11596 self.language_server_statuses.insert(
11597 server_id,
11598 LanguageServerStatus {
11599 name: language_server.name(),
11600 server_version: language_server.version(),
11601 server_readable_version: language_server.readable_version(),
11602 pending_work: Default::default(),
11603 has_pending_diagnostic_updates: false,
11604 progress_tokens: Default::default(),
11605 worktree: Some(key.worktree_id),
11606 binary: Some(language_server.binary().clone()),
11607 configuration: Some(language_server.configuration().clone()),
11608 workspace_folders: language_server.workspace_folders(),
11609 process_id: language_server.process_id(),
11610 },
11611 );
11612
11613 cx.emit(LspStoreEvent::LanguageServerAdded(
11614 server_id,
11615 language_server.name(),
11616 Some(key.worktree_id),
11617 ));
11618
11619 let server_capabilities = language_server.capabilities();
11620 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11621 downstream_client
11622 .send(proto::StartLanguageServer {
11623 project_id: *project_id,
11624 server: Some(proto::LanguageServer {
11625 id: server_id.to_proto(),
11626 name: language_server.name().to_string(),
11627 worktree_id: Some(key.worktree_id.to_proto()),
11628 }),
11629 capabilities: serde_json::to_string(&server_capabilities)
11630 .expect("serializing server LSP capabilities"),
11631 })
11632 .log_err();
11633 }
11634 self.lsp_server_capabilities
11635 .insert(server_id, server_capabilities);
11636
11637 // Tell the language server about every open buffer in the worktree that matches the language.
11638 // Also check for buffers in worktrees that reused this server
11639 let mut worktrees_using_server = vec![key.worktree_id];
11640 if let Some(local) = self.as_local() {
11641 // Find all worktrees that have this server in their language server tree
11642 for (worktree_id, servers) in &local.lsp_tree.instances {
11643 if *worktree_id != key.worktree_id {
11644 for server_map in servers.roots.values() {
11645 if server_map
11646 .values()
11647 .any(|(node, _)| node.id() == Some(server_id))
11648 {
11649 worktrees_using_server.push(*worktree_id);
11650 }
11651 }
11652 }
11653 }
11654 }
11655
11656 let mut buffer_paths_registered = Vec::new();
11657 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11658 let mut lsp_adapters = HashMap::default();
11659 for buffer_handle in buffer_store.buffers() {
11660 let buffer = buffer_handle.read(cx);
11661 let file = match File::from_dyn(buffer.file()) {
11662 Some(file) => file,
11663 None => continue,
11664 };
11665 let language = match buffer.language() {
11666 Some(language) => language,
11667 None => continue,
11668 };
11669
11670 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11671 || !lsp_adapters
11672 .entry(language.name())
11673 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11674 .iter()
11675 .any(|a| a.name == key.name)
11676 {
11677 continue;
11678 }
11679 // didOpen
11680 let file = match file.as_local() {
11681 Some(file) => file,
11682 None => continue,
11683 };
11684
11685 let local = self.as_local_mut().unwrap();
11686
11687 let buffer_id = buffer.remote_id();
11688 if local.registered_buffers.contains_key(&buffer_id) {
11689 let abs_path = file.abs_path(cx);
11690 let uri = match lsp::Uri::from_file_path(&abs_path) {
11691 Ok(uri) => uri,
11692 Err(()) => {
11693 log::error!("failed to convert path to URI: {:?}", abs_path);
11694 continue;
11695 }
11696 };
11697
11698 let versions = local
11699 .buffer_snapshots
11700 .entry(buffer_id)
11701 .or_default()
11702 .entry(server_id)
11703 .and_modify(|_| {
11704 assert!(
11705 false,
11706 "There should not be an existing snapshot for a newly inserted buffer"
11707 )
11708 })
11709 .or_insert_with(|| {
11710 vec![LspBufferSnapshot {
11711 version: 0,
11712 snapshot: buffer.text_snapshot(),
11713 }]
11714 });
11715
11716 let snapshot = versions.last().unwrap();
11717 let version = snapshot.version;
11718 let initial_snapshot = &snapshot.snapshot;
11719 language_server.register_buffer(
11720 uri,
11721 adapter.language_id(&language.name()),
11722 version,
11723 initial_snapshot.text(),
11724 );
11725 buffer_paths_registered.push((buffer_id, abs_path));
11726 local
11727 .buffers_opened_in_servers
11728 .entry(buffer_id)
11729 .or_default()
11730 .insert(server_id);
11731 }
11732 buffer_handle.update(cx, |buffer, cx| {
11733 buffer.set_completion_triggers(
11734 server_id,
11735 language_server
11736 .capabilities()
11737 .completion_provider
11738 .as_ref()
11739 .and_then(|provider| {
11740 provider
11741 .trigger_characters
11742 .as_ref()
11743 .map(|characters| characters.iter().cloned().collect())
11744 })
11745 .unwrap_or_default(),
11746 cx,
11747 )
11748 });
11749 }
11750 });
11751
11752 for (buffer_id, abs_path) in buffer_paths_registered {
11753 cx.emit(LspStoreEvent::LanguageServerUpdate {
11754 language_server_id: server_id,
11755 name: Some(adapter.name()),
11756 message: proto::update_language_server::Variant::RegisteredForBuffer(
11757 proto::RegisteredForBuffer {
11758 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11759 buffer_id: buffer_id.to_proto(),
11760 },
11761 ),
11762 });
11763 }
11764
11765 cx.notify();
11766 }
11767
11768 pub fn language_servers_running_disk_based_diagnostics(
11769 &self,
11770 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11771 self.language_server_statuses
11772 .iter()
11773 .filter_map(|(id, status)| {
11774 if status.has_pending_diagnostic_updates {
11775 Some(*id)
11776 } else {
11777 None
11778 }
11779 })
11780 }
11781
11782 pub(crate) fn cancel_language_server_work_for_buffers(
11783 &mut self,
11784 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11785 cx: &mut Context<Self>,
11786 ) {
11787 if let Some((client, project_id)) = self.upstream_client() {
11788 let request = client.request(proto::CancelLanguageServerWork {
11789 project_id,
11790 work: Some(proto::cancel_language_server_work::Work::Buffers(
11791 proto::cancel_language_server_work::Buffers {
11792 buffer_ids: buffers
11793 .into_iter()
11794 .map(|b| b.read(cx).remote_id().to_proto())
11795 .collect(),
11796 },
11797 )),
11798 });
11799 cx.background_spawn(request).detach_and_log_err(cx);
11800 } else if let Some(local) = self.as_local() {
11801 let servers = buffers
11802 .into_iter()
11803 .flat_map(|buffer| {
11804 buffer.update(cx, |buffer, cx| {
11805 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11806 })
11807 })
11808 .collect::<HashSet<_>>();
11809 for server_id in servers {
11810 self.cancel_language_server_work(server_id, None, cx);
11811 }
11812 }
11813 }
11814
11815 pub(crate) fn cancel_language_server_work(
11816 &mut self,
11817 server_id: LanguageServerId,
11818 token_to_cancel: Option<ProgressToken>,
11819 cx: &mut Context<Self>,
11820 ) {
11821 if let Some(local) = self.as_local() {
11822 let status = self.language_server_statuses.get(&server_id);
11823 let server = local.language_servers.get(&server_id);
11824 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11825 {
11826 for (token, progress) in &status.pending_work {
11827 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11828 && token != token_to_cancel
11829 {
11830 continue;
11831 }
11832 if progress.is_cancellable {
11833 server
11834 .notify::<lsp::notification::WorkDoneProgressCancel>(
11835 WorkDoneProgressCancelParams {
11836 token: token.to_lsp(),
11837 },
11838 )
11839 .ok();
11840 }
11841 }
11842 }
11843 } else if let Some((client, project_id)) = self.upstream_client() {
11844 let request = client.request(proto::CancelLanguageServerWork {
11845 project_id,
11846 work: Some(
11847 proto::cancel_language_server_work::Work::LanguageServerWork(
11848 proto::cancel_language_server_work::LanguageServerWork {
11849 language_server_id: server_id.to_proto(),
11850 token: token_to_cancel.map(|token| token.to_proto()),
11851 },
11852 ),
11853 ),
11854 });
11855 cx.background_spawn(request).detach_and_log_err(cx);
11856 }
11857 }
11858
11859 fn register_supplementary_language_server(
11860 &mut self,
11861 id: LanguageServerId,
11862 name: LanguageServerName,
11863 server: Arc<LanguageServer>,
11864 cx: &mut Context<Self>,
11865 ) {
11866 if let Some(local) = self.as_local_mut() {
11867 local
11868 .supplementary_language_servers
11869 .insert(id, (name.clone(), server));
11870 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11871 }
11872 }
11873
11874 fn unregister_supplementary_language_server(
11875 &mut self,
11876 id: LanguageServerId,
11877 cx: &mut Context<Self>,
11878 ) {
11879 if let Some(local) = self.as_local_mut() {
11880 local.supplementary_language_servers.remove(&id);
11881 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11882 }
11883 }
11884
11885 pub(crate) fn supplementary_language_servers(
11886 &self,
11887 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11888 self.as_local().into_iter().flat_map(|local| {
11889 local
11890 .supplementary_language_servers
11891 .iter()
11892 .map(|(id, (name, _))| (*id, name.clone()))
11893 })
11894 }
11895
11896 pub fn language_server_adapter_for_id(
11897 &self,
11898 id: LanguageServerId,
11899 ) -> Option<Arc<CachedLspAdapter>> {
11900 self.as_local()
11901 .and_then(|local| local.language_servers.get(&id))
11902 .and_then(|language_server_state| match language_server_state {
11903 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11904 _ => None,
11905 })
11906 }
11907
11908 pub(super) fn update_local_worktree_language_servers(
11909 &mut self,
11910 worktree_handle: &Entity<Worktree>,
11911 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11912 cx: &mut Context<Self>,
11913 ) {
11914 if changes.is_empty() {
11915 return;
11916 }
11917
11918 let Some(local) = self.as_local() else { return };
11919
11920 local.prettier_store.update(cx, |prettier_store, cx| {
11921 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11922 });
11923
11924 let worktree_id = worktree_handle.read(cx).id();
11925 let mut language_server_ids = local
11926 .language_server_ids
11927 .iter()
11928 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11929 .collect::<Vec<_>>();
11930 language_server_ids.sort();
11931 language_server_ids.dedup();
11932
11933 // let abs_path = worktree_handle.read(cx).abs_path();
11934 for server_id in &language_server_ids {
11935 if let Some(LanguageServerState::Running { server, .. }) =
11936 local.language_servers.get(server_id)
11937 && let Some(watched_paths) = local
11938 .language_server_watched_paths
11939 .get(server_id)
11940 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11941 {
11942 let params = lsp::DidChangeWatchedFilesParams {
11943 changes: changes
11944 .iter()
11945 .filter_map(|(path, _, change)| {
11946 if !watched_paths.is_match(path.as_std_path()) {
11947 return None;
11948 }
11949 let typ = match change {
11950 PathChange::Loaded => return None,
11951 PathChange::Added => lsp::FileChangeType::CREATED,
11952 PathChange::Removed => lsp::FileChangeType::DELETED,
11953 PathChange::Updated => lsp::FileChangeType::CHANGED,
11954 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11955 };
11956 let uri = lsp::Uri::from_file_path(
11957 worktree_handle.read(cx).absolutize(&path),
11958 )
11959 .ok()?;
11960 Some(lsp::FileEvent { uri, typ })
11961 })
11962 .collect(),
11963 };
11964 if !params.changes.is_empty() {
11965 server
11966 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11967 .ok();
11968 }
11969 }
11970 }
11971 for (path, _, _) in changes {
11972 if let Some(file_name) = path.file_name()
11973 && local.watched_manifest_filenames.contains(file_name)
11974 {
11975 self.request_workspace_config_refresh();
11976 break;
11977 }
11978 }
11979 }
11980
11981 pub fn wait_for_remote_buffer(
11982 &mut self,
11983 id: BufferId,
11984 cx: &mut Context<Self>,
11985 ) -> Task<Result<Entity<Buffer>>> {
11986 self.buffer_store.update(cx, |buffer_store, cx| {
11987 buffer_store.wait_for_remote_buffer(id, cx)
11988 })
11989 }
11990
11991 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11992 let mut result = proto::Symbol {
11993 language_server_name: symbol.language_server_name.0.to_string(),
11994 source_worktree_id: symbol.source_worktree_id.to_proto(),
11995 language_server_id: symbol.source_language_server_id.to_proto(),
11996 name: symbol.name.clone(),
11997 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11998 start: Some(proto::PointUtf16 {
11999 row: symbol.range.start.0.row,
12000 column: symbol.range.start.0.column,
12001 }),
12002 end: Some(proto::PointUtf16 {
12003 row: symbol.range.end.0.row,
12004 column: symbol.range.end.0.column,
12005 }),
12006 worktree_id: Default::default(),
12007 path: Default::default(),
12008 signature: Default::default(),
12009 container_name: symbol.container_name.clone(),
12010 };
12011 match &symbol.path {
12012 SymbolLocation::InProject(path) => {
12013 result.worktree_id = path.worktree_id.to_proto();
12014 result.path = path.path.to_proto();
12015 }
12016 SymbolLocation::OutsideProject {
12017 abs_path,
12018 signature,
12019 } => {
12020 result.path = abs_path.to_string_lossy().into_owned();
12021 result.signature = signature.to_vec();
12022 }
12023 }
12024 result
12025 }
12026
12027 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
12028 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
12029 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
12030 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
12031
12032 let path = if serialized_symbol.signature.is_empty() {
12033 SymbolLocation::InProject(ProjectPath {
12034 worktree_id,
12035 path: RelPath::from_proto(&serialized_symbol.path)
12036 .context("invalid symbol path")?,
12037 })
12038 } else {
12039 SymbolLocation::OutsideProject {
12040 abs_path: Path::new(&serialized_symbol.path).into(),
12041 signature: serialized_symbol
12042 .signature
12043 .try_into()
12044 .map_err(|_| anyhow!("invalid signature"))?,
12045 }
12046 };
12047
12048 let start = serialized_symbol.start.context("invalid start")?;
12049 let end = serialized_symbol.end.context("invalid end")?;
12050 Ok(CoreSymbol {
12051 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
12052 source_worktree_id,
12053 source_language_server_id: LanguageServerId::from_proto(
12054 serialized_symbol.language_server_id,
12055 ),
12056 path,
12057 name: serialized_symbol.name,
12058 range: Unclipped(PointUtf16::new(start.row, start.column))
12059 ..Unclipped(PointUtf16::new(end.row, end.column)),
12060 kind,
12061 container_name: serialized_symbol.container_name,
12062 })
12063 }
12064
12065 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
12066 let mut serialized_completion = proto::Completion {
12067 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
12068 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
12069 new_text: completion.new_text.clone(),
12070 ..proto::Completion::default()
12071 };
12072 match &completion.source {
12073 CompletionSource::Lsp {
12074 insert_range,
12075 server_id,
12076 lsp_completion,
12077 lsp_defaults,
12078 resolved,
12079 } => {
12080 let (old_insert_start, old_insert_end) = insert_range
12081 .as_ref()
12082 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
12083 .unzip();
12084
12085 serialized_completion.old_insert_start = old_insert_start;
12086 serialized_completion.old_insert_end = old_insert_end;
12087 serialized_completion.source = proto::completion::Source::Lsp as i32;
12088 serialized_completion.server_id = server_id.0 as u64;
12089 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
12090 serialized_completion.lsp_defaults = lsp_defaults
12091 .as_deref()
12092 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
12093 serialized_completion.resolved = *resolved;
12094 }
12095 CompletionSource::BufferWord {
12096 word_range,
12097 resolved,
12098 } => {
12099 serialized_completion.source = proto::completion::Source::BufferWord as i32;
12100 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
12101 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
12102 serialized_completion.resolved = *resolved;
12103 }
12104 CompletionSource::Custom => {
12105 serialized_completion.source = proto::completion::Source::Custom as i32;
12106 serialized_completion.resolved = true;
12107 }
12108 CompletionSource::Dap { sort_text } => {
12109 serialized_completion.source = proto::completion::Source::Dap as i32;
12110 serialized_completion.sort_text = Some(sort_text.clone());
12111 }
12112 }
12113
12114 serialized_completion
12115 }
12116
12117 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
12118 let old_replace_start = completion
12119 .old_replace_start
12120 .and_then(deserialize_anchor)
12121 .context("invalid old start")?;
12122 let old_replace_end = completion
12123 .old_replace_end
12124 .and_then(deserialize_anchor)
12125 .context("invalid old end")?;
12126 let insert_range = {
12127 match completion.old_insert_start.zip(completion.old_insert_end) {
12128 Some((start, end)) => {
12129 let start = deserialize_anchor(start).context("invalid insert old start")?;
12130 let end = deserialize_anchor(end).context("invalid insert old end")?;
12131 Some(start..end)
12132 }
12133 None => None,
12134 }
12135 };
12136 Ok(CoreCompletion {
12137 replace_range: old_replace_start..old_replace_end,
12138 new_text: completion.new_text,
12139 source: match proto::completion::Source::from_i32(completion.source) {
12140 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
12141 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
12142 insert_range,
12143 server_id: LanguageServerId::from_proto(completion.server_id),
12144 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
12145 lsp_defaults: completion
12146 .lsp_defaults
12147 .as_deref()
12148 .map(serde_json::from_slice)
12149 .transpose()?,
12150 resolved: completion.resolved,
12151 },
12152 Some(proto::completion::Source::BufferWord) => {
12153 let word_range = completion
12154 .buffer_word_start
12155 .and_then(deserialize_anchor)
12156 .context("invalid buffer word start")?
12157 ..completion
12158 .buffer_word_end
12159 .and_then(deserialize_anchor)
12160 .context("invalid buffer word end")?;
12161 CompletionSource::BufferWord {
12162 word_range,
12163 resolved: completion.resolved,
12164 }
12165 }
12166 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
12167 sort_text: completion
12168 .sort_text
12169 .context("expected sort text to exist")?,
12170 },
12171 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
12172 },
12173 })
12174 }
12175
12176 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
12177 let (kind, lsp_action) = match &action.lsp_action {
12178 LspAction::Action(code_action) => (
12179 proto::code_action::Kind::Action as i32,
12180 serde_json::to_vec(code_action).unwrap(),
12181 ),
12182 LspAction::Command(command) => (
12183 proto::code_action::Kind::Command as i32,
12184 serde_json::to_vec(command).unwrap(),
12185 ),
12186 LspAction::CodeLens(code_lens) => (
12187 proto::code_action::Kind::CodeLens as i32,
12188 serde_json::to_vec(code_lens).unwrap(),
12189 ),
12190 };
12191
12192 proto::CodeAction {
12193 server_id: action.server_id.0 as u64,
12194 start: Some(serialize_anchor(&action.range.start)),
12195 end: Some(serialize_anchor(&action.range.end)),
12196 lsp_action,
12197 kind,
12198 resolved: action.resolved,
12199 }
12200 }
12201
12202 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
12203 let start = action
12204 .start
12205 .and_then(deserialize_anchor)
12206 .context("invalid start")?;
12207 let end = action
12208 .end
12209 .and_then(deserialize_anchor)
12210 .context("invalid end")?;
12211 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12212 Some(proto::code_action::Kind::Action) => {
12213 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12214 }
12215 Some(proto::code_action::Kind::Command) => {
12216 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12217 }
12218 Some(proto::code_action::Kind::CodeLens) => {
12219 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12220 }
12221 None => anyhow::bail!("Unknown action kind {}", action.kind),
12222 };
12223 Ok(CodeAction {
12224 server_id: LanguageServerId(action.server_id as usize),
12225 range: start..end,
12226 resolved: action.resolved,
12227 lsp_action,
12228 })
12229 }
12230
12231 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12232 match &formatting_result {
12233 Ok(_) => self.last_formatting_failure = None,
12234 Err(error) => {
12235 let error_string = format!("{error:#}");
12236 log::error!("Formatting failed: {error_string}");
12237 self.last_formatting_failure
12238 .replace(error_string.lines().join(" "));
12239 }
12240 }
12241 }
12242
12243 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12244 self.lsp_server_capabilities.remove(&for_server);
12245 self.semantic_token_config.remove_server_data(for_server);
12246 for lsp_data in self.lsp_data.values_mut() {
12247 lsp_data.remove_server_data(for_server);
12248 }
12249 if let Some(local) = self.as_local_mut() {
12250 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12251 local
12252 .workspace_pull_diagnostics_result_ids
12253 .remove(&for_server);
12254 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12255 buffer_servers.remove(&for_server);
12256 }
12257 }
12258 }
12259
12260 pub fn result_id_for_buffer_pull(
12261 &self,
12262 server_id: LanguageServerId,
12263 buffer_id: BufferId,
12264 registration_id: &Option<SharedString>,
12265 cx: &App,
12266 ) -> Option<SharedString> {
12267 let abs_path = self
12268 .buffer_store
12269 .read(cx)
12270 .get(buffer_id)
12271 .and_then(|b| File::from_dyn(b.read(cx).file()))
12272 .map(|f| f.abs_path(cx))?;
12273 self.as_local()?
12274 .buffer_pull_diagnostics_result_ids
12275 .get(&server_id)?
12276 .get(registration_id)?
12277 .get(&abs_path)?
12278 .clone()
12279 }
12280
12281 /// Gets all result_ids for a workspace diagnostics pull request.
12282 /// 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.
12283 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12284 pub fn result_ids_for_workspace_refresh(
12285 &self,
12286 server_id: LanguageServerId,
12287 registration_id: &Option<SharedString>,
12288 ) -> HashMap<PathBuf, SharedString> {
12289 let Some(local) = self.as_local() else {
12290 return HashMap::default();
12291 };
12292 local
12293 .workspace_pull_diagnostics_result_ids
12294 .get(&server_id)
12295 .into_iter()
12296 .filter_map(|diagnostics| diagnostics.get(registration_id))
12297 .flatten()
12298 .filter_map(|(abs_path, result_id)| {
12299 let result_id = local
12300 .buffer_pull_diagnostics_result_ids
12301 .get(&server_id)
12302 .and_then(|buffer_ids_result_ids| {
12303 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12304 })
12305 .cloned()
12306 .flatten()
12307 .or_else(|| result_id.clone())?;
12308 Some((abs_path.clone(), result_id))
12309 })
12310 .collect()
12311 }
12312
12313 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12314 if let Some(LanguageServerState::Running {
12315 workspace_diagnostics_refresh_tasks,
12316 ..
12317 }) = self
12318 .as_local_mut()
12319 .and_then(|local| local.language_servers.get_mut(&server_id))
12320 {
12321 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12322 diagnostics.refresh_tx.try_send(()).ok();
12323 }
12324 }
12325 }
12326
12327 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12328 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12329 /// which requires refreshing both workspace and document diagnostics.
12330 pub fn pull_document_diagnostics_for_server(
12331 &mut self,
12332 server_id: LanguageServerId,
12333 source_buffer_id: Option<BufferId>,
12334 cx: &mut Context<Self>,
12335 ) -> Shared<Task<()>> {
12336 let Some(local) = self.as_local_mut() else {
12337 return Task::ready(()).shared();
12338 };
12339 let mut buffers_to_refresh = HashSet::default();
12340 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12341 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12342 buffers_to_refresh.insert(*buffer_id);
12343 }
12344 }
12345
12346 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12347 }
12348
12349 pub fn pull_document_diagnostics_for_buffer_edit(
12350 &mut self,
12351 buffer_id: BufferId,
12352 cx: &mut Context<Self>,
12353 ) {
12354 let Some(local) = self.as_local_mut() else {
12355 return;
12356 };
12357 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12358 else {
12359 return;
12360 };
12361 for server_id in languages_servers {
12362 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12363 }
12364 }
12365
12366 fn apply_workspace_diagnostic_report(
12367 &mut self,
12368 server_id: LanguageServerId,
12369 report: lsp::WorkspaceDiagnosticReportResult,
12370 registration_id: Option<SharedString>,
12371 cx: &mut Context<Self>,
12372 ) {
12373 let mut workspace_diagnostics =
12374 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12375 report,
12376 server_id,
12377 registration_id,
12378 );
12379 workspace_diagnostics.retain(|d| match &d.diagnostics {
12380 LspPullDiagnostics::Response {
12381 server_id,
12382 registration_id,
12383 ..
12384 } => self.diagnostic_registration_exists(*server_id, registration_id),
12385 LspPullDiagnostics::Default => false,
12386 });
12387 let mut unchanged_buffers = HashMap::default();
12388 let workspace_diagnostics_updates = workspace_diagnostics
12389 .into_iter()
12390 .filter_map(
12391 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12392 LspPullDiagnostics::Response {
12393 server_id,
12394 uri,
12395 diagnostics,
12396 registration_id,
12397 } => Some((
12398 server_id,
12399 uri,
12400 diagnostics,
12401 workspace_diagnostics.version,
12402 registration_id,
12403 )),
12404 LspPullDiagnostics::Default => None,
12405 },
12406 )
12407 .fold(
12408 HashMap::default(),
12409 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12410 let (result_id, diagnostics) = match diagnostics {
12411 PulledDiagnostics::Unchanged { result_id } => {
12412 unchanged_buffers
12413 .entry(new_registration_id.clone())
12414 .or_insert_with(HashSet::default)
12415 .insert(uri.clone());
12416 (Some(result_id), Vec::new())
12417 }
12418 PulledDiagnostics::Changed {
12419 result_id,
12420 diagnostics,
12421 } => (result_id, diagnostics),
12422 };
12423 let disk_based_sources = Cow::Owned(
12424 self.language_server_adapter_for_id(server_id)
12425 .as_ref()
12426 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12427 .unwrap_or(&[])
12428 .to_vec(),
12429 );
12430
12431 let Some(abs_path) = uri.to_file_path().ok() else {
12432 return acc;
12433 };
12434 let Some((worktree, relative_path)) =
12435 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12436 else {
12437 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12438 return acc;
12439 };
12440 let worktree_id = worktree.read(cx).id();
12441 let project_path = ProjectPath {
12442 worktree_id,
12443 path: relative_path,
12444 };
12445 if let Some(local_lsp_store) = self.as_local_mut() {
12446 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12447 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12448 }
12449 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12450 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12451 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12452 acc.entry(server_id)
12453 .or_insert_with(HashMap::default)
12454 .entry(new_registration_id.clone())
12455 .or_insert_with(Vec::new)
12456 .push(DocumentDiagnosticsUpdate {
12457 server_id,
12458 diagnostics: lsp::PublishDiagnosticsParams {
12459 uri,
12460 diagnostics,
12461 version,
12462 },
12463 result_id: result_id.map(SharedString::new),
12464 disk_based_sources,
12465 registration_id: new_registration_id,
12466 });
12467 }
12468 acc
12469 },
12470 );
12471
12472 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12473 for (registration_id, diagnostic_updates) in diagnostic_updates {
12474 self.merge_lsp_diagnostics(
12475 DiagnosticSourceKind::Pulled,
12476 diagnostic_updates,
12477 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12478 DiagnosticSourceKind::Pulled => {
12479 old_diagnostic.registration_id != registration_id
12480 || unchanged_buffers
12481 .get(&old_diagnostic.registration_id)
12482 .is_some_and(|unchanged_buffers| {
12483 unchanged_buffers.contains(&document_uri)
12484 })
12485 }
12486 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12487 },
12488 cx,
12489 )
12490 .log_err();
12491 }
12492 }
12493 }
12494
12495 fn register_server_capabilities(
12496 &mut self,
12497 server_id: LanguageServerId,
12498 params: lsp::RegistrationParams,
12499 cx: &mut Context<Self>,
12500 ) -> anyhow::Result<()> {
12501 let server = self
12502 .language_server_for_id(server_id)
12503 .with_context(|| format!("no server {server_id} found"))?;
12504 for reg in params.registrations {
12505 match reg.method.as_str() {
12506 "workspace/didChangeWatchedFiles" => {
12507 if let Some(options) = reg.register_options {
12508 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12509 let caps = serde_json::from_value(options)?;
12510 local_lsp_store
12511 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12512 true
12513 } else {
12514 false
12515 };
12516 if notify {
12517 notify_server_capabilities_updated(&server, cx);
12518 }
12519 }
12520 }
12521 "workspace/didChangeConfiguration" => {
12522 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12523 }
12524 "workspace/didChangeWorkspaceFolders" => {
12525 // In this case register options is an empty object, we can ignore it
12526 let caps = lsp::WorkspaceFoldersServerCapabilities {
12527 supported: Some(true),
12528 change_notifications: Some(OneOf::Right(reg.id)),
12529 };
12530 server.update_capabilities(|capabilities| {
12531 capabilities
12532 .workspace
12533 .get_or_insert_default()
12534 .workspace_folders = Some(caps);
12535 });
12536 notify_server_capabilities_updated(&server, cx);
12537 }
12538 "workspace/symbol" => {
12539 let options = parse_register_capabilities(reg)?;
12540 server.update_capabilities(|capabilities| {
12541 capabilities.workspace_symbol_provider = Some(options);
12542 });
12543 notify_server_capabilities_updated(&server, cx);
12544 }
12545 "workspace/fileOperations" => {
12546 if let Some(options) = reg.register_options {
12547 let caps = serde_json::from_value(options)?;
12548 server.update_capabilities(|capabilities| {
12549 capabilities
12550 .workspace
12551 .get_or_insert_default()
12552 .file_operations = Some(caps);
12553 });
12554 notify_server_capabilities_updated(&server, cx);
12555 }
12556 }
12557 "workspace/executeCommand" => {
12558 if let Some(options) = reg.register_options {
12559 let options = serde_json::from_value(options)?;
12560 server.update_capabilities(|capabilities| {
12561 capabilities.execute_command_provider = Some(options);
12562 });
12563 notify_server_capabilities_updated(&server, cx);
12564 }
12565 }
12566 "textDocument/rangeFormatting" => {
12567 let options = parse_register_capabilities(reg)?;
12568 server.update_capabilities(|capabilities| {
12569 capabilities.document_range_formatting_provider = Some(options);
12570 });
12571 notify_server_capabilities_updated(&server, cx);
12572 }
12573 "textDocument/onTypeFormatting" => {
12574 if let Some(options) = reg
12575 .register_options
12576 .map(serde_json::from_value)
12577 .transpose()?
12578 {
12579 server.update_capabilities(|capabilities| {
12580 capabilities.document_on_type_formatting_provider = Some(options);
12581 });
12582 notify_server_capabilities_updated(&server, cx);
12583 }
12584 }
12585 "textDocument/formatting" => {
12586 let options = parse_register_capabilities(reg)?;
12587 server.update_capabilities(|capabilities| {
12588 capabilities.document_formatting_provider = Some(options);
12589 });
12590 notify_server_capabilities_updated(&server, cx);
12591 }
12592 "textDocument/rename" => {
12593 let options = parse_register_capabilities(reg)?;
12594 server.update_capabilities(|capabilities| {
12595 capabilities.rename_provider = Some(options);
12596 });
12597 notify_server_capabilities_updated(&server, cx);
12598 }
12599 "textDocument/inlayHint" => {
12600 let options = parse_register_capabilities(reg)?;
12601 server.update_capabilities(|capabilities| {
12602 capabilities.inlay_hint_provider = Some(options);
12603 });
12604 notify_server_capabilities_updated(&server, cx);
12605 }
12606 "textDocument/documentSymbol" => {
12607 let options = parse_register_capabilities(reg)?;
12608 server.update_capabilities(|capabilities| {
12609 capabilities.document_symbol_provider = Some(options);
12610 });
12611 notify_server_capabilities_updated(&server, cx);
12612 }
12613 "textDocument/codeAction" => {
12614 let options = parse_register_capabilities(reg)?;
12615 let provider = match options {
12616 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12617 OneOf::Right(caps) => caps,
12618 };
12619 server.update_capabilities(|capabilities| {
12620 capabilities.code_action_provider = Some(provider);
12621 });
12622 notify_server_capabilities_updated(&server, cx);
12623 }
12624 "textDocument/definition" => {
12625 let options = parse_register_capabilities(reg)?;
12626 server.update_capabilities(|capabilities| {
12627 capabilities.definition_provider = Some(options);
12628 });
12629 notify_server_capabilities_updated(&server, cx);
12630 }
12631 "textDocument/completion" => {
12632 if let Some(caps) = reg
12633 .register_options
12634 .map(serde_json::from_value::<CompletionOptions>)
12635 .transpose()?
12636 {
12637 server.update_capabilities(|capabilities| {
12638 capabilities.completion_provider = Some(caps.clone());
12639 });
12640
12641 if let Some(local) = self.as_local() {
12642 let mut buffers_with_language_server = Vec::new();
12643 for handle in self.buffer_store.read(cx).buffers() {
12644 let buffer_id = handle.read(cx).remote_id();
12645 if local
12646 .buffers_opened_in_servers
12647 .get(&buffer_id)
12648 .filter(|s| s.contains(&server_id))
12649 .is_some()
12650 {
12651 buffers_with_language_server.push(handle);
12652 }
12653 }
12654 let triggers = caps
12655 .trigger_characters
12656 .unwrap_or_default()
12657 .into_iter()
12658 .collect::<BTreeSet<_>>();
12659 for handle in buffers_with_language_server {
12660 let triggers = triggers.clone();
12661 let _ = handle.update(cx, move |buffer, cx| {
12662 buffer.set_completion_triggers(server_id, triggers, cx);
12663 });
12664 }
12665 }
12666 notify_server_capabilities_updated(&server, cx);
12667 }
12668 }
12669 "textDocument/hover" => {
12670 let options = parse_register_capabilities(reg)?;
12671 let provider = match options {
12672 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12673 OneOf::Right(caps) => caps,
12674 };
12675 server.update_capabilities(|capabilities| {
12676 capabilities.hover_provider = Some(provider);
12677 });
12678 notify_server_capabilities_updated(&server, cx);
12679 }
12680 "textDocument/signatureHelp" => {
12681 if let Some(caps) = reg
12682 .register_options
12683 .map(serde_json::from_value)
12684 .transpose()?
12685 {
12686 server.update_capabilities(|capabilities| {
12687 capabilities.signature_help_provider = Some(caps);
12688 });
12689 notify_server_capabilities_updated(&server, cx);
12690 }
12691 }
12692 "textDocument/didChange" => {
12693 if let Some(sync_kind) = reg
12694 .register_options
12695 .and_then(|opts| opts.get("syncKind").cloned())
12696 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12697 .transpose()?
12698 {
12699 server.update_capabilities(|capabilities| {
12700 let mut sync_options =
12701 Self::take_text_document_sync_options(capabilities);
12702 sync_options.change = Some(sync_kind);
12703 capabilities.text_document_sync =
12704 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12705 });
12706 notify_server_capabilities_updated(&server, cx);
12707 }
12708 }
12709 "textDocument/didSave" => {
12710 if let Some(include_text) = reg
12711 .register_options
12712 .map(|opts| {
12713 let transpose = opts
12714 .get("includeText")
12715 .cloned()
12716 .map(serde_json::from_value::<Option<bool>>)
12717 .transpose();
12718 match transpose {
12719 Ok(value) => Ok(value.flatten()),
12720 Err(e) => Err(e),
12721 }
12722 })
12723 .transpose()?
12724 {
12725 server.update_capabilities(|capabilities| {
12726 let mut sync_options =
12727 Self::take_text_document_sync_options(capabilities);
12728 sync_options.save =
12729 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12730 include_text,
12731 }));
12732 capabilities.text_document_sync =
12733 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12734 });
12735 notify_server_capabilities_updated(&server, cx);
12736 }
12737 }
12738 "textDocument/codeLens" => {
12739 if let Some(caps) = reg
12740 .register_options
12741 .map(serde_json::from_value)
12742 .transpose()?
12743 {
12744 server.update_capabilities(|capabilities| {
12745 capabilities.code_lens_provider = Some(caps);
12746 });
12747 notify_server_capabilities_updated(&server, cx);
12748 }
12749 }
12750 "textDocument/diagnostic" => {
12751 if let Some(caps) = reg
12752 .register_options
12753 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12754 .transpose()?
12755 {
12756 let local = self
12757 .as_local_mut()
12758 .context("Expected LSP Store to be local")?;
12759 let state = local
12760 .language_servers
12761 .get_mut(&server_id)
12762 .context("Could not obtain Language Servers state")?;
12763 local
12764 .language_server_dynamic_registrations
12765 .entry(server_id)
12766 .or_default()
12767 .diagnostics
12768 .insert(Some(reg.id.clone()), caps.clone());
12769
12770 let supports_workspace_diagnostics =
12771 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12772 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12773 diagnostic_options.workspace_diagnostics
12774 }
12775 DiagnosticServerCapabilities::RegistrationOptions(
12776 diagnostic_registration_options,
12777 ) => {
12778 diagnostic_registration_options
12779 .diagnostic_options
12780 .workspace_diagnostics
12781 }
12782 };
12783
12784 if supports_workspace_diagnostics(&caps) {
12785 if let LanguageServerState::Running {
12786 workspace_diagnostics_refresh_tasks,
12787 ..
12788 } = state
12789 && let Some(task) = lsp_workspace_diagnostics_refresh(
12790 Some(reg.id.clone()),
12791 caps.clone(),
12792 server.clone(),
12793 cx,
12794 )
12795 {
12796 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12797 }
12798 }
12799
12800 server.update_capabilities(|capabilities| {
12801 capabilities.diagnostic_provider = Some(caps);
12802 });
12803
12804 notify_server_capabilities_updated(&server, cx);
12805
12806 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12807 }
12808 }
12809 "textDocument/documentColor" => {
12810 let options = parse_register_capabilities(reg)?;
12811 let provider = match options {
12812 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12813 OneOf::Right(caps) => caps,
12814 };
12815 server.update_capabilities(|capabilities| {
12816 capabilities.color_provider = Some(provider);
12817 });
12818 notify_server_capabilities_updated(&server, cx);
12819 }
12820 "textDocument/foldingRange" => {
12821 let options = parse_register_capabilities(reg)?;
12822 let provider = match options {
12823 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12824 OneOf::Right(caps) => caps,
12825 };
12826 server.update_capabilities(|capabilities| {
12827 capabilities.folding_range_provider = Some(provider);
12828 });
12829 notify_server_capabilities_updated(&server, cx);
12830 }
12831 _ => log::warn!("unhandled capability registration: {reg:?}"),
12832 }
12833 }
12834
12835 Ok(())
12836 }
12837
12838 fn unregister_server_capabilities(
12839 &mut self,
12840 server_id: LanguageServerId,
12841 params: lsp::UnregistrationParams,
12842 cx: &mut Context<Self>,
12843 ) -> anyhow::Result<()> {
12844 let server = self
12845 .language_server_for_id(server_id)
12846 .with_context(|| format!("no server {server_id} found"))?;
12847 for unreg in params.unregisterations.iter() {
12848 match unreg.method.as_str() {
12849 "workspace/didChangeWatchedFiles" => {
12850 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12851 local_lsp_store
12852 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12853 true
12854 } else {
12855 false
12856 };
12857 if notify {
12858 notify_server_capabilities_updated(&server, cx);
12859 }
12860 }
12861 "workspace/didChangeConfiguration" => {
12862 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12863 }
12864 "workspace/didChangeWorkspaceFolders" => {
12865 server.update_capabilities(|capabilities| {
12866 capabilities
12867 .workspace
12868 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12869 workspace_folders: None,
12870 file_operations: None,
12871 })
12872 .workspace_folders = None;
12873 });
12874 notify_server_capabilities_updated(&server, cx);
12875 }
12876 "workspace/symbol" => {
12877 server.update_capabilities(|capabilities| {
12878 capabilities.workspace_symbol_provider = None
12879 });
12880 notify_server_capabilities_updated(&server, cx);
12881 }
12882 "workspace/fileOperations" => {
12883 server.update_capabilities(|capabilities| {
12884 capabilities
12885 .workspace
12886 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12887 workspace_folders: None,
12888 file_operations: None,
12889 })
12890 .file_operations = None;
12891 });
12892 notify_server_capabilities_updated(&server, cx);
12893 }
12894 "workspace/executeCommand" => {
12895 server.update_capabilities(|capabilities| {
12896 capabilities.execute_command_provider = None;
12897 });
12898 notify_server_capabilities_updated(&server, cx);
12899 }
12900 "textDocument/rangeFormatting" => {
12901 server.update_capabilities(|capabilities| {
12902 capabilities.document_range_formatting_provider = None
12903 });
12904 notify_server_capabilities_updated(&server, cx);
12905 }
12906 "textDocument/onTypeFormatting" => {
12907 server.update_capabilities(|capabilities| {
12908 capabilities.document_on_type_formatting_provider = None;
12909 });
12910 notify_server_capabilities_updated(&server, cx);
12911 }
12912 "textDocument/formatting" => {
12913 server.update_capabilities(|capabilities| {
12914 capabilities.document_formatting_provider = None;
12915 });
12916 notify_server_capabilities_updated(&server, cx);
12917 }
12918 "textDocument/rename" => {
12919 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12920 notify_server_capabilities_updated(&server, cx);
12921 }
12922 "textDocument/codeAction" => {
12923 server.update_capabilities(|capabilities| {
12924 capabilities.code_action_provider = None;
12925 });
12926 notify_server_capabilities_updated(&server, cx);
12927 }
12928 "textDocument/definition" => {
12929 server.update_capabilities(|capabilities| {
12930 capabilities.definition_provider = None;
12931 });
12932 notify_server_capabilities_updated(&server, cx);
12933 }
12934 "textDocument/completion" => {
12935 server.update_capabilities(|capabilities| {
12936 capabilities.completion_provider = None;
12937 });
12938 notify_server_capabilities_updated(&server, cx);
12939 }
12940 "textDocument/hover" => {
12941 server.update_capabilities(|capabilities| {
12942 capabilities.hover_provider = None;
12943 });
12944 notify_server_capabilities_updated(&server, cx);
12945 }
12946 "textDocument/signatureHelp" => {
12947 server.update_capabilities(|capabilities| {
12948 capabilities.signature_help_provider = None;
12949 });
12950 notify_server_capabilities_updated(&server, cx);
12951 }
12952 "textDocument/didChange" => {
12953 server.update_capabilities(|capabilities| {
12954 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12955 sync_options.change = None;
12956 capabilities.text_document_sync =
12957 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12958 });
12959 notify_server_capabilities_updated(&server, cx);
12960 }
12961 "textDocument/didSave" => {
12962 server.update_capabilities(|capabilities| {
12963 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12964 sync_options.save = None;
12965 capabilities.text_document_sync =
12966 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12967 });
12968 notify_server_capabilities_updated(&server, cx);
12969 }
12970 "textDocument/codeLens" => {
12971 server.update_capabilities(|capabilities| {
12972 capabilities.code_lens_provider = None;
12973 });
12974 notify_server_capabilities_updated(&server, cx);
12975 }
12976 "textDocument/diagnostic" => {
12977 let local = self
12978 .as_local_mut()
12979 .context("Expected LSP Store to be local")?;
12980
12981 let state = local
12982 .language_servers
12983 .get_mut(&server_id)
12984 .context("Could not obtain Language Servers state")?;
12985 let registrations = local
12986 .language_server_dynamic_registrations
12987 .get_mut(&server_id)
12988 .with_context(|| {
12989 format!("Expected dynamic registration to exist for server {server_id}")
12990 })?;
12991 registrations.diagnostics
12992 .remove(&Some(unreg.id.clone()))
12993 .with_context(|| format!(
12994 "Attempted to unregister non-existent diagnostic registration with ID {}",
12995 unreg.id)
12996 )?;
12997 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12998
12999 if let LanguageServerState::Running {
13000 workspace_diagnostics_refresh_tasks,
13001 ..
13002 } = state
13003 {
13004 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
13005 }
13006
13007 self.clear_unregistered_diagnostics(
13008 server_id,
13009 SharedString::from(unreg.id.clone()),
13010 cx,
13011 )?;
13012
13013 if removed_last_diagnostic_provider {
13014 server.update_capabilities(|capabilities| {
13015 debug_assert!(capabilities.diagnostic_provider.is_some());
13016 capabilities.diagnostic_provider = None;
13017 });
13018 }
13019
13020 notify_server_capabilities_updated(&server, cx);
13021 }
13022 "textDocument/documentColor" => {
13023 server.update_capabilities(|capabilities| {
13024 capabilities.color_provider = None;
13025 });
13026 notify_server_capabilities_updated(&server, cx);
13027 }
13028 "textDocument/foldingRange" => {
13029 server.update_capabilities(|capabilities| {
13030 capabilities.folding_range_provider = None;
13031 });
13032 notify_server_capabilities_updated(&server, cx);
13033 }
13034 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
13035 }
13036 }
13037
13038 Ok(())
13039 }
13040
13041 fn clear_unregistered_diagnostics(
13042 &mut self,
13043 server_id: LanguageServerId,
13044 cleared_registration_id: SharedString,
13045 cx: &mut Context<Self>,
13046 ) -> anyhow::Result<()> {
13047 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
13048
13049 self.buffer_store.update(cx, |buffer_store, cx| {
13050 for buffer_handle in buffer_store.buffers() {
13051 let buffer = buffer_handle.read(cx);
13052 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
13053 let Some(abs_path) = abs_path else {
13054 continue;
13055 };
13056 affected_abs_paths.insert(abs_path);
13057 }
13058 });
13059
13060 let local = self.as_local().context("Expected LSP Store to be local")?;
13061 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
13062 let Some(worktree) = self
13063 .worktree_store
13064 .read(cx)
13065 .worktree_for_id(*worktree_id, cx)
13066 else {
13067 continue;
13068 };
13069
13070 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
13071 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
13072 let has_matching_registration =
13073 diagnostics_by_server_id[ix].1.iter().any(|entry| {
13074 entry.diagnostic.registration_id.as_ref()
13075 == Some(&cleared_registration_id)
13076 });
13077 if has_matching_registration {
13078 let abs_path = worktree.read(cx).absolutize(rel_path);
13079 affected_abs_paths.insert(abs_path);
13080 }
13081 }
13082 }
13083 }
13084
13085 if affected_abs_paths.is_empty() {
13086 return Ok(());
13087 }
13088
13089 // Send a fake diagnostic update which clears the state for the registration ID
13090 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
13091 affected_abs_paths
13092 .into_iter()
13093 .map(|abs_path| DocumentDiagnosticsUpdate {
13094 diagnostics: DocumentDiagnostics {
13095 diagnostics: Vec::new(),
13096 document_abs_path: abs_path,
13097 version: None,
13098 },
13099 result_id: None,
13100 registration_id: Some(cleared_registration_id.clone()),
13101 server_id,
13102 disk_based_sources: Cow::Borrowed(&[]),
13103 })
13104 .collect();
13105
13106 let merge_registration_id = cleared_registration_id.clone();
13107 self.merge_diagnostic_entries(
13108 clears,
13109 move |_, diagnostic, _| {
13110 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
13111 diagnostic.registration_id != Some(merge_registration_id.clone())
13112 } else {
13113 true
13114 }
13115 },
13116 cx,
13117 )?;
13118
13119 Ok(())
13120 }
13121
13122 async fn deduplicate_range_based_lsp_requests<T>(
13123 lsp_store: &Entity<Self>,
13124 server_id: Option<LanguageServerId>,
13125 lsp_request_id: LspRequestId,
13126 proto_request: &T::ProtoRequest,
13127 range: Range<Anchor>,
13128 cx: &mut AsyncApp,
13129 ) -> Result<()>
13130 where
13131 T: LspCommand,
13132 T::ProtoRequest: proto::LspRequestMessage,
13133 {
13134 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13135 let version = deserialize_version(proto_request.buffer_version());
13136 let buffer = lsp_store.update(cx, |this, cx| {
13137 this.buffer_store.read(cx).get_existing(buffer_id)
13138 })?;
13139 buffer
13140 .update(cx, |buffer, _| buffer.wait_for_version(version))
13141 .await?;
13142 lsp_store.update(cx, |lsp_store, cx| {
13143 let buffer_snapshot = buffer.read(cx).snapshot();
13144 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13145 let chunks_queried_for = lsp_data
13146 .inlay_hints
13147 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
13148 .collect::<Vec<_>>();
13149 match chunks_queried_for.as_slice() {
13150 &[chunk] => {
13151 let key = LspKey {
13152 request_type: TypeId::of::<T>(),
13153 server_queried: server_id,
13154 };
13155 let previous_request = lsp_data
13156 .chunk_lsp_requests
13157 .entry(key)
13158 .or_default()
13159 .insert(chunk, lsp_request_id);
13160 if let Some((previous_request, running_requests)) =
13161 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
13162 {
13163 running_requests.remove(&previous_request);
13164 }
13165 }
13166 _ambiguous_chunks => {
13167 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
13168 // there, a buffer version-based check will be performed and outdated requests discarded.
13169 }
13170 }
13171 anyhow::Ok(())
13172 })?;
13173
13174 Ok(())
13175 }
13176
13177 async fn query_lsp_locally<T>(
13178 lsp_store: Entity<Self>,
13179 for_server_id: Option<LanguageServerId>,
13180 sender_id: proto::PeerId,
13181 lsp_request_id: LspRequestId,
13182 proto_request: T::ProtoRequest,
13183 position: Option<Anchor>,
13184 cx: &mut AsyncApp,
13185 ) -> Result<()>
13186 where
13187 T: LspCommand + Clone,
13188 T::ProtoRequest: proto::LspRequestMessage,
13189 <T::ProtoRequest as proto::RequestMessage>::Response:
13190 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
13191 {
13192 let (buffer_version, buffer) =
13193 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
13194 let request =
13195 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
13196 let key = LspKey {
13197 request_type: TypeId::of::<T>(),
13198 server_queried: for_server_id,
13199 };
13200 lsp_store.update(cx, |lsp_store, cx| {
13201 let request_task = match for_server_id {
13202 Some(server_id) => {
13203 let server_task = lsp_store.request_lsp(
13204 buffer.clone(),
13205 LanguageServerToQuery::Other(server_id),
13206 request.clone(),
13207 cx,
13208 );
13209 cx.background_spawn(async move {
13210 let mut responses = Vec::new();
13211 match server_task.await {
13212 Ok(response) => responses.push((server_id, response)),
13213 // rust-analyzer likes to error with this when its still loading up
13214 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13215 Err(e) => log::error!(
13216 "Error handling response for request {request:?}: {e:#}"
13217 ),
13218 }
13219 responses
13220 })
13221 }
13222 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13223 };
13224 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13225 if T::ProtoRequest::stop_previous_requests() {
13226 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13227 lsp_requests.clear();
13228 }
13229 }
13230 lsp_data.lsp_requests.entry(key).or_default().insert(
13231 lsp_request_id,
13232 cx.spawn(async move |lsp_store, cx| {
13233 let response = request_task.await;
13234 lsp_store
13235 .update(cx, |lsp_store, cx| {
13236 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13237 {
13238 let response = response
13239 .into_iter()
13240 .map(|(server_id, response)| {
13241 (
13242 server_id.to_proto(),
13243 T::response_to_proto(
13244 response,
13245 lsp_store,
13246 sender_id,
13247 &buffer_version,
13248 cx,
13249 )
13250 .into(),
13251 )
13252 })
13253 .collect::<HashMap<_, _>>();
13254 match client.send_lsp_response::<T::ProtoRequest>(
13255 project_id,
13256 lsp_request_id,
13257 response,
13258 ) {
13259 Ok(()) => {}
13260 Err(e) => {
13261 log::error!("Failed to send LSP response: {e:#}",)
13262 }
13263 }
13264 }
13265 })
13266 .ok();
13267 }),
13268 );
13269 });
13270 Ok(())
13271 }
13272
13273 async fn wait_for_buffer_version<T>(
13274 lsp_store: &Entity<Self>,
13275 proto_request: &T::ProtoRequest,
13276 cx: &mut AsyncApp,
13277 ) -> Result<(Global, Entity<Buffer>)>
13278 where
13279 T: LspCommand,
13280 T::ProtoRequest: proto::LspRequestMessage,
13281 {
13282 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13283 let version = deserialize_version(proto_request.buffer_version());
13284 let buffer = lsp_store.update(cx, |this, cx| {
13285 this.buffer_store.read(cx).get_existing(buffer_id)
13286 })?;
13287 buffer
13288 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13289 .await?;
13290 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13291 Ok((buffer_version, buffer))
13292 }
13293
13294 fn take_text_document_sync_options(
13295 capabilities: &mut lsp::ServerCapabilities,
13296 ) -> lsp::TextDocumentSyncOptions {
13297 match capabilities.text_document_sync.take() {
13298 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13299 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13300 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13301 sync_options.change = Some(sync_kind);
13302 sync_options
13303 }
13304 None => lsp::TextDocumentSyncOptions::default(),
13305 }
13306 }
13307
13308 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13309 self.downstream_client.clone()
13310 }
13311
13312 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13313 self.worktree_store.clone()
13314 }
13315
13316 /// Gets what's stored in the LSP data for the given buffer.
13317 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13318 self.lsp_data.get_mut(&buffer_id)
13319 }
13320
13321 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13322 /// new [`BufferLspData`] will be created to replace the previous state.
13323 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13324 let (buffer_id, buffer_version) =
13325 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13326 let lsp_data = self
13327 .lsp_data
13328 .entry(buffer_id)
13329 .or_insert_with(|| BufferLspData::new(buffer, cx));
13330 if buffer_version.changed_since(&lsp_data.buffer_version) {
13331 // To send delta requests for semantic tokens, the previous tokens
13332 // need to be kept between buffer changes.
13333 let semantic_tokens = lsp_data.semantic_tokens.take();
13334 *lsp_data = BufferLspData::new(buffer, cx);
13335 lsp_data.semantic_tokens = semantic_tokens;
13336 }
13337 lsp_data
13338 }
13339}
13340
13341// Registration with registerOptions as null, should fallback to true.
13342// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13343fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13344 reg: lsp::Registration,
13345) -> Result<OneOf<bool, T>> {
13346 Ok(match reg.register_options {
13347 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13348 None => OneOf::Left(true),
13349 })
13350}
13351
13352fn subscribe_to_binary_statuses(
13353 languages: &Arc<LanguageRegistry>,
13354 cx: &mut Context<'_, LspStore>,
13355) -> Task<()> {
13356 let mut server_statuses = languages.language_server_binary_statuses();
13357 cx.spawn(async move |lsp_store, cx| {
13358 while let Some((server_name, binary_status)) = server_statuses.next().await {
13359 if lsp_store
13360 .update(cx, |_, cx| {
13361 let mut message = None;
13362 let binary_status = match binary_status {
13363 BinaryStatus::None => proto::ServerBinaryStatus::None,
13364 BinaryStatus::CheckingForUpdate => {
13365 proto::ServerBinaryStatus::CheckingForUpdate
13366 }
13367 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13368 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13369 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13370 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13371 BinaryStatus::Failed { error } => {
13372 message = Some(error);
13373 proto::ServerBinaryStatus::Failed
13374 }
13375 };
13376 cx.emit(LspStoreEvent::LanguageServerUpdate {
13377 // Binary updates are about the binary that might not have any language server id at that point.
13378 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13379 language_server_id: LanguageServerId(0),
13380 name: Some(server_name),
13381 message: proto::update_language_server::Variant::StatusUpdate(
13382 proto::StatusUpdate {
13383 message,
13384 status: Some(proto::status_update::Status::Binary(
13385 binary_status as i32,
13386 )),
13387 },
13388 ),
13389 });
13390 })
13391 .is_err()
13392 {
13393 break;
13394 }
13395 }
13396 })
13397}
13398
13399fn lsp_workspace_diagnostics_refresh(
13400 registration_id: Option<String>,
13401 options: DiagnosticServerCapabilities,
13402 server: Arc<LanguageServer>,
13403 cx: &mut Context<'_, LspStore>,
13404) -> Option<WorkspaceRefreshTask> {
13405 let identifier = workspace_diagnostic_identifier(&options)?;
13406 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13407
13408 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13409 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13410 refresh_tx.try_send(()).ok();
13411
13412 let request_timeout = ProjectSettings::get_global(cx)
13413 .global_lsp_settings
13414 .get_request_timeout();
13415
13416 // 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.
13417 // This allows users to increase the duration if need be
13418 let timeout = if request_timeout != Duration::ZERO {
13419 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13420 } else {
13421 request_timeout
13422 };
13423
13424 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13425 let mut attempts = 0;
13426 let max_attempts = 50;
13427 let mut requests = 0;
13428
13429 loop {
13430 let Some(()) = refresh_rx.recv().await else {
13431 return;
13432 };
13433
13434 'request: loop {
13435 requests += 1;
13436 if attempts > max_attempts {
13437 log::error!(
13438 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13439 );
13440 return;
13441 }
13442 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13443 cx.background_executor()
13444 .timer(Duration::from_millis(backoff_millis))
13445 .await;
13446 attempts += 1;
13447
13448 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13449 lsp_store
13450 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13451 .into_iter()
13452 .filter_map(|(abs_path, result_id)| {
13453 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13454 Some(lsp::PreviousResultId {
13455 uri,
13456 value: result_id.to_string(),
13457 })
13458 })
13459 .collect()
13460 }) else {
13461 return;
13462 };
13463
13464 let token = if let Some(registration_id) = ®istration_id {
13465 format!(
13466 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13467 server.server_id(),
13468 )
13469 } else {
13470 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13471 };
13472
13473 progress_rx.try_recv().ok();
13474 let timer = server.request_timer(timeout).fuse();
13475 let progress = pin!(progress_rx.recv().fuse());
13476 let response_result = server
13477 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13478 lsp::WorkspaceDiagnosticParams {
13479 previous_result_ids,
13480 identifier: identifier.clone(),
13481 work_done_progress_params: Default::default(),
13482 partial_result_params: lsp::PartialResultParams {
13483 partial_result_token: Some(lsp::ProgressToken::String(token)),
13484 },
13485 },
13486 select(timer, progress).then(|either| match either {
13487 Either::Left((message, ..)) => ready(message).left_future(),
13488 Either::Right(..) => pending::<String>().right_future(),
13489 }),
13490 )
13491 .await;
13492
13493 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13494 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13495 match response_result {
13496 ConnectionResult::Timeout => {
13497 log::error!("Timeout during workspace diagnostics pull");
13498 continue 'request;
13499 }
13500 ConnectionResult::ConnectionReset => {
13501 log::error!("Server closed a workspace diagnostics pull request");
13502 continue 'request;
13503 }
13504 ConnectionResult::Result(Err(e)) => {
13505 log::error!("Error during workspace diagnostics pull: {e:#}");
13506 break 'request;
13507 }
13508 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13509 attempts = 0;
13510 if lsp_store
13511 .update(cx, |lsp_store, cx| {
13512 lsp_store.apply_workspace_diagnostic_report(
13513 server.server_id(),
13514 pulled_diagnostics,
13515 registration_id_shared.clone(),
13516 cx,
13517 )
13518 })
13519 .is_err()
13520 {
13521 return;
13522 }
13523 break 'request;
13524 }
13525 }
13526 }
13527 }
13528 });
13529
13530 Some(WorkspaceRefreshTask {
13531 refresh_tx,
13532 progress_tx,
13533 task: workspace_query_language_server,
13534 })
13535}
13536
13537fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13538 match &options {
13539 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13540 .identifier
13541 .as_deref()
13542 .map(SharedString::new),
13543 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13544 let diagnostic_options = ®istration_options.diagnostic_options;
13545 diagnostic_options
13546 .identifier
13547 .as_deref()
13548 .map(SharedString::new)
13549 }
13550 }
13551}
13552
13553fn workspace_diagnostic_identifier(
13554 options: &DiagnosticServerCapabilities,
13555) -> Option<Option<String>> {
13556 match &options {
13557 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13558 if !diagnostic_options.workspace_diagnostics {
13559 return None;
13560 }
13561 Some(diagnostic_options.identifier.clone())
13562 }
13563 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13564 let diagnostic_options = ®istration_options.diagnostic_options;
13565 if !diagnostic_options.workspace_diagnostics {
13566 return None;
13567 }
13568 Some(diagnostic_options.identifier.clone())
13569 }
13570 }
13571}
13572
13573fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13574 let CompletionSource::BufferWord {
13575 word_range,
13576 resolved,
13577 } = &mut completion.source
13578 else {
13579 return;
13580 };
13581 if *resolved {
13582 return;
13583 }
13584
13585 if completion.new_text
13586 != snapshot
13587 .text_for_range(word_range.clone())
13588 .collect::<String>()
13589 {
13590 return;
13591 }
13592
13593 let mut offset = 0;
13594 for chunk in snapshot.chunks(
13595 word_range.clone(),
13596 LanguageAwareStyling {
13597 tree_sitter: true,
13598 diagnostics: true,
13599 },
13600 ) {
13601 let end_offset = offset + chunk.text.len();
13602 if let Some(highlight_id) = chunk.syntax_highlight_id {
13603 completion
13604 .label
13605 .runs
13606 .push((offset..end_offset, highlight_id));
13607 }
13608 offset = end_offset;
13609 }
13610 *resolved = true;
13611}
13612
13613impl EventEmitter<LspStoreEvent> for LspStore {}
13614
13615fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13616 hover
13617 .contents
13618 .retain(|hover_block| !hover_block.text.trim().is_empty());
13619 if hover.contents.is_empty() {
13620 None
13621 } else {
13622 Some(hover)
13623 }
13624}
13625
13626async fn populate_labels_for_completions(
13627 new_completions: Vec<CoreCompletion>,
13628 language: Option<Arc<Language>>,
13629 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13630) -> Vec<Completion> {
13631 let lsp_completions = new_completions
13632 .iter()
13633 .filter_map(|new_completion| {
13634 new_completion
13635 .source
13636 .lsp_completion(true)
13637 .map(|lsp_completion| lsp_completion.into_owned())
13638 })
13639 .collect::<Vec<_>>();
13640
13641 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13642 lsp_adapter
13643 .labels_for_completions(&lsp_completions, language)
13644 .await
13645 .log_err()
13646 .unwrap_or_default()
13647 } else {
13648 Vec::new()
13649 }
13650 .into_iter()
13651 .fuse();
13652
13653 let mut completions = Vec::new();
13654 for completion in new_completions {
13655 match completion.source.lsp_completion(true) {
13656 Some(lsp_completion) => {
13657 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13658
13659 let mut label = labels.next().flatten().unwrap_or_else(|| {
13660 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13661 });
13662 ensure_uniform_list_compatible_label(&mut label);
13663 completions.push(Completion {
13664 label,
13665 documentation,
13666 replace_range: completion.replace_range,
13667 new_text: completion.new_text,
13668 insert_text_mode: lsp_completion.insert_text_mode,
13669 source: completion.source,
13670 icon_path: None,
13671 confirm: None,
13672 match_start: None,
13673 snippet_deduplication_key: None,
13674 });
13675 }
13676 None => {
13677 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13678 ensure_uniform_list_compatible_label(&mut label);
13679 completions.push(Completion {
13680 label,
13681 documentation: None,
13682 replace_range: completion.replace_range,
13683 new_text: completion.new_text,
13684 source: completion.source,
13685 insert_text_mode: None,
13686 icon_path: None,
13687 confirm: None,
13688 match_start: None,
13689 snippet_deduplication_key: None,
13690 });
13691 }
13692 }
13693 }
13694 completions
13695}
13696
13697#[derive(Debug)]
13698pub enum LanguageServerToQuery {
13699 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13700 FirstCapable,
13701 /// Query a specific language server.
13702 Other(LanguageServerId),
13703}
13704
13705#[derive(Default)]
13706struct RenamePathsWatchedForServer {
13707 did_rename: Vec<RenameActionPredicate>,
13708 will_rename: Vec<RenameActionPredicate>,
13709}
13710
13711impl RenamePathsWatchedForServer {
13712 fn with_did_rename_patterns(
13713 mut self,
13714 did_rename: Option<&FileOperationRegistrationOptions>,
13715 ) -> Self {
13716 if let Some(did_rename) = did_rename {
13717 self.did_rename = did_rename
13718 .filters
13719 .iter()
13720 .filter_map(|filter| filter.try_into().log_err())
13721 .collect();
13722 }
13723 self
13724 }
13725 fn with_will_rename_patterns(
13726 mut self,
13727 will_rename: Option<&FileOperationRegistrationOptions>,
13728 ) -> Self {
13729 if let Some(will_rename) = will_rename {
13730 self.will_rename = will_rename
13731 .filters
13732 .iter()
13733 .filter_map(|filter| filter.try_into().log_err())
13734 .collect();
13735 }
13736 self
13737 }
13738
13739 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13740 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13741 }
13742 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13743 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13744 }
13745}
13746
13747impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13748 type Error = globset::Error;
13749 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13750 Ok(Self {
13751 kind: ops.pattern.matches.clone(),
13752 glob: GlobBuilder::new(&ops.pattern.glob)
13753 .case_insensitive(
13754 ops.pattern
13755 .options
13756 .as_ref()
13757 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13758 )
13759 .build()?
13760 .compile_matcher(),
13761 })
13762 }
13763}
13764struct RenameActionPredicate {
13765 glob: GlobMatcher,
13766 kind: Option<FileOperationPatternKind>,
13767}
13768
13769impl RenameActionPredicate {
13770 // Returns true if language server should be notified
13771 fn eval(&self, path: &str, is_dir: bool) -> bool {
13772 self.kind.as_ref().is_none_or(|kind| {
13773 let expected_kind = if is_dir {
13774 FileOperationPatternKind::Folder
13775 } else {
13776 FileOperationPatternKind::File
13777 };
13778 kind == &expected_kind
13779 }) && self.glob.is_match(path)
13780 }
13781}
13782
13783#[derive(Default)]
13784struct LanguageServerWatchedPaths {
13785 worktree_paths: HashMap<WorktreeId, GlobSet>,
13786 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13787}
13788
13789#[derive(Default)]
13790struct LanguageServerWatchedPathsBuilder {
13791 worktree_paths: HashMap<WorktreeId, GlobSet>,
13792 abs_paths: HashMap<Arc<Path>, GlobSet>,
13793}
13794
13795impl LanguageServerWatchedPathsBuilder {
13796 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13797 self.worktree_paths.insert(worktree_id, glob_set);
13798 }
13799 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13800 self.abs_paths.insert(path, glob_set);
13801 }
13802 fn build(
13803 self,
13804 fs: Arc<dyn Fs>,
13805 language_server_id: LanguageServerId,
13806 cx: &mut Context<LspStore>,
13807 ) -> LanguageServerWatchedPaths {
13808 let lsp_store = cx.weak_entity();
13809
13810 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13811 let abs_paths = self
13812 .abs_paths
13813 .into_iter()
13814 .map(|(abs_path, globset)| {
13815 let task = cx.spawn({
13816 let abs_path = abs_path.clone();
13817 let fs = fs.clone();
13818
13819 let lsp_store = lsp_store.clone();
13820 async move |_, cx| {
13821 maybe!(async move {
13822 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13823 while let Some(update) = push_updates.0.next().await {
13824 let action = lsp_store
13825 .update(cx, |this, _| {
13826 let Some(local) = this.as_local() else {
13827 return ControlFlow::Break(());
13828 };
13829 let Some(watcher) = local
13830 .language_server_watched_paths
13831 .get(&language_server_id)
13832 else {
13833 return ControlFlow::Break(());
13834 };
13835 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13836 "Watched abs path is not registered with a watcher",
13837 );
13838 let matching_entries = update
13839 .into_iter()
13840 .filter(|event| globs.is_match(&event.path))
13841 .collect::<Vec<_>>();
13842 this.lsp_notify_abs_paths_changed(
13843 language_server_id,
13844 matching_entries,
13845 );
13846 ControlFlow::Continue(())
13847 })
13848 .ok()?;
13849
13850 if action.is_break() {
13851 break;
13852 }
13853 }
13854 Some(())
13855 })
13856 .await;
13857 }
13858 });
13859 (abs_path, (globset, task))
13860 })
13861 .collect();
13862 LanguageServerWatchedPaths {
13863 worktree_paths: self.worktree_paths,
13864 abs_paths,
13865 }
13866 }
13867}
13868
13869struct LspBufferSnapshot {
13870 version: i32,
13871 snapshot: TextBufferSnapshot,
13872}
13873
13874/// A prompt requested by LSP server.
13875#[derive(Clone, Debug)]
13876pub struct LanguageServerPromptRequest {
13877 pub id: usize,
13878 pub level: PromptLevel,
13879 pub message: String,
13880 pub actions: Vec<MessageActionItem>,
13881 pub lsp_name: String,
13882 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13883}
13884
13885impl LanguageServerPromptRequest {
13886 pub fn new(
13887 level: PromptLevel,
13888 message: String,
13889 actions: Vec<MessageActionItem>,
13890 lsp_name: String,
13891 response_channel: smol::channel::Sender<MessageActionItem>,
13892 ) -> Self {
13893 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13894 LanguageServerPromptRequest {
13895 id,
13896 level,
13897 message,
13898 actions,
13899 lsp_name,
13900 response_channel,
13901 }
13902 }
13903 pub async fn respond(self, index: usize) -> Option<()> {
13904 if let Some(response) = self.actions.into_iter().nth(index) {
13905 self.response_channel.send(response).await.ok()
13906 } else {
13907 None
13908 }
13909 }
13910
13911 #[cfg(any(test, feature = "test-support"))]
13912 pub fn test(
13913 level: PromptLevel,
13914 message: String,
13915 actions: Vec<MessageActionItem>,
13916 lsp_name: String,
13917 ) -> Self {
13918 let (tx, _rx) = smol::channel::unbounded();
13919 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13920 }
13921}
13922impl PartialEq for LanguageServerPromptRequest {
13923 fn eq(&self, other: &Self) -> bool {
13924 self.message == other.message && self.actions == other.actions
13925 }
13926}
13927
13928#[derive(Clone, Debug, PartialEq)]
13929pub enum LanguageServerLogType {
13930 Log(MessageType),
13931 Trace { verbose_info: Option<String> },
13932 Rpc { received: bool },
13933}
13934
13935impl LanguageServerLogType {
13936 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13937 match self {
13938 Self::Log(log_type) => {
13939 use proto::log_message::LogLevel;
13940 let level = match *log_type {
13941 MessageType::ERROR => LogLevel::Error,
13942 MessageType::WARNING => LogLevel::Warning,
13943 MessageType::INFO => LogLevel::Info,
13944 MessageType::LOG => LogLevel::Log,
13945 other => {
13946 log::warn!("Unknown lsp log message type: {other:?}");
13947 LogLevel::Log
13948 }
13949 };
13950 proto::language_server_log::LogType::Log(proto::LogMessage {
13951 level: level as i32,
13952 })
13953 }
13954 Self::Trace { verbose_info } => {
13955 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13956 verbose_info: verbose_info.to_owned(),
13957 })
13958 }
13959 Self::Rpc { received } => {
13960 let kind = if *received {
13961 proto::rpc_message::Kind::Received
13962 } else {
13963 proto::rpc_message::Kind::Sent
13964 };
13965 let kind = kind as i32;
13966 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13967 }
13968 }
13969 }
13970
13971 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13972 use proto::log_message::LogLevel;
13973 use proto::rpc_message;
13974 match log_type {
13975 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13976 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13977 LogLevel::Error => MessageType::ERROR,
13978 LogLevel::Warning => MessageType::WARNING,
13979 LogLevel::Info => MessageType::INFO,
13980 LogLevel::Log => MessageType::LOG,
13981 },
13982 ),
13983 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13984 verbose_info: trace_message.verbose_info,
13985 },
13986 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13987 received: match rpc_message::Kind::from_i32(message.kind)
13988 .unwrap_or(rpc_message::Kind::Received)
13989 {
13990 rpc_message::Kind::Received => true,
13991 rpc_message::Kind::Sent => false,
13992 },
13993 },
13994 }
13995 }
13996}
13997
13998pub struct WorkspaceRefreshTask {
13999 refresh_tx: mpsc::Sender<()>,
14000 progress_tx: mpsc::Sender<()>,
14001 #[allow(dead_code)]
14002 task: Task<()>,
14003}
14004
14005pub enum LanguageServerState {
14006 Starting {
14007 startup: Task<Option<Arc<LanguageServer>>>,
14008 /// List of language servers that will be added to the workspace once it's initialization completes.
14009 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
14010 },
14011
14012 Running {
14013 adapter: Arc<CachedLspAdapter>,
14014 server: Arc<LanguageServer>,
14015 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
14016 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
14017 },
14018}
14019
14020impl LanguageServerState {
14021 fn add_workspace_folder(&self, uri: Uri) {
14022 match self {
14023 LanguageServerState::Starting {
14024 pending_workspace_folders,
14025 ..
14026 } => {
14027 pending_workspace_folders.lock().insert(uri);
14028 }
14029 LanguageServerState::Running { server, .. } => {
14030 server.add_workspace_folder(uri);
14031 }
14032 }
14033 }
14034 fn _remove_workspace_folder(&self, uri: Uri) {
14035 match self {
14036 LanguageServerState::Starting {
14037 pending_workspace_folders,
14038 ..
14039 } => {
14040 pending_workspace_folders.lock().remove(&uri);
14041 }
14042 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
14043 }
14044 }
14045}
14046
14047impl std::fmt::Debug for LanguageServerState {
14048 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14049 match self {
14050 LanguageServerState::Starting { .. } => {
14051 f.debug_struct("LanguageServerState::Starting").finish()
14052 }
14053 LanguageServerState::Running { .. } => {
14054 f.debug_struct("LanguageServerState::Running").finish()
14055 }
14056 }
14057 }
14058}
14059
14060#[derive(Clone, Debug, Serialize)]
14061pub struct LanguageServerProgress {
14062 pub is_disk_based_diagnostics_progress: bool,
14063 pub is_cancellable: bool,
14064 pub title: Option<String>,
14065 pub message: Option<String>,
14066 pub percentage: Option<usize>,
14067 #[serde(skip_serializing)]
14068 pub last_update_at: Instant,
14069}
14070
14071#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
14072pub struct DiagnosticSummary {
14073 pub error_count: usize,
14074 pub warning_count: usize,
14075}
14076
14077impl DiagnosticSummary {
14078 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
14079 let mut this = Self {
14080 error_count: 0,
14081 warning_count: 0,
14082 };
14083
14084 for entry in diagnostics {
14085 if entry.diagnostic.is_primary {
14086 match entry.diagnostic.severity {
14087 DiagnosticSeverity::ERROR => this.error_count += 1,
14088 DiagnosticSeverity::WARNING => this.warning_count += 1,
14089 _ => {}
14090 }
14091 }
14092 }
14093
14094 this
14095 }
14096
14097 pub fn is_empty(&self) -> bool {
14098 self.error_count == 0 && self.warning_count == 0
14099 }
14100
14101 pub fn to_proto(
14102 self,
14103 language_server_id: LanguageServerId,
14104 path: &RelPath,
14105 ) -> proto::DiagnosticSummary {
14106 proto::DiagnosticSummary {
14107 path: path.to_proto(),
14108 language_server_id: language_server_id.0 as u64,
14109 error_count: self.error_count as u32,
14110 warning_count: self.warning_count as u32,
14111 }
14112 }
14113}
14114
14115#[derive(Clone, Debug)]
14116pub enum CompletionDocumentation {
14117 /// There is no documentation for this completion.
14118 Undocumented,
14119 /// A single line of documentation.
14120 SingleLine(SharedString),
14121 /// Multiple lines of plain text documentation.
14122 MultiLinePlainText(SharedString),
14123 /// Markdown documentation.
14124 MultiLineMarkdown(SharedString),
14125 /// Both single line and multiple lines of plain text documentation.
14126 SingleLineAndMultiLinePlainText {
14127 single_line: SharedString,
14128 plain_text: Option<SharedString>,
14129 },
14130}
14131
14132impl CompletionDocumentation {
14133 #[cfg(any(test, feature = "test-support"))]
14134 pub fn text(&self) -> SharedString {
14135 match self {
14136 CompletionDocumentation::Undocumented => "".into(),
14137 CompletionDocumentation::SingleLine(s) => s.clone(),
14138 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
14139 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
14140 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
14141 single_line.clone()
14142 }
14143 }
14144 }
14145}
14146
14147impl From<lsp::Documentation> for CompletionDocumentation {
14148 fn from(docs: lsp::Documentation) -> Self {
14149 match docs {
14150 lsp::Documentation::String(text) => {
14151 if text.lines().count() <= 1 {
14152 CompletionDocumentation::SingleLine(text.trim().to_string().into())
14153 } else {
14154 CompletionDocumentation::MultiLinePlainText(text.into())
14155 }
14156 }
14157
14158 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
14159 lsp::MarkupKind::PlainText => {
14160 if value.lines().count() <= 1 {
14161 CompletionDocumentation::SingleLine(value.into())
14162 } else {
14163 CompletionDocumentation::MultiLinePlainText(value.into())
14164 }
14165 }
14166
14167 lsp::MarkupKind::Markdown => {
14168 CompletionDocumentation::MultiLineMarkdown(value.into())
14169 }
14170 },
14171 }
14172 }
14173}
14174
14175pub enum ResolvedHint {
14176 Resolved(InlayHint),
14177 Resolving(Shared<Task<()>>),
14178}
14179
14180pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
14181 glob.components()
14182 .take_while(|component| match component {
14183 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
14184 _ => true,
14185 })
14186 .collect()
14187}
14188
14189pub struct SshLspAdapter {
14190 name: LanguageServerName,
14191 binary: LanguageServerBinary,
14192 initialization_options: Option<String>,
14193 code_action_kinds: Option<Vec<CodeActionKind>>,
14194}
14195
14196impl SshLspAdapter {
14197 pub fn new(
14198 name: LanguageServerName,
14199 binary: LanguageServerBinary,
14200 initialization_options: Option<String>,
14201 code_action_kinds: Option<String>,
14202 ) -> Self {
14203 Self {
14204 name,
14205 binary,
14206 initialization_options,
14207 code_action_kinds: code_action_kinds
14208 .as_ref()
14209 .and_then(|c| serde_json::from_str(c).ok()),
14210 }
14211 }
14212}
14213
14214impl LspInstaller for SshLspAdapter {
14215 type BinaryVersion = ();
14216 async fn check_if_user_installed(
14217 &self,
14218 _: &dyn LspAdapterDelegate,
14219 _: Option<Toolchain>,
14220 _: &AsyncApp,
14221 ) -> Option<LanguageServerBinary> {
14222 Some(self.binary.clone())
14223 }
14224
14225 async fn cached_server_binary(
14226 &self,
14227 _: PathBuf,
14228 _: &dyn LspAdapterDelegate,
14229 ) -> Option<LanguageServerBinary> {
14230 None
14231 }
14232
14233 async fn fetch_latest_server_version(
14234 &self,
14235 _: &dyn LspAdapterDelegate,
14236 _: bool,
14237 _: &mut AsyncApp,
14238 ) -> Result<()> {
14239 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14240 }
14241
14242 async fn fetch_server_binary(
14243 &self,
14244 _: (),
14245 _: PathBuf,
14246 _: &dyn LspAdapterDelegate,
14247 ) -> Result<LanguageServerBinary> {
14248 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14249 }
14250}
14251
14252#[async_trait(?Send)]
14253impl LspAdapter for SshLspAdapter {
14254 fn name(&self) -> LanguageServerName {
14255 self.name.clone()
14256 }
14257
14258 async fn initialization_options(
14259 self: Arc<Self>,
14260 _: &Arc<dyn LspAdapterDelegate>,
14261 _: &mut AsyncApp,
14262 ) -> Result<Option<serde_json::Value>> {
14263 let Some(options) = &self.initialization_options else {
14264 return Ok(None);
14265 };
14266 let result = serde_json::from_str(options)?;
14267 Ok(result)
14268 }
14269
14270 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14271 self.code_action_kinds.clone()
14272 }
14273}
14274
14275pub fn language_server_settings<'a>(
14276 delegate: &'a dyn LspAdapterDelegate,
14277 language: &LanguageServerName,
14278 cx: &'a App,
14279) -> Option<&'a LspSettings> {
14280 language_server_settings_for(
14281 SettingsLocation {
14282 worktree_id: delegate.worktree_id(),
14283 path: RelPath::empty(),
14284 },
14285 language,
14286 cx,
14287 )
14288}
14289
14290pub fn language_server_settings_for<'a>(
14291 location: SettingsLocation<'a>,
14292 language: &LanguageServerName,
14293 cx: &'a App,
14294) -> Option<&'a LspSettings> {
14295 ProjectSettings::get(Some(location), cx).lsp.get(language)
14296}
14297
14298pub struct LocalLspAdapterDelegate {
14299 lsp_store: WeakEntity<LspStore>,
14300 worktree: worktree::Snapshot,
14301 fs: Arc<dyn Fs>,
14302 http_client: Arc<dyn HttpClient>,
14303 language_registry: Arc<LanguageRegistry>,
14304 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14305}
14306
14307impl LocalLspAdapterDelegate {
14308 pub fn new(
14309 language_registry: Arc<LanguageRegistry>,
14310 environment: &Entity<ProjectEnvironment>,
14311 lsp_store: WeakEntity<LspStore>,
14312 worktree: &Entity<Worktree>,
14313 http_client: Arc<dyn HttpClient>,
14314 fs: Arc<dyn Fs>,
14315 cx: &mut App,
14316 ) -> Arc<Self> {
14317 let load_shell_env_task =
14318 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14319
14320 Arc::new(Self {
14321 lsp_store,
14322 worktree: worktree.read(cx).snapshot(),
14323 fs,
14324 http_client,
14325 language_registry,
14326 load_shell_env_task,
14327 })
14328 }
14329
14330 pub fn from_local_lsp(
14331 local: &LocalLspStore,
14332 worktree: &Entity<Worktree>,
14333 cx: &mut App,
14334 ) -> Arc<Self> {
14335 Self::new(
14336 local.languages.clone(),
14337 &local.environment,
14338 local.weak.clone(),
14339 worktree,
14340 local.http_client.clone(),
14341 local.fs.clone(),
14342 cx,
14343 )
14344 }
14345}
14346
14347#[async_trait]
14348impl LspAdapterDelegate for LocalLspAdapterDelegate {
14349 fn show_notification(&self, message: &str, cx: &mut App) {
14350 self.lsp_store
14351 .update(cx, |_, cx| {
14352 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14353 })
14354 .ok();
14355 }
14356
14357 fn http_client(&self) -> Arc<dyn HttpClient> {
14358 self.http_client.clone()
14359 }
14360
14361 fn worktree_id(&self) -> WorktreeId {
14362 self.worktree.id()
14363 }
14364
14365 fn worktree_root_path(&self) -> &Path {
14366 self.worktree.abs_path().as_ref()
14367 }
14368
14369 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14370 self.worktree.resolve_relative_path(path)
14371 }
14372
14373 async fn shell_env(&self) -> HashMap<String, String> {
14374 let task = self.load_shell_env_task.clone();
14375 task.await.unwrap_or_default()
14376 }
14377
14378 async fn npm_package_installed_version(
14379 &self,
14380 package_name: &str,
14381 ) -> Result<Option<(PathBuf, Version)>> {
14382 let local_package_directory = self.worktree_root_path();
14383 let node_modules_directory = local_package_directory.join("node_modules");
14384
14385 if let Some(version) =
14386 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14387 {
14388 return Ok(Some((node_modules_directory, version)));
14389 }
14390 let Some(npm) = self.which("npm".as_ref()).await else {
14391 log::warn!(
14392 "Failed to find npm executable for {:?}",
14393 local_package_directory
14394 );
14395 return Ok(None);
14396 };
14397
14398 let env = self.shell_env().await;
14399 let output = util::command::new_command(&npm)
14400 .args(["root", "-g"])
14401 .envs(env)
14402 .current_dir(local_package_directory)
14403 .output()
14404 .await?;
14405 let global_node_modules =
14406 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14407
14408 if let Some(version) =
14409 read_package_installed_version(global_node_modules.clone(), package_name).await?
14410 {
14411 return Ok(Some((global_node_modules, version)));
14412 }
14413 return Ok(None);
14414 }
14415
14416 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14417 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14418 if self.fs.is_file(&worktree_abs_path).await {
14419 worktree_abs_path.pop();
14420 }
14421
14422 let env = self.shell_env().await;
14423
14424 let shell_path = env.get("PATH").cloned();
14425
14426 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14427 }
14428
14429 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14430 let mut working_dir = self.worktree_root_path().to_path_buf();
14431 if self.fs.is_file(&working_dir).await {
14432 working_dir.pop();
14433 }
14434 let output = util::command::new_command(&command.path)
14435 .args(command.arguments)
14436 .envs(command.env.clone().unwrap_or_default())
14437 .current_dir(working_dir)
14438 .output()
14439 .await?;
14440
14441 anyhow::ensure!(
14442 output.status.success(),
14443 "{}, stdout: {:?}, stderr: {:?}",
14444 output.status,
14445 String::from_utf8_lossy(&output.stdout),
14446 String::from_utf8_lossy(&output.stderr)
14447 );
14448 Ok(())
14449 }
14450
14451 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14452 self.language_registry
14453 .update_lsp_binary_status(server_name, status);
14454 }
14455
14456 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14457 self.language_registry
14458 .all_lsp_adapters()
14459 .into_iter()
14460 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14461 .collect()
14462 }
14463
14464 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14465 let dir = self.language_registry.language_server_download_dir(name)?;
14466
14467 if !dir.exists() {
14468 smol::fs::create_dir_all(&dir)
14469 .await
14470 .context("failed to create container directory")
14471 .log_err()?;
14472 }
14473
14474 Some(dir)
14475 }
14476
14477 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14478 let entry = self
14479 .worktree
14480 .entry_for_path(path)
14481 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14482 let abs_path = self.worktree.absolutize(&entry.path);
14483 self.fs.load(&abs_path).await
14484 }
14485}
14486
14487async fn populate_labels_for_symbols(
14488 symbols: Vec<CoreSymbol>,
14489 language_registry: &Arc<LanguageRegistry>,
14490 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14491 output: &mut Vec<Symbol>,
14492) {
14493 #[allow(clippy::mutable_key_type)]
14494 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14495
14496 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14497 for symbol in symbols {
14498 let Some(file_name) = symbol.path.file_name() else {
14499 continue;
14500 };
14501 let language = language_registry
14502 .load_language_for_file_path(Path::new(file_name))
14503 .await
14504 .ok()
14505 .or_else(|| {
14506 unknown_paths.insert(file_name.into());
14507 None
14508 });
14509 symbols_by_language
14510 .entry(language)
14511 .or_default()
14512 .push(symbol);
14513 }
14514
14515 for unknown_path in unknown_paths {
14516 log::info!("no language found for symbol in file {unknown_path:?}");
14517 }
14518
14519 let mut label_params = Vec::new();
14520 for (language, mut symbols) in symbols_by_language {
14521 label_params.clear();
14522 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14523 name: mem::take(&mut symbol.name),
14524 kind: symbol.kind,
14525 container_name: symbol.container_name.take(),
14526 }));
14527
14528 let mut labels = Vec::new();
14529 if let Some(language) = language {
14530 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14531 language_registry
14532 .lsp_adapters(&language.name())
14533 .first()
14534 .cloned()
14535 });
14536 if let Some(lsp_adapter) = lsp_adapter {
14537 labels = lsp_adapter
14538 .labels_for_symbols(&label_params, &language)
14539 .await
14540 .log_err()
14541 .unwrap_or_default();
14542 }
14543 }
14544
14545 for (
14546 (
14547 symbol,
14548 language::Symbol {
14549 name,
14550 container_name,
14551 ..
14552 },
14553 ),
14554 label,
14555 ) in symbols
14556 .into_iter()
14557 .zip(label_params.drain(..))
14558 .zip(labels.into_iter().chain(iter::repeat(None)))
14559 {
14560 output.push(Symbol {
14561 language_server_name: symbol.language_server_name,
14562 source_worktree_id: symbol.source_worktree_id,
14563 source_language_server_id: symbol.source_language_server_id,
14564 path: symbol.path,
14565 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14566 name,
14567 kind: symbol.kind,
14568 range: symbol.range,
14569 container_name,
14570 });
14571 }
14572 }
14573}
14574
14575pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14576 text.lines()
14577 .map(|line| line.trim())
14578 .filter(|line| !line.is_empty())
14579 .join(separator)
14580}
14581
14582fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14583 match server.capabilities().text_document_sync.as_ref()? {
14584 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14585 // Server wants didSave but didn't specify includeText.
14586 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14587 // Server doesn't want didSave at all.
14588 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14589 // Server provided SaveOptions.
14590 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14591 Some(save_options.include_text.unwrap_or(false))
14592 }
14593 },
14594 // We do not have any save info. Kind affects didChange only.
14595 lsp::TextDocumentSyncCapability::Kind(_) => None,
14596 }
14597}
14598
14599/// Completion items are displayed in a `UniformList`.
14600/// Usually, those items are single-line strings, but in LSP responses,
14601/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14602/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14603/// 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,
14604/// breaking the completions menu presentation.
14605///
14606/// 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.
14607pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14608 let mut new_text = String::with_capacity(label.text.len());
14609 let mut offset_map = vec![0; label.text.len() + 1];
14610 let mut last_char_was_space = false;
14611 let mut new_idx = 0;
14612 let chars = label.text.char_indices().fuse();
14613 let mut newlines_removed = false;
14614
14615 for (idx, c) in chars {
14616 offset_map[idx] = new_idx;
14617
14618 match c {
14619 '\n' if last_char_was_space => {
14620 newlines_removed = true;
14621 }
14622 '\t' | ' ' if last_char_was_space => {}
14623 '\n' if !last_char_was_space => {
14624 new_text.push(' ');
14625 new_idx += 1;
14626 last_char_was_space = true;
14627 newlines_removed = true;
14628 }
14629 ' ' | '\t' => {
14630 new_text.push(' ');
14631 new_idx += 1;
14632 last_char_was_space = true;
14633 }
14634 _ => {
14635 new_text.push(c);
14636 new_idx += c.len_utf8();
14637 last_char_was_space = false;
14638 }
14639 }
14640 }
14641 offset_map[label.text.len()] = new_idx;
14642
14643 // Only modify the label if newlines were removed.
14644 if !newlines_removed {
14645 return;
14646 }
14647
14648 let last_index = new_idx;
14649 let mut run_ranges_errors = Vec::new();
14650 label.runs.retain_mut(|(range, _)| {
14651 match offset_map.get(range.start) {
14652 Some(&start) => range.start = start,
14653 None => {
14654 run_ranges_errors.push(range.clone());
14655 return false;
14656 }
14657 }
14658
14659 match offset_map.get(range.end) {
14660 Some(&end) => range.end = end,
14661 None => {
14662 run_ranges_errors.push(range.clone());
14663 range.end = last_index;
14664 }
14665 }
14666 true
14667 });
14668 if !run_ranges_errors.is_empty() {
14669 log::error!(
14670 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14671 label.text
14672 );
14673 }
14674
14675 let mut wrong_filter_range = None;
14676 if label.filter_range == (0..label.text.len()) {
14677 label.filter_range = 0..new_text.len();
14678 } else {
14679 let mut original_filter_range = Some(label.filter_range.clone());
14680 match offset_map.get(label.filter_range.start) {
14681 Some(&start) => label.filter_range.start = start,
14682 None => {
14683 wrong_filter_range = original_filter_range.take();
14684 label.filter_range.start = last_index;
14685 }
14686 }
14687
14688 match offset_map.get(label.filter_range.end) {
14689 Some(&end) => label.filter_range.end = end,
14690 None => {
14691 wrong_filter_range = original_filter_range.take();
14692 label.filter_range.end = last_index;
14693 }
14694 }
14695 }
14696 if let Some(wrong_filter_range) = wrong_filter_range {
14697 log::error!(
14698 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14699 label.text
14700 );
14701 }
14702
14703 label.text = new_text;
14704}
14705
14706/// Apply edits to the buffer that will become part of the formatting transaction.
14707/// Fails if the buffer has been edited since the start of that transaction.
14708fn extend_formatting_transaction(
14709 buffer: &FormattableBuffer,
14710 formatting_transaction_id: text::TransactionId,
14711 cx: &mut AsyncApp,
14712 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
14713) -> anyhow::Result<()> {
14714 buffer.handle.update(cx, |buffer, cx| {
14715 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
14716 if last_transaction_id != Some(formatting_transaction_id) {
14717 anyhow::bail!("Buffer edited while formatting. Aborting")
14718 }
14719 buffer.start_transaction();
14720 operation(buffer, cx);
14721 if let Some(transaction_id) = buffer.end_transaction(cx) {
14722 buffer.merge_transactions(transaction_id, formatting_transaction_id);
14723 }
14724 Ok(())
14725 })
14726}