1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
77 Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 language_settings,
81 },
82 point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153pub use semantic_tokens::{
154 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
155};
156
157pub use worktree::{
158 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
159 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
160};
161
162const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
163pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
164const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
165const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
166static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
167
168#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
169pub enum ProgressToken {
170 Number(i32),
171 String(SharedString),
172}
173
174impl std::fmt::Display for ProgressToken {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Number(number) => write!(f, "{number}"),
178 Self::String(string) => write!(f, "{string}"),
179 }
180 }
181}
182
183impl ProgressToken {
184 fn from_lsp(value: lsp::NumberOrString) -> Self {
185 match value {
186 lsp::NumberOrString::Number(number) => Self::Number(number),
187 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
188 }
189 }
190
191 fn to_lsp(&self) -> lsp::NumberOrString {
192 match self {
193 Self::Number(number) => lsp::NumberOrString::Number(*number),
194 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
195 }
196 }
197
198 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
199 Some(match value.value? {
200 proto::progress_token::Value::Number(number) => Self::Number(number),
201 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
202 })
203 }
204
205 fn to_proto(&self) -> proto::ProgressToken {
206 proto::ProgressToken {
207 value: Some(match self {
208 Self::Number(number) => proto::progress_token::Value::Number(*number),
209 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
210 }),
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum FormatTrigger {
217 Save,
218 Manual,
219}
220
221pub enum LspFormatTarget {
222 Buffers,
223 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
228
229struct OpenLspBuffer(Entity<Buffer>);
230
231impl FormatTrigger {
232 fn from_proto(value: i32) -> FormatTrigger {
233 match value {
234 0 => FormatTrigger::Save,
235 1 => FormatTrigger::Manual,
236 _ => FormatTrigger::Save,
237 }
238 }
239}
240
241#[derive(Clone)]
242struct UnifiedLanguageServer {
243 id: LanguageServerId,
244 project_roots: HashSet<Arc<RelPath>>,
245}
246
247/// Settings that affect language server identity.
248///
249/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
250/// updated via `workspace/didChangeConfiguration` without restarting the server.
251#[derive(Clone, Debug, Hash, PartialEq, Eq)]
252struct LanguageServerSeedSettings {
253 binary: Option<BinarySettings>,
254 initialization_options: Option<serde_json::Value>,
255}
256
257#[derive(Clone, Debug, Hash, PartialEq, Eq)]
258struct LanguageServerSeed {
259 worktree_id: WorktreeId,
260 name: LanguageServerName,
261 toolchain: Option<Toolchain>,
262 settings: LanguageServerSeedSettings,
263}
264
265#[derive(Debug)]
266pub struct DocumentDiagnosticsUpdate<'a, D> {
267 pub diagnostics: D,
268 pub result_id: Option<SharedString>,
269 pub registration_id: Option<SharedString>,
270 pub server_id: LanguageServerId,
271 pub disk_based_sources: Cow<'a, [String]>,
272}
273
274pub struct DocumentDiagnostics {
275 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 document_abs_path: PathBuf,
277 version: Option<i32>,
278}
279
280#[derive(Default, Debug)]
281struct DynamicRegistrations {
282 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
283 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
284}
285
286pub struct LocalLspStore {
287 weak: WeakEntity<LspStore>,
288 pub worktree_store: Entity<WorktreeStore>,
289 toolchain_store: Entity<LocalToolchainStore>,
290 http_client: Arc<dyn HttpClient>,
291 environment: Entity<ProjectEnvironment>,
292 fs: Arc<dyn Fs>,
293 languages: Arc<LanguageRegistry>,
294 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
295 yarn: Entity<YarnPathStore>,
296 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
297 buffers_being_formatted: HashSet<BufferId>,
298 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
299 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
300 watched_manifest_filenames: HashSet<ManifestName>,
301 language_server_paths_watched_for_rename:
302 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
303 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
304 supplementary_language_servers:
305 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
306 prettier_store: Entity<PrettierStore>,
307 next_diagnostic_group_id: usize,
308 diagnostics: HashMap<
309 WorktreeId,
310 HashMap<
311 Arc<RelPath>,
312 Vec<(
313 LanguageServerId,
314 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
315 )>,
316 >,
317 >,
318 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
319 _subscriptions: Vec<gpui::Subscription>,
320 lsp_tree: LanguageServerTree,
321 registered_buffers: HashMap<BufferId, usize>,
322 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
323 buffer_pull_diagnostics_result_ids: HashMap<
324 LanguageServerId,
325 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
326 >,
327 workspace_pull_diagnostics_result_ids: HashMap<
328 LanguageServerId,
329 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
330 >,
331 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
332
333 buffers_to_refresh_hash_set: HashSet<BufferId>,
334 buffers_to_refresh_queue: VecDeque<BufferId>,
335 _background_diagnostics_worker: Shared<Task<()>>,
336}
337
338impl LocalLspStore {
339 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
340 pub fn running_language_server_for_id(
341 &self,
342 id: LanguageServerId,
343 ) -> Option<&Arc<LanguageServer>> {
344 let language_server_state = self.language_servers.get(&id)?;
345
346 match language_server_state {
347 LanguageServerState::Running { server, .. } => Some(server),
348 LanguageServerState::Starting { .. } => None,
349 }
350 }
351
352 fn get_or_insert_language_server(
353 &mut self,
354 worktree_handle: &Entity<Worktree>,
355 delegate: Arc<LocalLspAdapterDelegate>,
356 disposition: &Arc<LaunchDisposition>,
357 language_name: &LanguageName,
358 cx: &mut App,
359 ) -> LanguageServerId {
360 let key = LanguageServerSeed {
361 worktree_id: worktree_handle.read(cx).id(),
362 name: disposition.server_name.clone(),
363 settings: LanguageServerSeedSettings {
364 binary: disposition.settings.binary.clone(),
365 initialization_options: disposition.settings.initialization_options.clone(),
366 },
367 toolchain: disposition.toolchain.clone(),
368 };
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 state.id
372 } else {
373 let adapter = self
374 .languages
375 .lsp_adapters(language_name)
376 .into_iter()
377 .find(|adapter| adapter.name() == disposition.server_name)
378 .expect("To find LSP adapter");
379 let new_language_server_id = self.start_language_server(
380 worktree_handle,
381 delegate,
382 adapter,
383 disposition.settings.clone(),
384 key.clone(),
385 language_name.clone(),
386 cx,
387 );
388 if let Some(state) = self.language_server_ids.get_mut(&key) {
389 state.project_roots.insert(disposition.path.path.clone());
390 } else {
391 debug_assert!(
392 false,
393 "Expected `start_language_server` to ensure that `key` exists in a map"
394 );
395 }
396 new_language_server_id
397 }
398 }
399
400 fn start_language_server(
401 &mut self,
402 worktree_handle: &Entity<Worktree>,
403 delegate: Arc<LocalLspAdapterDelegate>,
404 adapter: Arc<CachedLspAdapter>,
405 settings: Arc<LspSettings>,
406 key: LanguageServerSeed,
407 language_name: LanguageName,
408 cx: &mut App,
409 ) -> LanguageServerId {
410 let worktree = worktree_handle.read(cx);
411
412 let worktree_id = worktree.id();
413 let worktree_abs_path = worktree.abs_path();
414 let toolchain = key.toolchain.clone();
415 let override_options = settings.initialization_options.clone();
416
417 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
418
419 let server_id = self.languages.next_language_server_id();
420 log::trace!(
421 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
422 adapter.name.0
423 );
424
425 let wait_until_worktree_trust =
426 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
427 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
428 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
429 });
430 if can_trust {
431 self.restricted_worktrees_tasks.remove(&worktree_id);
432 None
433 } else {
434 match self.restricted_worktrees_tasks.entry(worktree_id) {
435 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
436 hash_map::Entry::Vacant(v) => {
437 let (mut tx, rx) = watch::channel::<bool>();
438 let lsp_store = self.weak.clone();
439 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
440 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
441 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
442 tx.blocking_send(true).ok();
443 lsp_store
444 .update(cx, |lsp_store, _| {
445 if let Some(local_lsp_store) =
446 lsp_store.as_local_mut()
447 {
448 local_lsp_store
449 .restricted_worktrees_tasks
450 .remove(&worktree_id);
451 }
452 })
453 .ok();
454 }
455 }
456 });
457 v.insert((subscription, rx.clone()));
458 Some(rx)
459 }
460 }
461 }
462 });
463 let update_binary_status = wait_until_worktree_trust.is_none();
464
465 let binary = self.get_language_server_binary(
466 worktree_abs_path.clone(),
467 adapter.clone(),
468 settings,
469 toolchain.clone(),
470 delegate.clone(),
471 true,
472 wait_until_worktree_trust,
473 cx,
474 );
475 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
476
477 let pending_server = cx.spawn({
478 let adapter = adapter.clone();
479 let server_name = adapter.name.clone();
480 let stderr_capture = stderr_capture.clone();
481 #[cfg(any(test, feature = "test-support"))]
482 let lsp_store = self.weak.clone();
483 let pending_workspace_folders = pending_workspace_folders.clone();
484 async move |cx| {
485 let binary = binary.await?;
486 #[cfg(any(test, feature = "test-support"))]
487 if let Some(server) = lsp_store
488 .update(&mut cx.clone(), |this, cx| {
489 this.languages.create_fake_language_server(
490 server_id,
491 &server_name,
492 binary.clone(),
493 &mut cx.to_async(),
494 )
495 })
496 .ok()
497 .flatten()
498 {
499 return Ok(server);
500 }
501
502 let code_action_kinds = adapter.code_action_kinds();
503 lsp::LanguageServer::new(
504 stderr_capture,
505 server_id,
506 server_name,
507 binary,
508 &worktree_abs_path,
509 code_action_kinds,
510 Some(pending_workspace_folders),
511 cx,
512 )
513 }
514 });
515
516 let startup = {
517 let server_name = adapter.name.0.clone();
518 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
519 let key = key.clone();
520 let adapter = adapter.clone();
521 let lsp_store = self.weak.clone();
522 let pending_workspace_folders = pending_workspace_folders.clone();
523 let pull_diagnostics = ProjectSettings::get_global(cx)
524 .diagnostics
525 .lsp_pull_diagnostics
526 .enabled;
527 let settings_location = SettingsLocation {
528 worktree_id,
529 path: RelPath::empty(),
530 };
531 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
532 .language(Some(settings_location), Some(&language_name), cx)
533 .semantic_tokens
534 .use_tree_sitter();
535 cx.spawn(async move |cx| {
536 let result = async {
537 let language_server = pending_server.await?;
538
539 let workspace_config = Self::workspace_configuration_for_adapter(
540 adapter.adapter.clone(),
541 &delegate,
542 toolchain,
543 None,
544 cx,
545 )
546 .await?;
547
548 let mut initialization_options = Self::initialization_options_for_adapter(
549 adapter.adapter.clone(),
550 &delegate,
551 cx,
552 )
553 .await?;
554
555 match (&mut initialization_options, override_options) {
556 (Some(initialization_options), Some(override_options)) => {
557 merge_json_value_into(override_options, initialization_options);
558 }
559 (None, override_options) => initialization_options = override_options,
560 _ => {}
561 }
562
563 let initialization_params = cx.update(|cx| {
564 let mut params = language_server.default_initialize_params(
565 pull_diagnostics,
566 augments_syntax_tokens,
567 cx,
568 );
569 params.initialization_options = initialization_options;
570 adapter.adapter.prepare_initialize_params(params, cx)
571 })?;
572
573 Self::setup_lsp_messages(
574 lsp_store.clone(),
575 &language_server,
576 delegate.clone(),
577 adapter.clone(),
578 );
579
580 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
581 settings: workspace_config,
582 };
583 let language_server = cx
584 .update(|cx| {
585 let request_timeout = ProjectSettings::get_global(cx)
586 .global_lsp_settings
587 .get_request_timeout();
588
589 language_server.initialize(
590 initialization_params,
591 Arc::new(did_change_configuration_params.clone()),
592 request_timeout,
593 cx,
594 )
595 })
596 .await
597 .inspect_err(|_| {
598 if let Some(lsp_store) = lsp_store.upgrade() {
599 lsp_store.update(cx, |lsp_store, cx| {
600 lsp_store.cleanup_lsp_data(server_id);
601 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
602 });
603 }
604 })?;
605
606 language_server.notify::<lsp::notification::DidChangeConfiguration>(
607 did_change_configuration_params,
608 )?;
609
610 anyhow::Ok(language_server)
611 }
612 .await;
613
614 match result {
615 Ok(server) => {
616 lsp_store
617 .update(cx, |lsp_store, cx| {
618 lsp_store.insert_newly_running_language_server(
619 adapter,
620 server.clone(),
621 server_id,
622 key,
623 pending_workspace_folders,
624 cx,
625 );
626 })
627 .ok();
628 stderr_capture.lock().take();
629 Some(server)
630 }
631
632 Err(err) => {
633 let log = stderr_capture.lock().take().unwrap_or_default();
634 delegate.update_status(
635 adapter.name(),
636 BinaryStatus::Failed {
637 error: if log.is_empty() {
638 format!("{err:#}")
639 } else {
640 format!("{err:#}\n-- stderr --\n{log}")
641 },
642 },
643 );
644 log::error!(
645 "Failed to start language server {server_name:?}: {}",
646 redact_command(&format!("{err:?}"))
647 );
648 if !log.is_empty() {
649 log::error!("server stderr: {}", redact_command(&log));
650 }
651 None
652 }
653 }
654 })
655 };
656 let state = LanguageServerState::Starting {
657 startup,
658 pending_workspace_folders,
659 };
660
661 if update_binary_status {
662 self.languages
663 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
664 }
665
666 self.language_servers.insert(server_id, state);
667 self.language_server_ids
668 .entry(key)
669 .or_insert(UnifiedLanguageServer {
670 id: server_id,
671 project_roots: Default::default(),
672 });
673 server_id
674 }
675
676 fn get_language_server_binary(
677 &self,
678 worktree_abs_path: Arc<Path>,
679 adapter: Arc<CachedLspAdapter>,
680 settings: Arc<LspSettings>,
681 toolchain: Option<Toolchain>,
682 delegate: Arc<dyn LspAdapterDelegate>,
683 allow_binary_download: bool,
684 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
685 cx: &mut App,
686 ) -> Task<Result<LanguageServerBinary>> {
687 if let Some(settings) = &settings.binary
688 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
689 {
690 let settings = settings.clone();
691 let languages = self.languages.clone();
692 return cx.background_spawn(async move {
693 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
694 let already_trusted = *wait_until_worktree_trust.borrow();
695 if !already_trusted {
696 log::info!(
697 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
698 adapter.name(),
699 );
700 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
701 if worktree_trusted {
702 break;
703 }
704 }
705 log::info!(
706 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
707 adapter.name(),
708 );
709 }
710 languages
711 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
712 }
713 let mut env = delegate.shell_env().await;
714 env.extend(settings.env.unwrap_or_default());
715
716 Ok(LanguageServerBinary {
717 path: delegate.resolve_relative_path(path),
718 env: Some(env),
719 arguments: settings
720 .arguments
721 .unwrap_or_default()
722 .iter()
723 .map(Into::into)
724 .collect(),
725 })
726 });
727 }
728 let lsp_binary_options = LanguageServerBinaryOptions {
729 allow_path_lookup: !settings
730 .binary
731 .as_ref()
732 .and_then(|b| b.ignore_system_version)
733 .unwrap_or_default(),
734 allow_binary_download,
735 pre_release: settings
736 .fetch
737 .as_ref()
738 .and_then(|f| f.pre_release)
739 .unwrap_or(false),
740 };
741
742 cx.spawn(async move |cx| {
743 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
744 let already_trusted = *wait_until_worktree_trust.borrow();
745 if !already_trusted {
746 log::info!(
747 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
748 adapter.name(),
749 );
750 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
751 if worktree_trusted {
752 break;
753 }
754 }
755 log::info!(
756 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
757 adapter.name(),
758 );
759 }
760 }
761
762 let (existing_binary, maybe_download_binary) = adapter
763 .clone()
764 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
765 .await
766 .await;
767
768 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
769
770 let mut binary = match (existing_binary, maybe_download_binary) {
771 (binary, None) => binary?,
772 (Err(_), Some(downloader)) => downloader.await?,
773 (Ok(existing_binary), Some(downloader)) => {
774 let mut download_timeout = cx
775 .background_executor()
776 .timer(SERVER_DOWNLOAD_TIMEOUT)
777 .fuse();
778 let mut downloader = downloader.fuse();
779 futures::select! {
780 _ = download_timeout => {
781 // Return existing binary and kick the existing work to the background.
782 cx.spawn(async move |_| downloader.await).detach();
783 Ok(existing_binary)
784 },
785 downloaded_or_existing_binary = downloader => {
786 // If download fails, this results in the existing binary.
787 downloaded_or_existing_binary
788 }
789 }?
790 }
791 };
792 let mut shell_env = delegate.shell_env().await;
793
794 shell_env.extend(binary.env.unwrap_or_default());
795
796 if let Some(settings) = settings.binary.as_ref() {
797 if let Some(arguments) = &settings.arguments {
798 binary.arguments = arguments.iter().map(Into::into).collect();
799 }
800 if let Some(env) = &settings.env {
801 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
802 }
803 }
804
805 binary.env = Some(shell_env);
806 Ok(binary)
807 })
808 }
809
810 fn setup_lsp_messages(
811 lsp_store: WeakEntity<LspStore>,
812 language_server: &LanguageServer,
813 delegate: Arc<dyn LspAdapterDelegate>,
814 adapter: Arc<CachedLspAdapter>,
815 ) {
816 let name = language_server.name();
817 let server_id = language_server.server_id();
818 language_server
819 .on_notification::<lsp::notification::PublishDiagnostics, _>({
820 let adapter = adapter.clone();
821 let this = lsp_store.clone();
822 move |mut params, cx| {
823 let adapter = adapter.clone();
824 if let Some(this) = this.upgrade() {
825 this.update(cx, |this, cx| {
826 {
827 let buffer = params
828 .uri
829 .to_file_path()
830 .map(|file_path| this.get_buffer(&file_path, cx))
831 .ok()
832 .flatten();
833 adapter.process_diagnostics(&mut params, server_id, buffer);
834 }
835
836 this.merge_lsp_diagnostics(
837 DiagnosticSourceKind::Pushed,
838 vec![DocumentDiagnosticsUpdate {
839 server_id,
840 diagnostics: params,
841 result_id: None,
842 disk_based_sources: Cow::Borrowed(
843 &adapter.disk_based_diagnostic_sources,
844 ),
845 registration_id: None,
846 }],
847 |_, diagnostic, cx| match diagnostic.source_kind {
848 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
849 adapter.retain_old_diagnostic(diagnostic, cx)
850 }
851 DiagnosticSourceKind::Pulled => true,
852 },
853 cx,
854 )
855 .log_err();
856 });
857 }
858 }
859 })
860 .detach();
861 language_server
862 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
863 let adapter = adapter.adapter.clone();
864 let delegate = delegate.clone();
865 let this = lsp_store.clone();
866 move |params, cx| {
867 let adapter = adapter.clone();
868 let delegate = delegate.clone();
869 let this = this.clone();
870 let mut cx = cx.clone();
871 async move {
872 let toolchain_for_id = this
873 .update(&mut cx, |this, _| {
874 this.as_local()?.language_server_ids.iter().find_map(
875 |(seed, value)| {
876 (value.id == server_id).then(|| seed.toolchain.clone())
877 },
878 )
879 })?
880 .context("Expected the LSP store to be in a local mode")?;
881
882 let mut scope_uri_to_workspace_config = BTreeMap::new();
883 for item in ¶ms.items {
884 let scope_uri = item.scope_uri.clone();
885 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
886 scope_uri_to_workspace_config.entry(scope_uri.clone())
887 else {
888 // We've already queried workspace configuration of this URI.
889 continue;
890 };
891 let workspace_config = Self::workspace_configuration_for_adapter(
892 adapter.clone(),
893 &delegate,
894 toolchain_for_id.clone(),
895 scope_uri,
896 &mut cx,
897 )
898 .await?;
899 new_scope_uri.insert(workspace_config);
900 }
901
902 Ok(params
903 .items
904 .into_iter()
905 .filter_map(|item| {
906 let workspace_config =
907 scope_uri_to_workspace_config.get(&item.scope_uri)?;
908 if let Some(section) = &item.section {
909 Some(
910 workspace_config
911 .get(section)
912 .cloned()
913 .unwrap_or(serde_json::Value::Null),
914 )
915 } else {
916 Some(workspace_config.clone())
917 }
918 })
919 .collect())
920 }
921 }
922 })
923 .detach();
924
925 language_server
926 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
927 let this = lsp_store.clone();
928 move |_, cx| {
929 let this = this.clone();
930 let cx = cx.clone();
931 async move {
932 let Some(server) =
933 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
934 else {
935 return Ok(None);
936 };
937 let root = server.workspace_folders();
938 Ok(Some(
939 root.into_iter()
940 .map(|uri| WorkspaceFolder {
941 uri,
942 name: Default::default(),
943 })
944 .collect(),
945 ))
946 }
947 }
948 })
949 .detach();
950 // Even though we don't have handling for these requests, respond to them to
951 // avoid stalling any language server like `gopls` which waits for a response
952 // to these requests when initializing.
953 language_server
954 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
955 let this = lsp_store.clone();
956 move |params, cx| {
957 let this = this.clone();
958 let mut cx = cx.clone();
959 async move {
960 this.update(&mut cx, |this, _| {
961 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
962 {
963 status
964 .progress_tokens
965 .insert(ProgressToken::from_lsp(params.token));
966 }
967 })?;
968
969 Ok(())
970 }
971 }
972 })
973 .detach();
974
975 language_server
976 .on_request::<lsp::request::RegisterCapability, _, _>({
977 let lsp_store = lsp_store.clone();
978 move |params, cx| {
979 let lsp_store = lsp_store.clone();
980 let mut cx = cx.clone();
981 async move {
982 lsp_store
983 .update(&mut cx, |lsp_store, cx| {
984 if lsp_store.as_local().is_some() {
985 match lsp_store
986 .register_server_capabilities(server_id, params, cx)
987 {
988 Ok(()) => {}
989 Err(e) => {
990 log::error!(
991 "Failed to register server capabilities: {e:#}"
992 );
993 }
994 };
995 }
996 })
997 .ok();
998 Ok(())
999 }
1000 }
1001 })
1002 .detach();
1003
1004 language_server
1005 .on_request::<lsp::request::UnregisterCapability, _, _>({
1006 let lsp_store = lsp_store.clone();
1007 move |params, cx| {
1008 let lsp_store = lsp_store.clone();
1009 let mut cx = cx.clone();
1010 async move {
1011 lsp_store
1012 .update(&mut cx, |lsp_store, cx| {
1013 if lsp_store.as_local().is_some() {
1014 match lsp_store
1015 .unregister_server_capabilities(server_id, params, cx)
1016 {
1017 Ok(()) => {}
1018 Err(e) => {
1019 log::error!(
1020 "Failed to unregister server capabilities: {e:#}"
1021 );
1022 }
1023 }
1024 }
1025 })
1026 .ok();
1027 Ok(())
1028 }
1029 }
1030 })
1031 .detach();
1032
1033 language_server
1034 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1035 let this = lsp_store.clone();
1036 move |params, cx| {
1037 let mut cx = cx.clone();
1038 let this = this.clone();
1039 async move {
1040 LocalLspStore::on_lsp_workspace_edit(
1041 this.clone(),
1042 params,
1043 server_id,
1044 &mut cx,
1045 )
1046 .await
1047 }
1048 }
1049 })
1050 .detach();
1051
1052 language_server
1053 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1054 let lsp_store = lsp_store.clone();
1055 let request_id = Arc::new(AtomicUsize::new(0));
1056 move |(), cx| {
1057 let lsp_store = lsp_store.clone();
1058 let request_id = request_id.clone();
1059 let mut cx = cx.clone();
1060 async move {
1061 lsp_store
1062 .update(&mut cx, |lsp_store, cx| {
1063 let request_id =
1064 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1065 cx.emit(LspStoreEvent::RefreshInlayHints {
1066 server_id,
1067 request_id,
1068 });
1069 lsp_store
1070 .downstream_client
1071 .as_ref()
1072 .map(|(client, project_id)| {
1073 client.send(proto::RefreshInlayHints {
1074 project_id: *project_id,
1075 server_id: server_id.to_proto(),
1076 request_id: request_id.map(|id| id as u64),
1077 })
1078 })
1079 })?
1080 .transpose()?;
1081 Ok(())
1082 }
1083 }
1084 })
1085 .detach();
1086
1087 language_server
1088 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1089 let this = lsp_store.clone();
1090 move |(), cx| {
1091 let this = this.clone();
1092 let mut cx = cx.clone();
1093 async move {
1094 this.update(&mut cx, |this, cx| {
1095 cx.emit(LspStoreEvent::RefreshCodeLens);
1096 this.downstream_client.as_ref().map(|(client, project_id)| {
1097 client.send(proto::RefreshCodeLens {
1098 project_id: *project_id,
1099 })
1100 })
1101 })?
1102 .transpose()?;
1103 Ok(())
1104 }
1105 }
1106 })
1107 .detach();
1108
1109 language_server
1110 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1111 let lsp_store = lsp_store.clone();
1112 let request_id = Arc::new(AtomicUsize::new(0));
1113 move |(), cx| {
1114 let lsp_store = lsp_store.clone();
1115 let request_id = request_id.clone();
1116 let mut cx = cx.clone();
1117 async move {
1118 lsp_store
1119 .update(&mut cx, |lsp_store, cx| {
1120 let request_id =
1121 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1122 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1123 server_id,
1124 request_id,
1125 });
1126 lsp_store
1127 .downstream_client
1128 .as_ref()
1129 .map(|(client, project_id)| {
1130 client.send(proto::RefreshSemanticTokens {
1131 project_id: *project_id,
1132 server_id: server_id.to_proto(),
1133 request_id: request_id.map(|id| id as u64),
1134 })
1135 })
1136 })?
1137 .transpose()?;
1138 Ok(())
1139 }
1140 }
1141 })
1142 .detach();
1143
1144 language_server
1145 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1146 let this = lsp_store.clone();
1147 move |(), cx| {
1148 let this = this.clone();
1149 let mut cx = cx.clone();
1150 async move {
1151 this.update(&mut cx, |lsp_store, cx| {
1152 lsp_store.pull_workspace_diagnostics(server_id);
1153 lsp_store
1154 .downstream_client
1155 .as_ref()
1156 .map(|(client, project_id)| {
1157 client.send(proto::PullWorkspaceDiagnostics {
1158 project_id: *project_id,
1159 server_id: server_id.to_proto(),
1160 })
1161 })
1162 .transpose()?;
1163 anyhow::Ok(
1164 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1165 )
1166 })??
1167 .await;
1168 Ok(())
1169 }
1170 }
1171 })
1172 .detach();
1173
1174 language_server
1175 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1176 let this = lsp_store.clone();
1177 let name = name.to_string();
1178 let adapter = adapter.clone();
1179 move |params, cx| {
1180 let this = this.clone();
1181 let name = name.to_string();
1182 let adapter = adapter.clone();
1183 let mut cx = cx.clone();
1184 async move {
1185 let actions = params.actions.unwrap_or_default();
1186 let message = params.message.clone();
1187 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1188 let level = match params.typ {
1189 lsp::MessageType::ERROR => PromptLevel::Critical,
1190 lsp::MessageType::WARNING => PromptLevel::Warning,
1191 _ => PromptLevel::Info,
1192 };
1193 let request = LanguageServerPromptRequest::new(
1194 level,
1195 params.message,
1196 actions,
1197 name.clone(),
1198 tx,
1199 );
1200
1201 let did_update = this
1202 .update(&mut cx, |_, cx| {
1203 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1204 })
1205 .is_ok();
1206 if did_update {
1207 let response = rx.recv().await.ok();
1208 if let Some(ref selected_action) = response {
1209 let context = language::PromptResponseContext {
1210 message,
1211 selected_action: selected_action.clone(),
1212 };
1213 adapter.process_prompt_response(&context, &mut cx)
1214 }
1215
1216 Ok(response)
1217 } else {
1218 Ok(None)
1219 }
1220 }
1221 }
1222 })
1223 .detach();
1224 language_server
1225 .on_notification::<lsp::notification::ShowMessage, _>({
1226 let this = lsp_store.clone();
1227 let name = name.to_string();
1228 move |params, cx| {
1229 let this = this.clone();
1230 let name = name.to_string();
1231 let mut cx = cx.clone();
1232
1233 let (tx, _) = smol::channel::bounded(1);
1234 let level = match params.typ {
1235 lsp::MessageType::ERROR => PromptLevel::Critical,
1236 lsp::MessageType::WARNING => PromptLevel::Warning,
1237 _ => PromptLevel::Info,
1238 };
1239 let request =
1240 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1241
1242 let _ = this.update(&mut cx, |_, cx| {
1243 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1244 });
1245 }
1246 })
1247 .detach();
1248
1249 let disk_based_diagnostics_progress_token =
1250 adapter.disk_based_diagnostics_progress_token.clone();
1251
1252 language_server
1253 .on_notification::<lsp::notification::Progress, _>({
1254 let this = lsp_store.clone();
1255 move |params, cx| {
1256 if let Some(this) = this.upgrade() {
1257 this.update(cx, |this, cx| {
1258 this.on_lsp_progress(
1259 params,
1260 server_id,
1261 disk_based_diagnostics_progress_token.clone(),
1262 cx,
1263 );
1264 });
1265 }
1266 }
1267 })
1268 .detach();
1269
1270 language_server
1271 .on_notification::<lsp::notification::LogMessage, _>({
1272 let this = lsp_store.clone();
1273 move |params, cx| {
1274 if let Some(this) = this.upgrade() {
1275 this.update(cx, |_, cx| {
1276 cx.emit(LspStoreEvent::LanguageServerLog(
1277 server_id,
1278 LanguageServerLogType::Log(params.typ),
1279 params.message,
1280 ));
1281 });
1282 }
1283 }
1284 })
1285 .detach();
1286
1287 language_server
1288 .on_notification::<lsp::notification::LogTrace, _>({
1289 let this = lsp_store.clone();
1290 move |params, cx| {
1291 let mut cx = cx.clone();
1292 if let Some(this) = this.upgrade() {
1293 this.update(&mut cx, |_, cx| {
1294 cx.emit(LspStoreEvent::LanguageServerLog(
1295 server_id,
1296 LanguageServerLogType::Trace {
1297 verbose_info: params.verbose,
1298 },
1299 params.message,
1300 ));
1301 });
1302 }
1303 }
1304 })
1305 .detach();
1306
1307 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1309 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1310 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1311 }
1312
1313 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1314 let shutdown_futures = self
1315 .language_servers
1316 .drain()
1317 .map(|(_, server_state)| Self::shutdown_server(server_state))
1318 .collect::<Vec<_>>();
1319
1320 async move {
1321 join_all(shutdown_futures).await;
1322 }
1323 }
1324
1325 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1326 match server_state {
1327 LanguageServerState::Running { server, .. } => {
1328 if let Some(shutdown) = server.shutdown() {
1329 shutdown.await;
1330 }
1331 }
1332 LanguageServerState::Starting { startup, .. } => {
1333 if let Some(server) = startup.await
1334 && let Some(shutdown) = server.shutdown()
1335 {
1336 shutdown.await;
1337 }
1338 }
1339 }
1340 Ok(())
1341 }
1342
1343 fn language_servers_for_worktree(
1344 &self,
1345 worktree_id: WorktreeId,
1346 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1347 self.language_server_ids
1348 .iter()
1349 .filter_map(move |(seed, state)| {
1350 if seed.worktree_id != worktree_id {
1351 return None;
1352 }
1353
1354 if let Some(LanguageServerState::Running { server, .. }) =
1355 self.language_servers.get(&state.id)
1356 {
1357 Some(server)
1358 } else {
1359 None
1360 }
1361 })
1362 }
1363
1364 fn language_server_ids_for_project_path(
1365 &self,
1366 project_path: ProjectPath,
1367 language: &Language,
1368 cx: &mut App,
1369 ) -> Vec<LanguageServerId> {
1370 let Some(worktree) = self
1371 .worktree_store
1372 .read(cx)
1373 .worktree_for_id(project_path.worktree_id, cx)
1374 else {
1375 return Vec::new();
1376 };
1377 let delegate: Arc<dyn ManifestDelegate> =
1378 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1379
1380 self.lsp_tree
1381 .get(
1382 project_path,
1383 language.name(),
1384 language.manifest(),
1385 &delegate,
1386 cx,
1387 )
1388 .collect::<Vec<_>>()
1389 }
1390
1391 fn language_server_ids_for_buffer(
1392 &self,
1393 buffer: &Buffer,
1394 cx: &mut App,
1395 ) -> Vec<LanguageServerId> {
1396 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1397 let worktree_id = file.worktree_id(cx);
1398
1399 let path: Arc<RelPath> = file
1400 .path()
1401 .parent()
1402 .map(Arc::from)
1403 .unwrap_or_else(|| file.path().clone());
1404 let worktree_path = ProjectPath { worktree_id, path };
1405 self.language_server_ids_for_project_path(worktree_path, language, cx)
1406 } else {
1407 Vec::new()
1408 }
1409 }
1410
1411 fn language_servers_for_buffer<'a>(
1412 &'a self,
1413 buffer: &'a Buffer,
1414 cx: &'a mut App,
1415 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1416 self.language_server_ids_for_buffer(buffer, cx)
1417 .into_iter()
1418 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1419 LanguageServerState::Running {
1420 adapter, server, ..
1421 } => Some((adapter, server)),
1422 _ => None,
1423 })
1424 }
1425
1426 async fn execute_code_action_kind_locally(
1427 lsp_store: WeakEntity<LspStore>,
1428 mut buffers: Vec<Entity<Buffer>>,
1429 kind: CodeActionKind,
1430 push_to_history: bool,
1431 cx: &mut AsyncApp,
1432 ) -> anyhow::Result<ProjectTransaction> {
1433 // Do not allow multiple concurrent code actions requests for the
1434 // same buffer.
1435 lsp_store.update(cx, |this, cx| {
1436 let this = this.as_local_mut().unwrap();
1437 buffers.retain(|buffer| {
1438 this.buffers_being_formatted
1439 .insert(buffer.read(cx).remote_id())
1440 });
1441 })?;
1442 let _cleanup = defer({
1443 let this = lsp_store.clone();
1444 let mut cx = cx.clone();
1445 let buffers = &buffers;
1446 move || {
1447 this.update(&mut cx, |this, cx| {
1448 let this = this.as_local_mut().unwrap();
1449 for buffer in buffers {
1450 this.buffers_being_formatted
1451 .remove(&buffer.read(cx).remote_id());
1452 }
1453 })
1454 .ok();
1455 }
1456 });
1457 let mut project_transaction = ProjectTransaction::default();
1458
1459 for buffer in &buffers {
1460 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1461 buffer.update(cx, |buffer, cx| {
1462 lsp_store
1463 .as_local()
1464 .unwrap()
1465 .language_servers_for_buffer(buffer, cx)
1466 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1467 .collect::<Vec<_>>()
1468 })
1469 })?;
1470 for (_, language_server) in adapters_and_servers.iter() {
1471 let actions = Self::get_server_code_actions_from_action_kinds(
1472 &lsp_store,
1473 language_server.server_id(),
1474 vec![kind.clone()],
1475 buffer,
1476 cx,
1477 )
1478 .await?;
1479 Self::execute_code_actions_on_server(
1480 &lsp_store,
1481 language_server,
1482 actions,
1483 push_to_history,
1484 &mut project_transaction,
1485 cx,
1486 )
1487 .await?;
1488 }
1489 }
1490 Ok(project_transaction)
1491 }
1492
1493 async fn format_locally(
1494 lsp_store: WeakEntity<LspStore>,
1495 mut buffers: Vec<FormattableBuffer>,
1496 push_to_history: bool,
1497 trigger: FormatTrigger,
1498 logger: zlog::Logger,
1499 cx: &mut AsyncApp,
1500 ) -> anyhow::Result<ProjectTransaction> {
1501 // Do not allow multiple concurrent formatting requests for the
1502 // same buffer.
1503 lsp_store.update(cx, |this, cx| {
1504 let this = this.as_local_mut().unwrap();
1505 buffers.retain(|buffer| {
1506 this.buffers_being_formatted
1507 .insert(buffer.handle.read(cx).remote_id())
1508 });
1509 })?;
1510
1511 let _cleanup = defer({
1512 let this = lsp_store.clone();
1513 let mut cx = cx.clone();
1514 let buffers = &buffers;
1515 move || {
1516 this.update(&mut cx, |this, cx| {
1517 let this = this.as_local_mut().unwrap();
1518 for buffer in buffers {
1519 this.buffers_being_formatted
1520 .remove(&buffer.handle.read(cx).remote_id());
1521 }
1522 })
1523 .ok();
1524 }
1525 });
1526
1527 let mut project_transaction = ProjectTransaction::default();
1528
1529 for buffer in &buffers {
1530 zlog::debug!(
1531 logger =>
1532 "formatting buffer '{:?}'",
1533 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1534 );
1535 // Create an empty transaction to hold all of the formatting edits.
1536 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1537 // ensure no transactions created while formatting are
1538 // grouped with the previous transaction in the history
1539 // based on the transaction group interval
1540 buffer.finalize_last_transaction();
1541 buffer
1542 .start_transaction()
1543 .context("transaction already open")?;
1544 buffer.end_transaction(cx);
1545 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1546 buffer.finalize_last_transaction();
1547 anyhow::Ok(transaction_id)
1548 })?;
1549
1550 let result = Self::format_buffer_locally(
1551 lsp_store.clone(),
1552 buffer,
1553 formatting_transaction_id,
1554 trigger,
1555 logger,
1556 cx,
1557 )
1558 .await;
1559
1560 buffer.handle.update(cx, |buffer, cx| {
1561 let Some(formatting_transaction) =
1562 buffer.get_transaction(formatting_transaction_id).cloned()
1563 else {
1564 zlog::warn!(logger => "no formatting transaction");
1565 return;
1566 };
1567 if formatting_transaction.edit_ids.is_empty() {
1568 zlog::debug!(logger => "no changes made while formatting");
1569 buffer.forget_transaction(formatting_transaction_id);
1570 return;
1571 }
1572 if !push_to_history {
1573 zlog::trace!(logger => "forgetting format transaction");
1574 buffer.forget_transaction(formatting_transaction.id);
1575 }
1576 project_transaction
1577 .0
1578 .insert(cx.entity(), formatting_transaction);
1579 });
1580
1581 result?;
1582 }
1583
1584 Ok(project_transaction)
1585 }
1586
1587 async fn format_buffer_locally(
1588 lsp_store: WeakEntity<LspStore>,
1589 buffer: &FormattableBuffer,
1590 formatting_transaction_id: clock::Lamport,
1591 trigger: FormatTrigger,
1592 logger: zlog::Logger,
1593 cx: &mut AsyncApp,
1594 ) -> Result<()> {
1595 let (adapters_and_servers, settings, request_timeout) =
1596 lsp_store.update(cx, |lsp_store, cx| {
1597 buffer.handle.update(cx, |buffer, cx| {
1598 let adapters_and_servers = lsp_store
1599 .as_local()
1600 .unwrap()
1601 .language_servers_for_buffer(buffer, cx)
1602 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1603 .collect::<Vec<_>>();
1604 let settings =
1605 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1606 .into_owned();
1607 let request_timeout = ProjectSettings::get_global(cx)
1608 .global_lsp_settings
1609 .get_request_timeout();
1610 (adapters_and_servers, settings, request_timeout)
1611 })
1612 })?;
1613
1614 /// Apply edits to the buffer that will become part of the formatting transaction.
1615 /// Fails if the buffer has been edited since the start of that transaction.
1616 fn extend_formatting_transaction(
1617 buffer: &FormattableBuffer,
1618 formatting_transaction_id: text::TransactionId,
1619 cx: &mut AsyncApp,
1620 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1621 ) -> anyhow::Result<()> {
1622 buffer.handle.update(cx, |buffer, cx| {
1623 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1624 if last_transaction_id != Some(formatting_transaction_id) {
1625 anyhow::bail!("Buffer edited while formatting. Aborting")
1626 }
1627 buffer.start_transaction();
1628 operation(buffer, cx);
1629 if let Some(transaction_id) = buffer.end_transaction(cx) {
1630 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1631 }
1632 Ok(())
1633 })
1634 }
1635
1636 // handle whitespace formatting
1637 if settings.remove_trailing_whitespace_on_save {
1638 zlog::trace!(logger => "removing trailing whitespace");
1639 let diff = buffer
1640 .handle
1641 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1642 .await;
1643 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1644 buffer.apply_diff(diff, cx);
1645 })?;
1646 }
1647
1648 if settings.ensure_final_newline_on_save {
1649 zlog::trace!(logger => "ensuring final newline");
1650 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1651 buffer.ensure_final_newline(cx);
1652 })?;
1653 }
1654
1655 // Formatter for `code_actions_on_format` that runs before
1656 // the rest of the formatters
1657 let mut code_actions_on_format_formatters = None;
1658 let should_run_code_actions_on_format = !matches!(
1659 (trigger, &settings.format_on_save),
1660 (FormatTrigger::Save, &FormatOnSave::Off)
1661 );
1662 if should_run_code_actions_on_format {
1663 let have_code_actions_to_run_on_format = settings
1664 .code_actions_on_format
1665 .values()
1666 .any(|enabled| *enabled);
1667 if have_code_actions_to_run_on_format {
1668 zlog::trace!(logger => "going to run code actions on format");
1669 code_actions_on_format_formatters = Some(
1670 settings
1671 .code_actions_on_format
1672 .iter()
1673 .filter_map(|(action, enabled)| enabled.then_some(action))
1674 .cloned()
1675 .map(Formatter::CodeAction)
1676 .collect::<Vec<_>>(),
1677 );
1678 }
1679 }
1680
1681 let formatters = match (trigger, &settings.format_on_save) {
1682 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1683 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1684 settings.formatter.as_ref()
1685 }
1686 };
1687
1688 let formatters = code_actions_on_format_formatters
1689 .iter()
1690 .flatten()
1691 .chain(formatters);
1692
1693 for formatter in formatters {
1694 let formatter = if formatter == &Formatter::Auto {
1695 if settings.prettier.allowed {
1696 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1697 &Formatter::Prettier
1698 } else {
1699 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1700 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1701 }
1702 } else {
1703 formatter
1704 };
1705 match formatter {
1706 Formatter::None => {
1707 zlog::trace!(logger => "skipping formatter 'none'");
1708 continue;
1709 }
1710 Formatter::Auto => unreachable!("Auto resolved above"),
1711 Formatter::Prettier => {
1712 let logger = zlog::scoped!(logger => "prettier");
1713 zlog::trace!(logger => "formatting");
1714 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1715
1716 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1717 lsp_store.prettier_store().unwrap().downgrade()
1718 })?;
1719 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1720 .await
1721 .transpose()?;
1722 let Some(diff) = diff else {
1723 zlog::trace!(logger => "No changes");
1724 continue;
1725 };
1726
1727 extend_formatting_transaction(
1728 buffer,
1729 formatting_transaction_id,
1730 cx,
1731 |buffer, cx| {
1732 buffer.apply_diff(diff, cx);
1733 },
1734 )?;
1735 }
1736 Formatter::External { command, arguments } => {
1737 let logger = zlog::scoped!(logger => "command");
1738 zlog::trace!(logger => "formatting");
1739 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1740
1741 let diff = Self::format_via_external_command(
1742 buffer,
1743 &command,
1744 arguments.as_deref(),
1745 cx,
1746 )
1747 .await
1748 .with_context(|| {
1749 format!("Failed to format buffer via external command: {}", command)
1750 })?;
1751 let Some(diff) = diff else {
1752 zlog::trace!(logger => "No changes");
1753 continue;
1754 };
1755
1756 extend_formatting_transaction(
1757 buffer,
1758 formatting_transaction_id,
1759 cx,
1760 |buffer, cx| {
1761 buffer.apply_diff(diff, cx);
1762 },
1763 )?;
1764 }
1765 Formatter::LanguageServer(specifier) => {
1766 let logger = zlog::scoped!(logger => "language-server");
1767 zlog::trace!(logger => "formatting");
1768 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1769
1770 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1771 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1772 continue;
1773 };
1774
1775 let language_server = match specifier {
1776 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1777 adapters_and_servers.iter().find_map(|(adapter, server)| {
1778 if adapter.name.0.as_ref() == name {
1779 Some(server.clone())
1780 } else {
1781 None
1782 }
1783 })
1784 }
1785 settings::LanguageServerFormatterSpecifier::Current => adapters_and_servers
1786 .iter()
1787 .find(|(_, server)| Self::server_supports_formatting(server))
1788 .map(|(_, server)| server.clone()),
1789 };
1790
1791 let Some(language_server) = language_server else {
1792 log::debug!(
1793 "No language server found to format buffer '{:?}'. Skipping",
1794 buffer_path_abs.as_path().to_string_lossy()
1795 );
1796 continue;
1797 };
1798
1799 zlog::trace!(
1800 logger =>
1801 "Formatting buffer '{:?}' using language server '{:?}'",
1802 buffer_path_abs.as_path().to_string_lossy(),
1803 language_server.name()
1804 );
1805
1806 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1807 zlog::trace!(logger => "formatting ranges");
1808 Self::format_ranges_via_lsp(
1809 &lsp_store,
1810 &buffer.handle,
1811 ranges,
1812 buffer_path_abs,
1813 &language_server,
1814 &settings,
1815 cx,
1816 )
1817 .await
1818 .context("Failed to format ranges via language server")?
1819 } else {
1820 zlog::trace!(logger => "formatting full");
1821 Self::format_via_lsp(
1822 &lsp_store,
1823 &buffer.handle,
1824 buffer_path_abs,
1825 &language_server,
1826 &settings,
1827 cx,
1828 )
1829 .await
1830 .context("failed to format via language server")?
1831 };
1832
1833 if edits.is_empty() {
1834 zlog::trace!(logger => "No changes");
1835 continue;
1836 }
1837 extend_formatting_transaction(
1838 buffer,
1839 formatting_transaction_id,
1840 cx,
1841 |buffer, cx| {
1842 buffer.edit(edits, None, cx);
1843 },
1844 )?;
1845 }
1846 Formatter::CodeAction(code_action_name) => {
1847 let logger = zlog::scoped!(logger => "code-actions");
1848 zlog::trace!(logger => "formatting");
1849 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1850
1851 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1852 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1853 continue;
1854 };
1855
1856 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1857 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1858
1859 let mut actions_and_servers = Vec::new();
1860
1861 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1862 let actions_result = Self::get_server_code_actions_from_action_kinds(
1863 &lsp_store,
1864 language_server.server_id(),
1865 vec![code_action_kind.clone()],
1866 &buffer.handle,
1867 cx,
1868 )
1869 .await
1870 .with_context(|| {
1871 format!(
1872 "Failed to resolve code action {:?} with language server {}",
1873 code_action_kind,
1874 language_server.name()
1875 )
1876 });
1877 let Ok(actions) = actions_result else {
1878 // note: it may be better to set result to the error and break formatters here
1879 // but for now we try to execute the actions that we can resolve and skip the rest
1880 zlog::error!(
1881 logger =>
1882 "Failed to resolve code action {:?} with language server {}",
1883 code_action_kind,
1884 language_server.name()
1885 );
1886 continue;
1887 };
1888 for action in actions {
1889 actions_and_servers.push((action, index));
1890 }
1891 }
1892
1893 if actions_and_servers.is_empty() {
1894 zlog::warn!(logger => "No code actions were resolved, continuing");
1895 continue;
1896 }
1897
1898 'actions: for (mut action, server_index) in actions_and_servers {
1899 let server = &adapters_and_servers[server_index].1;
1900
1901 let describe_code_action = |action: &CodeAction| {
1902 format!(
1903 "code action '{}' with title \"{}\" on server {}",
1904 action
1905 .lsp_action
1906 .action_kind()
1907 .unwrap_or("unknown".into())
1908 .as_str(),
1909 action.lsp_action.title(),
1910 server.name(),
1911 )
1912 };
1913
1914 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1915
1916 if let Err(err) =
1917 Self::try_resolve_code_action(server, &mut action, request_timeout)
1918 .await
1919 {
1920 zlog::error!(
1921 logger =>
1922 "Failed to resolve {}. Error: {}",
1923 describe_code_action(&action),
1924 err
1925 );
1926 continue;
1927 }
1928
1929 if let Some(edit) = action.lsp_action.edit().cloned() {
1930 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1931 // but filters out and logs warnings for code actions that require unreasonably
1932 // difficult handling on our part, such as:
1933 // - applying edits that call commands
1934 // which can result in arbitrary workspace edits being sent from the server that
1935 // have no way of being tied back to the command that initiated them (i.e. we
1936 // can't know which edits are part of the format request, or if the server is done sending
1937 // actions in response to the command)
1938 // - actions that create/delete/modify/rename files other than the one we are formatting
1939 // as we then would need to handle such changes correctly in the local history as well
1940 // as the remote history through the ProjectTransaction
1941 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1942 // Supporting these actions is not impossible, but not supported as of yet.
1943 if edit.changes.is_none() && edit.document_changes.is_none() {
1944 zlog::trace!(
1945 logger =>
1946 "No changes for code action. Skipping {}",
1947 describe_code_action(&action),
1948 );
1949 continue;
1950 }
1951
1952 let mut operations = Vec::new();
1953 if let Some(document_changes) = edit.document_changes {
1954 match document_changes {
1955 lsp::DocumentChanges::Edits(edits) => operations.extend(
1956 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1957 ),
1958 lsp::DocumentChanges::Operations(ops) => operations = ops,
1959 }
1960 } else if let Some(changes) = edit.changes {
1961 operations.extend(changes.into_iter().map(|(uri, edits)| {
1962 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1963 text_document:
1964 lsp::OptionalVersionedTextDocumentIdentifier {
1965 uri,
1966 version: None,
1967 },
1968 edits: edits.into_iter().map(Edit::Plain).collect(),
1969 })
1970 }));
1971 }
1972
1973 let mut edits = Vec::with_capacity(operations.len());
1974
1975 if operations.is_empty() {
1976 zlog::trace!(
1977 logger =>
1978 "No changes for code action. Skipping {}",
1979 describe_code_action(&action),
1980 );
1981 continue;
1982 }
1983 for operation in operations {
1984 let op = match operation {
1985 lsp::DocumentChangeOperation::Edit(op) => op,
1986 lsp::DocumentChangeOperation::Op(_) => {
1987 zlog::warn!(
1988 logger =>
1989 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1990 describe_code_action(&action),
1991 );
1992 continue 'actions;
1993 }
1994 };
1995 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1996 zlog::warn!(
1997 logger =>
1998 "Failed to convert URI '{:?}' to file path. Skipping {}",
1999 &op.text_document.uri,
2000 describe_code_action(&action),
2001 );
2002 continue 'actions;
2003 };
2004 if &file_path != buffer_path_abs {
2005 zlog::warn!(
2006 logger =>
2007 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2008 file_path,
2009 buffer_path_abs,
2010 describe_code_action(&action),
2011 );
2012 continue 'actions;
2013 }
2014
2015 let mut lsp_edits = Vec::new();
2016 for edit in op.edits {
2017 match edit {
2018 Edit::Plain(edit) => {
2019 if !lsp_edits.contains(&edit) {
2020 lsp_edits.push(edit);
2021 }
2022 }
2023 Edit::Annotated(edit) => {
2024 if !lsp_edits.contains(&edit.text_edit) {
2025 lsp_edits.push(edit.text_edit);
2026 }
2027 }
2028 Edit::Snippet(_) => {
2029 zlog::warn!(
2030 logger =>
2031 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2032 describe_code_action(&action),
2033 );
2034 continue 'actions;
2035 }
2036 }
2037 }
2038 let edits_result = lsp_store
2039 .update(cx, |lsp_store, cx| {
2040 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2041 &buffer.handle,
2042 lsp_edits,
2043 server.server_id(),
2044 op.text_document.version,
2045 cx,
2046 )
2047 })?
2048 .await;
2049 let Ok(resolved_edits) = edits_result else {
2050 zlog::warn!(
2051 logger =>
2052 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2053 buffer_path_abs.as_path(),
2054 describe_code_action(&action),
2055 );
2056 continue 'actions;
2057 };
2058 edits.extend(resolved_edits);
2059 }
2060
2061 if edits.is_empty() {
2062 zlog::warn!(logger => "No edits resolved from LSP");
2063 continue;
2064 }
2065
2066 extend_formatting_transaction(
2067 buffer,
2068 formatting_transaction_id,
2069 cx,
2070 |buffer, cx| {
2071 zlog::info!(
2072 "Applying edits {edits:?}. Content: {:?}",
2073 buffer.text()
2074 );
2075 buffer.edit(edits, None, cx);
2076 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2077 },
2078 )?;
2079 }
2080
2081 // bail early if command is invalid
2082 let Some(command) = action.lsp_action.command() else {
2083 continue;
2084 };
2085
2086 zlog::warn!(
2087 logger =>
2088 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2089 &command.command,
2090 );
2091
2092 let server_capabilities = server.capabilities();
2093 let available_commands = server_capabilities
2094 .execute_command_provider
2095 .as_ref()
2096 .map(|options| options.commands.as_slice())
2097 .unwrap_or_default();
2098 if !available_commands.contains(&command.command) {
2099 zlog::warn!(
2100 logger =>
2101 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2102 command.command,
2103 server.name(),
2104 );
2105 continue;
2106 }
2107
2108 // noop so we just ensure buffer hasn't been edited since resolving code actions
2109 extend_formatting_transaction(
2110 buffer,
2111 formatting_transaction_id,
2112 cx,
2113 |_, _| {},
2114 )?;
2115 zlog::info!(logger => "Executing command {}", &command.command);
2116
2117 lsp_store.update(cx, |this, _| {
2118 this.as_local_mut()
2119 .unwrap()
2120 .last_workspace_edits_by_language_server
2121 .remove(&server.server_id());
2122 })?;
2123
2124 let execute_command_result = server
2125 .request::<lsp::request::ExecuteCommand>(
2126 lsp::ExecuteCommandParams {
2127 command: command.command.clone(),
2128 arguments: command.arguments.clone().unwrap_or_default(),
2129 ..Default::default()
2130 },
2131 request_timeout,
2132 )
2133 .await
2134 .into_response();
2135
2136 if execute_command_result.is_err() {
2137 zlog::error!(
2138 logger =>
2139 "Failed to execute command '{}' as part of {}",
2140 &command.command,
2141 describe_code_action(&action),
2142 );
2143 continue 'actions;
2144 }
2145
2146 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2147 this.as_local_mut()
2148 .unwrap()
2149 .last_workspace_edits_by_language_server
2150 .remove(&server.server_id())
2151 .unwrap_or_default()
2152 })?;
2153
2154 if let Some(transaction) =
2155 project_transaction_command.0.remove(&buffer.handle)
2156 {
2157 zlog::trace!(
2158 logger =>
2159 "Successfully captured {} edits that resulted from command {}",
2160 transaction.edit_ids.len(),
2161 &command.command,
2162 );
2163 let transaction_id_project_transaction = transaction.id;
2164 buffer.handle.update(cx, |buffer, _| {
2165 // it may have been removed from history if push_to_history was
2166 // false in deserialize_workspace_edit. If so push it so we
2167 // can merge it with the format transaction
2168 // and pop the combined transaction off the history stack
2169 // later if push_to_history is false
2170 if buffer.get_transaction(transaction.id).is_none() {
2171 buffer.push_transaction(transaction, Instant::now());
2172 }
2173 buffer.merge_transactions(
2174 transaction_id_project_transaction,
2175 formatting_transaction_id,
2176 );
2177 });
2178 }
2179
2180 if project_transaction_command.0.is_empty() {
2181 continue;
2182 }
2183
2184 let mut extra_buffers = String::new();
2185 for buffer in project_transaction_command.0.keys() {
2186 buffer.read_with(cx, |b, cx| {
2187 let Some(path) = b.project_path(cx) else {
2188 return;
2189 };
2190
2191 if !extra_buffers.is_empty() {
2192 extra_buffers.push_str(", ");
2193 }
2194 extra_buffers.push_str(path.path.as_unix_str());
2195 });
2196 }
2197 zlog::warn!(
2198 logger =>
2199 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2200 &command.command,
2201 extra_buffers,
2202 );
2203 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2204 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2205 // add it so it's included, and merge it into the format transaction when its created later
2206 }
2207 }
2208 }
2209 }
2210
2211 Ok(())
2212 }
2213
2214 pub async fn format_ranges_via_lsp(
2215 this: &WeakEntity<LspStore>,
2216 buffer_handle: &Entity<Buffer>,
2217 ranges: &[Range<Anchor>],
2218 abs_path: &Path,
2219 language_server: &Arc<LanguageServer>,
2220 settings: &LanguageSettings,
2221 cx: &mut AsyncApp,
2222 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2223 let capabilities = &language_server.capabilities();
2224 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2225 if range_formatting_provider == Some(&OneOf::Left(false)) {
2226 anyhow::bail!(
2227 "{} language server does not support range formatting",
2228 language_server.name()
2229 );
2230 }
2231
2232 let uri = file_path_to_lsp_url(abs_path)?;
2233 let text_document = lsp::TextDocumentIdentifier::new(uri);
2234
2235 let request_timeout = cx.update(|app| {
2236 ProjectSettings::get_global(app)
2237 .global_lsp_settings
2238 .get_request_timeout()
2239 });
2240 let lsp_edits = {
2241 let mut lsp_ranges = Vec::new();
2242 this.update(cx, |_this, cx| {
2243 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2244 // not have been sent to the language server. This seems like a fairly systemic
2245 // issue, though, the resolution probably is not specific to formatting.
2246 //
2247 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2248 // LSP.
2249 let snapshot = buffer_handle.read(cx).snapshot();
2250 for range in ranges {
2251 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2252 }
2253 anyhow::Ok(())
2254 })??;
2255
2256 let mut edits = None;
2257 for range in lsp_ranges {
2258 if let Some(mut edit) = language_server
2259 .request::<lsp::request::RangeFormatting>(
2260 lsp::DocumentRangeFormattingParams {
2261 text_document: text_document.clone(),
2262 range,
2263 options: lsp_command::lsp_formatting_options(settings),
2264 work_done_progress_params: Default::default(),
2265 },
2266 request_timeout,
2267 )
2268 .await
2269 .into_response()?
2270 {
2271 edits.get_or_insert_with(Vec::new).append(&mut edit);
2272 }
2273 }
2274 edits
2275 };
2276
2277 if let Some(lsp_edits) = lsp_edits {
2278 this.update(cx, |this, cx| {
2279 this.as_local_mut().unwrap().edits_from_lsp(
2280 buffer_handle,
2281 lsp_edits,
2282 language_server.server_id(),
2283 None,
2284 cx,
2285 )
2286 })?
2287 .await
2288 } else {
2289 Ok(Vec::with_capacity(0))
2290 }
2291 }
2292
2293 fn server_supports_formatting(server: &Arc<LanguageServer>) -> bool {
2294 let capabilities = server.capabilities();
2295 let formatting = capabilities.document_formatting_provider.as_ref();
2296 let range_formatting = capabilities.document_range_formatting_provider.as_ref();
2297 matches!(formatting, Some(p) if *p != OneOf::Left(false))
2298 || matches!(range_formatting, Some(p) if *p != OneOf::Left(false))
2299 }
2300
2301 async fn format_via_lsp(
2302 this: &WeakEntity<LspStore>,
2303 buffer: &Entity<Buffer>,
2304 abs_path: &Path,
2305 language_server: &Arc<LanguageServer>,
2306 settings: &LanguageSettings,
2307 cx: &mut AsyncApp,
2308 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2309 let logger = zlog::scoped!("lsp_format");
2310 zlog::debug!(logger => "Formatting via LSP");
2311
2312 let uri = file_path_to_lsp_url(abs_path)?;
2313 let text_document = lsp::TextDocumentIdentifier::new(uri);
2314 let capabilities = &language_server.capabilities();
2315
2316 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2317 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2318
2319 let request_timeout = cx.update(|app| {
2320 ProjectSettings::get_global(app)
2321 .global_lsp_settings
2322 .get_request_timeout()
2323 });
2324
2325 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2326 let _timer = zlog::time!(logger => "format-full");
2327 language_server
2328 .request::<lsp::request::Formatting>(
2329 lsp::DocumentFormattingParams {
2330 text_document,
2331 options: lsp_command::lsp_formatting_options(settings),
2332 work_done_progress_params: Default::default(),
2333 },
2334 request_timeout,
2335 )
2336 .await
2337 .into_response()?
2338 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2339 let _timer = zlog::time!(logger => "format-range");
2340 let buffer_start = lsp::Position::new(0, 0);
2341 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2342 language_server
2343 .request::<lsp::request::RangeFormatting>(
2344 lsp::DocumentRangeFormattingParams {
2345 text_document: text_document.clone(),
2346 range: lsp::Range::new(buffer_start, buffer_end),
2347 options: lsp_command::lsp_formatting_options(settings),
2348 work_done_progress_params: Default::default(),
2349 },
2350 request_timeout,
2351 )
2352 .await
2353 .into_response()?
2354 } else {
2355 None
2356 };
2357
2358 if let Some(lsp_edits) = lsp_edits {
2359 this.update(cx, |this, cx| {
2360 this.as_local_mut().unwrap().edits_from_lsp(
2361 buffer,
2362 lsp_edits,
2363 language_server.server_id(),
2364 None,
2365 cx,
2366 )
2367 })?
2368 .await
2369 } else {
2370 Ok(Vec::with_capacity(0))
2371 }
2372 }
2373
2374 async fn format_via_external_command(
2375 buffer: &FormattableBuffer,
2376 command: &str,
2377 arguments: Option<&[String]>,
2378 cx: &mut AsyncApp,
2379 ) -> Result<Option<Diff>> {
2380 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2381 let file = File::from_dyn(buffer.file())?;
2382 let worktree = file.worktree.read(cx);
2383 let mut worktree_path = worktree.abs_path().to_path_buf();
2384 if worktree.root_entry()?.is_file() {
2385 worktree_path.pop();
2386 }
2387 Some(worktree_path)
2388 });
2389
2390 use util::command::Stdio;
2391 let mut child = util::command::new_command(command);
2392
2393 if let Some(buffer_env) = buffer.env.as_ref() {
2394 child.envs(buffer_env);
2395 }
2396
2397 if let Some(working_dir_path) = working_dir_path {
2398 child.current_dir(working_dir_path);
2399 }
2400
2401 if let Some(arguments) = arguments {
2402 child.args(arguments.iter().map(|arg| {
2403 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2404 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2405 } else {
2406 arg.replace("{buffer_path}", "Untitled")
2407 }
2408 }));
2409 }
2410
2411 let mut child = child
2412 .stdin(Stdio::piped())
2413 .stdout(Stdio::piped())
2414 .stderr(Stdio::piped())
2415 .spawn()?;
2416
2417 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2418 let text = buffer
2419 .handle
2420 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2421 for chunk in text.chunks() {
2422 stdin.write_all(chunk.as_bytes()).await?;
2423 }
2424 stdin.flush().await?;
2425
2426 let output = child.output().await?;
2427 anyhow::ensure!(
2428 output.status.success(),
2429 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2430 output.status.code(),
2431 String::from_utf8_lossy(&output.stdout),
2432 String::from_utf8_lossy(&output.stderr),
2433 );
2434
2435 let stdout = String::from_utf8(output.stdout)?;
2436 Ok(Some(
2437 buffer
2438 .handle
2439 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2440 .await,
2441 ))
2442 }
2443
2444 async fn try_resolve_code_action(
2445 lang_server: &LanguageServer,
2446 action: &mut CodeAction,
2447 request_timeout: Duration,
2448 ) -> anyhow::Result<()> {
2449 match &mut action.lsp_action {
2450 LspAction::Action(lsp_action) => {
2451 if !action.resolved
2452 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2453 && lsp_action.data.is_some()
2454 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2455 {
2456 **lsp_action = lang_server
2457 .request::<lsp::request::CodeActionResolveRequest>(
2458 *lsp_action.clone(),
2459 request_timeout,
2460 )
2461 .await
2462 .into_response()?;
2463 }
2464 }
2465 LspAction::CodeLens(lens) => {
2466 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2467 *lens = lang_server
2468 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2469 .await
2470 .into_response()?;
2471 }
2472 }
2473 LspAction::Command(_) => {}
2474 }
2475
2476 action.resolved = true;
2477 anyhow::Ok(())
2478 }
2479
2480 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2481 let buffer = buffer_handle.read(cx);
2482
2483 let file = buffer.file().cloned();
2484
2485 let Some(file) = File::from_dyn(file.as_ref()) else {
2486 return;
2487 };
2488 if !file.is_local() {
2489 return;
2490 }
2491 let path = ProjectPath::from_file(file, cx);
2492 let worktree_id = file.worktree_id(cx);
2493 let language = buffer.language().cloned();
2494
2495 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2496 for (server_id, diagnostics) in
2497 diagnostics.get(file.path()).cloned().unwrap_or_default()
2498 {
2499 self.update_buffer_diagnostics(
2500 buffer_handle,
2501 server_id,
2502 None,
2503 None,
2504 None,
2505 Vec::new(),
2506 diagnostics,
2507 cx,
2508 )
2509 .log_err();
2510 }
2511 }
2512 let Some(language) = language else {
2513 return;
2514 };
2515 let Some(snapshot) = self
2516 .worktree_store
2517 .read(cx)
2518 .worktree_for_id(worktree_id, cx)
2519 .map(|worktree| worktree.read(cx).snapshot())
2520 else {
2521 return;
2522 };
2523 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2524
2525 for server_id in
2526 self.lsp_tree
2527 .get(path, language.name(), language.manifest(), &delegate, cx)
2528 {
2529 let server = self
2530 .language_servers
2531 .get(&server_id)
2532 .and_then(|server_state| {
2533 if let LanguageServerState::Running { server, .. } = server_state {
2534 Some(server.clone())
2535 } else {
2536 None
2537 }
2538 });
2539 let server = match server {
2540 Some(server) => server,
2541 None => continue,
2542 };
2543
2544 buffer_handle.update(cx, |buffer, cx| {
2545 buffer.set_completion_triggers(
2546 server.server_id(),
2547 server
2548 .capabilities()
2549 .completion_provider
2550 .as_ref()
2551 .and_then(|provider| {
2552 provider
2553 .trigger_characters
2554 .as_ref()
2555 .map(|characters| characters.iter().cloned().collect())
2556 })
2557 .unwrap_or_default(),
2558 cx,
2559 );
2560 });
2561 }
2562 }
2563
2564 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2565 buffer.update(cx, |buffer, cx| {
2566 let Some(language) = buffer.language() else {
2567 return;
2568 };
2569 let path = ProjectPath {
2570 worktree_id: old_file.worktree_id(cx),
2571 path: old_file.path.clone(),
2572 };
2573 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2574 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2575 buffer.set_completion_triggers(server_id, Default::default(), cx);
2576 }
2577 });
2578 }
2579
2580 fn update_buffer_diagnostics(
2581 &mut self,
2582 buffer: &Entity<Buffer>,
2583 server_id: LanguageServerId,
2584 registration_id: Option<Option<SharedString>>,
2585 result_id: Option<SharedString>,
2586 version: Option<i32>,
2587 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2588 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2589 cx: &mut Context<LspStore>,
2590 ) -> Result<()> {
2591 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2592 Ordering::Equal
2593 .then_with(|| b.is_primary.cmp(&a.is_primary))
2594 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2595 .then_with(|| a.severity.cmp(&b.severity))
2596 .then_with(|| a.message.cmp(&b.message))
2597 }
2598
2599 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2600 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2601 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2602
2603 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2604 Ordering::Equal
2605 .then_with(|| a.range.start.cmp(&b.range.start))
2606 .then_with(|| b.range.end.cmp(&a.range.end))
2607 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2608 });
2609
2610 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2611
2612 let edits_since_save = std::cell::LazyCell::new(|| {
2613 let saved_version = buffer.read(cx).saved_version();
2614 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2615 });
2616
2617 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2618
2619 for (new_diagnostic, entry) in diagnostics {
2620 let start;
2621 let end;
2622 if new_diagnostic && entry.diagnostic.is_disk_based {
2623 // Some diagnostics are based on files on disk instead of buffers'
2624 // current contents. Adjust these diagnostics' ranges to reflect
2625 // any unsaved edits.
2626 // Do not alter the reused ones though, as their coordinates were stored as anchors
2627 // and were properly adjusted on reuse.
2628 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2629 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2630 } else {
2631 start = entry.range.start;
2632 end = entry.range.end;
2633 }
2634
2635 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2636 ..snapshot.clip_point_utf16(end, Bias::Right);
2637
2638 // Expand empty ranges by one codepoint
2639 if range.start == range.end {
2640 // This will be go to the next boundary when being clipped
2641 range.end.column += 1;
2642 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2643 if range.start == range.end && range.end.column > 0 {
2644 range.start.column -= 1;
2645 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2646 }
2647 }
2648
2649 sanitized_diagnostics.push(DiagnosticEntry {
2650 range,
2651 diagnostic: entry.diagnostic,
2652 });
2653 }
2654 drop(edits_since_save);
2655
2656 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2657 buffer.update(cx, |buffer, cx| {
2658 if let Some(registration_id) = registration_id {
2659 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2660 self.buffer_pull_diagnostics_result_ids
2661 .entry(server_id)
2662 .or_default()
2663 .entry(registration_id)
2664 .or_default()
2665 .insert(abs_path, result_id);
2666 }
2667 }
2668
2669 buffer.update_diagnostics(server_id, set, cx)
2670 });
2671
2672 Ok(())
2673 }
2674
2675 fn register_language_server_for_invisible_worktree(
2676 &mut self,
2677 worktree: &Entity<Worktree>,
2678 language_server_id: LanguageServerId,
2679 cx: &mut App,
2680 ) {
2681 let worktree = worktree.read(cx);
2682 let worktree_id = worktree.id();
2683 debug_assert!(!worktree.is_visible());
2684 let Some(mut origin_seed) = self
2685 .language_server_ids
2686 .iter()
2687 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2688 else {
2689 return;
2690 };
2691 origin_seed.worktree_id = worktree_id;
2692 self.language_server_ids
2693 .entry(origin_seed)
2694 .or_insert_with(|| UnifiedLanguageServer {
2695 id: language_server_id,
2696 project_roots: Default::default(),
2697 });
2698 }
2699
2700 fn register_buffer_with_language_servers(
2701 &mut self,
2702 buffer_handle: &Entity<Buffer>,
2703 only_register_servers: HashSet<LanguageServerSelector>,
2704 cx: &mut Context<LspStore>,
2705 ) {
2706 let buffer = buffer_handle.read(cx);
2707 let buffer_id = buffer.remote_id();
2708
2709 let Some(file) = File::from_dyn(buffer.file()) else {
2710 return;
2711 };
2712 if !file.is_local() {
2713 return;
2714 }
2715
2716 let abs_path = file.abs_path(cx);
2717 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2718 return;
2719 };
2720 let initial_snapshot = buffer.text_snapshot();
2721 let worktree_id = file.worktree_id(cx);
2722
2723 let Some(language) = buffer.language().cloned() else {
2724 return;
2725 };
2726 let path: Arc<RelPath> = file
2727 .path()
2728 .parent()
2729 .map(Arc::from)
2730 .unwrap_or_else(|| file.path().clone());
2731 let Some(worktree) = self
2732 .worktree_store
2733 .read(cx)
2734 .worktree_for_id(worktree_id, cx)
2735 else {
2736 return;
2737 };
2738 let language_name = language.name();
2739 let (reused, delegate, servers) = self
2740 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2741 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2742 .unwrap_or_else(|| {
2743 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2744 let delegate: Arc<dyn ManifestDelegate> =
2745 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2746
2747 let servers = self
2748 .lsp_tree
2749 .walk(
2750 ProjectPath { worktree_id, path },
2751 language.name(),
2752 language.manifest(),
2753 &delegate,
2754 cx,
2755 )
2756 .collect::<Vec<_>>();
2757 (false, lsp_delegate, servers)
2758 });
2759 let servers_and_adapters = servers
2760 .into_iter()
2761 .filter_map(|server_node| {
2762 if reused && server_node.server_id().is_none() {
2763 return None;
2764 }
2765 if !only_register_servers.is_empty() {
2766 if let Some(server_id) = server_node.server_id()
2767 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2768 {
2769 return None;
2770 }
2771 if let Some(name) = server_node.name()
2772 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2773 {
2774 return None;
2775 }
2776 }
2777
2778 let server_id = server_node.server_id_or_init(|disposition| {
2779 let path = &disposition.path;
2780
2781 {
2782 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2783
2784 let server_id = self.get_or_insert_language_server(
2785 &worktree,
2786 delegate.clone(),
2787 disposition,
2788 &language_name,
2789 cx,
2790 );
2791
2792 if let Some(state) = self.language_servers.get(&server_id)
2793 && let Ok(uri) = uri
2794 {
2795 state.add_workspace_folder(uri);
2796 };
2797 server_id
2798 }
2799 })?;
2800 let server_state = self.language_servers.get(&server_id)?;
2801 if let LanguageServerState::Running {
2802 server, adapter, ..
2803 } = server_state
2804 {
2805 Some((server.clone(), adapter.clone()))
2806 } else {
2807 None
2808 }
2809 })
2810 .collect::<Vec<_>>();
2811 for (server, adapter) in servers_and_adapters {
2812 buffer_handle.update(cx, |buffer, cx| {
2813 buffer.set_completion_triggers(
2814 server.server_id(),
2815 server
2816 .capabilities()
2817 .completion_provider
2818 .as_ref()
2819 .and_then(|provider| {
2820 provider
2821 .trigger_characters
2822 .as_ref()
2823 .map(|characters| characters.iter().cloned().collect())
2824 })
2825 .unwrap_or_default(),
2826 cx,
2827 );
2828 });
2829
2830 let snapshot = LspBufferSnapshot {
2831 version: 0,
2832 snapshot: initial_snapshot.clone(),
2833 };
2834
2835 let mut registered = false;
2836 self.buffer_snapshots
2837 .entry(buffer_id)
2838 .or_default()
2839 .entry(server.server_id())
2840 .or_insert_with(|| {
2841 registered = true;
2842 server.register_buffer(
2843 uri.clone(),
2844 adapter.language_id(&language.name()),
2845 0,
2846 initial_snapshot.text(),
2847 );
2848
2849 vec![snapshot]
2850 });
2851
2852 self.buffers_opened_in_servers
2853 .entry(buffer_id)
2854 .or_default()
2855 .insert(server.server_id());
2856 if registered {
2857 cx.emit(LspStoreEvent::LanguageServerUpdate {
2858 language_server_id: server.server_id(),
2859 name: None,
2860 message: proto::update_language_server::Variant::RegisteredForBuffer(
2861 proto::RegisteredForBuffer {
2862 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2863 buffer_id: buffer_id.to_proto(),
2864 },
2865 ),
2866 });
2867 }
2868 }
2869 }
2870
2871 fn reuse_existing_language_server<'lang_name>(
2872 &self,
2873 server_tree: &LanguageServerTree,
2874 worktree: &Entity<Worktree>,
2875 language_name: &'lang_name LanguageName,
2876 cx: &mut App,
2877 ) -> Option<(
2878 Arc<LocalLspAdapterDelegate>,
2879 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2880 )> {
2881 if worktree.read(cx).is_visible() {
2882 return None;
2883 }
2884
2885 let worktree_store = self.worktree_store.read(cx);
2886 let servers = server_tree
2887 .instances
2888 .iter()
2889 .filter(|(worktree_id, _)| {
2890 worktree_store
2891 .worktree_for_id(**worktree_id, cx)
2892 .is_some_and(|worktree| worktree.read(cx).is_visible())
2893 })
2894 .flat_map(|(worktree_id, servers)| {
2895 servers
2896 .roots
2897 .iter()
2898 .flat_map(|(_, language_servers)| language_servers)
2899 .map(move |(_, (server_node, server_languages))| {
2900 (worktree_id, server_node, server_languages)
2901 })
2902 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2903 .map(|(worktree_id, server_node, _)| {
2904 (
2905 *worktree_id,
2906 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2907 )
2908 })
2909 })
2910 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2911 acc.entry(worktree_id)
2912 .or_insert_with(Vec::new)
2913 .push(server_node);
2914 acc
2915 })
2916 .into_values()
2917 .max_by_key(|servers| servers.len())?;
2918
2919 let worktree_id = worktree.read(cx).id();
2920 let apply = move |tree: &mut LanguageServerTree| {
2921 for server_node in &servers {
2922 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2923 }
2924 servers
2925 };
2926
2927 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2928 Some((delegate, apply))
2929 }
2930
2931 pub(crate) fn unregister_old_buffer_from_language_servers(
2932 &mut self,
2933 buffer: &Entity<Buffer>,
2934 old_file: &File,
2935 cx: &mut App,
2936 ) {
2937 let old_path = match old_file.as_local() {
2938 Some(local) => local.abs_path(cx),
2939 None => return,
2940 };
2941
2942 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2943 debug_panic!("{old_path:?} is not parseable as an URI");
2944 return;
2945 };
2946 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2947 }
2948
2949 pub(crate) fn unregister_buffer_from_language_servers(
2950 &mut self,
2951 buffer: &Entity<Buffer>,
2952 file_url: &lsp::Uri,
2953 cx: &mut App,
2954 ) {
2955 buffer.update(cx, |buffer, cx| {
2956 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2957
2958 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2959 if snapshots
2960 .as_mut()
2961 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2962 {
2963 language_server.unregister_buffer(file_url.clone());
2964 }
2965 }
2966 });
2967 }
2968
2969 fn buffer_snapshot_for_lsp_version(
2970 &mut self,
2971 buffer: &Entity<Buffer>,
2972 server_id: LanguageServerId,
2973 version: Option<i32>,
2974 cx: &App,
2975 ) -> Result<TextBufferSnapshot> {
2976 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2977
2978 if let Some(version) = version {
2979 let buffer_id = buffer.read(cx).remote_id();
2980 let snapshots = if let Some(snapshots) = self
2981 .buffer_snapshots
2982 .get_mut(&buffer_id)
2983 .and_then(|m| m.get_mut(&server_id))
2984 {
2985 snapshots
2986 } else if version == 0 {
2987 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2988 // We detect this case and treat it as if the version was `None`.
2989 return Ok(buffer.read(cx).text_snapshot());
2990 } else {
2991 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2992 };
2993
2994 let found_snapshot = snapshots
2995 .binary_search_by_key(&version, |e| e.version)
2996 .map(|ix| snapshots[ix].snapshot.clone())
2997 .map_err(|_| {
2998 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2999 })?;
3000
3001 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
3002 Ok(found_snapshot)
3003 } else {
3004 Ok((buffer.read(cx)).text_snapshot())
3005 }
3006 }
3007
3008 async fn get_server_code_actions_from_action_kinds(
3009 lsp_store: &WeakEntity<LspStore>,
3010 language_server_id: LanguageServerId,
3011 code_action_kinds: Vec<lsp::CodeActionKind>,
3012 buffer: &Entity<Buffer>,
3013 cx: &mut AsyncApp,
3014 ) -> Result<Vec<CodeAction>> {
3015 let actions = lsp_store
3016 .update(cx, move |this, cx| {
3017 let request = GetCodeActions {
3018 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3019 kinds: Some(code_action_kinds),
3020 };
3021 let server = LanguageServerToQuery::Other(language_server_id);
3022 this.request_lsp(buffer.clone(), server, request, cx)
3023 })?
3024 .await?;
3025 Ok(actions)
3026 }
3027
3028 pub async fn execute_code_actions_on_server(
3029 lsp_store: &WeakEntity<LspStore>,
3030 language_server: &Arc<LanguageServer>,
3031 actions: Vec<CodeAction>,
3032 push_to_history: bool,
3033 project_transaction: &mut ProjectTransaction,
3034 cx: &mut AsyncApp,
3035 ) -> anyhow::Result<()> {
3036 let request_timeout = cx.update(|app| {
3037 ProjectSettings::get_global(app)
3038 .global_lsp_settings
3039 .get_request_timeout()
3040 });
3041
3042 for mut action in actions {
3043 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3044 .await
3045 .context("resolving a formatting code action")?;
3046
3047 if let Some(edit) = action.lsp_action.edit() {
3048 if edit.changes.is_none() && edit.document_changes.is_none() {
3049 continue;
3050 }
3051
3052 let new = Self::deserialize_workspace_edit(
3053 lsp_store.upgrade().context("project dropped")?,
3054 edit.clone(),
3055 push_to_history,
3056 language_server.clone(),
3057 cx,
3058 )
3059 .await?;
3060 project_transaction.0.extend(new.0);
3061 }
3062
3063 let Some(command) = action.lsp_action.command() else {
3064 continue;
3065 };
3066
3067 let server_capabilities = language_server.capabilities();
3068 let available_commands = server_capabilities
3069 .execute_command_provider
3070 .as_ref()
3071 .map(|options| options.commands.as_slice())
3072 .unwrap_or_default();
3073 if !available_commands.contains(&command.command) {
3074 log::warn!(
3075 "Cannot execute a command {} not listed in the language server capabilities",
3076 command.command
3077 );
3078 continue;
3079 }
3080
3081 lsp_store.update(cx, |lsp_store, _| {
3082 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3083 mode.last_workspace_edits_by_language_server
3084 .remove(&language_server.server_id());
3085 }
3086 })?;
3087
3088 language_server
3089 .request::<lsp::request::ExecuteCommand>(
3090 lsp::ExecuteCommandParams {
3091 command: command.command.clone(),
3092 arguments: command.arguments.clone().unwrap_or_default(),
3093 ..Default::default()
3094 },
3095 request_timeout,
3096 )
3097 .await
3098 .into_response()
3099 .context("execute command")?;
3100
3101 lsp_store.update(cx, |this, _| {
3102 if let LspStoreMode::Local(mode) = &mut this.mode {
3103 project_transaction.0.extend(
3104 mode.last_workspace_edits_by_language_server
3105 .remove(&language_server.server_id())
3106 .unwrap_or_default()
3107 .0,
3108 )
3109 }
3110 })?;
3111 }
3112 Ok(())
3113 }
3114
3115 pub async fn deserialize_text_edits(
3116 this: Entity<LspStore>,
3117 buffer_to_edit: Entity<Buffer>,
3118 edits: Vec<lsp::TextEdit>,
3119 push_to_history: bool,
3120 _: Arc<CachedLspAdapter>,
3121 language_server: Arc<LanguageServer>,
3122 cx: &mut AsyncApp,
3123 ) -> Result<Option<Transaction>> {
3124 let edits = this
3125 .update(cx, |this, cx| {
3126 this.as_local_mut().unwrap().edits_from_lsp(
3127 &buffer_to_edit,
3128 edits,
3129 language_server.server_id(),
3130 None,
3131 cx,
3132 )
3133 })
3134 .await?;
3135
3136 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3137 buffer.finalize_last_transaction();
3138 buffer.start_transaction();
3139 for (range, text) in edits {
3140 buffer.edit([(range, text)], None, cx);
3141 }
3142
3143 if buffer.end_transaction(cx).is_some() {
3144 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3145 if !push_to_history {
3146 buffer.forget_transaction(transaction.id);
3147 }
3148 Some(transaction)
3149 } else {
3150 None
3151 }
3152 });
3153
3154 Ok(transaction)
3155 }
3156
3157 #[allow(clippy::type_complexity)]
3158 pub fn edits_from_lsp(
3159 &mut self,
3160 buffer: &Entity<Buffer>,
3161 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3162 server_id: LanguageServerId,
3163 version: Option<i32>,
3164 cx: &mut Context<LspStore>,
3165 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3166 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3167 cx.background_spawn(async move {
3168 let snapshot = snapshot?;
3169 let mut lsp_edits = lsp_edits
3170 .into_iter()
3171 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3172 .collect::<Vec<_>>();
3173
3174 lsp_edits.sort_unstable_by_key(|(range, _)| (range.start, range.end));
3175
3176 let mut lsp_edits = lsp_edits.into_iter().peekable();
3177 let mut edits = Vec::new();
3178 while let Some((range, mut new_text)) = lsp_edits.next() {
3179 // Clip invalid ranges provided by the language server.
3180 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3181 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3182
3183 // Combine any LSP edits that are adjacent.
3184 //
3185 // Also, combine LSP edits that are separated from each other by only
3186 // a newline. This is important because for some code actions,
3187 // Rust-analyzer rewrites the entire buffer via a series of edits that
3188 // are separated by unchanged newline characters.
3189 //
3190 // In order for the diffing logic below to work properly, any edits that
3191 // cancel each other out must be combined into one.
3192 while let Some((next_range, next_text)) = lsp_edits.peek() {
3193 if next_range.start.0 > range.end {
3194 if next_range.start.0.row > range.end.row + 1
3195 || next_range.start.0.column > 0
3196 || snapshot.clip_point_utf16(
3197 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3198 Bias::Left,
3199 ) > range.end
3200 {
3201 break;
3202 }
3203 new_text.push('\n');
3204 }
3205 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3206 new_text.push_str(next_text);
3207 lsp_edits.next();
3208 }
3209
3210 // For multiline edits, perform a diff of the old and new text so that
3211 // we can identify the changes more precisely, preserving the locations
3212 // of any anchors positioned in the unchanged regions.
3213 if range.end.row > range.start.row {
3214 let offset = range.start.to_offset(&snapshot);
3215 let old_text = snapshot.text_for_range(range).collect::<String>();
3216 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3217 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3218 (
3219 snapshot.anchor_after(offset + range.start)
3220 ..snapshot.anchor_before(offset + range.end),
3221 replacement,
3222 )
3223 }));
3224 } else if range.end == range.start {
3225 let anchor = snapshot.anchor_after(range.start);
3226 edits.push((anchor..anchor, new_text.into()));
3227 } else {
3228 let edit_start = snapshot.anchor_after(range.start);
3229 let edit_end = snapshot.anchor_before(range.end);
3230 edits.push((edit_start..edit_end, new_text.into()));
3231 }
3232 }
3233
3234 Ok(edits)
3235 })
3236 }
3237
3238 pub(crate) async fn deserialize_workspace_edit(
3239 this: Entity<LspStore>,
3240 edit: lsp::WorkspaceEdit,
3241 push_to_history: bool,
3242 language_server: Arc<LanguageServer>,
3243 cx: &mut AsyncApp,
3244 ) -> Result<ProjectTransaction> {
3245 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3246
3247 let mut operations = Vec::new();
3248 if let Some(document_changes) = edit.document_changes {
3249 match document_changes {
3250 lsp::DocumentChanges::Edits(edits) => {
3251 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3252 }
3253 lsp::DocumentChanges::Operations(ops) => operations = ops,
3254 }
3255 } else if let Some(changes) = edit.changes {
3256 operations.extend(changes.into_iter().map(|(uri, edits)| {
3257 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3258 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3259 uri,
3260 version: None,
3261 },
3262 edits: edits.into_iter().map(Edit::Plain).collect(),
3263 })
3264 }));
3265 }
3266
3267 let mut project_transaction = ProjectTransaction::default();
3268 for operation in operations {
3269 match operation {
3270 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3271 let abs_path = op
3272 .uri
3273 .to_file_path()
3274 .map_err(|()| anyhow!("can't convert URI to path"))?;
3275
3276 if let Some(parent_path) = abs_path.parent() {
3277 fs.create_dir(parent_path).await?;
3278 }
3279 if abs_path.ends_with("/") {
3280 fs.create_dir(&abs_path).await?;
3281 } else {
3282 fs.create_file(
3283 &abs_path,
3284 op.options
3285 .map(|options| fs::CreateOptions {
3286 overwrite: options.overwrite.unwrap_or(false),
3287 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3288 })
3289 .unwrap_or_default(),
3290 )
3291 .await?;
3292 }
3293 }
3294
3295 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3296 let source_abs_path = op
3297 .old_uri
3298 .to_file_path()
3299 .map_err(|()| anyhow!("can't convert URI to path"))?;
3300 let target_abs_path = op
3301 .new_uri
3302 .to_file_path()
3303 .map_err(|()| anyhow!("can't convert URI to path"))?;
3304
3305 let options = fs::RenameOptions {
3306 overwrite: op
3307 .options
3308 .as_ref()
3309 .and_then(|options| options.overwrite)
3310 .unwrap_or(false),
3311 ignore_if_exists: op
3312 .options
3313 .as_ref()
3314 .and_then(|options| options.ignore_if_exists)
3315 .unwrap_or(false),
3316 create_parents: true,
3317 };
3318
3319 fs.rename(&source_abs_path, &target_abs_path, options)
3320 .await?;
3321 }
3322
3323 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3324 let abs_path = op
3325 .uri
3326 .to_file_path()
3327 .map_err(|()| anyhow!("can't convert URI to path"))?;
3328 let options = op
3329 .options
3330 .map(|options| fs::RemoveOptions {
3331 recursive: options.recursive.unwrap_or(false),
3332 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3333 })
3334 .unwrap_or_default();
3335 if abs_path.ends_with("/") {
3336 fs.remove_dir(&abs_path, options).await?;
3337 } else {
3338 fs.remove_file(&abs_path, options).await?;
3339 }
3340 }
3341
3342 lsp::DocumentChangeOperation::Edit(op) => {
3343 let buffer_to_edit = this
3344 .update(cx, |this, cx| {
3345 this.open_local_buffer_via_lsp(
3346 op.text_document.uri.clone(),
3347 language_server.server_id(),
3348 cx,
3349 )
3350 })
3351 .await?;
3352
3353 let edits = this
3354 .update(cx, |this, cx| {
3355 let path = buffer_to_edit.read(cx).project_path(cx);
3356 let active_entry = this.active_entry;
3357 let is_active_entry = path.is_some_and(|project_path| {
3358 this.worktree_store
3359 .read(cx)
3360 .entry_for_path(&project_path, cx)
3361 .is_some_and(|entry| Some(entry.id) == active_entry)
3362 });
3363 let local = this.as_local_mut().unwrap();
3364
3365 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3366 for edit in op.edits {
3367 match edit {
3368 Edit::Plain(edit) => {
3369 if !edits.contains(&edit) {
3370 edits.push(edit)
3371 }
3372 }
3373 Edit::Annotated(edit) => {
3374 if !edits.contains(&edit.text_edit) {
3375 edits.push(edit.text_edit)
3376 }
3377 }
3378 Edit::Snippet(edit) => {
3379 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3380 else {
3381 continue;
3382 };
3383
3384 if is_active_entry {
3385 snippet_edits.push((edit.range, snippet));
3386 } else {
3387 // Since this buffer is not focused, apply a normal edit.
3388 let new_edit = TextEdit {
3389 range: edit.range,
3390 new_text: snippet.text,
3391 };
3392 if !edits.contains(&new_edit) {
3393 edits.push(new_edit);
3394 }
3395 }
3396 }
3397 }
3398 }
3399 if !snippet_edits.is_empty() {
3400 let buffer_id = buffer_to_edit.read(cx).remote_id();
3401 let version = if let Some(buffer_version) = op.text_document.version
3402 {
3403 local
3404 .buffer_snapshot_for_lsp_version(
3405 &buffer_to_edit,
3406 language_server.server_id(),
3407 Some(buffer_version),
3408 cx,
3409 )
3410 .ok()
3411 .map(|snapshot| snapshot.version)
3412 } else {
3413 Some(buffer_to_edit.read(cx).saved_version().clone())
3414 };
3415
3416 let most_recent_edit =
3417 version.and_then(|version| version.most_recent());
3418 // Check if the edit that triggered that edit has been made by this participant.
3419
3420 if let Some(most_recent_edit) = most_recent_edit {
3421 cx.emit(LspStoreEvent::SnippetEdit {
3422 buffer_id,
3423 edits: snippet_edits,
3424 most_recent_edit,
3425 });
3426 }
3427 }
3428
3429 local.edits_from_lsp(
3430 &buffer_to_edit,
3431 edits,
3432 language_server.server_id(),
3433 op.text_document.version,
3434 cx,
3435 )
3436 })
3437 .await?;
3438
3439 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3440 buffer.finalize_last_transaction();
3441 buffer.start_transaction();
3442 for (range, text) in edits {
3443 buffer.edit([(range, text)], None, cx);
3444 }
3445
3446 buffer.end_transaction(cx).and_then(|transaction_id| {
3447 if push_to_history {
3448 buffer.finalize_last_transaction();
3449 buffer.get_transaction(transaction_id).cloned()
3450 } else {
3451 buffer.forget_transaction(transaction_id)
3452 }
3453 })
3454 });
3455 if let Some(transaction) = transaction {
3456 project_transaction.0.insert(buffer_to_edit, transaction);
3457 }
3458 }
3459 }
3460 }
3461
3462 Ok(project_transaction)
3463 }
3464
3465 async fn on_lsp_workspace_edit(
3466 this: WeakEntity<LspStore>,
3467 params: lsp::ApplyWorkspaceEditParams,
3468 server_id: LanguageServerId,
3469 cx: &mut AsyncApp,
3470 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3471 let this = this.upgrade().context("project project closed")?;
3472 let language_server = this
3473 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3474 .context("language server not found")?;
3475 let transaction = Self::deserialize_workspace_edit(
3476 this.clone(),
3477 params.edit,
3478 true,
3479 language_server.clone(),
3480 cx,
3481 )
3482 .await
3483 .log_err();
3484 this.update(cx, |this, cx| {
3485 if let Some(transaction) = transaction {
3486 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3487
3488 this.as_local_mut()
3489 .unwrap()
3490 .last_workspace_edits_by_language_server
3491 .insert(server_id, transaction);
3492 }
3493 });
3494 Ok(lsp::ApplyWorkspaceEditResponse {
3495 applied: true,
3496 failed_change: None,
3497 failure_reason: None,
3498 })
3499 }
3500
3501 fn remove_worktree(
3502 &mut self,
3503 id_to_remove: WorktreeId,
3504 cx: &mut Context<LspStore>,
3505 ) -> Vec<LanguageServerId> {
3506 self.restricted_worktrees_tasks.remove(&id_to_remove);
3507 self.diagnostics.remove(&id_to_remove);
3508 self.prettier_store.update(cx, |prettier_store, cx| {
3509 prettier_store.remove_worktree(id_to_remove, cx);
3510 });
3511
3512 let mut servers_to_remove = BTreeSet::default();
3513 let mut servers_to_preserve = HashSet::default();
3514 for (seed, state) in &self.language_server_ids {
3515 if seed.worktree_id == id_to_remove {
3516 servers_to_remove.insert(state.id);
3517 } else {
3518 servers_to_preserve.insert(state.id);
3519 }
3520 }
3521 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3522 self.language_server_ids
3523 .retain(|_, state| !servers_to_remove.contains(&state.id));
3524 for server_id_to_remove in &servers_to_remove {
3525 self.language_server_watched_paths
3526 .remove(server_id_to_remove);
3527 self.language_server_paths_watched_for_rename
3528 .remove(server_id_to_remove);
3529 self.last_workspace_edits_by_language_server
3530 .remove(server_id_to_remove);
3531 self.language_servers.remove(server_id_to_remove);
3532 self.buffer_pull_diagnostics_result_ids
3533 .remove(server_id_to_remove);
3534 self.workspace_pull_diagnostics_result_ids
3535 .remove(server_id_to_remove);
3536 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3537 buffer_servers.remove(server_id_to_remove);
3538 }
3539 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3540 }
3541 servers_to_remove.into_iter().collect()
3542 }
3543
3544 fn rebuild_watched_paths_inner<'a>(
3545 &'a self,
3546 language_server_id: LanguageServerId,
3547 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3548 cx: &mut Context<LspStore>,
3549 ) -> LanguageServerWatchedPathsBuilder {
3550 let worktrees = self
3551 .worktree_store
3552 .read(cx)
3553 .worktrees()
3554 .filter_map(|worktree| {
3555 self.language_servers_for_worktree(worktree.read(cx).id())
3556 .find(|server| server.server_id() == language_server_id)
3557 .map(|_| worktree)
3558 })
3559 .collect::<Vec<_>>();
3560
3561 let mut worktree_globs = HashMap::default();
3562 let mut abs_globs = HashMap::default();
3563 log::trace!(
3564 "Processing new watcher paths for language server with id {}",
3565 language_server_id
3566 );
3567
3568 for watcher in watchers {
3569 if let Some((worktree, literal_prefix, pattern)) =
3570 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3571 {
3572 worktree.update(cx, |worktree, _| {
3573 if let Some((tree, glob)) =
3574 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3575 {
3576 tree.add_path_prefix_to_scan(literal_prefix);
3577 worktree_globs
3578 .entry(tree.id())
3579 .or_insert_with(GlobSetBuilder::new)
3580 .add(glob);
3581 }
3582 });
3583 } else {
3584 let (path, pattern) = match &watcher.glob_pattern {
3585 lsp::GlobPattern::String(s) => {
3586 let watcher_path = SanitizedPath::new(s);
3587 let path = glob_literal_prefix(watcher_path.as_path());
3588 let pattern = watcher_path
3589 .as_path()
3590 .strip_prefix(&path)
3591 .map(|p| p.to_string_lossy().into_owned())
3592 .unwrap_or_else(|e| {
3593 debug_panic!(
3594 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3595 s,
3596 path.display(),
3597 e
3598 );
3599 watcher_path.as_path().to_string_lossy().into_owned()
3600 });
3601 (path, pattern)
3602 }
3603 lsp::GlobPattern::Relative(rp) => {
3604 let Ok(mut base_uri) = match &rp.base_uri {
3605 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3606 lsp::OneOf::Right(base_uri) => base_uri,
3607 }
3608 .to_file_path() else {
3609 continue;
3610 };
3611
3612 let path = glob_literal_prefix(Path::new(&rp.pattern));
3613 let pattern = Path::new(&rp.pattern)
3614 .strip_prefix(&path)
3615 .map(|p| p.to_string_lossy().into_owned())
3616 .unwrap_or_else(|e| {
3617 debug_panic!(
3618 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3619 rp.pattern,
3620 path.display(),
3621 e
3622 );
3623 rp.pattern.clone()
3624 });
3625 base_uri.push(path);
3626 (base_uri, pattern)
3627 }
3628 };
3629
3630 if let Some(glob) = Glob::new(&pattern).log_err() {
3631 if !path
3632 .components()
3633 .any(|c| matches!(c, path::Component::Normal(_)))
3634 {
3635 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3636 // rather than adding a new watcher for `/`.
3637 for worktree in &worktrees {
3638 worktree_globs
3639 .entry(worktree.read(cx).id())
3640 .or_insert_with(GlobSetBuilder::new)
3641 .add(glob.clone());
3642 }
3643 } else {
3644 abs_globs
3645 .entry(path.into())
3646 .or_insert_with(GlobSetBuilder::new)
3647 .add(glob);
3648 }
3649 }
3650 }
3651 }
3652
3653 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3654 for (worktree_id, builder) in worktree_globs {
3655 if let Ok(globset) = builder.build() {
3656 watch_builder.watch_worktree(worktree_id, globset);
3657 }
3658 }
3659 for (abs_path, builder) in abs_globs {
3660 if let Ok(globset) = builder.build() {
3661 watch_builder.watch_abs_path(abs_path, globset);
3662 }
3663 }
3664 watch_builder
3665 }
3666
3667 fn worktree_and_path_for_file_watcher(
3668 worktrees: &[Entity<Worktree>],
3669 watcher: &FileSystemWatcher,
3670 cx: &App,
3671 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3672 worktrees.iter().find_map(|worktree| {
3673 let tree = worktree.read(cx);
3674 let worktree_root_path = tree.abs_path();
3675 let path_style = tree.path_style();
3676 match &watcher.glob_pattern {
3677 lsp::GlobPattern::String(s) => {
3678 let watcher_path = SanitizedPath::new(s);
3679 let relative = watcher_path
3680 .as_path()
3681 .strip_prefix(&worktree_root_path)
3682 .ok()?;
3683 let literal_prefix = glob_literal_prefix(relative);
3684 Some((
3685 worktree.clone(),
3686 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3687 relative.to_string_lossy().into_owned(),
3688 ))
3689 }
3690 lsp::GlobPattern::Relative(rp) => {
3691 let base_uri = match &rp.base_uri {
3692 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3693 lsp::OneOf::Right(base_uri) => base_uri,
3694 }
3695 .to_file_path()
3696 .ok()?;
3697 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3698 let mut literal_prefix = relative.to_owned();
3699 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3700 Some((
3701 worktree.clone(),
3702 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3703 rp.pattern.clone(),
3704 ))
3705 }
3706 }
3707 })
3708 }
3709
3710 fn rebuild_watched_paths(
3711 &mut self,
3712 language_server_id: LanguageServerId,
3713 cx: &mut Context<LspStore>,
3714 ) {
3715 let Some(registrations) = self
3716 .language_server_dynamic_registrations
3717 .get(&language_server_id)
3718 else {
3719 return;
3720 };
3721
3722 let watch_builder = self.rebuild_watched_paths_inner(
3723 language_server_id,
3724 registrations.did_change_watched_files.values().flatten(),
3725 cx,
3726 );
3727 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3728 self.language_server_watched_paths
3729 .insert(language_server_id, watcher);
3730
3731 cx.notify();
3732 }
3733
3734 fn on_lsp_did_change_watched_files(
3735 &mut self,
3736 language_server_id: LanguageServerId,
3737 registration_id: &str,
3738 params: DidChangeWatchedFilesRegistrationOptions,
3739 cx: &mut Context<LspStore>,
3740 ) {
3741 let registrations = self
3742 .language_server_dynamic_registrations
3743 .entry(language_server_id)
3744 .or_default();
3745
3746 registrations
3747 .did_change_watched_files
3748 .insert(registration_id.to_string(), params.watchers);
3749
3750 self.rebuild_watched_paths(language_server_id, cx);
3751 }
3752
3753 fn on_lsp_unregister_did_change_watched_files(
3754 &mut self,
3755 language_server_id: LanguageServerId,
3756 registration_id: &str,
3757 cx: &mut Context<LspStore>,
3758 ) {
3759 let registrations = self
3760 .language_server_dynamic_registrations
3761 .entry(language_server_id)
3762 .or_default();
3763
3764 if registrations
3765 .did_change_watched_files
3766 .remove(registration_id)
3767 .is_some()
3768 {
3769 log::info!(
3770 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3771 language_server_id,
3772 registration_id
3773 );
3774 } else {
3775 log::warn!(
3776 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3777 language_server_id,
3778 registration_id
3779 );
3780 }
3781
3782 self.rebuild_watched_paths(language_server_id, cx);
3783 }
3784
3785 async fn initialization_options_for_adapter(
3786 adapter: Arc<dyn LspAdapter>,
3787 delegate: &Arc<dyn LspAdapterDelegate>,
3788 cx: &mut AsyncApp,
3789 ) -> Result<Option<serde_json::Value>> {
3790 let Some(mut initialization_config) =
3791 adapter.clone().initialization_options(delegate, cx).await?
3792 else {
3793 return Ok(None);
3794 };
3795
3796 for other_adapter in delegate.registered_lsp_adapters() {
3797 if other_adapter.name() == adapter.name() {
3798 continue;
3799 }
3800 if let Ok(Some(target_config)) = other_adapter
3801 .clone()
3802 .additional_initialization_options(adapter.name(), delegate)
3803 .await
3804 {
3805 merge_json_value_into(target_config.clone(), &mut initialization_config);
3806 }
3807 }
3808
3809 Ok(Some(initialization_config))
3810 }
3811
3812 async fn workspace_configuration_for_adapter(
3813 adapter: Arc<dyn LspAdapter>,
3814 delegate: &Arc<dyn LspAdapterDelegate>,
3815 toolchain: Option<Toolchain>,
3816 requested_uri: Option<Uri>,
3817 cx: &mut AsyncApp,
3818 ) -> Result<serde_json::Value> {
3819 let mut workspace_config = adapter
3820 .clone()
3821 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3822 .await?;
3823
3824 for other_adapter in delegate.registered_lsp_adapters() {
3825 if other_adapter.name() == adapter.name() {
3826 continue;
3827 }
3828 if let Ok(Some(target_config)) = other_adapter
3829 .clone()
3830 .additional_workspace_configuration(adapter.name(), delegate, cx)
3831 .await
3832 {
3833 merge_json_value_into(target_config.clone(), &mut workspace_config);
3834 }
3835 }
3836
3837 Ok(workspace_config)
3838 }
3839
3840 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3841 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3842 Some(server.clone())
3843 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3844 Some(Arc::clone(server))
3845 } else {
3846 None
3847 }
3848 }
3849}
3850
3851fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3852 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3853 cx.emit(LspStoreEvent::LanguageServerUpdate {
3854 language_server_id: server.server_id(),
3855 name: Some(server.name()),
3856 message: proto::update_language_server::Variant::MetadataUpdated(
3857 proto::ServerMetadataUpdated {
3858 capabilities: Some(capabilities),
3859 binary: Some(proto::LanguageServerBinaryInfo {
3860 path: server.binary().path.to_string_lossy().into_owned(),
3861 arguments: server
3862 .binary()
3863 .arguments
3864 .iter()
3865 .map(|arg| arg.to_string_lossy().into_owned())
3866 .collect(),
3867 }),
3868 configuration: serde_json::to_string(server.configuration()).ok(),
3869 workspace_folders: server
3870 .workspace_folders()
3871 .iter()
3872 .map(|uri| uri.to_string())
3873 .collect(),
3874 },
3875 ),
3876 });
3877 }
3878}
3879
3880#[derive(Debug)]
3881pub struct FormattableBuffer {
3882 handle: Entity<Buffer>,
3883 abs_path: Option<PathBuf>,
3884 env: Option<HashMap<String, String>>,
3885 ranges: Option<Vec<Range<Anchor>>>,
3886}
3887
3888pub struct RemoteLspStore {
3889 upstream_client: Option<AnyProtoClient>,
3890 upstream_project_id: u64,
3891}
3892
3893pub(crate) enum LspStoreMode {
3894 Local(LocalLspStore), // ssh host and collab host
3895 Remote(RemoteLspStore), // collab guest
3896}
3897
3898impl LspStoreMode {
3899 fn is_local(&self) -> bool {
3900 matches!(self, LspStoreMode::Local(_))
3901 }
3902}
3903
3904pub struct LspStore {
3905 mode: LspStoreMode,
3906 last_formatting_failure: Option<String>,
3907 downstream_client: Option<(AnyProtoClient, u64)>,
3908 nonce: u128,
3909 buffer_store: Entity<BufferStore>,
3910 worktree_store: Entity<WorktreeStore>,
3911 pub languages: Arc<LanguageRegistry>,
3912 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3913 active_entry: Option<ProjectEntryId>,
3914 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3915 _maintain_buffer_languages: Task<()>,
3916 diagnostic_summaries:
3917 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3918 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3919 semantic_token_config: SemanticTokenConfig,
3920 lsp_data: HashMap<BufferId, BufferLspData>,
3921 next_hint_id: Arc<AtomicUsize>,
3922}
3923
3924#[derive(Debug)]
3925pub struct BufferLspData {
3926 buffer_version: Global,
3927 document_colors: Option<DocumentColorData>,
3928 code_lens: Option<CodeLensData>,
3929 semantic_tokens: Option<SemanticTokensData>,
3930 folding_ranges: Option<FoldingRangeData>,
3931 document_symbols: Option<DocumentSymbolsData>,
3932 inlay_hints: BufferInlayHints,
3933 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3934 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3935}
3936
3937#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3938struct LspKey {
3939 request_type: TypeId,
3940 server_queried: Option<LanguageServerId>,
3941}
3942
3943impl BufferLspData {
3944 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3945 Self {
3946 buffer_version: buffer.read(cx).version(),
3947 document_colors: None,
3948 code_lens: None,
3949 semantic_tokens: None,
3950 folding_ranges: None,
3951 document_symbols: None,
3952 inlay_hints: BufferInlayHints::new(buffer, cx),
3953 lsp_requests: HashMap::default(),
3954 chunk_lsp_requests: HashMap::default(),
3955 }
3956 }
3957
3958 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3959 if let Some(document_colors) = &mut self.document_colors {
3960 document_colors.remove_server_data(for_server);
3961 }
3962
3963 if let Some(code_lens) = &mut self.code_lens {
3964 code_lens.remove_server_data(for_server);
3965 }
3966
3967 self.inlay_hints.remove_server_data(for_server);
3968
3969 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3970 semantic_tokens.remove_server_data(for_server);
3971 }
3972
3973 if let Some(folding_ranges) = &mut self.folding_ranges {
3974 folding_ranges.ranges.remove(&for_server);
3975 }
3976
3977 if let Some(document_symbols) = &mut self.document_symbols {
3978 document_symbols.remove_server_data(for_server);
3979 }
3980 }
3981
3982 #[cfg(any(test, feature = "test-support"))]
3983 pub fn inlay_hints(&self) -> &BufferInlayHints {
3984 &self.inlay_hints
3985 }
3986}
3987
3988#[derive(Debug)]
3989pub enum LspStoreEvent {
3990 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3991 LanguageServerRemoved(LanguageServerId),
3992 LanguageServerUpdate {
3993 language_server_id: LanguageServerId,
3994 name: Option<LanguageServerName>,
3995 message: proto::update_language_server::Variant,
3996 },
3997 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3998 LanguageServerPrompt(LanguageServerPromptRequest),
3999 LanguageDetected {
4000 buffer: Entity<Buffer>,
4001 new_language: Option<Arc<Language>>,
4002 },
4003 Notification(String),
4004 RefreshInlayHints {
4005 server_id: LanguageServerId,
4006 request_id: Option<usize>,
4007 },
4008 RefreshSemanticTokens {
4009 server_id: LanguageServerId,
4010 request_id: Option<usize>,
4011 },
4012 RefreshCodeLens,
4013 DiagnosticsUpdated {
4014 server_id: LanguageServerId,
4015 paths: Vec<ProjectPath>,
4016 },
4017 DiskBasedDiagnosticsStarted {
4018 language_server_id: LanguageServerId,
4019 },
4020 DiskBasedDiagnosticsFinished {
4021 language_server_id: LanguageServerId,
4022 },
4023 SnippetEdit {
4024 buffer_id: BufferId,
4025 edits: Vec<(lsp::Range, Snippet)>,
4026 most_recent_edit: clock::Lamport,
4027 },
4028 WorkspaceEditApplied(ProjectTransaction),
4029}
4030
4031#[derive(Clone, Debug, Serialize)]
4032pub struct LanguageServerStatus {
4033 pub name: LanguageServerName,
4034 pub server_version: Option<SharedString>,
4035 pub server_readable_version: Option<SharedString>,
4036 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4037 pub has_pending_diagnostic_updates: bool,
4038 pub progress_tokens: HashSet<ProgressToken>,
4039 pub worktree: Option<WorktreeId>,
4040 pub binary: Option<LanguageServerBinary>,
4041 pub configuration: Option<Value>,
4042 pub workspace_folders: BTreeSet<Uri>,
4043 pub process_id: Option<u32>,
4044}
4045
4046#[derive(Clone, Debug)]
4047struct CoreSymbol {
4048 pub language_server_name: LanguageServerName,
4049 pub source_worktree_id: WorktreeId,
4050 pub source_language_server_id: LanguageServerId,
4051 pub path: SymbolLocation,
4052 pub name: String,
4053 pub kind: lsp::SymbolKind,
4054 pub range: Range<Unclipped<PointUtf16>>,
4055 pub container_name: Option<String>,
4056}
4057
4058#[derive(Clone, Debug, PartialEq, Eq)]
4059pub enum SymbolLocation {
4060 InProject(ProjectPath),
4061 OutsideProject {
4062 abs_path: Arc<Path>,
4063 signature: [u8; 32],
4064 },
4065}
4066
4067impl SymbolLocation {
4068 fn file_name(&self) -> Option<&str> {
4069 match self {
4070 Self::InProject(path) => path.path.file_name(),
4071 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4072 }
4073 }
4074}
4075
4076impl LspStore {
4077 pub fn init(client: &AnyProtoClient) {
4078 client.add_entity_request_handler(Self::handle_lsp_query);
4079 client.add_entity_message_handler(Self::handle_lsp_query_response);
4080 client.add_entity_request_handler(Self::handle_restart_language_servers);
4081 client.add_entity_request_handler(Self::handle_stop_language_servers);
4082 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4083 client.add_entity_message_handler(Self::handle_start_language_server);
4084 client.add_entity_message_handler(Self::handle_update_language_server);
4085 client.add_entity_message_handler(Self::handle_language_server_log);
4086 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4087 client.add_entity_request_handler(Self::handle_format_buffers);
4088 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4089 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4090 client.add_entity_request_handler(Self::handle_apply_code_action);
4091 client.add_entity_request_handler(Self::handle_get_project_symbols);
4092 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4093 client.add_entity_request_handler(Self::handle_get_color_presentation);
4094 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4095 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4096 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4097 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4098 client.add_entity_request_handler(Self::handle_on_type_formatting);
4099 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4100 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4101 client.add_entity_request_handler(Self::handle_rename_project_entry);
4102 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4103 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4104 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4105 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4106 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4107 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4108 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4109
4110 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4111 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4112 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4113 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4114 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4115 client.add_entity_request_handler(
4116 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4117 );
4118 client.add_entity_request_handler(
4119 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4120 );
4121 client.add_entity_request_handler(
4122 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4123 );
4124 }
4125
4126 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4127 match &self.mode {
4128 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4129 _ => None,
4130 }
4131 }
4132
4133 pub fn as_local(&self) -> Option<&LocalLspStore> {
4134 match &self.mode {
4135 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4136 _ => None,
4137 }
4138 }
4139
4140 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4141 match &mut self.mode {
4142 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4143 _ => None,
4144 }
4145 }
4146
4147 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4148 match &self.mode {
4149 LspStoreMode::Remote(RemoteLspStore {
4150 upstream_client: Some(upstream_client),
4151 upstream_project_id,
4152 ..
4153 }) => Some((upstream_client.clone(), *upstream_project_id)),
4154
4155 LspStoreMode::Remote(RemoteLspStore {
4156 upstream_client: None,
4157 ..
4158 }) => None,
4159 LspStoreMode::Local(_) => None,
4160 }
4161 }
4162
4163 fn shutdown_language_servers(&mut self, cx: &mut App) {
4164 if let Some(local) = self.as_local_mut() {
4165 let shutdown_futures: Vec<_> = local
4166 .language_servers
4167 .drain()
4168 .map(|(_, server_state)| LocalLspStore::shutdown_server(server_state))
4169 .collect();
4170
4171 let supplementary_shutdown_futures: Vec<_> = local
4172 .supplementary_language_servers
4173 .drain()
4174 .filter_map(|(_, (_, server))| server.shutdown())
4175 .collect();
4176
4177 cx.background_spawn(async move {
4178 join_all(shutdown_futures).await;
4179 join_all(supplementary_shutdown_futures).await;
4180 })
4181 .detach();
4182 }
4183 }
4184
4185 pub fn new_local(
4186 buffer_store: Entity<BufferStore>,
4187 worktree_store: Entity<WorktreeStore>,
4188 prettier_store: Entity<PrettierStore>,
4189 toolchain_store: Entity<LocalToolchainStore>,
4190 environment: Entity<ProjectEnvironment>,
4191 manifest_tree: Entity<ManifestTree>,
4192 languages: Arc<LanguageRegistry>,
4193 http_client: Arc<dyn HttpClient>,
4194 fs: Arc<dyn Fs>,
4195 cx: &mut Context<Self>,
4196 ) -> Self {
4197 let yarn = YarnPathStore::new(fs.clone(), cx);
4198 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4199 .detach();
4200 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4201 .detach();
4202 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4203 .detach();
4204 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4205 .detach();
4206 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4207 .detach();
4208 subscribe_to_binary_statuses(&languages, cx).detach();
4209
4210 let _maintain_workspace_config = {
4211 let (sender, receiver) = watch::channel();
4212 (Self::maintain_workspace_config(receiver, cx), sender)
4213 };
4214
4215 Self {
4216 mode: LspStoreMode::Local(LocalLspStore {
4217 weak: cx.weak_entity(),
4218 worktree_store: worktree_store.clone(),
4219
4220 supplementary_language_servers: Default::default(),
4221 languages: languages.clone(),
4222 language_server_ids: Default::default(),
4223 language_servers: Default::default(),
4224 last_workspace_edits_by_language_server: Default::default(),
4225 language_server_watched_paths: Default::default(),
4226 language_server_paths_watched_for_rename: Default::default(),
4227 language_server_dynamic_registrations: Default::default(),
4228 buffers_being_formatted: Default::default(),
4229 buffers_to_refresh_hash_set: HashSet::default(),
4230 buffers_to_refresh_queue: VecDeque::new(),
4231 _background_diagnostics_worker: Task::ready(()).shared(),
4232 buffer_snapshots: Default::default(),
4233 prettier_store,
4234 environment,
4235 http_client,
4236 fs,
4237 yarn,
4238 next_diagnostic_group_id: Default::default(),
4239 diagnostics: Default::default(),
4240 _subscriptions: vec![
4241 cx.on_app_quit(|this, _| {
4242 this.as_local_mut()
4243 .unwrap()
4244 .shutdown_language_servers_on_quit()
4245 }),
4246 cx.on_release(Self::shutdown_language_servers),
4247 ],
4248 lsp_tree: LanguageServerTree::new(
4249 manifest_tree,
4250 languages.clone(),
4251 toolchain_store.clone(),
4252 ),
4253 toolchain_store,
4254 registered_buffers: HashMap::default(),
4255 buffers_opened_in_servers: HashMap::default(),
4256 buffer_pull_diagnostics_result_ids: HashMap::default(),
4257 workspace_pull_diagnostics_result_ids: HashMap::default(),
4258 restricted_worktrees_tasks: HashMap::default(),
4259 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4260 .manifest_file_names(),
4261 }),
4262 last_formatting_failure: None,
4263 downstream_client: None,
4264 buffer_store,
4265 worktree_store,
4266 languages: languages.clone(),
4267 language_server_statuses: Default::default(),
4268 nonce: StdRng::from_os_rng().random(),
4269 diagnostic_summaries: HashMap::default(),
4270 lsp_server_capabilities: HashMap::default(),
4271 semantic_token_config: SemanticTokenConfig::new(cx),
4272 lsp_data: HashMap::default(),
4273 next_hint_id: Arc::default(),
4274 active_entry: None,
4275 _maintain_workspace_config,
4276 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4277 }
4278 }
4279
4280 fn send_lsp_proto_request<R: LspCommand>(
4281 &self,
4282 buffer: Entity<Buffer>,
4283 client: AnyProtoClient,
4284 upstream_project_id: u64,
4285 request: R,
4286 cx: &mut Context<LspStore>,
4287 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4288 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4289 return Task::ready(Ok(R::Response::default()));
4290 }
4291 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4292 cx.spawn(async move |this, cx| {
4293 let response = client.request(message).await?;
4294 let this = this.upgrade().context("project dropped")?;
4295 request
4296 .response_from_proto(response, this, buffer, cx.clone())
4297 .await
4298 })
4299 }
4300
4301 pub(super) fn new_remote(
4302 buffer_store: Entity<BufferStore>,
4303 worktree_store: Entity<WorktreeStore>,
4304 languages: Arc<LanguageRegistry>,
4305 upstream_client: AnyProtoClient,
4306 project_id: u64,
4307 cx: &mut Context<Self>,
4308 ) -> Self {
4309 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4310 .detach();
4311 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4312 .detach();
4313 subscribe_to_binary_statuses(&languages, cx).detach();
4314 let _maintain_workspace_config = {
4315 let (sender, receiver) = watch::channel();
4316 (Self::maintain_workspace_config(receiver, cx), sender)
4317 };
4318 Self {
4319 mode: LspStoreMode::Remote(RemoteLspStore {
4320 upstream_client: Some(upstream_client),
4321 upstream_project_id: project_id,
4322 }),
4323 downstream_client: None,
4324 last_formatting_failure: None,
4325 buffer_store,
4326 worktree_store,
4327 languages: languages.clone(),
4328 language_server_statuses: Default::default(),
4329 nonce: StdRng::from_os_rng().random(),
4330 diagnostic_summaries: HashMap::default(),
4331 lsp_server_capabilities: HashMap::default(),
4332 semantic_token_config: SemanticTokenConfig::new(cx),
4333 next_hint_id: Arc::default(),
4334 lsp_data: HashMap::default(),
4335 active_entry: None,
4336
4337 _maintain_workspace_config,
4338 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4339 }
4340 }
4341
4342 fn on_buffer_store_event(
4343 &mut self,
4344 _: Entity<BufferStore>,
4345 event: &BufferStoreEvent,
4346 cx: &mut Context<Self>,
4347 ) {
4348 match event {
4349 BufferStoreEvent::BufferAdded(buffer) => {
4350 self.on_buffer_added(buffer, cx).log_err();
4351 }
4352 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4353 let buffer_id = buffer.read(cx).remote_id();
4354 if let Some(local) = self.as_local_mut()
4355 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4356 {
4357 local.reset_buffer(buffer, old_file, cx);
4358
4359 if local.registered_buffers.contains_key(&buffer_id) {
4360 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4361 }
4362 }
4363
4364 self.detect_language_for_buffer(buffer, cx);
4365 if let Some(local) = self.as_local_mut() {
4366 local.initialize_buffer(buffer, cx);
4367 if local.registered_buffers.contains_key(&buffer_id) {
4368 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4369 }
4370 }
4371 }
4372 _ => {}
4373 }
4374 }
4375
4376 fn on_worktree_store_event(
4377 &mut self,
4378 _: Entity<WorktreeStore>,
4379 event: &WorktreeStoreEvent,
4380 cx: &mut Context<Self>,
4381 ) {
4382 match event {
4383 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4384 if !worktree.read(cx).is_local() {
4385 return;
4386 }
4387 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4388 worktree::Event::UpdatedEntries(changes) => {
4389 this.update_local_worktree_language_servers(&worktree, changes, cx);
4390 }
4391 worktree::Event::UpdatedGitRepositories(_)
4392 | worktree::Event::DeletedEntry(_) => {}
4393 })
4394 .detach()
4395 }
4396 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4397 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4398 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4399 }
4400 WorktreeStoreEvent::WorktreeReleased(..)
4401 | WorktreeStoreEvent::WorktreeOrderChanged
4402 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4403 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4404 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4405 }
4406 }
4407
4408 fn on_prettier_store_event(
4409 &mut self,
4410 _: Entity<PrettierStore>,
4411 event: &PrettierStoreEvent,
4412 cx: &mut Context<Self>,
4413 ) {
4414 match event {
4415 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4416 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4417 }
4418 PrettierStoreEvent::LanguageServerAdded {
4419 new_server_id,
4420 name,
4421 prettier_server,
4422 } => {
4423 self.register_supplementary_language_server(
4424 *new_server_id,
4425 name.clone(),
4426 prettier_server.clone(),
4427 cx,
4428 );
4429 }
4430 }
4431 }
4432
4433 fn on_toolchain_store_event(
4434 &mut self,
4435 _: Entity<LocalToolchainStore>,
4436 event: &ToolchainStoreEvent,
4437 _: &mut Context<Self>,
4438 ) {
4439 if let ToolchainStoreEvent::ToolchainActivated = event {
4440 self.request_workspace_config_refresh()
4441 }
4442 }
4443
4444 fn request_workspace_config_refresh(&mut self) {
4445 *self._maintain_workspace_config.1.borrow_mut() = ();
4446 }
4447
4448 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4449 self.as_local().map(|local| local.prettier_store.clone())
4450 }
4451
4452 fn on_buffer_event(
4453 &mut self,
4454 buffer: Entity<Buffer>,
4455 event: &language::BufferEvent,
4456 cx: &mut Context<Self>,
4457 ) {
4458 match event {
4459 language::BufferEvent::Edited { .. } => {
4460 self.on_buffer_edited(buffer, cx);
4461 }
4462
4463 language::BufferEvent::Saved => {
4464 self.on_buffer_saved(buffer, cx);
4465 }
4466
4467 _ => {}
4468 }
4469 }
4470
4471 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4472 buffer
4473 .read(cx)
4474 .set_language_registry(self.languages.clone());
4475
4476 cx.subscribe(buffer, |this, buffer, event, cx| {
4477 this.on_buffer_event(buffer, event, cx);
4478 })
4479 .detach();
4480
4481 self.detect_language_for_buffer(buffer, cx);
4482 if let Some(local) = self.as_local_mut() {
4483 local.initialize_buffer(buffer, cx);
4484 }
4485
4486 Ok(())
4487 }
4488
4489 pub fn refresh_background_diagnostics_for_buffers(
4490 &mut self,
4491 buffers: HashSet<BufferId>,
4492 cx: &mut Context<Self>,
4493 ) -> Shared<Task<()>> {
4494 let Some(local) = self.as_local_mut() else {
4495 return Task::ready(()).shared();
4496 };
4497 for buffer in buffers {
4498 if local.buffers_to_refresh_hash_set.insert(buffer) {
4499 local.buffers_to_refresh_queue.push_back(buffer);
4500 if local.buffers_to_refresh_queue.len() == 1 {
4501 local._background_diagnostics_worker =
4502 Self::background_diagnostics_worker(cx).shared();
4503 }
4504 }
4505 }
4506
4507 local._background_diagnostics_worker.clone()
4508 }
4509
4510 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4511 let buffer_store = self.buffer_store.clone();
4512 let local = self.as_local_mut()?;
4513 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4514 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4515 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4516 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4517 }
4518 }
4519 None
4520 }
4521
4522 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4523 cx.spawn(async move |this, cx| {
4524 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4525 task.await.log_err();
4526 }
4527 })
4528 }
4529
4530 pub(crate) fn register_buffer_with_language_servers(
4531 &mut self,
4532 buffer: &Entity<Buffer>,
4533 only_register_servers: HashSet<LanguageServerSelector>,
4534 ignore_refcounts: bool,
4535 cx: &mut Context<Self>,
4536 ) -> OpenLspBufferHandle {
4537 let buffer_id = buffer.read(cx).remote_id();
4538 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4539 if let Some(local) = self.as_local_mut() {
4540 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4541 if !ignore_refcounts {
4542 *refcount += 1;
4543 }
4544
4545 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4546 // 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
4547 // 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
4548 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4549 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4550 return handle;
4551 };
4552 if !file.is_local() {
4553 return handle;
4554 }
4555
4556 if ignore_refcounts || *refcount == 1 {
4557 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4558 }
4559 if !ignore_refcounts {
4560 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4561 let refcount = {
4562 let local = lsp_store.as_local_mut().unwrap();
4563 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4564 debug_panic!("bad refcounting");
4565 return;
4566 };
4567
4568 *refcount -= 1;
4569 *refcount
4570 };
4571 if refcount == 0 {
4572 lsp_store.lsp_data.remove(&buffer_id);
4573 let local = lsp_store.as_local_mut().unwrap();
4574 local.registered_buffers.remove(&buffer_id);
4575
4576 local.buffers_opened_in_servers.remove(&buffer_id);
4577 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4578 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4579
4580 let buffer_abs_path = file.abs_path(cx);
4581 for (_, buffer_pull_diagnostics_result_ids) in
4582 &mut local.buffer_pull_diagnostics_result_ids
4583 {
4584 buffer_pull_diagnostics_result_ids.retain(
4585 |_, buffer_result_ids| {
4586 buffer_result_ids.remove(&buffer_abs_path);
4587 !buffer_result_ids.is_empty()
4588 },
4589 );
4590 }
4591
4592 let diagnostic_updates = local
4593 .language_servers
4594 .keys()
4595 .cloned()
4596 .map(|server_id| DocumentDiagnosticsUpdate {
4597 diagnostics: DocumentDiagnostics {
4598 document_abs_path: buffer_abs_path.clone(),
4599 version: None,
4600 diagnostics: Vec::new(),
4601 },
4602 result_id: None,
4603 registration_id: None,
4604 server_id,
4605 disk_based_sources: Cow::Borrowed(&[]),
4606 })
4607 .collect::<Vec<_>>();
4608
4609 lsp_store
4610 .merge_diagnostic_entries(
4611 diagnostic_updates,
4612 |_, diagnostic, _| {
4613 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4614 },
4615 cx,
4616 )
4617 .context("Clearing diagnostics for the closed buffer")
4618 .log_err();
4619 }
4620 }
4621 })
4622 .detach();
4623 }
4624 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4625 let buffer_id = buffer.read(cx).remote_id().to_proto();
4626 cx.background_spawn(async move {
4627 upstream_client
4628 .request(proto::RegisterBufferWithLanguageServers {
4629 project_id: upstream_project_id,
4630 buffer_id,
4631 only_servers: only_register_servers
4632 .into_iter()
4633 .map(|selector| {
4634 let selector = match selector {
4635 LanguageServerSelector::Id(language_server_id) => {
4636 proto::language_server_selector::Selector::ServerId(
4637 language_server_id.to_proto(),
4638 )
4639 }
4640 LanguageServerSelector::Name(language_server_name) => {
4641 proto::language_server_selector::Selector::Name(
4642 language_server_name.to_string(),
4643 )
4644 }
4645 };
4646 proto::LanguageServerSelector {
4647 selector: Some(selector),
4648 }
4649 })
4650 .collect(),
4651 })
4652 .await
4653 })
4654 .detach();
4655 } else {
4656 // Our remote connection got closed
4657 }
4658 handle
4659 }
4660
4661 fn maintain_buffer_languages(
4662 languages: Arc<LanguageRegistry>,
4663 cx: &mut Context<Self>,
4664 ) -> Task<()> {
4665 let mut subscription = languages.subscribe();
4666 let mut prev_reload_count = languages.reload_count();
4667 cx.spawn(async move |this, cx| {
4668 while let Some(()) = subscription.next().await {
4669 if let Some(this) = this.upgrade() {
4670 // If the language registry has been reloaded, then remove and
4671 // re-assign the languages on all open buffers.
4672 let reload_count = languages.reload_count();
4673 if reload_count > prev_reload_count {
4674 prev_reload_count = reload_count;
4675 this.update(cx, |this, cx| {
4676 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4677 for buffer in buffer_store.buffers() {
4678 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4679 {
4680 buffer.update(cx, |buffer, cx| {
4681 buffer.set_language_async(None, cx)
4682 });
4683 if let Some(local) = this.as_local_mut() {
4684 local.reset_buffer(&buffer, &f, cx);
4685
4686 if local
4687 .registered_buffers
4688 .contains_key(&buffer.read(cx).remote_id())
4689 && let Some(file_url) =
4690 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4691 {
4692 local.unregister_buffer_from_language_servers(
4693 &buffer, &file_url, cx,
4694 );
4695 }
4696 }
4697 }
4698 }
4699 });
4700 });
4701 }
4702
4703 this.update(cx, |this, cx| {
4704 let mut plain_text_buffers = Vec::new();
4705 let mut buffers_with_unknown_injections = Vec::new();
4706 for handle in this.buffer_store.read(cx).buffers() {
4707 let buffer = handle.read(cx);
4708 if buffer.language().is_none()
4709 || buffer.language() == Some(&*language::PLAIN_TEXT)
4710 {
4711 plain_text_buffers.push(handle);
4712 } else if buffer.contains_unknown_injections() {
4713 buffers_with_unknown_injections.push(handle);
4714 }
4715 }
4716
4717 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4718 // and reused later in the invisible worktrees.
4719 plain_text_buffers.sort_by_key(|buffer| {
4720 Reverse(
4721 File::from_dyn(buffer.read(cx).file())
4722 .map(|file| file.worktree.read(cx).is_visible()),
4723 )
4724 });
4725
4726 for buffer in plain_text_buffers {
4727 this.detect_language_for_buffer(&buffer, cx);
4728 if let Some(local) = this.as_local_mut() {
4729 local.initialize_buffer(&buffer, cx);
4730 if local
4731 .registered_buffers
4732 .contains_key(&buffer.read(cx).remote_id())
4733 {
4734 local.register_buffer_with_language_servers(
4735 &buffer,
4736 HashSet::default(),
4737 cx,
4738 );
4739 }
4740 }
4741 }
4742
4743 for buffer in buffers_with_unknown_injections {
4744 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4745 }
4746 });
4747 }
4748 }
4749 })
4750 }
4751
4752 fn detect_language_for_buffer(
4753 &mut self,
4754 buffer_handle: &Entity<Buffer>,
4755 cx: &mut Context<Self>,
4756 ) -> Option<language::AvailableLanguage> {
4757 // If the buffer has a language, set it and start the language server if we haven't already.
4758 let buffer = buffer_handle.read(cx);
4759 let file = buffer.file()?;
4760
4761 let content = buffer.as_rope();
4762 let available_language = self.languages.language_for_file(file, Some(content), cx);
4763 if let Some(available_language) = &available_language {
4764 if let Some(Ok(Ok(new_language))) = self
4765 .languages
4766 .load_language(available_language)
4767 .now_or_never()
4768 {
4769 self.set_language_for_buffer(buffer_handle, new_language, cx);
4770 }
4771 } else {
4772 cx.emit(LspStoreEvent::LanguageDetected {
4773 buffer: buffer_handle.clone(),
4774 new_language: None,
4775 });
4776 }
4777
4778 available_language
4779 }
4780
4781 pub(crate) fn set_language_for_buffer(
4782 &mut self,
4783 buffer_entity: &Entity<Buffer>,
4784 new_language: Arc<Language>,
4785 cx: &mut Context<Self>,
4786 ) {
4787 let buffer = buffer_entity.read(cx);
4788 let buffer_file = buffer.file().cloned();
4789 let buffer_id = buffer.remote_id();
4790 if let Some(local_store) = self.as_local_mut()
4791 && local_store.registered_buffers.contains_key(&buffer_id)
4792 && let Some(abs_path) =
4793 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4794 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4795 {
4796 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4797 }
4798 buffer_entity.update(cx, |buffer, cx| {
4799 if buffer
4800 .language()
4801 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4802 {
4803 buffer.set_language_async(Some(new_language.clone()), cx);
4804 }
4805 });
4806
4807 let settings =
4808 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4809 let buffer_file = File::from_dyn(buffer_file.as_ref());
4810
4811 let worktree_id = if let Some(file) = buffer_file {
4812 let worktree = file.worktree.clone();
4813
4814 if let Some(local) = self.as_local_mut()
4815 && local.registered_buffers.contains_key(&buffer_id)
4816 {
4817 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4818 }
4819 Some(worktree.read(cx).id())
4820 } else {
4821 None
4822 };
4823
4824 if settings.prettier.allowed
4825 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4826 {
4827 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4828 if let Some(prettier_store) = prettier_store {
4829 prettier_store.update(cx, |prettier_store, cx| {
4830 prettier_store.install_default_prettier(
4831 worktree_id,
4832 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4833 cx,
4834 )
4835 })
4836 }
4837 }
4838
4839 cx.emit(LspStoreEvent::LanguageDetected {
4840 buffer: buffer_entity.clone(),
4841 new_language: Some(new_language),
4842 })
4843 }
4844
4845 pub fn buffer_store(&self) -> Entity<BufferStore> {
4846 self.buffer_store.clone()
4847 }
4848
4849 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4850 self.active_entry = active_entry;
4851 }
4852
4853 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4854 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4855 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4856 {
4857 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4858 summaries
4859 .iter()
4860 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4861 });
4862 if let Some(summary) = summaries.next() {
4863 client
4864 .send(proto::UpdateDiagnosticSummary {
4865 project_id: downstream_project_id,
4866 worktree_id: worktree.id().to_proto(),
4867 summary: Some(summary),
4868 more_summaries: summaries.collect(),
4869 })
4870 .log_err();
4871 }
4872 }
4873 }
4874
4875 fn is_capable_for_proto_request<R>(
4876 &self,
4877 buffer: &Entity<Buffer>,
4878 request: &R,
4879 cx: &App,
4880 ) -> bool
4881 where
4882 R: LspCommand,
4883 {
4884 self.check_if_capable_for_proto_request(
4885 buffer,
4886 |capabilities| {
4887 request.check_capabilities(AdapterServerCapabilities {
4888 server_capabilities: capabilities.clone(),
4889 code_action_kinds: None,
4890 })
4891 },
4892 cx,
4893 )
4894 }
4895
4896 fn check_if_capable_for_proto_request<F>(
4897 &self,
4898 buffer: &Entity<Buffer>,
4899 check: F,
4900 cx: &App,
4901 ) -> bool
4902 where
4903 F: FnMut(&lsp::ServerCapabilities) -> bool,
4904 {
4905 let Some(language) = buffer.read(cx).language().cloned() else {
4906 return false;
4907 };
4908 let registered_language_servers = self
4909 .languages
4910 .lsp_adapters(&language.name())
4911 .into_iter()
4912 .map(|lsp_adapter| lsp_adapter.name())
4913 .collect::<HashSet<_>>();
4914 self.language_server_statuses
4915 .iter()
4916 .filter_map(|(server_id, server_status)| {
4917 // Include servers that are either registered for this language OR
4918 // available to be loaded (for SSH remote mode where adapters like
4919 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4920 // but only loaded on the server side)
4921 let is_relevant = registered_language_servers.contains(&server_status.name)
4922 || self.languages.is_lsp_adapter_available(&server_status.name);
4923 is_relevant.then_some(server_id)
4924 })
4925 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4926 .any(check)
4927 }
4928
4929 fn all_capable_for_proto_request<F>(
4930 &self,
4931 buffer: &Entity<Buffer>,
4932 mut check: F,
4933 cx: &App,
4934 ) -> Vec<(lsp::LanguageServerId, lsp::LanguageServerName)>
4935 where
4936 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4937 {
4938 let Some(language) = buffer.read(cx).language().cloned() else {
4939 return Vec::default();
4940 };
4941 let registered_language_servers = self
4942 .languages
4943 .lsp_adapters(&language.name())
4944 .into_iter()
4945 .map(|lsp_adapter| lsp_adapter.name())
4946 .collect::<HashSet<_>>();
4947 self.language_server_statuses
4948 .iter()
4949 .filter_map(|(server_id, server_status)| {
4950 // Include servers that are either registered for this language OR
4951 // available to be loaded (for SSH remote mode where adapters like
4952 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4953 // but only loaded on the server side)
4954 let is_relevant = registered_language_servers.contains(&server_status.name)
4955 || self.languages.is_lsp_adapter_available(&server_status.name);
4956 is_relevant.then_some((server_id, &server_status.name))
4957 })
4958 .filter_map(|(server_id, server_name)| {
4959 self.lsp_server_capabilities
4960 .get(server_id)
4961 .map(|c| (server_id, server_name, c))
4962 })
4963 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4964 .map(|(server_id, server_name, _)| (*server_id, server_name.clone()))
4965 .collect()
4966 }
4967
4968 pub fn request_lsp<R>(
4969 &mut self,
4970 buffer: Entity<Buffer>,
4971 server: LanguageServerToQuery,
4972 request: R,
4973 cx: &mut Context<Self>,
4974 ) -> Task<Result<R::Response>>
4975 where
4976 R: LspCommand,
4977 <R::LspRequest as lsp::request::Request>::Result: Send,
4978 <R::LspRequest as lsp::request::Request>::Params: Send,
4979 {
4980 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4981 return self.send_lsp_proto_request(
4982 buffer,
4983 upstream_client,
4984 upstream_project_id,
4985 request,
4986 cx,
4987 );
4988 }
4989
4990 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4991 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4992 local
4993 .language_servers_for_buffer(buffer, cx)
4994 .find(|(_, server)| {
4995 request.check_capabilities(server.adapter_server_capabilities())
4996 })
4997 .map(|(_, server)| server.clone())
4998 }),
4999 LanguageServerToQuery::Other(id) => self
5000 .language_server_for_local_buffer(buffer, id, cx)
5001 .and_then(|(_, server)| {
5002 request
5003 .check_capabilities(server.adapter_server_capabilities())
5004 .then(|| Arc::clone(server))
5005 }),
5006 }) else {
5007 return Task::ready(Ok(Default::default()));
5008 };
5009
5010 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
5011
5012 let Some(file) = file else {
5013 return Task::ready(Ok(Default::default()));
5014 };
5015
5016 let lsp_params = match request.to_lsp_params_or_response(
5017 &file.abs_path(cx),
5018 buffer.read(cx),
5019 &language_server,
5020 cx,
5021 ) {
5022 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
5023 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
5024 Err(err) => {
5025 let message = format!(
5026 "{} via {} failed: {}",
5027 request.display_name(),
5028 language_server.name(),
5029 err
5030 );
5031 // rust-analyzer likes to error with this when its still loading up
5032 if !message.ends_with("content modified") {
5033 log::warn!("{message}");
5034 }
5035 return Task::ready(Err(anyhow!(message)));
5036 }
5037 };
5038
5039 let status = request.status();
5040 let request_timeout = ProjectSettings::get_global(cx)
5041 .global_lsp_settings
5042 .get_request_timeout();
5043
5044 cx.spawn(async move |this, cx| {
5045 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5046
5047 let id = lsp_request.id();
5048 let _cleanup = if status.is_some() {
5049 cx.update(|cx| {
5050 this.update(cx, |this, cx| {
5051 this.on_lsp_work_start(
5052 language_server.server_id(),
5053 ProgressToken::Number(id),
5054 LanguageServerProgress {
5055 is_disk_based_diagnostics_progress: false,
5056 is_cancellable: false,
5057 title: None,
5058 message: status.clone(),
5059 percentage: None,
5060 last_update_at: cx.background_executor().now(),
5061 },
5062 cx,
5063 );
5064 })
5065 })
5066 .log_err();
5067
5068 Some(defer(|| {
5069 cx.update(|cx| {
5070 this.update(cx, |this, cx| {
5071 this.on_lsp_work_end(
5072 language_server.server_id(),
5073 ProgressToken::Number(id),
5074 cx,
5075 );
5076 })
5077 })
5078 .log_err();
5079 }))
5080 } else {
5081 None
5082 };
5083
5084 let result = lsp_request.await.into_response();
5085
5086 let response = result.map_err(|err| {
5087 let message = format!(
5088 "{} via {} failed: {}",
5089 request.display_name(),
5090 language_server.name(),
5091 err
5092 );
5093 // rust-analyzer likes to error with this when its still loading up
5094 if !message.ends_with("content modified") {
5095 log::warn!("{message}");
5096 }
5097 anyhow::anyhow!(message)
5098 })?;
5099
5100 request
5101 .response_from_lsp(
5102 response,
5103 this.upgrade().context("no app context")?,
5104 buffer,
5105 language_server.server_id(),
5106 cx.clone(),
5107 )
5108 .await
5109 })
5110 }
5111
5112 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5113 let mut language_formatters_to_check = Vec::new();
5114 for buffer in self.buffer_store.read(cx).buffers() {
5115 let buffer = buffer.read(cx);
5116 let buffer_file = File::from_dyn(buffer.file());
5117 let buffer_language = buffer.language();
5118 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5119 if buffer_language.is_some() {
5120 language_formatters_to_check.push((
5121 buffer_file.map(|f| f.worktree_id(cx)),
5122 settings.into_owned(),
5123 ));
5124 }
5125 }
5126
5127 self.request_workspace_config_refresh();
5128
5129 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5130 prettier_store.update(cx, |prettier_store, cx| {
5131 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5132 })
5133 }
5134
5135 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5136 .global_lsp_settings
5137 .semantic_token_rules
5138 .clone();
5139 self.semantic_token_config
5140 .update_rules(new_semantic_token_rules);
5141 // Always clear cached stylizers so that changes to language-specific
5142 // semantic token rules (e.g. from extension install/uninstall) are
5143 // picked up. Stylizers are recreated lazily, so this is cheap.
5144 self.semantic_token_config.clear_stylizers();
5145
5146 let new_global_semantic_tokens_mode =
5147 all_language_settings(None, cx).defaults.semantic_tokens;
5148 if self
5149 .semantic_token_config
5150 .update_global_mode(new_global_semantic_tokens_mode)
5151 {
5152 self.restart_all_language_servers(cx);
5153 }
5154
5155 cx.notify();
5156 }
5157
5158 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5159 let buffer_store = self.buffer_store.clone();
5160 let Some(local) = self.as_local_mut() else {
5161 return;
5162 };
5163 let mut adapters = BTreeMap::default();
5164 let get_adapter = {
5165 let languages = local.languages.clone();
5166 let environment = local.environment.clone();
5167 let weak = local.weak.clone();
5168 let worktree_store = local.worktree_store.clone();
5169 let http_client = local.http_client.clone();
5170 let fs = local.fs.clone();
5171 move |worktree_id, cx: &mut App| {
5172 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5173 Some(LocalLspAdapterDelegate::new(
5174 languages.clone(),
5175 &environment,
5176 weak.clone(),
5177 &worktree,
5178 http_client.clone(),
5179 fs.clone(),
5180 cx,
5181 ))
5182 }
5183 };
5184
5185 let mut messages_to_report = Vec::new();
5186 let (new_tree, to_stop) = {
5187 let mut rebase = local.lsp_tree.rebase();
5188 let buffers = buffer_store
5189 .read(cx)
5190 .buffers()
5191 .filter_map(|buffer| {
5192 let raw_buffer = buffer.read(cx);
5193 if !local
5194 .registered_buffers
5195 .contains_key(&raw_buffer.remote_id())
5196 {
5197 return None;
5198 }
5199 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5200 let language = raw_buffer.language().cloned()?;
5201 Some((file, language, raw_buffer.remote_id()))
5202 })
5203 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5204 for (file, language, buffer_id) in buffers {
5205 let worktree_id = file.worktree_id(cx);
5206 let Some(worktree) = local
5207 .worktree_store
5208 .read(cx)
5209 .worktree_for_id(worktree_id, cx)
5210 else {
5211 continue;
5212 };
5213
5214 if let Some((_, apply)) = local.reuse_existing_language_server(
5215 rebase.server_tree(),
5216 &worktree,
5217 &language.name(),
5218 cx,
5219 ) {
5220 (apply)(rebase.server_tree());
5221 } else if let Some(lsp_delegate) = adapters
5222 .entry(worktree_id)
5223 .or_insert_with(|| get_adapter(worktree_id, cx))
5224 .clone()
5225 {
5226 let delegate =
5227 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5228 let path = file
5229 .path()
5230 .parent()
5231 .map(Arc::from)
5232 .unwrap_or_else(|| file.path().clone());
5233 let worktree_path = ProjectPath { worktree_id, path };
5234 let abs_path = file.abs_path(cx);
5235 let nodes = rebase
5236 .walk(
5237 worktree_path,
5238 language.name(),
5239 language.manifest(),
5240 delegate.clone(),
5241 cx,
5242 )
5243 .collect::<Vec<_>>();
5244 for node in nodes {
5245 let server_id = node.server_id_or_init(|disposition| {
5246 let path = &disposition.path;
5247 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5248 let key = LanguageServerSeed {
5249 worktree_id,
5250 name: disposition.server_name.clone(),
5251 settings: LanguageServerSeedSettings {
5252 binary: disposition.settings.binary.clone(),
5253 initialization_options: disposition
5254 .settings
5255 .initialization_options
5256 .clone(),
5257 },
5258 toolchain: local.toolchain_store.read(cx).active_toolchain(
5259 path.worktree_id,
5260 &path.path,
5261 language.name(),
5262 ),
5263 };
5264 local.language_server_ids.remove(&key);
5265
5266 let server_id = local.get_or_insert_language_server(
5267 &worktree,
5268 lsp_delegate.clone(),
5269 disposition,
5270 &language.name(),
5271 cx,
5272 );
5273 if let Some(state) = local.language_servers.get(&server_id)
5274 && let Ok(uri) = uri
5275 {
5276 state.add_workspace_folder(uri);
5277 };
5278 server_id
5279 });
5280
5281 if let Some(language_server_id) = server_id {
5282 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5283 language_server_id,
5284 name: node.name(),
5285 message:
5286 proto::update_language_server::Variant::RegisteredForBuffer(
5287 proto::RegisteredForBuffer {
5288 buffer_abs_path: abs_path
5289 .to_string_lossy()
5290 .into_owned(),
5291 buffer_id: buffer_id.to_proto(),
5292 },
5293 ),
5294 });
5295 }
5296 }
5297 } else {
5298 continue;
5299 }
5300 }
5301 rebase.finish()
5302 };
5303 for message in messages_to_report {
5304 cx.emit(message);
5305 }
5306 local.lsp_tree = new_tree;
5307 for (id, _) in to_stop {
5308 self.stop_local_language_server(id, cx).detach();
5309 }
5310 }
5311
5312 pub fn apply_code_action(
5313 &self,
5314 buffer_handle: Entity<Buffer>,
5315 mut action: CodeAction,
5316 push_to_history: bool,
5317 cx: &mut Context<Self>,
5318 ) -> Task<Result<ProjectTransaction>> {
5319 if let Some((upstream_client, project_id)) = self.upstream_client() {
5320 let request = proto::ApplyCodeAction {
5321 project_id,
5322 buffer_id: buffer_handle.read(cx).remote_id().into(),
5323 action: Some(Self::serialize_code_action(&action)),
5324 };
5325 let buffer_store = self.buffer_store();
5326 cx.spawn(async move |_, cx| {
5327 let response = upstream_client
5328 .request(request)
5329 .await?
5330 .transaction
5331 .context("missing transaction")?;
5332
5333 buffer_store
5334 .update(cx, |buffer_store, cx| {
5335 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5336 })
5337 .await
5338 })
5339 } else if self.mode.is_local() {
5340 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5341 let request_timeout = ProjectSettings::get_global(cx)
5342 .global_lsp_settings
5343 .get_request_timeout();
5344 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5345 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5346 }) else {
5347 return Task::ready(Ok(ProjectTransaction::default()));
5348 };
5349
5350 cx.spawn(async move |this, cx| {
5351 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5352 .await
5353 .context("resolving a code action")?;
5354 if let Some(edit) = action.lsp_action.edit()
5355 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5356 return LocalLspStore::deserialize_workspace_edit(
5357 this.upgrade().context("no app present")?,
5358 edit.clone(),
5359 push_to_history,
5360
5361 lang_server.clone(),
5362 cx,
5363 )
5364 .await;
5365 }
5366
5367 let Some(command) = action.lsp_action.command() else {
5368 return Ok(ProjectTransaction::default())
5369 };
5370
5371 let server_capabilities = lang_server.capabilities();
5372 let available_commands = server_capabilities
5373 .execute_command_provider
5374 .as_ref()
5375 .map(|options| options.commands.as_slice())
5376 .unwrap_or_default();
5377
5378 if !available_commands.contains(&command.command) {
5379 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5380 return Ok(ProjectTransaction::default())
5381 }
5382
5383 let request_timeout = cx.update(|app|
5384 ProjectSettings::get_global(app)
5385 .global_lsp_settings
5386 .get_request_timeout()
5387 );
5388
5389 this.update(cx, |this, _| {
5390 this.as_local_mut()
5391 .unwrap()
5392 .last_workspace_edits_by_language_server
5393 .remove(&lang_server.server_id());
5394 })?;
5395
5396 let _result = lang_server
5397 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5398 command: command.command.clone(),
5399 arguments: command.arguments.clone().unwrap_or_default(),
5400 ..lsp::ExecuteCommandParams::default()
5401 }, request_timeout)
5402 .await.into_response()
5403 .context("execute command")?;
5404
5405 return this.update(cx, |this, _| {
5406 this.as_local_mut()
5407 .unwrap()
5408 .last_workspace_edits_by_language_server
5409 .remove(&lang_server.server_id())
5410 .unwrap_or_default()
5411 });
5412 })
5413 } else {
5414 Task::ready(Err(anyhow!("no upstream client and not local")))
5415 }
5416 }
5417
5418 pub fn apply_code_action_kind(
5419 &mut self,
5420 buffers: HashSet<Entity<Buffer>>,
5421 kind: CodeActionKind,
5422 push_to_history: bool,
5423 cx: &mut Context<Self>,
5424 ) -> Task<anyhow::Result<ProjectTransaction>> {
5425 if self.as_local().is_some() {
5426 cx.spawn(async move |lsp_store, cx| {
5427 let buffers = buffers.into_iter().collect::<Vec<_>>();
5428 let result = LocalLspStore::execute_code_action_kind_locally(
5429 lsp_store.clone(),
5430 buffers,
5431 kind,
5432 push_to_history,
5433 cx,
5434 )
5435 .await;
5436 lsp_store.update(cx, |lsp_store, _| {
5437 lsp_store.update_last_formatting_failure(&result);
5438 })?;
5439 result
5440 })
5441 } else if let Some((client, project_id)) = self.upstream_client() {
5442 let buffer_store = self.buffer_store();
5443 cx.spawn(async move |lsp_store, cx| {
5444 let result = client
5445 .request(proto::ApplyCodeActionKind {
5446 project_id,
5447 kind: kind.as_str().to_owned(),
5448 buffer_ids: buffers
5449 .iter()
5450 .map(|buffer| {
5451 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5452 })
5453 .collect(),
5454 })
5455 .await
5456 .and_then(|result| result.transaction.context("missing transaction"));
5457 lsp_store.update(cx, |lsp_store, _| {
5458 lsp_store.update_last_formatting_failure(&result);
5459 })?;
5460
5461 let transaction_response = result?;
5462 buffer_store
5463 .update(cx, |buffer_store, cx| {
5464 buffer_store.deserialize_project_transaction(
5465 transaction_response,
5466 push_to_history,
5467 cx,
5468 )
5469 })
5470 .await
5471 })
5472 } else {
5473 Task::ready(Ok(ProjectTransaction::default()))
5474 }
5475 }
5476
5477 pub fn resolved_hint(
5478 &mut self,
5479 buffer_id: BufferId,
5480 id: InlayId,
5481 cx: &mut Context<Self>,
5482 ) -> Option<ResolvedHint> {
5483 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5484
5485 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5486 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5487 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5488 let (server_id, resolve_data) = match &hint.resolve_state {
5489 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5490 ResolveState::Resolving => {
5491 return Some(ResolvedHint::Resolving(
5492 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5493 ));
5494 }
5495 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5496 };
5497
5498 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5499 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5500 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5501 id,
5502 cx.spawn(async move |lsp_store, cx| {
5503 let resolved_hint = resolve_task.await;
5504 lsp_store
5505 .update(cx, |lsp_store, _| {
5506 if let Some(old_inlay_hint) = lsp_store
5507 .lsp_data
5508 .get_mut(&buffer_id)
5509 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5510 {
5511 match resolved_hint {
5512 Ok(resolved_hint) => {
5513 *old_inlay_hint = resolved_hint;
5514 }
5515 Err(e) => {
5516 old_inlay_hint.resolve_state =
5517 ResolveState::CanResolve(server_id, resolve_data);
5518 log::error!("Inlay hint resolve failed: {e:#}");
5519 }
5520 }
5521 }
5522 })
5523 .ok();
5524 })
5525 .shared(),
5526 );
5527 debug_assert!(
5528 previous_task.is_none(),
5529 "Did not change hint's resolve state after spawning its resolve"
5530 );
5531 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5532 None
5533 }
5534
5535 pub(crate) fn linked_edits(
5536 &mut self,
5537 buffer: &Entity<Buffer>,
5538 position: Anchor,
5539 cx: &mut Context<Self>,
5540 ) -> Task<Result<Vec<Range<Anchor>>>> {
5541 let snapshot = buffer.read(cx).snapshot();
5542 let scope = snapshot.language_scope_at(position);
5543 let Some(server_id) = self
5544 .as_local()
5545 .and_then(|local| {
5546 buffer.update(cx, |buffer, cx| {
5547 local
5548 .language_servers_for_buffer(buffer, cx)
5549 .filter(|(_, server)| {
5550 LinkedEditingRange::check_server_capabilities(server.capabilities())
5551 })
5552 .filter(|(adapter, _)| {
5553 scope
5554 .as_ref()
5555 .map(|scope| scope.language_allowed(&adapter.name))
5556 .unwrap_or(true)
5557 })
5558 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5559 .next()
5560 })
5561 })
5562 .or_else(|| {
5563 self.upstream_client()
5564 .is_some()
5565 .then_some(LanguageServerToQuery::FirstCapable)
5566 })
5567 .filter(|_| {
5568 maybe!({
5569 let language = buffer.read(cx).language_at(position)?;
5570 Some(
5571 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5572 .linked_edits,
5573 )
5574 }) == Some(true)
5575 })
5576 else {
5577 return Task::ready(Ok(Vec::new()));
5578 };
5579
5580 self.request_lsp(
5581 buffer.clone(),
5582 server_id,
5583 LinkedEditingRange { position },
5584 cx,
5585 )
5586 }
5587
5588 fn apply_on_type_formatting(
5589 &mut self,
5590 buffer: Entity<Buffer>,
5591 position: Anchor,
5592 trigger: String,
5593 cx: &mut Context<Self>,
5594 ) -> Task<Result<Option<Transaction>>> {
5595 if let Some((client, project_id)) = self.upstream_client() {
5596 if !self.check_if_capable_for_proto_request(
5597 &buffer,
5598 |capabilities| {
5599 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5600 },
5601 cx,
5602 ) {
5603 return Task::ready(Ok(None));
5604 }
5605 let request = proto::OnTypeFormatting {
5606 project_id,
5607 buffer_id: buffer.read(cx).remote_id().into(),
5608 position: Some(serialize_anchor(&position)),
5609 trigger,
5610 version: serialize_version(&buffer.read(cx).version()),
5611 };
5612 cx.background_spawn(async move {
5613 client
5614 .request(request)
5615 .await?
5616 .transaction
5617 .map(language::proto::deserialize_transaction)
5618 .transpose()
5619 })
5620 } else if let Some(local) = self.as_local_mut() {
5621 let buffer_id = buffer.read(cx).remote_id();
5622 local.buffers_being_formatted.insert(buffer_id);
5623 cx.spawn(async move |this, cx| {
5624 let _cleanup = defer({
5625 let this = this.clone();
5626 let mut cx = cx.clone();
5627 move || {
5628 this.update(&mut cx, |this, _| {
5629 if let Some(local) = this.as_local_mut() {
5630 local.buffers_being_formatted.remove(&buffer_id);
5631 }
5632 })
5633 .ok();
5634 }
5635 });
5636
5637 buffer
5638 .update(cx, |buffer, _| {
5639 buffer.wait_for_edits(Some(position.timestamp()))
5640 })
5641 .await?;
5642 this.update(cx, |this, cx| {
5643 let position = position.to_point_utf16(buffer.read(cx));
5644 this.on_type_format(buffer, position, trigger, false, cx)
5645 })?
5646 .await
5647 })
5648 } else {
5649 Task::ready(Err(anyhow!("No upstream client or local language server")))
5650 }
5651 }
5652
5653 pub fn on_type_format<T: ToPointUtf16>(
5654 &mut self,
5655 buffer: Entity<Buffer>,
5656 position: T,
5657 trigger: String,
5658 push_to_history: bool,
5659 cx: &mut Context<Self>,
5660 ) -> Task<Result<Option<Transaction>>> {
5661 let position = position.to_point_utf16(buffer.read(cx));
5662 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5663 }
5664
5665 fn on_type_format_impl(
5666 &mut self,
5667 buffer: Entity<Buffer>,
5668 position: PointUtf16,
5669 trigger: String,
5670 push_to_history: bool,
5671 cx: &mut Context<Self>,
5672 ) -> Task<Result<Option<Transaction>>> {
5673 let options = buffer.update(cx, |buffer, cx| {
5674 lsp_command::lsp_formatting_options(
5675 language_settings(
5676 buffer.language_at(position).map(|l| l.name()),
5677 buffer.file(),
5678 cx,
5679 )
5680 .as_ref(),
5681 )
5682 });
5683
5684 cx.spawn(async move |this, cx| {
5685 if let Some(waiter) =
5686 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5687 {
5688 waiter.await?;
5689 }
5690 cx.update(|cx| {
5691 this.update(cx, |this, cx| {
5692 this.request_lsp(
5693 buffer.clone(),
5694 LanguageServerToQuery::FirstCapable,
5695 OnTypeFormatting {
5696 position,
5697 trigger,
5698 options,
5699 push_to_history,
5700 },
5701 cx,
5702 )
5703 })
5704 })?
5705 .await
5706 })
5707 }
5708
5709 pub fn definitions(
5710 &mut self,
5711 buffer: &Entity<Buffer>,
5712 position: PointUtf16,
5713 cx: &mut Context<Self>,
5714 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5715 if let Some((upstream_client, project_id)) = self.upstream_client() {
5716 let request = GetDefinitions { position };
5717 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5718 return Task::ready(Ok(None));
5719 }
5720
5721 let request_timeout = ProjectSettings::get_global(cx)
5722 .global_lsp_settings
5723 .get_request_timeout();
5724
5725 let request_task = upstream_client.request_lsp(
5726 project_id,
5727 None,
5728 request_timeout,
5729 cx.background_executor().clone(),
5730 request.to_proto(project_id, buffer.read(cx)),
5731 );
5732 let buffer = buffer.clone();
5733 cx.spawn(async move |weak_lsp_store, cx| {
5734 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5735 return Ok(None);
5736 };
5737 let Some(responses) = request_task.await? else {
5738 return Ok(None);
5739 };
5740 let actions = join_all(responses.payload.into_iter().map(|response| {
5741 GetDefinitions { position }.response_from_proto(
5742 response.response,
5743 lsp_store.clone(),
5744 buffer.clone(),
5745 cx.clone(),
5746 )
5747 }))
5748 .await;
5749
5750 Ok(Some(
5751 actions
5752 .into_iter()
5753 .collect::<Result<Vec<Vec<_>>>>()?
5754 .into_iter()
5755 .flatten()
5756 .dedup()
5757 .collect(),
5758 ))
5759 })
5760 } else {
5761 let definitions_task = self.request_multiple_lsp_locally(
5762 buffer,
5763 Some(position),
5764 GetDefinitions { position },
5765 cx,
5766 );
5767 cx.background_spawn(async move {
5768 Ok(Some(
5769 definitions_task
5770 .await
5771 .into_iter()
5772 .flat_map(|(_, definitions)| definitions)
5773 .dedup()
5774 .collect(),
5775 ))
5776 })
5777 }
5778 }
5779
5780 pub fn declarations(
5781 &mut self,
5782 buffer: &Entity<Buffer>,
5783 position: PointUtf16,
5784 cx: &mut Context<Self>,
5785 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5786 if let Some((upstream_client, project_id)) = self.upstream_client() {
5787 let request = GetDeclarations { position };
5788 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5789 return Task::ready(Ok(None));
5790 }
5791 let request_timeout = ProjectSettings::get_global(cx)
5792 .global_lsp_settings
5793 .get_request_timeout();
5794 let request_task = upstream_client.request_lsp(
5795 project_id,
5796 None,
5797 request_timeout,
5798 cx.background_executor().clone(),
5799 request.to_proto(project_id, buffer.read(cx)),
5800 );
5801 let buffer = buffer.clone();
5802 cx.spawn(async move |weak_lsp_store, cx| {
5803 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5804 return Ok(None);
5805 };
5806 let Some(responses) = request_task.await? else {
5807 return Ok(None);
5808 };
5809 let actions = join_all(responses.payload.into_iter().map(|response| {
5810 GetDeclarations { position }.response_from_proto(
5811 response.response,
5812 lsp_store.clone(),
5813 buffer.clone(),
5814 cx.clone(),
5815 )
5816 }))
5817 .await;
5818
5819 Ok(Some(
5820 actions
5821 .into_iter()
5822 .collect::<Result<Vec<Vec<_>>>>()?
5823 .into_iter()
5824 .flatten()
5825 .dedup()
5826 .collect(),
5827 ))
5828 })
5829 } else {
5830 let declarations_task = self.request_multiple_lsp_locally(
5831 buffer,
5832 Some(position),
5833 GetDeclarations { position },
5834 cx,
5835 );
5836 cx.background_spawn(async move {
5837 Ok(Some(
5838 declarations_task
5839 .await
5840 .into_iter()
5841 .flat_map(|(_, declarations)| declarations)
5842 .dedup()
5843 .collect(),
5844 ))
5845 })
5846 }
5847 }
5848
5849 pub fn type_definitions(
5850 &mut self,
5851 buffer: &Entity<Buffer>,
5852 position: PointUtf16,
5853 cx: &mut Context<Self>,
5854 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5855 if let Some((upstream_client, project_id)) = self.upstream_client() {
5856 let request = GetTypeDefinitions { position };
5857 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5858 return Task::ready(Ok(None));
5859 }
5860 let request_timeout = ProjectSettings::get_global(cx)
5861 .global_lsp_settings
5862 .get_request_timeout();
5863 let request_task = upstream_client.request_lsp(
5864 project_id,
5865 None,
5866 request_timeout,
5867 cx.background_executor().clone(),
5868 request.to_proto(project_id, buffer.read(cx)),
5869 );
5870 let buffer = buffer.clone();
5871 cx.spawn(async move |weak_lsp_store, cx| {
5872 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5873 return Ok(None);
5874 };
5875 let Some(responses) = request_task.await? else {
5876 return Ok(None);
5877 };
5878 let actions = join_all(responses.payload.into_iter().map(|response| {
5879 GetTypeDefinitions { position }.response_from_proto(
5880 response.response,
5881 lsp_store.clone(),
5882 buffer.clone(),
5883 cx.clone(),
5884 )
5885 }))
5886 .await;
5887
5888 Ok(Some(
5889 actions
5890 .into_iter()
5891 .collect::<Result<Vec<Vec<_>>>>()?
5892 .into_iter()
5893 .flatten()
5894 .dedup()
5895 .collect(),
5896 ))
5897 })
5898 } else {
5899 let type_definitions_task = self.request_multiple_lsp_locally(
5900 buffer,
5901 Some(position),
5902 GetTypeDefinitions { position },
5903 cx,
5904 );
5905 cx.background_spawn(async move {
5906 Ok(Some(
5907 type_definitions_task
5908 .await
5909 .into_iter()
5910 .flat_map(|(_, type_definitions)| type_definitions)
5911 .dedup()
5912 .collect(),
5913 ))
5914 })
5915 }
5916 }
5917
5918 pub fn implementations(
5919 &mut self,
5920 buffer: &Entity<Buffer>,
5921 position: PointUtf16,
5922 cx: &mut Context<Self>,
5923 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5924 if let Some((upstream_client, project_id)) = self.upstream_client() {
5925 let request = GetImplementations { position };
5926 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5927 return Task::ready(Ok(None));
5928 }
5929
5930 let request_timeout = ProjectSettings::get_global(cx)
5931 .global_lsp_settings
5932 .get_request_timeout();
5933 let request_task = upstream_client.request_lsp(
5934 project_id,
5935 None,
5936 request_timeout,
5937 cx.background_executor().clone(),
5938 request.to_proto(project_id, buffer.read(cx)),
5939 );
5940 let buffer = buffer.clone();
5941 cx.spawn(async move |weak_lsp_store, cx| {
5942 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5943 return Ok(None);
5944 };
5945 let Some(responses) = request_task.await? else {
5946 return Ok(None);
5947 };
5948 let actions = join_all(responses.payload.into_iter().map(|response| {
5949 GetImplementations { position }.response_from_proto(
5950 response.response,
5951 lsp_store.clone(),
5952 buffer.clone(),
5953 cx.clone(),
5954 )
5955 }))
5956 .await;
5957
5958 Ok(Some(
5959 actions
5960 .into_iter()
5961 .collect::<Result<Vec<Vec<_>>>>()?
5962 .into_iter()
5963 .flatten()
5964 .dedup()
5965 .collect(),
5966 ))
5967 })
5968 } else {
5969 let implementations_task = self.request_multiple_lsp_locally(
5970 buffer,
5971 Some(position),
5972 GetImplementations { position },
5973 cx,
5974 );
5975 cx.background_spawn(async move {
5976 Ok(Some(
5977 implementations_task
5978 .await
5979 .into_iter()
5980 .flat_map(|(_, implementations)| implementations)
5981 .dedup()
5982 .collect(),
5983 ))
5984 })
5985 }
5986 }
5987
5988 pub fn references(
5989 &mut self,
5990 buffer: &Entity<Buffer>,
5991 position: PointUtf16,
5992 cx: &mut Context<Self>,
5993 ) -> Task<Result<Option<Vec<Location>>>> {
5994 if let Some((upstream_client, project_id)) = self.upstream_client() {
5995 let request = GetReferences { position };
5996 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5997 return Task::ready(Ok(None));
5998 }
5999
6000 let request_timeout = ProjectSettings::get_global(cx)
6001 .global_lsp_settings
6002 .get_request_timeout();
6003 let request_task = upstream_client.request_lsp(
6004 project_id,
6005 None,
6006 request_timeout,
6007 cx.background_executor().clone(),
6008 request.to_proto(project_id, buffer.read(cx)),
6009 );
6010 let buffer = buffer.clone();
6011 cx.spawn(async move |weak_lsp_store, cx| {
6012 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6013 return Ok(None);
6014 };
6015 let Some(responses) = request_task.await? else {
6016 return Ok(None);
6017 };
6018
6019 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
6020 GetReferences { position }.response_from_proto(
6021 lsp_response.response,
6022 lsp_store.clone(),
6023 buffer.clone(),
6024 cx.clone(),
6025 )
6026 }))
6027 .await
6028 .into_iter()
6029 .collect::<Result<Vec<Vec<_>>>>()?
6030 .into_iter()
6031 .flatten()
6032 .dedup()
6033 .collect();
6034 Ok(Some(locations))
6035 })
6036 } else {
6037 let references_task = self.request_multiple_lsp_locally(
6038 buffer,
6039 Some(position),
6040 GetReferences { position },
6041 cx,
6042 );
6043 cx.background_spawn(async move {
6044 Ok(Some(
6045 references_task
6046 .await
6047 .into_iter()
6048 .flat_map(|(_, references)| references)
6049 .dedup()
6050 .collect(),
6051 ))
6052 })
6053 }
6054 }
6055
6056 pub fn code_actions(
6057 &mut self,
6058 buffer: &Entity<Buffer>,
6059 range: Range<Anchor>,
6060 kinds: Option<Vec<CodeActionKind>>,
6061 cx: &mut Context<Self>,
6062 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6063 if let Some((upstream_client, project_id)) = self.upstream_client() {
6064 let request = GetCodeActions {
6065 range: range.clone(),
6066 kinds: kinds.clone(),
6067 };
6068 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6069 return Task::ready(Ok(None));
6070 }
6071 let request_timeout = ProjectSettings::get_global(cx)
6072 .global_lsp_settings
6073 .get_request_timeout();
6074 let request_task = upstream_client.request_lsp(
6075 project_id,
6076 None,
6077 request_timeout,
6078 cx.background_executor().clone(),
6079 request.to_proto(project_id, buffer.read(cx)),
6080 );
6081 let buffer = buffer.clone();
6082 cx.spawn(async move |weak_lsp_store, cx| {
6083 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6084 return Ok(None);
6085 };
6086 let Some(responses) = request_task.await? else {
6087 return Ok(None);
6088 };
6089 let actions = join_all(responses.payload.into_iter().map(|response| {
6090 GetCodeActions {
6091 range: range.clone(),
6092 kinds: kinds.clone(),
6093 }
6094 .response_from_proto(
6095 response.response,
6096 lsp_store.clone(),
6097 buffer.clone(),
6098 cx.clone(),
6099 )
6100 }))
6101 .await;
6102
6103 Ok(Some(
6104 actions
6105 .into_iter()
6106 .collect::<Result<Vec<Vec<_>>>>()?
6107 .into_iter()
6108 .flatten()
6109 .collect(),
6110 ))
6111 })
6112 } else {
6113 let all_actions_task = self.request_multiple_lsp_locally(
6114 buffer,
6115 Some(range.start),
6116 GetCodeActions { range, kinds },
6117 cx,
6118 );
6119 cx.background_spawn(async move {
6120 Ok(Some(
6121 all_actions_task
6122 .await
6123 .into_iter()
6124 .flat_map(|(_, actions)| actions)
6125 .collect(),
6126 ))
6127 })
6128 }
6129 }
6130
6131 #[inline(never)]
6132 pub fn completions(
6133 &self,
6134 buffer: &Entity<Buffer>,
6135 position: PointUtf16,
6136 context: CompletionContext,
6137 cx: &mut Context<Self>,
6138 ) -> Task<Result<Vec<CompletionResponse>>> {
6139 let language_registry = self.languages.clone();
6140
6141 if let Some((upstream_client, project_id)) = self.upstream_client() {
6142 let snapshot = buffer.read(cx).snapshot();
6143 let offset = position.to_offset(&snapshot);
6144 let scope = snapshot.language_scope_at(offset);
6145 let capable_lsps = self.all_capable_for_proto_request(
6146 buffer,
6147 |server_name, capabilities| {
6148 capabilities.completion_provider.is_some()
6149 && scope
6150 .as_ref()
6151 .map(|scope| scope.language_allowed(server_name))
6152 .unwrap_or(true)
6153 },
6154 cx,
6155 );
6156 if capable_lsps.is_empty() {
6157 return Task::ready(Ok(Vec::new()));
6158 }
6159
6160 let language = buffer.read(cx).language().cloned();
6161
6162 let buffer = buffer.clone();
6163
6164 cx.spawn(async move |this, cx| {
6165 let requests = join_all(
6166 capable_lsps
6167 .into_iter()
6168 .map(|(id, server_name)| {
6169 let request = GetCompletions {
6170 position,
6171 context: context.clone(),
6172 server_id: Some(id),
6173 };
6174 let buffer = buffer.clone();
6175 let language = language.clone();
6176 let lsp_adapter = language.as_ref().and_then(|language| {
6177 let adapters = language_registry.lsp_adapters(&language.name());
6178 adapters
6179 .iter()
6180 .find(|adapter| adapter.name() == server_name)
6181 .or_else(|| adapters.first())
6182 .cloned()
6183 });
6184 let upstream_client = upstream_client.clone();
6185 let response = this
6186 .update(cx, |this, cx| {
6187 this.send_lsp_proto_request(
6188 buffer,
6189 upstream_client,
6190 project_id,
6191 request,
6192 cx,
6193 )
6194 })
6195 .log_err();
6196 async move {
6197 let response = response?.await.log_err()?;
6198
6199 let completions = populate_labels_for_completions(
6200 response.completions,
6201 language,
6202 lsp_adapter,
6203 )
6204 .await;
6205
6206 Some(CompletionResponse {
6207 completions,
6208 display_options: CompletionDisplayOptions::default(),
6209 is_incomplete: response.is_incomplete,
6210 })
6211 }
6212 })
6213 .collect::<Vec<_>>(),
6214 );
6215 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6216 })
6217 } else if let Some(local) = self.as_local() {
6218 let snapshot = buffer.read(cx).snapshot();
6219 let offset = position.to_offset(&snapshot);
6220 let scope = snapshot.language_scope_at(offset);
6221 let language = snapshot.language().cloned();
6222 let completion_settings = language_settings(
6223 language.as_ref().map(|language| language.name()),
6224 buffer.read(cx).file(),
6225 cx,
6226 )
6227 .completions
6228 .clone();
6229 if !completion_settings.lsp {
6230 return Task::ready(Ok(Vec::new()));
6231 }
6232
6233 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6234 local
6235 .language_servers_for_buffer(buffer, cx)
6236 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6237 .filter(|(adapter, _)| {
6238 scope
6239 .as_ref()
6240 .map(|scope| scope.language_allowed(&adapter.name))
6241 .unwrap_or(true)
6242 })
6243 .map(|(_, server)| server.server_id())
6244 .collect()
6245 });
6246
6247 let buffer = buffer.clone();
6248 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6249 let lsp_timeout = if lsp_timeout > 0 {
6250 Some(Duration::from_millis(lsp_timeout))
6251 } else {
6252 None
6253 };
6254 cx.spawn(async move |this, cx| {
6255 let mut tasks = Vec::with_capacity(server_ids.len());
6256 this.update(cx, |lsp_store, cx| {
6257 for server_id in server_ids {
6258 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6259 let lsp_timeout = lsp_timeout
6260 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6261 let mut timeout = cx.background_spawn(async move {
6262 match lsp_timeout {
6263 Some(lsp_timeout) => {
6264 lsp_timeout.await;
6265 true
6266 },
6267 None => false,
6268 }
6269 }).fuse();
6270 let mut lsp_request = lsp_store.request_lsp(
6271 buffer.clone(),
6272 LanguageServerToQuery::Other(server_id),
6273 GetCompletions {
6274 position,
6275 context: context.clone(),
6276 server_id: Some(server_id),
6277 },
6278 cx,
6279 ).fuse();
6280 let new_task = cx.background_spawn(async move {
6281 select_biased! {
6282 response = lsp_request => anyhow::Ok(Some(response?)),
6283 timeout_happened = timeout => {
6284 if timeout_happened {
6285 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6286 Ok(None)
6287 } else {
6288 let completions = lsp_request.await?;
6289 Ok(Some(completions))
6290 }
6291 },
6292 }
6293 });
6294 tasks.push((lsp_adapter, new_task));
6295 }
6296 })?;
6297
6298 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6299 let completion_response = task.await.ok()??;
6300 let completions = populate_labels_for_completions(
6301 completion_response.completions,
6302 language.clone(),
6303 lsp_adapter,
6304 )
6305 .await;
6306 Some(CompletionResponse {
6307 completions,
6308 display_options: CompletionDisplayOptions::default(),
6309 is_incomplete: completion_response.is_incomplete,
6310 })
6311 });
6312
6313 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6314
6315 Ok(responses.into_iter().flatten().collect())
6316 })
6317 } else {
6318 Task::ready(Err(anyhow!("No upstream client or local language server")))
6319 }
6320 }
6321
6322 pub fn resolve_completions(
6323 &self,
6324 buffer: Entity<Buffer>,
6325 completion_indices: Vec<usize>,
6326 completions: Rc<RefCell<Box<[Completion]>>>,
6327 cx: &mut Context<Self>,
6328 ) -> Task<Result<bool>> {
6329 let client = self.upstream_client();
6330 let buffer_id = buffer.read(cx).remote_id();
6331 let buffer_snapshot = buffer.read(cx).snapshot();
6332
6333 if !self.check_if_capable_for_proto_request(
6334 &buffer,
6335 GetCompletions::can_resolve_completions,
6336 cx,
6337 ) {
6338 return Task::ready(Ok(false));
6339 }
6340 cx.spawn(async move |lsp_store, cx| {
6341 let request_timeout = cx.update(|app| {
6342 ProjectSettings::get_global(app)
6343 .global_lsp_settings
6344 .get_request_timeout()
6345 });
6346
6347 let mut did_resolve = false;
6348 if let Some((client, project_id)) = client {
6349 for completion_index in completion_indices {
6350 let server_id = {
6351 let completion = &completions.borrow()[completion_index];
6352 completion.source.server_id()
6353 };
6354 if let Some(server_id) = server_id {
6355 if Self::resolve_completion_remote(
6356 project_id,
6357 server_id,
6358 buffer_id,
6359 completions.clone(),
6360 completion_index,
6361 client.clone(),
6362 )
6363 .await
6364 .log_err()
6365 .is_some()
6366 {
6367 did_resolve = true;
6368 }
6369 } else {
6370 resolve_word_completion(
6371 &buffer_snapshot,
6372 &mut completions.borrow_mut()[completion_index],
6373 );
6374 }
6375 }
6376 } else {
6377 for completion_index in completion_indices {
6378 let server_id = {
6379 let completion = &completions.borrow()[completion_index];
6380 completion.source.server_id()
6381 };
6382 if let Some(server_id) = server_id {
6383 let server_and_adapter = lsp_store
6384 .read_with(cx, |lsp_store, _| {
6385 let server = lsp_store.language_server_for_id(server_id)?;
6386 let adapter =
6387 lsp_store.language_server_adapter_for_id(server.server_id())?;
6388 Some((server, adapter))
6389 })
6390 .ok()
6391 .flatten();
6392 let Some((server, adapter)) = server_and_adapter else {
6393 continue;
6394 };
6395
6396 let resolved = Self::resolve_completion_local(
6397 server,
6398 completions.clone(),
6399 completion_index,
6400 request_timeout,
6401 )
6402 .await
6403 .log_err()
6404 .is_some();
6405 if resolved {
6406 Self::regenerate_completion_labels(
6407 adapter,
6408 &buffer_snapshot,
6409 completions.clone(),
6410 completion_index,
6411 )
6412 .await
6413 .log_err();
6414 did_resolve = true;
6415 }
6416 } else {
6417 resolve_word_completion(
6418 &buffer_snapshot,
6419 &mut completions.borrow_mut()[completion_index],
6420 );
6421 }
6422 }
6423 }
6424
6425 Ok(did_resolve)
6426 })
6427 }
6428
6429 async fn resolve_completion_local(
6430 server: Arc<lsp::LanguageServer>,
6431 completions: Rc<RefCell<Box<[Completion]>>>,
6432 completion_index: usize,
6433 request_timeout: Duration,
6434 ) -> Result<()> {
6435 let server_id = server.server_id();
6436 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6437 return Ok(());
6438 }
6439
6440 let request = {
6441 let completion = &completions.borrow()[completion_index];
6442 match &completion.source {
6443 CompletionSource::Lsp {
6444 lsp_completion,
6445 resolved,
6446 server_id: completion_server_id,
6447 ..
6448 } => {
6449 if *resolved {
6450 return Ok(());
6451 }
6452 anyhow::ensure!(
6453 server_id == *completion_server_id,
6454 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6455 );
6456 server.request::<lsp::request::ResolveCompletionItem>(
6457 *lsp_completion.clone(),
6458 request_timeout,
6459 )
6460 }
6461 CompletionSource::BufferWord { .. }
6462 | CompletionSource::Dap { .. }
6463 | CompletionSource::Custom => {
6464 return Ok(());
6465 }
6466 }
6467 };
6468 let resolved_completion = request
6469 .await
6470 .into_response()
6471 .context("resolve completion")?;
6472
6473 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6474 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6475
6476 let mut completions = completions.borrow_mut();
6477 let completion = &mut completions[completion_index];
6478 if let CompletionSource::Lsp {
6479 lsp_completion,
6480 resolved,
6481 server_id: completion_server_id,
6482 ..
6483 } = &mut completion.source
6484 {
6485 if *resolved {
6486 return Ok(());
6487 }
6488 anyhow::ensure!(
6489 server_id == *completion_server_id,
6490 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6491 );
6492 **lsp_completion = resolved_completion;
6493 *resolved = true;
6494 }
6495 Ok(())
6496 }
6497
6498 async fn regenerate_completion_labels(
6499 adapter: Arc<CachedLspAdapter>,
6500 snapshot: &BufferSnapshot,
6501 completions: Rc<RefCell<Box<[Completion]>>>,
6502 completion_index: usize,
6503 ) -> Result<()> {
6504 let completion_item = completions.borrow()[completion_index]
6505 .source
6506 .lsp_completion(true)
6507 .map(Cow::into_owned);
6508 if let Some(lsp_documentation) = completion_item
6509 .as_ref()
6510 .and_then(|completion_item| completion_item.documentation.clone())
6511 {
6512 let mut completions = completions.borrow_mut();
6513 let completion = &mut completions[completion_index];
6514 completion.documentation = Some(lsp_documentation.into());
6515 } else {
6516 let mut completions = completions.borrow_mut();
6517 let completion = &mut completions[completion_index];
6518 completion.documentation = Some(CompletionDocumentation::Undocumented);
6519 }
6520
6521 let mut new_label = match completion_item {
6522 Some(completion_item) => {
6523 // Some language servers always return `detail` lazily via resolve, regardless of
6524 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6525 // See: https://github.com/yioneko/vtsls/issues/213
6526 let language = snapshot.language();
6527 match language {
6528 Some(language) => {
6529 adapter
6530 .labels_for_completions(
6531 std::slice::from_ref(&completion_item),
6532 language,
6533 )
6534 .await?
6535 }
6536 None => Vec::new(),
6537 }
6538 .pop()
6539 .flatten()
6540 .unwrap_or_else(|| {
6541 CodeLabel::fallback_for_completion(
6542 &completion_item,
6543 language.map(|language| language.as_ref()),
6544 )
6545 })
6546 }
6547 None => CodeLabel::plain(
6548 completions.borrow()[completion_index].new_text.clone(),
6549 None,
6550 ),
6551 };
6552 ensure_uniform_list_compatible_label(&mut new_label);
6553
6554 let mut completions = completions.borrow_mut();
6555 let completion = &mut completions[completion_index];
6556 if completion.label.filter_text() == new_label.filter_text() {
6557 completion.label = new_label;
6558 } else {
6559 log::error!(
6560 "Resolved completion changed display label from {} to {}. \
6561 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6562 completion.label.text(),
6563 new_label.text(),
6564 completion.label.filter_text(),
6565 new_label.filter_text()
6566 );
6567 }
6568
6569 Ok(())
6570 }
6571
6572 async fn resolve_completion_remote(
6573 project_id: u64,
6574 server_id: LanguageServerId,
6575 buffer_id: BufferId,
6576 completions: Rc<RefCell<Box<[Completion]>>>,
6577 completion_index: usize,
6578 client: AnyProtoClient,
6579 ) -> Result<()> {
6580 let lsp_completion = {
6581 let completion = &completions.borrow()[completion_index];
6582 match &completion.source {
6583 CompletionSource::Lsp {
6584 lsp_completion,
6585 resolved,
6586 server_id: completion_server_id,
6587 ..
6588 } => {
6589 anyhow::ensure!(
6590 server_id == *completion_server_id,
6591 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6592 );
6593 if *resolved {
6594 return Ok(());
6595 }
6596 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6597 }
6598 CompletionSource::Custom
6599 | CompletionSource::Dap { .. }
6600 | CompletionSource::BufferWord { .. } => {
6601 return Ok(());
6602 }
6603 }
6604 };
6605 let request = proto::ResolveCompletionDocumentation {
6606 project_id,
6607 language_server_id: server_id.0 as u64,
6608 lsp_completion,
6609 buffer_id: buffer_id.into(),
6610 };
6611
6612 let response = client
6613 .request(request)
6614 .await
6615 .context("completion documentation resolve proto request")?;
6616 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6617
6618 let documentation = if response.documentation.is_empty() {
6619 CompletionDocumentation::Undocumented
6620 } else if response.documentation_is_markdown {
6621 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6622 } else if response.documentation.lines().count() <= 1 {
6623 CompletionDocumentation::SingleLine(response.documentation.into())
6624 } else {
6625 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6626 };
6627
6628 let mut completions = completions.borrow_mut();
6629 let completion = &mut completions[completion_index];
6630 completion.documentation = Some(documentation);
6631 if let CompletionSource::Lsp {
6632 insert_range,
6633 lsp_completion,
6634 resolved,
6635 server_id: completion_server_id,
6636 lsp_defaults: _,
6637 } = &mut completion.source
6638 {
6639 let completion_insert_range = response
6640 .old_insert_start
6641 .and_then(deserialize_anchor)
6642 .zip(response.old_insert_end.and_then(deserialize_anchor));
6643 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6644
6645 if *resolved {
6646 return Ok(());
6647 }
6648 anyhow::ensure!(
6649 server_id == *completion_server_id,
6650 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6651 );
6652 **lsp_completion = resolved_lsp_completion;
6653 *resolved = true;
6654 }
6655
6656 let replace_range = response
6657 .old_replace_start
6658 .and_then(deserialize_anchor)
6659 .zip(response.old_replace_end.and_then(deserialize_anchor));
6660 if let Some((old_replace_start, old_replace_end)) = replace_range
6661 && !response.new_text.is_empty()
6662 {
6663 completion.new_text = response.new_text;
6664 completion.replace_range = old_replace_start..old_replace_end;
6665 }
6666
6667 Ok(())
6668 }
6669
6670 pub fn apply_additional_edits_for_completion(
6671 &self,
6672 buffer_handle: Entity<Buffer>,
6673 completions: Rc<RefCell<Box<[Completion]>>>,
6674 completion_index: usize,
6675 push_to_history: bool,
6676 all_commit_ranges: Vec<Range<language::Anchor>>,
6677 cx: &mut Context<Self>,
6678 ) -> Task<Result<Option<Transaction>>> {
6679 if let Some((client, project_id)) = self.upstream_client() {
6680 let buffer = buffer_handle.read(cx);
6681 let buffer_id = buffer.remote_id();
6682 cx.spawn(async move |_, cx| {
6683 let request = {
6684 let completion = completions.borrow()[completion_index].clone();
6685 proto::ApplyCompletionAdditionalEdits {
6686 project_id,
6687 buffer_id: buffer_id.into(),
6688 completion: Some(Self::serialize_completion(&CoreCompletion {
6689 replace_range: completion.replace_range,
6690 new_text: completion.new_text,
6691 source: completion.source,
6692 })),
6693 all_commit_ranges: all_commit_ranges
6694 .iter()
6695 .cloned()
6696 .map(language::proto::serialize_anchor_range)
6697 .collect(),
6698 }
6699 };
6700
6701 let Some(transaction) = client.request(request).await?.transaction else {
6702 return Ok(None);
6703 };
6704
6705 let transaction = language::proto::deserialize_transaction(transaction)?;
6706 buffer_handle
6707 .update(cx, |buffer, _| {
6708 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6709 })
6710 .await?;
6711 if push_to_history {
6712 buffer_handle.update(cx, |buffer, _| {
6713 buffer.push_transaction(transaction.clone(), Instant::now());
6714 buffer.finalize_last_transaction();
6715 });
6716 }
6717 Ok(Some(transaction))
6718 })
6719 } else {
6720 let request_timeout = ProjectSettings::get_global(cx)
6721 .global_lsp_settings
6722 .get_request_timeout();
6723
6724 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6725 let completion = &completions.borrow()[completion_index];
6726 let server_id = completion.source.server_id()?;
6727 Some(
6728 self.language_server_for_local_buffer(buffer, server_id, cx)?
6729 .1
6730 .clone(),
6731 )
6732 }) else {
6733 return Task::ready(Ok(None));
6734 };
6735
6736 cx.spawn(async move |this, cx| {
6737 Self::resolve_completion_local(
6738 server.clone(),
6739 completions.clone(),
6740 completion_index,
6741 request_timeout,
6742 )
6743 .await
6744 .context("resolving completion")?;
6745 let completion = completions.borrow()[completion_index].clone();
6746 let additional_text_edits = completion
6747 .source
6748 .lsp_completion(true)
6749 .as_ref()
6750 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6751 if let Some(edits) = additional_text_edits {
6752 let edits = this
6753 .update(cx, |this, cx| {
6754 this.as_local_mut().unwrap().edits_from_lsp(
6755 &buffer_handle,
6756 edits,
6757 server.server_id(),
6758 None,
6759 cx,
6760 )
6761 })?
6762 .await?;
6763
6764 buffer_handle.update(cx, |buffer, cx| {
6765 buffer.finalize_last_transaction();
6766 buffer.start_transaction();
6767
6768 for (range, text) in edits {
6769 let primary = &completion.replace_range;
6770
6771 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6772 // and the primary completion is just an insertion (empty range), then this is likely
6773 // an auto-import scenario and should not be considered overlapping
6774 // https://github.com/zed-industries/zed/issues/26136
6775 let is_file_start_auto_import = {
6776 let snapshot = buffer.snapshot();
6777 let primary_start_point = primary.start.to_point(&snapshot);
6778 let range_start_point = range.start.to_point(&snapshot);
6779
6780 let result = primary_start_point.row == 0
6781 && primary_start_point.column == 0
6782 && range_start_point.row == 0
6783 && range_start_point.column == 0;
6784
6785 result
6786 };
6787
6788 let has_overlap = if is_file_start_auto_import {
6789 false
6790 } else {
6791 all_commit_ranges.iter().any(|commit_range| {
6792 let start_within =
6793 commit_range.start.cmp(&range.start, buffer).is_le()
6794 && commit_range.end.cmp(&range.start, buffer).is_ge();
6795 let end_within =
6796 range.start.cmp(&commit_range.end, buffer).is_le()
6797 && range.end.cmp(&commit_range.end, buffer).is_ge();
6798 start_within || end_within
6799 })
6800 };
6801
6802 //Skip additional edits which overlap with the primary completion edit
6803 //https://github.com/zed-industries/zed/pull/1871
6804 if !has_overlap {
6805 buffer.edit([(range, text)], None, cx);
6806 }
6807 }
6808
6809 let transaction = if buffer.end_transaction(cx).is_some() {
6810 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6811 if !push_to_history {
6812 buffer.forget_transaction(transaction.id);
6813 }
6814 Some(transaction)
6815 } else {
6816 None
6817 };
6818 Ok(transaction)
6819 })
6820 } else {
6821 Ok(None)
6822 }
6823 })
6824 }
6825 }
6826
6827 pub fn pull_diagnostics(
6828 &mut self,
6829 buffer: Entity<Buffer>,
6830 cx: &mut Context<Self>,
6831 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6832 let buffer_id = buffer.read(cx).remote_id();
6833
6834 if let Some((client, upstream_project_id)) = self.upstream_client() {
6835 let mut suitable_capabilities = None;
6836 // Are we capable for proto request?
6837 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6838 &buffer,
6839 |capabilities| {
6840 if let Some(caps) = &capabilities.diagnostic_provider {
6841 suitable_capabilities = Some(caps.clone());
6842 true
6843 } else {
6844 false
6845 }
6846 },
6847 cx,
6848 );
6849 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6850 let Some(dynamic_caps) = suitable_capabilities else {
6851 return Task::ready(Ok(None));
6852 };
6853 assert!(any_server_has_diagnostics_provider);
6854
6855 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6856 let request = GetDocumentDiagnostics {
6857 previous_result_id: None,
6858 identifier,
6859 registration_id: None,
6860 };
6861 let request_timeout = ProjectSettings::get_global(cx)
6862 .global_lsp_settings
6863 .get_request_timeout();
6864 let request_task = client.request_lsp(
6865 upstream_project_id,
6866 None,
6867 request_timeout,
6868 cx.background_executor().clone(),
6869 request.to_proto(upstream_project_id, buffer.read(cx)),
6870 );
6871 cx.background_spawn(async move {
6872 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6873 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6874 // Do not attempt to further process the dummy responses here.
6875 let _response = request_task.await?;
6876 Ok(None)
6877 })
6878 } else {
6879 let servers = buffer.update(cx, |buffer, cx| {
6880 self.running_language_servers_for_local_buffer(buffer, cx)
6881 .map(|(_, server)| server.clone())
6882 .collect::<Vec<_>>()
6883 });
6884
6885 let pull_diagnostics = servers
6886 .into_iter()
6887 .flat_map(|server| {
6888 let result = maybe!({
6889 let local = self.as_local()?;
6890 let server_id = server.server_id();
6891 let providers_with_identifiers = local
6892 .language_server_dynamic_registrations
6893 .get(&server_id)
6894 .into_iter()
6895 .flat_map(|registrations| registrations.diagnostics.clone())
6896 .collect::<Vec<_>>();
6897 Some(
6898 providers_with_identifiers
6899 .into_iter()
6900 .map(|(registration_id, dynamic_caps)| {
6901 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6902 let registration_id = registration_id.map(SharedString::from);
6903 let result_id = self.result_id_for_buffer_pull(
6904 server_id,
6905 buffer_id,
6906 ®istration_id,
6907 cx,
6908 );
6909 self.request_lsp(
6910 buffer.clone(),
6911 LanguageServerToQuery::Other(server_id),
6912 GetDocumentDiagnostics {
6913 previous_result_id: result_id,
6914 registration_id,
6915 identifier,
6916 },
6917 cx,
6918 )
6919 })
6920 .collect::<Vec<_>>(),
6921 )
6922 });
6923
6924 result.unwrap_or_default()
6925 })
6926 .collect::<Vec<_>>();
6927
6928 cx.background_spawn(async move {
6929 let mut responses = Vec::new();
6930 for diagnostics in join_all(pull_diagnostics).await {
6931 responses.extend(diagnostics?);
6932 }
6933 Ok(Some(responses))
6934 })
6935 }
6936 }
6937
6938 pub fn applicable_inlay_chunks(
6939 &mut self,
6940 buffer: &Entity<Buffer>,
6941 ranges: &[Range<text::Anchor>],
6942 cx: &mut Context<Self>,
6943 ) -> Vec<Range<BufferRow>> {
6944 let buffer_snapshot = buffer.read(cx).snapshot();
6945 let ranges = ranges
6946 .iter()
6947 .map(|range| range.to_point(&buffer_snapshot))
6948 .collect::<Vec<_>>();
6949
6950 self.latest_lsp_data(buffer, cx)
6951 .inlay_hints
6952 .applicable_chunks(ranges.as_slice())
6953 .map(|chunk| chunk.row_range())
6954 .collect()
6955 }
6956
6957 pub fn invalidate_inlay_hints<'a>(
6958 &'a mut self,
6959 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6960 ) {
6961 for buffer_id in for_buffers {
6962 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6963 lsp_data.inlay_hints.clear();
6964 }
6965 }
6966 }
6967
6968 pub fn inlay_hints(
6969 &mut self,
6970 invalidate: InvalidationStrategy,
6971 buffer: Entity<Buffer>,
6972 ranges: Vec<Range<text::Anchor>>,
6973 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6974 cx: &mut Context<Self>,
6975 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6976 let next_hint_id = self.next_hint_id.clone();
6977 let lsp_data = self.latest_lsp_data(&buffer, cx);
6978 let query_version = lsp_data.buffer_version.clone();
6979 let mut lsp_refresh_requested = false;
6980 let for_server = if let InvalidationStrategy::RefreshRequested {
6981 server_id,
6982 request_id,
6983 } = invalidate
6984 {
6985 let invalidated = lsp_data
6986 .inlay_hints
6987 .invalidate_for_server_refresh(server_id, request_id);
6988 lsp_refresh_requested = invalidated;
6989 Some(server_id)
6990 } else {
6991 None
6992 };
6993 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6994 let known_chunks = known_chunks
6995 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6996 .map(|(_, known_chunks)| known_chunks)
6997 .unwrap_or_default();
6998
6999 let buffer_snapshot = buffer.read(cx).snapshot();
7000 let ranges = ranges
7001 .iter()
7002 .map(|range| range.to_point(&buffer_snapshot))
7003 .collect::<Vec<_>>();
7004
7005 let mut hint_fetch_tasks = Vec::new();
7006 let mut cached_inlay_hints = None;
7007 let mut ranges_to_query = None;
7008 let applicable_chunks = existing_inlay_hints
7009 .applicable_chunks(ranges.as_slice())
7010 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
7011 .collect::<Vec<_>>();
7012 if applicable_chunks.is_empty() {
7013 return HashMap::default();
7014 }
7015
7016 for row_chunk in applicable_chunks {
7017 match (
7018 existing_inlay_hints
7019 .cached_hints(&row_chunk)
7020 .filter(|_| !lsp_refresh_requested)
7021 .cloned(),
7022 existing_inlay_hints
7023 .fetched_hints(&row_chunk)
7024 .as_ref()
7025 .filter(|_| !lsp_refresh_requested)
7026 .cloned(),
7027 ) {
7028 (None, None) => {
7029 let chunk_range = row_chunk.anchor_range();
7030 ranges_to_query
7031 .get_or_insert_with(Vec::new)
7032 .push((row_chunk, chunk_range));
7033 }
7034 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
7035 (Some(cached_hints), None) => {
7036 for (server_id, cached_hints) in cached_hints {
7037 if for_server.is_none_or(|for_server| for_server == server_id) {
7038 cached_inlay_hints
7039 .get_or_insert_with(HashMap::default)
7040 .entry(row_chunk.row_range())
7041 .or_insert_with(HashMap::default)
7042 .entry(server_id)
7043 .or_insert_with(Vec::new)
7044 .extend(cached_hints);
7045 }
7046 }
7047 }
7048 (Some(cached_hints), Some(fetched_hints)) => {
7049 hint_fetch_tasks.push((row_chunk, fetched_hints));
7050 for (server_id, cached_hints) in cached_hints {
7051 if for_server.is_none_or(|for_server| for_server == server_id) {
7052 cached_inlay_hints
7053 .get_or_insert_with(HashMap::default)
7054 .entry(row_chunk.row_range())
7055 .or_insert_with(HashMap::default)
7056 .entry(server_id)
7057 .or_insert_with(Vec::new)
7058 .extend(cached_hints);
7059 }
7060 }
7061 }
7062 }
7063 }
7064
7065 if hint_fetch_tasks.is_empty()
7066 && ranges_to_query
7067 .as_ref()
7068 .is_none_or(|ranges| ranges.is_empty())
7069 && let Some(cached_inlay_hints) = cached_inlay_hints
7070 {
7071 cached_inlay_hints
7072 .into_iter()
7073 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7074 .collect()
7075 } else {
7076 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7077 // When a server refresh was requested, other servers' cached hints
7078 // are unaffected by the refresh and must be included in the result.
7079 // Otherwise apply_fetched_hints (with should_invalidate()=true)
7080 // removes all visible hints but only adds back the requesting
7081 // server's new hints, permanently losing other servers' hints.
7082 let other_servers_cached: CacheInlayHints = if lsp_refresh_requested {
7083 lsp_data
7084 .inlay_hints
7085 .cached_hints(&chunk)
7086 .cloned()
7087 .unwrap_or_default()
7088 } else {
7089 HashMap::default()
7090 };
7091
7092 let next_hint_id = next_hint_id.clone();
7093 let buffer = buffer.clone();
7094 let query_version = query_version.clone();
7095 let new_inlay_hints = cx
7096 .spawn(async move |lsp_store, cx| {
7097 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7098 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7099 })?;
7100 new_fetch_task
7101 .await
7102 .and_then(|new_hints_by_server| {
7103 lsp_store.update(cx, |lsp_store, cx| {
7104 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7105 let update_cache = lsp_data.buffer_version == query_version;
7106 if new_hints_by_server.is_empty() {
7107 if update_cache {
7108 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7109 }
7110 other_servers_cached
7111 } else {
7112 let mut result = other_servers_cached;
7113 for (server_id, new_hints) in new_hints_by_server {
7114 let new_hints = new_hints
7115 .into_iter()
7116 .map(|new_hint| {
7117 (
7118 InlayId::Hint(next_hint_id.fetch_add(
7119 1,
7120 atomic::Ordering::AcqRel,
7121 )),
7122 new_hint,
7123 )
7124 })
7125 .collect::<Vec<_>>();
7126 if update_cache {
7127 lsp_data.inlay_hints.insert_new_hints(
7128 chunk,
7129 server_id,
7130 new_hints.clone(),
7131 );
7132 }
7133 result.insert(server_id, new_hints);
7134 }
7135 result
7136 }
7137 })
7138 })
7139 .map_err(Arc::new)
7140 })
7141 .shared();
7142
7143 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7144 *fetch_task = Some(new_inlay_hints.clone());
7145 hint_fetch_tasks.push((chunk, new_inlay_hints));
7146 }
7147
7148 cached_inlay_hints
7149 .unwrap_or_default()
7150 .into_iter()
7151 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7152 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7153 (
7154 chunk.row_range(),
7155 cx.spawn(async move |_, _| {
7156 hints_fetch.await.map_err(|e| {
7157 if e.error_code() != ErrorCode::Internal {
7158 anyhow!(e.error_code())
7159 } else {
7160 anyhow!("{e:#}")
7161 }
7162 })
7163 }),
7164 )
7165 }))
7166 .collect()
7167 }
7168 }
7169
7170 fn fetch_inlay_hints(
7171 &mut self,
7172 for_server: Option<LanguageServerId>,
7173 buffer: &Entity<Buffer>,
7174 range: Range<Anchor>,
7175 cx: &mut Context<Self>,
7176 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7177 let request = InlayHints {
7178 range: range.clone(),
7179 };
7180 if let Some((upstream_client, project_id)) = self.upstream_client() {
7181 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7182 return Task::ready(Ok(HashMap::default()));
7183 }
7184 let request_timeout = ProjectSettings::get_global(cx)
7185 .global_lsp_settings
7186 .get_request_timeout();
7187 let request_task = upstream_client.request_lsp(
7188 project_id,
7189 for_server.map(|id| id.to_proto()),
7190 request_timeout,
7191 cx.background_executor().clone(),
7192 request.to_proto(project_id, buffer.read(cx)),
7193 );
7194 let buffer = buffer.clone();
7195 cx.spawn(async move |weak_lsp_store, cx| {
7196 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7197 return Ok(HashMap::default());
7198 };
7199 let Some(responses) = request_task.await? else {
7200 return Ok(HashMap::default());
7201 };
7202
7203 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7204 let lsp_store = lsp_store.clone();
7205 let buffer = buffer.clone();
7206 let cx = cx.clone();
7207 let request = request.clone();
7208 async move {
7209 (
7210 LanguageServerId::from_proto(response.server_id),
7211 request
7212 .response_from_proto(response.response, lsp_store, buffer, cx)
7213 .await,
7214 )
7215 }
7216 }))
7217 .await;
7218
7219 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7220 let mut has_errors = false;
7221 let inlay_hints = inlay_hints
7222 .into_iter()
7223 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7224 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7225 Err(e) => {
7226 has_errors = true;
7227 log::error!("{e:#}");
7228 None
7229 }
7230 })
7231 .map(|(server_id, mut new_hints)| {
7232 new_hints.retain(|hint| {
7233 hint.position.is_valid(&buffer_snapshot)
7234 && range.start.is_valid(&buffer_snapshot)
7235 && range.end.is_valid(&buffer_snapshot)
7236 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7237 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7238 });
7239 (server_id, new_hints)
7240 })
7241 .collect::<HashMap<_, _>>();
7242 anyhow::ensure!(
7243 !has_errors || !inlay_hints.is_empty(),
7244 "Failed to fetch inlay hints"
7245 );
7246 Ok(inlay_hints)
7247 })
7248 } else {
7249 let inlay_hints_task = match for_server {
7250 Some(server_id) => {
7251 let server_task = self.request_lsp(
7252 buffer.clone(),
7253 LanguageServerToQuery::Other(server_id),
7254 request,
7255 cx,
7256 );
7257 cx.background_spawn(async move {
7258 let mut responses = Vec::new();
7259 match server_task.await {
7260 Ok(response) => responses.push((server_id, response)),
7261 // rust-analyzer likes to error with this when its still loading up
7262 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7263 Err(e) => log::error!(
7264 "Error handling response for inlay hints request: {e:#}"
7265 ),
7266 }
7267 responses
7268 })
7269 }
7270 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7271 };
7272 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7273 cx.background_spawn(async move {
7274 Ok(inlay_hints_task
7275 .await
7276 .into_iter()
7277 .map(|(server_id, mut new_hints)| {
7278 new_hints.retain(|hint| {
7279 hint.position.is_valid(&buffer_snapshot)
7280 && range.start.is_valid(&buffer_snapshot)
7281 && range.end.is_valid(&buffer_snapshot)
7282 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7283 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7284 });
7285 (server_id, new_hints)
7286 })
7287 .collect())
7288 })
7289 }
7290 }
7291
7292 fn diagnostic_registration_exists(
7293 &self,
7294 server_id: LanguageServerId,
7295 registration_id: &Option<SharedString>,
7296 ) -> bool {
7297 let Some(local) = self.as_local() else {
7298 return false;
7299 };
7300 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7301 else {
7302 return false;
7303 };
7304 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7305 registrations.diagnostics.contains_key(®istration_key)
7306 }
7307
7308 pub fn pull_diagnostics_for_buffer(
7309 &mut self,
7310 buffer: Entity<Buffer>,
7311 cx: &mut Context<Self>,
7312 ) -> Task<anyhow::Result<()>> {
7313 let diagnostics = self.pull_diagnostics(buffer, cx);
7314 cx.spawn(async move |lsp_store, cx| {
7315 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7316 return Ok(());
7317 };
7318 lsp_store.update(cx, |lsp_store, cx| {
7319 if lsp_store.as_local().is_none() {
7320 return;
7321 }
7322
7323 let mut unchanged_buffers = HashMap::default();
7324 let server_diagnostics_updates = diagnostics
7325 .into_iter()
7326 .filter_map(|diagnostics_set| match diagnostics_set {
7327 LspPullDiagnostics::Response {
7328 server_id,
7329 uri,
7330 diagnostics,
7331 registration_id,
7332 } => Some((server_id, uri, diagnostics, registration_id)),
7333 LspPullDiagnostics::Default => None,
7334 })
7335 .filter(|(server_id, _, _, registration_id)| {
7336 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7337 })
7338 .fold(
7339 HashMap::default(),
7340 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7341 let (result_id, diagnostics) = match diagnostics {
7342 PulledDiagnostics::Unchanged { result_id } => {
7343 unchanged_buffers
7344 .entry(new_registration_id.clone())
7345 .or_insert_with(HashSet::default)
7346 .insert(uri.clone());
7347 (Some(result_id), Vec::new())
7348 }
7349 PulledDiagnostics::Changed {
7350 result_id,
7351 diagnostics,
7352 } => (result_id, diagnostics),
7353 };
7354 let disk_based_sources = Cow::Owned(
7355 lsp_store
7356 .language_server_adapter_for_id(server_id)
7357 .as_ref()
7358 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7359 .unwrap_or(&[])
7360 .to_vec(),
7361 );
7362 acc.entry(server_id)
7363 .or_insert_with(HashMap::default)
7364 .entry(new_registration_id.clone())
7365 .or_insert_with(Vec::new)
7366 .push(DocumentDiagnosticsUpdate {
7367 server_id,
7368 diagnostics: lsp::PublishDiagnosticsParams {
7369 uri,
7370 diagnostics,
7371 version: None,
7372 },
7373 result_id: result_id.map(SharedString::new),
7374 disk_based_sources,
7375 registration_id: new_registration_id,
7376 });
7377 acc
7378 },
7379 );
7380
7381 for diagnostic_updates in server_diagnostics_updates.into_values() {
7382 for (registration_id, diagnostic_updates) in diagnostic_updates {
7383 lsp_store
7384 .merge_lsp_diagnostics(
7385 DiagnosticSourceKind::Pulled,
7386 diagnostic_updates,
7387 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7388 DiagnosticSourceKind::Pulled => {
7389 old_diagnostic.registration_id != registration_id
7390 || unchanged_buffers
7391 .get(&old_diagnostic.registration_id)
7392 .is_some_and(|unchanged_buffers| {
7393 unchanged_buffers.contains(&document_uri)
7394 })
7395 }
7396 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7397 true
7398 }
7399 },
7400 cx,
7401 )
7402 .log_err();
7403 }
7404 }
7405 })
7406 })
7407 }
7408
7409 pub fn signature_help<T: ToPointUtf16>(
7410 &mut self,
7411 buffer: &Entity<Buffer>,
7412 position: T,
7413 cx: &mut Context<Self>,
7414 ) -> Task<Option<Vec<SignatureHelp>>> {
7415 let position = position.to_point_utf16(buffer.read(cx));
7416
7417 if let Some((client, upstream_project_id)) = self.upstream_client() {
7418 let request = GetSignatureHelp { position };
7419 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7420 return Task::ready(None);
7421 }
7422 let request_timeout = ProjectSettings::get_global(cx)
7423 .global_lsp_settings
7424 .get_request_timeout();
7425 let request_task = client.request_lsp(
7426 upstream_project_id,
7427 None,
7428 request_timeout,
7429 cx.background_executor().clone(),
7430 request.to_proto(upstream_project_id, buffer.read(cx)),
7431 );
7432 let buffer = buffer.clone();
7433 cx.spawn(async move |weak_lsp_store, cx| {
7434 let lsp_store = weak_lsp_store.upgrade()?;
7435 let signatures = join_all(
7436 request_task
7437 .await
7438 .log_err()
7439 .flatten()
7440 .map(|response| response.payload)
7441 .unwrap_or_default()
7442 .into_iter()
7443 .map(|response| {
7444 let response = GetSignatureHelp { position }.response_from_proto(
7445 response.response,
7446 lsp_store.clone(),
7447 buffer.clone(),
7448 cx.clone(),
7449 );
7450 async move { response.await.log_err().flatten() }
7451 }),
7452 )
7453 .await
7454 .into_iter()
7455 .flatten()
7456 .collect();
7457 Some(signatures)
7458 })
7459 } else {
7460 let all_actions_task = self.request_multiple_lsp_locally(
7461 buffer,
7462 Some(position),
7463 GetSignatureHelp { position },
7464 cx,
7465 );
7466 cx.background_spawn(async move {
7467 Some(
7468 all_actions_task
7469 .await
7470 .into_iter()
7471 .flat_map(|(_, actions)| actions)
7472 .collect::<Vec<_>>(),
7473 )
7474 })
7475 }
7476 }
7477
7478 pub fn hover(
7479 &mut self,
7480 buffer: &Entity<Buffer>,
7481 position: PointUtf16,
7482 cx: &mut Context<Self>,
7483 ) -> Task<Option<Vec<Hover>>> {
7484 if let Some((client, upstream_project_id)) = self.upstream_client() {
7485 let request = GetHover { position };
7486 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7487 return Task::ready(None);
7488 }
7489 let request_timeout = ProjectSettings::get_global(cx)
7490 .global_lsp_settings
7491 .get_request_timeout();
7492 let request_task = client.request_lsp(
7493 upstream_project_id,
7494 None,
7495 request_timeout,
7496 cx.background_executor().clone(),
7497 request.to_proto(upstream_project_id, buffer.read(cx)),
7498 );
7499 let buffer = buffer.clone();
7500 cx.spawn(async move |weak_lsp_store, cx| {
7501 let lsp_store = weak_lsp_store.upgrade()?;
7502 let hovers = join_all(
7503 request_task
7504 .await
7505 .log_err()
7506 .flatten()
7507 .map(|response| response.payload)
7508 .unwrap_or_default()
7509 .into_iter()
7510 .map(|response| {
7511 let response = GetHover { position }.response_from_proto(
7512 response.response,
7513 lsp_store.clone(),
7514 buffer.clone(),
7515 cx.clone(),
7516 );
7517 async move {
7518 response
7519 .await
7520 .log_err()
7521 .flatten()
7522 .and_then(remove_empty_hover_blocks)
7523 }
7524 }),
7525 )
7526 .await
7527 .into_iter()
7528 .flatten()
7529 .collect();
7530 Some(hovers)
7531 })
7532 } else {
7533 let all_actions_task = self.request_multiple_lsp_locally(
7534 buffer,
7535 Some(position),
7536 GetHover { position },
7537 cx,
7538 );
7539 cx.background_spawn(async move {
7540 Some(
7541 all_actions_task
7542 .await
7543 .into_iter()
7544 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7545 .collect::<Vec<Hover>>(),
7546 )
7547 })
7548 }
7549 }
7550
7551 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7552 let language_registry = self.languages.clone();
7553
7554 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7555 let request = upstream_client.request(proto::GetProjectSymbols {
7556 project_id: *project_id,
7557 query: query.to_string(),
7558 });
7559 cx.foreground_executor().spawn(async move {
7560 let response = request.await?;
7561 let mut symbols = Vec::new();
7562 let core_symbols = response
7563 .symbols
7564 .into_iter()
7565 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7566 .collect::<Vec<_>>();
7567 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7568 .await;
7569 Ok(symbols)
7570 })
7571 } else if let Some(local) = self.as_local() {
7572 struct WorkspaceSymbolsResult {
7573 server_id: LanguageServerId,
7574 lsp_adapter: Arc<CachedLspAdapter>,
7575 worktree: WeakEntity<Worktree>,
7576 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7577 }
7578
7579 let mut requests = Vec::new();
7580 let mut requested_servers = BTreeSet::new();
7581 let request_timeout = ProjectSettings::get_global(cx)
7582 .global_lsp_settings
7583 .get_request_timeout();
7584
7585 for (seed, state) in local.language_server_ids.iter() {
7586 let Some(worktree_handle) = self
7587 .worktree_store
7588 .read(cx)
7589 .worktree_for_id(seed.worktree_id, cx)
7590 else {
7591 continue;
7592 };
7593
7594 let worktree = worktree_handle.read(cx);
7595 if !worktree.is_visible() {
7596 continue;
7597 }
7598
7599 if !requested_servers.insert(state.id) {
7600 continue;
7601 }
7602
7603 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7604 Some(LanguageServerState::Running {
7605 adapter, server, ..
7606 }) => (adapter.clone(), server),
7607
7608 _ => continue,
7609 };
7610
7611 let supports_workspace_symbol_request =
7612 match server.capabilities().workspace_symbol_provider {
7613 Some(OneOf::Left(supported)) => supported,
7614 Some(OneOf::Right(_)) => true,
7615 None => false,
7616 };
7617
7618 if !supports_workspace_symbol_request {
7619 continue;
7620 }
7621
7622 let worktree_handle = worktree_handle.clone();
7623 let server_id = server.server_id();
7624 requests.push(
7625 server
7626 .request::<lsp::request::WorkspaceSymbolRequest>(
7627 lsp::WorkspaceSymbolParams {
7628 query: query.to_string(),
7629 ..Default::default()
7630 },
7631 request_timeout,
7632 )
7633 .map(move |response| {
7634 let lsp_symbols = response
7635 .into_response()
7636 .context("workspace symbols request")
7637 .log_err()
7638 .flatten()
7639 .map(|symbol_response| match symbol_response {
7640 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7641 flat_responses
7642 .into_iter()
7643 .map(|lsp_symbol| {
7644 (
7645 lsp_symbol.name,
7646 lsp_symbol.kind,
7647 lsp_symbol.location,
7648 lsp_symbol.container_name,
7649 )
7650 })
7651 .collect::<Vec<_>>()
7652 }
7653 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7654 nested_responses
7655 .into_iter()
7656 .filter_map(|lsp_symbol| {
7657 let location = match lsp_symbol.location {
7658 OneOf::Left(location) => location,
7659 OneOf::Right(_) => {
7660 log::error!(
7661 "Unexpected: client capabilities \
7662 forbid symbol resolutions in \
7663 workspace.symbol.resolveSupport"
7664 );
7665 return None;
7666 }
7667 };
7668 Some((
7669 lsp_symbol.name,
7670 lsp_symbol.kind,
7671 location,
7672 lsp_symbol.container_name,
7673 ))
7674 })
7675 .collect::<Vec<_>>()
7676 }
7677 })
7678 .unwrap_or_default();
7679
7680 WorkspaceSymbolsResult {
7681 server_id,
7682 lsp_adapter,
7683 worktree: worktree_handle.downgrade(),
7684 lsp_symbols,
7685 }
7686 }),
7687 );
7688 }
7689
7690 cx.spawn(async move |this, cx| {
7691 let responses = futures::future::join_all(requests).await;
7692 let this = match this.upgrade() {
7693 Some(this) => this,
7694 None => return Ok(Vec::new()),
7695 };
7696
7697 let mut symbols = Vec::new();
7698 for result in responses {
7699 let core_symbols = this.update(cx, |this, cx| {
7700 result
7701 .lsp_symbols
7702 .into_iter()
7703 .filter_map(
7704 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7705 let abs_path = symbol_location.uri.to_file_path().ok()?;
7706 let source_worktree = result.worktree.upgrade()?;
7707 let source_worktree_id = source_worktree.read(cx).id();
7708
7709 let path = if let Some((tree, rel_path)) =
7710 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7711 {
7712 let worktree_id = tree.read(cx).id();
7713 SymbolLocation::InProject(ProjectPath {
7714 worktree_id,
7715 path: rel_path,
7716 })
7717 } else {
7718 SymbolLocation::OutsideProject {
7719 signature: this.symbol_signature(&abs_path),
7720 abs_path: abs_path.into(),
7721 }
7722 };
7723
7724 Some(CoreSymbol {
7725 source_language_server_id: result.server_id,
7726 language_server_name: result.lsp_adapter.name.clone(),
7727 source_worktree_id,
7728 path,
7729 kind: symbol_kind,
7730 name: collapse_newlines(&symbol_name, "↵ "),
7731 range: range_from_lsp(symbol_location.range),
7732 container_name: container_name
7733 .map(|c| collapse_newlines(&c, "↵ ")),
7734 })
7735 },
7736 )
7737 .collect::<Vec<_>>()
7738 });
7739
7740 populate_labels_for_symbols(
7741 core_symbols,
7742 &language_registry,
7743 Some(result.lsp_adapter),
7744 &mut symbols,
7745 )
7746 .await;
7747 }
7748
7749 Ok(symbols)
7750 })
7751 } else {
7752 Task::ready(Err(anyhow!("No upstream client or local language server")))
7753 }
7754 }
7755
7756 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7757 let mut summary = DiagnosticSummary::default();
7758 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7759 summary.error_count += path_summary.error_count;
7760 summary.warning_count += path_summary.warning_count;
7761 }
7762 summary
7763 }
7764
7765 /// Returns the diagnostic summary for a specific project path.
7766 pub fn diagnostic_summary_for_path(
7767 &self,
7768 project_path: &ProjectPath,
7769 _: &App,
7770 ) -> DiagnosticSummary {
7771 if let Some(summaries) = self
7772 .diagnostic_summaries
7773 .get(&project_path.worktree_id)
7774 .and_then(|map| map.get(&project_path.path))
7775 {
7776 let (error_count, warning_count) = summaries.iter().fold(
7777 (0, 0),
7778 |(error_count, warning_count), (_language_server_id, summary)| {
7779 (
7780 error_count + summary.error_count,
7781 warning_count + summary.warning_count,
7782 )
7783 },
7784 );
7785
7786 DiagnosticSummary {
7787 error_count,
7788 warning_count,
7789 }
7790 } else {
7791 DiagnosticSummary::default()
7792 }
7793 }
7794
7795 pub fn diagnostic_summaries<'a>(
7796 &'a self,
7797 include_ignored: bool,
7798 cx: &'a App,
7799 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7800 self.worktree_store
7801 .read(cx)
7802 .visible_worktrees(cx)
7803 .filter_map(|worktree| {
7804 let worktree = worktree.read(cx);
7805 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7806 })
7807 .flat_map(move |(worktree, summaries)| {
7808 let worktree_id = worktree.id();
7809 summaries
7810 .iter()
7811 .filter(move |(path, _)| {
7812 include_ignored
7813 || worktree
7814 .entry_for_path(path.as_ref())
7815 .is_some_and(|entry| !entry.is_ignored)
7816 })
7817 .flat_map(move |(path, summaries)| {
7818 summaries.iter().map(move |(server_id, summary)| {
7819 (
7820 ProjectPath {
7821 worktree_id,
7822 path: path.clone(),
7823 },
7824 *server_id,
7825 *summary,
7826 )
7827 })
7828 })
7829 })
7830 }
7831
7832 pub fn on_buffer_edited(
7833 &mut self,
7834 buffer: Entity<Buffer>,
7835 cx: &mut Context<Self>,
7836 ) -> Option<()> {
7837 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7838 Some(
7839 self.as_local()?
7840 .language_servers_for_buffer(buffer, cx)
7841 .map(|i| i.1.clone())
7842 .collect(),
7843 )
7844 })?;
7845
7846 let buffer = buffer.read(cx);
7847 let file = File::from_dyn(buffer.file())?;
7848 let abs_path = file.as_local()?.abs_path(cx);
7849 let uri = lsp::Uri::from_file_path(&abs_path)
7850 .ok()
7851 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7852 .log_err()?;
7853 let next_snapshot = buffer.text_snapshot();
7854 for language_server in language_servers {
7855 let language_server = language_server.clone();
7856
7857 let buffer_snapshots = self
7858 .as_local_mut()?
7859 .buffer_snapshots
7860 .get_mut(&buffer.remote_id())
7861 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7862 let previous_snapshot = buffer_snapshots.last()?;
7863
7864 let build_incremental_change = || {
7865 buffer
7866 .edits_since::<Dimensions<PointUtf16, usize>>(
7867 previous_snapshot.snapshot.version(),
7868 )
7869 .map(|edit| {
7870 let edit_start = edit.new.start.0;
7871 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7872 let new_text = next_snapshot
7873 .text_for_range(edit.new.start.1..edit.new.end.1)
7874 .collect();
7875 lsp::TextDocumentContentChangeEvent {
7876 range: Some(lsp::Range::new(
7877 point_to_lsp(edit_start),
7878 point_to_lsp(edit_end),
7879 )),
7880 range_length: None,
7881 text: new_text,
7882 }
7883 })
7884 .collect()
7885 };
7886
7887 let document_sync_kind = language_server
7888 .capabilities()
7889 .text_document_sync
7890 .as_ref()
7891 .and_then(|sync| match sync {
7892 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7893 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7894 });
7895
7896 let content_changes: Vec<_> = match document_sync_kind {
7897 Some(lsp::TextDocumentSyncKind::FULL) => {
7898 vec![lsp::TextDocumentContentChangeEvent {
7899 range: None,
7900 range_length: None,
7901 text: next_snapshot.text(),
7902 }]
7903 }
7904 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7905 _ => {
7906 #[cfg(any(test, feature = "test-support"))]
7907 {
7908 build_incremental_change()
7909 }
7910
7911 #[cfg(not(any(test, feature = "test-support")))]
7912 {
7913 continue;
7914 }
7915 }
7916 };
7917
7918 let next_version = previous_snapshot.version + 1;
7919 buffer_snapshots.push(LspBufferSnapshot {
7920 version: next_version,
7921 snapshot: next_snapshot.clone(),
7922 });
7923
7924 language_server
7925 .notify::<lsp::notification::DidChangeTextDocument>(
7926 lsp::DidChangeTextDocumentParams {
7927 text_document: lsp::VersionedTextDocumentIdentifier::new(
7928 uri.clone(),
7929 next_version,
7930 ),
7931 content_changes,
7932 },
7933 )
7934 .ok();
7935 self.pull_workspace_diagnostics(language_server.server_id());
7936 }
7937
7938 None
7939 }
7940
7941 pub fn on_buffer_saved(
7942 &mut self,
7943 buffer: Entity<Buffer>,
7944 cx: &mut Context<Self>,
7945 ) -> Option<()> {
7946 let file = File::from_dyn(buffer.read(cx).file())?;
7947 let worktree_id = file.worktree_id(cx);
7948 let abs_path = file.as_local()?.abs_path(cx);
7949 let text_document = lsp::TextDocumentIdentifier {
7950 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7951 };
7952 let local = self.as_local()?;
7953
7954 for server in local.language_servers_for_worktree(worktree_id) {
7955 if let Some(include_text) = include_text(server.as_ref()) {
7956 let text = if include_text {
7957 Some(buffer.read(cx).text())
7958 } else {
7959 None
7960 };
7961 server
7962 .notify::<lsp::notification::DidSaveTextDocument>(
7963 lsp::DidSaveTextDocumentParams {
7964 text_document: text_document.clone(),
7965 text,
7966 },
7967 )
7968 .ok();
7969 }
7970 }
7971
7972 let language_servers = buffer.update(cx, |buffer, cx| {
7973 local.language_server_ids_for_buffer(buffer, cx)
7974 });
7975 for language_server_id in language_servers {
7976 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7977 }
7978
7979 None
7980 }
7981
7982 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7983 maybe!(async move {
7984 let mut refreshed_servers = HashSet::default();
7985 let servers = lsp_store
7986 .update(cx, |lsp_store, cx| {
7987 let local = lsp_store.as_local()?;
7988
7989 let servers = local
7990 .language_server_ids
7991 .iter()
7992 .filter_map(|(seed, state)| {
7993 let worktree = lsp_store
7994 .worktree_store
7995 .read(cx)
7996 .worktree_for_id(seed.worktree_id, cx);
7997 let delegate: Arc<dyn LspAdapterDelegate> =
7998 worktree.map(|worktree| {
7999 LocalLspAdapterDelegate::new(
8000 local.languages.clone(),
8001 &local.environment,
8002 cx.weak_entity(),
8003 &worktree,
8004 local.http_client.clone(),
8005 local.fs.clone(),
8006 cx,
8007 )
8008 })?;
8009 let server_id = state.id;
8010
8011 let states = local.language_servers.get(&server_id)?;
8012
8013 match states {
8014 LanguageServerState::Starting { .. } => None,
8015 LanguageServerState::Running {
8016 adapter, server, ..
8017 } => {
8018 let adapter = adapter.clone();
8019 let server = server.clone();
8020 refreshed_servers.insert(server.name());
8021 let toolchain = seed.toolchain.clone();
8022 Some(cx.spawn(async move |_, cx| {
8023 let settings =
8024 LocalLspStore::workspace_configuration_for_adapter(
8025 adapter.adapter.clone(),
8026 &delegate,
8027 toolchain,
8028 None,
8029 cx,
8030 )
8031 .await
8032 .ok()?;
8033 server
8034 .notify::<lsp::notification::DidChangeConfiguration>(
8035 lsp::DidChangeConfigurationParams { settings },
8036 )
8037 .ok()?;
8038 Some(())
8039 }))
8040 }
8041 }
8042 })
8043 .collect::<Vec<_>>();
8044
8045 Some(servers)
8046 })
8047 .ok()
8048 .flatten()?;
8049
8050 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
8051 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
8052 // to stop and unregister its language server wrapper.
8053 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
8054 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
8055 let _: Vec<Option<()>> = join_all(servers).await;
8056
8057 Some(())
8058 })
8059 .await;
8060 }
8061
8062 fn maintain_workspace_config(
8063 external_refresh_requests: watch::Receiver<()>,
8064 cx: &mut Context<Self>,
8065 ) -> Task<Result<()>> {
8066 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8067 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8068
8069 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8070 *settings_changed_tx.borrow_mut() = ();
8071 });
8072
8073 let mut joint_future =
8074 futures::stream::select(settings_changed_rx, external_refresh_requests);
8075 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8076 // - 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).
8077 // - 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.
8078 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8079 // - 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,
8080 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8081 cx.spawn(async move |this, cx| {
8082 while let Some(()) = joint_future.next().await {
8083 this.update(cx, |this, cx| {
8084 this.refresh_server_tree(cx);
8085 })
8086 .ok();
8087
8088 Self::refresh_workspace_configurations(&this, cx).await;
8089 }
8090
8091 drop(settings_observation);
8092 anyhow::Ok(())
8093 })
8094 }
8095
8096 pub fn running_language_servers_for_local_buffer<'a>(
8097 &'a self,
8098 buffer: &Buffer,
8099 cx: &mut App,
8100 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8101 let local = self.as_local();
8102 let language_server_ids = local
8103 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8104 .unwrap_or_default();
8105
8106 language_server_ids
8107 .into_iter()
8108 .filter_map(
8109 move |server_id| match local?.language_servers.get(&server_id)? {
8110 LanguageServerState::Running {
8111 adapter, server, ..
8112 } => Some((adapter, server)),
8113 _ => None,
8114 },
8115 )
8116 }
8117
8118 pub fn language_servers_for_local_buffer(
8119 &self,
8120 buffer: &Buffer,
8121 cx: &mut App,
8122 ) -> Vec<LanguageServerId> {
8123 let local = self.as_local();
8124 local
8125 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8126 .unwrap_or_default()
8127 }
8128
8129 pub fn language_server_for_local_buffer<'a>(
8130 &'a self,
8131 buffer: &'a Buffer,
8132 server_id: LanguageServerId,
8133 cx: &'a mut App,
8134 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8135 self.as_local()?
8136 .language_servers_for_buffer(buffer, cx)
8137 .find(|(_, s)| s.server_id() == server_id)
8138 }
8139
8140 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8141 self.diagnostic_summaries.remove(&id_to_remove);
8142 if let Some(local) = self.as_local_mut() {
8143 let to_remove = local.remove_worktree(id_to_remove, cx);
8144 for server in to_remove {
8145 self.language_server_statuses.remove(&server);
8146 }
8147 }
8148 }
8149
8150 pub fn shared(
8151 &mut self,
8152 project_id: u64,
8153 downstream_client: AnyProtoClient,
8154 _: &mut Context<Self>,
8155 ) {
8156 self.downstream_client = Some((downstream_client.clone(), project_id));
8157
8158 for (server_id, status) in &self.language_server_statuses {
8159 if let Some(server) = self.language_server_for_id(*server_id) {
8160 downstream_client
8161 .send(proto::StartLanguageServer {
8162 project_id,
8163 server: Some(proto::LanguageServer {
8164 id: server_id.to_proto(),
8165 name: status.name.to_string(),
8166 worktree_id: status.worktree.map(|id| id.to_proto()),
8167 }),
8168 capabilities: serde_json::to_string(&server.capabilities())
8169 .expect("serializing server LSP capabilities"),
8170 })
8171 .log_err();
8172 }
8173 }
8174 }
8175
8176 pub fn disconnected_from_host(&mut self) {
8177 self.downstream_client.take();
8178 }
8179
8180 pub fn disconnected_from_ssh_remote(&mut self) {
8181 if let LspStoreMode::Remote(RemoteLspStore {
8182 upstream_client, ..
8183 }) = &mut self.mode
8184 {
8185 upstream_client.take();
8186 }
8187 }
8188
8189 pub(crate) fn set_language_server_statuses_from_proto(
8190 &mut self,
8191 project: WeakEntity<Project>,
8192 language_servers: Vec<proto::LanguageServer>,
8193 server_capabilities: Vec<String>,
8194 cx: &mut Context<Self>,
8195 ) {
8196 let lsp_logs = cx
8197 .try_global::<GlobalLogStore>()
8198 .map(|lsp_store| lsp_store.0.clone());
8199
8200 self.language_server_statuses = language_servers
8201 .into_iter()
8202 .zip(server_capabilities)
8203 .map(|(server, server_capabilities)| {
8204 let server_id = LanguageServerId(server.id as usize);
8205 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8206 self.lsp_server_capabilities
8207 .insert(server_id, server_capabilities);
8208 }
8209
8210 let name = LanguageServerName::from_proto(server.name);
8211 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8212
8213 if let Some(lsp_logs) = &lsp_logs {
8214 lsp_logs.update(cx, |lsp_logs, cx| {
8215 lsp_logs.add_language_server(
8216 // Only remote clients get their language servers set from proto
8217 LanguageServerKind::Remote {
8218 project: project.clone(),
8219 },
8220 server_id,
8221 Some(name.clone()),
8222 worktree,
8223 None,
8224 cx,
8225 );
8226 });
8227 }
8228
8229 (
8230 server_id,
8231 LanguageServerStatus {
8232 name,
8233 server_version: None,
8234 server_readable_version: None,
8235 pending_work: Default::default(),
8236 has_pending_diagnostic_updates: false,
8237 progress_tokens: Default::default(),
8238 worktree,
8239 binary: None,
8240 configuration: None,
8241 workspace_folders: BTreeSet::new(),
8242 process_id: None,
8243 },
8244 )
8245 })
8246 .collect();
8247 }
8248
8249 #[cfg(feature = "test-support")]
8250 pub fn update_diagnostic_entries(
8251 &mut self,
8252 server_id: LanguageServerId,
8253 abs_path: PathBuf,
8254 result_id: Option<SharedString>,
8255 version: Option<i32>,
8256 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8257 cx: &mut Context<Self>,
8258 ) -> anyhow::Result<()> {
8259 self.merge_diagnostic_entries(
8260 vec![DocumentDiagnosticsUpdate {
8261 diagnostics: DocumentDiagnostics {
8262 diagnostics,
8263 document_abs_path: abs_path,
8264 version,
8265 },
8266 result_id,
8267 server_id,
8268 disk_based_sources: Cow::Borrowed(&[]),
8269 registration_id: None,
8270 }],
8271 |_, _, _| false,
8272 cx,
8273 )?;
8274 Ok(())
8275 }
8276
8277 pub fn merge_diagnostic_entries<'a>(
8278 &mut self,
8279 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8280 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8281 cx: &mut Context<Self>,
8282 ) -> anyhow::Result<()> {
8283 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8284 let mut updated_diagnostics_paths = HashMap::default();
8285 for mut update in diagnostic_updates {
8286 let abs_path = &update.diagnostics.document_abs_path;
8287 let server_id = update.server_id;
8288 let Some((worktree, relative_path)) =
8289 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8290 else {
8291 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8292 return Ok(());
8293 };
8294
8295 let worktree_id = worktree.read(cx).id();
8296 let project_path = ProjectPath {
8297 worktree_id,
8298 path: relative_path,
8299 };
8300
8301 let document_uri = lsp::Uri::from_file_path(abs_path)
8302 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8303 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8304 let snapshot = buffer_handle.read(cx).snapshot();
8305 let buffer = buffer_handle.read(cx);
8306 let reused_diagnostics = buffer
8307 .buffer_diagnostics(Some(server_id))
8308 .iter()
8309 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8310 .map(|v| {
8311 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8312 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8313 DiagnosticEntry {
8314 range: start..end,
8315 diagnostic: v.diagnostic.clone(),
8316 }
8317 })
8318 .collect::<Vec<_>>();
8319
8320 self.as_local_mut()
8321 .context("cannot merge diagnostics on a remote LspStore")?
8322 .update_buffer_diagnostics(
8323 &buffer_handle,
8324 server_id,
8325 Some(update.registration_id),
8326 update.result_id,
8327 update.diagnostics.version,
8328 update.diagnostics.diagnostics.clone(),
8329 reused_diagnostics.clone(),
8330 cx,
8331 )?;
8332
8333 update.diagnostics.diagnostics.extend(reused_diagnostics);
8334 } else if let Some(local) = self.as_local() {
8335 let reused_diagnostics = local
8336 .diagnostics
8337 .get(&worktree_id)
8338 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8339 .and_then(|diagnostics_by_server_id| {
8340 diagnostics_by_server_id
8341 .binary_search_by_key(&server_id, |e| e.0)
8342 .ok()
8343 .map(|ix| &diagnostics_by_server_id[ix].1)
8344 })
8345 .into_iter()
8346 .flatten()
8347 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8348
8349 update
8350 .diagnostics
8351 .diagnostics
8352 .extend(reused_diagnostics.cloned());
8353 }
8354
8355 let updated = worktree.update(cx, |worktree, cx| {
8356 self.update_worktree_diagnostics(
8357 worktree.id(),
8358 server_id,
8359 project_path.path.clone(),
8360 update.diagnostics.diagnostics,
8361 cx,
8362 )
8363 })?;
8364 match updated {
8365 ControlFlow::Continue(new_summary) => {
8366 if let Some((project_id, new_summary)) = new_summary {
8367 match &mut diagnostics_summary {
8368 Some(diagnostics_summary) => {
8369 diagnostics_summary
8370 .more_summaries
8371 .push(proto::DiagnosticSummary {
8372 path: project_path.path.as_ref().to_proto(),
8373 language_server_id: server_id.0 as u64,
8374 error_count: new_summary.error_count,
8375 warning_count: new_summary.warning_count,
8376 })
8377 }
8378 None => {
8379 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8380 project_id,
8381 worktree_id: worktree_id.to_proto(),
8382 summary: Some(proto::DiagnosticSummary {
8383 path: project_path.path.as_ref().to_proto(),
8384 language_server_id: server_id.0 as u64,
8385 error_count: new_summary.error_count,
8386 warning_count: new_summary.warning_count,
8387 }),
8388 more_summaries: Vec::new(),
8389 })
8390 }
8391 }
8392 }
8393 updated_diagnostics_paths
8394 .entry(server_id)
8395 .or_insert_with(Vec::new)
8396 .push(project_path);
8397 }
8398 ControlFlow::Break(()) => {}
8399 }
8400 }
8401
8402 if let Some((diagnostics_summary, (downstream_client, _))) =
8403 diagnostics_summary.zip(self.downstream_client.as_ref())
8404 {
8405 downstream_client.send(diagnostics_summary).log_err();
8406 }
8407 for (server_id, paths) in updated_diagnostics_paths {
8408 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8409 }
8410 Ok(())
8411 }
8412
8413 fn update_worktree_diagnostics(
8414 &mut self,
8415 worktree_id: WorktreeId,
8416 server_id: LanguageServerId,
8417 path_in_worktree: Arc<RelPath>,
8418 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8419 _: &mut Context<Worktree>,
8420 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8421 let local = match &mut self.mode {
8422 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8423 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8424 };
8425
8426 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8427 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8428 let summaries_by_server_id = summaries_for_tree
8429 .entry(path_in_worktree.clone())
8430 .or_default();
8431
8432 let old_summary = summaries_by_server_id
8433 .remove(&server_id)
8434 .unwrap_or_default();
8435
8436 let new_summary = DiagnosticSummary::new(&diagnostics);
8437 if diagnostics.is_empty() {
8438 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8439 {
8440 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8441 diagnostics_by_server_id.remove(ix);
8442 }
8443 if diagnostics_by_server_id.is_empty() {
8444 diagnostics_for_tree.remove(&path_in_worktree);
8445 }
8446 }
8447 } else {
8448 summaries_by_server_id.insert(server_id, new_summary);
8449 let diagnostics_by_server_id = diagnostics_for_tree
8450 .entry(path_in_worktree.clone())
8451 .or_default();
8452 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8453 Ok(ix) => {
8454 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8455 }
8456 Err(ix) => {
8457 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8458 }
8459 }
8460 }
8461
8462 if !old_summary.is_empty() || !new_summary.is_empty() {
8463 if let Some((_, project_id)) = &self.downstream_client {
8464 Ok(ControlFlow::Continue(Some((
8465 *project_id,
8466 proto::DiagnosticSummary {
8467 path: path_in_worktree.to_proto(),
8468 language_server_id: server_id.0 as u64,
8469 error_count: new_summary.error_count as u32,
8470 warning_count: new_summary.warning_count as u32,
8471 },
8472 ))))
8473 } else {
8474 Ok(ControlFlow::Continue(None))
8475 }
8476 } else {
8477 Ok(ControlFlow::Break(()))
8478 }
8479 }
8480
8481 pub fn open_buffer_for_symbol(
8482 &mut self,
8483 symbol: &Symbol,
8484 cx: &mut Context<Self>,
8485 ) -> Task<Result<Entity<Buffer>>> {
8486 if let Some((client, project_id)) = self.upstream_client() {
8487 let request = client.request(proto::OpenBufferForSymbol {
8488 project_id,
8489 symbol: Some(Self::serialize_symbol(symbol)),
8490 });
8491 cx.spawn(async move |this, cx| {
8492 let response = request.await?;
8493 let buffer_id = BufferId::new(response.buffer_id)?;
8494 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8495 .await
8496 })
8497 } else if let Some(local) = self.as_local() {
8498 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8499 seed.worktree_id == symbol.source_worktree_id
8500 && state.id == symbol.source_language_server_id
8501 && symbol.language_server_name == seed.name
8502 });
8503 if !is_valid {
8504 return Task::ready(Err(anyhow!(
8505 "language server for worktree and language not found"
8506 )));
8507 };
8508
8509 let symbol_abs_path = match &symbol.path {
8510 SymbolLocation::InProject(project_path) => self
8511 .worktree_store
8512 .read(cx)
8513 .absolutize(&project_path, cx)
8514 .context("no such worktree"),
8515 SymbolLocation::OutsideProject {
8516 abs_path,
8517 signature: _,
8518 } => Ok(abs_path.to_path_buf()),
8519 };
8520 let symbol_abs_path = match symbol_abs_path {
8521 Ok(abs_path) => abs_path,
8522 Err(err) => return Task::ready(Err(err)),
8523 };
8524 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8525 uri
8526 } else {
8527 return Task::ready(Err(anyhow!("invalid symbol path")));
8528 };
8529
8530 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8531 } else {
8532 Task::ready(Err(anyhow!("no upstream client or local store")))
8533 }
8534 }
8535
8536 pub(crate) fn open_local_buffer_via_lsp(
8537 &mut self,
8538 abs_path: lsp::Uri,
8539 language_server_id: LanguageServerId,
8540 cx: &mut Context<Self>,
8541 ) -> Task<Result<Entity<Buffer>>> {
8542 let path_style = self.worktree_store.read(cx).path_style();
8543 cx.spawn(async move |lsp_store, cx| {
8544 // Escape percent-encoded string.
8545 let current_scheme = abs_path.scheme().to_owned();
8546 // Uri is immutable, so we can't modify the scheme
8547
8548 let abs_path = abs_path
8549 .to_file_path_ext(path_style)
8550 .map_err(|()| anyhow!("can't convert URI to path"))?;
8551 let p = abs_path.clone();
8552 let yarn_worktree = lsp_store
8553 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8554 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8555 cx.spawn(async move |this, cx| {
8556 let t = this
8557 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8558 .ok()?;
8559 t.await
8560 })
8561 }),
8562 None => Task::ready(None),
8563 })?
8564 .await;
8565 let (worktree_root_target, known_relative_path) =
8566 if let Some((zip_root, relative_path)) = yarn_worktree {
8567 (zip_root, Some(relative_path))
8568 } else {
8569 (Arc::<Path>::from(abs_path.as_path()), None)
8570 };
8571 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8572 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8573 worktree_store.find_worktree(&worktree_root_target, cx)
8574 })
8575 })?;
8576 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8577 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8578 (result.0, relative_path, None)
8579 } else {
8580 let worktree = lsp_store
8581 .update(cx, |lsp_store, cx| {
8582 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8583 worktree_store.create_worktree(&worktree_root_target, false, cx)
8584 })
8585 })?
8586 .await?;
8587 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8588 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8589 lsp_store
8590 .update(cx, |lsp_store, cx| {
8591 if let Some(local) = lsp_store.as_local_mut() {
8592 local.register_language_server_for_invisible_worktree(
8593 &worktree,
8594 language_server_id,
8595 cx,
8596 )
8597 }
8598 match lsp_store.language_server_statuses.get(&language_server_id) {
8599 Some(status) => status.worktree,
8600 None => None,
8601 }
8602 })
8603 .ok()
8604 .flatten()
8605 .zip(Some(worktree_root.clone()))
8606 } else {
8607 None
8608 };
8609 let relative_path = if let Some(known_path) = known_relative_path {
8610 known_path
8611 } else {
8612 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8613 .into_arc()
8614 };
8615 (worktree, relative_path, source_ws)
8616 };
8617 let project_path = ProjectPath {
8618 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8619 path: relative_path,
8620 };
8621 let buffer = lsp_store
8622 .update(cx, |lsp_store, cx| {
8623 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8624 buffer_store.open_buffer(project_path, cx)
8625 })
8626 })?
8627 .await?;
8628 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8629 if let Some((source_ws, worktree_root)) = source_ws {
8630 buffer.update(cx, |buffer, cx| {
8631 let settings = WorktreeSettings::get(
8632 Some(
8633 (&ProjectPath {
8634 worktree_id: source_ws,
8635 path: Arc::from(RelPath::empty()),
8636 })
8637 .into(),
8638 ),
8639 cx,
8640 );
8641 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8642 if is_read_only {
8643 buffer.set_capability(Capability::ReadOnly, cx);
8644 }
8645 });
8646 }
8647 Ok(buffer)
8648 })
8649 }
8650
8651 fn local_lsp_servers_for_buffer(
8652 &self,
8653 buffer: &Entity<Buffer>,
8654 cx: &mut Context<Self>,
8655 ) -> Vec<LanguageServerId> {
8656 let Some(local) = self.as_local() else {
8657 return Vec::new();
8658 };
8659
8660 let snapshot = buffer.read(cx).snapshot();
8661
8662 buffer.update(cx, |buffer, cx| {
8663 local
8664 .language_servers_for_buffer(buffer, cx)
8665 .map(|(_, server)| server.server_id())
8666 .filter(|server_id| {
8667 self.as_local().is_none_or(|local| {
8668 local
8669 .buffers_opened_in_servers
8670 .get(&snapshot.remote_id())
8671 .is_some_and(|servers| servers.contains(server_id))
8672 })
8673 })
8674 .collect()
8675 })
8676 }
8677
8678 fn request_multiple_lsp_locally<P, R>(
8679 &mut self,
8680 buffer: &Entity<Buffer>,
8681 position: Option<P>,
8682 request: R,
8683 cx: &mut Context<Self>,
8684 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8685 where
8686 P: ToOffset,
8687 R: LspCommand + Clone,
8688 <R::LspRequest as lsp::request::Request>::Result: Send,
8689 <R::LspRequest as lsp::request::Request>::Params: Send,
8690 {
8691 let Some(local) = self.as_local() else {
8692 return Task::ready(Vec::new());
8693 };
8694
8695 let snapshot = buffer.read(cx).snapshot();
8696 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8697
8698 let server_ids = buffer.update(cx, |buffer, cx| {
8699 local
8700 .language_servers_for_buffer(buffer, cx)
8701 .filter(|(adapter, _)| {
8702 scope
8703 .as_ref()
8704 .map(|scope| scope.language_allowed(&adapter.name))
8705 .unwrap_or(true)
8706 })
8707 .map(|(_, server)| server.server_id())
8708 .filter(|server_id| {
8709 self.as_local().is_none_or(|local| {
8710 local
8711 .buffers_opened_in_servers
8712 .get(&snapshot.remote_id())
8713 .is_some_and(|servers| servers.contains(server_id))
8714 })
8715 })
8716 .collect::<Vec<_>>()
8717 });
8718
8719 let mut response_results = server_ids
8720 .into_iter()
8721 .map(|server_id| {
8722 let task = self.request_lsp(
8723 buffer.clone(),
8724 LanguageServerToQuery::Other(server_id),
8725 request.clone(),
8726 cx,
8727 );
8728 async move { (server_id, task.await) }
8729 })
8730 .collect::<FuturesUnordered<_>>();
8731
8732 cx.background_spawn(async move {
8733 let mut responses = Vec::with_capacity(response_results.len());
8734 while let Some((server_id, response_result)) = response_results.next().await {
8735 match response_result {
8736 Ok(response) => responses.push((server_id, response)),
8737 // rust-analyzer likes to error with this when its still loading up
8738 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8739 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8740 }
8741 }
8742 responses
8743 })
8744 }
8745
8746 async fn handle_lsp_get_completions(
8747 this: Entity<Self>,
8748 envelope: TypedEnvelope<proto::GetCompletions>,
8749 mut cx: AsyncApp,
8750 ) -> Result<proto::GetCompletionsResponse> {
8751 let sender_id = envelope.original_sender_id().unwrap_or_default();
8752
8753 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8754 let buffer_handle = this.update(&mut cx, |this, cx| {
8755 this.buffer_store.read(cx).get_existing(buffer_id)
8756 })?;
8757 let request = GetCompletions::from_proto(
8758 envelope.payload,
8759 this.clone(),
8760 buffer_handle.clone(),
8761 cx.clone(),
8762 )
8763 .await?;
8764
8765 let server_to_query = match request.server_id {
8766 Some(server_id) => LanguageServerToQuery::Other(server_id),
8767 None => LanguageServerToQuery::FirstCapable,
8768 };
8769
8770 let response = this
8771 .update(&mut cx, |this, cx| {
8772 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8773 })
8774 .await?;
8775 this.update(&mut cx, |this, cx| {
8776 Ok(GetCompletions::response_to_proto(
8777 response,
8778 this,
8779 sender_id,
8780 &buffer_handle.read(cx).version(),
8781 cx,
8782 ))
8783 })
8784 }
8785
8786 async fn handle_lsp_command<T: LspCommand>(
8787 this: Entity<Self>,
8788 envelope: TypedEnvelope<T::ProtoRequest>,
8789 mut cx: AsyncApp,
8790 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8791 where
8792 <T::LspRequest as lsp::request::Request>::Params: Send,
8793 <T::LspRequest as lsp::request::Request>::Result: Send,
8794 {
8795 let sender_id = envelope.original_sender_id().unwrap_or_default();
8796 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8797 let buffer_handle = this.update(&mut cx, |this, cx| {
8798 this.buffer_store.read(cx).get_existing(buffer_id)
8799 })?;
8800 let request = T::from_proto(
8801 envelope.payload,
8802 this.clone(),
8803 buffer_handle.clone(),
8804 cx.clone(),
8805 )
8806 .await?;
8807 let response = this
8808 .update(&mut cx, |this, cx| {
8809 this.request_lsp(
8810 buffer_handle.clone(),
8811 LanguageServerToQuery::FirstCapable,
8812 request,
8813 cx,
8814 )
8815 })
8816 .await?;
8817 this.update(&mut cx, |this, cx| {
8818 Ok(T::response_to_proto(
8819 response,
8820 this,
8821 sender_id,
8822 &buffer_handle.read(cx).version(),
8823 cx,
8824 ))
8825 })
8826 }
8827
8828 async fn handle_lsp_query(
8829 lsp_store: Entity<Self>,
8830 envelope: TypedEnvelope<proto::LspQuery>,
8831 mut cx: AsyncApp,
8832 ) -> Result<proto::Ack> {
8833 use proto::lsp_query::Request;
8834 let sender_id = envelope.original_sender_id().unwrap_or_default();
8835 let lsp_query = envelope.payload;
8836 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8837 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8838 match lsp_query.request.context("invalid LSP query request")? {
8839 Request::GetReferences(get_references) => {
8840 let position = get_references.position.clone().and_then(deserialize_anchor);
8841 Self::query_lsp_locally::<GetReferences>(
8842 lsp_store,
8843 server_id,
8844 sender_id,
8845 lsp_request_id,
8846 get_references,
8847 position,
8848 &mut cx,
8849 )
8850 .await?;
8851 }
8852 Request::GetDocumentColor(get_document_color) => {
8853 Self::query_lsp_locally::<GetDocumentColor>(
8854 lsp_store,
8855 server_id,
8856 sender_id,
8857 lsp_request_id,
8858 get_document_color,
8859 None,
8860 &mut cx,
8861 )
8862 .await?;
8863 }
8864 Request::GetFoldingRanges(get_folding_ranges) => {
8865 Self::query_lsp_locally::<GetFoldingRanges>(
8866 lsp_store,
8867 server_id,
8868 sender_id,
8869 lsp_request_id,
8870 get_folding_ranges,
8871 None,
8872 &mut cx,
8873 )
8874 .await?;
8875 }
8876 Request::GetDocumentSymbols(get_document_symbols) => {
8877 Self::query_lsp_locally::<GetDocumentSymbols>(
8878 lsp_store,
8879 server_id,
8880 sender_id,
8881 lsp_request_id,
8882 get_document_symbols,
8883 None,
8884 &mut cx,
8885 )
8886 .await?;
8887 }
8888 Request::GetHover(get_hover) => {
8889 let position = get_hover.position.clone().and_then(deserialize_anchor);
8890 Self::query_lsp_locally::<GetHover>(
8891 lsp_store,
8892 server_id,
8893 sender_id,
8894 lsp_request_id,
8895 get_hover,
8896 position,
8897 &mut cx,
8898 )
8899 .await?;
8900 }
8901 Request::GetCodeActions(get_code_actions) => {
8902 Self::query_lsp_locally::<GetCodeActions>(
8903 lsp_store,
8904 server_id,
8905 sender_id,
8906 lsp_request_id,
8907 get_code_actions,
8908 None,
8909 &mut cx,
8910 )
8911 .await?;
8912 }
8913 Request::GetSignatureHelp(get_signature_help) => {
8914 let position = get_signature_help
8915 .position
8916 .clone()
8917 .and_then(deserialize_anchor);
8918 Self::query_lsp_locally::<GetSignatureHelp>(
8919 lsp_store,
8920 server_id,
8921 sender_id,
8922 lsp_request_id,
8923 get_signature_help,
8924 position,
8925 &mut cx,
8926 )
8927 .await?;
8928 }
8929 Request::GetCodeLens(get_code_lens) => {
8930 Self::query_lsp_locally::<GetCodeLens>(
8931 lsp_store,
8932 server_id,
8933 sender_id,
8934 lsp_request_id,
8935 get_code_lens,
8936 None,
8937 &mut cx,
8938 )
8939 .await?;
8940 }
8941 Request::GetDefinition(get_definition) => {
8942 let position = get_definition.position.clone().and_then(deserialize_anchor);
8943 Self::query_lsp_locally::<GetDefinitions>(
8944 lsp_store,
8945 server_id,
8946 sender_id,
8947 lsp_request_id,
8948 get_definition,
8949 position,
8950 &mut cx,
8951 )
8952 .await?;
8953 }
8954 Request::GetDeclaration(get_declaration) => {
8955 let position = get_declaration
8956 .position
8957 .clone()
8958 .and_then(deserialize_anchor);
8959 Self::query_lsp_locally::<GetDeclarations>(
8960 lsp_store,
8961 server_id,
8962 sender_id,
8963 lsp_request_id,
8964 get_declaration,
8965 position,
8966 &mut cx,
8967 )
8968 .await?;
8969 }
8970 Request::GetTypeDefinition(get_type_definition) => {
8971 let position = get_type_definition
8972 .position
8973 .clone()
8974 .and_then(deserialize_anchor);
8975 Self::query_lsp_locally::<GetTypeDefinitions>(
8976 lsp_store,
8977 server_id,
8978 sender_id,
8979 lsp_request_id,
8980 get_type_definition,
8981 position,
8982 &mut cx,
8983 )
8984 .await?;
8985 }
8986 Request::GetImplementation(get_implementation) => {
8987 let position = get_implementation
8988 .position
8989 .clone()
8990 .and_then(deserialize_anchor);
8991 Self::query_lsp_locally::<GetImplementations>(
8992 lsp_store,
8993 server_id,
8994 sender_id,
8995 lsp_request_id,
8996 get_implementation,
8997 position,
8998 &mut cx,
8999 )
9000 .await?;
9001 }
9002 Request::InlayHints(inlay_hints) => {
9003 let query_start = inlay_hints
9004 .start
9005 .clone()
9006 .and_then(deserialize_anchor)
9007 .context("invalid inlay hints range start")?;
9008 let query_end = inlay_hints
9009 .end
9010 .clone()
9011 .and_then(deserialize_anchor)
9012 .context("invalid inlay hints range end")?;
9013 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
9014 &lsp_store,
9015 server_id,
9016 lsp_request_id,
9017 &inlay_hints,
9018 query_start..query_end,
9019 &mut cx,
9020 )
9021 .await
9022 .context("preparing inlay hints request")?;
9023 Self::query_lsp_locally::<InlayHints>(
9024 lsp_store,
9025 server_id,
9026 sender_id,
9027 lsp_request_id,
9028 inlay_hints,
9029 None,
9030 &mut cx,
9031 )
9032 .await
9033 .context("querying for inlay hints")?
9034 }
9035 //////////////////////////////
9036 // Below are LSP queries that need to fetch more data,
9037 // hence cannot just proxy the request to language server with `query_lsp_locally`.
9038 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
9039 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
9040 &lsp_store,
9041 &get_document_diagnostics,
9042 &mut cx,
9043 )
9044 .await?;
9045 lsp_store.update(&mut cx, |lsp_store, cx| {
9046 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9047 let key = LspKey {
9048 request_type: TypeId::of::<GetDocumentDiagnostics>(),
9049 server_queried: server_id,
9050 };
9051 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
9052 ) {
9053 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9054 lsp_requests.clear();
9055 };
9056 }
9057
9058 lsp_data.lsp_requests.entry(key).or_default().insert(
9059 lsp_request_id,
9060 cx.spawn(async move |lsp_store, cx| {
9061 let diagnostics_pull = lsp_store
9062 .update(cx, |lsp_store, cx| {
9063 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9064 })
9065 .ok();
9066 if let Some(diagnostics_pull) = diagnostics_pull {
9067 match diagnostics_pull.await {
9068 Ok(()) => {}
9069 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9070 };
9071 }
9072 }),
9073 );
9074 });
9075 }
9076 Request::SemanticTokens(semantic_tokens) => {
9077 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9078 &lsp_store,
9079 &semantic_tokens,
9080 &mut cx,
9081 )
9082 .await?;
9083 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9084 lsp_store.update(&mut cx, |lsp_store, cx| {
9085 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9086 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9087 let key = LspKey {
9088 request_type: TypeId::of::<SemanticTokensFull>(),
9089 server_queried: server_id,
9090 };
9091 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9092 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9093 lsp_requests.clear();
9094 };
9095 }
9096
9097 lsp_data.lsp_requests.entry(key).or_default().insert(
9098 lsp_request_id,
9099 cx.spawn(async move |lsp_store, cx| {
9100 let tokens_fetch = lsp_store
9101 .update(cx, |lsp_store, cx| {
9102 lsp_store
9103 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9104 })
9105 .ok();
9106 if let Some(tokens_fetch) = tokens_fetch {
9107 let new_tokens = tokens_fetch.await;
9108 if let Some(new_tokens) = new_tokens {
9109 lsp_store
9110 .update(cx, |lsp_store, cx| {
9111 let response = new_tokens
9112 .into_iter()
9113 .map(|(server_id, response)| {
9114 (
9115 server_id.to_proto(),
9116 SemanticTokensFull::response_to_proto(
9117 response,
9118 lsp_store,
9119 sender_id,
9120 &buffer_version,
9121 cx,
9122 ),
9123 )
9124 })
9125 .collect::<HashMap<_, _>>();
9126 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9127 project_id,
9128 lsp_request_id,
9129 response,
9130 ) {
9131 Ok(()) => {}
9132 Err(e) => {
9133 log::error!(
9134 "Failed to send semantic tokens LSP response: {e:#}",
9135 )
9136 }
9137 }
9138 })
9139 .ok();
9140 }
9141 }
9142 }),
9143 );
9144 }
9145 });
9146 }
9147 }
9148 Ok(proto::Ack {})
9149 }
9150
9151 async fn handle_lsp_query_response(
9152 lsp_store: Entity<Self>,
9153 envelope: TypedEnvelope<proto::LspQueryResponse>,
9154 cx: AsyncApp,
9155 ) -> Result<()> {
9156 lsp_store.read_with(&cx, |lsp_store, _| {
9157 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9158 upstream_client.handle_lsp_response(envelope.clone());
9159 }
9160 });
9161 Ok(())
9162 }
9163
9164 async fn handle_apply_code_action(
9165 this: Entity<Self>,
9166 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9167 mut cx: AsyncApp,
9168 ) -> Result<proto::ApplyCodeActionResponse> {
9169 let sender_id = envelope.original_sender_id().unwrap_or_default();
9170 let action =
9171 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9172 let apply_code_action = this.update(&mut cx, |this, cx| {
9173 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9174 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9175 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9176 })?;
9177
9178 let project_transaction = apply_code_action.await?;
9179 let project_transaction = this.update(&mut cx, |this, cx| {
9180 this.buffer_store.update(cx, |buffer_store, cx| {
9181 buffer_store.serialize_project_transaction_for_peer(
9182 project_transaction,
9183 sender_id,
9184 cx,
9185 )
9186 })
9187 });
9188 Ok(proto::ApplyCodeActionResponse {
9189 transaction: Some(project_transaction),
9190 })
9191 }
9192
9193 async fn handle_register_buffer_with_language_servers(
9194 this: Entity<Self>,
9195 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9196 mut cx: AsyncApp,
9197 ) -> Result<proto::Ack> {
9198 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9199 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9200 this.update(&mut cx, |this, cx| {
9201 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9202 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9203 project_id: upstream_project_id,
9204 buffer_id: buffer_id.to_proto(),
9205 only_servers: envelope.payload.only_servers,
9206 });
9207 }
9208
9209 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9210 anyhow::bail!("buffer is not open");
9211 };
9212
9213 let handle = this.register_buffer_with_language_servers(
9214 &buffer,
9215 envelope
9216 .payload
9217 .only_servers
9218 .into_iter()
9219 .filter_map(|selector| {
9220 Some(match selector.selector? {
9221 proto::language_server_selector::Selector::ServerId(server_id) => {
9222 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9223 }
9224 proto::language_server_selector::Selector::Name(name) => {
9225 LanguageServerSelector::Name(LanguageServerName(
9226 SharedString::from(name),
9227 ))
9228 }
9229 })
9230 })
9231 .collect(),
9232 false,
9233 cx,
9234 );
9235 // Pull diagnostics for the buffer even if it was already registered.
9236 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9237 // but it's unclear if we need it.
9238 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9239 .detach();
9240 this.buffer_store().update(cx, |buffer_store, _| {
9241 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9242 });
9243
9244 Ok(())
9245 })?;
9246 Ok(proto::Ack {})
9247 }
9248
9249 async fn handle_rename_project_entry(
9250 this: Entity<Self>,
9251 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9252 mut cx: AsyncApp,
9253 ) -> Result<proto::ProjectEntryResponse> {
9254 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9255 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9256 let new_path =
9257 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9258
9259 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9260 .update(&mut cx, |this, cx| {
9261 let (worktree, entry) = this
9262 .worktree_store
9263 .read(cx)
9264 .worktree_and_entry_for_id(entry_id, cx)?;
9265 let new_worktree = this
9266 .worktree_store
9267 .read(cx)
9268 .worktree_for_id(new_worktree_id, cx)?;
9269 Some((
9270 this.worktree_store.clone(),
9271 worktree,
9272 new_worktree,
9273 entry.clone(),
9274 ))
9275 })
9276 .context("worktree not found")?;
9277 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9278 (worktree.absolutize(&old_entry.path), worktree.id())
9279 });
9280 let new_abs_path =
9281 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9282
9283 let _transaction = Self::will_rename_entry(
9284 this.downgrade(),
9285 old_worktree_id,
9286 &old_abs_path,
9287 &new_abs_path,
9288 old_entry.is_dir(),
9289 cx.clone(),
9290 )
9291 .await;
9292 let response = WorktreeStore::handle_rename_project_entry(
9293 worktree_store,
9294 envelope.payload,
9295 cx.clone(),
9296 )
9297 .await;
9298 this.read_with(&cx, |this, _| {
9299 this.did_rename_entry(
9300 old_worktree_id,
9301 &old_abs_path,
9302 &new_abs_path,
9303 old_entry.is_dir(),
9304 );
9305 });
9306 response
9307 }
9308
9309 async fn handle_update_diagnostic_summary(
9310 this: Entity<Self>,
9311 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9312 mut cx: AsyncApp,
9313 ) -> Result<()> {
9314 this.update(&mut cx, |lsp_store, cx| {
9315 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9316 let mut updated_diagnostics_paths = HashMap::default();
9317 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9318 for message_summary in envelope
9319 .payload
9320 .summary
9321 .into_iter()
9322 .chain(envelope.payload.more_summaries)
9323 {
9324 let project_path = ProjectPath {
9325 worktree_id,
9326 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9327 };
9328 let path = project_path.path.clone();
9329 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9330 let summary = DiagnosticSummary {
9331 error_count: message_summary.error_count as usize,
9332 warning_count: message_summary.warning_count as usize,
9333 };
9334
9335 if summary.is_empty() {
9336 if let Some(worktree_summaries) =
9337 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9338 && let Some(summaries) = worktree_summaries.get_mut(&path)
9339 {
9340 summaries.remove(&server_id);
9341 if summaries.is_empty() {
9342 worktree_summaries.remove(&path);
9343 }
9344 }
9345 } else {
9346 lsp_store
9347 .diagnostic_summaries
9348 .entry(worktree_id)
9349 .or_default()
9350 .entry(path)
9351 .or_default()
9352 .insert(server_id, summary);
9353 }
9354
9355 if let Some((_, project_id)) = &lsp_store.downstream_client {
9356 match &mut diagnostics_summary {
9357 Some(diagnostics_summary) => {
9358 diagnostics_summary
9359 .more_summaries
9360 .push(proto::DiagnosticSummary {
9361 path: project_path.path.as_ref().to_proto(),
9362 language_server_id: server_id.0 as u64,
9363 error_count: summary.error_count as u32,
9364 warning_count: summary.warning_count as u32,
9365 })
9366 }
9367 None => {
9368 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9369 project_id: *project_id,
9370 worktree_id: worktree_id.to_proto(),
9371 summary: Some(proto::DiagnosticSummary {
9372 path: project_path.path.as_ref().to_proto(),
9373 language_server_id: server_id.0 as u64,
9374 error_count: summary.error_count as u32,
9375 warning_count: summary.warning_count as u32,
9376 }),
9377 more_summaries: Vec::new(),
9378 })
9379 }
9380 }
9381 }
9382 updated_diagnostics_paths
9383 .entry(server_id)
9384 .or_insert_with(Vec::new)
9385 .push(project_path);
9386 }
9387
9388 if let Some((diagnostics_summary, (downstream_client, _))) =
9389 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9390 {
9391 downstream_client.send(diagnostics_summary).log_err();
9392 }
9393 for (server_id, paths) in updated_diagnostics_paths {
9394 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9395 }
9396 Ok(())
9397 })
9398 }
9399
9400 async fn handle_start_language_server(
9401 lsp_store: Entity<Self>,
9402 envelope: TypedEnvelope<proto::StartLanguageServer>,
9403 mut cx: AsyncApp,
9404 ) -> Result<()> {
9405 let server = envelope.payload.server.context("invalid server")?;
9406 let server_capabilities =
9407 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9408 .with_context(|| {
9409 format!(
9410 "incorrect server capabilities {}",
9411 envelope.payload.capabilities
9412 )
9413 })?;
9414 lsp_store.update(&mut cx, |lsp_store, cx| {
9415 let server_id = LanguageServerId(server.id as usize);
9416 let server_name = LanguageServerName::from_proto(server.name.clone());
9417 lsp_store
9418 .lsp_server_capabilities
9419 .insert(server_id, server_capabilities);
9420 lsp_store.language_server_statuses.insert(
9421 server_id,
9422 LanguageServerStatus {
9423 name: server_name.clone(),
9424 server_version: None,
9425 server_readable_version: None,
9426 pending_work: Default::default(),
9427 has_pending_diagnostic_updates: false,
9428 progress_tokens: Default::default(),
9429 worktree: server.worktree_id.map(WorktreeId::from_proto),
9430 binary: None,
9431 configuration: None,
9432 workspace_folders: BTreeSet::new(),
9433 process_id: None,
9434 },
9435 );
9436 cx.emit(LspStoreEvent::LanguageServerAdded(
9437 server_id,
9438 server_name,
9439 server.worktree_id.map(WorktreeId::from_proto),
9440 ));
9441 cx.notify();
9442 });
9443 Ok(())
9444 }
9445
9446 async fn handle_update_language_server(
9447 lsp_store: Entity<Self>,
9448 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9449 mut cx: AsyncApp,
9450 ) -> Result<()> {
9451 lsp_store.update(&mut cx, |lsp_store, cx| {
9452 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9453
9454 match envelope.payload.variant.context("invalid variant")? {
9455 proto::update_language_server::Variant::WorkStart(payload) => {
9456 lsp_store.on_lsp_work_start(
9457 language_server_id,
9458 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9459 .context("invalid progress token value")?,
9460 LanguageServerProgress {
9461 title: payload.title,
9462 is_disk_based_diagnostics_progress: false,
9463 is_cancellable: payload.is_cancellable.unwrap_or(false),
9464 message: payload.message,
9465 percentage: payload.percentage.map(|p| p as usize),
9466 last_update_at: cx.background_executor().now(),
9467 },
9468 cx,
9469 );
9470 }
9471 proto::update_language_server::Variant::WorkProgress(payload) => {
9472 lsp_store.on_lsp_work_progress(
9473 language_server_id,
9474 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9475 .context("invalid progress token value")?,
9476 LanguageServerProgress {
9477 title: None,
9478 is_disk_based_diagnostics_progress: false,
9479 is_cancellable: payload.is_cancellable.unwrap_or(false),
9480 message: payload.message,
9481 percentage: payload.percentage.map(|p| p as usize),
9482 last_update_at: cx.background_executor().now(),
9483 },
9484 cx,
9485 );
9486 }
9487
9488 proto::update_language_server::Variant::WorkEnd(payload) => {
9489 lsp_store.on_lsp_work_end(
9490 language_server_id,
9491 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9492 .context("invalid progress token value")?,
9493 cx,
9494 );
9495 }
9496
9497 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9498 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9499 }
9500
9501 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9502 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9503 }
9504
9505 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9506 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9507 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9508 cx.emit(LspStoreEvent::LanguageServerUpdate {
9509 language_server_id,
9510 name: envelope
9511 .payload
9512 .server_name
9513 .map(SharedString::new)
9514 .map(LanguageServerName),
9515 message: non_lsp,
9516 });
9517 }
9518 }
9519
9520 Ok(())
9521 })
9522 }
9523
9524 async fn handle_language_server_log(
9525 this: Entity<Self>,
9526 envelope: TypedEnvelope<proto::LanguageServerLog>,
9527 mut cx: AsyncApp,
9528 ) -> Result<()> {
9529 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9530 let log_type = envelope
9531 .payload
9532 .log_type
9533 .map(LanguageServerLogType::from_proto)
9534 .context("invalid language server log type")?;
9535
9536 let message = envelope.payload.message;
9537
9538 this.update(&mut cx, |_, cx| {
9539 cx.emit(LspStoreEvent::LanguageServerLog(
9540 language_server_id,
9541 log_type,
9542 message,
9543 ));
9544 });
9545 Ok(())
9546 }
9547
9548 async fn handle_lsp_ext_cancel_flycheck(
9549 lsp_store: Entity<Self>,
9550 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9551 cx: AsyncApp,
9552 ) -> Result<proto::Ack> {
9553 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9554 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9555 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9556 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9557 } else {
9558 None
9559 }
9560 });
9561 if let Some(task) = task {
9562 task.context("handling lsp ext cancel flycheck")?;
9563 }
9564
9565 Ok(proto::Ack {})
9566 }
9567
9568 async fn handle_lsp_ext_run_flycheck(
9569 lsp_store: Entity<Self>,
9570 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9571 mut cx: AsyncApp,
9572 ) -> Result<proto::Ack> {
9573 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9574 lsp_store.update(&mut cx, |lsp_store, cx| {
9575 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9576 let text_document = if envelope.payload.current_file_only {
9577 let buffer_id = envelope
9578 .payload
9579 .buffer_id
9580 .map(|id| BufferId::new(id))
9581 .transpose()?;
9582 buffer_id
9583 .and_then(|buffer_id| {
9584 lsp_store
9585 .buffer_store()
9586 .read(cx)
9587 .get(buffer_id)
9588 .and_then(|buffer| {
9589 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9590 })
9591 .map(|path| make_text_document_identifier(&path))
9592 })
9593 .transpose()?
9594 } else {
9595 None
9596 };
9597 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9598 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9599 )?;
9600 }
9601 anyhow::Ok(())
9602 })?;
9603
9604 Ok(proto::Ack {})
9605 }
9606
9607 async fn handle_lsp_ext_clear_flycheck(
9608 lsp_store: Entity<Self>,
9609 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9610 cx: AsyncApp,
9611 ) -> Result<proto::Ack> {
9612 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9613 lsp_store.read_with(&cx, |lsp_store, _| {
9614 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9615 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9616 } else {
9617 None
9618 }
9619 });
9620
9621 Ok(proto::Ack {})
9622 }
9623
9624 pub fn disk_based_diagnostics_started(
9625 &mut self,
9626 language_server_id: LanguageServerId,
9627 cx: &mut Context<Self>,
9628 ) {
9629 if let Some(language_server_status) =
9630 self.language_server_statuses.get_mut(&language_server_id)
9631 {
9632 language_server_status.has_pending_diagnostic_updates = true;
9633 }
9634
9635 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9636 cx.emit(LspStoreEvent::LanguageServerUpdate {
9637 language_server_id,
9638 name: self
9639 .language_server_adapter_for_id(language_server_id)
9640 .map(|adapter| adapter.name()),
9641 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9642 Default::default(),
9643 ),
9644 })
9645 }
9646
9647 pub fn disk_based_diagnostics_finished(
9648 &mut self,
9649 language_server_id: LanguageServerId,
9650 cx: &mut Context<Self>,
9651 ) {
9652 if let Some(language_server_status) =
9653 self.language_server_statuses.get_mut(&language_server_id)
9654 {
9655 language_server_status.has_pending_diagnostic_updates = false;
9656 }
9657
9658 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9659 cx.emit(LspStoreEvent::LanguageServerUpdate {
9660 language_server_id,
9661 name: self
9662 .language_server_adapter_for_id(language_server_id)
9663 .map(|adapter| adapter.name()),
9664 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9665 Default::default(),
9666 ),
9667 })
9668 }
9669
9670 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9671 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9672 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9673 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9674 // the language server might take some time to publish diagnostics.
9675 fn simulate_disk_based_diagnostics_events_if_needed(
9676 &mut self,
9677 language_server_id: LanguageServerId,
9678 cx: &mut Context<Self>,
9679 ) {
9680 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9681
9682 let Some(LanguageServerState::Running {
9683 simulate_disk_based_diagnostics_completion,
9684 adapter,
9685 ..
9686 }) = self
9687 .as_local_mut()
9688 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9689 else {
9690 return;
9691 };
9692
9693 if adapter.disk_based_diagnostics_progress_token.is_some() {
9694 return;
9695 }
9696
9697 let prev_task =
9698 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9699 cx.background_executor()
9700 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9701 .await;
9702
9703 this.update(cx, |this, cx| {
9704 this.disk_based_diagnostics_finished(language_server_id, cx);
9705
9706 if let Some(LanguageServerState::Running {
9707 simulate_disk_based_diagnostics_completion,
9708 ..
9709 }) = this.as_local_mut().and_then(|local_store| {
9710 local_store.language_servers.get_mut(&language_server_id)
9711 }) {
9712 *simulate_disk_based_diagnostics_completion = None;
9713 }
9714 })
9715 .ok();
9716 }));
9717
9718 if prev_task.is_none() {
9719 self.disk_based_diagnostics_started(language_server_id, cx);
9720 }
9721 }
9722
9723 pub fn language_server_statuses(
9724 &self,
9725 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9726 self.language_server_statuses
9727 .iter()
9728 .map(|(key, value)| (*key, value))
9729 }
9730
9731 pub(super) fn did_rename_entry(
9732 &self,
9733 worktree_id: WorktreeId,
9734 old_path: &Path,
9735 new_path: &Path,
9736 is_dir: bool,
9737 ) {
9738 maybe!({
9739 let local_store = self.as_local()?;
9740
9741 let old_uri = lsp::Uri::from_file_path(old_path)
9742 .ok()
9743 .map(|uri| uri.to_string())?;
9744 let new_uri = lsp::Uri::from_file_path(new_path)
9745 .ok()
9746 .map(|uri| uri.to_string())?;
9747
9748 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9749 let Some(filter) = local_store
9750 .language_server_paths_watched_for_rename
9751 .get(&language_server.server_id())
9752 else {
9753 continue;
9754 };
9755
9756 if filter.should_send_did_rename(&old_uri, is_dir) {
9757 language_server
9758 .notify::<DidRenameFiles>(RenameFilesParams {
9759 files: vec![FileRename {
9760 old_uri: old_uri.clone(),
9761 new_uri: new_uri.clone(),
9762 }],
9763 })
9764 .ok();
9765 }
9766 }
9767 Some(())
9768 });
9769 }
9770
9771 pub(super) fn will_rename_entry(
9772 this: WeakEntity<Self>,
9773 worktree_id: WorktreeId,
9774 old_path: &Path,
9775 new_path: &Path,
9776 is_dir: bool,
9777 cx: AsyncApp,
9778 ) -> Task<ProjectTransaction> {
9779 let old_uri = lsp::Uri::from_file_path(old_path)
9780 .ok()
9781 .map(|uri| uri.to_string());
9782 let new_uri = lsp::Uri::from_file_path(new_path)
9783 .ok()
9784 .map(|uri| uri.to_string());
9785 cx.spawn(async move |cx| {
9786 let mut tasks = vec![];
9787 this.update(cx, |this, cx| {
9788 let local_store = this.as_local()?;
9789 let old_uri = old_uri?;
9790 let new_uri = new_uri?;
9791 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9792 let Some(filter) = local_store
9793 .language_server_paths_watched_for_rename
9794 .get(&language_server.server_id())
9795 else {
9796 continue;
9797 };
9798
9799 if !filter.should_send_will_rename(&old_uri, is_dir) {
9800 continue;
9801 }
9802 let request_timeout = ProjectSettings::get_global(cx)
9803 .global_lsp_settings
9804 .get_request_timeout();
9805
9806 let apply_edit = cx.spawn({
9807 let old_uri = old_uri.clone();
9808 let new_uri = new_uri.clone();
9809 let language_server = language_server.clone();
9810 async move |this, cx| {
9811 let edit = language_server
9812 .request::<WillRenameFiles>(
9813 RenameFilesParams {
9814 files: vec![FileRename { old_uri, new_uri }],
9815 },
9816 request_timeout,
9817 )
9818 .await
9819 .into_response()
9820 .context("will rename files")
9821 .log_err()
9822 .flatten()?;
9823
9824 LocalLspStore::deserialize_workspace_edit(
9825 this.upgrade()?,
9826 edit,
9827 false,
9828 language_server.clone(),
9829 cx,
9830 )
9831 .await
9832 .ok()
9833 }
9834 });
9835 tasks.push(apply_edit);
9836 }
9837 Some(())
9838 })
9839 .ok()
9840 .flatten();
9841 let mut merged_transaction = ProjectTransaction::default();
9842 for task in tasks {
9843 // Await on tasks sequentially so that the order of application of edits is deterministic
9844 // (at least with regards to the order of registration of language servers)
9845 if let Some(transaction) = task.await {
9846 for (buffer, buffer_transaction) in transaction.0 {
9847 merged_transaction.0.insert(buffer, buffer_transaction);
9848 }
9849 }
9850 }
9851 merged_transaction
9852 })
9853 }
9854
9855 fn lsp_notify_abs_paths_changed(
9856 &mut self,
9857 server_id: LanguageServerId,
9858 changes: Vec<PathEvent>,
9859 ) {
9860 maybe!({
9861 let server = self.language_server_for_id(server_id)?;
9862 let changes = changes
9863 .into_iter()
9864 .filter_map(|event| {
9865 let typ = match event.kind? {
9866 PathEventKind::Created => lsp::FileChangeType::CREATED,
9867 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9868 PathEventKind::Changed | PathEventKind::Rescan => {
9869 lsp::FileChangeType::CHANGED
9870 }
9871 };
9872 Some(lsp::FileEvent {
9873 uri: file_path_to_lsp_url(&event.path).log_err()?,
9874 typ,
9875 })
9876 })
9877 .collect::<Vec<_>>();
9878 if !changes.is_empty() {
9879 server
9880 .notify::<lsp::notification::DidChangeWatchedFiles>(
9881 lsp::DidChangeWatchedFilesParams { changes },
9882 )
9883 .ok();
9884 }
9885 Some(())
9886 });
9887 }
9888
9889 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9890 self.as_local()?.language_server_for_id(id)
9891 }
9892
9893 fn on_lsp_progress(
9894 &mut self,
9895 progress_params: lsp::ProgressParams,
9896 language_server_id: LanguageServerId,
9897 disk_based_diagnostics_progress_token: Option<String>,
9898 cx: &mut Context<Self>,
9899 ) {
9900 match progress_params.value {
9901 lsp::ProgressParamsValue::WorkDone(progress) => {
9902 self.handle_work_done_progress(
9903 progress,
9904 language_server_id,
9905 disk_based_diagnostics_progress_token,
9906 ProgressToken::from_lsp(progress_params.token),
9907 cx,
9908 );
9909 }
9910 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9911 let registration_id = match progress_params.token {
9912 lsp::NumberOrString::Number(_) => None,
9913 lsp::NumberOrString::String(token) => token
9914 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9915 .map(|(_, id)| id.to_owned()),
9916 };
9917 if let Some(LanguageServerState::Running {
9918 workspace_diagnostics_refresh_tasks,
9919 ..
9920 }) = self
9921 .as_local_mut()
9922 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9923 && let Some(workspace_diagnostics) =
9924 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9925 {
9926 workspace_diagnostics.progress_tx.try_send(()).ok();
9927 self.apply_workspace_diagnostic_report(
9928 language_server_id,
9929 report,
9930 registration_id.map(SharedString::from),
9931 cx,
9932 )
9933 }
9934 }
9935 }
9936 }
9937
9938 fn handle_work_done_progress(
9939 &mut self,
9940 progress: lsp::WorkDoneProgress,
9941 language_server_id: LanguageServerId,
9942 disk_based_diagnostics_progress_token: Option<String>,
9943 token: ProgressToken,
9944 cx: &mut Context<Self>,
9945 ) {
9946 let language_server_status =
9947 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9948 status
9949 } else {
9950 return;
9951 };
9952
9953 if !language_server_status.progress_tokens.contains(&token) {
9954 return;
9955 }
9956
9957 let is_disk_based_diagnostics_progress =
9958 if let (Some(disk_based_token), ProgressToken::String(token)) =
9959 (&disk_based_diagnostics_progress_token, &token)
9960 {
9961 token.starts_with(disk_based_token)
9962 } else {
9963 false
9964 };
9965
9966 match progress {
9967 lsp::WorkDoneProgress::Begin(report) => {
9968 if is_disk_based_diagnostics_progress {
9969 self.disk_based_diagnostics_started(language_server_id, cx);
9970 }
9971 self.on_lsp_work_start(
9972 language_server_id,
9973 token.clone(),
9974 LanguageServerProgress {
9975 title: Some(report.title),
9976 is_disk_based_diagnostics_progress,
9977 is_cancellable: report.cancellable.unwrap_or(false),
9978 message: report.message.clone(),
9979 percentage: report.percentage.map(|p| p as usize),
9980 last_update_at: cx.background_executor().now(),
9981 },
9982 cx,
9983 );
9984 }
9985 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9986 language_server_id,
9987 token,
9988 LanguageServerProgress {
9989 title: None,
9990 is_disk_based_diagnostics_progress,
9991 is_cancellable: report.cancellable.unwrap_or(false),
9992 message: report.message,
9993 percentage: report.percentage.map(|p| p as usize),
9994 last_update_at: cx.background_executor().now(),
9995 },
9996 cx,
9997 ),
9998 lsp::WorkDoneProgress::End(_) => {
9999 language_server_status.progress_tokens.remove(&token);
10000 self.on_lsp_work_end(language_server_id, token.clone(), cx);
10001 if is_disk_based_diagnostics_progress {
10002 self.disk_based_diagnostics_finished(language_server_id, cx);
10003 }
10004 }
10005 }
10006 }
10007
10008 fn on_lsp_work_start(
10009 &mut self,
10010 language_server_id: LanguageServerId,
10011 token: ProgressToken,
10012 progress: LanguageServerProgress,
10013 cx: &mut Context<Self>,
10014 ) {
10015 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10016 status.pending_work.insert(token.clone(), progress.clone());
10017 cx.notify();
10018 }
10019 cx.emit(LspStoreEvent::LanguageServerUpdate {
10020 language_server_id,
10021 name: self
10022 .language_server_adapter_for_id(language_server_id)
10023 .map(|adapter| adapter.name()),
10024 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
10025 token: Some(token.to_proto()),
10026 title: progress.title,
10027 message: progress.message,
10028 percentage: progress.percentage.map(|p| p as u32),
10029 is_cancellable: Some(progress.is_cancellable),
10030 }),
10031 })
10032 }
10033
10034 fn on_lsp_work_progress(
10035 &mut self,
10036 language_server_id: LanguageServerId,
10037 token: ProgressToken,
10038 progress: LanguageServerProgress,
10039 cx: &mut Context<Self>,
10040 ) {
10041 let mut did_update = false;
10042 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10043 match status.pending_work.entry(token.clone()) {
10044 btree_map::Entry::Vacant(entry) => {
10045 entry.insert(progress.clone());
10046 did_update = true;
10047 }
10048 btree_map::Entry::Occupied(mut entry) => {
10049 let entry = entry.get_mut();
10050 if (progress.last_update_at - entry.last_update_at)
10051 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
10052 {
10053 entry.last_update_at = progress.last_update_at;
10054 if progress.message.is_some() {
10055 entry.message = progress.message.clone();
10056 }
10057 if progress.percentage.is_some() {
10058 entry.percentage = progress.percentage;
10059 }
10060 if progress.is_cancellable != entry.is_cancellable {
10061 entry.is_cancellable = progress.is_cancellable;
10062 }
10063 did_update = true;
10064 }
10065 }
10066 }
10067 }
10068
10069 if did_update {
10070 cx.emit(LspStoreEvent::LanguageServerUpdate {
10071 language_server_id,
10072 name: self
10073 .language_server_adapter_for_id(language_server_id)
10074 .map(|adapter| adapter.name()),
10075 message: proto::update_language_server::Variant::WorkProgress(
10076 proto::LspWorkProgress {
10077 token: Some(token.to_proto()),
10078 message: progress.message,
10079 percentage: progress.percentage.map(|p| p as u32),
10080 is_cancellable: Some(progress.is_cancellable),
10081 },
10082 ),
10083 })
10084 }
10085 }
10086
10087 fn on_lsp_work_end(
10088 &mut self,
10089 language_server_id: LanguageServerId,
10090 token: ProgressToken,
10091 cx: &mut Context<Self>,
10092 ) {
10093 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10094 if let Some(work) = status.pending_work.remove(&token)
10095 && !work.is_disk_based_diagnostics_progress
10096 {
10097 cx.emit(LspStoreEvent::RefreshInlayHints {
10098 server_id: language_server_id,
10099 request_id: None,
10100 });
10101 }
10102 cx.notify();
10103 }
10104
10105 cx.emit(LspStoreEvent::LanguageServerUpdate {
10106 language_server_id,
10107 name: self
10108 .language_server_adapter_for_id(language_server_id)
10109 .map(|adapter| adapter.name()),
10110 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10111 token: Some(token.to_proto()),
10112 }),
10113 })
10114 }
10115
10116 pub async fn handle_resolve_completion_documentation(
10117 this: Entity<Self>,
10118 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10119 mut cx: AsyncApp,
10120 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10121 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10122
10123 let completion = this
10124 .read_with(&cx, |this, cx| {
10125 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10126 let server = this
10127 .language_server_for_id(id)
10128 .with_context(|| format!("No language server {id}"))?;
10129
10130 let request_timeout = ProjectSettings::get_global(cx)
10131 .global_lsp_settings
10132 .get_request_timeout();
10133
10134 anyhow::Ok(cx.background_spawn(async move {
10135 let can_resolve = server
10136 .capabilities()
10137 .completion_provider
10138 .as_ref()
10139 .and_then(|options| options.resolve_provider)
10140 .unwrap_or(false);
10141 if can_resolve {
10142 server
10143 .request::<lsp::request::ResolveCompletionItem>(
10144 lsp_completion,
10145 request_timeout,
10146 )
10147 .await
10148 .into_response()
10149 .context("resolve completion item")
10150 } else {
10151 anyhow::Ok(lsp_completion)
10152 }
10153 }))
10154 })?
10155 .await?;
10156
10157 let mut documentation_is_markdown = false;
10158 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10159 let documentation = match completion.documentation {
10160 Some(lsp::Documentation::String(text)) => text,
10161
10162 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10163 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10164 value
10165 }
10166
10167 _ => String::new(),
10168 };
10169
10170 // If we have a new buffer_id, that means we're talking to a new client
10171 // and want to check for new text_edits in the completion too.
10172 let mut old_replace_start = None;
10173 let mut old_replace_end = None;
10174 let mut old_insert_start = None;
10175 let mut old_insert_end = None;
10176 let mut new_text = String::default();
10177 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10178 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10179 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10180 anyhow::Ok(buffer.read(cx).snapshot())
10181 })?;
10182
10183 if let Some(text_edit) = completion.text_edit.as_ref() {
10184 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10185
10186 if let Some(mut edit) = edit {
10187 LineEnding::normalize(&mut edit.new_text);
10188
10189 new_text = edit.new_text;
10190 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10191 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10192 if let Some(insert_range) = edit.insert_range {
10193 old_insert_start = Some(serialize_anchor(&insert_range.start));
10194 old_insert_end = Some(serialize_anchor(&insert_range.end));
10195 }
10196 }
10197 }
10198 }
10199
10200 Ok(proto::ResolveCompletionDocumentationResponse {
10201 documentation,
10202 documentation_is_markdown,
10203 old_replace_start,
10204 old_replace_end,
10205 new_text,
10206 lsp_completion,
10207 old_insert_start,
10208 old_insert_end,
10209 })
10210 }
10211
10212 async fn handle_on_type_formatting(
10213 this: Entity<Self>,
10214 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10215 mut cx: AsyncApp,
10216 ) -> Result<proto::OnTypeFormattingResponse> {
10217 let on_type_formatting = this.update(&mut cx, |this, cx| {
10218 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10219 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10220 let position = envelope
10221 .payload
10222 .position
10223 .and_then(deserialize_anchor)
10224 .context("invalid position")?;
10225 anyhow::Ok(this.apply_on_type_formatting(
10226 buffer,
10227 position,
10228 envelope.payload.trigger.clone(),
10229 cx,
10230 ))
10231 })?;
10232
10233 let transaction = on_type_formatting
10234 .await?
10235 .as_ref()
10236 .map(language::proto::serialize_transaction);
10237 Ok(proto::OnTypeFormattingResponse { transaction })
10238 }
10239
10240 async fn handle_pull_workspace_diagnostics(
10241 lsp_store: Entity<Self>,
10242 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10243 mut cx: AsyncApp,
10244 ) -> Result<proto::Ack> {
10245 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10246 lsp_store.update(&mut cx, |lsp_store, _| {
10247 lsp_store.pull_workspace_diagnostics(server_id);
10248 });
10249 Ok(proto::Ack {})
10250 }
10251
10252 async fn handle_open_buffer_for_symbol(
10253 this: Entity<Self>,
10254 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10255 mut cx: AsyncApp,
10256 ) -> Result<proto::OpenBufferForSymbolResponse> {
10257 let peer_id = envelope.original_sender_id().unwrap_or_default();
10258 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10259 let symbol = Self::deserialize_symbol(symbol)?;
10260 this.read_with(&cx, |this, _| {
10261 if let SymbolLocation::OutsideProject {
10262 abs_path,
10263 signature,
10264 } = &symbol.path
10265 {
10266 let new_signature = this.symbol_signature(&abs_path);
10267 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10268 }
10269 Ok(())
10270 })?;
10271 let buffer = this
10272 .update(&mut cx, |this, cx| {
10273 this.open_buffer_for_symbol(
10274 &Symbol {
10275 language_server_name: symbol.language_server_name,
10276 source_worktree_id: symbol.source_worktree_id,
10277 source_language_server_id: symbol.source_language_server_id,
10278 path: symbol.path,
10279 name: symbol.name,
10280 kind: symbol.kind,
10281 range: symbol.range,
10282 label: CodeLabel::default(),
10283 container_name: symbol.container_name,
10284 },
10285 cx,
10286 )
10287 })
10288 .await?;
10289
10290 this.update(&mut cx, |this, cx| {
10291 let is_private = buffer
10292 .read(cx)
10293 .file()
10294 .map(|f| f.is_private())
10295 .unwrap_or_default();
10296 if is_private {
10297 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10298 } else {
10299 this.buffer_store
10300 .update(cx, |buffer_store, cx| {
10301 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10302 })
10303 .detach_and_log_err(cx);
10304 let buffer_id = buffer.read(cx).remote_id().to_proto();
10305 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10306 }
10307 })
10308 }
10309
10310 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10311 let mut hasher = Sha256::new();
10312 hasher.update(abs_path.to_string_lossy().as_bytes());
10313 hasher.update(self.nonce.to_be_bytes());
10314 hasher.finalize().as_slice().try_into().unwrap()
10315 }
10316
10317 pub async fn handle_get_project_symbols(
10318 this: Entity<Self>,
10319 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10320 mut cx: AsyncApp,
10321 ) -> Result<proto::GetProjectSymbolsResponse> {
10322 let symbols = this
10323 .update(&mut cx, |this, cx| {
10324 this.symbols(&envelope.payload.query, cx)
10325 })
10326 .await?;
10327
10328 Ok(proto::GetProjectSymbolsResponse {
10329 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10330 })
10331 }
10332
10333 pub async fn handle_restart_language_servers(
10334 this: Entity<Self>,
10335 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10336 mut cx: AsyncApp,
10337 ) -> Result<proto::Ack> {
10338 this.update(&mut cx, |lsp_store, cx| {
10339 let buffers =
10340 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10341 lsp_store.restart_language_servers_for_buffers(
10342 buffers,
10343 envelope
10344 .payload
10345 .only_servers
10346 .into_iter()
10347 .filter_map(|selector| {
10348 Some(match selector.selector? {
10349 proto::language_server_selector::Selector::ServerId(server_id) => {
10350 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10351 }
10352 proto::language_server_selector::Selector::Name(name) => {
10353 LanguageServerSelector::Name(LanguageServerName(
10354 SharedString::from(name),
10355 ))
10356 }
10357 })
10358 })
10359 .collect(),
10360 cx,
10361 );
10362 });
10363
10364 Ok(proto::Ack {})
10365 }
10366
10367 pub async fn handle_stop_language_servers(
10368 lsp_store: Entity<Self>,
10369 envelope: TypedEnvelope<proto::StopLanguageServers>,
10370 mut cx: AsyncApp,
10371 ) -> Result<proto::Ack> {
10372 lsp_store.update(&mut cx, |lsp_store, cx| {
10373 if envelope.payload.all
10374 && envelope.payload.also_servers.is_empty()
10375 && envelope.payload.buffer_ids.is_empty()
10376 {
10377 lsp_store.stop_all_language_servers(cx);
10378 } else {
10379 let buffers =
10380 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10381 lsp_store
10382 .stop_language_servers_for_buffers(
10383 buffers,
10384 envelope
10385 .payload
10386 .also_servers
10387 .into_iter()
10388 .filter_map(|selector| {
10389 Some(match selector.selector? {
10390 proto::language_server_selector::Selector::ServerId(
10391 server_id,
10392 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10393 server_id,
10394 )),
10395 proto::language_server_selector::Selector::Name(name) => {
10396 LanguageServerSelector::Name(LanguageServerName(
10397 SharedString::from(name),
10398 ))
10399 }
10400 })
10401 })
10402 .collect(),
10403 cx,
10404 )
10405 .detach_and_log_err(cx);
10406 }
10407 });
10408
10409 Ok(proto::Ack {})
10410 }
10411
10412 pub async fn handle_cancel_language_server_work(
10413 lsp_store: Entity<Self>,
10414 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10415 mut cx: AsyncApp,
10416 ) -> Result<proto::Ack> {
10417 lsp_store.update(&mut cx, |lsp_store, cx| {
10418 if let Some(work) = envelope.payload.work {
10419 match work {
10420 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10421 let buffers =
10422 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10423 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10424 }
10425 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10426 let server_id = LanguageServerId::from_proto(work.language_server_id);
10427 let token = work
10428 .token
10429 .map(|token| {
10430 ProgressToken::from_proto(token)
10431 .context("invalid work progress token")
10432 })
10433 .transpose()?;
10434 lsp_store.cancel_language_server_work(server_id, token, cx);
10435 }
10436 }
10437 }
10438 anyhow::Ok(())
10439 })?;
10440
10441 Ok(proto::Ack {})
10442 }
10443
10444 fn buffer_ids_to_buffers(
10445 &mut self,
10446 buffer_ids: impl Iterator<Item = u64>,
10447 cx: &mut Context<Self>,
10448 ) -> Vec<Entity<Buffer>> {
10449 buffer_ids
10450 .into_iter()
10451 .flat_map(|buffer_id| {
10452 self.buffer_store
10453 .read(cx)
10454 .get(BufferId::new(buffer_id).log_err()?)
10455 })
10456 .collect::<Vec<_>>()
10457 }
10458
10459 async fn handle_apply_additional_edits_for_completion(
10460 this: Entity<Self>,
10461 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10462 mut cx: AsyncApp,
10463 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10464 let (buffer, completion, all_commit_ranges) = this.update(&mut cx, |this, cx| {
10465 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10466 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10467 let completion = Self::deserialize_completion(
10468 envelope.payload.completion.context("invalid completion")?,
10469 )?;
10470 let all_commit_ranges = envelope
10471 .payload
10472 .all_commit_ranges
10473 .into_iter()
10474 .map(language::proto::deserialize_anchor_range)
10475 .collect::<Result<Vec<_>, _>>()?;
10476 anyhow::Ok((buffer, completion, all_commit_ranges))
10477 })?;
10478
10479 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10480 this.apply_additional_edits_for_completion(
10481 buffer,
10482 Rc::new(RefCell::new(Box::new([Completion {
10483 replace_range: completion.replace_range,
10484 new_text: completion.new_text,
10485 source: completion.source,
10486 documentation: None,
10487 label: CodeLabel::default(),
10488 match_start: None,
10489 snippet_deduplication_key: None,
10490 insert_text_mode: None,
10491 icon_path: None,
10492 confirm: None,
10493 }]))),
10494 0,
10495 false,
10496 all_commit_ranges,
10497 cx,
10498 )
10499 });
10500
10501 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10502 transaction: apply_additional_edits
10503 .await?
10504 .as_ref()
10505 .map(language::proto::serialize_transaction),
10506 })
10507 }
10508
10509 pub fn last_formatting_failure(&self) -> Option<&str> {
10510 self.last_formatting_failure.as_deref()
10511 }
10512
10513 pub fn reset_last_formatting_failure(&mut self) {
10514 self.last_formatting_failure = None;
10515 }
10516
10517 pub fn environment_for_buffer(
10518 &self,
10519 buffer: &Entity<Buffer>,
10520 cx: &mut Context<Self>,
10521 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10522 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10523 environment.update(cx, |env, cx| {
10524 env.buffer_environment(buffer, &self.worktree_store, cx)
10525 })
10526 } else {
10527 Task::ready(None).shared()
10528 }
10529 }
10530
10531 pub fn format(
10532 &mut self,
10533 buffers: HashSet<Entity<Buffer>>,
10534 target: LspFormatTarget,
10535 push_to_history: bool,
10536 trigger: FormatTrigger,
10537 cx: &mut Context<Self>,
10538 ) -> Task<anyhow::Result<ProjectTransaction>> {
10539 let logger = zlog::scoped!("format");
10540 if self.as_local().is_some() {
10541 zlog::trace!(logger => "Formatting locally");
10542 let logger = zlog::scoped!(logger => "local");
10543 let buffers = buffers
10544 .into_iter()
10545 .map(|buffer_handle| {
10546 let buffer = buffer_handle.read(cx);
10547 let buffer_abs_path = File::from_dyn(buffer.file())
10548 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10549
10550 (buffer_handle, buffer_abs_path, buffer.remote_id())
10551 })
10552 .collect::<Vec<_>>();
10553
10554 cx.spawn(async move |lsp_store, cx| {
10555 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10556
10557 for (handle, abs_path, id) in buffers {
10558 let env = lsp_store
10559 .update(cx, |lsp_store, cx| {
10560 lsp_store.environment_for_buffer(&handle, cx)
10561 })?
10562 .await;
10563
10564 let ranges = match &target {
10565 LspFormatTarget::Buffers => None,
10566 LspFormatTarget::Ranges(ranges) => {
10567 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10568 }
10569 };
10570
10571 formattable_buffers.push(FormattableBuffer {
10572 handle,
10573 abs_path,
10574 env,
10575 ranges,
10576 });
10577 }
10578 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10579
10580 let format_timer = zlog::time!(logger => "Formatting buffers");
10581 let result = LocalLspStore::format_locally(
10582 lsp_store.clone(),
10583 formattable_buffers,
10584 push_to_history,
10585 trigger,
10586 logger,
10587 cx,
10588 )
10589 .await;
10590 format_timer.end();
10591
10592 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10593
10594 lsp_store.update(cx, |lsp_store, _| {
10595 lsp_store.update_last_formatting_failure(&result);
10596 })?;
10597
10598 result
10599 })
10600 } else if let Some((client, project_id)) = self.upstream_client() {
10601 zlog::trace!(logger => "Formatting remotely");
10602 let logger = zlog::scoped!(logger => "remote");
10603
10604 let buffer_ranges = match &target {
10605 LspFormatTarget::Buffers => Vec::new(),
10606 LspFormatTarget::Ranges(ranges) => ranges
10607 .iter()
10608 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10609 buffer_id: buffer_id.to_proto(),
10610 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10611 })
10612 .collect(),
10613 };
10614
10615 let buffer_store = self.buffer_store();
10616 cx.spawn(async move |lsp_store, cx| {
10617 zlog::trace!(logger => "Sending remote format request");
10618 let request_timer = zlog::time!(logger => "remote format request");
10619 let result = client
10620 .request(proto::FormatBuffers {
10621 project_id,
10622 trigger: trigger as i32,
10623 buffer_ids: buffers
10624 .iter()
10625 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10626 .collect(),
10627 buffer_ranges,
10628 })
10629 .await
10630 .and_then(|result| result.transaction.context("missing transaction"));
10631 request_timer.end();
10632
10633 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10634
10635 lsp_store.update(cx, |lsp_store, _| {
10636 lsp_store.update_last_formatting_failure(&result);
10637 })?;
10638
10639 let transaction_response = result?;
10640 let _timer = zlog::time!(logger => "deserializing project transaction");
10641 buffer_store
10642 .update(cx, |buffer_store, cx| {
10643 buffer_store.deserialize_project_transaction(
10644 transaction_response,
10645 push_to_history,
10646 cx,
10647 )
10648 })
10649 .await
10650 })
10651 } else {
10652 zlog::trace!(logger => "Not formatting");
10653 Task::ready(Ok(ProjectTransaction::default()))
10654 }
10655 }
10656
10657 async fn handle_format_buffers(
10658 this: Entity<Self>,
10659 envelope: TypedEnvelope<proto::FormatBuffers>,
10660 mut cx: AsyncApp,
10661 ) -> Result<proto::FormatBuffersResponse> {
10662 let sender_id = envelope.original_sender_id().unwrap_or_default();
10663 let format = this.update(&mut cx, |this, cx| {
10664 let mut buffers = HashSet::default();
10665 for buffer_id in &envelope.payload.buffer_ids {
10666 let buffer_id = BufferId::new(*buffer_id)?;
10667 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10668 }
10669
10670 let target = if envelope.payload.buffer_ranges.is_empty() {
10671 LspFormatTarget::Buffers
10672 } else {
10673 let mut ranges_map = BTreeMap::new();
10674 for buffer_range in &envelope.payload.buffer_ranges {
10675 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10676 let ranges: Result<Vec<_>> = buffer_range
10677 .ranges
10678 .iter()
10679 .map(|range| {
10680 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10681 })
10682 .collect();
10683 ranges_map.insert(buffer_id, ranges?);
10684 }
10685 LspFormatTarget::Ranges(ranges_map)
10686 };
10687
10688 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10689 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10690 })?;
10691
10692 let project_transaction = format.await?;
10693 let project_transaction = this.update(&mut cx, |this, cx| {
10694 this.buffer_store.update(cx, |buffer_store, cx| {
10695 buffer_store.serialize_project_transaction_for_peer(
10696 project_transaction,
10697 sender_id,
10698 cx,
10699 )
10700 })
10701 });
10702 Ok(proto::FormatBuffersResponse {
10703 transaction: Some(project_transaction),
10704 })
10705 }
10706
10707 async fn handle_apply_code_action_kind(
10708 this: Entity<Self>,
10709 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10710 mut cx: AsyncApp,
10711 ) -> Result<proto::ApplyCodeActionKindResponse> {
10712 let sender_id = envelope.original_sender_id().unwrap_or_default();
10713 let format = this.update(&mut cx, |this, cx| {
10714 let mut buffers = HashSet::default();
10715 for buffer_id in &envelope.payload.buffer_ids {
10716 let buffer_id = BufferId::new(*buffer_id)?;
10717 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10718 }
10719 let kind = match envelope.payload.kind.as_str() {
10720 "" => CodeActionKind::EMPTY,
10721 "quickfix" => CodeActionKind::QUICKFIX,
10722 "refactor" => CodeActionKind::REFACTOR,
10723 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10724 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10725 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10726 "source" => CodeActionKind::SOURCE,
10727 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10728 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10729 _ => anyhow::bail!(
10730 "Invalid code action kind {}",
10731 envelope.payload.kind.as_str()
10732 ),
10733 };
10734 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10735 })?;
10736
10737 let project_transaction = format.await?;
10738 let project_transaction = this.update(&mut cx, |this, cx| {
10739 this.buffer_store.update(cx, |buffer_store, cx| {
10740 buffer_store.serialize_project_transaction_for_peer(
10741 project_transaction,
10742 sender_id,
10743 cx,
10744 )
10745 })
10746 });
10747 Ok(proto::ApplyCodeActionKindResponse {
10748 transaction: Some(project_transaction),
10749 })
10750 }
10751
10752 async fn shutdown_language_server(
10753 server_state: Option<LanguageServerState>,
10754 name: LanguageServerName,
10755 cx: &mut AsyncApp,
10756 ) {
10757 let server = match server_state {
10758 Some(LanguageServerState::Starting { startup, .. }) => {
10759 let mut timer = cx
10760 .background_executor()
10761 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10762 .fuse();
10763
10764 select! {
10765 server = startup.fuse() => server,
10766 () = timer => {
10767 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10768 None
10769 },
10770 }
10771 }
10772
10773 Some(LanguageServerState::Running { server, .. }) => Some(server),
10774
10775 None => None,
10776 };
10777
10778 let Some(server) = server else { return };
10779 if let Some(shutdown) = server.shutdown() {
10780 shutdown.await;
10781 }
10782 }
10783
10784 // Returns a list of all of the worktrees which no longer have a language server and the root path
10785 // for the stopped server
10786 fn stop_local_language_server(
10787 &mut self,
10788 server_id: LanguageServerId,
10789 cx: &mut Context<Self>,
10790 ) -> Task<()> {
10791 let local = match &mut self.mode {
10792 LspStoreMode::Local(local) => local,
10793 _ => {
10794 return Task::ready(());
10795 }
10796 };
10797
10798 // Remove this server ID from all entries in the given worktree.
10799 local
10800 .language_server_ids
10801 .retain(|_, state| state.id != server_id);
10802 self.buffer_store.update(cx, |buffer_store, cx| {
10803 for buffer in buffer_store.buffers() {
10804 buffer.update(cx, |buffer, cx| {
10805 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10806 buffer.set_completion_triggers(server_id, Default::default(), cx);
10807 });
10808 }
10809 });
10810
10811 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10812 summaries.retain(|path, summaries_by_server_id| {
10813 if summaries_by_server_id.remove(&server_id).is_some() {
10814 if let Some((client, project_id)) = self.downstream_client.clone() {
10815 client
10816 .send(proto::UpdateDiagnosticSummary {
10817 project_id,
10818 worktree_id: worktree_id.to_proto(),
10819 summary: Some(proto::DiagnosticSummary {
10820 path: path.as_ref().to_proto(),
10821 language_server_id: server_id.0 as u64,
10822 error_count: 0,
10823 warning_count: 0,
10824 }),
10825 more_summaries: Vec::new(),
10826 })
10827 .log_err();
10828 }
10829 !summaries_by_server_id.is_empty()
10830 } else {
10831 true
10832 }
10833 });
10834 }
10835
10836 let local = self.as_local_mut().unwrap();
10837 for diagnostics in local.diagnostics.values_mut() {
10838 diagnostics.retain(|_, diagnostics_by_server_id| {
10839 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10840 diagnostics_by_server_id.remove(ix);
10841 !diagnostics_by_server_id.is_empty()
10842 } else {
10843 true
10844 }
10845 });
10846 }
10847 local.language_server_watched_paths.remove(&server_id);
10848
10849 let server_state = local.language_servers.remove(&server_id);
10850 self.cleanup_lsp_data(server_id);
10851 let name = self
10852 .language_server_statuses
10853 .remove(&server_id)
10854 .map(|status| status.name)
10855 .or_else(|| {
10856 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10857 Some(adapter.name())
10858 } else {
10859 None
10860 }
10861 });
10862
10863 if let Some(name) = name {
10864 log::info!("stopping language server {name}");
10865 self.languages
10866 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10867 cx.notify();
10868
10869 return cx.spawn(async move |lsp_store, cx| {
10870 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10871 lsp_store
10872 .update(cx, |lsp_store, cx| {
10873 lsp_store
10874 .languages
10875 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10876 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10877 cx.notify();
10878 })
10879 .ok();
10880 });
10881 }
10882
10883 if server_state.is_some() {
10884 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10885 }
10886 Task::ready(())
10887 }
10888
10889 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10890 self.shutdown_all_language_servers(cx).detach();
10891 }
10892
10893 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10894 if let Some((client, project_id)) = self.upstream_client() {
10895 let request = client.request(proto::StopLanguageServers {
10896 project_id,
10897 buffer_ids: Vec::new(),
10898 also_servers: Vec::new(),
10899 all: true,
10900 });
10901 cx.background_spawn(async move {
10902 request.await.ok();
10903 })
10904 } else {
10905 let Some(local) = self.as_local_mut() else {
10906 return Task::ready(());
10907 };
10908 let language_servers_to_stop = local
10909 .language_server_ids
10910 .values()
10911 .map(|state| state.id)
10912 .collect();
10913 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10914 let tasks = language_servers_to_stop
10915 .into_iter()
10916 .map(|server| self.stop_local_language_server(server, cx))
10917 .collect::<Vec<_>>();
10918 cx.background_spawn(async move {
10919 futures::future::join_all(tasks).await;
10920 })
10921 }
10922 }
10923
10924 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10925 let buffers = self.buffer_store.read(cx).buffers().collect();
10926 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10927 }
10928
10929 pub fn restart_language_servers_for_buffers(
10930 &mut self,
10931 buffers: Vec<Entity<Buffer>>,
10932 only_restart_servers: HashSet<LanguageServerSelector>,
10933 cx: &mut Context<Self>,
10934 ) {
10935 if let Some((client, project_id)) = self.upstream_client() {
10936 let request = client.request(proto::RestartLanguageServers {
10937 project_id,
10938 buffer_ids: buffers
10939 .into_iter()
10940 .map(|b| b.read(cx).remote_id().to_proto())
10941 .collect(),
10942 only_servers: only_restart_servers
10943 .into_iter()
10944 .map(|selector| {
10945 let selector = match selector {
10946 LanguageServerSelector::Id(language_server_id) => {
10947 proto::language_server_selector::Selector::ServerId(
10948 language_server_id.to_proto(),
10949 )
10950 }
10951 LanguageServerSelector::Name(language_server_name) => {
10952 proto::language_server_selector::Selector::Name(
10953 language_server_name.to_string(),
10954 )
10955 }
10956 };
10957 proto::LanguageServerSelector {
10958 selector: Some(selector),
10959 }
10960 })
10961 .collect(),
10962 all: false,
10963 });
10964 cx.background_spawn(request).detach_and_log_err(cx);
10965 } else {
10966 let stop_task = if only_restart_servers.is_empty() {
10967 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10968 } else {
10969 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10970 };
10971 cx.spawn(async move |lsp_store, cx| {
10972 stop_task.await;
10973 lsp_store.update(cx, |lsp_store, cx| {
10974 for buffer in buffers {
10975 lsp_store.register_buffer_with_language_servers(
10976 &buffer,
10977 only_restart_servers.clone(),
10978 true,
10979 cx,
10980 );
10981 }
10982 })
10983 })
10984 .detach();
10985 }
10986 }
10987
10988 pub fn stop_language_servers_for_buffers(
10989 &mut self,
10990 buffers: Vec<Entity<Buffer>>,
10991 also_stop_servers: HashSet<LanguageServerSelector>,
10992 cx: &mut Context<Self>,
10993 ) -> Task<Result<()>> {
10994 if let Some((client, project_id)) = self.upstream_client() {
10995 let request = client.request(proto::StopLanguageServers {
10996 project_id,
10997 buffer_ids: buffers
10998 .into_iter()
10999 .map(|b| b.read(cx).remote_id().to_proto())
11000 .collect(),
11001 also_servers: also_stop_servers
11002 .into_iter()
11003 .map(|selector| {
11004 let selector = match selector {
11005 LanguageServerSelector::Id(language_server_id) => {
11006 proto::language_server_selector::Selector::ServerId(
11007 language_server_id.to_proto(),
11008 )
11009 }
11010 LanguageServerSelector::Name(language_server_name) => {
11011 proto::language_server_selector::Selector::Name(
11012 language_server_name.to_string(),
11013 )
11014 }
11015 };
11016 proto::LanguageServerSelector {
11017 selector: Some(selector),
11018 }
11019 })
11020 .collect(),
11021 all: false,
11022 });
11023 cx.background_spawn(async move {
11024 let _ = request.await?;
11025 Ok(())
11026 })
11027 } else {
11028 let task =
11029 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
11030 cx.background_spawn(async move {
11031 task.await;
11032 Ok(())
11033 })
11034 }
11035 }
11036
11037 fn stop_local_language_servers_for_buffers(
11038 &mut self,
11039 buffers: &[Entity<Buffer>],
11040 also_stop_servers: HashSet<LanguageServerSelector>,
11041 cx: &mut Context<Self>,
11042 ) -> Task<()> {
11043 let Some(local) = self.as_local_mut() else {
11044 return Task::ready(());
11045 };
11046 let mut language_server_names_to_stop = BTreeSet::default();
11047 let mut language_servers_to_stop = also_stop_servers
11048 .into_iter()
11049 .flat_map(|selector| match selector {
11050 LanguageServerSelector::Id(id) => Some(id),
11051 LanguageServerSelector::Name(name) => {
11052 language_server_names_to_stop.insert(name);
11053 None
11054 }
11055 })
11056 .collect::<BTreeSet<_>>();
11057
11058 let mut covered_worktrees = HashSet::default();
11059 for buffer in buffers {
11060 buffer.update(cx, |buffer, cx| {
11061 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
11062 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
11063 && covered_worktrees.insert(worktree_id)
11064 {
11065 language_server_names_to_stop.retain(|name| {
11066 let old_ids_count = language_servers_to_stop.len();
11067 let all_language_servers_with_this_name = local
11068 .language_server_ids
11069 .iter()
11070 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11071 language_servers_to_stop.extend(all_language_servers_with_this_name);
11072 old_ids_count == language_servers_to_stop.len()
11073 });
11074 }
11075 });
11076 }
11077 for name in language_server_names_to_stop {
11078 language_servers_to_stop.extend(
11079 local
11080 .language_server_ids
11081 .iter()
11082 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11083 );
11084 }
11085
11086 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11087 let tasks = language_servers_to_stop
11088 .into_iter()
11089 .map(|server| self.stop_local_language_server(server, cx))
11090 .collect::<Vec<_>>();
11091
11092 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11093 }
11094
11095 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11096 let (worktree, relative_path) =
11097 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11098
11099 let project_path = ProjectPath {
11100 worktree_id: worktree.read(cx).id(),
11101 path: relative_path,
11102 };
11103
11104 Some(
11105 self.buffer_store()
11106 .read(cx)
11107 .get_by_path(&project_path)?
11108 .read(cx),
11109 )
11110 }
11111
11112 #[cfg(any(test, feature = "test-support"))]
11113 pub fn update_diagnostics(
11114 &mut self,
11115 server_id: LanguageServerId,
11116 diagnostics: lsp::PublishDiagnosticsParams,
11117 result_id: Option<SharedString>,
11118 source_kind: DiagnosticSourceKind,
11119 disk_based_sources: &[String],
11120 cx: &mut Context<Self>,
11121 ) -> Result<()> {
11122 self.merge_lsp_diagnostics(
11123 source_kind,
11124 vec![DocumentDiagnosticsUpdate {
11125 diagnostics,
11126 result_id,
11127 server_id,
11128 disk_based_sources: Cow::Borrowed(disk_based_sources),
11129 registration_id: None,
11130 }],
11131 |_, _, _| false,
11132 cx,
11133 )
11134 }
11135
11136 pub fn merge_lsp_diagnostics(
11137 &mut self,
11138 source_kind: DiagnosticSourceKind,
11139 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11140 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11141 cx: &mut Context<Self>,
11142 ) -> Result<()> {
11143 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11144 let updates = lsp_diagnostics
11145 .into_iter()
11146 .filter_map(|update| {
11147 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11148 Some(DocumentDiagnosticsUpdate {
11149 diagnostics: self.lsp_to_document_diagnostics(
11150 abs_path,
11151 source_kind,
11152 update.server_id,
11153 update.diagnostics,
11154 &update.disk_based_sources,
11155 update.registration_id.clone(),
11156 ),
11157 result_id: update.result_id,
11158 server_id: update.server_id,
11159 disk_based_sources: update.disk_based_sources,
11160 registration_id: update.registration_id,
11161 })
11162 })
11163 .collect();
11164 self.merge_diagnostic_entries(updates, merge, cx)?;
11165 Ok(())
11166 }
11167
11168 fn lsp_to_document_diagnostics(
11169 &mut self,
11170 document_abs_path: PathBuf,
11171 source_kind: DiagnosticSourceKind,
11172 server_id: LanguageServerId,
11173 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11174 disk_based_sources: &[String],
11175 registration_id: Option<SharedString>,
11176 ) -> DocumentDiagnostics {
11177 let mut diagnostics = Vec::default();
11178 let mut primary_diagnostic_group_ids = HashMap::default();
11179 let mut sources_by_group_id = HashMap::default();
11180 let mut supporting_diagnostics = HashMap::default();
11181
11182 let adapter = self.language_server_adapter_for_id(server_id);
11183
11184 // Ensure that primary diagnostics are always the most severe
11185 lsp_diagnostics
11186 .diagnostics
11187 .sort_by_key(|item| item.severity);
11188
11189 for diagnostic in &lsp_diagnostics.diagnostics {
11190 let source = diagnostic.source.as_ref();
11191 let range = range_from_lsp(diagnostic.range);
11192 let is_supporting = diagnostic
11193 .related_information
11194 .as_ref()
11195 .is_some_and(|infos| {
11196 infos.iter().any(|info| {
11197 primary_diagnostic_group_ids.contains_key(&(
11198 source,
11199 diagnostic.code.clone(),
11200 range_from_lsp(info.location.range),
11201 ))
11202 })
11203 });
11204
11205 let is_unnecessary = diagnostic
11206 .tags
11207 .as_ref()
11208 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11209
11210 let underline = self
11211 .language_server_adapter_for_id(server_id)
11212 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11213
11214 if is_supporting {
11215 supporting_diagnostics.insert(
11216 (source, diagnostic.code.clone(), range),
11217 (diagnostic.severity, is_unnecessary),
11218 );
11219 } else {
11220 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11221 let is_disk_based =
11222 source.is_some_and(|source| disk_based_sources.contains(source));
11223
11224 sources_by_group_id.insert(group_id, source);
11225 primary_diagnostic_group_ids
11226 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11227
11228 diagnostics.push(DiagnosticEntry {
11229 range,
11230 diagnostic: Diagnostic {
11231 source: diagnostic.source.clone(),
11232 source_kind,
11233 code: diagnostic.code.clone(),
11234 code_description: diagnostic
11235 .code_description
11236 .as_ref()
11237 .and_then(|d| d.href.clone()),
11238 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11239 markdown: adapter.as_ref().and_then(|adapter| {
11240 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11241 }),
11242 message: diagnostic.message.trim().to_string(),
11243 group_id,
11244 is_primary: true,
11245 is_disk_based,
11246 is_unnecessary,
11247 underline,
11248 data: diagnostic.data.clone(),
11249 registration_id: registration_id.clone(),
11250 },
11251 });
11252 if let Some(infos) = &diagnostic.related_information {
11253 for info in infos {
11254 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11255 let range = range_from_lsp(info.location.range);
11256 diagnostics.push(DiagnosticEntry {
11257 range,
11258 diagnostic: Diagnostic {
11259 source: diagnostic.source.clone(),
11260 source_kind,
11261 code: diagnostic.code.clone(),
11262 code_description: diagnostic
11263 .code_description
11264 .as_ref()
11265 .and_then(|d| d.href.clone()),
11266 severity: DiagnosticSeverity::INFORMATION,
11267 markdown: adapter.as_ref().and_then(|adapter| {
11268 adapter.diagnostic_message_to_markdown(&info.message)
11269 }),
11270 message: info.message.trim().to_string(),
11271 group_id,
11272 is_primary: false,
11273 is_disk_based,
11274 is_unnecessary: false,
11275 underline,
11276 data: diagnostic.data.clone(),
11277 registration_id: registration_id.clone(),
11278 },
11279 });
11280 }
11281 }
11282 }
11283 }
11284 }
11285
11286 for entry in &mut diagnostics {
11287 let diagnostic = &mut entry.diagnostic;
11288 if !diagnostic.is_primary {
11289 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11290 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11291 source,
11292 diagnostic.code.clone(),
11293 entry.range.clone(),
11294 )) {
11295 if let Some(severity) = severity {
11296 diagnostic.severity = severity;
11297 }
11298 diagnostic.is_unnecessary = is_unnecessary;
11299 }
11300 }
11301 }
11302
11303 DocumentDiagnostics {
11304 diagnostics,
11305 document_abs_path,
11306 version: lsp_diagnostics.version,
11307 }
11308 }
11309
11310 fn insert_newly_running_language_server(
11311 &mut self,
11312 adapter: Arc<CachedLspAdapter>,
11313 language_server: Arc<LanguageServer>,
11314 server_id: LanguageServerId,
11315 key: LanguageServerSeed,
11316 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11317 cx: &mut Context<Self>,
11318 ) {
11319 let Some(local) = self.as_local_mut() else {
11320 return;
11321 };
11322 // If the language server for this key doesn't match the server id, don't store the
11323 // server. Which will cause it to be dropped, killing the process
11324 if local
11325 .language_server_ids
11326 .get(&key)
11327 .map(|state| state.id != server_id)
11328 .unwrap_or(false)
11329 {
11330 return;
11331 }
11332
11333 // Update language_servers collection with Running variant of LanguageServerState
11334 // indicating that the server is up and running and ready
11335 let workspace_folders = workspace_folders.lock().clone();
11336 language_server.set_workspace_folders(workspace_folders);
11337
11338 let workspace_diagnostics_refresh_tasks = language_server
11339 .capabilities()
11340 .diagnostic_provider
11341 .and_then(|provider| {
11342 local
11343 .language_server_dynamic_registrations
11344 .entry(server_id)
11345 .or_default()
11346 .diagnostics
11347 .entry(None)
11348 .or_insert(provider.clone());
11349 let workspace_refresher =
11350 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11351
11352 Some((None, workspace_refresher))
11353 })
11354 .into_iter()
11355 .collect();
11356 local.language_servers.insert(
11357 server_id,
11358 LanguageServerState::Running {
11359 workspace_diagnostics_refresh_tasks,
11360 adapter: adapter.clone(),
11361 server: language_server.clone(),
11362 simulate_disk_based_diagnostics_completion: None,
11363 },
11364 );
11365 local
11366 .languages
11367 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11368 if let Some(file_ops_caps) = language_server
11369 .capabilities()
11370 .workspace
11371 .as_ref()
11372 .and_then(|ws| ws.file_operations.as_ref())
11373 {
11374 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11375 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11376 if did_rename_caps.or(will_rename_caps).is_some() {
11377 let watcher = RenamePathsWatchedForServer::default()
11378 .with_did_rename_patterns(did_rename_caps)
11379 .with_will_rename_patterns(will_rename_caps);
11380 local
11381 .language_server_paths_watched_for_rename
11382 .insert(server_id, watcher);
11383 }
11384 }
11385
11386 self.language_server_statuses.insert(
11387 server_id,
11388 LanguageServerStatus {
11389 name: language_server.name(),
11390 server_version: language_server.version(),
11391 server_readable_version: language_server.readable_version(),
11392 pending_work: Default::default(),
11393 has_pending_diagnostic_updates: false,
11394 progress_tokens: Default::default(),
11395 worktree: Some(key.worktree_id),
11396 binary: Some(language_server.binary().clone()),
11397 configuration: Some(language_server.configuration().clone()),
11398 workspace_folders: language_server.workspace_folders(),
11399 process_id: language_server.process_id(),
11400 },
11401 );
11402
11403 cx.emit(LspStoreEvent::LanguageServerAdded(
11404 server_id,
11405 language_server.name(),
11406 Some(key.worktree_id),
11407 ));
11408
11409 let server_capabilities = language_server.capabilities();
11410 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11411 downstream_client
11412 .send(proto::StartLanguageServer {
11413 project_id: *project_id,
11414 server: Some(proto::LanguageServer {
11415 id: server_id.to_proto(),
11416 name: language_server.name().to_string(),
11417 worktree_id: Some(key.worktree_id.to_proto()),
11418 }),
11419 capabilities: serde_json::to_string(&server_capabilities)
11420 .expect("serializing server LSP capabilities"),
11421 })
11422 .log_err();
11423 }
11424 self.lsp_server_capabilities
11425 .insert(server_id, server_capabilities);
11426
11427 // Tell the language server about every open buffer in the worktree that matches the language.
11428 // Also check for buffers in worktrees that reused this server
11429 let mut worktrees_using_server = vec![key.worktree_id];
11430 if let Some(local) = self.as_local() {
11431 // Find all worktrees that have this server in their language server tree
11432 for (worktree_id, servers) in &local.lsp_tree.instances {
11433 if *worktree_id != key.worktree_id {
11434 for server_map in servers.roots.values() {
11435 if server_map
11436 .values()
11437 .any(|(node, _)| node.id() == Some(server_id))
11438 {
11439 worktrees_using_server.push(*worktree_id);
11440 }
11441 }
11442 }
11443 }
11444 }
11445
11446 let mut buffer_paths_registered = Vec::new();
11447 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11448 let mut lsp_adapters = HashMap::default();
11449 for buffer_handle in buffer_store.buffers() {
11450 let buffer = buffer_handle.read(cx);
11451 let file = match File::from_dyn(buffer.file()) {
11452 Some(file) => file,
11453 None => continue,
11454 };
11455 let language = match buffer.language() {
11456 Some(language) => language,
11457 None => continue,
11458 };
11459
11460 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11461 || !lsp_adapters
11462 .entry(language.name())
11463 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11464 .iter()
11465 .any(|a| a.name == key.name)
11466 {
11467 continue;
11468 }
11469 // didOpen
11470 let file = match file.as_local() {
11471 Some(file) => file,
11472 None => continue,
11473 };
11474
11475 let local = self.as_local_mut().unwrap();
11476
11477 let buffer_id = buffer.remote_id();
11478 if local.registered_buffers.contains_key(&buffer_id) {
11479 let abs_path = file.abs_path(cx);
11480 let uri = match lsp::Uri::from_file_path(&abs_path) {
11481 Ok(uri) => uri,
11482 Err(()) => {
11483 log::error!("failed to convert path to URI: {:?}", abs_path);
11484 continue;
11485 }
11486 };
11487
11488 let versions = local
11489 .buffer_snapshots
11490 .entry(buffer_id)
11491 .or_default()
11492 .entry(server_id)
11493 .and_modify(|_| {
11494 assert!(
11495 false,
11496 "There should not be an existing snapshot for a newly inserted buffer"
11497 )
11498 })
11499 .or_insert_with(|| {
11500 vec![LspBufferSnapshot {
11501 version: 0,
11502 snapshot: buffer.text_snapshot(),
11503 }]
11504 });
11505
11506 let snapshot = versions.last().unwrap();
11507 let version = snapshot.version;
11508 let initial_snapshot = &snapshot.snapshot;
11509 language_server.register_buffer(
11510 uri,
11511 adapter.language_id(&language.name()),
11512 version,
11513 initial_snapshot.text(),
11514 );
11515 buffer_paths_registered.push((buffer_id, abs_path));
11516 local
11517 .buffers_opened_in_servers
11518 .entry(buffer_id)
11519 .or_default()
11520 .insert(server_id);
11521 }
11522 buffer_handle.update(cx, |buffer, cx| {
11523 buffer.set_completion_triggers(
11524 server_id,
11525 language_server
11526 .capabilities()
11527 .completion_provider
11528 .as_ref()
11529 .and_then(|provider| {
11530 provider
11531 .trigger_characters
11532 .as_ref()
11533 .map(|characters| characters.iter().cloned().collect())
11534 })
11535 .unwrap_or_default(),
11536 cx,
11537 )
11538 });
11539 }
11540 });
11541
11542 for (buffer_id, abs_path) in buffer_paths_registered {
11543 cx.emit(LspStoreEvent::LanguageServerUpdate {
11544 language_server_id: server_id,
11545 name: Some(adapter.name()),
11546 message: proto::update_language_server::Variant::RegisteredForBuffer(
11547 proto::RegisteredForBuffer {
11548 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11549 buffer_id: buffer_id.to_proto(),
11550 },
11551 ),
11552 });
11553 }
11554
11555 cx.notify();
11556 }
11557
11558 pub fn language_servers_running_disk_based_diagnostics(
11559 &self,
11560 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11561 self.language_server_statuses
11562 .iter()
11563 .filter_map(|(id, status)| {
11564 if status.has_pending_diagnostic_updates {
11565 Some(*id)
11566 } else {
11567 None
11568 }
11569 })
11570 }
11571
11572 pub(crate) fn cancel_language_server_work_for_buffers(
11573 &mut self,
11574 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11575 cx: &mut Context<Self>,
11576 ) {
11577 if let Some((client, project_id)) = self.upstream_client() {
11578 let request = client.request(proto::CancelLanguageServerWork {
11579 project_id,
11580 work: Some(proto::cancel_language_server_work::Work::Buffers(
11581 proto::cancel_language_server_work::Buffers {
11582 buffer_ids: buffers
11583 .into_iter()
11584 .map(|b| b.read(cx).remote_id().to_proto())
11585 .collect(),
11586 },
11587 )),
11588 });
11589 cx.background_spawn(request).detach_and_log_err(cx);
11590 } else if let Some(local) = self.as_local() {
11591 let servers = buffers
11592 .into_iter()
11593 .flat_map(|buffer| {
11594 buffer.update(cx, |buffer, cx| {
11595 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11596 })
11597 })
11598 .collect::<HashSet<_>>();
11599 for server_id in servers {
11600 self.cancel_language_server_work(server_id, None, cx);
11601 }
11602 }
11603 }
11604
11605 pub(crate) fn cancel_language_server_work(
11606 &mut self,
11607 server_id: LanguageServerId,
11608 token_to_cancel: Option<ProgressToken>,
11609 cx: &mut Context<Self>,
11610 ) {
11611 if let Some(local) = self.as_local() {
11612 let status = self.language_server_statuses.get(&server_id);
11613 let server = local.language_servers.get(&server_id);
11614 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11615 {
11616 for (token, progress) in &status.pending_work {
11617 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11618 && token != token_to_cancel
11619 {
11620 continue;
11621 }
11622 if progress.is_cancellable {
11623 server
11624 .notify::<lsp::notification::WorkDoneProgressCancel>(
11625 WorkDoneProgressCancelParams {
11626 token: token.to_lsp(),
11627 },
11628 )
11629 .ok();
11630 }
11631 }
11632 }
11633 } else if let Some((client, project_id)) = self.upstream_client() {
11634 let request = client.request(proto::CancelLanguageServerWork {
11635 project_id,
11636 work: Some(
11637 proto::cancel_language_server_work::Work::LanguageServerWork(
11638 proto::cancel_language_server_work::LanguageServerWork {
11639 language_server_id: server_id.to_proto(),
11640 token: token_to_cancel.map(|token| token.to_proto()),
11641 },
11642 ),
11643 ),
11644 });
11645 cx.background_spawn(request).detach_and_log_err(cx);
11646 }
11647 }
11648
11649 fn register_supplementary_language_server(
11650 &mut self,
11651 id: LanguageServerId,
11652 name: LanguageServerName,
11653 server: Arc<LanguageServer>,
11654 cx: &mut Context<Self>,
11655 ) {
11656 if let Some(local) = self.as_local_mut() {
11657 local
11658 .supplementary_language_servers
11659 .insert(id, (name.clone(), server));
11660 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11661 }
11662 }
11663
11664 fn unregister_supplementary_language_server(
11665 &mut self,
11666 id: LanguageServerId,
11667 cx: &mut Context<Self>,
11668 ) {
11669 if let Some(local) = self.as_local_mut() {
11670 local.supplementary_language_servers.remove(&id);
11671 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11672 }
11673 }
11674
11675 pub(crate) fn supplementary_language_servers(
11676 &self,
11677 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11678 self.as_local().into_iter().flat_map(|local| {
11679 local
11680 .supplementary_language_servers
11681 .iter()
11682 .map(|(id, (name, _))| (*id, name.clone()))
11683 })
11684 }
11685
11686 pub fn language_server_adapter_for_id(
11687 &self,
11688 id: LanguageServerId,
11689 ) -> Option<Arc<CachedLspAdapter>> {
11690 self.as_local()
11691 .and_then(|local| local.language_servers.get(&id))
11692 .and_then(|language_server_state| match language_server_state {
11693 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11694 _ => None,
11695 })
11696 }
11697
11698 pub(super) fn update_local_worktree_language_servers(
11699 &mut self,
11700 worktree_handle: &Entity<Worktree>,
11701 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11702 cx: &mut Context<Self>,
11703 ) {
11704 if changes.is_empty() {
11705 return;
11706 }
11707
11708 let Some(local) = self.as_local() else { return };
11709
11710 local.prettier_store.update(cx, |prettier_store, cx| {
11711 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11712 });
11713
11714 let worktree_id = worktree_handle.read(cx).id();
11715 let mut language_server_ids = local
11716 .language_server_ids
11717 .iter()
11718 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11719 .collect::<Vec<_>>();
11720 language_server_ids.sort();
11721 language_server_ids.dedup();
11722
11723 // let abs_path = worktree_handle.read(cx).abs_path();
11724 for server_id in &language_server_ids {
11725 if let Some(LanguageServerState::Running { server, .. }) =
11726 local.language_servers.get(server_id)
11727 && let Some(watched_paths) = local
11728 .language_server_watched_paths
11729 .get(server_id)
11730 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11731 {
11732 let params = lsp::DidChangeWatchedFilesParams {
11733 changes: changes
11734 .iter()
11735 .filter_map(|(path, _, change)| {
11736 if !watched_paths.is_match(path.as_std_path()) {
11737 return None;
11738 }
11739 let typ = match change {
11740 PathChange::Loaded => return None,
11741 PathChange::Added => lsp::FileChangeType::CREATED,
11742 PathChange::Removed => lsp::FileChangeType::DELETED,
11743 PathChange::Updated => lsp::FileChangeType::CHANGED,
11744 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11745 };
11746 let uri = lsp::Uri::from_file_path(
11747 worktree_handle.read(cx).absolutize(&path),
11748 )
11749 .ok()?;
11750 Some(lsp::FileEvent { uri, typ })
11751 })
11752 .collect(),
11753 };
11754 if !params.changes.is_empty() {
11755 server
11756 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11757 .ok();
11758 }
11759 }
11760 }
11761 for (path, _, _) in changes {
11762 if let Some(file_name) = path.file_name()
11763 && local.watched_manifest_filenames.contains(file_name)
11764 {
11765 self.request_workspace_config_refresh();
11766 break;
11767 }
11768 }
11769 }
11770
11771 pub fn wait_for_remote_buffer(
11772 &mut self,
11773 id: BufferId,
11774 cx: &mut Context<Self>,
11775 ) -> Task<Result<Entity<Buffer>>> {
11776 self.buffer_store.update(cx, |buffer_store, cx| {
11777 buffer_store.wait_for_remote_buffer(id, cx)
11778 })
11779 }
11780
11781 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11782 let mut result = proto::Symbol {
11783 language_server_name: symbol.language_server_name.0.to_string(),
11784 source_worktree_id: symbol.source_worktree_id.to_proto(),
11785 language_server_id: symbol.source_language_server_id.to_proto(),
11786 name: symbol.name.clone(),
11787 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11788 start: Some(proto::PointUtf16 {
11789 row: symbol.range.start.0.row,
11790 column: symbol.range.start.0.column,
11791 }),
11792 end: Some(proto::PointUtf16 {
11793 row: symbol.range.end.0.row,
11794 column: symbol.range.end.0.column,
11795 }),
11796 worktree_id: Default::default(),
11797 path: Default::default(),
11798 signature: Default::default(),
11799 container_name: symbol.container_name.clone(),
11800 };
11801 match &symbol.path {
11802 SymbolLocation::InProject(path) => {
11803 result.worktree_id = path.worktree_id.to_proto();
11804 result.path = path.path.to_proto();
11805 }
11806 SymbolLocation::OutsideProject {
11807 abs_path,
11808 signature,
11809 } => {
11810 result.path = abs_path.to_string_lossy().into_owned();
11811 result.signature = signature.to_vec();
11812 }
11813 }
11814 result
11815 }
11816
11817 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11818 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11819 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11820 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11821
11822 let path = if serialized_symbol.signature.is_empty() {
11823 SymbolLocation::InProject(ProjectPath {
11824 worktree_id,
11825 path: RelPath::from_proto(&serialized_symbol.path)
11826 .context("invalid symbol path")?,
11827 })
11828 } else {
11829 SymbolLocation::OutsideProject {
11830 abs_path: Path::new(&serialized_symbol.path).into(),
11831 signature: serialized_symbol
11832 .signature
11833 .try_into()
11834 .map_err(|_| anyhow!("invalid signature"))?,
11835 }
11836 };
11837
11838 let start = serialized_symbol.start.context("invalid start")?;
11839 let end = serialized_symbol.end.context("invalid end")?;
11840 Ok(CoreSymbol {
11841 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11842 source_worktree_id,
11843 source_language_server_id: LanguageServerId::from_proto(
11844 serialized_symbol.language_server_id,
11845 ),
11846 path,
11847 name: serialized_symbol.name,
11848 range: Unclipped(PointUtf16::new(start.row, start.column))
11849 ..Unclipped(PointUtf16::new(end.row, end.column)),
11850 kind,
11851 container_name: serialized_symbol.container_name,
11852 })
11853 }
11854
11855 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11856 let mut serialized_completion = proto::Completion {
11857 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11858 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11859 new_text: completion.new_text.clone(),
11860 ..proto::Completion::default()
11861 };
11862 match &completion.source {
11863 CompletionSource::Lsp {
11864 insert_range,
11865 server_id,
11866 lsp_completion,
11867 lsp_defaults,
11868 resolved,
11869 } => {
11870 let (old_insert_start, old_insert_end) = insert_range
11871 .as_ref()
11872 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11873 .unzip();
11874
11875 serialized_completion.old_insert_start = old_insert_start;
11876 serialized_completion.old_insert_end = old_insert_end;
11877 serialized_completion.source = proto::completion::Source::Lsp as i32;
11878 serialized_completion.server_id = server_id.0 as u64;
11879 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11880 serialized_completion.lsp_defaults = lsp_defaults
11881 .as_deref()
11882 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11883 serialized_completion.resolved = *resolved;
11884 }
11885 CompletionSource::BufferWord {
11886 word_range,
11887 resolved,
11888 } => {
11889 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11890 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11891 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11892 serialized_completion.resolved = *resolved;
11893 }
11894 CompletionSource::Custom => {
11895 serialized_completion.source = proto::completion::Source::Custom as i32;
11896 serialized_completion.resolved = true;
11897 }
11898 CompletionSource::Dap { sort_text } => {
11899 serialized_completion.source = proto::completion::Source::Dap as i32;
11900 serialized_completion.sort_text = Some(sort_text.clone());
11901 }
11902 }
11903
11904 serialized_completion
11905 }
11906
11907 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11908 let old_replace_start = completion
11909 .old_replace_start
11910 .and_then(deserialize_anchor)
11911 .context("invalid old start")?;
11912 let old_replace_end = completion
11913 .old_replace_end
11914 .and_then(deserialize_anchor)
11915 .context("invalid old end")?;
11916 let insert_range = {
11917 match completion.old_insert_start.zip(completion.old_insert_end) {
11918 Some((start, end)) => {
11919 let start = deserialize_anchor(start).context("invalid insert old start")?;
11920 let end = deserialize_anchor(end).context("invalid insert old end")?;
11921 Some(start..end)
11922 }
11923 None => None,
11924 }
11925 };
11926 Ok(CoreCompletion {
11927 replace_range: old_replace_start..old_replace_end,
11928 new_text: completion.new_text,
11929 source: match proto::completion::Source::from_i32(completion.source) {
11930 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11931 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11932 insert_range,
11933 server_id: LanguageServerId::from_proto(completion.server_id),
11934 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11935 lsp_defaults: completion
11936 .lsp_defaults
11937 .as_deref()
11938 .map(serde_json::from_slice)
11939 .transpose()?,
11940 resolved: completion.resolved,
11941 },
11942 Some(proto::completion::Source::BufferWord) => {
11943 let word_range = completion
11944 .buffer_word_start
11945 .and_then(deserialize_anchor)
11946 .context("invalid buffer word start")?
11947 ..completion
11948 .buffer_word_end
11949 .and_then(deserialize_anchor)
11950 .context("invalid buffer word end")?;
11951 CompletionSource::BufferWord {
11952 word_range,
11953 resolved: completion.resolved,
11954 }
11955 }
11956 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11957 sort_text: completion
11958 .sort_text
11959 .context("expected sort text to exist")?,
11960 },
11961 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11962 },
11963 })
11964 }
11965
11966 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11967 let (kind, lsp_action) = match &action.lsp_action {
11968 LspAction::Action(code_action) => (
11969 proto::code_action::Kind::Action as i32,
11970 serde_json::to_vec(code_action).unwrap(),
11971 ),
11972 LspAction::Command(command) => (
11973 proto::code_action::Kind::Command as i32,
11974 serde_json::to_vec(command).unwrap(),
11975 ),
11976 LspAction::CodeLens(code_lens) => (
11977 proto::code_action::Kind::CodeLens as i32,
11978 serde_json::to_vec(code_lens).unwrap(),
11979 ),
11980 };
11981
11982 proto::CodeAction {
11983 server_id: action.server_id.0 as u64,
11984 start: Some(serialize_anchor(&action.range.start)),
11985 end: Some(serialize_anchor(&action.range.end)),
11986 lsp_action,
11987 kind,
11988 resolved: action.resolved,
11989 }
11990 }
11991
11992 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11993 let start = action
11994 .start
11995 .and_then(deserialize_anchor)
11996 .context("invalid start")?;
11997 let end = action
11998 .end
11999 .and_then(deserialize_anchor)
12000 .context("invalid end")?;
12001 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
12002 Some(proto::code_action::Kind::Action) => {
12003 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
12004 }
12005 Some(proto::code_action::Kind::Command) => {
12006 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
12007 }
12008 Some(proto::code_action::Kind::CodeLens) => {
12009 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
12010 }
12011 None => anyhow::bail!("Unknown action kind {}", action.kind),
12012 };
12013 Ok(CodeAction {
12014 server_id: LanguageServerId(action.server_id as usize),
12015 range: start..end,
12016 resolved: action.resolved,
12017 lsp_action,
12018 })
12019 }
12020
12021 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
12022 match &formatting_result {
12023 Ok(_) => self.last_formatting_failure = None,
12024 Err(error) => {
12025 let error_string = format!("{error:#}");
12026 log::error!("Formatting failed: {error_string}");
12027 self.last_formatting_failure
12028 .replace(error_string.lines().join(" "));
12029 }
12030 }
12031 }
12032
12033 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
12034 self.lsp_server_capabilities.remove(&for_server);
12035 self.semantic_token_config.remove_server_data(for_server);
12036 for lsp_data in self.lsp_data.values_mut() {
12037 lsp_data.remove_server_data(for_server);
12038 }
12039 if let Some(local) = self.as_local_mut() {
12040 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
12041 local
12042 .workspace_pull_diagnostics_result_ids
12043 .remove(&for_server);
12044 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
12045 buffer_servers.remove(&for_server);
12046 }
12047 }
12048 }
12049
12050 pub fn result_id_for_buffer_pull(
12051 &self,
12052 server_id: LanguageServerId,
12053 buffer_id: BufferId,
12054 registration_id: &Option<SharedString>,
12055 cx: &App,
12056 ) -> Option<SharedString> {
12057 let abs_path = self
12058 .buffer_store
12059 .read(cx)
12060 .get(buffer_id)
12061 .and_then(|b| File::from_dyn(b.read(cx).file()))
12062 .map(|f| f.abs_path(cx))?;
12063 self.as_local()?
12064 .buffer_pull_diagnostics_result_ids
12065 .get(&server_id)?
12066 .get(registration_id)?
12067 .get(&abs_path)?
12068 .clone()
12069 }
12070
12071 /// Gets all result_ids for a workspace diagnostics pull request.
12072 /// 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.
12073 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
12074 pub fn result_ids_for_workspace_refresh(
12075 &self,
12076 server_id: LanguageServerId,
12077 registration_id: &Option<SharedString>,
12078 ) -> HashMap<PathBuf, SharedString> {
12079 let Some(local) = self.as_local() else {
12080 return HashMap::default();
12081 };
12082 local
12083 .workspace_pull_diagnostics_result_ids
12084 .get(&server_id)
12085 .into_iter()
12086 .filter_map(|diagnostics| diagnostics.get(registration_id))
12087 .flatten()
12088 .filter_map(|(abs_path, result_id)| {
12089 let result_id = local
12090 .buffer_pull_diagnostics_result_ids
12091 .get(&server_id)
12092 .and_then(|buffer_ids_result_ids| {
12093 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12094 })
12095 .cloned()
12096 .flatten()
12097 .or_else(|| result_id.clone())?;
12098 Some((abs_path.clone(), result_id))
12099 })
12100 .collect()
12101 }
12102
12103 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12104 if let Some(LanguageServerState::Running {
12105 workspace_diagnostics_refresh_tasks,
12106 ..
12107 }) = self
12108 .as_local_mut()
12109 .and_then(|local| local.language_servers.get_mut(&server_id))
12110 {
12111 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12112 diagnostics.refresh_tx.try_send(()).ok();
12113 }
12114 }
12115 }
12116
12117 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12118 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12119 /// which requires refreshing both workspace and document diagnostics.
12120 pub fn pull_document_diagnostics_for_server(
12121 &mut self,
12122 server_id: LanguageServerId,
12123 source_buffer_id: Option<BufferId>,
12124 cx: &mut Context<Self>,
12125 ) -> Shared<Task<()>> {
12126 let Some(local) = self.as_local_mut() else {
12127 return Task::ready(()).shared();
12128 };
12129 let mut buffers_to_refresh = HashSet::default();
12130 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12131 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12132 buffers_to_refresh.insert(*buffer_id);
12133 }
12134 }
12135
12136 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12137 }
12138
12139 pub fn pull_document_diagnostics_for_buffer_edit(
12140 &mut self,
12141 buffer_id: BufferId,
12142 cx: &mut Context<Self>,
12143 ) {
12144 let Some(local) = self.as_local_mut() else {
12145 return;
12146 };
12147 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12148 else {
12149 return;
12150 };
12151 for server_id in languages_servers {
12152 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12153 }
12154 }
12155
12156 fn apply_workspace_diagnostic_report(
12157 &mut self,
12158 server_id: LanguageServerId,
12159 report: lsp::WorkspaceDiagnosticReportResult,
12160 registration_id: Option<SharedString>,
12161 cx: &mut Context<Self>,
12162 ) {
12163 let mut workspace_diagnostics =
12164 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12165 report,
12166 server_id,
12167 registration_id,
12168 );
12169 workspace_diagnostics.retain(|d| match &d.diagnostics {
12170 LspPullDiagnostics::Response {
12171 server_id,
12172 registration_id,
12173 ..
12174 } => self.diagnostic_registration_exists(*server_id, registration_id),
12175 LspPullDiagnostics::Default => false,
12176 });
12177 let mut unchanged_buffers = HashMap::default();
12178 let workspace_diagnostics_updates = workspace_diagnostics
12179 .into_iter()
12180 .filter_map(
12181 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12182 LspPullDiagnostics::Response {
12183 server_id,
12184 uri,
12185 diagnostics,
12186 registration_id,
12187 } => Some((
12188 server_id,
12189 uri,
12190 diagnostics,
12191 workspace_diagnostics.version,
12192 registration_id,
12193 )),
12194 LspPullDiagnostics::Default => None,
12195 },
12196 )
12197 .fold(
12198 HashMap::default(),
12199 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12200 let (result_id, diagnostics) = match diagnostics {
12201 PulledDiagnostics::Unchanged { result_id } => {
12202 unchanged_buffers
12203 .entry(new_registration_id.clone())
12204 .or_insert_with(HashSet::default)
12205 .insert(uri.clone());
12206 (Some(result_id), Vec::new())
12207 }
12208 PulledDiagnostics::Changed {
12209 result_id,
12210 diagnostics,
12211 } => (result_id, diagnostics),
12212 };
12213 let disk_based_sources = Cow::Owned(
12214 self.language_server_adapter_for_id(server_id)
12215 .as_ref()
12216 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12217 .unwrap_or(&[])
12218 .to_vec(),
12219 );
12220
12221 let Some(abs_path) = uri.to_file_path().ok() else {
12222 return acc;
12223 };
12224 let Some((worktree, relative_path)) =
12225 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12226 else {
12227 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12228 return acc;
12229 };
12230 let worktree_id = worktree.read(cx).id();
12231 let project_path = ProjectPath {
12232 worktree_id,
12233 path: relative_path,
12234 };
12235 if let Some(local_lsp_store) = self.as_local_mut() {
12236 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12237 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12238 }
12239 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12240 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12241 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12242 acc.entry(server_id)
12243 .or_insert_with(HashMap::default)
12244 .entry(new_registration_id.clone())
12245 .or_insert_with(Vec::new)
12246 .push(DocumentDiagnosticsUpdate {
12247 server_id,
12248 diagnostics: lsp::PublishDiagnosticsParams {
12249 uri,
12250 diagnostics,
12251 version,
12252 },
12253 result_id: result_id.map(SharedString::new),
12254 disk_based_sources,
12255 registration_id: new_registration_id,
12256 });
12257 }
12258 acc
12259 },
12260 );
12261
12262 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12263 for (registration_id, diagnostic_updates) in diagnostic_updates {
12264 self.merge_lsp_diagnostics(
12265 DiagnosticSourceKind::Pulled,
12266 diagnostic_updates,
12267 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12268 DiagnosticSourceKind::Pulled => {
12269 old_diagnostic.registration_id != registration_id
12270 || unchanged_buffers
12271 .get(&old_diagnostic.registration_id)
12272 .is_some_and(|unchanged_buffers| {
12273 unchanged_buffers.contains(&document_uri)
12274 })
12275 }
12276 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12277 },
12278 cx,
12279 )
12280 .log_err();
12281 }
12282 }
12283 }
12284
12285 fn register_server_capabilities(
12286 &mut self,
12287 server_id: LanguageServerId,
12288 params: lsp::RegistrationParams,
12289 cx: &mut Context<Self>,
12290 ) -> anyhow::Result<()> {
12291 let server = self
12292 .language_server_for_id(server_id)
12293 .with_context(|| format!("no server {server_id} found"))?;
12294 for reg in params.registrations {
12295 match reg.method.as_str() {
12296 "workspace/didChangeWatchedFiles" => {
12297 if let Some(options) = reg.register_options {
12298 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12299 let caps = serde_json::from_value(options)?;
12300 local_lsp_store
12301 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12302 true
12303 } else {
12304 false
12305 };
12306 if notify {
12307 notify_server_capabilities_updated(&server, cx);
12308 }
12309 }
12310 }
12311 "workspace/didChangeConfiguration" => {
12312 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12313 }
12314 "workspace/didChangeWorkspaceFolders" => {
12315 // In this case register options is an empty object, we can ignore it
12316 let caps = lsp::WorkspaceFoldersServerCapabilities {
12317 supported: Some(true),
12318 change_notifications: Some(OneOf::Right(reg.id)),
12319 };
12320 server.update_capabilities(|capabilities| {
12321 capabilities
12322 .workspace
12323 .get_or_insert_default()
12324 .workspace_folders = Some(caps);
12325 });
12326 notify_server_capabilities_updated(&server, cx);
12327 }
12328 "workspace/symbol" => {
12329 let options = parse_register_capabilities(reg)?;
12330 server.update_capabilities(|capabilities| {
12331 capabilities.workspace_symbol_provider = Some(options);
12332 });
12333 notify_server_capabilities_updated(&server, cx);
12334 }
12335 "workspace/fileOperations" => {
12336 if let Some(options) = reg.register_options {
12337 let caps = serde_json::from_value(options)?;
12338 server.update_capabilities(|capabilities| {
12339 capabilities
12340 .workspace
12341 .get_or_insert_default()
12342 .file_operations = Some(caps);
12343 });
12344 notify_server_capabilities_updated(&server, cx);
12345 }
12346 }
12347 "workspace/executeCommand" => {
12348 if let Some(options) = reg.register_options {
12349 let options = serde_json::from_value(options)?;
12350 server.update_capabilities(|capabilities| {
12351 capabilities.execute_command_provider = Some(options);
12352 });
12353 notify_server_capabilities_updated(&server, cx);
12354 }
12355 }
12356 "textDocument/rangeFormatting" => {
12357 let options = parse_register_capabilities(reg)?;
12358 server.update_capabilities(|capabilities| {
12359 capabilities.document_range_formatting_provider = Some(options);
12360 });
12361 notify_server_capabilities_updated(&server, cx);
12362 }
12363 "textDocument/onTypeFormatting" => {
12364 if let Some(options) = reg
12365 .register_options
12366 .map(serde_json::from_value)
12367 .transpose()?
12368 {
12369 server.update_capabilities(|capabilities| {
12370 capabilities.document_on_type_formatting_provider = Some(options);
12371 });
12372 notify_server_capabilities_updated(&server, cx);
12373 }
12374 }
12375 "textDocument/formatting" => {
12376 let options = parse_register_capabilities(reg)?;
12377 server.update_capabilities(|capabilities| {
12378 capabilities.document_formatting_provider = Some(options);
12379 });
12380 notify_server_capabilities_updated(&server, cx);
12381 }
12382 "textDocument/rename" => {
12383 let options = parse_register_capabilities(reg)?;
12384 server.update_capabilities(|capabilities| {
12385 capabilities.rename_provider = Some(options);
12386 });
12387 notify_server_capabilities_updated(&server, cx);
12388 }
12389 "textDocument/inlayHint" => {
12390 let options = parse_register_capabilities(reg)?;
12391 server.update_capabilities(|capabilities| {
12392 capabilities.inlay_hint_provider = Some(options);
12393 });
12394 notify_server_capabilities_updated(&server, cx);
12395 }
12396 "textDocument/documentSymbol" => {
12397 let options = parse_register_capabilities(reg)?;
12398 server.update_capabilities(|capabilities| {
12399 capabilities.document_symbol_provider = Some(options);
12400 });
12401 notify_server_capabilities_updated(&server, cx);
12402 }
12403 "textDocument/codeAction" => {
12404 let options = parse_register_capabilities(reg)?;
12405 let provider = match options {
12406 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12407 OneOf::Right(caps) => caps,
12408 };
12409 server.update_capabilities(|capabilities| {
12410 capabilities.code_action_provider = Some(provider);
12411 });
12412 notify_server_capabilities_updated(&server, cx);
12413 }
12414 "textDocument/definition" => {
12415 let options = parse_register_capabilities(reg)?;
12416 server.update_capabilities(|capabilities| {
12417 capabilities.definition_provider = Some(options);
12418 });
12419 notify_server_capabilities_updated(&server, cx);
12420 }
12421 "textDocument/completion" => {
12422 if let Some(caps) = reg
12423 .register_options
12424 .map(serde_json::from_value::<CompletionOptions>)
12425 .transpose()?
12426 {
12427 server.update_capabilities(|capabilities| {
12428 capabilities.completion_provider = Some(caps.clone());
12429 });
12430
12431 if let Some(local) = self.as_local() {
12432 let mut buffers_with_language_server = Vec::new();
12433 for handle in self.buffer_store.read(cx).buffers() {
12434 let buffer_id = handle.read(cx).remote_id();
12435 if local
12436 .buffers_opened_in_servers
12437 .get(&buffer_id)
12438 .filter(|s| s.contains(&server_id))
12439 .is_some()
12440 {
12441 buffers_with_language_server.push(handle);
12442 }
12443 }
12444 let triggers = caps
12445 .trigger_characters
12446 .unwrap_or_default()
12447 .into_iter()
12448 .collect::<BTreeSet<_>>();
12449 for handle in buffers_with_language_server {
12450 let triggers = triggers.clone();
12451 let _ = handle.update(cx, move |buffer, cx| {
12452 buffer.set_completion_triggers(server_id, triggers, cx);
12453 });
12454 }
12455 }
12456 notify_server_capabilities_updated(&server, cx);
12457 }
12458 }
12459 "textDocument/hover" => {
12460 let options = parse_register_capabilities(reg)?;
12461 let provider = match options {
12462 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12463 OneOf::Right(caps) => caps,
12464 };
12465 server.update_capabilities(|capabilities| {
12466 capabilities.hover_provider = Some(provider);
12467 });
12468 notify_server_capabilities_updated(&server, cx);
12469 }
12470 "textDocument/signatureHelp" => {
12471 if let Some(caps) = reg
12472 .register_options
12473 .map(serde_json::from_value)
12474 .transpose()?
12475 {
12476 server.update_capabilities(|capabilities| {
12477 capabilities.signature_help_provider = Some(caps);
12478 });
12479 notify_server_capabilities_updated(&server, cx);
12480 }
12481 }
12482 "textDocument/didChange" => {
12483 if let Some(sync_kind) = reg
12484 .register_options
12485 .and_then(|opts| opts.get("syncKind").cloned())
12486 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12487 .transpose()?
12488 {
12489 server.update_capabilities(|capabilities| {
12490 let mut sync_options =
12491 Self::take_text_document_sync_options(capabilities);
12492 sync_options.change = Some(sync_kind);
12493 capabilities.text_document_sync =
12494 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12495 });
12496 notify_server_capabilities_updated(&server, cx);
12497 }
12498 }
12499 "textDocument/didSave" => {
12500 if let Some(include_text) = reg
12501 .register_options
12502 .map(|opts| {
12503 let transpose = opts
12504 .get("includeText")
12505 .cloned()
12506 .map(serde_json::from_value::<Option<bool>>)
12507 .transpose();
12508 match transpose {
12509 Ok(value) => Ok(value.flatten()),
12510 Err(e) => Err(e),
12511 }
12512 })
12513 .transpose()?
12514 {
12515 server.update_capabilities(|capabilities| {
12516 let mut sync_options =
12517 Self::take_text_document_sync_options(capabilities);
12518 sync_options.save =
12519 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12520 include_text,
12521 }));
12522 capabilities.text_document_sync =
12523 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12524 });
12525 notify_server_capabilities_updated(&server, cx);
12526 }
12527 }
12528 "textDocument/codeLens" => {
12529 if let Some(caps) = reg
12530 .register_options
12531 .map(serde_json::from_value)
12532 .transpose()?
12533 {
12534 server.update_capabilities(|capabilities| {
12535 capabilities.code_lens_provider = Some(caps);
12536 });
12537 notify_server_capabilities_updated(&server, cx);
12538 }
12539 }
12540 "textDocument/diagnostic" => {
12541 if let Some(caps) = reg
12542 .register_options
12543 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12544 .transpose()?
12545 {
12546 let local = self
12547 .as_local_mut()
12548 .context("Expected LSP Store to be local")?;
12549 let state = local
12550 .language_servers
12551 .get_mut(&server_id)
12552 .context("Could not obtain Language Servers state")?;
12553 local
12554 .language_server_dynamic_registrations
12555 .entry(server_id)
12556 .or_default()
12557 .diagnostics
12558 .insert(Some(reg.id.clone()), caps.clone());
12559
12560 let supports_workspace_diagnostics =
12561 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12562 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12563 diagnostic_options.workspace_diagnostics
12564 }
12565 DiagnosticServerCapabilities::RegistrationOptions(
12566 diagnostic_registration_options,
12567 ) => {
12568 diagnostic_registration_options
12569 .diagnostic_options
12570 .workspace_diagnostics
12571 }
12572 };
12573
12574 if supports_workspace_diagnostics(&caps) {
12575 if let LanguageServerState::Running {
12576 workspace_diagnostics_refresh_tasks,
12577 ..
12578 } = state
12579 && let Some(task) = lsp_workspace_diagnostics_refresh(
12580 Some(reg.id.clone()),
12581 caps.clone(),
12582 server.clone(),
12583 cx,
12584 )
12585 {
12586 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12587 }
12588 }
12589
12590 server.update_capabilities(|capabilities| {
12591 capabilities.diagnostic_provider = Some(caps);
12592 });
12593
12594 notify_server_capabilities_updated(&server, cx);
12595
12596 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12597 }
12598 }
12599 "textDocument/documentColor" => {
12600 let options = parse_register_capabilities(reg)?;
12601 let provider = match options {
12602 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12603 OneOf::Right(caps) => caps,
12604 };
12605 server.update_capabilities(|capabilities| {
12606 capabilities.color_provider = Some(provider);
12607 });
12608 notify_server_capabilities_updated(&server, cx);
12609 }
12610 "textDocument/foldingRange" => {
12611 let options = parse_register_capabilities(reg)?;
12612 let provider = match options {
12613 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12614 OneOf::Right(caps) => caps,
12615 };
12616 server.update_capabilities(|capabilities| {
12617 capabilities.folding_range_provider = Some(provider);
12618 });
12619 notify_server_capabilities_updated(&server, cx);
12620 }
12621 _ => log::warn!("unhandled capability registration: {reg:?}"),
12622 }
12623 }
12624
12625 Ok(())
12626 }
12627
12628 fn unregister_server_capabilities(
12629 &mut self,
12630 server_id: LanguageServerId,
12631 params: lsp::UnregistrationParams,
12632 cx: &mut Context<Self>,
12633 ) -> anyhow::Result<()> {
12634 let server = self
12635 .language_server_for_id(server_id)
12636 .with_context(|| format!("no server {server_id} found"))?;
12637 for unreg in params.unregisterations.iter() {
12638 match unreg.method.as_str() {
12639 "workspace/didChangeWatchedFiles" => {
12640 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12641 local_lsp_store
12642 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12643 true
12644 } else {
12645 false
12646 };
12647 if notify {
12648 notify_server_capabilities_updated(&server, cx);
12649 }
12650 }
12651 "workspace/didChangeConfiguration" => {
12652 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12653 }
12654 "workspace/didChangeWorkspaceFolders" => {
12655 server.update_capabilities(|capabilities| {
12656 capabilities
12657 .workspace
12658 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12659 workspace_folders: None,
12660 file_operations: None,
12661 })
12662 .workspace_folders = None;
12663 });
12664 notify_server_capabilities_updated(&server, cx);
12665 }
12666 "workspace/symbol" => {
12667 server.update_capabilities(|capabilities| {
12668 capabilities.workspace_symbol_provider = None
12669 });
12670 notify_server_capabilities_updated(&server, cx);
12671 }
12672 "workspace/fileOperations" => {
12673 server.update_capabilities(|capabilities| {
12674 capabilities
12675 .workspace
12676 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12677 workspace_folders: None,
12678 file_operations: None,
12679 })
12680 .file_operations = None;
12681 });
12682 notify_server_capabilities_updated(&server, cx);
12683 }
12684 "workspace/executeCommand" => {
12685 server.update_capabilities(|capabilities| {
12686 capabilities.execute_command_provider = None;
12687 });
12688 notify_server_capabilities_updated(&server, cx);
12689 }
12690 "textDocument/rangeFormatting" => {
12691 server.update_capabilities(|capabilities| {
12692 capabilities.document_range_formatting_provider = None
12693 });
12694 notify_server_capabilities_updated(&server, cx);
12695 }
12696 "textDocument/onTypeFormatting" => {
12697 server.update_capabilities(|capabilities| {
12698 capabilities.document_on_type_formatting_provider = None;
12699 });
12700 notify_server_capabilities_updated(&server, cx);
12701 }
12702 "textDocument/formatting" => {
12703 server.update_capabilities(|capabilities| {
12704 capabilities.document_formatting_provider = None;
12705 });
12706 notify_server_capabilities_updated(&server, cx);
12707 }
12708 "textDocument/rename" => {
12709 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12710 notify_server_capabilities_updated(&server, cx);
12711 }
12712 "textDocument/codeAction" => {
12713 server.update_capabilities(|capabilities| {
12714 capabilities.code_action_provider = None;
12715 });
12716 notify_server_capabilities_updated(&server, cx);
12717 }
12718 "textDocument/definition" => {
12719 server.update_capabilities(|capabilities| {
12720 capabilities.definition_provider = None;
12721 });
12722 notify_server_capabilities_updated(&server, cx);
12723 }
12724 "textDocument/completion" => {
12725 server.update_capabilities(|capabilities| {
12726 capabilities.completion_provider = None;
12727 });
12728 notify_server_capabilities_updated(&server, cx);
12729 }
12730 "textDocument/hover" => {
12731 server.update_capabilities(|capabilities| {
12732 capabilities.hover_provider = None;
12733 });
12734 notify_server_capabilities_updated(&server, cx);
12735 }
12736 "textDocument/signatureHelp" => {
12737 server.update_capabilities(|capabilities| {
12738 capabilities.signature_help_provider = None;
12739 });
12740 notify_server_capabilities_updated(&server, cx);
12741 }
12742 "textDocument/didChange" => {
12743 server.update_capabilities(|capabilities| {
12744 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12745 sync_options.change = None;
12746 capabilities.text_document_sync =
12747 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12748 });
12749 notify_server_capabilities_updated(&server, cx);
12750 }
12751 "textDocument/didSave" => {
12752 server.update_capabilities(|capabilities| {
12753 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12754 sync_options.save = None;
12755 capabilities.text_document_sync =
12756 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12757 });
12758 notify_server_capabilities_updated(&server, cx);
12759 }
12760 "textDocument/codeLens" => {
12761 server.update_capabilities(|capabilities| {
12762 capabilities.code_lens_provider = None;
12763 });
12764 notify_server_capabilities_updated(&server, cx);
12765 }
12766 "textDocument/diagnostic" => {
12767 let local = self
12768 .as_local_mut()
12769 .context("Expected LSP Store to be local")?;
12770
12771 let state = local
12772 .language_servers
12773 .get_mut(&server_id)
12774 .context("Could not obtain Language Servers state")?;
12775 let registrations = local
12776 .language_server_dynamic_registrations
12777 .get_mut(&server_id)
12778 .with_context(|| {
12779 format!("Expected dynamic registration to exist for server {server_id}")
12780 })?;
12781 registrations.diagnostics
12782 .remove(&Some(unreg.id.clone()))
12783 .with_context(|| format!(
12784 "Attempted to unregister non-existent diagnostic registration with ID {}",
12785 unreg.id)
12786 )?;
12787 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12788
12789 if let LanguageServerState::Running {
12790 workspace_diagnostics_refresh_tasks,
12791 ..
12792 } = state
12793 {
12794 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12795 }
12796
12797 self.clear_unregistered_diagnostics(
12798 server_id,
12799 SharedString::from(unreg.id.clone()),
12800 cx,
12801 )?;
12802
12803 if removed_last_diagnostic_provider {
12804 server.update_capabilities(|capabilities| {
12805 debug_assert!(capabilities.diagnostic_provider.is_some());
12806 capabilities.diagnostic_provider = None;
12807 });
12808 }
12809
12810 notify_server_capabilities_updated(&server, cx);
12811 }
12812 "textDocument/documentColor" => {
12813 server.update_capabilities(|capabilities| {
12814 capabilities.color_provider = None;
12815 });
12816 notify_server_capabilities_updated(&server, cx);
12817 }
12818 "textDocument/foldingRange" => {
12819 server.update_capabilities(|capabilities| {
12820 capabilities.folding_range_provider = None;
12821 });
12822 notify_server_capabilities_updated(&server, cx);
12823 }
12824 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12825 }
12826 }
12827
12828 Ok(())
12829 }
12830
12831 fn clear_unregistered_diagnostics(
12832 &mut self,
12833 server_id: LanguageServerId,
12834 cleared_registration_id: SharedString,
12835 cx: &mut Context<Self>,
12836 ) -> anyhow::Result<()> {
12837 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12838
12839 self.buffer_store.update(cx, |buffer_store, cx| {
12840 for buffer_handle in buffer_store.buffers() {
12841 let buffer = buffer_handle.read(cx);
12842 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12843 let Some(abs_path) = abs_path else {
12844 continue;
12845 };
12846 affected_abs_paths.insert(abs_path);
12847 }
12848 });
12849
12850 let local = self.as_local().context("Expected LSP Store to be local")?;
12851 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12852 let Some(worktree) = self
12853 .worktree_store
12854 .read(cx)
12855 .worktree_for_id(*worktree_id, cx)
12856 else {
12857 continue;
12858 };
12859
12860 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12861 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12862 let has_matching_registration =
12863 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12864 entry.diagnostic.registration_id.as_ref()
12865 == Some(&cleared_registration_id)
12866 });
12867 if has_matching_registration {
12868 let abs_path = worktree.read(cx).absolutize(rel_path);
12869 affected_abs_paths.insert(abs_path);
12870 }
12871 }
12872 }
12873 }
12874
12875 if affected_abs_paths.is_empty() {
12876 return Ok(());
12877 }
12878
12879 // Send a fake diagnostic update which clears the state for the registration ID
12880 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12881 affected_abs_paths
12882 .into_iter()
12883 .map(|abs_path| DocumentDiagnosticsUpdate {
12884 diagnostics: DocumentDiagnostics {
12885 diagnostics: Vec::new(),
12886 document_abs_path: abs_path,
12887 version: None,
12888 },
12889 result_id: None,
12890 registration_id: Some(cleared_registration_id.clone()),
12891 server_id,
12892 disk_based_sources: Cow::Borrowed(&[]),
12893 })
12894 .collect();
12895
12896 let merge_registration_id = cleared_registration_id.clone();
12897 self.merge_diagnostic_entries(
12898 clears,
12899 move |_, diagnostic, _| {
12900 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12901 diagnostic.registration_id != Some(merge_registration_id.clone())
12902 } else {
12903 true
12904 }
12905 },
12906 cx,
12907 )?;
12908
12909 Ok(())
12910 }
12911
12912 async fn deduplicate_range_based_lsp_requests<T>(
12913 lsp_store: &Entity<Self>,
12914 server_id: Option<LanguageServerId>,
12915 lsp_request_id: LspRequestId,
12916 proto_request: &T::ProtoRequest,
12917 range: Range<Anchor>,
12918 cx: &mut AsyncApp,
12919 ) -> Result<()>
12920 where
12921 T: LspCommand,
12922 T::ProtoRequest: proto::LspRequestMessage,
12923 {
12924 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12925 let version = deserialize_version(proto_request.buffer_version());
12926 let buffer = lsp_store.update(cx, |this, cx| {
12927 this.buffer_store.read(cx).get_existing(buffer_id)
12928 })?;
12929 buffer
12930 .update(cx, |buffer, _| buffer.wait_for_version(version))
12931 .await?;
12932 lsp_store.update(cx, |lsp_store, cx| {
12933 let buffer_snapshot = buffer.read(cx).snapshot();
12934 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12935 let chunks_queried_for = lsp_data
12936 .inlay_hints
12937 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12938 .collect::<Vec<_>>();
12939 match chunks_queried_for.as_slice() {
12940 &[chunk] => {
12941 let key = LspKey {
12942 request_type: TypeId::of::<T>(),
12943 server_queried: server_id,
12944 };
12945 let previous_request = lsp_data
12946 .chunk_lsp_requests
12947 .entry(key)
12948 .or_default()
12949 .insert(chunk, lsp_request_id);
12950 if let Some((previous_request, running_requests)) =
12951 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12952 {
12953 running_requests.remove(&previous_request);
12954 }
12955 }
12956 _ambiguous_chunks => {
12957 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12958 // there, a buffer version-based check will be performed and outdated requests discarded.
12959 }
12960 }
12961 anyhow::Ok(())
12962 })?;
12963
12964 Ok(())
12965 }
12966
12967 async fn query_lsp_locally<T>(
12968 lsp_store: Entity<Self>,
12969 for_server_id: Option<LanguageServerId>,
12970 sender_id: proto::PeerId,
12971 lsp_request_id: LspRequestId,
12972 proto_request: T::ProtoRequest,
12973 position: Option<Anchor>,
12974 cx: &mut AsyncApp,
12975 ) -> Result<()>
12976 where
12977 T: LspCommand + Clone,
12978 T::ProtoRequest: proto::LspRequestMessage,
12979 <T::ProtoRequest as proto::RequestMessage>::Response:
12980 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12981 {
12982 let (buffer_version, buffer) =
12983 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12984 let request =
12985 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12986 let key = LspKey {
12987 request_type: TypeId::of::<T>(),
12988 server_queried: for_server_id,
12989 };
12990 lsp_store.update(cx, |lsp_store, cx| {
12991 let request_task = match for_server_id {
12992 Some(server_id) => {
12993 let server_task = lsp_store.request_lsp(
12994 buffer.clone(),
12995 LanguageServerToQuery::Other(server_id),
12996 request.clone(),
12997 cx,
12998 );
12999 cx.background_spawn(async move {
13000 let mut responses = Vec::new();
13001 match server_task.await {
13002 Ok(response) => responses.push((server_id, response)),
13003 // rust-analyzer likes to error with this when its still loading up
13004 Err(e) if format!("{e:#}").ends_with("content modified") => (),
13005 Err(e) => log::error!(
13006 "Error handling response for request {request:?}: {e:#}"
13007 ),
13008 }
13009 responses
13010 })
13011 }
13012 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
13013 };
13014 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
13015 if T::ProtoRequest::stop_previous_requests() {
13016 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
13017 lsp_requests.clear();
13018 }
13019 }
13020 lsp_data.lsp_requests.entry(key).or_default().insert(
13021 lsp_request_id,
13022 cx.spawn(async move |lsp_store, cx| {
13023 let response = request_task.await;
13024 lsp_store
13025 .update(cx, |lsp_store, cx| {
13026 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
13027 {
13028 let response = response
13029 .into_iter()
13030 .map(|(server_id, response)| {
13031 (
13032 server_id.to_proto(),
13033 T::response_to_proto(
13034 response,
13035 lsp_store,
13036 sender_id,
13037 &buffer_version,
13038 cx,
13039 )
13040 .into(),
13041 )
13042 })
13043 .collect::<HashMap<_, _>>();
13044 match client.send_lsp_response::<T::ProtoRequest>(
13045 project_id,
13046 lsp_request_id,
13047 response,
13048 ) {
13049 Ok(()) => {}
13050 Err(e) => {
13051 log::error!("Failed to send LSP response: {e:#}",)
13052 }
13053 }
13054 }
13055 })
13056 .ok();
13057 }),
13058 );
13059 });
13060 Ok(())
13061 }
13062
13063 async fn wait_for_buffer_version<T>(
13064 lsp_store: &Entity<Self>,
13065 proto_request: &T::ProtoRequest,
13066 cx: &mut AsyncApp,
13067 ) -> Result<(Global, Entity<Buffer>)>
13068 where
13069 T: LspCommand,
13070 T::ProtoRequest: proto::LspRequestMessage,
13071 {
13072 let buffer_id = BufferId::new(proto_request.buffer_id())?;
13073 let version = deserialize_version(proto_request.buffer_version());
13074 let buffer = lsp_store.update(cx, |this, cx| {
13075 this.buffer_store.read(cx).get_existing(buffer_id)
13076 })?;
13077 buffer
13078 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
13079 .await?;
13080 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13081 Ok((buffer_version, buffer))
13082 }
13083
13084 fn take_text_document_sync_options(
13085 capabilities: &mut lsp::ServerCapabilities,
13086 ) -> lsp::TextDocumentSyncOptions {
13087 match capabilities.text_document_sync.take() {
13088 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13089 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13090 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13091 sync_options.change = Some(sync_kind);
13092 sync_options
13093 }
13094 None => lsp::TextDocumentSyncOptions::default(),
13095 }
13096 }
13097
13098 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13099 self.downstream_client.clone()
13100 }
13101
13102 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13103 self.worktree_store.clone()
13104 }
13105
13106 /// Gets what's stored in the LSP data for the given buffer.
13107 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13108 self.lsp_data.get_mut(&buffer_id)
13109 }
13110
13111 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13112 /// new [`BufferLspData`] will be created to replace the previous state.
13113 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13114 let (buffer_id, buffer_version) =
13115 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13116 let lsp_data = self
13117 .lsp_data
13118 .entry(buffer_id)
13119 .or_insert_with(|| BufferLspData::new(buffer, cx));
13120 if buffer_version.changed_since(&lsp_data.buffer_version) {
13121 // To send delta requests for semantic tokens, the previous tokens
13122 // need to be kept between buffer changes.
13123 let semantic_tokens = lsp_data.semantic_tokens.take();
13124 *lsp_data = BufferLspData::new(buffer, cx);
13125 lsp_data.semantic_tokens = semantic_tokens;
13126 }
13127 lsp_data
13128 }
13129}
13130
13131// Registration with registerOptions as null, should fallback to true.
13132// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13133fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13134 reg: lsp::Registration,
13135) -> Result<OneOf<bool, T>> {
13136 Ok(match reg.register_options {
13137 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13138 None => OneOf::Left(true),
13139 })
13140}
13141
13142fn subscribe_to_binary_statuses(
13143 languages: &Arc<LanguageRegistry>,
13144 cx: &mut Context<'_, LspStore>,
13145) -> Task<()> {
13146 let mut server_statuses = languages.language_server_binary_statuses();
13147 cx.spawn(async move |lsp_store, cx| {
13148 while let Some((server_name, binary_status)) = server_statuses.next().await {
13149 if lsp_store
13150 .update(cx, |_, cx| {
13151 let mut message = None;
13152 let binary_status = match binary_status {
13153 BinaryStatus::None => proto::ServerBinaryStatus::None,
13154 BinaryStatus::CheckingForUpdate => {
13155 proto::ServerBinaryStatus::CheckingForUpdate
13156 }
13157 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13158 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13159 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13160 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13161 BinaryStatus::Failed { error } => {
13162 message = Some(error);
13163 proto::ServerBinaryStatus::Failed
13164 }
13165 };
13166 cx.emit(LspStoreEvent::LanguageServerUpdate {
13167 // Binary updates are about the binary that might not have any language server id at that point.
13168 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13169 language_server_id: LanguageServerId(0),
13170 name: Some(server_name),
13171 message: proto::update_language_server::Variant::StatusUpdate(
13172 proto::StatusUpdate {
13173 message,
13174 status: Some(proto::status_update::Status::Binary(
13175 binary_status as i32,
13176 )),
13177 },
13178 ),
13179 });
13180 })
13181 .is_err()
13182 {
13183 break;
13184 }
13185 }
13186 })
13187}
13188
13189fn lsp_workspace_diagnostics_refresh(
13190 registration_id: Option<String>,
13191 options: DiagnosticServerCapabilities,
13192 server: Arc<LanguageServer>,
13193 cx: &mut Context<'_, LspStore>,
13194) -> Option<WorkspaceRefreshTask> {
13195 let identifier = workspace_diagnostic_identifier(&options)?;
13196 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13197
13198 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13199 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13200 refresh_tx.try_send(()).ok();
13201
13202 let request_timeout = ProjectSettings::get_global(cx)
13203 .global_lsp_settings
13204 .get_request_timeout();
13205
13206 // 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.
13207 // This allows users to increase the duration if need be
13208 let timeout = if request_timeout != Duration::ZERO {
13209 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13210 } else {
13211 request_timeout
13212 };
13213
13214 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13215 let mut attempts = 0;
13216 let max_attempts = 50;
13217 let mut requests = 0;
13218
13219 loop {
13220 let Some(()) = refresh_rx.recv().await else {
13221 return;
13222 };
13223
13224 'request: loop {
13225 requests += 1;
13226 if attempts > max_attempts {
13227 log::error!(
13228 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13229 );
13230 return;
13231 }
13232 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13233 cx.background_executor()
13234 .timer(Duration::from_millis(backoff_millis))
13235 .await;
13236 attempts += 1;
13237
13238 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13239 lsp_store
13240 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13241 .into_iter()
13242 .filter_map(|(abs_path, result_id)| {
13243 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13244 Some(lsp::PreviousResultId {
13245 uri,
13246 value: result_id.to_string(),
13247 })
13248 })
13249 .collect()
13250 }) else {
13251 return;
13252 };
13253
13254 let token = if let Some(registration_id) = ®istration_id {
13255 format!(
13256 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13257 server.server_id(),
13258 )
13259 } else {
13260 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13261 };
13262
13263 progress_rx.try_recv().ok();
13264 let timer = server.request_timer(timeout).fuse();
13265 let progress = pin!(progress_rx.recv().fuse());
13266 let response_result = server
13267 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13268 lsp::WorkspaceDiagnosticParams {
13269 previous_result_ids,
13270 identifier: identifier.clone(),
13271 work_done_progress_params: Default::default(),
13272 partial_result_params: lsp::PartialResultParams {
13273 partial_result_token: Some(lsp::ProgressToken::String(token)),
13274 },
13275 },
13276 select(timer, progress).then(|either| match either {
13277 Either::Left((message, ..)) => ready(message).left_future(),
13278 Either::Right(..) => pending::<String>().right_future(),
13279 }),
13280 )
13281 .await;
13282
13283 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13284 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13285 match response_result {
13286 ConnectionResult::Timeout => {
13287 log::error!("Timeout during workspace diagnostics pull");
13288 continue 'request;
13289 }
13290 ConnectionResult::ConnectionReset => {
13291 log::error!("Server closed a workspace diagnostics pull request");
13292 continue 'request;
13293 }
13294 ConnectionResult::Result(Err(e)) => {
13295 log::error!("Error during workspace diagnostics pull: {e:#}");
13296 break 'request;
13297 }
13298 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13299 attempts = 0;
13300 if lsp_store
13301 .update(cx, |lsp_store, cx| {
13302 lsp_store.apply_workspace_diagnostic_report(
13303 server.server_id(),
13304 pulled_diagnostics,
13305 registration_id_shared.clone(),
13306 cx,
13307 )
13308 })
13309 .is_err()
13310 {
13311 return;
13312 }
13313 break 'request;
13314 }
13315 }
13316 }
13317 }
13318 });
13319
13320 Some(WorkspaceRefreshTask {
13321 refresh_tx,
13322 progress_tx,
13323 task: workspace_query_language_server,
13324 })
13325}
13326
13327fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13328 match &options {
13329 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13330 .identifier
13331 .as_deref()
13332 .map(SharedString::new),
13333 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13334 let diagnostic_options = ®istration_options.diagnostic_options;
13335 diagnostic_options
13336 .identifier
13337 .as_deref()
13338 .map(SharedString::new)
13339 }
13340 }
13341}
13342
13343fn workspace_diagnostic_identifier(
13344 options: &DiagnosticServerCapabilities,
13345) -> Option<Option<String>> {
13346 match &options {
13347 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13348 if !diagnostic_options.workspace_diagnostics {
13349 return None;
13350 }
13351 Some(diagnostic_options.identifier.clone())
13352 }
13353 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13354 let diagnostic_options = ®istration_options.diagnostic_options;
13355 if !diagnostic_options.workspace_diagnostics {
13356 return None;
13357 }
13358 Some(diagnostic_options.identifier.clone())
13359 }
13360 }
13361}
13362
13363fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13364 let CompletionSource::BufferWord {
13365 word_range,
13366 resolved,
13367 } = &mut completion.source
13368 else {
13369 return;
13370 };
13371 if *resolved {
13372 return;
13373 }
13374
13375 if completion.new_text
13376 != snapshot
13377 .text_for_range(word_range.clone())
13378 .collect::<String>()
13379 {
13380 return;
13381 }
13382
13383 let mut offset = 0;
13384 for chunk in snapshot.chunks(word_range.clone(), true) {
13385 let end_offset = offset + chunk.text.len();
13386 if let Some(highlight_id) = chunk.syntax_highlight_id {
13387 completion
13388 .label
13389 .runs
13390 .push((offset..end_offset, highlight_id));
13391 }
13392 offset = end_offset;
13393 }
13394 *resolved = true;
13395}
13396
13397impl EventEmitter<LspStoreEvent> for LspStore {}
13398
13399fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13400 hover
13401 .contents
13402 .retain(|hover_block| !hover_block.text.trim().is_empty());
13403 if hover.contents.is_empty() {
13404 None
13405 } else {
13406 Some(hover)
13407 }
13408}
13409
13410async fn populate_labels_for_completions(
13411 new_completions: Vec<CoreCompletion>,
13412 language: Option<Arc<Language>>,
13413 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13414) -> Vec<Completion> {
13415 let lsp_completions = new_completions
13416 .iter()
13417 .filter_map(|new_completion| {
13418 new_completion
13419 .source
13420 .lsp_completion(true)
13421 .map(|lsp_completion| lsp_completion.into_owned())
13422 })
13423 .collect::<Vec<_>>();
13424
13425 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13426 lsp_adapter
13427 .labels_for_completions(&lsp_completions, language)
13428 .await
13429 .log_err()
13430 .unwrap_or_default()
13431 } else {
13432 Vec::new()
13433 }
13434 .into_iter()
13435 .fuse();
13436
13437 let mut completions = Vec::new();
13438 for completion in new_completions {
13439 match completion.source.lsp_completion(true) {
13440 Some(lsp_completion) => {
13441 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13442
13443 let mut label = labels.next().flatten().unwrap_or_else(|| {
13444 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13445 });
13446 ensure_uniform_list_compatible_label(&mut label);
13447 completions.push(Completion {
13448 label,
13449 documentation,
13450 replace_range: completion.replace_range,
13451 new_text: completion.new_text,
13452 insert_text_mode: lsp_completion.insert_text_mode,
13453 source: completion.source,
13454 icon_path: None,
13455 confirm: None,
13456 match_start: None,
13457 snippet_deduplication_key: None,
13458 });
13459 }
13460 None => {
13461 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13462 ensure_uniform_list_compatible_label(&mut label);
13463 completions.push(Completion {
13464 label,
13465 documentation: None,
13466 replace_range: completion.replace_range,
13467 new_text: completion.new_text,
13468 source: completion.source,
13469 insert_text_mode: None,
13470 icon_path: None,
13471 confirm: None,
13472 match_start: None,
13473 snippet_deduplication_key: None,
13474 });
13475 }
13476 }
13477 }
13478 completions
13479}
13480
13481#[derive(Debug)]
13482pub enum LanguageServerToQuery {
13483 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13484 FirstCapable,
13485 /// Query a specific language server.
13486 Other(LanguageServerId),
13487}
13488
13489#[derive(Default)]
13490struct RenamePathsWatchedForServer {
13491 did_rename: Vec<RenameActionPredicate>,
13492 will_rename: Vec<RenameActionPredicate>,
13493}
13494
13495impl RenamePathsWatchedForServer {
13496 fn with_did_rename_patterns(
13497 mut self,
13498 did_rename: Option<&FileOperationRegistrationOptions>,
13499 ) -> Self {
13500 if let Some(did_rename) = did_rename {
13501 self.did_rename = did_rename
13502 .filters
13503 .iter()
13504 .filter_map(|filter| filter.try_into().log_err())
13505 .collect();
13506 }
13507 self
13508 }
13509 fn with_will_rename_patterns(
13510 mut self,
13511 will_rename: Option<&FileOperationRegistrationOptions>,
13512 ) -> Self {
13513 if let Some(will_rename) = will_rename {
13514 self.will_rename = will_rename
13515 .filters
13516 .iter()
13517 .filter_map(|filter| filter.try_into().log_err())
13518 .collect();
13519 }
13520 self
13521 }
13522
13523 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13524 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13525 }
13526 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13527 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13528 }
13529}
13530
13531impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13532 type Error = globset::Error;
13533 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13534 Ok(Self {
13535 kind: ops.pattern.matches.clone(),
13536 glob: GlobBuilder::new(&ops.pattern.glob)
13537 .case_insensitive(
13538 ops.pattern
13539 .options
13540 .as_ref()
13541 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13542 )
13543 .build()?
13544 .compile_matcher(),
13545 })
13546 }
13547}
13548struct RenameActionPredicate {
13549 glob: GlobMatcher,
13550 kind: Option<FileOperationPatternKind>,
13551}
13552
13553impl RenameActionPredicate {
13554 // Returns true if language server should be notified
13555 fn eval(&self, path: &str, is_dir: bool) -> bool {
13556 self.kind.as_ref().is_none_or(|kind| {
13557 let expected_kind = if is_dir {
13558 FileOperationPatternKind::Folder
13559 } else {
13560 FileOperationPatternKind::File
13561 };
13562 kind == &expected_kind
13563 }) && self.glob.is_match(path)
13564 }
13565}
13566
13567#[derive(Default)]
13568struct LanguageServerWatchedPaths {
13569 worktree_paths: HashMap<WorktreeId, GlobSet>,
13570 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13571}
13572
13573#[derive(Default)]
13574struct LanguageServerWatchedPathsBuilder {
13575 worktree_paths: HashMap<WorktreeId, GlobSet>,
13576 abs_paths: HashMap<Arc<Path>, GlobSet>,
13577}
13578
13579impl LanguageServerWatchedPathsBuilder {
13580 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13581 self.worktree_paths.insert(worktree_id, glob_set);
13582 }
13583 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13584 self.abs_paths.insert(path, glob_set);
13585 }
13586 fn build(
13587 self,
13588 fs: Arc<dyn Fs>,
13589 language_server_id: LanguageServerId,
13590 cx: &mut Context<LspStore>,
13591 ) -> LanguageServerWatchedPaths {
13592 let lsp_store = cx.weak_entity();
13593
13594 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13595 let abs_paths = self
13596 .abs_paths
13597 .into_iter()
13598 .map(|(abs_path, globset)| {
13599 let task = cx.spawn({
13600 let abs_path = abs_path.clone();
13601 let fs = fs.clone();
13602
13603 let lsp_store = lsp_store.clone();
13604 async move |_, cx| {
13605 maybe!(async move {
13606 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13607 while let Some(update) = push_updates.0.next().await {
13608 let action = lsp_store
13609 .update(cx, |this, _| {
13610 let Some(local) = this.as_local() else {
13611 return ControlFlow::Break(());
13612 };
13613 let Some(watcher) = local
13614 .language_server_watched_paths
13615 .get(&language_server_id)
13616 else {
13617 return ControlFlow::Break(());
13618 };
13619 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13620 "Watched abs path is not registered with a watcher",
13621 );
13622 let matching_entries = update
13623 .into_iter()
13624 .filter(|event| globs.is_match(&event.path))
13625 .collect::<Vec<_>>();
13626 this.lsp_notify_abs_paths_changed(
13627 language_server_id,
13628 matching_entries,
13629 );
13630 ControlFlow::Continue(())
13631 })
13632 .ok()?;
13633
13634 if action.is_break() {
13635 break;
13636 }
13637 }
13638 Some(())
13639 })
13640 .await;
13641 }
13642 });
13643 (abs_path, (globset, task))
13644 })
13645 .collect();
13646 LanguageServerWatchedPaths {
13647 worktree_paths: self.worktree_paths,
13648 abs_paths,
13649 }
13650 }
13651}
13652
13653struct LspBufferSnapshot {
13654 version: i32,
13655 snapshot: TextBufferSnapshot,
13656}
13657
13658/// A prompt requested by LSP server.
13659#[derive(Clone, Debug)]
13660pub struct LanguageServerPromptRequest {
13661 pub id: usize,
13662 pub level: PromptLevel,
13663 pub message: String,
13664 pub actions: Vec<MessageActionItem>,
13665 pub lsp_name: String,
13666 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13667}
13668
13669impl LanguageServerPromptRequest {
13670 pub fn new(
13671 level: PromptLevel,
13672 message: String,
13673 actions: Vec<MessageActionItem>,
13674 lsp_name: String,
13675 response_channel: smol::channel::Sender<MessageActionItem>,
13676 ) -> Self {
13677 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13678 LanguageServerPromptRequest {
13679 id,
13680 level,
13681 message,
13682 actions,
13683 lsp_name,
13684 response_channel,
13685 }
13686 }
13687 pub async fn respond(self, index: usize) -> Option<()> {
13688 if let Some(response) = self.actions.into_iter().nth(index) {
13689 self.response_channel.send(response).await.ok()
13690 } else {
13691 None
13692 }
13693 }
13694
13695 #[cfg(any(test, feature = "test-support"))]
13696 pub fn test(
13697 level: PromptLevel,
13698 message: String,
13699 actions: Vec<MessageActionItem>,
13700 lsp_name: String,
13701 ) -> Self {
13702 let (tx, _rx) = smol::channel::unbounded();
13703 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13704 }
13705}
13706impl PartialEq for LanguageServerPromptRequest {
13707 fn eq(&self, other: &Self) -> bool {
13708 self.message == other.message && self.actions == other.actions
13709 }
13710}
13711
13712#[derive(Clone, Debug, PartialEq)]
13713pub enum LanguageServerLogType {
13714 Log(MessageType),
13715 Trace { verbose_info: Option<String> },
13716 Rpc { received: bool },
13717}
13718
13719impl LanguageServerLogType {
13720 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13721 match self {
13722 Self::Log(log_type) => {
13723 use proto::log_message::LogLevel;
13724 let level = match *log_type {
13725 MessageType::ERROR => LogLevel::Error,
13726 MessageType::WARNING => LogLevel::Warning,
13727 MessageType::INFO => LogLevel::Info,
13728 MessageType::LOG => LogLevel::Log,
13729 other => {
13730 log::warn!("Unknown lsp log message type: {other:?}");
13731 LogLevel::Log
13732 }
13733 };
13734 proto::language_server_log::LogType::Log(proto::LogMessage {
13735 level: level as i32,
13736 })
13737 }
13738 Self::Trace { verbose_info } => {
13739 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13740 verbose_info: verbose_info.to_owned(),
13741 })
13742 }
13743 Self::Rpc { received } => {
13744 let kind = if *received {
13745 proto::rpc_message::Kind::Received
13746 } else {
13747 proto::rpc_message::Kind::Sent
13748 };
13749 let kind = kind as i32;
13750 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13751 }
13752 }
13753 }
13754
13755 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13756 use proto::log_message::LogLevel;
13757 use proto::rpc_message;
13758 match log_type {
13759 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13760 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13761 LogLevel::Error => MessageType::ERROR,
13762 LogLevel::Warning => MessageType::WARNING,
13763 LogLevel::Info => MessageType::INFO,
13764 LogLevel::Log => MessageType::LOG,
13765 },
13766 ),
13767 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13768 verbose_info: trace_message.verbose_info,
13769 },
13770 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13771 received: match rpc_message::Kind::from_i32(message.kind)
13772 .unwrap_or(rpc_message::Kind::Received)
13773 {
13774 rpc_message::Kind::Received => true,
13775 rpc_message::Kind::Sent => false,
13776 },
13777 },
13778 }
13779 }
13780}
13781
13782pub struct WorkspaceRefreshTask {
13783 refresh_tx: mpsc::Sender<()>,
13784 progress_tx: mpsc::Sender<()>,
13785 #[allow(dead_code)]
13786 task: Task<()>,
13787}
13788
13789pub enum LanguageServerState {
13790 Starting {
13791 startup: Task<Option<Arc<LanguageServer>>>,
13792 /// List of language servers that will be added to the workspace once it's initialization completes.
13793 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13794 },
13795
13796 Running {
13797 adapter: Arc<CachedLspAdapter>,
13798 server: Arc<LanguageServer>,
13799 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13800 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13801 },
13802}
13803
13804impl LanguageServerState {
13805 fn add_workspace_folder(&self, uri: Uri) {
13806 match self {
13807 LanguageServerState::Starting {
13808 pending_workspace_folders,
13809 ..
13810 } => {
13811 pending_workspace_folders.lock().insert(uri);
13812 }
13813 LanguageServerState::Running { server, .. } => {
13814 server.add_workspace_folder(uri);
13815 }
13816 }
13817 }
13818 fn _remove_workspace_folder(&self, uri: Uri) {
13819 match self {
13820 LanguageServerState::Starting {
13821 pending_workspace_folders,
13822 ..
13823 } => {
13824 pending_workspace_folders.lock().remove(&uri);
13825 }
13826 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13827 }
13828 }
13829}
13830
13831impl std::fmt::Debug for LanguageServerState {
13832 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13833 match self {
13834 LanguageServerState::Starting { .. } => {
13835 f.debug_struct("LanguageServerState::Starting").finish()
13836 }
13837 LanguageServerState::Running { .. } => {
13838 f.debug_struct("LanguageServerState::Running").finish()
13839 }
13840 }
13841 }
13842}
13843
13844#[derive(Clone, Debug, Serialize)]
13845pub struct LanguageServerProgress {
13846 pub is_disk_based_diagnostics_progress: bool,
13847 pub is_cancellable: bool,
13848 pub title: Option<String>,
13849 pub message: Option<String>,
13850 pub percentage: Option<usize>,
13851 #[serde(skip_serializing)]
13852 pub last_update_at: Instant,
13853}
13854
13855#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13856pub struct DiagnosticSummary {
13857 pub error_count: usize,
13858 pub warning_count: usize,
13859}
13860
13861impl DiagnosticSummary {
13862 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13863 let mut this = Self {
13864 error_count: 0,
13865 warning_count: 0,
13866 };
13867
13868 for entry in diagnostics {
13869 if entry.diagnostic.is_primary {
13870 match entry.diagnostic.severity {
13871 DiagnosticSeverity::ERROR => this.error_count += 1,
13872 DiagnosticSeverity::WARNING => this.warning_count += 1,
13873 _ => {}
13874 }
13875 }
13876 }
13877
13878 this
13879 }
13880
13881 pub fn is_empty(&self) -> bool {
13882 self.error_count == 0 && self.warning_count == 0
13883 }
13884
13885 pub fn to_proto(
13886 self,
13887 language_server_id: LanguageServerId,
13888 path: &RelPath,
13889 ) -> proto::DiagnosticSummary {
13890 proto::DiagnosticSummary {
13891 path: path.to_proto(),
13892 language_server_id: language_server_id.0 as u64,
13893 error_count: self.error_count as u32,
13894 warning_count: self.warning_count as u32,
13895 }
13896 }
13897}
13898
13899#[derive(Clone, Debug)]
13900pub enum CompletionDocumentation {
13901 /// There is no documentation for this completion.
13902 Undocumented,
13903 /// A single line of documentation.
13904 SingleLine(SharedString),
13905 /// Multiple lines of plain text documentation.
13906 MultiLinePlainText(SharedString),
13907 /// Markdown documentation.
13908 MultiLineMarkdown(SharedString),
13909 /// Both single line and multiple lines of plain text documentation.
13910 SingleLineAndMultiLinePlainText {
13911 single_line: SharedString,
13912 plain_text: Option<SharedString>,
13913 },
13914}
13915
13916impl CompletionDocumentation {
13917 #[cfg(any(test, feature = "test-support"))]
13918 pub fn text(&self) -> SharedString {
13919 match self {
13920 CompletionDocumentation::Undocumented => "".into(),
13921 CompletionDocumentation::SingleLine(s) => s.clone(),
13922 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13923 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13924 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13925 single_line.clone()
13926 }
13927 }
13928 }
13929}
13930
13931impl From<lsp::Documentation> for CompletionDocumentation {
13932 fn from(docs: lsp::Documentation) -> Self {
13933 match docs {
13934 lsp::Documentation::String(text) => {
13935 if text.lines().count() <= 1 {
13936 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13937 } else {
13938 CompletionDocumentation::MultiLinePlainText(text.into())
13939 }
13940 }
13941
13942 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13943 lsp::MarkupKind::PlainText => {
13944 if value.lines().count() <= 1 {
13945 CompletionDocumentation::SingleLine(value.into())
13946 } else {
13947 CompletionDocumentation::MultiLinePlainText(value.into())
13948 }
13949 }
13950
13951 lsp::MarkupKind::Markdown => {
13952 CompletionDocumentation::MultiLineMarkdown(value.into())
13953 }
13954 },
13955 }
13956 }
13957}
13958
13959pub enum ResolvedHint {
13960 Resolved(InlayHint),
13961 Resolving(Shared<Task<()>>),
13962}
13963
13964pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13965 glob.components()
13966 .take_while(|component| match component {
13967 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13968 _ => true,
13969 })
13970 .collect()
13971}
13972
13973pub struct SshLspAdapter {
13974 name: LanguageServerName,
13975 binary: LanguageServerBinary,
13976 initialization_options: Option<String>,
13977 code_action_kinds: Option<Vec<CodeActionKind>>,
13978}
13979
13980impl SshLspAdapter {
13981 pub fn new(
13982 name: LanguageServerName,
13983 binary: LanguageServerBinary,
13984 initialization_options: Option<String>,
13985 code_action_kinds: Option<String>,
13986 ) -> Self {
13987 Self {
13988 name,
13989 binary,
13990 initialization_options,
13991 code_action_kinds: code_action_kinds
13992 .as_ref()
13993 .and_then(|c| serde_json::from_str(c).ok()),
13994 }
13995 }
13996}
13997
13998impl LspInstaller for SshLspAdapter {
13999 type BinaryVersion = ();
14000 async fn check_if_user_installed(
14001 &self,
14002 _: &dyn LspAdapterDelegate,
14003 _: Option<Toolchain>,
14004 _: &AsyncApp,
14005 ) -> Option<LanguageServerBinary> {
14006 Some(self.binary.clone())
14007 }
14008
14009 async fn cached_server_binary(
14010 &self,
14011 _: PathBuf,
14012 _: &dyn LspAdapterDelegate,
14013 ) -> Option<LanguageServerBinary> {
14014 None
14015 }
14016
14017 async fn fetch_latest_server_version(
14018 &self,
14019 _: &dyn LspAdapterDelegate,
14020 _: bool,
14021 _: &mut AsyncApp,
14022 ) -> Result<()> {
14023 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
14024 }
14025
14026 async fn fetch_server_binary(
14027 &self,
14028 _: (),
14029 _: PathBuf,
14030 _: &dyn LspAdapterDelegate,
14031 ) -> Result<LanguageServerBinary> {
14032 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
14033 }
14034}
14035
14036#[async_trait(?Send)]
14037impl LspAdapter for SshLspAdapter {
14038 fn name(&self) -> LanguageServerName {
14039 self.name.clone()
14040 }
14041
14042 async fn initialization_options(
14043 self: Arc<Self>,
14044 _: &Arc<dyn LspAdapterDelegate>,
14045 _: &mut AsyncApp,
14046 ) -> Result<Option<serde_json::Value>> {
14047 let Some(options) = &self.initialization_options else {
14048 return Ok(None);
14049 };
14050 let result = serde_json::from_str(options)?;
14051 Ok(result)
14052 }
14053
14054 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
14055 self.code_action_kinds.clone()
14056 }
14057}
14058
14059pub fn language_server_settings<'a>(
14060 delegate: &'a dyn LspAdapterDelegate,
14061 language: &LanguageServerName,
14062 cx: &'a App,
14063) -> Option<&'a LspSettings> {
14064 language_server_settings_for(
14065 SettingsLocation {
14066 worktree_id: delegate.worktree_id(),
14067 path: RelPath::empty(),
14068 },
14069 language,
14070 cx,
14071 )
14072}
14073
14074pub fn language_server_settings_for<'a>(
14075 location: SettingsLocation<'a>,
14076 language: &LanguageServerName,
14077 cx: &'a App,
14078) -> Option<&'a LspSettings> {
14079 ProjectSettings::get(Some(location), cx).lsp.get(language)
14080}
14081
14082pub struct LocalLspAdapterDelegate {
14083 lsp_store: WeakEntity<LspStore>,
14084 worktree: worktree::Snapshot,
14085 fs: Arc<dyn Fs>,
14086 http_client: Arc<dyn HttpClient>,
14087 language_registry: Arc<LanguageRegistry>,
14088 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14089}
14090
14091impl LocalLspAdapterDelegate {
14092 pub fn new(
14093 language_registry: Arc<LanguageRegistry>,
14094 environment: &Entity<ProjectEnvironment>,
14095 lsp_store: WeakEntity<LspStore>,
14096 worktree: &Entity<Worktree>,
14097 http_client: Arc<dyn HttpClient>,
14098 fs: Arc<dyn Fs>,
14099 cx: &mut App,
14100 ) -> Arc<Self> {
14101 let load_shell_env_task =
14102 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14103
14104 Arc::new(Self {
14105 lsp_store,
14106 worktree: worktree.read(cx).snapshot(),
14107 fs,
14108 http_client,
14109 language_registry,
14110 load_shell_env_task,
14111 })
14112 }
14113
14114 pub fn from_local_lsp(
14115 local: &LocalLspStore,
14116 worktree: &Entity<Worktree>,
14117 cx: &mut App,
14118 ) -> Arc<Self> {
14119 Self::new(
14120 local.languages.clone(),
14121 &local.environment,
14122 local.weak.clone(),
14123 worktree,
14124 local.http_client.clone(),
14125 local.fs.clone(),
14126 cx,
14127 )
14128 }
14129}
14130
14131#[async_trait]
14132impl LspAdapterDelegate for LocalLspAdapterDelegate {
14133 fn show_notification(&self, message: &str, cx: &mut App) {
14134 self.lsp_store
14135 .update(cx, |_, cx| {
14136 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14137 })
14138 .ok();
14139 }
14140
14141 fn http_client(&self) -> Arc<dyn HttpClient> {
14142 self.http_client.clone()
14143 }
14144
14145 fn worktree_id(&self) -> WorktreeId {
14146 self.worktree.id()
14147 }
14148
14149 fn worktree_root_path(&self) -> &Path {
14150 self.worktree.abs_path().as_ref()
14151 }
14152
14153 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14154 self.worktree.resolve_relative_path(path)
14155 }
14156
14157 async fn shell_env(&self) -> HashMap<String, String> {
14158 let task = self.load_shell_env_task.clone();
14159 task.await.unwrap_or_default()
14160 }
14161
14162 async fn npm_package_installed_version(
14163 &self,
14164 package_name: &str,
14165 ) -> Result<Option<(PathBuf, Version)>> {
14166 let local_package_directory = self.worktree_root_path();
14167 let node_modules_directory = local_package_directory.join("node_modules");
14168
14169 if let Some(version) =
14170 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14171 {
14172 return Ok(Some((node_modules_directory, version)));
14173 }
14174 let Some(npm) = self.which("npm".as_ref()).await else {
14175 log::warn!(
14176 "Failed to find npm executable for {:?}",
14177 local_package_directory
14178 );
14179 return Ok(None);
14180 };
14181
14182 let env = self.shell_env().await;
14183 let output = util::command::new_command(&npm)
14184 .args(["root", "-g"])
14185 .envs(env)
14186 .current_dir(local_package_directory)
14187 .output()
14188 .await?;
14189 let global_node_modules =
14190 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14191
14192 if let Some(version) =
14193 read_package_installed_version(global_node_modules.clone(), package_name).await?
14194 {
14195 return Ok(Some((global_node_modules, version)));
14196 }
14197 return Ok(None);
14198 }
14199
14200 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14201 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14202 if self.fs.is_file(&worktree_abs_path).await {
14203 worktree_abs_path.pop();
14204 }
14205
14206 let env = self.shell_env().await;
14207
14208 let shell_path = env.get("PATH").cloned();
14209
14210 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14211 }
14212
14213 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14214 let mut working_dir = self.worktree_root_path().to_path_buf();
14215 if self.fs.is_file(&working_dir).await {
14216 working_dir.pop();
14217 }
14218 let output = util::command::new_command(&command.path)
14219 .args(command.arguments)
14220 .envs(command.env.clone().unwrap_or_default())
14221 .current_dir(working_dir)
14222 .output()
14223 .await?;
14224
14225 anyhow::ensure!(
14226 output.status.success(),
14227 "{}, stdout: {:?}, stderr: {:?}",
14228 output.status,
14229 String::from_utf8_lossy(&output.stdout),
14230 String::from_utf8_lossy(&output.stderr)
14231 );
14232 Ok(())
14233 }
14234
14235 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14236 self.language_registry
14237 .update_lsp_binary_status(server_name, status);
14238 }
14239
14240 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14241 self.language_registry
14242 .all_lsp_adapters()
14243 .into_iter()
14244 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14245 .collect()
14246 }
14247
14248 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14249 let dir = self.language_registry.language_server_download_dir(name)?;
14250
14251 if !dir.exists() {
14252 smol::fs::create_dir_all(&dir)
14253 .await
14254 .context("failed to create container directory")
14255 .log_err()?;
14256 }
14257
14258 Some(dir)
14259 }
14260
14261 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14262 let entry = self
14263 .worktree
14264 .entry_for_path(path)
14265 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14266 let abs_path = self.worktree.absolutize(&entry.path);
14267 self.fs.load(&abs_path).await
14268 }
14269}
14270
14271async fn populate_labels_for_symbols(
14272 symbols: Vec<CoreSymbol>,
14273 language_registry: &Arc<LanguageRegistry>,
14274 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14275 output: &mut Vec<Symbol>,
14276) {
14277 #[allow(clippy::mutable_key_type)]
14278 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14279
14280 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14281 for symbol in symbols {
14282 let Some(file_name) = symbol.path.file_name() else {
14283 continue;
14284 };
14285 let language = language_registry
14286 .load_language_for_file_path(Path::new(file_name))
14287 .await
14288 .ok()
14289 .or_else(|| {
14290 unknown_paths.insert(file_name.into());
14291 None
14292 });
14293 symbols_by_language
14294 .entry(language)
14295 .or_default()
14296 .push(symbol);
14297 }
14298
14299 for unknown_path in unknown_paths {
14300 log::info!("no language found for symbol in file {unknown_path:?}");
14301 }
14302
14303 let mut label_params = Vec::new();
14304 for (language, mut symbols) in symbols_by_language {
14305 label_params.clear();
14306 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14307 name: mem::take(&mut symbol.name),
14308 kind: symbol.kind,
14309 container_name: symbol.container_name.take(),
14310 }));
14311
14312 let mut labels = Vec::new();
14313 if let Some(language) = language {
14314 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14315 language_registry
14316 .lsp_adapters(&language.name())
14317 .first()
14318 .cloned()
14319 });
14320 if let Some(lsp_adapter) = lsp_adapter {
14321 labels = lsp_adapter
14322 .labels_for_symbols(&label_params, &language)
14323 .await
14324 .log_err()
14325 .unwrap_or_default();
14326 }
14327 }
14328
14329 for (
14330 (
14331 symbol,
14332 language::Symbol {
14333 name,
14334 container_name,
14335 ..
14336 },
14337 ),
14338 label,
14339 ) in symbols
14340 .into_iter()
14341 .zip(label_params.drain(..))
14342 .zip(labels.into_iter().chain(iter::repeat(None)))
14343 {
14344 output.push(Symbol {
14345 language_server_name: symbol.language_server_name,
14346 source_worktree_id: symbol.source_worktree_id,
14347 source_language_server_id: symbol.source_language_server_id,
14348 path: symbol.path,
14349 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14350 name,
14351 kind: symbol.kind,
14352 range: symbol.range,
14353 container_name,
14354 });
14355 }
14356 }
14357}
14358
14359pub(crate) fn collapse_newlines(text: &str, separator: &str) -> String {
14360 text.lines()
14361 .map(|line| line.trim())
14362 .filter(|line| !line.is_empty())
14363 .join(separator)
14364}
14365
14366fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14367 match server.capabilities().text_document_sync.as_ref()? {
14368 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14369 // Server wants didSave but didn't specify includeText.
14370 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14371 // Server doesn't want didSave at all.
14372 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14373 // Server provided SaveOptions.
14374 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14375 Some(save_options.include_text.unwrap_or(false))
14376 }
14377 },
14378 // We do not have any save info. Kind affects didChange only.
14379 lsp::TextDocumentSyncCapability::Kind(_) => None,
14380 }
14381}
14382
14383/// Completion items are displayed in a `UniformList`.
14384/// Usually, those items are single-line strings, but in LSP responses,
14385/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14386/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14387/// 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,
14388/// breaking the completions menu presentation.
14389///
14390/// 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.
14391pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14392 let mut new_text = String::with_capacity(label.text.len());
14393 let mut offset_map = vec![0; label.text.len() + 1];
14394 let mut last_char_was_space = false;
14395 let mut new_idx = 0;
14396 let chars = label.text.char_indices().fuse();
14397 let mut newlines_removed = false;
14398
14399 for (idx, c) in chars {
14400 offset_map[idx] = new_idx;
14401
14402 match c {
14403 '\n' if last_char_was_space => {
14404 newlines_removed = true;
14405 }
14406 '\t' | ' ' if last_char_was_space => {}
14407 '\n' if !last_char_was_space => {
14408 new_text.push(' ');
14409 new_idx += 1;
14410 last_char_was_space = true;
14411 newlines_removed = true;
14412 }
14413 ' ' | '\t' => {
14414 new_text.push(' ');
14415 new_idx += 1;
14416 last_char_was_space = true;
14417 }
14418 _ => {
14419 new_text.push(c);
14420 new_idx += c.len_utf8();
14421 last_char_was_space = false;
14422 }
14423 }
14424 }
14425 offset_map[label.text.len()] = new_idx;
14426
14427 // Only modify the label if newlines were removed.
14428 if !newlines_removed {
14429 return;
14430 }
14431
14432 let last_index = new_idx;
14433 let mut run_ranges_errors = Vec::new();
14434 label.runs.retain_mut(|(range, _)| {
14435 match offset_map.get(range.start) {
14436 Some(&start) => range.start = start,
14437 None => {
14438 run_ranges_errors.push(range.clone());
14439 return false;
14440 }
14441 }
14442
14443 match offset_map.get(range.end) {
14444 Some(&end) => range.end = end,
14445 None => {
14446 run_ranges_errors.push(range.clone());
14447 range.end = last_index;
14448 }
14449 }
14450 true
14451 });
14452 if !run_ranges_errors.is_empty() {
14453 log::error!(
14454 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14455 label.text
14456 );
14457 }
14458
14459 let mut wrong_filter_range = None;
14460 if label.filter_range == (0..label.text.len()) {
14461 label.filter_range = 0..new_text.len();
14462 } else {
14463 let mut original_filter_range = Some(label.filter_range.clone());
14464 match offset_map.get(label.filter_range.start) {
14465 Some(&start) => label.filter_range.start = start,
14466 None => {
14467 wrong_filter_range = original_filter_range.take();
14468 label.filter_range.start = last_index;
14469 }
14470 }
14471
14472 match offset_map.get(label.filter_range.end) {
14473 Some(&end) => label.filter_range.end = end,
14474 None => {
14475 wrong_filter_range = original_filter_range.take();
14476 label.filter_range.end = last_index;
14477 }
14478 }
14479 }
14480 if let Some(wrong_filter_range) = wrong_filter_range {
14481 log::error!(
14482 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14483 label.text
14484 );
14485 }
14486
14487 label.text = new_text;
14488}