1//! LSP store provides unified access to the language server protocol.
2//! The consumers of LSP store can interact with language servers without knowing exactly which language server they're interacting with.
3//!
4//! # Local/Remote LSP Stores
5//! This module is split up into three distinct parts:
6//! - [`LocalLspStore`], which is ran on the host machine (either project host or SSH host), that manages the lifecycle of language servers.
7//! - [`RemoteLspStore`], which is ran on the remote machine (project guests) which is mostly about passing through the requests via RPC.
8//! The remote stores don't really care about which language server they're running against - they don't usually get to decide which language server is going to responsible for handling their request.
9//! - [`LspStore`], which unifies the two under one consistent interface for interacting with language servers.
10//!
11//! Most of the interesting work happens at the local layer, as bulk of the complexity is with managing the lifecycle of language servers. The actual implementation of the LSP protocol is handled by [`lsp`] crate.
12pub mod clangd_ext;
13mod code_lens;
14mod document_colors;
15mod document_symbols;
16mod folding_ranges;
17mod inlay_hints;
18pub mod json_language_server_ext;
19pub mod log_store;
20pub mod lsp_ext_command;
21pub mod rust_analyzer_ext;
22mod semantic_tokens;
23pub mod vue_language_server_ext;
24
25use self::code_lens::CodeLensData;
26use self::document_colors::DocumentColorData;
27use self::document_symbols::DocumentSymbolsData;
28use self::inlay_hints::BufferInlayHints;
29use crate::{
30 CodeAction, Completion, CompletionDisplayOptions, CompletionResponse, CompletionSource,
31 CoreCompletion, Hover, InlayHint, InlayId, LocationLink, LspAction, LspPullDiagnostics,
32 ManifestProvidersStore, Project, ProjectItem, ProjectPath, ProjectTransaction,
33 PulledDiagnostics, ResolveState, Symbol,
34 buffer_store::{BufferStore, BufferStoreEvent},
35 environment::ProjectEnvironment,
36 lsp_command::{self, *},
37 lsp_store::{
38 self,
39 folding_ranges::FoldingRangeData,
40 log_store::{GlobalLogStore, LanguageServerKind},
41 semantic_tokens::{SemanticTokenConfig, SemanticTokensData},
42 },
43 manifest_tree::{
44 LanguageServerTree, LanguageServerTreeNode, LaunchDisposition, ManifestQueryDelegate,
45 ManifestTree,
46 },
47 prettier_store::{self, PrettierStore, PrettierStoreEvent},
48 project_settings::{BinarySettings, LspSettings, ProjectSettings},
49 toolchain_store::{LocalToolchainStore, ToolchainStoreEvent},
50 trusted_worktrees::{PathTrust, TrustedWorktrees, TrustedWorktreesEvent},
51 worktree_store::{WorktreeStore, WorktreeStoreEvent},
52 yarn::YarnPathStore,
53};
54use anyhow::{Context as _, Result, anyhow};
55use async_trait::async_trait;
56use client::{TypedEnvelope, proto};
57use clock::Global;
58use collections::{BTreeMap, BTreeSet, HashMap, HashSet, btree_map};
59use futures::{
60 AsyncWriteExt, Future, FutureExt, StreamExt,
61 future::{Either, Shared, join_all, pending, select},
62 select, select_biased,
63 stream::FuturesUnordered,
64};
65use globset::{Glob, GlobBuilder, GlobMatcher, GlobSet, GlobSetBuilder};
66use gpui::{
67 App, AppContext, AsyncApp, Context, Entity, EventEmitter, PromptLevel, SharedString,
68 Subscription, Task, WeakEntity,
69};
70use http_client::HttpClient;
71use itertools::Itertools as _;
72use language::{
73 Bias, BinaryStatus, Buffer, BufferRow, BufferSnapshot, CachedLspAdapter, Capability, CodeLabel,
74 Diagnostic, DiagnosticEntry, DiagnosticSet, DiagnosticSourceKind, Diff, File as _, Language,
75 LanguageName, LanguageRegistry, LocalFile, LspAdapter, LspAdapterDelegate, LspInstaller,
76 ManifestDelegate, ManifestName, Patch, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16,
77 Toolchain, Transaction, Unclipped,
78 language_settings::{
79 AllLanguageSettings, FormatOnSave, Formatter, LanguageSettings, all_language_settings,
80 language_settings,
81 },
82 point_to_lsp,
83 proto::{
84 deserialize_anchor, deserialize_anchor_range, deserialize_version, serialize_anchor,
85 serialize_anchor_range, serialize_version,
86 },
87 range_from_lsp, range_to_lsp,
88 row_chunk::RowChunk,
89};
90use lsp::{
91 AdapterServerCapabilities, CodeActionKind, CompletionContext, CompletionOptions,
92 DEFAULT_LSP_REQUEST_TIMEOUT, DiagnosticServerCapabilities, DiagnosticSeverity, DiagnosticTag,
93 DidChangeWatchedFilesRegistrationOptions, Edit, FileOperationFilter, FileOperationPatternKind,
94 FileOperationRegistrationOptions, FileRename, FileSystemWatcher, LanguageServer,
95 LanguageServerBinary, LanguageServerBinaryOptions, LanguageServerId, LanguageServerName,
96 LanguageServerSelector, LspRequestFuture, MessageActionItem, MessageType, OneOf,
97 RenameFilesParams, SymbolKind, TextDocumentSyncSaveOptions, TextEdit, Uri, WillRenameFiles,
98 WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
99};
100use node_runtime::read_package_installed_version;
101use parking_lot::Mutex;
102use postage::{mpsc, sink::Sink, stream::Stream, watch};
103use rand::prelude::*;
104use rpc::{
105 AnyProtoClient, ErrorCode, ErrorExt as _,
106 proto::{LspRequestId, LspRequestMessage as _},
107};
108use semver::Version;
109use serde::Serialize;
110use serde_json::Value;
111use settings::{Settings, SettingsLocation, SettingsStore};
112use sha2::{Digest, Sha256};
113use snippet::Snippet;
114use std::{
115 any::TypeId,
116 borrow::Cow,
117 cell::RefCell,
118 cmp::{Ordering, Reverse},
119 collections::{VecDeque, hash_map},
120 convert::TryInto,
121 ffi::OsStr,
122 future::ready,
123 iter, mem,
124 ops::{ControlFlow, Range},
125 path::{self, Path, PathBuf},
126 pin::pin,
127 rc::Rc,
128 sync::{
129 Arc,
130 atomic::{self, AtomicUsize},
131 },
132 time::{Duration, Instant},
133 vec,
134};
135use sum_tree::Dimensions;
136use text::{Anchor, BufferId, LineEnding, OffsetRangeExt, ToPoint as _};
137
138use util::{
139 ConnectionResult, ResultExt as _, debug_panic, defer, maybe, merge_json_value_into,
140 paths::{PathStyle, SanitizedPath, UrlExt},
141 post_inc,
142 redact::redact_command,
143 rel_path::RelPath,
144};
145
146pub use document_colors::DocumentColors;
147pub use folding_ranges::LspFoldingRange;
148pub use fs::*;
149pub use language::Location;
150pub use lsp_store::inlay_hints::{CacheInlayHints, InvalidationStrategy};
151#[cfg(any(test, feature = "test-support"))]
152pub use prettier::FORMAT_SUFFIX as TEST_PRETTIER_FORMAT_SUFFIX;
153pub use semantic_tokens::{
154 BufferSemanticToken, BufferSemanticTokens, RefreshForServer, SemanticTokenStylizer, TokenType,
155};
156
157pub use worktree::{
158 Entry, EntryKind, FS_WATCH_LATENCY, File, LocalWorktree, PathChange, ProjectEntryId,
159 UpdatedEntriesSet, UpdatedGitRepositoriesSet, Worktree, WorktreeId, WorktreeSettings,
160};
161
162const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
163pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
164const WORKSPACE_DIAGNOSTICS_TOKEN_START: &str = "id:";
165const SERVER_DOWNLOAD_TIMEOUT: Duration = Duration::from_secs(10);
166static NEXT_PROMPT_REQUEST_ID: AtomicUsize = AtomicUsize::new(0);
167
168#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
169pub enum ProgressToken {
170 Number(i32),
171 String(SharedString),
172}
173
174impl std::fmt::Display for ProgressToken {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 Self::Number(number) => write!(f, "{number}"),
178 Self::String(string) => write!(f, "{string}"),
179 }
180 }
181}
182
183impl ProgressToken {
184 fn from_lsp(value: lsp::NumberOrString) -> Self {
185 match value {
186 lsp::NumberOrString::Number(number) => Self::Number(number),
187 lsp::NumberOrString::String(string) => Self::String(SharedString::new(string)),
188 }
189 }
190
191 fn to_lsp(&self) -> lsp::NumberOrString {
192 match self {
193 Self::Number(number) => lsp::NumberOrString::Number(*number),
194 Self::String(string) => lsp::NumberOrString::String(string.to_string()),
195 }
196 }
197
198 fn from_proto(value: proto::ProgressToken) -> Option<Self> {
199 Some(match value.value? {
200 proto::progress_token::Value::Number(number) => Self::Number(number),
201 proto::progress_token::Value::String(string) => Self::String(SharedString::new(string)),
202 })
203 }
204
205 fn to_proto(&self) -> proto::ProgressToken {
206 proto::ProgressToken {
207 value: Some(match self {
208 Self::Number(number) => proto::progress_token::Value::Number(*number),
209 Self::String(string) => proto::progress_token::Value::String(string.to_string()),
210 }),
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub enum FormatTrigger {
217 Save,
218 Manual,
219}
220
221pub enum LspFormatTarget {
222 Buffers,
223 Ranges(BTreeMap<BufferId, Vec<Range<Anchor>>>),
224}
225
226#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227pub struct OpenLspBufferHandle(Entity<OpenLspBuffer>);
228
229struct OpenLspBuffer(Entity<Buffer>);
230
231impl FormatTrigger {
232 fn from_proto(value: i32) -> FormatTrigger {
233 match value {
234 0 => FormatTrigger::Save,
235 1 => FormatTrigger::Manual,
236 _ => FormatTrigger::Save,
237 }
238 }
239}
240
241#[derive(Clone)]
242struct UnifiedLanguageServer {
243 id: LanguageServerId,
244 project_roots: HashSet<Arc<RelPath>>,
245}
246
247/// Settings that affect language server identity.
248///
249/// Dynamic settings (`LspSettings::settings`) are excluded because they can be
250/// updated via `workspace/didChangeConfiguration` without restarting the server.
251#[derive(Clone, Debug, Hash, PartialEq, Eq)]
252struct LanguageServerSeedSettings {
253 binary: Option<BinarySettings>,
254 initialization_options: Option<serde_json::Value>,
255}
256
257#[derive(Clone, Debug, Hash, PartialEq, Eq)]
258struct LanguageServerSeed {
259 worktree_id: WorktreeId,
260 name: LanguageServerName,
261 toolchain: Option<Toolchain>,
262 settings: LanguageServerSeedSettings,
263}
264
265#[derive(Debug)]
266pub struct DocumentDiagnosticsUpdate<'a, D> {
267 pub diagnostics: D,
268 pub result_id: Option<SharedString>,
269 pub registration_id: Option<SharedString>,
270 pub server_id: LanguageServerId,
271 pub disk_based_sources: Cow<'a, [String]>,
272}
273
274pub struct DocumentDiagnostics {
275 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
276 document_abs_path: PathBuf,
277 version: Option<i32>,
278}
279
280#[derive(Default, Debug)]
281struct DynamicRegistrations {
282 did_change_watched_files: HashMap<String, Vec<FileSystemWatcher>>,
283 diagnostics: HashMap<Option<String>, DiagnosticServerCapabilities>,
284}
285
286pub struct LocalLspStore {
287 weak: WeakEntity<LspStore>,
288 pub worktree_store: Entity<WorktreeStore>,
289 toolchain_store: Entity<LocalToolchainStore>,
290 http_client: Arc<dyn HttpClient>,
291 environment: Entity<ProjectEnvironment>,
292 fs: Arc<dyn Fs>,
293 languages: Arc<LanguageRegistry>,
294 language_server_ids: HashMap<LanguageServerSeed, UnifiedLanguageServer>,
295 yarn: Entity<YarnPathStore>,
296 pub language_servers: HashMap<LanguageServerId, LanguageServerState>,
297 buffers_being_formatted: HashSet<BufferId>,
298 last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
299 language_server_watched_paths: HashMap<LanguageServerId, LanguageServerWatchedPaths>,
300 watched_manifest_filenames: HashSet<ManifestName>,
301 language_server_paths_watched_for_rename:
302 HashMap<LanguageServerId, RenamePathsWatchedForServer>,
303 language_server_dynamic_registrations: HashMap<LanguageServerId, DynamicRegistrations>,
304 supplementary_language_servers:
305 HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
306 prettier_store: Entity<PrettierStore>,
307 next_diagnostic_group_id: usize,
308 diagnostics: HashMap<
309 WorktreeId,
310 HashMap<
311 Arc<RelPath>,
312 Vec<(
313 LanguageServerId,
314 Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
315 )>,
316 >,
317 >,
318 buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
319 _subscription: gpui::Subscription,
320 lsp_tree: LanguageServerTree,
321 registered_buffers: HashMap<BufferId, usize>,
322 buffers_opened_in_servers: HashMap<BufferId, HashSet<LanguageServerId>>,
323 buffer_pull_diagnostics_result_ids: HashMap<
324 LanguageServerId,
325 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
326 >,
327 workspace_pull_diagnostics_result_ids: HashMap<
328 LanguageServerId,
329 HashMap<Option<SharedString>, HashMap<PathBuf, Option<SharedString>>>,
330 >,
331 restricted_worktrees_tasks: HashMap<WorktreeId, (Subscription, watch::Receiver<bool>)>,
332
333 buffers_to_refresh_hash_set: HashSet<BufferId>,
334 buffers_to_refresh_queue: VecDeque<BufferId>,
335 _background_diagnostics_worker: Shared<Task<()>>,
336}
337
338impl LocalLspStore {
339 /// Returns the running language server for the given ID. Note if the language server is starting, it will not be returned.
340 pub fn running_language_server_for_id(
341 &self,
342 id: LanguageServerId,
343 ) -> Option<&Arc<LanguageServer>> {
344 let language_server_state = self.language_servers.get(&id)?;
345
346 match language_server_state {
347 LanguageServerState::Running { server, .. } => Some(server),
348 LanguageServerState::Starting { .. } => None,
349 }
350 }
351
352 fn get_or_insert_language_server(
353 &mut self,
354 worktree_handle: &Entity<Worktree>,
355 delegate: Arc<LocalLspAdapterDelegate>,
356 disposition: &Arc<LaunchDisposition>,
357 language_name: &LanguageName,
358 cx: &mut App,
359 ) -> LanguageServerId {
360 let key = LanguageServerSeed {
361 worktree_id: worktree_handle.read(cx).id(),
362 name: disposition.server_name.clone(),
363 settings: LanguageServerSeedSettings {
364 binary: disposition.settings.binary.clone(),
365 initialization_options: disposition.settings.initialization_options.clone(),
366 },
367 toolchain: disposition.toolchain.clone(),
368 };
369 if let Some(state) = self.language_server_ids.get_mut(&key) {
370 state.project_roots.insert(disposition.path.path.clone());
371 state.id
372 } else {
373 let adapter = self
374 .languages
375 .lsp_adapters(language_name)
376 .into_iter()
377 .find(|adapter| adapter.name() == disposition.server_name)
378 .expect("To find LSP adapter");
379 let new_language_server_id = self.start_language_server(
380 worktree_handle,
381 delegate,
382 adapter,
383 disposition.settings.clone(),
384 key.clone(),
385 language_name.clone(),
386 cx,
387 );
388 if let Some(state) = self.language_server_ids.get_mut(&key) {
389 state.project_roots.insert(disposition.path.path.clone());
390 } else {
391 debug_assert!(
392 false,
393 "Expected `start_language_server` to ensure that `key` exists in a map"
394 );
395 }
396 new_language_server_id
397 }
398 }
399
400 fn start_language_server(
401 &mut self,
402 worktree_handle: &Entity<Worktree>,
403 delegate: Arc<LocalLspAdapterDelegate>,
404 adapter: Arc<CachedLspAdapter>,
405 settings: Arc<LspSettings>,
406 key: LanguageServerSeed,
407 language_name: LanguageName,
408 cx: &mut App,
409 ) -> LanguageServerId {
410 let worktree = worktree_handle.read(cx);
411
412 let worktree_id = worktree.id();
413 let worktree_abs_path = worktree.abs_path();
414 let toolchain = key.toolchain.clone();
415 let override_options = settings.initialization_options.clone();
416
417 let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
418
419 let server_id = self.languages.next_language_server_id();
420 log::trace!(
421 "attempting to start language server {:?}, path: {worktree_abs_path:?}, id: {server_id}",
422 adapter.name.0
423 );
424
425 let wait_until_worktree_trust =
426 TrustedWorktrees::try_get_global(cx).and_then(|trusted_worktrees| {
427 let can_trust = trusted_worktrees.update(cx, |trusted_worktrees, cx| {
428 trusted_worktrees.can_trust(&self.worktree_store, worktree_id, cx)
429 });
430 if can_trust {
431 self.restricted_worktrees_tasks.remove(&worktree_id);
432 None
433 } else {
434 match self.restricted_worktrees_tasks.entry(worktree_id) {
435 hash_map::Entry::Occupied(o) => Some(o.get().1.clone()),
436 hash_map::Entry::Vacant(v) => {
437 let (mut tx, rx) = watch::channel::<bool>();
438 let lsp_store = self.weak.clone();
439 let subscription = cx.subscribe(&trusted_worktrees, move |_, e, cx| {
440 if let TrustedWorktreesEvent::Trusted(_, trusted_paths) = e {
441 if trusted_paths.contains(&PathTrust::Worktree(worktree_id)) {
442 tx.blocking_send(true).ok();
443 lsp_store
444 .update(cx, |lsp_store, _| {
445 if let Some(local_lsp_store) =
446 lsp_store.as_local_mut()
447 {
448 local_lsp_store
449 .restricted_worktrees_tasks
450 .remove(&worktree_id);
451 }
452 })
453 .ok();
454 }
455 }
456 });
457 v.insert((subscription, rx.clone()));
458 Some(rx)
459 }
460 }
461 }
462 });
463 let update_binary_status = wait_until_worktree_trust.is_none();
464
465 let binary = self.get_language_server_binary(
466 worktree_abs_path.clone(),
467 adapter.clone(),
468 settings,
469 toolchain.clone(),
470 delegate.clone(),
471 true,
472 wait_until_worktree_trust,
473 cx,
474 );
475 let pending_workspace_folders = Arc::<Mutex<BTreeSet<Uri>>>::default();
476
477 let pending_server = cx.spawn({
478 let adapter = adapter.clone();
479 let server_name = adapter.name.clone();
480 let stderr_capture = stderr_capture.clone();
481 #[cfg(any(test, feature = "test-support"))]
482 let lsp_store = self.weak.clone();
483 let pending_workspace_folders = pending_workspace_folders.clone();
484 async move |cx| {
485 let binary = binary.await?;
486 #[cfg(any(test, feature = "test-support"))]
487 if let Some(server) = lsp_store
488 .update(&mut cx.clone(), |this, cx| {
489 this.languages.create_fake_language_server(
490 server_id,
491 &server_name,
492 binary.clone(),
493 &mut cx.to_async(),
494 )
495 })
496 .ok()
497 .flatten()
498 {
499 return Ok(server);
500 }
501
502 let code_action_kinds = adapter.code_action_kinds();
503 lsp::LanguageServer::new(
504 stderr_capture,
505 server_id,
506 server_name,
507 binary,
508 &worktree_abs_path,
509 code_action_kinds,
510 Some(pending_workspace_folders),
511 cx,
512 )
513 }
514 });
515
516 let startup = {
517 let server_name = adapter.name.0.clone();
518 let delegate = delegate as Arc<dyn LspAdapterDelegate>;
519 let key = key.clone();
520 let adapter = adapter.clone();
521 let lsp_store = self.weak.clone();
522 let pending_workspace_folders = pending_workspace_folders.clone();
523 let pull_diagnostics = ProjectSettings::get_global(cx)
524 .diagnostics
525 .lsp_pull_diagnostics
526 .enabled;
527 let settings_location = SettingsLocation {
528 worktree_id,
529 path: RelPath::empty(),
530 };
531 let augments_syntax_tokens = AllLanguageSettings::get(Some(settings_location), cx)
532 .language(Some(settings_location), Some(&language_name), cx)
533 .semantic_tokens
534 .use_tree_sitter();
535 cx.spawn(async move |cx| {
536 let result = async {
537 let language_server = pending_server.await?;
538
539 let workspace_config = Self::workspace_configuration_for_adapter(
540 adapter.adapter.clone(),
541 &delegate,
542 toolchain,
543 None,
544 cx,
545 )
546 .await?;
547
548 let mut initialization_options = Self::initialization_options_for_adapter(
549 adapter.adapter.clone(),
550 &delegate,
551 )
552 .await?;
553
554 match (&mut initialization_options, override_options) {
555 (Some(initialization_options), Some(override_options)) => {
556 merge_json_value_into(override_options, initialization_options);
557 }
558 (None, override_options) => initialization_options = override_options,
559 _ => {}
560 }
561
562 let initialization_params = cx.update(|cx| {
563 let mut params = language_server.default_initialize_params(
564 pull_diagnostics,
565 augments_syntax_tokens,
566 cx,
567 );
568 params.initialization_options = initialization_options;
569 adapter.adapter.prepare_initialize_params(params, cx)
570 })?;
571
572 Self::setup_lsp_messages(
573 lsp_store.clone(),
574 &language_server,
575 delegate.clone(),
576 adapter.clone(),
577 );
578
579 let did_change_configuration_params = lsp::DidChangeConfigurationParams {
580 settings: workspace_config,
581 };
582 let language_server = cx
583 .update(|cx| {
584 let request_timeout = ProjectSettings::get_global(cx)
585 .global_lsp_settings
586 .get_request_timeout();
587
588 language_server.initialize(
589 initialization_params,
590 Arc::new(did_change_configuration_params.clone()),
591 request_timeout,
592 cx,
593 )
594 })
595 .await
596 .inspect_err(|_| {
597 if let Some(lsp_store) = lsp_store.upgrade() {
598 lsp_store.update(cx, |lsp_store, cx| {
599 lsp_store.cleanup_lsp_data(server_id);
600 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id))
601 });
602 }
603 })?;
604
605 language_server.notify::<lsp::notification::DidChangeConfiguration>(
606 did_change_configuration_params,
607 )?;
608
609 anyhow::Ok(language_server)
610 }
611 .await;
612
613 match result {
614 Ok(server) => {
615 lsp_store
616 .update(cx, |lsp_store, cx| {
617 lsp_store.insert_newly_running_language_server(
618 adapter,
619 server.clone(),
620 server_id,
621 key,
622 pending_workspace_folders,
623 cx,
624 );
625 })
626 .ok();
627 stderr_capture.lock().take();
628 Some(server)
629 }
630
631 Err(err) => {
632 let log = stderr_capture.lock().take().unwrap_or_default();
633 delegate.update_status(
634 adapter.name(),
635 BinaryStatus::Failed {
636 error: if log.is_empty() {
637 format!("{err:#}")
638 } else {
639 format!("{err:#}\n-- stderr --\n{log}")
640 },
641 },
642 );
643 log::error!(
644 "Failed to start language server {server_name:?}: {}",
645 redact_command(&format!("{err:?}"))
646 );
647 if !log.is_empty() {
648 log::error!("server stderr: {}", redact_command(&log));
649 }
650 None
651 }
652 }
653 })
654 };
655 let state = LanguageServerState::Starting {
656 startup,
657 pending_workspace_folders,
658 };
659
660 if update_binary_status {
661 self.languages
662 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
663 }
664
665 self.language_servers.insert(server_id, state);
666 self.language_server_ids
667 .entry(key)
668 .or_insert(UnifiedLanguageServer {
669 id: server_id,
670 project_roots: Default::default(),
671 });
672 server_id
673 }
674
675 fn get_language_server_binary(
676 &self,
677 worktree_abs_path: Arc<Path>,
678 adapter: Arc<CachedLspAdapter>,
679 settings: Arc<LspSettings>,
680 toolchain: Option<Toolchain>,
681 delegate: Arc<dyn LspAdapterDelegate>,
682 allow_binary_download: bool,
683 wait_until_worktree_trust: Option<watch::Receiver<bool>>,
684 cx: &mut App,
685 ) -> Task<Result<LanguageServerBinary>> {
686 if let Some(settings) = &settings.binary
687 && let Some(path) = settings.path.as_ref().map(PathBuf::from)
688 {
689 let settings = settings.clone();
690 let languages = self.languages.clone();
691 return cx.background_spawn(async move {
692 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
693 let already_trusted = *wait_until_worktree_trust.borrow();
694 if !already_trusted {
695 log::info!(
696 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
697 adapter.name(),
698 );
699 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
700 if worktree_trusted {
701 break;
702 }
703 }
704 log::info!(
705 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
706 adapter.name(),
707 );
708 }
709 languages
710 .update_lsp_binary_status(adapter.name(), BinaryStatus::Starting);
711 }
712 let mut env = delegate.shell_env().await;
713 env.extend(settings.env.unwrap_or_default());
714
715 Ok(LanguageServerBinary {
716 path: delegate.resolve_relative_path(path),
717 env: Some(env),
718 arguments: settings
719 .arguments
720 .unwrap_or_default()
721 .iter()
722 .map(Into::into)
723 .collect(),
724 })
725 });
726 }
727 let lsp_binary_options = LanguageServerBinaryOptions {
728 allow_path_lookup: !settings
729 .binary
730 .as_ref()
731 .and_then(|b| b.ignore_system_version)
732 .unwrap_or_default(),
733 allow_binary_download,
734 pre_release: settings
735 .fetch
736 .as_ref()
737 .and_then(|f| f.pre_release)
738 .unwrap_or(false),
739 };
740
741 cx.spawn(async move |cx| {
742 if let Some(mut wait_until_worktree_trust) = wait_until_worktree_trust {
743 let already_trusted = *wait_until_worktree_trust.borrow();
744 if !already_trusted {
745 log::info!(
746 "Waiting for worktree {worktree_abs_path:?} to be trusted, before starting language server {}",
747 adapter.name(),
748 );
749 while let Some(worktree_trusted) = wait_until_worktree_trust.recv().await {
750 if worktree_trusted {
751 break;
752 }
753 }
754 log::info!(
755 "Worktree {worktree_abs_path:?} is trusted, starting language server {}",
756 adapter.name(),
757 );
758 }
759 }
760
761 let (existing_binary, maybe_download_binary) = adapter
762 .clone()
763 .get_language_server_command(delegate.clone(), toolchain, lsp_binary_options, cx)
764 .await
765 .await;
766
767 delegate.update_status(adapter.name.clone(), BinaryStatus::None);
768
769 let mut binary = match (existing_binary, maybe_download_binary) {
770 (binary, None) => binary?,
771 (Err(_), Some(downloader)) => downloader.await?,
772 (Ok(existing_binary), Some(downloader)) => {
773 let mut download_timeout = cx
774 .background_executor()
775 .timer(SERVER_DOWNLOAD_TIMEOUT)
776 .fuse();
777 let mut downloader = downloader.fuse();
778 futures::select! {
779 _ = download_timeout => {
780 // Return existing binary and kick the existing work to the background.
781 cx.spawn(async move |_| downloader.await).detach();
782 Ok(existing_binary)
783 },
784 downloaded_or_existing_binary = downloader => {
785 // If download fails, this results in the existing binary.
786 downloaded_or_existing_binary
787 }
788 }?
789 }
790 };
791 let mut shell_env = delegate.shell_env().await;
792
793 shell_env.extend(binary.env.unwrap_or_default());
794
795 if let Some(settings) = settings.binary.as_ref() {
796 if let Some(arguments) = &settings.arguments {
797 binary.arguments = arguments.iter().map(Into::into).collect();
798 }
799 if let Some(env) = &settings.env {
800 shell_env.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
801 }
802 }
803
804 binary.env = Some(shell_env);
805 Ok(binary)
806 })
807 }
808
809 fn setup_lsp_messages(
810 lsp_store: WeakEntity<LspStore>,
811 language_server: &LanguageServer,
812 delegate: Arc<dyn LspAdapterDelegate>,
813 adapter: Arc<CachedLspAdapter>,
814 ) {
815 let name = language_server.name();
816 let server_id = language_server.server_id();
817 language_server
818 .on_notification::<lsp::notification::PublishDiagnostics, _>({
819 let adapter = adapter.clone();
820 let this = lsp_store.clone();
821 move |mut params, cx| {
822 let adapter = adapter.clone();
823 if let Some(this) = this.upgrade() {
824 this.update(cx, |this, cx| {
825 {
826 let buffer = params
827 .uri
828 .to_file_path()
829 .map(|file_path| this.get_buffer(&file_path, cx))
830 .ok()
831 .flatten();
832 adapter.process_diagnostics(&mut params, server_id, buffer);
833 }
834
835 this.merge_lsp_diagnostics(
836 DiagnosticSourceKind::Pushed,
837 vec![DocumentDiagnosticsUpdate {
838 server_id,
839 diagnostics: params,
840 result_id: None,
841 disk_based_sources: Cow::Borrowed(
842 &adapter.disk_based_diagnostic_sources,
843 ),
844 registration_id: None,
845 }],
846 |_, diagnostic, cx| match diagnostic.source_kind {
847 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
848 adapter.retain_old_diagnostic(diagnostic, cx)
849 }
850 DiagnosticSourceKind::Pulled => true,
851 },
852 cx,
853 )
854 .log_err();
855 });
856 }
857 }
858 })
859 .detach();
860 language_server
861 .on_request::<lsp::request::WorkspaceConfiguration, _, _>({
862 let adapter = adapter.adapter.clone();
863 let delegate = delegate.clone();
864 let this = lsp_store.clone();
865 move |params, cx| {
866 let adapter = adapter.clone();
867 let delegate = delegate.clone();
868 let this = this.clone();
869 let mut cx = cx.clone();
870 async move {
871 let toolchain_for_id = this
872 .update(&mut cx, |this, _| {
873 this.as_local()?.language_server_ids.iter().find_map(
874 |(seed, value)| {
875 (value.id == server_id).then(|| seed.toolchain.clone())
876 },
877 )
878 })?
879 .context("Expected the LSP store to be in a local mode")?;
880
881 let mut scope_uri_to_workspace_config = BTreeMap::new();
882 for item in ¶ms.items {
883 let scope_uri = item.scope_uri.clone();
884 let std::collections::btree_map::Entry::Vacant(new_scope_uri) =
885 scope_uri_to_workspace_config.entry(scope_uri.clone())
886 else {
887 // We've already queried workspace configuration of this URI.
888 continue;
889 };
890 let workspace_config = Self::workspace_configuration_for_adapter(
891 adapter.clone(),
892 &delegate,
893 toolchain_for_id.clone(),
894 scope_uri,
895 &mut cx,
896 )
897 .await?;
898 new_scope_uri.insert(workspace_config);
899 }
900
901 Ok(params
902 .items
903 .into_iter()
904 .filter_map(|item| {
905 let workspace_config =
906 scope_uri_to_workspace_config.get(&item.scope_uri)?;
907 if let Some(section) = &item.section {
908 Some(
909 workspace_config
910 .get(section)
911 .cloned()
912 .unwrap_or(serde_json::Value::Null),
913 )
914 } else {
915 Some(workspace_config.clone())
916 }
917 })
918 .collect())
919 }
920 }
921 })
922 .detach();
923
924 language_server
925 .on_request::<lsp::request::WorkspaceFoldersRequest, _, _>({
926 let this = lsp_store.clone();
927 move |_, cx| {
928 let this = this.clone();
929 let cx = cx.clone();
930 async move {
931 let Some(server) =
932 this.read_with(&cx, |this, _| this.language_server_for_id(server_id))?
933 else {
934 return Ok(None);
935 };
936 let root = server.workspace_folders();
937 Ok(Some(
938 root.into_iter()
939 .map(|uri| WorkspaceFolder {
940 uri,
941 name: Default::default(),
942 })
943 .collect(),
944 ))
945 }
946 }
947 })
948 .detach();
949 // Even though we don't have handling for these requests, respond to them to
950 // avoid stalling any language server like `gopls` which waits for a response
951 // to these requests when initializing.
952 language_server
953 .on_request::<lsp::request::WorkDoneProgressCreate, _, _>({
954 let this = lsp_store.clone();
955 move |params, cx| {
956 let this = this.clone();
957 let mut cx = cx.clone();
958 async move {
959 this.update(&mut cx, |this, _| {
960 if let Some(status) = this.language_server_statuses.get_mut(&server_id)
961 {
962 status
963 .progress_tokens
964 .insert(ProgressToken::from_lsp(params.token));
965 }
966 })?;
967
968 Ok(())
969 }
970 }
971 })
972 .detach();
973
974 language_server
975 .on_request::<lsp::request::RegisterCapability, _, _>({
976 let lsp_store = lsp_store.clone();
977 move |params, cx| {
978 let lsp_store = lsp_store.clone();
979 let mut cx = cx.clone();
980 async move {
981 lsp_store
982 .update(&mut cx, |lsp_store, cx| {
983 if lsp_store.as_local().is_some() {
984 match lsp_store
985 .register_server_capabilities(server_id, params, cx)
986 {
987 Ok(()) => {}
988 Err(e) => {
989 log::error!(
990 "Failed to register server capabilities: {e:#}"
991 );
992 }
993 };
994 }
995 })
996 .ok();
997 Ok(())
998 }
999 }
1000 })
1001 .detach();
1002
1003 language_server
1004 .on_request::<lsp::request::UnregisterCapability, _, _>({
1005 let lsp_store = lsp_store.clone();
1006 move |params, cx| {
1007 let lsp_store = lsp_store.clone();
1008 let mut cx = cx.clone();
1009 async move {
1010 lsp_store
1011 .update(&mut cx, |lsp_store, cx| {
1012 if lsp_store.as_local().is_some() {
1013 match lsp_store
1014 .unregister_server_capabilities(server_id, params, cx)
1015 {
1016 Ok(()) => {}
1017 Err(e) => {
1018 log::error!(
1019 "Failed to unregister server capabilities: {e:#}"
1020 );
1021 }
1022 }
1023 }
1024 })
1025 .ok();
1026 Ok(())
1027 }
1028 }
1029 })
1030 .detach();
1031
1032 language_server
1033 .on_request::<lsp::request::ApplyWorkspaceEdit, _, _>({
1034 let this = lsp_store.clone();
1035 move |params, cx| {
1036 let mut cx = cx.clone();
1037 let this = this.clone();
1038 async move {
1039 LocalLspStore::on_lsp_workspace_edit(
1040 this.clone(),
1041 params,
1042 server_id,
1043 &mut cx,
1044 )
1045 .await
1046 }
1047 }
1048 })
1049 .detach();
1050
1051 language_server
1052 .on_request::<lsp::request::InlayHintRefreshRequest, _, _>({
1053 let lsp_store = lsp_store.clone();
1054 let request_id = Arc::new(AtomicUsize::new(0));
1055 move |(), cx| {
1056 let lsp_store = lsp_store.clone();
1057 let request_id = request_id.clone();
1058 let mut cx = cx.clone();
1059 async move {
1060 lsp_store
1061 .update(&mut cx, |lsp_store, cx| {
1062 let request_id =
1063 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1064 cx.emit(LspStoreEvent::RefreshInlayHints {
1065 server_id,
1066 request_id,
1067 });
1068 lsp_store
1069 .downstream_client
1070 .as_ref()
1071 .map(|(client, project_id)| {
1072 client.send(proto::RefreshInlayHints {
1073 project_id: *project_id,
1074 server_id: server_id.to_proto(),
1075 request_id: request_id.map(|id| id as u64),
1076 })
1077 })
1078 })?
1079 .transpose()?;
1080 Ok(())
1081 }
1082 }
1083 })
1084 .detach();
1085
1086 language_server
1087 .on_request::<lsp::request::CodeLensRefresh, _, _>({
1088 let this = lsp_store.clone();
1089 move |(), cx| {
1090 let this = this.clone();
1091 let mut cx = cx.clone();
1092 async move {
1093 this.update(&mut cx, |this, cx| {
1094 cx.emit(LspStoreEvent::RefreshCodeLens);
1095 this.downstream_client.as_ref().map(|(client, project_id)| {
1096 client.send(proto::RefreshCodeLens {
1097 project_id: *project_id,
1098 })
1099 })
1100 })?
1101 .transpose()?;
1102 Ok(())
1103 }
1104 }
1105 })
1106 .detach();
1107
1108 language_server
1109 .on_request::<lsp::request::SemanticTokensRefresh, _, _>({
1110 let lsp_store = lsp_store.clone();
1111 let request_id = Arc::new(AtomicUsize::new(0));
1112 move |(), cx| {
1113 let lsp_store = lsp_store.clone();
1114 let request_id = request_id.clone();
1115 let mut cx = cx.clone();
1116 async move {
1117 lsp_store
1118 .update(&mut cx, |lsp_store, cx| {
1119 let request_id =
1120 Some(request_id.fetch_add(1, atomic::Ordering::AcqRel));
1121 cx.emit(LspStoreEvent::RefreshSemanticTokens {
1122 server_id,
1123 request_id,
1124 });
1125 lsp_store
1126 .downstream_client
1127 .as_ref()
1128 .map(|(client, project_id)| {
1129 client.send(proto::RefreshSemanticTokens {
1130 project_id: *project_id,
1131 server_id: server_id.to_proto(),
1132 request_id: request_id.map(|id| id as u64),
1133 })
1134 })
1135 })?
1136 .transpose()?;
1137 Ok(())
1138 }
1139 }
1140 })
1141 .detach();
1142
1143 language_server
1144 .on_request::<lsp::request::WorkspaceDiagnosticRefresh, _, _>({
1145 let this = lsp_store.clone();
1146 move |(), cx| {
1147 let this = this.clone();
1148 let mut cx = cx.clone();
1149 async move {
1150 this.update(&mut cx, |lsp_store, cx| {
1151 lsp_store.pull_workspace_diagnostics(server_id);
1152 lsp_store
1153 .downstream_client
1154 .as_ref()
1155 .map(|(client, project_id)| {
1156 client.send(proto::PullWorkspaceDiagnostics {
1157 project_id: *project_id,
1158 server_id: server_id.to_proto(),
1159 })
1160 })
1161 .transpose()?;
1162 anyhow::Ok(
1163 lsp_store.pull_document_diagnostics_for_server(server_id, None, cx),
1164 )
1165 })??
1166 .await;
1167 Ok(())
1168 }
1169 }
1170 })
1171 .detach();
1172
1173 language_server
1174 .on_request::<lsp::request::ShowMessageRequest, _, _>({
1175 let this = lsp_store.clone();
1176 let name = name.to_string();
1177 let adapter = adapter.clone();
1178 move |params, cx| {
1179 let this = this.clone();
1180 let name = name.to_string();
1181 let adapter = adapter.clone();
1182 let mut cx = cx.clone();
1183 async move {
1184 let actions = params.actions.unwrap_or_default();
1185 let message = params.message.clone();
1186 let (tx, rx) = smol::channel::bounded::<MessageActionItem>(1);
1187 let level = match params.typ {
1188 lsp::MessageType::ERROR => PromptLevel::Critical,
1189 lsp::MessageType::WARNING => PromptLevel::Warning,
1190 _ => PromptLevel::Info,
1191 };
1192 let request = LanguageServerPromptRequest::new(
1193 level,
1194 params.message,
1195 actions,
1196 name.clone(),
1197 tx,
1198 );
1199
1200 let did_update = this
1201 .update(&mut cx, |_, cx| {
1202 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1203 })
1204 .is_ok();
1205 if did_update {
1206 let response = rx.recv().await.ok();
1207 if let Some(ref selected_action) = response {
1208 let context = language::PromptResponseContext {
1209 message,
1210 selected_action: selected_action.clone(),
1211 };
1212 adapter.process_prompt_response(&context, &mut cx)
1213 }
1214
1215 Ok(response)
1216 } else {
1217 Ok(None)
1218 }
1219 }
1220 }
1221 })
1222 .detach();
1223 language_server
1224 .on_notification::<lsp::notification::ShowMessage, _>({
1225 let this = lsp_store.clone();
1226 let name = name.to_string();
1227 move |params, cx| {
1228 let this = this.clone();
1229 let name = name.to_string();
1230 let mut cx = cx.clone();
1231
1232 let (tx, _) = smol::channel::bounded(1);
1233 let level = match params.typ {
1234 lsp::MessageType::ERROR => PromptLevel::Critical,
1235 lsp::MessageType::WARNING => PromptLevel::Warning,
1236 _ => PromptLevel::Info,
1237 };
1238 let request =
1239 LanguageServerPromptRequest::new(level, params.message, vec![], name, tx);
1240
1241 let _ = this.update(&mut cx, |_, cx| {
1242 cx.emit(LspStoreEvent::LanguageServerPrompt(request));
1243 });
1244 }
1245 })
1246 .detach();
1247
1248 let disk_based_diagnostics_progress_token =
1249 adapter.disk_based_diagnostics_progress_token.clone();
1250
1251 language_server
1252 .on_notification::<lsp::notification::Progress, _>({
1253 let this = lsp_store.clone();
1254 move |params, cx| {
1255 if let Some(this) = this.upgrade() {
1256 this.update(cx, |this, cx| {
1257 this.on_lsp_progress(
1258 params,
1259 server_id,
1260 disk_based_diagnostics_progress_token.clone(),
1261 cx,
1262 );
1263 });
1264 }
1265 }
1266 })
1267 .detach();
1268
1269 language_server
1270 .on_notification::<lsp::notification::LogMessage, _>({
1271 let this = lsp_store.clone();
1272 move |params, cx| {
1273 if let Some(this) = this.upgrade() {
1274 this.update(cx, |_, cx| {
1275 cx.emit(LspStoreEvent::LanguageServerLog(
1276 server_id,
1277 LanguageServerLogType::Log(params.typ),
1278 params.message,
1279 ));
1280 });
1281 }
1282 }
1283 })
1284 .detach();
1285
1286 language_server
1287 .on_notification::<lsp::notification::LogTrace, _>({
1288 let this = lsp_store.clone();
1289 move |params, cx| {
1290 let mut cx = cx.clone();
1291 if let Some(this) = this.upgrade() {
1292 this.update(&mut cx, |_, cx| {
1293 cx.emit(LspStoreEvent::LanguageServerLog(
1294 server_id,
1295 LanguageServerLogType::Trace {
1296 verbose_info: params.verbose,
1297 },
1298 params.message,
1299 ));
1300 });
1301 }
1302 }
1303 })
1304 .detach();
1305
1306 vue_language_server_ext::register_requests(lsp_store.clone(), language_server);
1307 json_language_server_ext::register_requests(lsp_store.clone(), language_server);
1308 rust_analyzer_ext::register_notifications(lsp_store.clone(), language_server);
1309 clangd_ext::register_notifications(lsp_store, language_server, adapter);
1310 }
1311
1312 fn shutdown_language_servers_on_quit(&mut self) -> impl Future<Output = ()> + use<> {
1313 let shutdown_futures = self
1314 .language_servers
1315 .drain()
1316 .map(|(_, server_state)| Self::shutdown_server(server_state))
1317 .collect::<Vec<_>>();
1318
1319 async move {
1320 join_all(shutdown_futures).await;
1321 }
1322 }
1323
1324 async fn shutdown_server(server_state: LanguageServerState) -> anyhow::Result<()> {
1325 match server_state {
1326 LanguageServerState::Running { server, .. } => {
1327 if let Some(shutdown) = server.shutdown() {
1328 shutdown.await;
1329 }
1330 }
1331 LanguageServerState::Starting { startup, .. } => {
1332 if let Some(server) = startup.await
1333 && let Some(shutdown) = server.shutdown()
1334 {
1335 shutdown.await;
1336 }
1337 }
1338 }
1339 Ok(())
1340 }
1341
1342 fn language_servers_for_worktree(
1343 &self,
1344 worktree_id: WorktreeId,
1345 ) -> impl Iterator<Item = &Arc<LanguageServer>> {
1346 self.language_server_ids
1347 .iter()
1348 .filter_map(move |(seed, state)| {
1349 if seed.worktree_id != worktree_id {
1350 return None;
1351 }
1352
1353 if let Some(LanguageServerState::Running { server, .. }) =
1354 self.language_servers.get(&state.id)
1355 {
1356 Some(server)
1357 } else {
1358 None
1359 }
1360 })
1361 }
1362
1363 fn language_server_ids_for_project_path(
1364 &self,
1365 project_path: ProjectPath,
1366 language: &Language,
1367 cx: &mut App,
1368 ) -> Vec<LanguageServerId> {
1369 let Some(worktree) = self
1370 .worktree_store
1371 .read(cx)
1372 .worktree_for_id(project_path.worktree_id, cx)
1373 else {
1374 return Vec::new();
1375 };
1376 let delegate: Arc<dyn ManifestDelegate> =
1377 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
1378
1379 self.lsp_tree
1380 .get(
1381 project_path,
1382 language.name(),
1383 language.manifest(),
1384 &delegate,
1385 cx,
1386 )
1387 .collect::<Vec<_>>()
1388 }
1389
1390 fn language_server_ids_for_buffer(
1391 &self,
1392 buffer: &Buffer,
1393 cx: &mut App,
1394 ) -> Vec<LanguageServerId> {
1395 if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
1396 let worktree_id = file.worktree_id(cx);
1397
1398 let path: Arc<RelPath> = file
1399 .path()
1400 .parent()
1401 .map(Arc::from)
1402 .unwrap_or_else(|| file.path().clone());
1403 let worktree_path = ProjectPath { worktree_id, path };
1404 self.language_server_ids_for_project_path(worktree_path, language, cx)
1405 } else {
1406 Vec::new()
1407 }
1408 }
1409
1410 fn language_servers_for_buffer<'a>(
1411 &'a self,
1412 buffer: &'a Buffer,
1413 cx: &'a mut App,
1414 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
1415 self.language_server_ids_for_buffer(buffer, cx)
1416 .into_iter()
1417 .filter_map(|server_id| match self.language_servers.get(&server_id)? {
1418 LanguageServerState::Running {
1419 adapter, server, ..
1420 } => Some((adapter, server)),
1421 _ => None,
1422 })
1423 }
1424
1425 async fn execute_code_action_kind_locally(
1426 lsp_store: WeakEntity<LspStore>,
1427 mut buffers: Vec<Entity<Buffer>>,
1428 kind: CodeActionKind,
1429 push_to_history: bool,
1430 cx: &mut AsyncApp,
1431 ) -> anyhow::Result<ProjectTransaction> {
1432 // Do not allow multiple concurrent code actions requests for the
1433 // same buffer.
1434 lsp_store.update(cx, |this, cx| {
1435 let this = this.as_local_mut().unwrap();
1436 buffers.retain(|buffer| {
1437 this.buffers_being_formatted
1438 .insert(buffer.read(cx).remote_id())
1439 });
1440 })?;
1441 let _cleanup = defer({
1442 let this = lsp_store.clone();
1443 let mut cx = cx.clone();
1444 let buffers = &buffers;
1445 move || {
1446 this.update(&mut cx, |this, cx| {
1447 let this = this.as_local_mut().unwrap();
1448 for buffer in buffers {
1449 this.buffers_being_formatted
1450 .remove(&buffer.read(cx).remote_id());
1451 }
1452 })
1453 .ok();
1454 }
1455 });
1456 let mut project_transaction = ProjectTransaction::default();
1457
1458 for buffer in &buffers {
1459 let adapters_and_servers = lsp_store.update(cx, |lsp_store, cx| {
1460 buffer.update(cx, |buffer, cx| {
1461 lsp_store
1462 .as_local()
1463 .unwrap()
1464 .language_servers_for_buffer(buffer, cx)
1465 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1466 .collect::<Vec<_>>()
1467 })
1468 })?;
1469 for (_, language_server) in adapters_and_servers.iter() {
1470 let actions = Self::get_server_code_actions_from_action_kinds(
1471 &lsp_store,
1472 language_server.server_id(),
1473 vec![kind.clone()],
1474 buffer,
1475 cx,
1476 )
1477 .await?;
1478 Self::execute_code_actions_on_server(
1479 &lsp_store,
1480 language_server,
1481 actions,
1482 push_to_history,
1483 &mut project_transaction,
1484 cx,
1485 )
1486 .await?;
1487 }
1488 }
1489 Ok(project_transaction)
1490 }
1491
1492 async fn format_locally(
1493 lsp_store: WeakEntity<LspStore>,
1494 mut buffers: Vec<FormattableBuffer>,
1495 push_to_history: bool,
1496 trigger: FormatTrigger,
1497 logger: zlog::Logger,
1498 cx: &mut AsyncApp,
1499 ) -> anyhow::Result<ProjectTransaction> {
1500 // Do not allow multiple concurrent formatting requests for the
1501 // same buffer.
1502 lsp_store.update(cx, |this, cx| {
1503 let this = this.as_local_mut().unwrap();
1504 buffers.retain(|buffer| {
1505 this.buffers_being_formatted
1506 .insert(buffer.handle.read(cx).remote_id())
1507 });
1508 })?;
1509
1510 let _cleanup = defer({
1511 let this = lsp_store.clone();
1512 let mut cx = cx.clone();
1513 let buffers = &buffers;
1514 move || {
1515 this.update(&mut cx, |this, cx| {
1516 let this = this.as_local_mut().unwrap();
1517 for buffer in buffers {
1518 this.buffers_being_formatted
1519 .remove(&buffer.handle.read(cx).remote_id());
1520 }
1521 })
1522 .ok();
1523 }
1524 });
1525
1526 let mut project_transaction = ProjectTransaction::default();
1527
1528 for buffer in &buffers {
1529 zlog::debug!(
1530 logger =>
1531 "formatting buffer '{:?}'",
1532 buffer.abs_path.as_ref().unwrap_or(&PathBuf::from("unknown")).display()
1533 );
1534 // Create an empty transaction to hold all of the formatting edits.
1535 let formatting_transaction_id = buffer.handle.update(cx, |buffer, cx| {
1536 // ensure no transactions created while formatting are
1537 // grouped with the previous transaction in the history
1538 // based on the transaction group interval
1539 buffer.finalize_last_transaction();
1540 buffer
1541 .start_transaction()
1542 .context("transaction already open")?;
1543 buffer.end_transaction(cx);
1544 let transaction_id = buffer.push_empty_transaction(cx.background_executor().now());
1545 buffer.finalize_last_transaction();
1546 anyhow::Ok(transaction_id)
1547 })?;
1548
1549 let result = Self::format_buffer_locally(
1550 lsp_store.clone(),
1551 buffer,
1552 formatting_transaction_id,
1553 trigger,
1554 logger,
1555 cx,
1556 )
1557 .await;
1558
1559 buffer.handle.update(cx, |buffer, cx| {
1560 let Some(formatting_transaction) =
1561 buffer.get_transaction(formatting_transaction_id).cloned()
1562 else {
1563 zlog::warn!(logger => "no formatting transaction");
1564 return;
1565 };
1566 if formatting_transaction.edit_ids.is_empty() {
1567 zlog::debug!(logger => "no changes made while formatting");
1568 buffer.forget_transaction(formatting_transaction_id);
1569 return;
1570 }
1571 if !push_to_history {
1572 zlog::trace!(logger => "forgetting format transaction");
1573 buffer.forget_transaction(formatting_transaction.id);
1574 }
1575 project_transaction
1576 .0
1577 .insert(cx.entity(), formatting_transaction);
1578 });
1579
1580 result?;
1581 }
1582
1583 Ok(project_transaction)
1584 }
1585
1586 async fn format_buffer_locally(
1587 lsp_store: WeakEntity<LspStore>,
1588 buffer: &FormattableBuffer,
1589 formatting_transaction_id: clock::Lamport,
1590 trigger: FormatTrigger,
1591 logger: zlog::Logger,
1592 cx: &mut AsyncApp,
1593 ) -> Result<()> {
1594 let (adapters_and_servers, settings, request_timeout) =
1595 lsp_store.update(cx, |lsp_store, cx| {
1596 buffer.handle.update(cx, |buffer, cx| {
1597 let adapters_and_servers = lsp_store
1598 .as_local()
1599 .unwrap()
1600 .language_servers_for_buffer(buffer, cx)
1601 .map(|(adapter, lsp)| (adapter.clone(), lsp.clone()))
1602 .collect::<Vec<_>>();
1603 let settings =
1604 language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
1605 .into_owned();
1606 let request_timeout = ProjectSettings::get_global(cx)
1607 .global_lsp_settings
1608 .get_request_timeout();
1609 (adapters_and_servers, settings, request_timeout)
1610 })
1611 })?;
1612
1613 /// Apply edits to the buffer that will become part of the formatting transaction.
1614 /// Fails if the buffer has been edited since the start of that transaction.
1615 fn extend_formatting_transaction(
1616 buffer: &FormattableBuffer,
1617 formatting_transaction_id: text::TransactionId,
1618 cx: &mut AsyncApp,
1619 operation: impl FnOnce(&mut Buffer, &mut Context<Buffer>),
1620 ) -> anyhow::Result<()> {
1621 buffer.handle.update(cx, |buffer, cx| {
1622 let last_transaction_id = buffer.peek_undo_stack().map(|t| t.transaction_id());
1623 if last_transaction_id != Some(formatting_transaction_id) {
1624 anyhow::bail!("Buffer edited while formatting. Aborting")
1625 }
1626 buffer.start_transaction();
1627 operation(buffer, cx);
1628 if let Some(transaction_id) = buffer.end_transaction(cx) {
1629 buffer.merge_transactions(transaction_id, formatting_transaction_id);
1630 }
1631 Ok(())
1632 })
1633 }
1634
1635 // handle whitespace formatting
1636 if settings.remove_trailing_whitespace_on_save {
1637 zlog::trace!(logger => "removing trailing whitespace");
1638 let diff = buffer
1639 .handle
1640 .read_with(cx, |buffer, cx| buffer.remove_trailing_whitespace(cx))
1641 .await;
1642 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1643 buffer.apply_diff(diff, cx);
1644 })?;
1645 }
1646
1647 if settings.ensure_final_newline_on_save {
1648 zlog::trace!(logger => "ensuring final newline");
1649 extend_formatting_transaction(buffer, formatting_transaction_id, cx, |buffer, cx| {
1650 buffer.ensure_final_newline(cx);
1651 })?;
1652 }
1653
1654 // Formatter for `code_actions_on_format` that runs before
1655 // the rest of the formatters
1656 let mut code_actions_on_format_formatters = None;
1657 let should_run_code_actions_on_format = !matches!(
1658 (trigger, &settings.format_on_save),
1659 (FormatTrigger::Save, &FormatOnSave::Off)
1660 );
1661 if should_run_code_actions_on_format {
1662 let have_code_actions_to_run_on_format = settings
1663 .code_actions_on_format
1664 .values()
1665 .any(|enabled| *enabled);
1666 if have_code_actions_to_run_on_format {
1667 zlog::trace!(logger => "going to run code actions on format");
1668 code_actions_on_format_formatters = Some(
1669 settings
1670 .code_actions_on_format
1671 .iter()
1672 .filter_map(|(action, enabled)| enabled.then_some(action))
1673 .cloned()
1674 .map(Formatter::CodeAction)
1675 .collect::<Vec<_>>(),
1676 );
1677 }
1678 }
1679
1680 let formatters = match (trigger, &settings.format_on_save) {
1681 (FormatTrigger::Save, FormatOnSave::Off) => &[],
1682 (FormatTrigger::Manual, _) | (FormatTrigger::Save, FormatOnSave::On) => {
1683 settings.formatter.as_ref()
1684 }
1685 };
1686
1687 let formatters = code_actions_on_format_formatters
1688 .iter()
1689 .flatten()
1690 .chain(formatters);
1691
1692 for formatter in formatters {
1693 let formatter = if formatter == &Formatter::Auto {
1694 if settings.prettier.allowed {
1695 zlog::trace!(logger => "Formatter set to auto: defaulting to prettier");
1696 &Formatter::Prettier
1697 } else {
1698 zlog::trace!(logger => "Formatter set to auto: defaulting to primary language server");
1699 &Formatter::LanguageServer(settings::LanguageServerFormatterSpecifier::Current)
1700 }
1701 } else {
1702 formatter
1703 };
1704 match formatter {
1705 Formatter::Auto => unreachable!("Auto resolved above"),
1706 Formatter::Prettier => {
1707 let logger = zlog::scoped!(logger => "prettier");
1708 zlog::trace!(logger => "formatting");
1709 let _timer = zlog::time!(logger => "Formatting buffer via prettier");
1710
1711 let prettier = lsp_store.read_with(cx, |lsp_store, _cx| {
1712 lsp_store.prettier_store().unwrap().downgrade()
1713 })?;
1714 let diff = prettier_store::format_with_prettier(&prettier, &buffer.handle, cx)
1715 .await
1716 .transpose()?;
1717 let Some(diff) = diff else {
1718 zlog::trace!(logger => "No changes");
1719 continue;
1720 };
1721
1722 extend_formatting_transaction(
1723 buffer,
1724 formatting_transaction_id,
1725 cx,
1726 |buffer, cx| {
1727 buffer.apply_diff(diff, cx);
1728 },
1729 )?;
1730 }
1731 Formatter::External { command, arguments } => {
1732 let logger = zlog::scoped!(logger => "command");
1733 zlog::trace!(logger => "formatting");
1734 let _timer = zlog::time!(logger => "Formatting buffer via external command");
1735
1736 let diff = Self::format_via_external_command(
1737 buffer,
1738 &command,
1739 arguments.as_deref(),
1740 cx,
1741 )
1742 .await
1743 .with_context(|| {
1744 format!("Failed to format buffer via external command: {}", command)
1745 })?;
1746 let Some(diff) = diff else {
1747 zlog::trace!(logger => "No changes");
1748 continue;
1749 };
1750
1751 extend_formatting_transaction(
1752 buffer,
1753 formatting_transaction_id,
1754 cx,
1755 |buffer, cx| {
1756 buffer.apply_diff(diff, cx);
1757 },
1758 )?;
1759 }
1760 Formatter::LanguageServer(specifier) => {
1761 let logger = zlog::scoped!(logger => "language-server");
1762 zlog::trace!(logger => "formatting");
1763 let _timer = zlog::time!(logger => "Formatting buffer using language server");
1764
1765 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1766 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using language servers. Skipping");
1767 continue;
1768 };
1769
1770 let language_server = match specifier {
1771 settings::LanguageServerFormatterSpecifier::Specific { name } => {
1772 adapters_and_servers.iter().find_map(|(adapter, server)| {
1773 if adapter.name.0.as_ref() == name {
1774 Some(server.clone())
1775 } else {
1776 None
1777 }
1778 })
1779 }
1780 settings::LanguageServerFormatterSpecifier::Current => {
1781 adapters_and_servers.first().map(|e| e.1.clone())
1782 }
1783 };
1784
1785 let Some(language_server) = language_server else {
1786 log::debug!(
1787 "No language server found to format buffer '{:?}'. Skipping",
1788 buffer_path_abs.as_path().to_string_lossy()
1789 );
1790 continue;
1791 };
1792
1793 zlog::trace!(
1794 logger =>
1795 "Formatting buffer '{:?}' using language server '{:?}'",
1796 buffer_path_abs.as_path().to_string_lossy(),
1797 language_server.name()
1798 );
1799
1800 let edits = if let Some(ranges) = buffer.ranges.as_ref() {
1801 zlog::trace!(logger => "formatting ranges");
1802 Self::format_ranges_via_lsp(
1803 &lsp_store,
1804 &buffer.handle,
1805 ranges,
1806 buffer_path_abs,
1807 &language_server,
1808 &settings,
1809 cx,
1810 )
1811 .await
1812 .context("Failed to format ranges via language server")?
1813 } else {
1814 zlog::trace!(logger => "formatting full");
1815 Self::format_via_lsp(
1816 &lsp_store,
1817 &buffer.handle,
1818 buffer_path_abs,
1819 &language_server,
1820 &settings,
1821 cx,
1822 )
1823 .await
1824 .context("failed to format via language server")?
1825 };
1826
1827 if edits.is_empty() {
1828 zlog::trace!(logger => "No changes");
1829 continue;
1830 }
1831 extend_formatting_transaction(
1832 buffer,
1833 formatting_transaction_id,
1834 cx,
1835 |buffer, cx| {
1836 buffer.edit(edits, None, cx);
1837 },
1838 )?;
1839 }
1840 Formatter::CodeAction(code_action_name) => {
1841 let logger = zlog::scoped!(logger => "code-actions");
1842 zlog::trace!(logger => "formatting");
1843 let _timer = zlog::time!(logger => "Formatting buffer using code actions");
1844
1845 let Some(buffer_path_abs) = buffer.abs_path.as_ref() else {
1846 zlog::warn!(logger => "Cannot format buffer that is not backed by a file on disk using code actions. Skipping");
1847 continue;
1848 };
1849
1850 let code_action_kind: CodeActionKind = code_action_name.clone().into();
1851 zlog::trace!(logger => "Attempting to resolve code actions {:?}", &code_action_kind);
1852
1853 let mut actions_and_servers = Vec::new();
1854
1855 for (index, (_, language_server)) in adapters_and_servers.iter().enumerate() {
1856 let actions_result = Self::get_server_code_actions_from_action_kinds(
1857 &lsp_store,
1858 language_server.server_id(),
1859 vec![code_action_kind.clone()],
1860 &buffer.handle,
1861 cx,
1862 )
1863 .await
1864 .with_context(|| {
1865 format!(
1866 "Failed to resolve code action {:?} with language server {}",
1867 code_action_kind,
1868 language_server.name()
1869 )
1870 });
1871 let Ok(actions) = actions_result else {
1872 // note: it may be better to set result to the error and break formatters here
1873 // but for now we try to execute the actions that we can resolve and skip the rest
1874 zlog::error!(
1875 logger =>
1876 "Failed to resolve code action {:?} with language server {}",
1877 code_action_kind,
1878 language_server.name()
1879 );
1880 continue;
1881 };
1882 for action in actions {
1883 actions_and_servers.push((action, index));
1884 }
1885 }
1886
1887 if actions_and_servers.is_empty() {
1888 zlog::warn!(logger => "No code actions were resolved, continuing");
1889 continue;
1890 }
1891
1892 'actions: for (mut action, server_index) in actions_and_servers {
1893 let server = &adapters_and_servers[server_index].1;
1894
1895 let describe_code_action = |action: &CodeAction| {
1896 format!(
1897 "code action '{}' with title \"{}\" on server {}",
1898 action
1899 .lsp_action
1900 .action_kind()
1901 .unwrap_or("unknown".into())
1902 .as_str(),
1903 action.lsp_action.title(),
1904 server.name(),
1905 )
1906 };
1907
1908 zlog::trace!(logger => "Executing {}", describe_code_action(&action));
1909
1910 if let Err(err) =
1911 Self::try_resolve_code_action(server, &mut action, request_timeout)
1912 .await
1913 {
1914 zlog::error!(
1915 logger =>
1916 "Failed to resolve {}. Error: {}",
1917 describe_code_action(&action),
1918 err
1919 );
1920 continue;
1921 }
1922
1923 if let Some(edit) = action.lsp_action.edit().cloned() {
1924 // NOTE: code below duplicated from `Self::deserialize_workspace_edit`
1925 // but filters out and logs warnings for code actions that require unreasonably
1926 // difficult handling on our part, such as:
1927 // - applying edits that call commands
1928 // which can result in arbitrary workspace edits being sent from the server that
1929 // have no way of being tied back to the command that initiated them (i.e. we
1930 // can't know which edits are part of the format request, or if the server is done sending
1931 // actions in response to the command)
1932 // - actions that create/delete/modify/rename files other than the one we are formatting
1933 // as we then would need to handle such changes correctly in the local history as well
1934 // as the remote history through the ProjectTransaction
1935 // - actions with snippet edits, as these simply don't make sense in the context of a format request
1936 // Supporting these actions is not impossible, but not supported as of yet.
1937 if edit.changes.is_none() && edit.document_changes.is_none() {
1938 zlog::trace!(
1939 logger =>
1940 "No changes for code action. Skipping {}",
1941 describe_code_action(&action),
1942 );
1943 continue;
1944 }
1945
1946 let mut operations = Vec::new();
1947 if let Some(document_changes) = edit.document_changes {
1948 match document_changes {
1949 lsp::DocumentChanges::Edits(edits) => operations.extend(
1950 edits.into_iter().map(lsp::DocumentChangeOperation::Edit),
1951 ),
1952 lsp::DocumentChanges::Operations(ops) => operations = ops,
1953 }
1954 } else if let Some(changes) = edit.changes {
1955 operations.extend(changes.into_iter().map(|(uri, edits)| {
1956 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
1957 text_document:
1958 lsp::OptionalVersionedTextDocumentIdentifier {
1959 uri,
1960 version: None,
1961 },
1962 edits: edits.into_iter().map(Edit::Plain).collect(),
1963 })
1964 }));
1965 }
1966
1967 let mut edits = Vec::with_capacity(operations.len());
1968
1969 if operations.is_empty() {
1970 zlog::trace!(
1971 logger =>
1972 "No changes for code action. Skipping {}",
1973 describe_code_action(&action),
1974 );
1975 continue;
1976 }
1977 for operation in operations {
1978 let op = match operation {
1979 lsp::DocumentChangeOperation::Edit(op) => op,
1980 lsp::DocumentChangeOperation::Op(_) => {
1981 zlog::warn!(
1982 logger =>
1983 "Code actions which create, delete, or rename files are not supported on format. Skipping {}",
1984 describe_code_action(&action),
1985 );
1986 continue 'actions;
1987 }
1988 };
1989 let Ok(file_path) = op.text_document.uri.to_file_path() else {
1990 zlog::warn!(
1991 logger =>
1992 "Failed to convert URI '{:?}' to file path. Skipping {}",
1993 &op.text_document.uri,
1994 describe_code_action(&action),
1995 );
1996 continue 'actions;
1997 };
1998 if &file_path != buffer_path_abs {
1999 zlog::warn!(
2000 logger =>
2001 "File path '{:?}' does not match buffer path '{:?}'. Skipping {}",
2002 file_path,
2003 buffer_path_abs,
2004 describe_code_action(&action),
2005 );
2006 continue 'actions;
2007 }
2008
2009 let mut lsp_edits = Vec::new();
2010 for edit in op.edits {
2011 match edit {
2012 Edit::Plain(edit) => {
2013 if !lsp_edits.contains(&edit) {
2014 lsp_edits.push(edit);
2015 }
2016 }
2017 Edit::Annotated(edit) => {
2018 if !lsp_edits.contains(&edit.text_edit) {
2019 lsp_edits.push(edit.text_edit);
2020 }
2021 }
2022 Edit::Snippet(_) => {
2023 zlog::warn!(
2024 logger =>
2025 "Code actions which produce snippet edits are not supported during formatting. Skipping {}",
2026 describe_code_action(&action),
2027 );
2028 continue 'actions;
2029 }
2030 }
2031 }
2032 let edits_result = lsp_store
2033 .update(cx, |lsp_store, cx| {
2034 lsp_store.as_local_mut().unwrap().edits_from_lsp(
2035 &buffer.handle,
2036 lsp_edits,
2037 server.server_id(),
2038 op.text_document.version,
2039 cx,
2040 )
2041 })?
2042 .await;
2043 let Ok(resolved_edits) = edits_result else {
2044 zlog::warn!(
2045 logger =>
2046 "Failed to resolve edits from LSP for buffer {:?} while handling {}",
2047 buffer_path_abs.as_path(),
2048 describe_code_action(&action),
2049 );
2050 continue 'actions;
2051 };
2052 edits.extend(resolved_edits);
2053 }
2054
2055 if edits.is_empty() {
2056 zlog::warn!(logger => "No edits resolved from LSP");
2057 continue;
2058 }
2059
2060 extend_formatting_transaction(
2061 buffer,
2062 formatting_transaction_id,
2063 cx,
2064 |buffer, cx| {
2065 zlog::info!(
2066 "Applying edits {edits:?}. Content: {:?}",
2067 buffer.text()
2068 );
2069 buffer.edit(edits, None, cx);
2070 zlog::info!("Applied edits. New Content: {:?}", buffer.text());
2071 },
2072 )?;
2073 }
2074
2075 // bail early if command is invalid
2076 let Some(command) = action.lsp_action.command() else {
2077 continue;
2078 };
2079
2080 zlog::warn!(
2081 logger =>
2082 "Executing code action command '{}'. This may cause formatting to abort unnecessarily as well as splitting formatting into two entries in the undo history",
2083 &command.command,
2084 );
2085
2086 let server_capabilities = server.capabilities();
2087 let available_commands = server_capabilities
2088 .execute_command_provider
2089 .as_ref()
2090 .map(|options| options.commands.as_slice())
2091 .unwrap_or_default();
2092 if !available_commands.contains(&command.command) {
2093 zlog::warn!(
2094 logger =>
2095 "Cannot execute a command {} not listed in the language server capabilities of server {}",
2096 command.command,
2097 server.name(),
2098 );
2099 continue;
2100 }
2101
2102 // noop so we just ensure buffer hasn't been edited since resolving code actions
2103 extend_formatting_transaction(
2104 buffer,
2105 formatting_transaction_id,
2106 cx,
2107 |_, _| {},
2108 )?;
2109 zlog::info!(logger => "Executing command {}", &command.command);
2110
2111 lsp_store.update(cx, |this, _| {
2112 this.as_local_mut()
2113 .unwrap()
2114 .last_workspace_edits_by_language_server
2115 .remove(&server.server_id());
2116 })?;
2117
2118 let execute_command_result = server
2119 .request::<lsp::request::ExecuteCommand>(
2120 lsp::ExecuteCommandParams {
2121 command: command.command.clone(),
2122 arguments: command.arguments.clone().unwrap_or_default(),
2123 ..Default::default()
2124 },
2125 request_timeout,
2126 )
2127 .await
2128 .into_response();
2129
2130 if execute_command_result.is_err() {
2131 zlog::error!(
2132 logger =>
2133 "Failed to execute command '{}' as part of {}",
2134 &command.command,
2135 describe_code_action(&action),
2136 );
2137 continue 'actions;
2138 }
2139
2140 let mut project_transaction_command = lsp_store.update(cx, |this, _| {
2141 this.as_local_mut()
2142 .unwrap()
2143 .last_workspace_edits_by_language_server
2144 .remove(&server.server_id())
2145 .unwrap_or_default()
2146 })?;
2147
2148 if let Some(transaction) =
2149 project_transaction_command.0.remove(&buffer.handle)
2150 {
2151 zlog::trace!(
2152 logger =>
2153 "Successfully captured {} edits that resulted from command {}",
2154 transaction.edit_ids.len(),
2155 &command.command,
2156 );
2157 let transaction_id_project_transaction = transaction.id;
2158 buffer.handle.update(cx, |buffer, _| {
2159 // it may have been removed from history if push_to_history was
2160 // false in deserialize_workspace_edit. If so push it so we
2161 // can merge it with the format transaction
2162 // and pop the combined transaction off the history stack
2163 // later if push_to_history is false
2164 if buffer.get_transaction(transaction.id).is_none() {
2165 buffer.push_transaction(transaction, Instant::now());
2166 }
2167 buffer.merge_transactions(
2168 transaction_id_project_transaction,
2169 formatting_transaction_id,
2170 );
2171 });
2172 }
2173
2174 if project_transaction_command.0.is_empty() {
2175 continue;
2176 }
2177
2178 let mut extra_buffers = String::new();
2179 for buffer in project_transaction_command.0.keys() {
2180 buffer.read_with(cx, |b, cx| {
2181 let Some(path) = b.project_path(cx) else {
2182 return;
2183 };
2184
2185 if !extra_buffers.is_empty() {
2186 extra_buffers.push_str(", ");
2187 }
2188 extra_buffers.push_str(path.path.as_unix_str());
2189 });
2190 }
2191 zlog::warn!(
2192 logger =>
2193 "Unexpected edits to buffers other than the buffer actively being formatted due to command {}. Impacted buffers: [{}].",
2194 &command.command,
2195 extra_buffers,
2196 );
2197 // NOTE: if this case is hit, the proper thing to do is to for each buffer, merge the extra transaction
2198 // into the existing transaction in project_transaction if there is one, and if there isn't one in project_transaction,
2199 // add it so it's included, and merge it into the format transaction when its created later
2200 }
2201 }
2202 }
2203 }
2204
2205 Ok(())
2206 }
2207
2208 pub async fn format_ranges_via_lsp(
2209 this: &WeakEntity<LspStore>,
2210 buffer_handle: &Entity<Buffer>,
2211 ranges: &[Range<Anchor>],
2212 abs_path: &Path,
2213 language_server: &Arc<LanguageServer>,
2214 settings: &LanguageSettings,
2215 cx: &mut AsyncApp,
2216 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2217 let capabilities = &language_server.capabilities();
2218 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2219 if range_formatting_provider == Some(&OneOf::Left(false)) {
2220 anyhow::bail!(
2221 "{} language server does not support range formatting",
2222 language_server.name()
2223 );
2224 }
2225
2226 let uri = file_path_to_lsp_url(abs_path)?;
2227 let text_document = lsp::TextDocumentIdentifier::new(uri);
2228
2229 let request_timeout = cx.update(|app| {
2230 ProjectSettings::get_global(app)
2231 .global_lsp_settings
2232 .get_request_timeout()
2233 });
2234 let lsp_edits = {
2235 let mut lsp_ranges = Vec::new();
2236 this.update(cx, |_this, cx| {
2237 // TODO(#22930): In the case of formatting multibuffer selections, this buffer may
2238 // not have been sent to the language server. This seems like a fairly systemic
2239 // issue, though, the resolution probably is not specific to formatting.
2240 //
2241 // TODO: Instead of using current snapshot, should use the latest snapshot sent to
2242 // LSP.
2243 let snapshot = buffer_handle.read(cx).snapshot();
2244 for range in ranges {
2245 lsp_ranges.push(range_to_lsp(range.to_point_utf16(&snapshot))?);
2246 }
2247 anyhow::Ok(())
2248 })??;
2249
2250 let mut edits = None;
2251 for range in lsp_ranges {
2252 if let Some(mut edit) = language_server
2253 .request::<lsp::request::RangeFormatting>(
2254 lsp::DocumentRangeFormattingParams {
2255 text_document: text_document.clone(),
2256 range,
2257 options: lsp_command::lsp_formatting_options(settings),
2258 work_done_progress_params: Default::default(),
2259 },
2260 request_timeout,
2261 )
2262 .await
2263 .into_response()?
2264 {
2265 edits.get_or_insert_with(Vec::new).append(&mut edit);
2266 }
2267 }
2268 edits
2269 };
2270
2271 if let Some(lsp_edits) = lsp_edits {
2272 this.update(cx, |this, cx| {
2273 this.as_local_mut().unwrap().edits_from_lsp(
2274 buffer_handle,
2275 lsp_edits,
2276 language_server.server_id(),
2277 None,
2278 cx,
2279 )
2280 })?
2281 .await
2282 } else {
2283 Ok(Vec::with_capacity(0))
2284 }
2285 }
2286
2287 async fn format_via_lsp(
2288 this: &WeakEntity<LspStore>,
2289 buffer: &Entity<Buffer>,
2290 abs_path: &Path,
2291 language_server: &Arc<LanguageServer>,
2292 settings: &LanguageSettings,
2293 cx: &mut AsyncApp,
2294 ) -> Result<Vec<(Range<Anchor>, Arc<str>)>> {
2295 let logger = zlog::scoped!("lsp_format");
2296 zlog::debug!(logger => "Formatting via LSP");
2297
2298 let uri = file_path_to_lsp_url(abs_path)?;
2299 let text_document = lsp::TextDocumentIdentifier::new(uri);
2300 let capabilities = &language_server.capabilities();
2301
2302 let formatting_provider = capabilities.document_formatting_provider.as_ref();
2303 let range_formatting_provider = capabilities.document_range_formatting_provider.as_ref();
2304
2305 let request_timeout = cx.update(|app| {
2306 ProjectSettings::get_global(app)
2307 .global_lsp_settings
2308 .get_request_timeout()
2309 });
2310
2311 let lsp_edits = if matches!(formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2312 let _timer = zlog::time!(logger => "format-full");
2313 language_server
2314 .request::<lsp::request::Formatting>(
2315 lsp::DocumentFormattingParams {
2316 text_document,
2317 options: lsp_command::lsp_formatting_options(settings),
2318 work_done_progress_params: Default::default(),
2319 },
2320 request_timeout,
2321 )
2322 .await
2323 .into_response()?
2324 } else if matches!(range_formatting_provider, Some(p) if *p != OneOf::Left(false)) {
2325 let _timer = zlog::time!(logger => "format-range");
2326 let buffer_start = lsp::Position::new(0, 0);
2327 let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16()));
2328 language_server
2329 .request::<lsp::request::RangeFormatting>(
2330 lsp::DocumentRangeFormattingParams {
2331 text_document: text_document.clone(),
2332 range: lsp::Range::new(buffer_start, buffer_end),
2333 options: lsp_command::lsp_formatting_options(settings),
2334 work_done_progress_params: Default::default(),
2335 },
2336 request_timeout,
2337 )
2338 .await
2339 .into_response()?
2340 } else {
2341 None
2342 };
2343
2344 if let Some(lsp_edits) = lsp_edits {
2345 this.update(cx, |this, cx| {
2346 this.as_local_mut().unwrap().edits_from_lsp(
2347 buffer,
2348 lsp_edits,
2349 language_server.server_id(),
2350 None,
2351 cx,
2352 )
2353 })?
2354 .await
2355 } else {
2356 Ok(Vec::with_capacity(0))
2357 }
2358 }
2359
2360 async fn format_via_external_command(
2361 buffer: &FormattableBuffer,
2362 command: &str,
2363 arguments: Option<&[String]>,
2364 cx: &mut AsyncApp,
2365 ) -> Result<Option<Diff>> {
2366 let working_dir_path = buffer.handle.update(cx, |buffer, cx| {
2367 let file = File::from_dyn(buffer.file())?;
2368 let worktree = file.worktree.read(cx);
2369 let mut worktree_path = worktree.abs_path().to_path_buf();
2370 if worktree.root_entry()?.is_file() {
2371 worktree_path.pop();
2372 }
2373 Some(worktree_path)
2374 });
2375
2376 let mut child = util::command::new_smol_command(command);
2377
2378 if let Some(buffer_env) = buffer.env.as_ref() {
2379 child.envs(buffer_env);
2380 }
2381
2382 if let Some(working_dir_path) = working_dir_path {
2383 child.current_dir(working_dir_path);
2384 }
2385
2386 if let Some(arguments) = arguments {
2387 child.args(arguments.iter().map(|arg| {
2388 if let Some(buffer_abs_path) = buffer.abs_path.as_ref() {
2389 arg.replace("{buffer_path}", &buffer_abs_path.to_string_lossy())
2390 } else {
2391 arg.replace("{buffer_path}", "Untitled")
2392 }
2393 }));
2394 }
2395
2396 let mut child = child
2397 .stdin(smol::process::Stdio::piped())
2398 .stdout(smol::process::Stdio::piped())
2399 .stderr(smol::process::Stdio::piped())
2400 .spawn()?;
2401
2402 let stdin = child.stdin.as_mut().context("failed to acquire stdin")?;
2403 let text = buffer
2404 .handle
2405 .read_with(cx, |buffer, _| buffer.as_rope().clone());
2406 for chunk in text.chunks() {
2407 stdin.write_all(chunk.as_bytes()).await?;
2408 }
2409 stdin.flush().await?;
2410
2411 let output = child.output().await?;
2412 anyhow::ensure!(
2413 output.status.success(),
2414 "command failed with exit code {:?}:\nstdout: {}\nstderr: {}",
2415 output.status.code(),
2416 String::from_utf8_lossy(&output.stdout),
2417 String::from_utf8_lossy(&output.stderr),
2418 );
2419
2420 let stdout = String::from_utf8(output.stdout)?;
2421 Ok(Some(
2422 buffer
2423 .handle
2424 .update(cx, |buffer, cx| buffer.diff(stdout, cx))
2425 .await,
2426 ))
2427 }
2428
2429 async fn try_resolve_code_action(
2430 lang_server: &LanguageServer,
2431 action: &mut CodeAction,
2432 request_timeout: Duration,
2433 ) -> anyhow::Result<()> {
2434 match &mut action.lsp_action {
2435 LspAction::Action(lsp_action) => {
2436 if !action.resolved
2437 && GetCodeActions::can_resolve_actions(&lang_server.capabilities())
2438 && lsp_action.data.is_some()
2439 && (lsp_action.command.is_none() || lsp_action.edit.is_none())
2440 {
2441 **lsp_action = lang_server
2442 .request::<lsp::request::CodeActionResolveRequest>(
2443 *lsp_action.clone(),
2444 request_timeout,
2445 )
2446 .await
2447 .into_response()?;
2448 }
2449 }
2450 LspAction::CodeLens(lens) => {
2451 if !action.resolved && GetCodeLens::can_resolve_lens(&lang_server.capabilities()) {
2452 *lens = lang_server
2453 .request::<lsp::request::CodeLensResolve>(lens.clone(), request_timeout)
2454 .await
2455 .into_response()?;
2456 }
2457 }
2458 LspAction::Command(_) => {}
2459 }
2460
2461 action.resolved = true;
2462 anyhow::Ok(())
2463 }
2464
2465 fn initialize_buffer(&mut self, buffer_handle: &Entity<Buffer>, cx: &mut Context<LspStore>) {
2466 let buffer = buffer_handle.read(cx);
2467
2468 let file = buffer.file().cloned();
2469
2470 let Some(file) = File::from_dyn(file.as_ref()) else {
2471 return;
2472 };
2473 if !file.is_local() {
2474 return;
2475 }
2476 let path = ProjectPath::from_file(file, cx);
2477 let worktree_id = file.worktree_id(cx);
2478 let language = buffer.language().cloned();
2479
2480 if let Some(diagnostics) = self.diagnostics.get(&worktree_id) {
2481 for (server_id, diagnostics) in
2482 diagnostics.get(file.path()).cloned().unwrap_or_default()
2483 {
2484 self.update_buffer_diagnostics(
2485 buffer_handle,
2486 server_id,
2487 None,
2488 None,
2489 None,
2490 Vec::new(),
2491 diagnostics,
2492 cx,
2493 )
2494 .log_err();
2495 }
2496 }
2497 let Some(language) = language else {
2498 return;
2499 };
2500 let Some(snapshot) = self
2501 .worktree_store
2502 .read(cx)
2503 .worktree_for_id(worktree_id, cx)
2504 .map(|worktree| worktree.read(cx).snapshot())
2505 else {
2506 return;
2507 };
2508 let delegate: Arc<dyn ManifestDelegate> = Arc::new(ManifestQueryDelegate::new(snapshot));
2509
2510 for server_id in
2511 self.lsp_tree
2512 .get(path, language.name(), language.manifest(), &delegate, cx)
2513 {
2514 let server = self
2515 .language_servers
2516 .get(&server_id)
2517 .and_then(|server_state| {
2518 if let LanguageServerState::Running { server, .. } = server_state {
2519 Some(server.clone())
2520 } else {
2521 None
2522 }
2523 });
2524 let server = match server {
2525 Some(server) => server,
2526 None => continue,
2527 };
2528
2529 buffer_handle.update(cx, |buffer, cx| {
2530 buffer.set_completion_triggers(
2531 server.server_id(),
2532 server
2533 .capabilities()
2534 .completion_provider
2535 .as_ref()
2536 .and_then(|provider| {
2537 provider
2538 .trigger_characters
2539 .as_ref()
2540 .map(|characters| characters.iter().cloned().collect())
2541 })
2542 .unwrap_or_default(),
2543 cx,
2544 );
2545 });
2546 }
2547 }
2548
2549 pub(crate) fn reset_buffer(&mut self, buffer: &Entity<Buffer>, old_file: &File, cx: &mut App) {
2550 buffer.update(cx, |buffer, cx| {
2551 let Some(language) = buffer.language() else {
2552 return;
2553 };
2554 let path = ProjectPath {
2555 worktree_id: old_file.worktree_id(cx),
2556 path: old_file.path.clone(),
2557 };
2558 for server_id in self.language_server_ids_for_project_path(path, language, cx) {
2559 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
2560 buffer.set_completion_triggers(server_id, Default::default(), cx);
2561 }
2562 });
2563 }
2564
2565 fn update_buffer_diagnostics(
2566 &mut self,
2567 buffer: &Entity<Buffer>,
2568 server_id: LanguageServerId,
2569 registration_id: Option<Option<SharedString>>,
2570 result_id: Option<SharedString>,
2571 version: Option<i32>,
2572 new_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2573 reused_diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
2574 cx: &mut Context<LspStore>,
2575 ) -> Result<()> {
2576 fn compare_diagnostics(a: &Diagnostic, b: &Diagnostic) -> Ordering {
2577 Ordering::Equal
2578 .then_with(|| b.is_primary.cmp(&a.is_primary))
2579 .then_with(|| a.is_disk_based.cmp(&b.is_disk_based))
2580 .then_with(|| a.severity.cmp(&b.severity))
2581 .then_with(|| a.message.cmp(&b.message))
2582 }
2583
2584 let mut diagnostics = Vec::with_capacity(new_diagnostics.len() + reused_diagnostics.len());
2585 diagnostics.extend(new_diagnostics.into_iter().map(|d| (true, d)));
2586 diagnostics.extend(reused_diagnostics.into_iter().map(|d| (false, d)));
2587
2588 diagnostics.sort_unstable_by(|(_, a), (_, b)| {
2589 Ordering::Equal
2590 .then_with(|| a.range.start.cmp(&b.range.start))
2591 .then_with(|| b.range.end.cmp(&a.range.end))
2592 .then_with(|| compare_diagnostics(&a.diagnostic, &b.diagnostic))
2593 });
2594
2595 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx)?;
2596
2597 let edits_since_save = std::cell::LazyCell::new(|| {
2598 let saved_version = buffer.read(cx).saved_version();
2599 Patch::new(snapshot.edits_since::<PointUtf16>(saved_version).collect())
2600 });
2601
2602 let mut sanitized_diagnostics = Vec::with_capacity(diagnostics.len());
2603
2604 for (new_diagnostic, entry) in diagnostics {
2605 let start;
2606 let end;
2607 if new_diagnostic && entry.diagnostic.is_disk_based {
2608 // Some diagnostics are based on files on disk instead of buffers'
2609 // current contents. Adjust these diagnostics' ranges to reflect
2610 // any unsaved edits.
2611 // Do not alter the reused ones though, as their coordinates were stored as anchors
2612 // and were properly adjusted on reuse.
2613 start = Unclipped((*edits_since_save).old_to_new(entry.range.start.0));
2614 end = Unclipped((*edits_since_save).old_to_new(entry.range.end.0));
2615 } else {
2616 start = entry.range.start;
2617 end = entry.range.end;
2618 }
2619
2620 let mut range = snapshot.clip_point_utf16(start, Bias::Left)
2621 ..snapshot.clip_point_utf16(end, Bias::Right);
2622
2623 // Expand empty ranges by one codepoint
2624 if range.start == range.end {
2625 // This will be go to the next boundary when being clipped
2626 range.end.column += 1;
2627 range.end = snapshot.clip_point_utf16(Unclipped(range.end), Bias::Right);
2628 if range.start == range.end && range.end.column > 0 {
2629 range.start.column -= 1;
2630 range.start = snapshot.clip_point_utf16(Unclipped(range.start), Bias::Left);
2631 }
2632 }
2633
2634 sanitized_diagnostics.push(DiagnosticEntry {
2635 range,
2636 diagnostic: entry.diagnostic,
2637 });
2638 }
2639 drop(edits_since_save);
2640
2641 let set = DiagnosticSet::new(sanitized_diagnostics, &snapshot);
2642 buffer.update(cx, |buffer, cx| {
2643 if let Some(registration_id) = registration_id {
2644 if let Some(abs_path) = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx)) {
2645 self.buffer_pull_diagnostics_result_ids
2646 .entry(server_id)
2647 .or_default()
2648 .entry(registration_id)
2649 .or_default()
2650 .insert(abs_path, result_id);
2651 }
2652 }
2653
2654 buffer.update_diagnostics(server_id, set, cx)
2655 });
2656
2657 Ok(())
2658 }
2659
2660 fn register_language_server_for_invisible_worktree(
2661 &mut self,
2662 worktree: &Entity<Worktree>,
2663 language_server_id: LanguageServerId,
2664 cx: &mut App,
2665 ) {
2666 let worktree = worktree.read(cx);
2667 let worktree_id = worktree.id();
2668 debug_assert!(!worktree.is_visible());
2669 let Some(mut origin_seed) = self
2670 .language_server_ids
2671 .iter()
2672 .find_map(|(seed, state)| (state.id == language_server_id).then(|| seed.clone()))
2673 else {
2674 return;
2675 };
2676 origin_seed.worktree_id = worktree_id;
2677 self.language_server_ids
2678 .entry(origin_seed)
2679 .or_insert_with(|| UnifiedLanguageServer {
2680 id: language_server_id,
2681 project_roots: Default::default(),
2682 });
2683 }
2684
2685 fn register_buffer_with_language_servers(
2686 &mut self,
2687 buffer_handle: &Entity<Buffer>,
2688 only_register_servers: HashSet<LanguageServerSelector>,
2689 cx: &mut Context<LspStore>,
2690 ) {
2691 let buffer = buffer_handle.read(cx);
2692 let buffer_id = buffer.remote_id();
2693
2694 let Some(file) = File::from_dyn(buffer.file()) else {
2695 return;
2696 };
2697 if !file.is_local() {
2698 return;
2699 }
2700
2701 let abs_path = file.abs_path(cx);
2702 let Some(uri) = file_path_to_lsp_url(&abs_path).log_err() else {
2703 return;
2704 };
2705 let initial_snapshot = buffer.text_snapshot();
2706 let worktree_id = file.worktree_id(cx);
2707
2708 let Some(language) = buffer.language().cloned() else {
2709 return;
2710 };
2711 let path: Arc<RelPath> = file
2712 .path()
2713 .parent()
2714 .map(Arc::from)
2715 .unwrap_or_else(|| file.path().clone());
2716 let Some(worktree) = self
2717 .worktree_store
2718 .read(cx)
2719 .worktree_for_id(worktree_id, cx)
2720 else {
2721 return;
2722 };
2723 let language_name = language.name();
2724 let (reused, delegate, servers) = self
2725 .reuse_existing_language_server(&self.lsp_tree, &worktree, &language_name, cx)
2726 .map(|(delegate, apply)| (true, delegate, apply(&mut self.lsp_tree)))
2727 .unwrap_or_else(|| {
2728 let lsp_delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
2729 let delegate: Arc<dyn ManifestDelegate> =
2730 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
2731
2732 let servers = self
2733 .lsp_tree
2734 .walk(
2735 ProjectPath { worktree_id, path },
2736 language.name(),
2737 language.manifest(),
2738 &delegate,
2739 cx,
2740 )
2741 .collect::<Vec<_>>();
2742 (false, lsp_delegate, servers)
2743 });
2744 let servers_and_adapters = servers
2745 .into_iter()
2746 .filter_map(|server_node| {
2747 if reused && server_node.server_id().is_none() {
2748 return None;
2749 }
2750 if !only_register_servers.is_empty() {
2751 if let Some(server_id) = server_node.server_id()
2752 && !only_register_servers.contains(&LanguageServerSelector::Id(server_id))
2753 {
2754 return None;
2755 }
2756 if let Some(name) = server_node.name()
2757 && !only_register_servers.contains(&LanguageServerSelector::Name(name))
2758 {
2759 return None;
2760 }
2761 }
2762
2763 let server_id = server_node.server_id_or_init(|disposition| {
2764 let path = &disposition.path;
2765
2766 {
2767 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
2768
2769 let server_id = self.get_or_insert_language_server(
2770 &worktree,
2771 delegate.clone(),
2772 disposition,
2773 &language_name,
2774 cx,
2775 );
2776
2777 if let Some(state) = self.language_servers.get(&server_id)
2778 && let Ok(uri) = uri
2779 {
2780 state.add_workspace_folder(uri);
2781 };
2782 server_id
2783 }
2784 })?;
2785 let server_state = self.language_servers.get(&server_id)?;
2786 if let LanguageServerState::Running {
2787 server, adapter, ..
2788 } = server_state
2789 {
2790 Some((server.clone(), adapter.clone()))
2791 } else {
2792 None
2793 }
2794 })
2795 .collect::<Vec<_>>();
2796 for (server, adapter) in servers_and_adapters {
2797 buffer_handle.update(cx, |buffer, cx| {
2798 buffer.set_completion_triggers(
2799 server.server_id(),
2800 server
2801 .capabilities()
2802 .completion_provider
2803 .as_ref()
2804 .and_then(|provider| {
2805 provider
2806 .trigger_characters
2807 .as_ref()
2808 .map(|characters| characters.iter().cloned().collect())
2809 })
2810 .unwrap_or_default(),
2811 cx,
2812 );
2813 });
2814
2815 let snapshot = LspBufferSnapshot {
2816 version: 0,
2817 snapshot: initial_snapshot.clone(),
2818 };
2819
2820 let mut registered = false;
2821 self.buffer_snapshots
2822 .entry(buffer_id)
2823 .or_default()
2824 .entry(server.server_id())
2825 .or_insert_with(|| {
2826 registered = true;
2827 server.register_buffer(
2828 uri.clone(),
2829 adapter.language_id(&language.name()),
2830 0,
2831 initial_snapshot.text(),
2832 );
2833
2834 vec![snapshot]
2835 });
2836
2837 self.buffers_opened_in_servers
2838 .entry(buffer_id)
2839 .or_default()
2840 .insert(server.server_id());
2841 if registered {
2842 cx.emit(LspStoreEvent::LanguageServerUpdate {
2843 language_server_id: server.server_id(),
2844 name: None,
2845 message: proto::update_language_server::Variant::RegisteredForBuffer(
2846 proto::RegisteredForBuffer {
2847 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
2848 buffer_id: buffer_id.to_proto(),
2849 },
2850 ),
2851 });
2852 }
2853 }
2854 }
2855
2856 fn reuse_existing_language_server<'lang_name>(
2857 &self,
2858 server_tree: &LanguageServerTree,
2859 worktree: &Entity<Worktree>,
2860 language_name: &'lang_name LanguageName,
2861 cx: &mut App,
2862 ) -> Option<(
2863 Arc<LocalLspAdapterDelegate>,
2864 impl FnOnce(&mut LanguageServerTree) -> Vec<LanguageServerTreeNode> + use<'lang_name>,
2865 )> {
2866 if worktree.read(cx).is_visible() {
2867 return None;
2868 }
2869
2870 let worktree_store = self.worktree_store.read(cx);
2871 let servers = server_tree
2872 .instances
2873 .iter()
2874 .filter(|(worktree_id, _)| {
2875 worktree_store
2876 .worktree_for_id(**worktree_id, cx)
2877 .is_some_and(|worktree| worktree.read(cx).is_visible())
2878 })
2879 .flat_map(|(worktree_id, servers)| {
2880 servers
2881 .roots
2882 .iter()
2883 .flat_map(|(_, language_servers)| language_servers)
2884 .map(move |(_, (server_node, server_languages))| {
2885 (worktree_id, server_node, server_languages)
2886 })
2887 .filter(|(_, _, server_languages)| server_languages.contains(language_name))
2888 .map(|(worktree_id, server_node, _)| {
2889 (
2890 *worktree_id,
2891 LanguageServerTreeNode::from(Arc::downgrade(server_node)),
2892 )
2893 })
2894 })
2895 .fold(HashMap::default(), |mut acc, (worktree_id, server_node)| {
2896 acc.entry(worktree_id)
2897 .or_insert_with(Vec::new)
2898 .push(server_node);
2899 acc
2900 })
2901 .into_values()
2902 .max_by_key(|servers| servers.len())?;
2903
2904 let worktree_id = worktree.read(cx).id();
2905 let apply = move |tree: &mut LanguageServerTree| {
2906 for server_node in &servers {
2907 tree.register_reused(worktree_id, language_name.clone(), server_node.clone());
2908 }
2909 servers
2910 };
2911
2912 let delegate = LocalLspAdapterDelegate::from_local_lsp(self, worktree, cx);
2913 Some((delegate, apply))
2914 }
2915
2916 pub(crate) fn unregister_old_buffer_from_language_servers(
2917 &mut self,
2918 buffer: &Entity<Buffer>,
2919 old_file: &File,
2920 cx: &mut App,
2921 ) {
2922 let old_path = match old_file.as_local() {
2923 Some(local) => local.abs_path(cx),
2924 None => return,
2925 };
2926
2927 let Ok(file_url) = lsp::Uri::from_file_path(old_path.as_path()) else {
2928 debug_panic!("{old_path:?} is not parseable as an URI");
2929 return;
2930 };
2931 self.unregister_buffer_from_language_servers(buffer, &file_url, cx);
2932 }
2933
2934 pub(crate) fn unregister_buffer_from_language_servers(
2935 &mut self,
2936 buffer: &Entity<Buffer>,
2937 file_url: &lsp::Uri,
2938 cx: &mut App,
2939 ) {
2940 buffer.update(cx, |buffer, cx| {
2941 let mut snapshots = self.buffer_snapshots.remove(&buffer.remote_id());
2942
2943 for (_, language_server) in self.language_servers_for_buffer(buffer, cx) {
2944 if snapshots
2945 .as_mut()
2946 .is_some_and(|map| map.remove(&language_server.server_id()).is_some())
2947 {
2948 language_server.unregister_buffer(file_url.clone());
2949 }
2950 }
2951 });
2952 }
2953
2954 fn buffer_snapshot_for_lsp_version(
2955 &mut self,
2956 buffer: &Entity<Buffer>,
2957 server_id: LanguageServerId,
2958 version: Option<i32>,
2959 cx: &App,
2960 ) -> Result<TextBufferSnapshot> {
2961 const OLD_VERSIONS_TO_RETAIN: i32 = 10;
2962
2963 if let Some(version) = version {
2964 let buffer_id = buffer.read(cx).remote_id();
2965 let snapshots = if let Some(snapshots) = self
2966 .buffer_snapshots
2967 .get_mut(&buffer_id)
2968 .and_then(|m| m.get_mut(&server_id))
2969 {
2970 snapshots
2971 } else if version == 0 {
2972 // Some language servers report version 0 even if the buffer hasn't been opened yet.
2973 // We detect this case and treat it as if the version was `None`.
2974 return Ok(buffer.read(cx).text_snapshot());
2975 } else {
2976 anyhow::bail!("no snapshots found for buffer {buffer_id} and server {server_id}");
2977 };
2978
2979 let found_snapshot = snapshots
2980 .binary_search_by_key(&version, |e| e.version)
2981 .map(|ix| snapshots[ix].snapshot.clone())
2982 .map_err(|_| {
2983 anyhow!("snapshot not found for buffer {buffer_id} server {server_id} at version {version}")
2984 })?;
2985
2986 snapshots.retain(|snapshot| snapshot.version + OLD_VERSIONS_TO_RETAIN >= version);
2987 Ok(found_snapshot)
2988 } else {
2989 Ok((buffer.read(cx)).text_snapshot())
2990 }
2991 }
2992
2993 async fn get_server_code_actions_from_action_kinds(
2994 lsp_store: &WeakEntity<LspStore>,
2995 language_server_id: LanguageServerId,
2996 code_action_kinds: Vec<lsp::CodeActionKind>,
2997 buffer: &Entity<Buffer>,
2998 cx: &mut AsyncApp,
2999 ) -> Result<Vec<CodeAction>> {
3000 let actions = lsp_store
3001 .update(cx, move |this, cx| {
3002 let request = GetCodeActions {
3003 range: text::Anchor::min_max_range_for_buffer(buffer.read(cx).remote_id()),
3004 kinds: Some(code_action_kinds),
3005 };
3006 let server = LanguageServerToQuery::Other(language_server_id);
3007 this.request_lsp(buffer.clone(), server, request, cx)
3008 })?
3009 .await?;
3010 Ok(actions)
3011 }
3012
3013 pub async fn execute_code_actions_on_server(
3014 lsp_store: &WeakEntity<LspStore>,
3015 language_server: &Arc<LanguageServer>,
3016 actions: Vec<CodeAction>,
3017 push_to_history: bool,
3018 project_transaction: &mut ProjectTransaction,
3019 cx: &mut AsyncApp,
3020 ) -> anyhow::Result<()> {
3021 let request_timeout = cx.update(|app| {
3022 ProjectSettings::get_global(app)
3023 .global_lsp_settings
3024 .get_request_timeout()
3025 });
3026
3027 for mut action in actions {
3028 Self::try_resolve_code_action(language_server, &mut action, request_timeout)
3029 .await
3030 .context("resolving a formatting code action")?;
3031
3032 if let Some(edit) = action.lsp_action.edit() {
3033 if edit.changes.is_none() && edit.document_changes.is_none() {
3034 continue;
3035 }
3036
3037 let new = Self::deserialize_workspace_edit(
3038 lsp_store.upgrade().context("project dropped")?,
3039 edit.clone(),
3040 push_to_history,
3041 language_server.clone(),
3042 cx,
3043 )
3044 .await?;
3045 project_transaction.0.extend(new.0);
3046 }
3047
3048 let Some(command) = action.lsp_action.command() else {
3049 continue;
3050 };
3051
3052 let server_capabilities = language_server.capabilities();
3053 let available_commands = server_capabilities
3054 .execute_command_provider
3055 .as_ref()
3056 .map(|options| options.commands.as_slice())
3057 .unwrap_or_default();
3058 if !available_commands.contains(&command.command) {
3059 log::warn!(
3060 "Cannot execute a command {} not listed in the language server capabilities",
3061 command.command
3062 );
3063 continue;
3064 }
3065
3066 lsp_store.update(cx, |lsp_store, _| {
3067 if let LspStoreMode::Local(mode) = &mut lsp_store.mode {
3068 mode.last_workspace_edits_by_language_server
3069 .remove(&language_server.server_id());
3070 }
3071 })?;
3072
3073 language_server
3074 .request::<lsp::request::ExecuteCommand>(
3075 lsp::ExecuteCommandParams {
3076 command: command.command.clone(),
3077 arguments: command.arguments.clone().unwrap_or_default(),
3078 ..Default::default()
3079 },
3080 request_timeout,
3081 )
3082 .await
3083 .into_response()
3084 .context("execute command")?;
3085
3086 lsp_store.update(cx, |this, _| {
3087 if let LspStoreMode::Local(mode) = &mut this.mode {
3088 project_transaction.0.extend(
3089 mode.last_workspace_edits_by_language_server
3090 .remove(&language_server.server_id())
3091 .unwrap_or_default()
3092 .0,
3093 )
3094 }
3095 })?;
3096 }
3097 Ok(())
3098 }
3099
3100 pub async fn deserialize_text_edits(
3101 this: Entity<LspStore>,
3102 buffer_to_edit: Entity<Buffer>,
3103 edits: Vec<lsp::TextEdit>,
3104 push_to_history: bool,
3105 _: Arc<CachedLspAdapter>,
3106 language_server: Arc<LanguageServer>,
3107 cx: &mut AsyncApp,
3108 ) -> Result<Option<Transaction>> {
3109 let edits = this
3110 .update(cx, |this, cx| {
3111 this.as_local_mut().unwrap().edits_from_lsp(
3112 &buffer_to_edit,
3113 edits,
3114 language_server.server_id(),
3115 None,
3116 cx,
3117 )
3118 })
3119 .await?;
3120
3121 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3122 buffer.finalize_last_transaction();
3123 buffer.start_transaction();
3124 for (range, text) in edits {
3125 buffer.edit([(range, text)], None, cx);
3126 }
3127
3128 if buffer.end_transaction(cx).is_some() {
3129 let transaction = buffer.finalize_last_transaction().unwrap().clone();
3130 if !push_to_history {
3131 buffer.forget_transaction(transaction.id);
3132 }
3133 Some(transaction)
3134 } else {
3135 None
3136 }
3137 });
3138
3139 Ok(transaction)
3140 }
3141
3142 #[allow(clippy::type_complexity)]
3143 pub fn edits_from_lsp(
3144 &mut self,
3145 buffer: &Entity<Buffer>,
3146 lsp_edits: impl 'static + Send + IntoIterator<Item = lsp::TextEdit>,
3147 server_id: LanguageServerId,
3148 version: Option<i32>,
3149 cx: &mut Context<LspStore>,
3150 ) -> Task<Result<Vec<(Range<Anchor>, Arc<str>)>>> {
3151 let snapshot = self.buffer_snapshot_for_lsp_version(buffer, server_id, version, cx);
3152 cx.background_spawn(async move {
3153 let snapshot = snapshot?;
3154 let mut lsp_edits = lsp_edits
3155 .into_iter()
3156 .map(|edit| (range_from_lsp(edit.range), edit.new_text))
3157 .collect::<Vec<_>>();
3158
3159 lsp_edits.sort_by_key(|(range, _)| (range.start, range.end));
3160
3161 let mut lsp_edits = lsp_edits.into_iter().peekable();
3162 let mut edits = Vec::new();
3163 while let Some((range, mut new_text)) = lsp_edits.next() {
3164 // Clip invalid ranges provided by the language server.
3165 let mut range = snapshot.clip_point_utf16(range.start, Bias::Left)
3166 ..snapshot.clip_point_utf16(range.end, Bias::Left);
3167
3168 // Combine any LSP edits that are adjacent.
3169 //
3170 // Also, combine LSP edits that are separated from each other by only
3171 // a newline. This is important because for some code actions,
3172 // Rust-analyzer rewrites the entire buffer via a series of edits that
3173 // are separated by unchanged newline characters.
3174 //
3175 // In order for the diffing logic below to work properly, any edits that
3176 // cancel each other out must be combined into one.
3177 while let Some((next_range, next_text)) = lsp_edits.peek() {
3178 if next_range.start.0 > range.end {
3179 if next_range.start.0.row > range.end.row + 1
3180 || next_range.start.0.column > 0
3181 || snapshot.clip_point_utf16(
3182 Unclipped(PointUtf16::new(range.end.row, u32::MAX)),
3183 Bias::Left,
3184 ) > range.end
3185 {
3186 break;
3187 }
3188 new_text.push('\n');
3189 }
3190 range.end = snapshot.clip_point_utf16(next_range.end, Bias::Left);
3191 new_text.push_str(next_text);
3192 lsp_edits.next();
3193 }
3194
3195 // For multiline edits, perform a diff of the old and new text so that
3196 // we can identify the changes more precisely, preserving the locations
3197 // of any anchors positioned in the unchanged regions.
3198 if range.end.row > range.start.row {
3199 let offset = range.start.to_offset(&snapshot);
3200 let old_text = snapshot.text_for_range(range).collect::<String>();
3201 let range_edits = language::text_diff(old_text.as_str(), &new_text);
3202 edits.extend(range_edits.into_iter().map(|(range, replacement)| {
3203 (
3204 snapshot.anchor_after(offset + range.start)
3205 ..snapshot.anchor_before(offset + range.end),
3206 replacement,
3207 )
3208 }));
3209 } else if range.end == range.start {
3210 let anchor = snapshot.anchor_after(range.start);
3211 edits.push((anchor..anchor, new_text.into()));
3212 } else {
3213 let edit_start = snapshot.anchor_after(range.start);
3214 let edit_end = snapshot.anchor_before(range.end);
3215 edits.push((edit_start..edit_end, new_text.into()));
3216 }
3217 }
3218
3219 Ok(edits)
3220 })
3221 }
3222
3223 pub(crate) async fn deserialize_workspace_edit(
3224 this: Entity<LspStore>,
3225 edit: lsp::WorkspaceEdit,
3226 push_to_history: bool,
3227 language_server: Arc<LanguageServer>,
3228 cx: &mut AsyncApp,
3229 ) -> Result<ProjectTransaction> {
3230 let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone());
3231
3232 let mut operations = Vec::new();
3233 if let Some(document_changes) = edit.document_changes {
3234 match document_changes {
3235 lsp::DocumentChanges::Edits(edits) => {
3236 operations.extend(edits.into_iter().map(lsp::DocumentChangeOperation::Edit))
3237 }
3238 lsp::DocumentChanges::Operations(ops) => operations = ops,
3239 }
3240 } else if let Some(changes) = edit.changes {
3241 operations.extend(changes.into_iter().map(|(uri, edits)| {
3242 lsp::DocumentChangeOperation::Edit(lsp::TextDocumentEdit {
3243 text_document: lsp::OptionalVersionedTextDocumentIdentifier {
3244 uri,
3245 version: None,
3246 },
3247 edits: edits.into_iter().map(Edit::Plain).collect(),
3248 })
3249 }));
3250 }
3251
3252 let mut project_transaction = ProjectTransaction::default();
3253 for operation in operations {
3254 match operation {
3255 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Create(op)) => {
3256 let abs_path = op
3257 .uri
3258 .to_file_path()
3259 .map_err(|()| anyhow!("can't convert URI to path"))?;
3260
3261 if let Some(parent_path) = abs_path.parent() {
3262 fs.create_dir(parent_path).await?;
3263 }
3264 if abs_path.ends_with("/") {
3265 fs.create_dir(&abs_path).await?;
3266 } else {
3267 fs.create_file(
3268 &abs_path,
3269 op.options
3270 .map(|options| fs::CreateOptions {
3271 overwrite: options.overwrite.unwrap_or(false),
3272 ignore_if_exists: options.ignore_if_exists.unwrap_or(false),
3273 })
3274 .unwrap_or_default(),
3275 )
3276 .await?;
3277 }
3278 }
3279
3280 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Rename(op)) => {
3281 let source_abs_path = op
3282 .old_uri
3283 .to_file_path()
3284 .map_err(|()| anyhow!("can't convert URI to path"))?;
3285 let target_abs_path = op
3286 .new_uri
3287 .to_file_path()
3288 .map_err(|()| anyhow!("can't convert URI to path"))?;
3289
3290 let options = fs::RenameOptions {
3291 overwrite: op
3292 .options
3293 .as_ref()
3294 .and_then(|options| options.overwrite)
3295 .unwrap_or(false),
3296 ignore_if_exists: op
3297 .options
3298 .as_ref()
3299 .and_then(|options| options.ignore_if_exists)
3300 .unwrap_or(false),
3301 create_parents: true,
3302 };
3303
3304 fs.rename(&source_abs_path, &target_abs_path, options)
3305 .await?;
3306 }
3307
3308 lsp::DocumentChangeOperation::Op(lsp::ResourceOp::Delete(op)) => {
3309 let abs_path = op
3310 .uri
3311 .to_file_path()
3312 .map_err(|()| anyhow!("can't convert URI to path"))?;
3313 let options = op
3314 .options
3315 .map(|options| fs::RemoveOptions {
3316 recursive: options.recursive.unwrap_or(false),
3317 ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false),
3318 })
3319 .unwrap_or_default();
3320 if abs_path.ends_with("/") {
3321 fs.remove_dir(&abs_path, options).await?;
3322 } else {
3323 fs.remove_file(&abs_path, options).await?;
3324 }
3325 }
3326
3327 lsp::DocumentChangeOperation::Edit(op) => {
3328 let buffer_to_edit = this
3329 .update(cx, |this, cx| {
3330 this.open_local_buffer_via_lsp(
3331 op.text_document.uri.clone(),
3332 language_server.server_id(),
3333 cx,
3334 )
3335 })
3336 .await?;
3337
3338 let edits = this
3339 .update(cx, |this, cx| {
3340 let path = buffer_to_edit.read(cx).project_path(cx);
3341 let active_entry = this.active_entry;
3342 let is_active_entry = path.is_some_and(|project_path| {
3343 this.worktree_store
3344 .read(cx)
3345 .entry_for_path(&project_path, cx)
3346 .is_some_and(|entry| Some(entry.id) == active_entry)
3347 });
3348 let local = this.as_local_mut().unwrap();
3349
3350 let (mut edits, mut snippet_edits) = (vec![], vec![]);
3351 for edit in op.edits {
3352 match edit {
3353 Edit::Plain(edit) => {
3354 if !edits.contains(&edit) {
3355 edits.push(edit)
3356 }
3357 }
3358 Edit::Annotated(edit) => {
3359 if !edits.contains(&edit.text_edit) {
3360 edits.push(edit.text_edit)
3361 }
3362 }
3363 Edit::Snippet(edit) => {
3364 let Ok(snippet) = Snippet::parse(&edit.snippet.value)
3365 else {
3366 continue;
3367 };
3368
3369 if is_active_entry {
3370 snippet_edits.push((edit.range, snippet));
3371 } else {
3372 // Since this buffer is not focused, apply a normal edit.
3373 let new_edit = TextEdit {
3374 range: edit.range,
3375 new_text: snippet.text,
3376 };
3377 if !edits.contains(&new_edit) {
3378 edits.push(new_edit);
3379 }
3380 }
3381 }
3382 }
3383 }
3384 if !snippet_edits.is_empty() {
3385 let buffer_id = buffer_to_edit.read(cx).remote_id();
3386 let version = if let Some(buffer_version) = op.text_document.version
3387 {
3388 local
3389 .buffer_snapshot_for_lsp_version(
3390 &buffer_to_edit,
3391 language_server.server_id(),
3392 Some(buffer_version),
3393 cx,
3394 )
3395 .ok()
3396 .map(|snapshot| snapshot.version)
3397 } else {
3398 Some(buffer_to_edit.read(cx).saved_version().clone())
3399 };
3400
3401 let most_recent_edit =
3402 version.and_then(|version| version.most_recent());
3403 // Check if the edit that triggered that edit has been made by this participant.
3404
3405 if let Some(most_recent_edit) = most_recent_edit {
3406 cx.emit(LspStoreEvent::SnippetEdit {
3407 buffer_id,
3408 edits: snippet_edits,
3409 most_recent_edit,
3410 });
3411 }
3412 }
3413
3414 local.edits_from_lsp(
3415 &buffer_to_edit,
3416 edits,
3417 language_server.server_id(),
3418 op.text_document.version,
3419 cx,
3420 )
3421 })
3422 .await?;
3423
3424 let transaction = buffer_to_edit.update(cx, |buffer, cx| {
3425 buffer.finalize_last_transaction();
3426 buffer.start_transaction();
3427 for (range, text) in edits {
3428 buffer.edit([(range, text)], None, cx);
3429 }
3430
3431 buffer.end_transaction(cx).and_then(|transaction_id| {
3432 if push_to_history {
3433 buffer.finalize_last_transaction();
3434 buffer.get_transaction(transaction_id).cloned()
3435 } else {
3436 buffer.forget_transaction(transaction_id)
3437 }
3438 })
3439 });
3440 if let Some(transaction) = transaction {
3441 project_transaction.0.insert(buffer_to_edit, transaction);
3442 }
3443 }
3444 }
3445 }
3446
3447 Ok(project_transaction)
3448 }
3449
3450 async fn on_lsp_workspace_edit(
3451 this: WeakEntity<LspStore>,
3452 params: lsp::ApplyWorkspaceEditParams,
3453 server_id: LanguageServerId,
3454 cx: &mut AsyncApp,
3455 ) -> Result<lsp::ApplyWorkspaceEditResponse> {
3456 let this = this.upgrade().context("project project closed")?;
3457 let language_server = this
3458 .read_with(cx, |this, _| this.language_server_for_id(server_id))
3459 .context("language server not found")?;
3460 let transaction = Self::deserialize_workspace_edit(
3461 this.clone(),
3462 params.edit,
3463 true,
3464 language_server.clone(),
3465 cx,
3466 )
3467 .await
3468 .log_err();
3469 this.update(cx, |this, cx| {
3470 if let Some(transaction) = transaction {
3471 cx.emit(LspStoreEvent::WorkspaceEditApplied(transaction.clone()));
3472
3473 this.as_local_mut()
3474 .unwrap()
3475 .last_workspace_edits_by_language_server
3476 .insert(server_id, transaction);
3477 }
3478 });
3479 Ok(lsp::ApplyWorkspaceEditResponse {
3480 applied: true,
3481 failed_change: None,
3482 failure_reason: None,
3483 })
3484 }
3485
3486 fn remove_worktree(
3487 &mut self,
3488 id_to_remove: WorktreeId,
3489 cx: &mut Context<LspStore>,
3490 ) -> Vec<LanguageServerId> {
3491 self.restricted_worktrees_tasks.remove(&id_to_remove);
3492 self.diagnostics.remove(&id_to_remove);
3493 self.prettier_store.update(cx, |prettier_store, cx| {
3494 prettier_store.remove_worktree(id_to_remove, cx);
3495 });
3496
3497 let mut servers_to_remove = BTreeSet::default();
3498 let mut servers_to_preserve = HashSet::default();
3499 for (seed, state) in &self.language_server_ids {
3500 if seed.worktree_id == id_to_remove {
3501 servers_to_remove.insert(state.id);
3502 } else {
3503 servers_to_preserve.insert(state.id);
3504 }
3505 }
3506 servers_to_remove.retain(|server_id| !servers_to_preserve.contains(server_id));
3507 self.language_server_ids
3508 .retain(|_, state| !servers_to_remove.contains(&state.id));
3509 for server_id_to_remove in &servers_to_remove {
3510 self.language_server_watched_paths
3511 .remove(server_id_to_remove);
3512 self.language_server_paths_watched_for_rename
3513 .remove(server_id_to_remove);
3514 self.last_workspace_edits_by_language_server
3515 .remove(server_id_to_remove);
3516 self.language_servers.remove(server_id_to_remove);
3517 self.buffer_pull_diagnostics_result_ids
3518 .remove(server_id_to_remove);
3519 self.workspace_pull_diagnostics_result_ids
3520 .remove(server_id_to_remove);
3521 for buffer_servers in self.buffers_opened_in_servers.values_mut() {
3522 buffer_servers.remove(server_id_to_remove);
3523 }
3524 cx.emit(LspStoreEvent::LanguageServerRemoved(*server_id_to_remove));
3525 }
3526 servers_to_remove.into_iter().collect()
3527 }
3528
3529 fn rebuild_watched_paths_inner<'a>(
3530 &'a self,
3531 language_server_id: LanguageServerId,
3532 watchers: impl Iterator<Item = &'a FileSystemWatcher>,
3533 cx: &mut Context<LspStore>,
3534 ) -> LanguageServerWatchedPathsBuilder {
3535 let worktrees = self
3536 .worktree_store
3537 .read(cx)
3538 .worktrees()
3539 .filter_map(|worktree| {
3540 self.language_servers_for_worktree(worktree.read(cx).id())
3541 .find(|server| server.server_id() == language_server_id)
3542 .map(|_| worktree)
3543 })
3544 .collect::<Vec<_>>();
3545
3546 let mut worktree_globs = HashMap::default();
3547 let mut abs_globs = HashMap::default();
3548 log::trace!(
3549 "Processing new watcher paths for language server with id {}",
3550 language_server_id
3551 );
3552
3553 for watcher in watchers {
3554 if let Some((worktree, literal_prefix, pattern)) =
3555 Self::worktree_and_path_for_file_watcher(&worktrees, watcher, cx)
3556 {
3557 worktree.update(cx, |worktree, _| {
3558 if let Some((tree, glob)) =
3559 worktree.as_local_mut().zip(Glob::new(&pattern).log_err())
3560 {
3561 tree.add_path_prefix_to_scan(literal_prefix);
3562 worktree_globs
3563 .entry(tree.id())
3564 .or_insert_with(GlobSetBuilder::new)
3565 .add(glob);
3566 }
3567 });
3568 } else {
3569 let (path, pattern) = match &watcher.glob_pattern {
3570 lsp::GlobPattern::String(s) => {
3571 let watcher_path = SanitizedPath::new(s);
3572 let path = glob_literal_prefix(watcher_path.as_path());
3573 let pattern = watcher_path
3574 .as_path()
3575 .strip_prefix(&path)
3576 .map(|p| p.to_string_lossy().into_owned())
3577 .unwrap_or_else(|e| {
3578 debug_panic!(
3579 "Failed to strip prefix for string pattern: {}, with prefix: {}, with error: {}",
3580 s,
3581 path.display(),
3582 e
3583 );
3584 watcher_path.as_path().to_string_lossy().into_owned()
3585 });
3586 (path, pattern)
3587 }
3588 lsp::GlobPattern::Relative(rp) => {
3589 let Ok(mut base_uri) = match &rp.base_uri {
3590 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3591 lsp::OneOf::Right(base_uri) => base_uri,
3592 }
3593 .to_file_path() else {
3594 continue;
3595 };
3596
3597 let path = glob_literal_prefix(Path::new(&rp.pattern));
3598 let pattern = Path::new(&rp.pattern)
3599 .strip_prefix(&path)
3600 .map(|p| p.to_string_lossy().into_owned())
3601 .unwrap_or_else(|e| {
3602 debug_panic!(
3603 "Failed to strip prefix for relative pattern: {}, with prefix: {}, with error: {}",
3604 rp.pattern,
3605 path.display(),
3606 e
3607 );
3608 rp.pattern.clone()
3609 });
3610 base_uri.push(path);
3611 (base_uri, pattern)
3612 }
3613 };
3614
3615 if let Some(glob) = Glob::new(&pattern).log_err() {
3616 if !path
3617 .components()
3618 .any(|c| matches!(c, path::Component::Normal(_)))
3619 {
3620 // For an unrooted glob like `**/Cargo.toml`, watch it within each worktree,
3621 // rather than adding a new watcher for `/`.
3622 for worktree in &worktrees {
3623 worktree_globs
3624 .entry(worktree.read(cx).id())
3625 .or_insert_with(GlobSetBuilder::new)
3626 .add(glob.clone());
3627 }
3628 } else {
3629 abs_globs
3630 .entry(path.into())
3631 .or_insert_with(GlobSetBuilder::new)
3632 .add(glob);
3633 }
3634 }
3635 }
3636 }
3637
3638 let mut watch_builder = LanguageServerWatchedPathsBuilder::default();
3639 for (worktree_id, builder) in worktree_globs {
3640 if let Ok(globset) = builder.build() {
3641 watch_builder.watch_worktree(worktree_id, globset);
3642 }
3643 }
3644 for (abs_path, builder) in abs_globs {
3645 if let Ok(globset) = builder.build() {
3646 watch_builder.watch_abs_path(abs_path, globset);
3647 }
3648 }
3649 watch_builder
3650 }
3651
3652 fn worktree_and_path_for_file_watcher(
3653 worktrees: &[Entity<Worktree>],
3654 watcher: &FileSystemWatcher,
3655 cx: &App,
3656 ) -> Option<(Entity<Worktree>, Arc<RelPath>, String)> {
3657 worktrees.iter().find_map(|worktree| {
3658 let tree = worktree.read(cx);
3659 let worktree_root_path = tree.abs_path();
3660 let path_style = tree.path_style();
3661 match &watcher.glob_pattern {
3662 lsp::GlobPattern::String(s) => {
3663 let watcher_path = SanitizedPath::new(s);
3664 let relative = watcher_path
3665 .as_path()
3666 .strip_prefix(&worktree_root_path)
3667 .ok()?;
3668 let literal_prefix = glob_literal_prefix(relative);
3669 Some((
3670 worktree.clone(),
3671 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3672 relative.to_string_lossy().into_owned(),
3673 ))
3674 }
3675 lsp::GlobPattern::Relative(rp) => {
3676 let base_uri = match &rp.base_uri {
3677 lsp::OneOf::Left(workspace_folder) => &workspace_folder.uri,
3678 lsp::OneOf::Right(base_uri) => base_uri,
3679 }
3680 .to_file_path()
3681 .ok()?;
3682 let relative = base_uri.strip_prefix(&worktree_root_path).ok()?;
3683 let mut literal_prefix = relative.to_owned();
3684 literal_prefix.push(glob_literal_prefix(Path::new(&rp.pattern)));
3685 Some((
3686 worktree.clone(),
3687 RelPath::new(&literal_prefix, path_style).ok()?.into_arc(),
3688 rp.pattern.clone(),
3689 ))
3690 }
3691 }
3692 })
3693 }
3694
3695 fn rebuild_watched_paths(
3696 &mut self,
3697 language_server_id: LanguageServerId,
3698 cx: &mut Context<LspStore>,
3699 ) {
3700 let Some(registrations) = self
3701 .language_server_dynamic_registrations
3702 .get(&language_server_id)
3703 else {
3704 return;
3705 };
3706
3707 let watch_builder = self.rebuild_watched_paths_inner(
3708 language_server_id,
3709 registrations.did_change_watched_files.values().flatten(),
3710 cx,
3711 );
3712 let watcher = watch_builder.build(self.fs.clone(), language_server_id, cx);
3713 self.language_server_watched_paths
3714 .insert(language_server_id, watcher);
3715
3716 cx.notify();
3717 }
3718
3719 fn on_lsp_did_change_watched_files(
3720 &mut self,
3721 language_server_id: LanguageServerId,
3722 registration_id: &str,
3723 params: DidChangeWatchedFilesRegistrationOptions,
3724 cx: &mut Context<LspStore>,
3725 ) {
3726 let registrations = self
3727 .language_server_dynamic_registrations
3728 .entry(language_server_id)
3729 .or_default();
3730
3731 registrations
3732 .did_change_watched_files
3733 .insert(registration_id.to_string(), params.watchers);
3734
3735 self.rebuild_watched_paths(language_server_id, cx);
3736 }
3737
3738 fn on_lsp_unregister_did_change_watched_files(
3739 &mut self,
3740 language_server_id: LanguageServerId,
3741 registration_id: &str,
3742 cx: &mut Context<LspStore>,
3743 ) {
3744 let registrations = self
3745 .language_server_dynamic_registrations
3746 .entry(language_server_id)
3747 .or_default();
3748
3749 if registrations
3750 .did_change_watched_files
3751 .remove(registration_id)
3752 .is_some()
3753 {
3754 log::info!(
3755 "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}",
3756 language_server_id,
3757 registration_id
3758 );
3759 } else {
3760 log::warn!(
3761 "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.",
3762 language_server_id,
3763 registration_id
3764 );
3765 }
3766
3767 self.rebuild_watched_paths(language_server_id, cx);
3768 }
3769
3770 async fn initialization_options_for_adapter(
3771 adapter: Arc<dyn LspAdapter>,
3772 delegate: &Arc<dyn LspAdapterDelegate>,
3773 ) -> Result<Option<serde_json::Value>> {
3774 let Some(mut initialization_config) =
3775 adapter.clone().initialization_options(delegate).await?
3776 else {
3777 return Ok(None);
3778 };
3779
3780 for other_adapter in delegate.registered_lsp_adapters() {
3781 if other_adapter.name() == adapter.name() {
3782 continue;
3783 }
3784 if let Ok(Some(target_config)) = other_adapter
3785 .clone()
3786 .additional_initialization_options(adapter.name(), delegate)
3787 .await
3788 {
3789 merge_json_value_into(target_config.clone(), &mut initialization_config);
3790 }
3791 }
3792
3793 Ok(Some(initialization_config))
3794 }
3795
3796 async fn workspace_configuration_for_adapter(
3797 adapter: Arc<dyn LspAdapter>,
3798 delegate: &Arc<dyn LspAdapterDelegate>,
3799 toolchain: Option<Toolchain>,
3800 requested_uri: Option<Uri>,
3801 cx: &mut AsyncApp,
3802 ) -> Result<serde_json::Value> {
3803 let mut workspace_config = adapter
3804 .clone()
3805 .workspace_configuration(delegate, toolchain, requested_uri, cx)
3806 .await?;
3807
3808 for other_adapter in delegate.registered_lsp_adapters() {
3809 if other_adapter.name() == adapter.name() {
3810 continue;
3811 }
3812 if let Ok(Some(target_config)) = other_adapter
3813 .clone()
3814 .additional_workspace_configuration(adapter.name(), delegate, cx)
3815 .await
3816 {
3817 merge_json_value_into(target_config.clone(), &mut workspace_config);
3818 }
3819 }
3820
3821 Ok(workspace_config)
3822 }
3823
3824 fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
3825 if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
3826 Some(server.clone())
3827 } else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
3828 Some(Arc::clone(server))
3829 } else {
3830 None
3831 }
3832 }
3833}
3834
3835fn notify_server_capabilities_updated(server: &LanguageServer, cx: &mut Context<LspStore>) {
3836 if let Some(capabilities) = serde_json::to_string(&server.capabilities()).ok() {
3837 cx.emit(LspStoreEvent::LanguageServerUpdate {
3838 language_server_id: server.server_id(),
3839 name: Some(server.name()),
3840 message: proto::update_language_server::Variant::MetadataUpdated(
3841 proto::ServerMetadataUpdated {
3842 capabilities: Some(capabilities),
3843 binary: Some(proto::LanguageServerBinaryInfo {
3844 path: server.binary().path.to_string_lossy().into_owned(),
3845 arguments: server
3846 .binary()
3847 .arguments
3848 .iter()
3849 .map(|arg| arg.to_string_lossy().into_owned())
3850 .collect(),
3851 }),
3852 configuration: serde_json::to_string(server.configuration()).ok(),
3853 workspace_folders: server
3854 .workspace_folders()
3855 .iter()
3856 .map(|uri| uri.to_string())
3857 .collect(),
3858 },
3859 ),
3860 });
3861 }
3862}
3863
3864#[derive(Debug)]
3865pub struct FormattableBuffer {
3866 handle: Entity<Buffer>,
3867 abs_path: Option<PathBuf>,
3868 env: Option<HashMap<String, String>>,
3869 ranges: Option<Vec<Range<Anchor>>>,
3870}
3871
3872pub struct RemoteLspStore {
3873 upstream_client: Option<AnyProtoClient>,
3874 upstream_project_id: u64,
3875}
3876
3877pub(crate) enum LspStoreMode {
3878 Local(LocalLspStore), // ssh host and collab host
3879 Remote(RemoteLspStore), // collab guest
3880}
3881
3882impl LspStoreMode {
3883 fn is_local(&self) -> bool {
3884 matches!(self, LspStoreMode::Local(_))
3885 }
3886}
3887
3888pub struct LspStore {
3889 mode: LspStoreMode,
3890 last_formatting_failure: Option<String>,
3891 downstream_client: Option<(AnyProtoClient, u64)>,
3892 nonce: u128,
3893 buffer_store: Entity<BufferStore>,
3894 worktree_store: Entity<WorktreeStore>,
3895 pub languages: Arc<LanguageRegistry>,
3896 pub language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
3897 active_entry: Option<ProjectEntryId>,
3898 _maintain_workspace_config: (Task<Result<()>>, watch::Sender<()>),
3899 _maintain_buffer_languages: Task<()>,
3900 diagnostic_summaries:
3901 HashMap<WorktreeId, HashMap<Arc<RelPath>, HashMap<LanguageServerId, DiagnosticSummary>>>,
3902 pub lsp_server_capabilities: HashMap<LanguageServerId, lsp::ServerCapabilities>,
3903 semantic_token_config: SemanticTokenConfig,
3904 lsp_data: HashMap<BufferId, BufferLspData>,
3905 next_hint_id: Arc<AtomicUsize>,
3906}
3907
3908#[derive(Debug)]
3909pub struct BufferLspData {
3910 buffer_version: Global,
3911 document_colors: Option<DocumentColorData>,
3912 code_lens: Option<CodeLensData>,
3913 semantic_tokens: Option<SemanticTokensData>,
3914 folding_ranges: Option<FoldingRangeData>,
3915 document_symbols: Option<DocumentSymbolsData>,
3916 inlay_hints: BufferInlayHints,
3917 lsp_requests: HashMap<LspKey, HashMap<LspRequestId, Task<()>>>,
3918 chunk_lsp_requests: HashMap<LspKey, HashMap<RowChunk, LspRequestId>>,
3919}
3920
3921#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3922struct LspKey {
3923 request_type: TypeId,
3924 server_queried: Option<LanguageServerId>,
3925}
3926
3927impl BufferLspData {
3928 fn new(buffer: &Entity<Buffer>, cx: &mut App) -> Self {
3929 Self {
3930 buffer_version: buffer.read(cx).version(),
3931 document_colors: None,
3932 code_lens: None,
3933 semantic_tokens: None,
3934 folding_ranges: None,
3935 document_symbols: None,
3936 inlay_hints: BufferInlayHints::new(buffer, cx),
3937 lsp_requests: HashMap::default(),
3938 chunk_lsp_requests: HashMap::default(),
3939 }
3940 }
3941
3942 fn remove_server_data(&mut self, for_server: LanguageServerId) {
3943 if let Some(document_colors) = &mut self.document_colors {
3944 document_colors.remove_server_data(for_server);
3945 }
3946
3947 if let Some(code_lens) = &mut self.code_lens {
3948 code_lens.remove_server_data(for_server);
3949 }
3950
3951 self.inlay_hints.remove_server_data(for_server);
3952
3953 if let Some(semantic_tokens) = &mut self.semantic_tokens {
3954 semantic_tokens.raw_tokens.servers.remove(&for_server);
3955 semantic_tokens
3956 .latest_invalidation_requests
3957 .remove(&for_server);
3958 }
3959
3960 if let Some(folding_ranges) = &mut self.folding_ranges {
3961 folding_ranges.ranges.remove(&for_server);
3962 }
3963
3964 if let Some(document_symbols) = &mut self.document_symbols {
3965 document_symbols.remove_server_data(for_server);
3966 }
3967 }
3968
3969 #[cfg(any(test, feature = "test-support"))]
3970 pub fn inlay_hints(&self) -> &BufferInlayHints {
3971 &self.inlay_hints
3972 }
3973}
3974
3975#[derive(Debug)]
3976pub enum LspStoreEvent {
3977 LanguageServerAdded(LanguageServerId, LanguageServerName, Option<WorktreeId>),
3978 LanguageServerRemoved(LanguageServerId),
3979 LanguageServerUpdate {
3980 language_server_id: LanguageServerId,
3981 name: Option<LanguageServerName>,
3982 message: proto::update_language_server::Variant,
3983 },
3984 LanguageServerLog(LanguageServerId, LanguageServerLogType, String),
3985 LanguageServerPrompt(LanguageServerPromptRequest),
3986 LanguageDetected {
3987 buffer: Entity<Buffer>,
3988 new_language: Option<Arc<Language>>,
3989 },
3990 Notification(String),
3991 RefreshInlayHints {
3992 server_id: LanguageServerId,
3993 request_id: Option<usize>,
3994 },
3995 RefreshSemanticTokens {
3996 server_id: LanguageServerId,
3997 request_id: Option<usize>,
3998 },
3999 RefreshCodeLens,
4000 DiagnosticsUpdated {
4001 server_id: LanguageServerId,
4002 paths: Vec<ProjectPath>,
4003 },
4004 DiskBasedDiagnosticsStarted {
4005 language_server_id: LanguageServerId,
4006 },
4007 DiskBasedDiagnosticsFinished {
4008 language_server_id: LanguageServerId,
4009 },
4010 SnippetEdit {
4011 buffer_id: BufferId,
4012 edits: Vec<(lsp::Range, Snippet)>,
4013 most_recent_edit: clock::Lamport,
4014 },
4015 WorkspaceEditApplied(ProjectTransaction),
4016}
4017
4018#[derive(Clone, Debug, Serialize)]
4019pub struct LanguageServerStatus {
4020 pub name: LanguageServerName,
4021 pub server_version: Option<SharedString>,
4022 pub pending_work: BTreeMap<ProgressToken, LanguageServerProgress>,
4023 pub has_pending_diagnostic_updates: bool,
4024 pub progress_tokens: HashSet<ProgressToken>,
4025 pub worktree: Option<WorktreeId>,
4026 pub binary: Option<LanguageServerBinary>,
4027 pub configuration: Option<Value>,
4028 pub workspace_folders: BTreeSet<Uri>,
4029 pub process_id: Option<u32>,
4030}
4031
4032#[derive(Clone, Debug)]
4033struct CoreSymbol {
4034 pub language_server_name: LanguageServerName,
4035 pub source_worktree_id: WorktreeId,
4036 pub source_language_server_id: LanguageServerId,
4037 pub path: SymbolLocation,
4038 pub name: String,
4039 pub kind: lsp::SymbolKind,
4040 pub range: Range<Unclipped<PointUtf16>>,
4041 pub container_name: Option<String>,
4042}
4043
4044#[derive(Clone, Debug, PartialEq, Eq)]
4045pub enum SymbolLocation {
4046 InProject(ProjectPath),
4047 OutsideProject {
4048 abs_path: Arc<Path>,
4049 signature: [u8; 32],
4050 },
4051}
4052
4053impl SymbolLocation {
4054 fn file_name(&self) -> Option<&str> {
4055 match self {
4056 Self::InProject(path) => path.path.file_name(),
4057 Self::OutsideProject { abs_path, .. } => abs_path.file_name()?.to_str(),
4058 }
4059 }
4060}
4061
4062impl LspStore {
4063 pub fn init(client: &AnyProtoClient) {
4064 client.add_entity_request_handler(Self::handle_lsp_query);
4065 client.add_entity_message_handler(Self::handle_lsp_query_response);
4066 client.add_entity_request_handler(Self::handle_restart_language_servers);
4067 client.add_entity_request_handler(Self::handle_stop_language_servers);
4068 client.add_entity_request_handler(Self::handle_cancel_language_server_work);
4069 client.add_entity_message_handler(Self::handle_start_language_server);
4070 client.add_entity_message_handler(Self::handle_update_language_server);
4071 client.add_entity_message_handler(Self::handle_language_server_log);
4072 client.add_entity_message_handler(Self::handle_update_diagnostic_summary);
4073 client.add_entity_request_handler(Self::handle_format_buffers);
4074 client.add_entity_request_handler(Self::handle_apply_code_action_kind);
4075 client.add_entity_request_handler(Self::handle_resolve_completion_documentation);
4076 client.add_entity_request_handler(Self::handle_apply_code_action);
4077 client.add_entity_request_handler(Self::handle_get_project_symbols);
4078 client.add_entity_request_handler(Self::handle_resolve_inlay_hint);
4079 client.add_entity_request_handler(Self::handle_get_color_presentation);
4080 client.add_entity_request_handler(Self::handle_open_buffer_for_symbol);
4081 client.add_entity_request_handler(Self::handle_refresh_inlay_hints);
4082 client.add_entity_request_handler(Self::handle_refresh_semantic_tokens);
4083 client.add_entity_request_handler(Self::handle_refresh_code_lens);
4084 client.add_entity_request_handler(Self::handle_on_type_formatting);
4085 client.add_entity_request_handler(Self::handle_apply_additional_edits_for_completion);
4086 client.add_entity_request_handler(Self::handle_register_buffer_with_language_servers);
4087 client.add_entity_request_handler(Self::handle_rename_project_entry);
4088 client.add_entity_request_handler(Self::handle_pull_workspace_diagnostics);
4089 client.add_entity_request_handler(Self::handle_lsp_get_completions);
4090 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
4091 client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
4092 client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
4093 client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
4094 client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
4095
4096 client.add_entity_request_handler(Self::handle_lsp_ext_cancel_flycheck);
4097 client.add_entity_request_handler(Self::handle_lsp_ext_run_flycheck);
4098 client.add_entity_request_handler(Self::handle_lsp_ext_clear_flycheck);
4099 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
4100 client.add_entity_request_handler(Self::handle_lsp_command::<lsp_ext_command::OpenDocs>);
4101 client.add_entity_request_handler(
4102 Self::handle_lsp_command::<lsp_ext_command::GoToParentModule>,
4103 );
4104 client.add_entity_request_handler(
4105 Self::handle_lsp_command::<lsp_ext_command::GetLspRunnables>,
4106 );
4107 client.add_entity_request_handler(
4108 Self::handle_lsp_command::<lsp_ext_command::SwitchSourceHeader>,
4109 );
4110 }
4111
4112 pub fn as_remote(&self) -> Option<&RemoteLspStore> {
4113 match &self.mode {
4114 LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
4115 _ => None,
4116 }
4117 }
4118
4119 pub fn as_local(&self) -> Option<&LocalLspStore> {
4120 match &self.mode {
4121 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4122 _ => None,
4123 }
4124 }
4125
4126 pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
4127 match &mut self.mode {
4128 LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
4129 _ => None,
4130 }
4131 }
4132
4133 pub fn upstream_client(&self) -> Option<(AnyProtoClient, u64)> {
4134 match &self.mode {
4135 LspStoreMode::Remote(RemoteLspStore {
4136 upstream_client: Some(upstream_client),
4137 upstream_project_id,
4138 ..
4139 }) => Some((upstream_client.clone(), *upstream_project_id)),
4140
4141 LspStoreMode::Remote(RemoteLspStore {
4142 upstream_client: None,
4143 ..
4144 }) => None,
4145 LspStoreMode::Local(_) => None,
4146 }
4147 }
4148
4149 pub fn new_local(
4150 buffer_store: Entity<BufferStore>,
4151 worktree_store: Entity<WorktreeStore>,
4152 prettier_store: Entity<PrettierStore>,
4153 toolchain_store: Entity<LocalToolchainStore>,
4154 environment: Entity<ProjectEnvironment>,
4155 manifest_tree: Entity<ManifestTree>,
4156 languages: Arc<LanguageRegistry>,
4157 http_client: Arc<dyn HttpClient>,
4158 fs: Arc<dyn Fs>,
4159 cx: &mut Context<Self>,
4160 ) -> Self {
4161 let yarn = YarnPathStore::new(fs.clone(), cx);
4162 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4163 .detach();
4164 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4165 .detach();
4166 cx.subscribe(&prettier_store, Self::on_prettier_store_event)
4167 .detach();
4168 cx.subscribe(&toolchain_store, Self::on_toolchain_store_event)
4169 .detach();
4170 cx.observe_global::<SettingsStore>(Self::on_settings_changed)
4171 .detach();
4172 subscribe_to_binary_statuses(&languages, cx).detach();
4173
4174 let _maintain_workspace_config = {
4175 let (sender, receiver) = watch::channel();
4176 (Self::maintain_workspace_config(receiver, cx), sender)
4177 };
4178
4179 Self {
4180 mode: LspStoreMode::Local(LocalLspStore {
4181 weak: cx.weak_entity(),
4182 worktree_store: worktree_store.clone(),
4183
4184 supplementary_language_servers: Default::default(),
4185 languages: languages.clone(),
4186 language_server_ids: Default::default(),
4187 language_servers: Default::default(),
4188 last_workspace_edits_by_language_server: Default::default(),
4189 language_server_watched_paths: Default::default(),
4190 language_server_paths_watched_for_rename: Default::default(),
4191 language_server_dynamic_registrations: Default::default(),
4192 buffers_being_formatted: Default::default(),
4193 buffers_to_refresh_hash_set: HashSet::default(),
4194 buffers_to_refresh_queue: VecDeque::new(),
4195 _background_diagnostics_worker: Task::ready(()).shared(),
4196 buffer_snapshots: Default::default(),
4197 prettier_store,
4198 environment,
4199 http_client,
4200 fs,
4201 yarn,
4202 next_diagnostic_group_id: Default::default(),
4203 diagnostics: Default::default(),
4204 _subscription: cx.on_app_quit(|this, _| {
4205 this.as_local_mut()
4206 .unwrap()
4207 .shutdown_language_servers_on_quit()
4208 }),
4209 lsp_tree: LanguageServerTree::new(
4210 manifest_tree,
4211 languages.clone(),
4212 toolchain_store.clone(),
4213 ),
4214 toolchain_store,
4215 registered_buffers: HashMap::default(),
4216 buffers_opened_in_servers: HashMap::default(),
4217 buffer_pull_diagnostics_result_ids: HashMap::default(),
4218 workspace_pull_diagnostics_result_ids: HashMap::default(),
4219 restricted_worktrees_tasks: HashMap::default(),
4220 watched_manifest_filenames: ManifestProvidersStore::global(cx)
4221 .manifest_file_names(),
4222 }),
4223 last_formatting_failure: None,
4224 downstream_client: None,
4225 buffer_store,
4226 worktree_store,
4227 languages: languages.clone(),
4228 language_server_statuses: Default::default(),
4229 nonce: StdRng::from_os_rng().random(),
4230 diagnostic_summaries: HashMap::default(),
4231 lsp_server_capabilities: HashMap::default(),
4232 semantic_token_config: SemanticTokenConfig::new(cx),
4233 lsp_data: HashMap::default(),
4234 next_hint_id: Arc::default(),
4235 active_entry: None,
4236 _maintain_workspace_config,
4237 _maintain_buffer_languages: Self::maintain_buffer_languages(languages, cx),
4238 }
4239 }
4240
4241 fn send_lsp_proto_request<R: LspCommand>(
4242 &self,
4243 buffer: Entity<Buffer>,
4244 client: AnyProtoClient,
4245 upstream_project_id: u64,
4246 request: R,
4247 cx: &mut Context<LspStore>,
4248 ) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
4249 if !self.is_capable_for_proto_request(&buffer, &request, cx) {
4250 return Task::ready(Ok(R::Response::default()));
4251 }
4252 let message = request.to_proto(upstream_project_id, buffer.read(cx));
4253 cx.spawn(async move |this, cx| {
4254 let response = client.request(message).await?;
4255 let this = this.upgrade().context("project dropped")?;
4256 request
4257 .response_from_proto(response, this, buffer, cx.clone())
4258 .await
4259 })
4260 }
4261
4262 pub(super) fn new_remote(
4263 buffer_store: Entity<BufferStore>,
4264 worktree_store: Entity<WorktreeStore>,
4265 languages: Arc<LanguageRegistry>,
4266 upstream_client: AnyProtoClient,
4267 project_id: u64,
4268 cx: &mut Context<Self>,
4269 ) -> Self {
4270 cx.subscribe(&buffer_store, Self::on_buffer_store_event)
4271 .detach();
4272 cx.subscribe(&worktree_store, Self::on_worktree_store_event)
4273 .detach();
4274 subscribe_to_binary_statuses(&languages, cx).detach();
4275 let _maintain_workspace_config = {
4276 let (sender, receiver) = watch::channel();
4277 (Self::maintain_workspace_config(receiver, cx), sender)
4278 };
4279 Self {
4280 mode: LspStoreMode::Remote(RemoteLspStore {
4281 upstream_client: Some(upstream_client),
4282 upstream_project_id: project_id,
4283 }),
4284 downstream_client: None,
4285 last_formatting_failure: None,
4286 buffer_store,
4287 worktree_store,
4288 languages: languages.clone(),
4289 language_server_statuses: Default::default(),
4290 nonce: StdRng::from_os_rng().random(),
4291 diagnostic_summaries: HashMap::default(),
4292 lsp_server_capabilities: HashMap::default(),
4293 semantic_token_config: SemanticTokenConfig::new(cx),
4294 next_hint_id: Arc::default(),
4295 lsp_data: HashMap::default(),
4296 active_entry: None,
4297
4298 _maintain_workspace_config,
4299 _maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
4300 }
4301 }
4302
4303 fn on_buffer_store_event(
4304 &mut self,
4305 _: Entity<BufferStore>,
4306 event: &BufferStoreEvent,
4307 cx: &mut Context<Self>,
4308 ) {
4309 match event {
4310 BufferStoreEvent::BufferAdded(buffer) => {
4311 self.on_buffer_added(buffer, cx).log_err();
4312 }
4313 BufferStoreEvent::BufferChangedFilePath { buffer, old_file } => {
4314 let buffer_id = buffer.read(cx).remote_id();
4315 if let Some(local) = self.as_local_mut()
4316 && let Some(old_file) = File::from_dyn(old_file.as_ref())
4317 {
4318 local.reset_buffer(buffer, old_file, cx);
4319
4320 if local.registered_buffers.contains_key(&buffer_id) {
4321 local.unregister_old_buffer_from_language_servers(buffer, old_file, cx);
4322 }
4323 }
4324
4325 self.detect_language_for_buffer(buffer, cx);
4326 if let Some(local) = self.as_local_mut() {
4327 local.initialize_buffer(buffer, cx);
4328 if local.registered_buffers.contains_key(&buffer_id) {
4329 local.register_buffer_with_language_servers(buffer, HashSet::default(), cx);
4330 }
4331 }
4332 }
4333 _ => {}
4334 }
4335 }
4336
4337 fn on_worktree_store_event(
4338 &mut self,
4339 _: Entity<WorktreeStore>,
4340 event: &WorktreeStoreEvent,
4341 cx: &mut Context<Self>,
4342 ) {
4343 match event {
4344 WorktreeStoreEvent::WorktreeAdded(worktree) => {
4345 if !worktree.read(cx).is_local() {
4346 return;
4347 }
4348 cx.subscribe(worktree, |this, worktree, event, cx| match event {
4349 worktree::Event::UpdatedEntries(changes) => {
4350 this.update_local_worktree_language_servers(&worktree, changes, cx);
4351 }
4352 worktree::Event::UpdatedGitRepositories(_)
4353 | worktree::Event::DeletedEntry(_) => {}
4354 })
4355 .detach()
4356 }
4357 WorktreeStoreEvent::WorktreeRemoved(_, id) => self.remove_worktree(*id, cx),
4358 WorktreeStoreEvent::WorktreeUpdateSent(worktree) => {
4359 worktree.update(cx, |worktree, _cx| self.send_diagnostic_summaries(worktree));
4360 }
4361 WorktreeStoreEvent::WorktreeReleased(..)
4362 | WorktreeStoreEvent::WorktreeOrderChanged
4363 | WorktreeStoreEvent::WorktreeUpdatedEntries(..)
4364 | WorktreeStoreEvent::WorktreeUpdatedGitRepositories(..)
4365 | WorktreeStoreEvent::WorktreeDeletedEntry(..) => {}
4366 }
4367 }
4368
4369 fn on_prettier_store_event(
4370 &mut self,
4371 _: Entity<PrettierStore>,
4372 event: &PrettierStoreEvent,
4373 cx: &mut Context<Self>,
4374 ) {
4375 match event {
4376 PrettierStoreEvent::LanguageServerRemoved(prettier_server_id) => {
4377 self.unregister_supplementary_language_server(*prettier_server_id, cx);
4378 }
4379 PrettierStoreEvent::LanguageServerAdded {
4380 new_server_id,
4381 name,
4382 prettier_server,
4383 } => {
4384 self.register_supplementary_language_server(
4385 *new_server_id,
4386 name.clone(),
4387 prettier_server.clone(),
4388 cx,
4389 );
4390 }
4391 }
4392 }
4393
4394 fn on_toolchain_store_event(
4395 &mut self,
4396 _: Entity<LocalToolchainStore>,
4397 event: &ToolchainStoreEvent,
4398 _: &mut Context<Self>,
4399 ) {
4400 if let ToolchainStoreEvent::ToolchainActivated = event {
4401 self.request_workspace_config_refresh()
4402 }
4403 }
4404
4405 fn request_workspace_config_refresh(&mut self) {
4406 *self._maintain_workspace_config.1.borrow_mut() = ();
4407 }
4408
4409 pub fn prettier_store(&self) -> Option<Entity<PrettierStore>> {
4410 self.as_local().map(|local| local.prettier_store.clone())
4411 }
4412
4413 fn on_buffer_event(
4414 &mut self,
4415 buffer: Entity<Buffer>,
4416 event: &language::BufferEvent,
4417 cx: &mut Context<Self>,
4418 ) {
4419 match event {
4420 language::BufferEvent::Edited => {
4421 self.on_buffer_edited(buffer, cx);
4422 }
4423
4424 language::BufferEvent::Saved => {
4425 self.on_buffer_saved(buffer, cx);
4426 }
4427
4428 _ => {}
4429 }
4430 }
4431
4432 fn on_buffer_added(&mut self, buffer: &Entity<Buffer>, cx: &mut Context<Self>) -> Result<()> {
4433 buffer
4434 .read(cx)
4435 .set_language_registry(self.languages.clone());
4436
4437 cx.subscribe(buffer, |this, buffer, event, cx| {
4438 this.on_buffer_event(buffer, event, cx);
4439 })
4440 .detach();
4441
4442 self.detect_language_for_buffer(buffer, cx);
4443 if let Some(local) = self.as_local_mut() {
4444 local.initialize_buffer(buffer, cx);
4445 }
4446
4447 Ok(())
4448 }
4449
4450 pub fn refresh_background_diagnostics_for_buffers(
4451 &mut self,
4452 buffers: HashSet<BufferId>,
4453 cx: &mut Context<Self>,
4454 ) -> Shared<Task<()>> {
4455 let Some(local) = self.as_local_mut() else {
4456 return Task::ready(()).shared();
4457 };
4458 for buffer in buffers {
4459 if local.buffers_to_refresh_hash_set.insert(buffer) {
4460 local.buffers_to_refresh_queue.push_back(buffer);
4461 if local.buffers_to_refresh_queue.len() == 1 {
4462 local._background_diagnostics_worker =
4463 Self::background_diagnostics_worker(cx).shared();
4464 }
4465 }
4466 }
4467
4468 local._background_diagnostics_worker.clone()
4469 }
4470
4471 fn refresh_next_buffer(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
4472 let buffer_store = self.buffer_store.clone();
4473 let local = self.as_local_mut()?;
4474 while let Some(buffer_id) = local.buffers_to_refresh_queue.pop_front() {
4475 local.buffers_to_refresh_hash_set.remove(&buffer_id);
4476 if let Some(buffer) = buffer_store.read(cx).get(buffer_id) {
4477 return Some(self.pull_diagnostics_for_buffer(buffer, cx));
4478 }
4479 }
4480 None
4481 }
4482
4483 fn background_diagnostics_worker(cx: &mut Context<Self>) -> Task<()> {
4484 cx.spawn(async move |this, cx| {
4485 while let Ok(Some(task)) = this.update(cx, |this, cx| this.refresh_next_buffer(cx)) {
4486 task.await.log_err();
4487 }
4488 })
4489 }
4490
4491 pub(crate) fn register_buffer_with_language_servers(
4492 &mut self,
4493 buffer: &Entity<Buffer>,
4494 only_register_servers: HashSet<LanguageServerSelector>,
4495 ignore_refcounts: bool,
4496 cx: &mut Context<Self>,
4497 ) -> OpenLspBufferHandle {
4498 let buffer_id = buffer.read(cx).remote_id();
4499 let handle = OpenLspBufferHandle(cx.new(|_| OpenLspBuffer(buffer.clone())));
4500 if let Some(local) = self.as_local_mut() {
4501 let refcount = local.registered_buffers.entry(buffer_id).or_insert(0);
4502 if !ignore_refcounts {
4503 *refcount += 1;
4504 }
4505
4506 // We run early exits on non-existing buffers AFTER we mark the buffer as registered in order to handle buffer saving.
4507 // 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
4508 // 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
4509 // servers in practice (we don't support non-file URI schemes in our LSP impl).
4510 let Some(file) = File::from_dyn(buffer.read(cx).file()) else {
4511 return handle;
4512 };
4513 if !file.is_local() {
4514 return handle;
4515 }
4516
4517 if ignore_refcounts || *refcount == 1 {
4518 local.register_buffer_with_language_servers(buffer, only_register_servers, cx);
4519 }
4520 if !ignore_refcounts {
4521 cx.observe_release(&handle.0, move |lsp_store, buffer, cx| {
4522 let refcount = {
4523 let local = lsp_store.as_local_mut().unwrap();
4524 let Some(refcount) = local.registered_buffers.get_mut(&buffer_id) else {
4525 debug_panic!("bad refcounting");
4526 return;
4527 };
4528
4529 *refcount -= 1;
4530 *refcount
4531 };
4532 if refcount == 0 {
4533 lsp_store.lsp_data.remove(&buffer_id);
4534 let local = lsp_store.as_local_mut().unwrap();
4535 local.registered_buffers.remove(&buffer_id);
4536
4537 local.buffers_opened_in_servers.remove(&buffer_id);
4538 if let Some(file) = File::from_dyn(buffer.0.read(cx).file()).cloned() {
4539 local.unregister_old_buffer_from_language_servers(&buffer.0, &file, cx);
4540
4541 let buffer_abs_path = file.abs_path(cx);
4542 for (_, buffer_pull_diagnostics_result_ids) in
4543 &mut local.buffer_pull_diagnostics_result_ids
4544 {
4545 buffer_pull_diagnostics_result_ids.retain(
4546 |_, buffer_result_ids| {
4547 buffer_result_ids.remove(&buffer_abs_path);
4548 !buffer_result_ids.is_empty()
4549 },
4550 );
4551 }
4552
4553 let diagnostic_updates = local
4554 .language_servers
4555 .keys()
4556 .cloned()
4557 .map(|server_id| DocumentDiagnosticsUpdate {
4558 diagnostics: DocumentDiagnostics {
4559 document_abs_path: buffer_abs_path.clone(),
4560 version: None,
4561 diagnostics: Vec::new(),
4562 },
4563 result_id: None,
4564 registration_id: None,
4565 server_id,
4566 disk_based_sources: Cow::Borrowed(&[]),
4567 })
4568 .collect::<Vec<_>>();
4569
4570 lsp_store
4571 .merge_diagnostic_entries(
4572 diagnostic_updates,
4573 |_, diagnostic, _| {
4574 diagnostic.source_kind != DiagnosticSourceKind::Pulled
4575 },
4576 cx,
4577 )
4578 .context("Clearing diagnostics for the closed buffer")
4579 .log_err();
4580 }
4581 }
4582 })
4583 .detach();
4584 }
4585 } else if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4586 let buffer_id = buffer.read(cx).remote_id().to_proto();
4587 cx.background_spawn(async move {
4588 upstream_client
4589 .request(proto::RegisterBufferWithLanguageServers {
4590 project_id: upstream_project_id,
4591 buffer_id,
4592 only_servers: only_register_servers
4593 .into_iter()
4594 .map(|selector| {
4595 let selector = match selector {
4596 LanguageServerSelector::Id(language_server_id) => {
4597 proto::language_server_selector::Selector::ServerId(
4598 language_server_id.to_proto(),
4599 )
4600 }
4601 LanguageServerSelector::Name(language_server_name) => {
4602 proto::language_server_selector::Selector::Name(
4603 language_server_name.to_string(),
4604 )
4605 }
4606 };
4607 proto::LanguageServerSelector {
4608 selector: Some(selector),
4609 }
4610 })
4611 .collect(),
4612 })
4613 .await
4614 })
4615 .detach();
4616 } else {
4617 // Our remote connection got closed
4618 }
4619 handle
4620 }
4621
4622 fn maintain_buffer_languages(
4623 languages: Arc<LanguageRegistry>,
4624 cx: &mut Context<Self>,
4625 ) -> Task<()> {
4626 let mut subscription = languages.subscribe();
4627 let mut prev_reload_count = languages.reload_count();
4628 cx.spawn(async move |this, cx| {
4629 while let Some(()) = subscription.next().await {
4630 if let Some(this) = this.upgrade() {
4631 // If the language registry has been reloaded, then remove and
4632 // re-assign the languages on all open buffers.
4633 let reload_count = languages.reload_count();
4634 if reload_count > prev_reload_count {
4635 prev_reload_count = reload_count;
4636 this.update(cx, |this, cx| {
4637 this.buffer_store.clone().update(cx, |buffer_store, cx| {
4638 for buffer in buffer_store.buffers() {
4639 if let Some(f) = File::from_dyn(buffer.read(cx).file()).cloned()
4640 {
4641 buffer.update(cx, |buffer, cx| {
4642 buffer.set_language_async(None, cx)
4643 });
4644 if let Some(local) = this.as_local_mut() {
4645 local.reset_buffer(&buffer, &f, cx);
4646
4647 if local
4648 .registered_buffers
4649 .contains_key(&buffer.read(cx).remote_id())
4650 && let Some(file_url) =
4651 file_path_to_lsp_url(&f.abs_path(cx)).log_err()
4652 {
4653 local.unregister_buffer_from_language_servers(
4654 &buffer, &file_url, cx,
4655 );
4656 }
4657 }
4658 }
4659 }
4660 });
4661 });
4662 }
4663
4664 this.update(cx, |this, cx| {
4665 let mut plain_text_buffers = Vec::new();
4666 let mut buffers_with_unknown_injections = Vec::new();
4667 for handle in this.buffer_store.read(cx).buffers() {
4668 let buffer = handle.read(cx);
4669 if buffer.language().is_none()
4670 || buffer.language() == Some(&*language::PLAIN_TEXT)
4671 {
4672 plain_text_buffers.push(handle);
4673 } else if buffer.contains_unknown_injections() {
4674 buffers_with_unknown_injections.push(handle);
4675 }
4676 }
4677
4678 // Deprioritize the invisible worktrees so main worktrees' language servers can be started first,
4679 // and reused later in the invisible worktrees.
4680 plain_text_buffers.sort_by_key(|buffer| {
4681 Reverse(
4682 File::from_dyn(buffer.read(cx).file())
4683 .map(|file| file.worktree.read(cx).is_visible()),
4684 )
4685 });
4686
4687 for buffer in plain_text_buffers {
4688 this.detect_language_for_buffer(&buffer, cx);
4689 if let Some(local) = this.as_local_mut() {
4690 local.initialize_buffer(&buffer, cx);
4691 if local
4692 .registered_buffers
4693 .contains_key(&buffer.read(cx).remote_id())
4694 {
4695 local.register_buffer_with_language_servers(
4696 &buffer,
4697 HashSet::default(),
4698 cx,
4699 );
4700 }
4701 }
4702 }
4703
4704 for buffer in buffers_with_unknown_injections {
4705 buffer.update(cx, |buffer, cx| buffer.reparse(cx, false));
4706 }
4707 });
4708 }
4709 }
4710 })
4711 }
4712
4713 fn detect_language_for_buffer(
4714 &mut self,
4715 buffer_handle: &Entity<Buffer>,
4716 cx: &mut Context<Self>,
4717 ) -> Option<language::AvailableLanguage> {
4718 // If the buffer has a language, set it and start the language server if we haven't already.
4719 let buffer = buffer_handle.read(cx);
4720 let file = buffer.file()?;
4721
4722 let content = buffer.as_rope();
4723 let available_language = self.languages.language_for_file(file, Some(content), cx);
4724 if let Some(available_language) = &available_language {
4725 if let Some(Ok(Ok(new_language))) = self
4726 .languages
4727 .load_language(available_language)
4728 .now_or_never()
4729 {
4730 self.set_language_for_buffer(buffer_handle, new_language, cx);
4731 }
4732 } else {
4733 cx.emit(LspStoreEvent::LanguageDetected {
4734 buffer: buffer_handle.clone(),
4735 new_language: None,
4736 });
4737 }
4738
4739 available_language
4740 }
4741
4742 pub(crate) fn set_language_for_buffer(
4743 &mut self,
4744 buffer_entity: &Entity<Buffer>,
4745 new_language: Arc<Language>,
4746 cx: &mut Context<Self>,
4747 ) {
4748 let buffer = buffer_entity.read(cx);
4749 let buffer_file = buffer.file().cloned();
4750 let buffer_id = buffer.remote_id();
4751 if let Some(local_store) = self.as_local_mut()
4752 && local_store.registered_buffers.contains_key(&buffer_id)
4753 && let Some(abs_path) =
4754 File::from_dyn(buffer_file.as_ref()).map(|file| file.abs_path(cx))
4755 && let Some(file_url) = file_path_to_lsp_url(&abs_path).log_err()
4756 {
4757 local_store.unregister_buffer_from_language_servers(buffer_entity, &file_url, cx);
4758 }
4759 buffer_entity.update(cx, |buffer, cx| {
4760 if buffer
4761 .language()
4762 .is_none_or(|old_language| !Arc::ptr_eq(old_language, &new_language))
4763 {
4764 buffer.set_language_async(Some(new_language.clone()), cx);
4765 }
4766 });
4767
4768 let settings =
4769 language_settings(Some(new_language.name()), buffer_file.as_ref(), cx).into_owned();
4770 let buffer_file = File::from_dyn(buffer_file.as_ref());
4771
4772 let worktree_id = if let Some(file) = buffer_file {
4773 let worktree = file.worktree.clone();
4774
4775 if let Some(local) = self.as_local_mut()
4776 && local.registered_buffers.contains_key(&buffer_id)
4777 {
4778 local.register_buffer_with_language_servers(buffer_entity, HashSet::default(), cx);
4779 }
4780 Some(worktree.read(cx).id())
4781 } else {
4782 None
4783 };
4784
4785 if settings.prettier.allowed
4786 && let Some(prettier_plugins) = prettier_store::prettier_plugins_for_language(&settings)
4787 {
4788 let prettier_store = self.as_local().map(|s| s.prettier_store.clone());
4789 if let Some(prettier_store) = prettier_store {
4790 prettier_store.update(cx, |prettier_store, cx| {
4791 prettier_store.install_default_prettier(
4792 worktree_id,
4793 prettier_plugins.iter().map(|s| Arc::from(s.as_str())),
4794 cx,
4795 )
4796 })
4797 }
4798 }
4799
4800 cx.emit(LspStoreEvent::LanguageDetected {
4801 buffer: buffer_entity.clone(),
4802 new_language: Some(new_language),
4803 })
4804 }
4805
4806 pub fn buffer_store(&self) -> Entity<BufferStore> {
4807 self.buffer_store.clone()
4808 }
4809
4810 pub fn set_active_entry(&mut self, active_entry: Option<ProjectEntryId>) {
4811 self.active_entry = active_entry;
4812 }
4813
4814 pub(crate) fn send_diagnostic_summaries(&self, worktree: &mut Worktree) {
4815 if let Some((client, downstream_project_id)) = self.downstream_client.clone()
4816 && let Some(diangostic_summaries) = self.diagnostic_summaries.get(&worktree.id())
4817 {
4818 let mut summaries = diangostic_summaries.iter().flat_map(|(path, summaries)| {
4819 summaries
4820 .iter()
4821 .map(|(server_id, summary)| summary.to_proto(*server_id, path.as_ref()))
4822 });
4823 if let Some(summary) = summaries.next() {
4824 client
4825 .send(proto::UpdateDiagnosticSummary {
4826 project_id: downstream_project_id,
4827 worktree_id: worktree.id().to_proto(),
4828 summary: Some(summary),
4829 more_summaries: summaries.collect(),
4830 })
4831 .log_err();
4832 }
4833 }
4834 }
4835
4836 fn is_capable_for_proto_request<R>(
4837 &self,
4838 buffer: &Entity<Buffer>,
4839 request: &R,
4840 cx: &App,
4841 ) -> bool
4842 where
4843 R: LspCommand,
4844 {
4845 self.check_if_capable_for_proto_request(
4846 buffer,
4847 |capabilities| {
4848 request.check_capabilities(AdapterServerCapabilities {
4849 server_capabilities: capabilities.clone(),
4850 code_action_kinds: None,
4851 })
4852 },
4853 cx,
4854 )
4855 }
4856
4857 fn check_if_capable_for_proto_request<F>(
4858 &self,
4859 buffer: &Entity<Buffer>,
4860 check: F,
4861 cx: &App,
4862 ) -> bool
4863 where
4864 F: FnMut(&lsp::ServerCapabilities) -> bool,
4865 {
4866 let Some(language) = buffer.read(cx).language().cloned() else {
4867 return false;
4868 };
4869 let registered_language_servers = self
4870 .languages
4871 .lsp_adapters(&language.name())
4872 .into_iter()
4873 .map(|lsp_adapter| lsp_adapter.name())
4874 .collect::<HashSet<_>>();
4875 self.language_server_statuses
4876 .iter()
4877 .filter_map(|(server_id, server_status)| {
4878 // Include servers that are either registered for this language OR
4879 // available to be loaded (for SSH remote mode where adapters like
4880 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4881 // but only loaded on the server side)
4882 let is_relevant = registered_language_servers.contains(&server_status.name)
4883 || self.languages.is_lsp_adapter_available(&server_status.name);
4884 is_relevant.then_some(server_id)
4885 })
4886 .filter_map(|server_id| self.lsp_server_capabilities.get(server_id))
4887 .any(check)
4888 }
4889
4890 fn all_capable_for_proto_request<F>(
4891 &self,
4892 buffer: &Entity<Buffer>,
4893 mut check: F,
4894 cx: &App,
4895 ) -> Vec<lsp::LanguageServerId>
4896 where
4897 F: FnMut(&lsp::LanguageServerName, &lsp::ServerCapabilities) -> bool,
4898 {
4899 let Some(language) = buffer.read(cx).language().cloned() else {
4900 return Vec::default();
4901 };
4902 let registered_language_servers = self
4903 .languages
4904 .lsp_adapters(&language.name())
4905 .into_iter()
4906 .map(|lsp_adapter| lsp_adapter.name())
4907 .collect::<HashSet<_>>();
4908 self.language_server_statuses
4909 .iter()
4910 .filter_map(|(server_id, server_status)| {
4911 // Include servers that are either registered for this language OR
4912 // available to be loaded (for SSH remote mode where adapters like
4913 // ty/pylsp/pyright are registered via register_available_lsp_adapter
4914 // but only loaded on the server side)
4915 let is_relevant = registered_language_servers.contains(&server_status.name)
4916 || self.languages.is_lsp_adapter_available(&server_status.name);
4917 is_relevant.then_some((server_id, &server_status.name))
4918 })
4919 .filter_map(|(server_id, server_name)| {
4920 self.lsp_server_capabilities
4921 .get(server_id)
4922 .map(|c| (server_id, server_name, c))
4923 })
4924 .filter(|(_, server_name, capabilities)| check(server_name, capabilities))
4925 .map(|(server_id, _, _)| *server_id)
4926 .collect()
4927 }
4928
4929 pub fn request_lsp<R>(
4930 &mut self,
4931 buffer: Entity<Buffer>,
4932 server: LanguageServerToQuery,
4933 request: R,
4934 cx: &mut Context<Self>,
4935 ) -> Task<Result<R::Response>>
4936 where
4937 R: LspCommand,
4938 <R::LspRequest as lsp::request::Request>::Result: Send,
4939 <R::LspRequest as lsp::request::Request>::Params: Send,
4940 {
4941 if let Some((upstream_client, upstream_project_id)) = self.upstream_client() {
4942 return self.send_lsp_proto_request(
4943 buffer,
4944 upstream_client,
4945 upstream_project_id,
4946 request,
4947 cx,
4948 );
4949 }
4950
4951 let Some(language_server) = buffer.update(cx, |buffer, cx| match server {
4952 LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
4953 local
4954 .language_servers_for_buffer(buffer, cx)
4955 .find(|(_, server)| {
4956 request.check_capabilities(server.adapter_server_capabilities())
4957 })
4958 .map(|(_, server)| server.clone())
4959 }),
4960 LanguageServerToQuery::Other(id) => self
4961 .language_server_for_local_buffer(buffer, id, cx)
4962 .and_then(|(_, server)| {
4963 request
4964 .check_capabilities(server.adapter_server_capabilities())
4965 .then(|| Arc::clone(server))
4966 }),
4967 }) else {
4968 return Task::ready(Ok(Default::default()));
4969 };
4970
4971 let file = File::from_dyn(buffer.read(cx).file()).and_then(File::as_local);
4972
4973 let Some(file) = file else {
4974 return Task::ready(Ok(Default::default()));
4975 };
4976
4977 let lsp_params = match request.to_lsp_params_or_response(
4978 &file.abs_path(cx),
4979 buffer.read(cx),
4980 &language_server,
4981 cx,
4982 ) {
4983 Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
4984 Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
4985 Err(err) => {
4986 let message = format!(
4987 "{} via {} failed: {}",
4988 request.display_name(),
4989 language_server.name(),
4990 err
4991 );
4992 // rust-analyzer likes to error with this when its still loading up
4993 if !message.ends_with("content modified") {
4994 log::warn!("{message}");
4995 }
4996 return Task::ready(Err(anyhow!(message)));
4997 }
4998 };
4999
5000 let status = request.status();
5001 if !request.check_capabilities(language_server.adapter_server_capabilities()) {
5002 return Task::ready(Ok(Default::default()));
5003 }
5004
5005 let request_timeout = ProjectSettings::get_global(cx)
5006 .global_lsp_settings
5007 .get_request_timeout();
5008
5009 cx.spawn(async move |this, cx| {
5010 let lsp_request = language_server.request::<R::LspRequest>(lsp_params, request_timeout);
5011
5012 let id = lsp_request.id();
5013 let _cleanup = if status.is_some() {
5014 cx.update(|cx| {
5015 this.update(cx, |this, cx| {
5016 this.on_lsp_work_start(
5017 language_server.server_id(),
5018 ProgressToken::Number(id),
5019 LanguageServerProgress {
5020 is_disk_based_diagnostics_progress: false,
5021 is_cancellable: false,
5022 title: None,
5023 message: status.clone(),
5024 percentage: None,
5025 last_update_at: cx.background_executor().now(),
5026 },
5027 cx,
5028 );
5029 })
5030 })
5031 .log_err();
5032
5033 Some(defer(|| {
5034 cx.update(|cx| {
5035 this.update(cx, |this, cx| {
5036 this.on_lsp_work_end(
5037 language_server.server_id(),
5038 ProgressToken::Number(id),
5039 cx,
5040 );
5041 })
5042 })
5043 .log_err();
5044 }))
5045 } else {
5046 None
5047 };
5048
5049 let result = lsp_request.await.into_response();
5050
5051 let response = result.map_err(|err| {
5052 let message = format!(
5053 "{} via {} failed: {}",
5054 request.display_name(),
5055 language_server.name(),
5056 err
5057 );
5058 // rust-analyzer likes to error with this when its still loading up
5059 if !message.ends_with("content modified") {
5060 log::warn!("{message}");
5061 }
5062 anyhow::anyhow!(message)
5063 })?;
5064
5065 request
5066 .response_from_lsp(
5067 response,
5068 this.upgrade().context("no app context")?,
5069 buffer,
5070 language_server.server_id(),
5071 cx.clone(),
5072 )
5073 .await
5074 })
5075 }
5076
5077 fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
5078 let mut language_formatters_to_check = Vec::new();
5079 for buffer in self.buffer_store.read(cx).buffers() {
5080 let buffer = buffer.read(cx);
5081 let buffer_file = File::from_dyn(buffer.file());
5082 let buffer_language = buffer.language();
5083 let settings = language_settings(buffer_language.map(|l| l.name()), buffer.file(), cx);
5084 if buffer_language.is_some() {
5085 language_formatters_to_check.push((
5086 buffer_file.map(|f| f.worktree_id(cx)),
5087 settings.into_owned(),
5088 ));
5089 }
5090 }
5091
5092 self.request_workspace_config_refresh();
5093
5094 if let Some(prettier_store) = self.as_local().map(|s| s.prettier_store.clone()) {
5095 prettier_store.update(cx, |prettier_store, cx| {
5096 prettier_store.on_settings_changed(language_formatters_to_check, cx)
5097 })
5098 }
5099
5100 let new_semantic_token_rules = crate::project_settings::ProjectSettings::get_global(cx)
5101 .global_lsp_settings
5102 .semantic_token_rules
5103 .clone();
5104 self.semantic_token_config
5105 .update_rules(new_semantic_token_rules);
5106
5107 let new_global_semantic_tokens_mode =
5108 all_language_settings(None, cx).defaults.semantic_tokens;
5109 if self
5110 .semantic_token_config
5111 .update_global_mode(new_global_semantic_tokens_mode)
5112 {
5113 self.restart_all_language_servers(cx);
5114 }
5115
5116 cx.notify();
5117 }
5118
5119 fn refresh_server_tree(&mut self, cx: &mut Context<Self>) {
5120 let buffer_store = self.buffer_store.clone();
5121 let Some(local) = self.as_local_mut() else {
5122 return;
5123 };
5124 let mut adapters = BTreeMap::default();
5125 let get_adapter = {
5126 let languages = local.languages.clone();
5127 let environment = local.environment.clone();
5128 let weak = local.weak.clone();
5129 let worktree_store = local.worktree_store.clone();
5130 let http_client = local.http_client.clone();
5131 let fs = local.fs.clone();
5132 move |worktree_id, cx: &mut App| {
5133 let worktree = worktree_store.read(cx).worktree_for_id(worktree_id, cx)?;
5134 Some(LocalLspAdapterDelegate::new(
5135 languages.clone(),
5136 &environment,
5137 weak.clone(),
5138 &worktree,
5139 http_client.clone(),
5140 fs.clone(),
5141 cx,
5142 ))
5143 }
5144 };
5145
5146 let mut messages_to_report = Vec::new();
5147 let (new_tree, to_stop) = {
5148 let mut rebase = local.lsp_tree.rebase();
5149 let buffers = buffer_store
5150 .read(cx)
5151 .buffers()
5152 .filter_map(|buffer| {
5153 let raw_buffer = buffer.read(cx);
5154 if !local
5155 .registered_buffers
5156 .contains_key(&raw_buffer.remote_id())
5157 {
5158 return None;
5159 }
5160 let file = File::from_dyn(raw_buffer.file()).cloned()?;
5161 let language = raw_buffer.language().cloned()?;
5162 Some((file, language, raw_buffer.remote_id()))
5163 })
5164 .sorted_by_key(|(file, _, _)| Reverse(file.worktree.read(cx).is_visible()));
5165 for (file, language, buffer_id) in buffers {
5166 let worktree_id = file.worktree_id(cx);
5167 let Some(worktree) = local
5168 .worktree_store
5169 .read(cx)
5170 .worktree_for_id(worktree_id, cx)
5171 else {
5172 continue;
5173 };
5174
5175 if let Some((_, apply)) = local.reuse_existing_language_server(
5176 rebase.server_tree(),
5177 &worktree,
5178 &language.name(),
5179 cx,
5180 ) {
5181 (apply)(rebase.server_tree());
5182 } else if let Some(lsp_delegate) = adapters
5183 .entry(worktree_id)
5184 .or_insert_with(|| get_adapter(worktree_id, cx))
5185 .clone()
5186 {
5187 let delegate =
5188 Arc::new(ManifestQueryDelegate::new(worktree.read(cx).snapshot()));
5189 let path = file
5190 .path()
5191 .parent()
5192 .map(Arc::from)
5193 .unwrap_or_else(|| file.path().clone());
5194 let worktree_path = ProjectPath { worktree_id, path };
5195 let abs_path = file.abs_path(cx);
5196 let nodes = rebase
5197 .walk(
5198 worktree_path,
5199 language.name(),
5200 language.manifest(),
5201 delegate.clone(),
5202 cx,
5203 )
5204 .collect::<Vec<_>>();
5205 for node in nodes {
5206 let server_id = node.server_id_or_init(|disposition| {
5207 let path = &disposition.path;
5208 let uri = Uri::from_file_path(worktree.read(cx).absolutize(&path.path));
5209 let key = LanguageServerSeed {
5210 worktree_id,
5211 name: disposition.server_name.clone(),
5212 settings: LanguageServerSeedSettings {
5213 binary: disposition.settings.binary.clone(),
5214 initialization_options: disposition
5215 .settings
5216 .initialization_options
5217 .clone(),
5218 },
5219 toolchain: local.toolchain_store.read(cx).active_toolchain(
5220 path.worktree_id,
5221 &path.path,
5222 language.name(),
5223 ),
5224 };
5225 local.language_server_ids.remove(&key);
5226
5227 let server_id = local.get_or_insert_language_server(
5228 &worktree,
5229 lsp_delegate.clone(),
5230 disposition,
5231 &language.name(),
5232 cx,
5233 );
5234 if let Some(state) = local.language_servers.get(&server_id)
5235 && let Ok(uri) = uri
5236 {
5237 state.add_workspace_folder(uri);
5238 };
5239 server_id
5240 });
5241
5242 if let Some(language_server_id) = server_id {
5243 messages_to_report.push(LspStoreEvent::LanguageServerUpdate {
5244 language_server_id,
5245 name: node.name(),
5246 message:
5247 proto::update_language_server::Variant::RegisteredForBuffer(
5248 proto::RegisteredForBuffer {
5249 buffer_abs_path: abs_path
5250 .to_string_lossy()
5251 .into_owned(),
5252 buffer_id: buffer_id.to_proto(),
5253 },
5254 ),
5255 });
5256 }
5257 }
5258 } else {
5259 continue;
5260 }
5261 }
5262 rebase.finish()
5263 };
5264 for message in messages_to_report {
5265 cx.emit(message);
5266 }
5267 local.lsp_tree = new_tree;
5268 for (id, _) in to_stop {
5269 self.stop_local_language_server(id, cx).detach();
5270 }
5271 }
5272
5273 pub fn apply_code_action(
5274 &self,
5275 buffer_handle: Entity<Buffer>,
5276 mut action: CodeAction,
5277 push_to_history: bool,
5278 cx: &mut Context<Self>,
5279 ) -> Task<Result<ProjectTransaction>> {
5280 if let Some((upstream_client, project_id)) = self.upstream_client() {
5281 let request = proto::ApplyCodeAction {
5282 project_id,
5283 buffer_id: buffer_handle.read(cx).remote_id().into(),
5284 action: Some(Self::serialize_code_action(&action)),
5285 };
5286 let buffer_store = self.buffer_store();
5287 cx.spawn(async move |_, cx| {
5288 let response = upstream_client
5289 .request(request)
5290 .await?
5291 .transaction
5292 .context("missing transaction")?;
5293
5294 buffer_store
5295 .update(cx, |buffer_store, cx| {
5296 buffer_store.deserialize_project_transaction(response, push_to_history, cx)
5297 })
5298 .await
5299 })
5300 } else if self.mode.is_local() {
5301 let Some((_, lang_server, request_timeout)) = buffer_handle.update(cx, |buffer, cx| {
5302 let request_timeout = ProjectSettings::get_global(cx)
5303 .global_lsp_settings
5304 .get_request_timeout();
5305 self.language_server_for_local_buffer(buffer, action.server_id, cx)
5306 .map(|(adapter, server)| (adapter.clone(), server.clone(), request_timeout))
5307 }) else {
5308 return Task::ready(Ok(ProjectTransaction::default()));
5309 };
5310
5311 cx.spawn(async move |this, cx| {
5312 LocalLspStore::try_resolve_code_action(&lang_server, &mut action, request_timeout)
5313 .await
5314 .context("resolving a code action")?;
5315 if let Some(edit) = action.lsp_action.edit()
5316 && (edit.changes.is_some() || edit.document_changes.is_some()) {
5317 return LocalLspStore::deserialize_workspace_edit(
5318 this.upgrade().context("no app present")?,
5319 edit.clone(),
5320 push_to_history,
5321
5322 lang_server.clone(),
5323 cx,
5324 )
5325 .await;
5326 }
5327
5328 let Some(command) = action.lsp_action.command() else {
5329 return Ok(ProjectTransaction::default())
5330 };
5331
5332 let server_capabilities = lang_server.capabilities();
5333 let available_commands = server_capabilities
5334 .execute_command_provider
5335 .as_ref()
5336 .map(|options| options.commands.as_slice())
5337 .unwrap_or_default();
5338
5339 if !available_commands.contains(&command.command) {
5340 log::warn!("Cannot execute a command {} not listed in the language server capabilities", command.command);
5341 return Ok(ProjectTransaction::default())
5342 }
5343
5344 let request_timeout = cx.update(|app|
5345 ProjectSettings::get_global(app)
5346 .global_lsp_settings
5347 .get_request_timeout()
5348 );
5349
5350 this.update(cx, |this, _| {
5351 this.as_local_mut()
5352 .unwrap()
5353 .last_workspace_edits_by_language_server
5354 .remove(&lang_server.server_id());
5355 })?;
5356
5357 let _result = lang_server
5358 .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
5359 command: command.command.clone(),
5360 arguments: command.arguments.clone().unwrap_or_default(),
5361 ..lsp::ExecuteCommandParams::default()
5362 }, request_timeout)
5363 .await.into_response()
5364 .context("execute command")?;
5365
5366 return this.update(cx, |this, _| {
5367 this.as_local_mut()
5368 .unwrap()
5369 .last_workspace_edits_by_language_server
5370 .remove(&lang_server.server_id())
5371 .unwrap_or_default()
5372 });
5373 })
5374 } else {
5375 Task::ready(Err(anyhow!("no upstream client and not local")))
5376 }
5377 }
5378
5379 pub fn apply_code_action_kind(
5380 &mut self,
5381 buffers: HashSet<Entity<Buffer>>,
5382 kind: CodeActionKind,
5383 push_to_history: bool,
5384 cx: &mut Context<Self>,
5385 ) -> Task<anyhow::Result<ProjectTransaction>> {
5386 if self.as_local().is_some() {
5387 cx.spawn(async move |lsp_store, cx| {
5388 let buffers = buffers.into_iter().collect::<Vec<_>>();
5389 let result = LocalLspStore::execute_code_action_kind_locally(
5390 lsp_store.clone(),
5391 buffers,
5392 kind,
5393 push_to_history,
5394 cx,
5395 )
5396 .await;
5397 lsp_store.update(cx, |lsp_store, _| {
5398 lsp_store.update_last_formatting_failure(&result);
5399 })?;
5400 result
5401 })
5402 } else if let Some((client, project_id)) = self.upstream_client() {
5403 let buffer_store = self.buffer_store();
5404 cx.spawn(async move |lsp_store, cx| {
5405 let result = client
5406 .request(proto::ApplyCodeActionKind {
5407 project_id,
5408 kind: kind.as_str().to_owned(),
5409 buffer_ids: buffers
5410 .iter()
5411 .map(|buffer| {
5412 buffer.read_with(cx, |buffer, _| buffer.remote_id().into())
5413 })
5414 .collect(),
5415 })
5416 .await
5417 .and_then(|result| result.transaction.context("missing transaction"));
5418 lsp_store.update(cx, |lsp_store, _| {
5419 lsp_store.update_last_formatting_failure(&result);
5420 })?;
5421
5422 let transaction_response = result?;
5423 buffer_store
5424 .update(cx, |buffer_store, cx| {
5425 buffer_store.deserialize_project_transaction(
5426 transaction_response,
5427 push_to_history,
5428 cx,
5429 )
5430 })
5431 .await
5432 })
5433 } else {
5434 Task::ready(Ok(ProjectTransaction::default()))
5435 }
5436 }
5437
5438 pub fn resolved_hint(
5439 &mut self,
5440 buffer_id: BufferId,
5441 id: InlayId,
5442 cx: &mut Context<Self>,
5443 ) -> Option<ResolvedHint> {
5444 let buffer = self.buffer_store.read(cx).get(buffer_id)?;
5445
5446 let lsp_data = self.lsp_data.get_mut(&buffer_id)?;
5447 let buffer_lsp_hints = &mut lsp_data.inlay_hints;
5448 let hint = buffer_lsp_hints.hint_for_id(id)?.clone();
5449 let (server_id, resolve_data) = match &hint.resolve_state {
5450 ResolveState::Resolved => return Some(ResolvedHint::Resolved(hint)),
5451 ResolveState::Resolving => {
5452 return Some(ResolvedHint::Resolving(
5453 buffer_lsp_hints.hint_resolves.get(&id)?.clone(),
5454 ));
5455 }
5456 ResolveState::CanResolve(server_id, resolve_data) => (*server_id, resolve_data.clone()),
5457 };
5458
5459 let resolve_task = self.resolve_inlay_hint(hint, buffer, server_id, cx);
5460 let buffer_lsp_hints = &mut self.lsp_data.get_mut(&buffer_id)?.inlay_hints;
5461 let previous_task = buffer_lsp_hints.hint_resolves.insert(
5462 id,
5463 cx.spawn(async move |lsp_store, cx| {
5464 let resolved_hint = resolve_task.await;
5465 lsp_store
5466 .update(cx, |lsp_store, _| {
5467 if let Some(old_inlay_hint) = lsp_store
5468 .lsp_data
5469 .get_mut(&buffer_id)
5470 .and_then(|buffer_lsp_data| buffer_lsp_data.inlay_hints.hint_for_id(id))
5471 {
5472 match resolved_hint {
5473 Ok(resolved_hint) => {
5474 *old_inlay_hint = resolved_hint;
5475 }
5476 Err(e) => {
5477 old_inlay_hint.resolve_state =
5478 ResolveState::CanResolve(server_id, resolve_data);
5479 log::error!("Inlay hint resolve failed: {e:#}");
5480 }
5481 }
5482 }
5483 })
5484 .ok();
5485 })
5486 .shared(),
5487 );
5488 debug_assert!(
5489 previous_task.is_none(),
5490 "Did not change hint's resolve state after spawning its resolve"
5491 );
5492 buffer_lsp_hints.hint_for_id(id)?.resolve_state = ResolveState::Resolving;
5493 None
5494 }
5495
5496 pub(crate) fn linked_edits(
5497 &mut self,
5498 buffer: &Entity<Buffer>,
5499 position: Anchor,
5500 cx: &mut Context<Self>,
5501 ) -> Task<Result<Vec<Range<Anchor>>>> {
5502 let snapshot = buffer.read(cx).snapshot();
5503 let scope = snapshot.language_scope_at(position);
5504 let Some(server_id) = self
5505 .as_local()
5506 .and_then(|local| {
5507 buffer.update(cx, |buffer, cx| {
5508 local
5509 .language_servers_for_buffer(buffer, cx)
5510 .filter(|(_, server)| {
5511 LinkedEditingRange::check_server_capabilities(server.capabilities())
5512 })
5513 .filter(|(adapter, _)| {
5514 scope
5515 .as_ref()
5516 .map(|scope| scope.language_allowed(&adapter.name))
5517 .unwrap_or(true)
5518 })
5519 .map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
5520 .next()
5521 })
5522 })
5523 .or_else(|| {
5524 self.upstream_client()
5525 .is_some()
5526 .then_some(LanguageServerToQuery::FirstCapable)
5527 })
5528 .filter(|_| {
5529 maybe!({
5530 let language = buffer.read(cx).language_at(position)?;
5531 Some(
5532 language_settings(Some(language.name()), buffer.read(cx).file(), cx)
5533 .linked_edits,
5534 )
5535 }) == Some(true)
5536 })
5537 else {
5538 return Task::ready(Ok(Vec::new()));
5539 };
5540
5541 self.request_lsp(
5542 buffer.clone(),
5543 server_id,
5544 LinkedEditingRange { position },
5545 cx,
5546 )
5547 }
5548
5549 fn apply_on_type_formatting(
5550 &mut self,
5551 buffer: Entity<Buffer>,
5552 position: Anchor,
5553 trigger: String,
5554 cx: &mut Context<Self>,
5555 ) -> Task<Result<Option<Transaction>>> {
5556 if let Some((client, project_id)) = self.upstream_client() {
5557 if !self.check_if_capable_for_proto_request(
5558 &buffer,
5559 |capabilities| {
5560 OnTypeFormatting::supports_on_type_formatting(&trigger, capabilities)
5561 },
5562 cx,
5563 ) {
5564 return Task::ready(Ok(None));
5565 }
5566 let request = proto::OnTypeFormatting {
5567 project_id,
5568 buffer_id: buffer.read(cx).remote_id().into(),
5569 position: Some(serialize_anchor(&position)),
5570 trigger,
5571 version: serialize_version(&buffer.read(cx).version()),
5572 };
5573 cx.background_spawn(async move {
5574 client
5575 .request(request)
5576 .await?
5577 .transaction
5578 .map(language::proto::deserialize_transaction)
5579 .transpose()
5580 })
5581 } else if let Some(local) = self.as_local_mut() {
5582 let buffer_id = buffer.read(cx).remote_id();
5583 local.buffers_being_formatted.insert(buffer_id);
5584 cx.spawn(async move |this, cx| {
5585 let _cleanup = defer({
5586 let this = this.clone();
5587 let mut cx = cx.clone();
5588 move || {
5589 this.update(&mut cx, |this, _| {
5590 if let Some(local) = this.as_local_mut() {
5591 local.buffers_being_formatted.remove(&buffer_id);
5592 }
5593 })
5594 .ok();
5595 }
5596 });
5597
5598 buffer
5599 .update(cx, |buffer, _| {
5600 buffer.wait_for_edits(Some(position.timestamp))
5601 })
5602 .await?;
5603 this.update(cx, |this, cx| {
5604 let position = position.to_point_utf16(buffer.read(cx));
5605 this.on_type_format(buffer, position, trigger, false, cx)
5606 })?
5607 .await
5608 })
5609 } else {
5610 Task::ready(Err(anyhow!("No upstream client or local language server")))
5611 }
5612 }
5613
5614 pub fn on_type_format<T: ToPointUtf16>(
5615 &mut self,
5616 buffer: Entity<Buffer>,
5617 position: T,
5618 trigger: String,
5619 push_to_history: bool,
5620 cx: &mut Context<Self>,
5621 ) -> Task<Result<Option<Transaction>>> {
5622 let position = position.to_point_utf16(buffer.read(cx));
5623 self.on_type_format_impl(buffer, position, trigger, push_to_history, cx)
5624 }
5625
5626 fn on_type_format_impl(
5627 &mut self,
5628 buffer: Entity<Buffer>,
5629 position: PointUtf16,
5630 trigger: String,
5631 push_to_history: bool,
5632 cx: &mut Context<Self>,
5633 ) -> Task<Result<Option<Transaction>>> {
5634 let options = buffer.update(cx, |buffer, cx| {
5635 lsp_command::lsp_formatting_options(
5636 language_settings(
5637 buffer.language_at(position).map(|l| l.name()),
5638 buffer.file(),
5639 cx,
5640 )
5641 .as_ref(),
5642 )
5643 });
5644
5645 cx.spawn(async move |this, cx| {
5646 if let Some(waiter) =
5647 buffer.update(cx, |buffer, _| buffer.wait_for_autoindent_applied())
5648 {
5649 waiter.await?;
5650 }
5651 cx.update(|cx| {
5652 this.update(cx, |this, cx| {
5653 this.request_lsp(
5654 buffer.clone(),
5655 LanguageServerToQuery::FirstCapable,
5656 OnTypeFormatting {
5657 position,
5658 trigger,
5659 options,
5660 push_to_history,
5661 },
5662 cx,
5663 )
5664 })
5665 })?
5666 .await
5667 })
5668 }
5669
5670 pub fn definitions(
5671 &mut self,
5672 buffer: &Entity<Buffer>,
5673 position: PointUtf16,
5674 cx: &mut Context<Self>,
5675 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5676 if let Some((upstream_client, project_id)) = self.upstream_client() {
5677 let request = GetDefinitions { position };
5678 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5679 return Task::ready(Ok(None));
5680 }
5681
5682 let request_timeout = ProjectSettings::get_global(cx)
5683 .global_lsp_settings
5684 .get_request_timeout();
5685
5686 let request_task = upstream_client.request_lsp(
5687 project_id,
5688 None,
5689 request_timeout,
5690 cx.background_executor().clone(),
5691 request.to_proto(project_id, buffer.read(cx)),
5692 );
5693 let buffer = buffer.clone();
5694 cx.spawn(async move |weak_lsp_store, cx| {
5695 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5696 return Ok(None);
5697 };
5698 let Some(responses) = request_task.await? else {
5699 return Ok(None);
5700 };
5701 let actions = join_all(responses.payload.into_iter().map(|response| {
5702 GetDefinitions { position }.response_from_proto(
5703 response.response,
5704 lsp_store.clone(),
5705 buffer.clone(),
5706 cx.clone(),
5707 )
5708 }))
5709 .await;
5710
5711 Ok(Some(
5712 actions
5713 .into_iter()
5714 .collect::<Result<Vec<Vec<_>>>>()?
5715 .into_iter()
5716 .flatten()
5717 .dedup()
5718 .collect(),
5719 ))
5720 })
5721 } else {
5722 let definitions_task = self.request_multiple_lsp_locally(
5723 buffer,
5724 Some(position),
5725 GetDefinitions { position },
5726 cx,
5727 );
5728 cx.background_spawn(async move {
5729 Ok(Some(
5730 definitions_task
5731 .await
5732 .into_iter()
5733 .flat_map(|(_, definitions)| definitions)
5734 .dedup()
5735 .collect(),
5736 ))
5737 })
5738 }
5739 }
5740
5741 pub fn declarations(
5742 &mut self,
5743 buffer: &Entity<Buffer>,
5744 position: PointUtf16,
5745 cx: &mut Context<Self>,
5746 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5747 if let Some((upstream_client, project_id)) = self.upstream_client() {
5748 let request = GetDeclarations { position };
5749 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5750 return Task::ready(Ok(None));
5751 }
5752 let request_timeout = ProjectSettings::get_global(cx)
5753 .global_lsp_settings
5754 .get_request_timeout();
5755 let request_task = upstream_client.request_lsp(
5756 project_id,
5757 None,
5758 request_timeout,
5759 cx.background_executor().clone(),
5760 request.to_proto(project_id, buffer.read(cx)),
5761 );
5762 let buffer = buffer.clone();
5763 cx.spawn(async move |weak_lsp_store, cx| {
5764 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5765 return Ok(None);
5766 };
5767 let Some(responses) = request_task.await? else {
5768 return Ok(None);
5769 };
5770 let actions = join_all(responses.payload.into_iter().map(|response| {
5771 GetDeclarations { position }.response_from_proto(
5772 response.response,
5773 lsp_store.clone(),
5774 buffer.clone(),
5775 cx.clone(),
5776 )
5777 }))
5778 .await;
5779
5780 Ok(Some(
5781 actions
5782 .into_iter()
5783 .collect::<Result<Vec<Vec<_>>>>()?
5784 .into_iter()
5785 .flatten()
5786 .dedup()
5787 .collect(),
5788 ))
5789 })
5790 } else {
5791 let declarations_task = self.request_multiple_lsp_locally(
5792 buffer,
5793 Some(position),
5794 GetDeclarations { position },
5795 cx,
5796 );
5797 cx.background_spawn(async move {
5798 Ok(Some(
5799 declarations_task
5800 .await
5801 .into_iter()
5802 .flat_map(|(_, declarations)| declarations)
5803 .dedup()
5804 .collect(),
5805 ))
5806 })
5807 }
5808 }
5809
5810 pub fn type_definitions(
5811 &mut self,
5812 buffer: &Entity<Buffer>,
5813 position: PointUtf16,
5814 cx: &mut Context<Self>,
5815 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5816 if let Some((upstream_client, project_id)) = self.upstream_client() {
5817 let request = GetTypeDefinitions { position };
5818 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5819 return Task::ready(Ok(None));
5820 }
5821 let request_timeout = ProjectSettings::get_global(cx)
5822 .global_lsp_settings
5823 .get_request_timeout();
5824 let request_task = upstream_client.request_lsp(
5825 project_id,
5826 None,
5827 request_timeout,
5828 cx.background_executor().clone(),
5829 request.to_proto(project_id, buffer.read(cx)),
5830 );
5831 let buffer = buffer.clone();
5832 cx.spawn(async move |weak_lsp_store, cx| {
5833 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5834 return Ok(None);
5835 };
5836 let Some(responses) = request_task.await? else {
5837 return Ok(None);
5838 };
5839 let actions = join_all(responses.payload.into_iter().map(|response| {
5840 GetTypeDefinitions { position }.response_from_proto(
5841 response.response,
5842 lsp_store.clone(),
5843 buffer.clone(),
5844 cx.clone(),
5845 )
5846 }))
5847 .await;
5848
5849 Ok(Some(
5850 actions
5851 .into_iter()
5852 .collect::<Result<Vec<Vec<_>>>>()?
5853 .into_iter()
5854 .flatten()
5855 .dedup()
5856 .collect(),
5857 ))
5858 })
5859 } else {
5860 let type_definitions_task = self.request_multiple_lsp_locally(
5861 buffer,
5862 Some(position),
5863 GetTypeDefinitions { position },
5864 cx,
5865 );
5866 cx.background_spawn(async move {
5867 Ok(Some(
5868 type_definitions_task
5869 .await
5870 .into_iter()
5871 .flat_map(|(_, type_definitions)| type_definitions)
5872 .dedup()
5873 .collect(),
5874 ))
5875 })
5876 }
5877 }
5878
5879 pub fn implementations(
5880 &mut self,
5881 buffer: &Entity<Buffer>,
5882 position: PointUtf16,
5883 cx: &mut Context<Self>,
5884 ) -> Task<Result<Option<Vec<LocationLink>>>> {
5885 if let Some((upstream_client, project_id)) = self.upstream_client() {
5886 let request = GetImplementations { position };
5887 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5888 return Task::ready(Ok(None));
5889 }
5890
5891 let request_timeout = ProjectSettings::get_global(cx)
5892 .global_lsp_settings
5893 .get_request_timeout();
5894 let request_task = upstream_client.request_lsp(
5895 project_id,
5896 None,
5897 request_timeout,
5898 cx.background_executor().clone(),
5899 request.to_proto(project_id, buffer.read(cx)),
5900 );
5901 let buffer = buffer.clone();
5902 cx.spawn(async move |weak_lsp_store, cx| {
5903 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5904 return Ok(None);
5905 };
5906 let Some(responses) = request_task.await? else {
5907 return Ok(None);
5908 };
5909 let actions = join_all(responses.payload.into_iter().map(|response| {
5910 GetImplementations { position }.response_from_proto(
5911 response.response,
5912 lsp_store.clone(),
5913 buffer.clone(),
5914 cx.clone(),
5915 )
5916 }))
5917 .await;
5918
5919 Ok(Some(
5920 actions
5921 .into_iter()
5922 .collect::<Result<Vec<Vec<_>>>>()?
5923 .into_iter()
5924 .flatten()
5925 .dedup()
5926 .collect(),
5927 ))
5928 })
5929 } else {
5930 let implementations_task = self.request_multiple_lsp_locally(
5931 buffer,
5932 Some(position),
5933 GetImplementations { position },
5934 cx,
5935 );
5936 cx.background_spawn(async move {
5937 Ok(Some(
5938 implementations_task
5939 .await
5940 .into_iter()
5941 .flat_map(|(_, implementations)| implementations)
5942 .dedup()
5943 .collect(),
5944 ))
5945 })
5946 }
5947 }
5948
5949 pub fn references(
5950 &mut self,
5951 buffer: &Entity<Buffer>,
5952 position: PointUtf16,
5953 cx: &mut Context<Self>,
5954 ) -> Task<Result<Option<Vec<Location>>>> {
5955 if let Some((upstream_client, project_id)) = self.upstream_client() {
5956 let request = GetReferences { position };
5957 if !self.is_capable_for_proto_request(buffer, &request, cx) {
5958 return Task::ready(Ok(None));
5959 }
5960
5961 let request_timeout = ProjectSettings::get_global(cx)
5962 .global_lsp_settings
5963 .get_request_timeout();
5964 let request_task = upstream_client.request_lsp(
5965 project_id,
5966 None,
5967 request_timeout,
5968 cx.background_executor().clone(),
5969 request.to_proto(project_id, buffer.read(cx)),
5970 );
5971 let buffer = buffer.clone();
5972 cx.spawn(async move |weak_lsp_store, cx| {
5973 let Some(lsp_store) = weak_lsp_store.upgrade() else {
5974 return Ok(None);
5975 };
5976 let Some(responses) = request_task.await? else {
5977 return Ok(None);
5978 };
5979
5980 let locations = join_all(responses.payload.into_iter().map(|lsp_response| {
5981 GetReferences { position }.response_from_proto(
5982 lsp_response.response,
5983 lsp_store.clone(),
5984 buffer.clone(),
5985 cx.clone(),
5986 )
5987 }))
5988 .await
5989 .into_iter()
5990 .collect::<Result<Vec<Vec<_>>>>()?
5991 .into_iter()
5992 .flatten()
5993 .dedup()
5994 .collect();
5995 Ok(Some(locations))
5996 })
5997 } else {
5998 let references_task = self.request_multiple_lsp_locally(
5999 buffer,
6000 Some(position),
6001 GetReferences { position },
6002 cx,
6003 );
6004 cx.background_spawn(async move {
6005 Ok(Some(
6006 references_task
6007 .await
6008 .into_iter()
6009 .flat_map(|(_, references)| references)
6010 .dedup()
6011 .collect(),
6012 ))
6013 })
6014 }
6015 }
6016
6017 pub fn code_actions(
6018 &mut self,
6019 buffer: &Entity<Buffer>,
6020 range: Range<Anchor>,
6021 kinds: Option<Vec<CodeActionKind>>,
6022 cx: &mut Context<Self>,
6023 ) -> Task<Result<Option<Vec<CodeAction>>>> {
6024 if let Some((upstream_client, project_id)) = self.upstream_client() {
6025 let request = GetCodeActions {
6026 range: range.clone(),
6027 kinds: kinds.clone(),
6028 };
6029 if !self.is_capable_for_proto_request(buffer, &request, cx) {
6030 return Task::ready(Ok(None));
6031 }
6032 let request_timeout = ProjectSettings::get_global(cx)
6033 .global_lsp_settings
6034 .get_request_timeout();
6035 let request_task = upstream_client.request_lsp(
6036 project_id,
6037 None,
6038 request_timeout,
6039 cx.background_executor().clone(),
6040 request.to_proto(project_id, buffer.read(cx)),
6041 );
6042 let buffer = buffer.clone();
6043 cx.spawn(async move |weak_lsp_store, cx| {
6044 let Some(lsp_store) = weak_lsp_store.upgrade() else {
6045 return Ok(None);
6046 };
6047 let Some(responses) = request_task.await? else {
6048 return Ok(None);
6049 };
6050 let actions = join_all(responses.payload.into_iter().map(|response| {
6051 GetCodeActions {
6052 range: range.clone(),
6053 kinds: kinds.clone(),
6054 }
6055 .response_from_proto(
6056 response.response,
6057 lsp_store.clone(),
6058 buffer.clone(),
6059 cx.clone(),
6060 )
6061 }))
6062 .await;
6063
6064 Ok(Some(
6065 actions
6066 .into_iter()
6067 .collect::<Result<Vec<Vec<_>>>>()?
6068 .into_iter()
6069 .flatten()
6070 .collect(),
6071 ))
6072 })
6073 } else {
6074 let all_actions_task = self.request_multiple_lsp_locally(
6075 buffer,
6076 Some(range.start),
6077 GetCodeActions { range, kinds },
6078 cx,
6079 );
6080 cx.background_spawn(async move {
6081 Ok(Some(
6082 all_actions_task
6083 .await
6084 .into_iter()
6085 .flat_map(|(_, actions)| actions)
6086 .collect(),
6087 ))
6088 })
6089 }
6090 }
6091
6092 #[inline(never)]
6093 pub fn completions(
6094 &self,
6095 buffer: &Entity<Buffer>,
6096 position: PointUtf16,
6097 context: CompletionContext,
6098 cx: &mut Context<Self>,
6099 ) -> Task<Result<Vec<CompletionResponse>>> {
6100 let language_registry = self.languages.clone();
6101
6102 if let Some((upstream_client, project_id)) = self.upstream_client() {
6103 let snapshot = buffer.read(cx).snapshot();
6104 let offset = position.to_offset(&snapshot);
6105 let scope = snapshot.language_scope_at(offset);
6106 let capable_lsps = self.all_capable_for_proto_request(
6107 buffer,
6108 |server_name, capabilities| {
6109 capabilities.completion_provider.is_some()
6110 && scope
6111 .as_ref()
6112 .map(|scope| scope.language_allowed(server_name))
6113 .unwrap_or(true)
6114 },
6115 cx,
6116 );
6117 if capable_lsps.is_empty() {
6118 return Task::ready(Ok(Vec::new()));
6119 }
6120
6121 let language = buffer.read(cx).language().cloned();
6122
6123 // In the future, we should provide project guests with the names of LSP adapters,
6124 // so that they can use the correct LSP adapter when computing labels. For now,
6125 // guests just use the first LSP adapter associated with the buffer's language.
6126 let lsp_adapter = language.as_ref().and_then(|language| {
6127 language_registry
6128 .lsp_adapters(&language.name())
6129 .first()
6130 .cloned()
6131 });
6132
6133 let buffer = buffer.clone();
6134
6135 cx.spawn(async move |this, cx| {
6136 let requests = join_all(
6137 capable_lsps
6138 .into_iter()
6139 .map(|id| {
6140 let request = GetCompletions {
6141 position,
6142 context: context.clone(),
6143 server_id: Some(id),
6144 };
6145 let buffer = buffer.clone();
6146 let language = language.clone();
6147 let lsp_adapter = lsp_adapter.clone();
6148 let upstream_client = upstream_client.clone();
6149 let response = this
6150 .update(cx, |this, cx| {
6151 this.send_lsp_proto_request(
6152 buffer,
6153 upstream_client,
6154 project_id,
6155 request,
6156 cx,
6157 )
6158 })
6159 .log_err();
6160 async move {
6161 let response = response?.await.log_err()?;
6162
6163 let completions = populate_labels_for_completions(
6164 response.completions,
6165 language,
6166 lsp_adapter,
6167 )
6168 .await;
6169
6170 Some(CompletionResponse {
6171 completions,
6172 display_options: CompletionDisplayOptions::default(),
6173 is_incomplete: response.is_incomplete,
6174 })
6175 }
6176 })
6177 .collect::<Vec<_>>(),
6178 );
6179 Ok(requests.await.into_iter().flatten().collect::<Vec<_>>())
6180 })
6181 } else if let Some(local) = self.as_local() {
6182 let snapshot = buffer.read(cx).snapshot();
6183 let offset = position.to_offset(&snapshot);
6184 let scope = snapshot.language_scope_at(offset);
6185 let language = snapshot.language().cloned();
6186 let completion_settings = language_settings(
6187 language.as_ref().map(|language| language.name()),
6188 buffer.read(cx).file(),
6189 cx,
6190 )
6191 .completions
6192 .clone();
6193 if !completion_settings.lsp {
6194 return Task::ready(Ok(Vec::new()));
6195 }
6196
6197 let server_ids: Vec<_> = buffer.update(cx, |buffer, cx| {
6198 local
6199 .language_servers_for_buffer(buffer, cx)
6200 .filter(|(_, server)| server.capabilities().completion_provider.is_some())
6201 .filter(|(adapter, _)| {
6202 scope
6203 .as_ref()
6204 .map(|scope| scope.language_allowed(&adapter.name))
6205 .unwrap_or(true)
6206 })
6207 .map(|(_, server)| server.server_id())
6208 .collect()
6209 });
6210
6211 let buffer = buffer.clone();
6212 let lsp_timeout = completion_settings.lsp_fetch_timeout_ms;
6213 let lsp_timeout = if lsp_timeout > 0 {
6214 Some(Duration::from_millis(lsp_timeout))
6215 } else {
6216 None
6217 };
6218 cx.spawn(async move |this, cx| {
6219 let mut tasks = Vec::with_capacity(server_ids.len());
6220 this.update(cx, |lsp_store, cx| {
6221 for server_id in server_ids {
6222 let lsp_adapter = lsp_store.language_server_adapter_for_id(server_id);
6223 let lsp_timeout = lsp_timeout
6224 .map(|lsp_timeout| cx.background_executor().timer(lsp_timeout));
6225 let mut timeout = cx.background_spawn(async move {
6226 match lsp_timeout {
6227 Some(lsp_timeout) => {
6228 lsp_timeout.await;
6229 true
6230 },
6231 None => false,
6232 }
6233 }).fuse();
6234 let mut lsp_request = lsp_store.request_lsp(
6235 buffer.clone(),
6236 LanguageServerToQuery::Other(server_id),
6237 GetCompletions {
6238 position,
6239 context: context.clone(),
6240 server_id: Some(server_id),
6241 },
6242 cx,
6243 ).fuse();
6244 let new_task = cx.background_spawn(async move {
6245 select_biased! {
6246 response = lsp_request => anyhow::Ok(Some(response?)),
6247 timeout_happened = timeout => {
6248 if timeout_happened {
6249 log::warn!("Fetching completions from server {server_id} timed out, timeout ms: {}", completion_settings.lsp_fetch_timeout_ms);
6250 Ok(None)
6251 } else {
6252 let completions = lsp_request.await?;
6253 Ok(Some(completions))
6254 }
6255 },
6256 }
6257 });
6258 tasks.push((lsp_adapter, new_task));
6259 }
6260 })?;
6261
6262 let futures = tasks.into_iter().map(async |(lsp_adapter, task)| {
6263 let completion_response = task.await.ok()??;
6264 let completions = populate_labels_for_completions(
6265 completion_response.completions,
6266 language.clone(),
6267 lsp_adapter,
6268 )
6269 .await;
6270 Some(CompletionResponse {
6271 completions,
6272 display_options: CompletionDisplayOptions::default(),
6273 is_incomplete: completion_response.is_incomplete,
6274 })
6275 });
6276
6277 let responses: Vec<Option<CompletionResponse>> = join_all(futures).await;
6278
6279 Ok(responses.into_iter().flatten().collect())
6280 })
6281 } else {
6282 Task::ready(Err(anyhow!("No upstream client or local language server")))
6283 }
6284 }
6285
6286 pub fn resolve_completions(
6287 &self,
6288 buffer: Entity<Buffer>,
6289 completion_indices: Vec<usize>,
6290 completions: Rc<RefCell<Box<[Completion]>>>,
6291 cx: &mut Context<Self>,
6292 ) -> Task<Result<bool>> {
6293 let client = self.upstream_client();
6294 let buffer_id = buffer.read(cx).remote_id();
6295 let buffer_snapshot = buffer.read(cx).snapshot();
6296
6297 if !self.check_if_capable_for_proto_request(
6298 &buffer,
6299 GetCompletions::can_resolve_completions,
6300 cx,
6301 ) {
6302 return Task::ready(Ok(false));
6303 }
6304 cx.spawn(async move |lsp_store, cx| {
6305 let request_timeout = cx.update(|app| {
6306 ProjectSettings::get_global(app)
6307 .global_lsp_settings
6308 .get_request_timeout()
6309 });
6310
6311 let mut did_resolve = false;
6312 if let Some((client, project_id)) = client {
6313 for completion_index in completion_indices {
6314 let server_id = {
6315 let completion = &completions.borrow()[completion_index];
6316 completion.source.server_id()
6317 };
6318 if let Some(server_id) = server_id {
6319 if Self::resolve_completion_remote(
6320 project_id,
6321 server_id,
6322 buffer_id,
6323 completions.clone(),
6324 completion_index,
6325 client.clone(),
6326 )
6327 .await
6328 .log_err()
6329 .is_some()
6330 {
6331 did_resolve = true;
6332 }
6333 } else {
6334 resolve_word_completion(
6335 &buffer_snapshot,
6336 &mut completions.borrow_mut()[completion_index],
6337 );
6338 }
6339 }
6340 } else {
6341 for completion_index in completion_indices {
6342 let server_id = {
6343 let completion = &completions.borrow()[completion_index];
6344 completion.source.server_id()
6345 };
6346 if let Some(server_id) = server_id {
6347 let server_and_adapter = lsp_store
6348 .read_with(cx, |lsp_store, _| {
6349 let server = lsp_store.language_server_for_id(server_id)?;
6350 let adapter =
6351 lsp_store.language_server_adapter_for_id(server.server_id())?;
6352 Some((server, adapter))
6353 })
6354 .ok()
6355 .flatten();
6356 let Some((server, adapter)) = server_and_adapter else {
6357 continue;
6358 };
6359
6360 let resolved = Self::resolve_completion_local(
6361 server,
6362 completions.clone(),
6363 completion_index,
6364 request_timeout,
6365 )
6366 .await
6367 .log_err()
6368 .is_some();
6369 if resolved {
6370 Self::regenerate_completion_labels(
6371 adapter,
6372 &buffer_snapshot,
6373 completions.clone(),
6374 completion_index,
6375 )
6376 .await
6377 .log_err();
6378 did_resolve = true;
6379 }
6380 } else {
6381 resolve_word_completion(
6382 &buffer_snapshot,
6383 &mut completions.borrow_mut()[completion_index],
6384 );
6385 }
6386 }
6387 }
6388
6389 Ok(did_resolve)
6390 })
6391 }
6392
6393 async fn resolve_completion_local(
6394 server: Arc<lsp::LanguageServer>,
6395 completions: Rc<RefCell<Box<[Completion]>>>,
6396 completion_index: usize,
6397 request_timeout: Duration,
6398 ) -> Result<()> {
6399 let server_id = server.server_id();
6400 if !GetCompletions::can_resolve_completions(&server.capabilities()) {
6401 return Ok(());
6402 }
6403
6404 let request = {
6405 let completion = &completions.borrow()[completion_index];
6406 match &completion.source {
6407 CompletionSource::Lsp {
6408 lsp_completion,
6409 resolved,
6410 server_id: completion_server_id,
6411 ..
6412 } => {
6413 if *resolved {
6414 return Ok(());
6415 }
6416 anyhow::ensure!(
6417 server_id == *completion_server_id,
6418 "server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6419 );
6420 server.request::<lsp::request::ResolveCompletionItem>(
6421 *lsp_completion.clone(),
6422 request_timeout,
6423 )
6424 }
6425 CompletionSource::BufferWord { .. }
6426 | CompletionSource::Dap { .. }
6427 | CompletionSource::Custom => {
6428 return Ok(());
6429 }
6430 }
6431 };
6432 let resolved_completion = request
6433 .await
6434 .into_response()
6435 .context("resolve completion")?;
6436
6437 // We must not use any data such as sortText, filterText, insertText and textEdit to edit `Completion` since they are not suppose change during resolve.
6438 // Refer: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
6439
6440 let mut completions = completions.borrow_mut();
6441 let completion = &mut completions[completion_index];
6442 if let CompletionSource::Lsp {
6443 lsp_completion,
6444 resolved,
6445 server_id: completion_server_id,
6446 ..
6447 } = &mut completion.source
6448 {
6449 if *resolved {
6450 return Ok(());
6451 }
6452 anyhow::ensure!(
6453 server_id == *completion_server_id,
6454 "server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6455 );
6456 **lsp_completion = resolved_completion;
6457 *resolved = true;
6458 }
6459 Ok(())
6460 }
6461
6462 async fn regenerate_completion_labels(
6463 adapter: Arc<CachedLspAdapter>,
6464 snapshot: &BufferSnapshot,
6465 completions: Rc<RefCell<Box<[Completion]>>>,
6466 completion_index: usize,
6467 ) -> Result<()> {
6468 let completion_item = completions.borrow()[completion_index]
6469 .source
6470 .lsp_completion(true)
6471 .map(Cow::into_owned);
6472 if let Some(lsp_documentation) = completion_item
6473 .as_ref()
6474 .and_then(|completion_item| completion_item.documentation.clone())
6475 {
6476 let mut completions = completions.borrow_mut();
6477 let completion = &mut completions[completion_index];
6478 completion.documentation = Some(lsp_documentation.into());
6479 } else {
6480 let mut completions = completions.borrow_mut();
6481 let completion = &mut completions[completion_index];
6482 completion.documentation = Some(CompletionDocumentation::Undocumented);
6483 }
6484
6485 let mut new_label = match completion_item {
6486 Some(completion_item) => {
6487 // Some language servers always return `detail` lazily via resolve, regardless of
6488 // the resolvable properties Zed advertises. Regenerate labels here to handle this.
6489 // See: https://github.com/yioneko/vtsls/issues/213
6490 let language = snapshot.language();
6491 match language {
6492 Some(language) => {
6493 adapter
6494 .labels_for_completions(
6495 std::slice::from_ref(&completion_item),
6496 language,
6497 )
6498 .await?
6499 }
6500 None => Vec::new(),
6501 }
6502 .pop()
6503 .flatten()
6504 .unwrap_or_else(|| {
6505 CodeLabel::fallback_for_completion(
6506 &completion_item,
6507 language.map(|language| language.as_ref()),
6508 )
6509 })
6510 }
6511 None => CodeLabel::plain(
6512 completions.borrow()[completion_index].new_text.clone(),
6513 None,
6514 ),
6515 };
6516 ensure_uniform_list_compatible_label(&mut new_label);
6517
6518 let mut completions = completions.borrow_mut();
6519 let completion = &mut completions[completion_index];
6520 if completion.label.filter_text() == new_label.filter_text() {
6521 completion.label = new_label;
6522 } else {
6523 log::error!(
6524 "Resolved completion changed display label from {} to {}. \
6525 Refusing to apply this because it changes the fuzzy match text from {} to {}",
6526 completion.label.text(),
6527 new_label.text(),
6528 completion.label.filter_text(),
6529 new_label.filter_text()
6530 );
6531 }
6532
6533 Ok(())
6534 }
6535
6536 async fn resolve_completion_remote(
6537 project_id: u64,
6538 server_id: LanguageServerId,
6539 buffer_id: BufferId,
6540 completions: Rc<RefCell<Box<[Completion]>>>,
6541 completion_index: usize,
6542 client: AnyProtoClient,
6543 ) -> Result<()> {
6544 let lsp_completion = {
6545 let completion = &completions.borrow()[completion_index];
6546 match &completion.source {
6547 CompletionSource::Lsp {
6548 lsp_completion,
6549 resolved,
6550 server_id: completion_server_id,
6551 ..
6552 } => {
6553 anyhow::ensure!(
6554 server_id == *completion_server_id,
6555 "remote server_id mismatch, querying completion resolve for {server_id} but completion server id is {completion_server_id}"
6556 );
6557 if *resolved {
6558 return Ok(());
6559 }
6560 serde_json::to_string(lsp_completion).unwrap().into_bytes()
6561 }
6562 CompletionSource::Custom
6563 | CompletionSource::Dap { .. }
6564 | CompletionSource::BufferWord { .. } => {
6565 return Ok(());
6566 }
6567 }
6568 };
6569 let request = proto::ResolveCompletionDocumentation {
6570 project_id,
6571 language_server_id: server_id.0 as u64,
6572 lsp_completion,
6573 buffer_id: buffer_id.into(),
6574 };
6575
6576 let response = client
6577 .request(request)
6578 .await
6579 .context("completion documentation resolve proto request")?;
6580 let resolved_lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
6581
6582 let documentation = if response.documentation.is_empty() {
6583 CompletionDocumentation::Undocumented
6584 } else if response.documentation_is_markdown {
6585 CompletionDocumentation::MultiLineMarkdown(response.documentation.into())
6586 } else if response.documentation.lines().count() <= 1 {
6587 CompletionDocumentation::SingleLine(response.documentation.into())
6588 } else {
6589 CompletionDocumentation::MultiLinePlainText(response.documentation.into())
6590 };
6591
6592 let mut completions = completions.borrow_mut();
6593 let completion = &mut completions[completion_index];
6594 completion.documentation = Some(documentation);
6595 if let CompletionSource::Lsp {
6596 insert_range,
6597 lsp_completion,
6598 resolved,
6599 server_id: completion_server_id,
6600 lsp_defaults: _,
6601 } = &mut completion.source
6602 {
6603 let completion_insert_range = response
6604 .old_insert_start
6605 .and_then(deserialize_anchor)
6606 .zip(response.old_insert_end.and_then(deserialize_anchor));
6607 *insert_range = completion_insert_range.map(|(start, end)| start..end);
6608
6609 if *resolved {
6610 return Ok(());
6611 }
6612 anyhow::ensure!(
6613 server_id == *completion_server_id,
6614 "remote server_id mismatch, applying completion resolve for {server_id} but completion server id is {completion_server_id}"
6615 );
6616 **lsp_completion = resolved_lsp_completion;
6617 *resolved = true;
6618 }
6619
6620 let replace_range = response
6621 .old_replace_start
6622 .and_then(deserialize_anchor)
6623 .zip(response.old_replace_end.and_then(deserialize_anchor));
6624 if let Some((old_replace_start, old_replace_end)) = replace_range
6625 && !response.new_text.is_empty()
6626 {
6627 completion.new_text = response.new_text;
6628 completion.replace_range = old_replace_start..old_replace_end;
6629 }
6630
6631 Ok(())
6632 }
6633
6634 pub fn apply_additional_edits_for_completion(
6635 &self,
6636 buffer_handle: Entity<Buffer>,
6637 completions: Rc<RefCell<Box<[Completion]>>>,
6638 completion_index: usize,
6639 push_to_history: bool,
6640 cx: &mut Context<Self>,
6641 ) -> Task<Result<Option<Transaction>>> {
6642 if let Some((client, project_id)) = self.upstream_client() {
6643 let buffer = buffer_handle.read(cx);
6644 let buffer_id = buffer.remote_id();
6645 cx.spawn(async move |_, cx| {
6646 let request = {
6647 let completion = completions.borrow()[completion_index].clone();
6648 proto::ApplyCompletionAdditionalEdits {
6649 project_id,
6650 buffer_id: buffer_id.into(),
6651 completion: Some(Self::serialize_completion(&CoreCompletion {
6652 replace_range: completion.replace_range,
6653 new_text: completion.new_text,
6654 source: completion.source,
6655 })),
6656 }
6657 };
6658
6659 let Some(transaction) = client.request(request).await?.transaction else {
6660 return Ok(None);
6661 };
6662
6663 let transaction = language::proto::deserialize_transaction(transaction)?;
6664 buffer_handle
6665 .update(cx, |buffer, _| {
6666 buffer.wait_for_edits(transaction.edit_ids.iter().copied())
6667 })
6668 .await?;
6669 if push_to_history {
6670 buffer_handle.update(cx, |buffer, _| {
6671 buffer.push_transaction(transaction.clone(), Instant::now());
6672 buffer.finalize_last_transaction();
6673 });
6674 }
6675 Ok(Some(transaction))
6676 })
6677 } else {
6678 let request_timeout = ProjectSettings::get_global(cx)
6679 .global_lsp_settings
6680 .get_request_timeout();
6681
6682 let Some(server) = buffer_handle.update(cx, |buffer, cx| {
6683 let completion = &completions.borrow()[completion_index];
6684 let server_id = completion.source.server_id()?;
6685 Some(
6686 self.language_server_for_local_buffer(buffer, server_id, cx)?
6687 .1
6688 .clone(),
6689 )
6690 }) else {
6691 return Task::ready(Ok(None));
6692 };
6693
6694 cx.spawn(async move |this, cx| {
6695 Self::resolve_completion_local(
6696 server.clone(),
6697 completions.clone(),
6698 completion_index,
6699 request_timeout,
6700 )
6701 .await
6702 .context("resolving completion")?;
6703 let completion = completions.borrow()[completion_index].clone();
6704 let additional_text_edits = completion
6705 .source
6706 .lsp_completion(true)
6707 .as_ref()
6708 .and_then(|lsp_completion| lsp_completion.additional_text_edits.clone());
6709 if let Some(edits) = additional_text_edits {
6710 let edits = this
6711 .update(cx, |this, cx| {
6712 this.as_local_mut().unwrap().edits_from_lsp(
6713 &buffer_handle,
6714 edits,
6715 server.server_id(),
6716 None,
6717 cx,
6718 )
6719 })?
6720 .await?;
6721
6722 buffer_handle.update(cx, |buffer, cx| {
6723 buffer.finalize_last_transaction();
6724 buffer.start_transaction();
6725
6726 for (range, text) in edits {
6727 let primary = &completion.replace_range;
6728
6729 // Special case: if both ranges start at the very beginning of the file (line 0, column 0),
6730 // and the primary completion is just an insertion (empty range), then this is likely
6731 // an auto-import scenario and should not be considered overlapping
6732 // https://github.com/zed-industries/zed/issues/26136
6733 let is_file_start_auto_import = {
6734 let snapshot = buffer.snapshot();
6735 let primary_start_point = primary.start.to_point(&snapshot);
6736 let range_start_point = range.start.to_point(&snapshot);
6737
6738 let result = primary_start_point.row == 0
6739 && primary_start_point.column == 0
6740 && range_start_point.row == 0
6741 && range_start_point.column == 0;
6742
6743 result
6744 };
6745
6746 let has_overlap = if is_file_start_auto_import {
6747 false
6748 } else {
6749 let start_within = primary.start.cmp(&range.start, buffer).is_le()
6750 && primary.end.cmp(&range.start, buffer).is_ge();
6751 let end_within = range.start.cmp(&primary.end, buffer).is_le()
6752 && range.end.cmp(&primary.end, buffer).is_ge();
6753 let result = start_within || end_within;
6754 result
6755 };
6756
6757 //Skip additional edits which overlap with the primary completion edit
6758 //https://github.com/zed-industries/zed/pull/1871
6759 if !has_overlap {
6760 buffer.edit([(range, text)], None, cx);
6761 }
6762 }
6763
6764 let transaction = if buffer.end_transaction(cx).is_some() {
6765 let transaction = buffer.finalize_last_transaction().unwrap().clone();
6766 if !push_to_history {
6767 buffer.forget_transaction(transaction.id);
6768 }
6769 Some(transaction)
6770 } else {
6771 None
6772 };
6773 Ok(transaction)
6774 })
6775 } else {
6776 Ok(None)
6777 }
6778 })
6779 }
6780 }
6781
6782 pub fn pull_diagnostics(
6783 &mut self,
6784 buffer: Entity<Buffer>,
6785 cx: &mut Context<Self>,
6786 ) -> Task<Result<Option<Vec<LspPullDiagnostics>>>> {
6787 let buffer_id = buffer.read(cx).remote_id();
6788
6789 if let Some((client, upstream_project_id)) = self.upstream_client() {
6790 let mut suitable_capabilities = None;
6791 // Are we capable for proto request?
6792 let any_server_has_diagnostics_provider = self.check_if_capable_for_proto_request(
6793 &buffer,
6794 |capabilities| {
6795 if let Some(caps) = &capabilities.diagnostic_provider {
6796 suitable_capabilities = Some(caps.clone());
6797 true
6798 } else {
6799 false
6800 }
6801 },
6802 cx,
6803 );
6804 // We don't really care which caps are passed into the request, as they're ignored by RPC anyways.
6805 let Some(dynamic_caps) = suitable_capabilities else {
6806 return Task::ready(Ok(None));
6807 };
6808 assert!(any_server_has_diagnostics_provider);
6809
6810 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6811 let request = GetDocumentDiagnostics {
6812 previous_result_id: None,
6813 identifier,
6814 registration_id: None,
6815 };
6816 let request_timeout = ProjectSettings::get_global(cx)
6817 .global_lsp_settings
6818 .get_request_timeout();
6819 let request_task = client.request_lsp(
6820 upstream_project_id,
6821 None,
6822 request_timeout,
6823 cx.background_executor().clone(),
6824 request.to_proto(upstream_project_id, buffer.read(cx)),
6825 );
6826 cx.background_spawn(async move {
6827 // Proto requests cause the diagnostics to be pulled from language server(s) on the local side
6828 // and then, buffer state updated with the diagnostics received, which will be later propagated to the client.
6829 // Do not attempt to further process the dummy responses here.
6830 let _response = request_task.await?;
6831 Ok(None)
6832 })
6833 } else {
6834 let servers = buffer.update(cx, |buffer, cx| {
6835 self.running_language_servers_for_local_buffer(buffer, cx)
6836 .map(|(_, server)| server.clone())
6837 .collect::<Vec<_>>()
6838 });
6839
6840 let pull_diagnostics = servers
6841 .into_iter()
6842 .flat_map(|server| {
6843 let result = maybe!({
6844 let local = self.as_local()?;
6845 let server_id = server.server_id();
6846 let providers_with_identifiers = local
6847 .language_server_dynamic_registrations
6848 .get(&server_id)
6849 .into_iter()
6850 .flat_map(|registrations| registrations.diagnostics.clone())
6851 .collect::<Vec<_>>();
6852 Some(
6853 providers_with_identifiers
6854 .into_iter()
6855 .map(|(registration_id, dynamic_caps)| {
6856 let identifier = buffer_diagnostic_identifier(&dynamic_caps);
6857 let registration_id = registration_id.map(SharedString::from);
6858 let result_id = self.result_id_for_buffer_pull(
6859 server_id,
6860 buffer_id,
6861 ®istration_id,
6862 cx,
6863 );
6864 self.request_lsp(
6865 buffer.clone(),
6866 LanguageServerToQuery::Other(server_id),
6867 GetDocumentDiagnostics {
6868 previous_result_id: result_id,
6869 registration_id,
6870 identifier,
6871 },
6872 cx,
6873 )
6874 })
6875 .collect::<Vec<_>>(),
6876 )
6877 });
6878
6879 result.unwrap_or_default()
6880 })
6881 .collect::<Vec<_>>();
6882
6883 cx.background_spawn(async move {
6884 let mut responses = Vec::new();
6885 for diagnostics in join_all(pull_diagnostics).await {
6886 responses.extend(diagnostics?);
6887 }
6888 Ok(Some(responses))
6889 })
6890 }
6891 }
6892
6893 pub fn applicable_inlay_chunks(
6894 &mut self,
6895 buffer: &Entity<Buffer>,
6896 ranges: &[Range<text::Anchor>],
6897 cx: &mut Context<Self>,
6898 ) -> Vec<Range<BufferRow>> {
6899 let buffer_snapshot = buffer.read(cx).snapshot();
6900 let ranges = ranges
6901 .iter()
6902 .map(|range| range.to_point(&buffer_snapshot))
6903 .collect::<Vec<_>>();
6904
6905 self.latest_lsp_data(buffer, cx)
6906 .inlay_hints
6907 .applicable_chunks(ranges.as_slice())
6908 .map(|chunk| chunk.row_range())
6909 .collect()
6910 }
6911
6912 pub fn invalidate_inlay_hints<'a>(
6913 &'a mut self,
6914 for_buffers: impl IntoIterator<Item = &'a BufferId> + 'a,
6915 ) {
6916 for buffer_id in for_buffers {
6917 if let Some(lsp_data) = self.lsp_data.get_mut(buffer_id) {
6918 lsp_data.inlay_hints.clear();
6919 }
6920 }
6921 }
6922
6923 pub fn inlay_hints(
6924 &mut self,
6925 invalidate: InvalidationStrategy,
6926 buffer: Entity<Buffer>,
6927 ranges: Vec<Range<text::Anchor>>,
6928 known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
6929 cx: &mut Context<Self>,
6930 ) -> HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>> {
6931 let next_hint_id = self.next_hint_id.clone();
6932 let lsp_data = self.latest_lsp_data(&buffer, cx);
6933 let query_version = lsp_data.buffer_version.clone();
6934 let mut lsp_refresh_requested = false;
6935 let for_server = if let InvalidationStrategy::RefreshRequested {
6936 server_id,
6937 request_id,
6938 } = invalidate
6939 {
6940 let invalidated = lsp_data
6941 .inlay_hints
6942 .invalidate_for_server_refresh(server_id, request_id);
6943 lsp_refresh_requested = invalidated;
6944 Some(server_id)
6945 } else {
6946 None
6947 };
6948 let existing_inlay_hints = &mut lsp_data.inlay_hints;
6949 let known_chunks = known_chunks
6950 .filter(|(known_version, _)| !lsp_data.buffer_version.changed_since(known_version))
6951 .map(|(_, known_chunks)| known_chunks)
6952 .unwrap_or_default();
6953
6954 let buffer_snapshot = buffer.read(cx).snapshot();
6955 let ranges = ranges
6956 .iter()
6957 .map(|range| range.to_point(&buffer_snapshot))
6958 .collect::<Vec<_>>();
6959
6960 let mut hint_fetch_tasks = Vec::new();
6961 let mut cached_inlay_hints = None;
6962 let mut ranges_to_query = None;
6963 let applicable_chunks = existing_inlay_hints
6964 .applicable_chunks(ranges.as_slice())
6965 .filter(|chunk| !known_chunks.contains(&chunk.row_range()))
6966 .collect::<Vec<_>>();
6967 if applicable_chunks.is_empty() {
6968 return HashMap::default();
6969 }
6970
6971 for row_chunk in applicable_chunks {
6972 match (
6973 existing_inlay_hints
6974 .cached_hints(&row_chunk)
6975 .filter(|_| !lsp_refresh_requested)
6976 .cloned(),
6977 existing_inlay_hints
6978 .fetched_hints(&row_chunk)
6979 .as_ref()
6980 .filter(|_| !lsp_refresh_requested)
6981 .cloned(),
6982 ) {
6983 (None, None) => {
6984 let chunk_range = row_chunk.anchor_range();
6985 ranges_to_query
6986 .get_or_insert_with(Vec::new)
6987 .push((row_chunk, chunk_range));
6988 }
6989 (None, Some(fetched_hints)) => hint_fetch_tasks.push((row_chunk, fetched_hints)),
6990 (Some(cached_hints), None) => {
6991 for (server_id, cached_hints) in cached_hints {
6992 if for_server.is_none_or(|for_server| for_server == server_id) {
6993 cached_inlay_hints
6994 .get_or_insert_with(HashMap::default)
6995 .entry(row_chunk.row_range())
6996 .or_insert_with(HashMap::default)
6997 .entry(server_id)
6998 .or_insert_with(Vec::new)
6999 .extend(cached_hints);
7000 }
7001 }
7002 }
7003 (Some(cached_hints), Some(fetched_hints)) => {
7004 hint_fetch_tasks.push((row_chunk, fetched_hints));
7005 for (server_id, cached_hints) in cached_hints {
7006 if for_server.is_none_or(|for_server| for_server == server_id) {
7007 cached_inlay_hints
7008 .get_or_insert_with(HashMap::default)
7009 .entry(row_chunk.row_range())
7010 .or_insert_with(HashMap::default)
7011 .entry(server_id)
7012 .or_insert_with(Vec::new)
7013 .extend(cached_hints);
7014 }
7015 }
7016 }
7017 }
7018 }
7019
7020 if hint_fetch_tasks.is_empty()
7021 && ranges_to_query
7022 .as_ref()
7023 .is_none_or(|ranges| ranges.is_empty())
7024 && let Some(cached_inlay_hints) = cached_inlay_hints
7025 {
7026 cached_inlay_hints
7027 .into_iter()
7028 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7029 .collect()
7030 } else {
7031 for (chunk, range_to_query) in ranges_to_query.into_iter().flatten() {
7032 let next_hint_id = next_hint_id.clone();
7033 let buffer = buffer.clone();
7034 let query_version = query_version.clone();
7035 let new_inlay_hints = cx
7036 .spawn(async move |lsp_store, cx| {
7037 let new_fetch_task = lsp_store.update(cx, |lsp_store, cx| {
7038 lsp_store.fetch_inlay_hints(for_server, &buffer, range_to_query, cx)
7039 })?;
7040 new_fetch_task
7041 .await
7042 .and_then(|new_hints_by_server| {
7043 lsp_store.update(cx, |lsp_store, cx| {
7044 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
7045 let update_cache = lsp_data.buffer_version == query_version;
7046 if new_hints_by_server.is_empty() {
7047 if update_cache {
7048 lsp_data.inlay_hints.invalidate_for_chunk(chunk);
7049 }
7050 HashMap::default()
7051 } else {
7052 new_hints_by_server
7053 .into_iter()
7054 .map(|(server_id, new_hints)| {
7055 let new_hints = new_hints
7056 .into_iter()
7057 .map(|new_hint| {
7058 (
7059 InlayId::Hint(next_hint_id.fetch_add(
7060 1,
7061 atomic::Ordering::AcqRel,
7062 )),
7063 new_hint,
7064 )
7065 })
7066 .collect::<Vec<_>>();
7067 if update_cache {
7068 lsp_data.inlay_hints.insert_new_hints(
7069 chunk,
7070 server_id,
7071 new_hints.clone(),
7072 );
7073 }
7074 (server_id, new_hints)
7075 })
7076 .collect()
7077 }
7078 })
7079 })
7080 .map_err(Arc::new)
7081 })
7082 .shared();
7083
7084 let fetch_task = lsp_data.inlay_hints.fetched_hints(&chunk);
7085 *fetch_task = Some(new_inlay_hints.clone());
7086 hint_fetch_tasks.push((chunk, new_inlay_hints));
7087 }
7088
7089 cached_inlay_hints
7090 .unwrap_or_default()
7091 .into_iter()
7092 .map(|(row_chunk, hints)| (row_chunk, Task::ready(Ok(hints))))
7093 .chain(hint_fetch_tasks.into_iter().map(|(chunk, hints_fetch)| {
7094 (
7095 chunk.row_range(),
7096 cx.spawn(async move |_, _| {
7097 hints_fetch.await.map_err(|e| {
7098 if e.error_code() != ErrorCode::Internal {
7099 anyhow!(e.error_code())
7100 } else {
7101 anyhow!("{e:#}")
7102 }
7103 })
7104 }),
7105 )
7106 }))
7107 .collect()
7108 }
7109 }
7110
7111 fn fetch_inlay_hints(
7112 &mut self,
7113 for_server: Option<LanguageServerId>,
7114 buffer: &Entity<Buffer>,
7115 range: Range<Anchor>,
7116 cx: &mut Context<Self>,
7117 ) -> Task<Result<HashMap<LanguageServerId, Vec<InlayHint>>>> {
7118 let request = InlayHints {
7119 range: range.clone(),
7120 };
7121 if let Some((upstream_client, project_id)) = self.upstream_client() {
7122 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7123 return Task::ready(Ok(HashMap::default()));
7124 }
7125 let request_timeout = ProjectSettings::get_global(cx)
7126 .global_lsp_settings
7127 .get_request_timeout();
7128 let request_task = upstream_client.request_lsp(
7129 project_id,
7130 for_server.map(|id| id.to_proto()),
7131 request_timeout,
7132 cx.background_executor().clone(),
7133 request.to_proto(project_id, buffer.read(cx)),
7134 );
7135 let buffer = buffer.clone();
7136 cx.spawn(async move |weak_lsp_store, cx| {
7137 let Some(lsp_store) = weak_lsp_store.upgrade() else {
7138 return Ok(HashMap::default());
7139 };
7140 let Some(responses) = request_task.await? else {
7141 return Ok(HashMap::default());
7142 };
7143
7144 let inlay_hints = join_all(responses.payload.into_iter().map(|response| {
7145 let lsp_store = lsp_store.clone();
7146 let buffer = buffer.clone();
7147 let cx = cx.clone();
7148 let request = request.clone();
7149 async move {
7150 (
7151 LanguageServerId::from_proto(response.server_id),
7152 request
7153 .response_from_proto(response.response, lsp_store, buffer, cx)
7154 .await,
7155 )
7156 }
7157 }))
7158 .await;
7159
7160 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7161 let mut has_errors = false;
7162 let inlay_hints = inlay_hints
7163 .into_iter()
7164 .filter_map(|(server_id, inlay_hints)| match inlay_hints {
7165 Ok(inlay_hints) => Some((server_id, inlay_hints)),
7166 Err(e) => {
7167 has_errors = true;
7168 log::error!("{e:#}");
7169 None
7170 }
7171 })
7172 .map(|(server_id, mut new_hints)| {
7173 new_hints.retain(|hint| {
7174 hint.position.is_valid(&buffer_snapshot)
7175 && range.start.is_valid(&buffer_snapshot)
7176 && range.end.is_valid(&buffer_snapshot)
7177 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7178 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7179 });
7180 (server_id, new_hints)
7181 })
7182 .collect::<HashMap<_, _>>();
7183 anyhow::ensure!(
7184 !has_errors || !inlay_hints.is_empty(),
7185 "Failed to fetch inlay hints"
7186 );
7187 Ok(inlay_hints)
7188 })
7189 } else {
7190 let inlay_hints_task = match for_server {
7191 Some(server_id) => {
7192 let server_task = self.request_lsp(
7193 buffer.clone(),
7194 LanguageServerToQuery::Other(server_id),
7195 request,
7196 cx,
7197 );
7198 cx.background_spawn(async move {
7199 let mut responses = Vec::new();
7200 match server_task.await {
7201 Ok(response) => responses.push((server_id, response)),
7202 // rust-analyzer likes to error with this when its still loading up
7203 Err(e) if format!("{e:#}").ends_with("content modified") => (),
7204 Err(e) => log::error!(
7205 "Error handling response for inlay hints request: {e:#}"
7206 ),
7207 }
7208 responses
7209 })
7210 }
7211 None => self.request_multiple_lsp_locally(buffer, None::<usize>, request, cx),
7212 };
7213 let buffer_snapshot = buffer.read_with(cx, |buffer, _| buffer.snapshot());
7214 cx.background_spawn(async move {
7215 Ok(inlay_hints_task
7216 .await
7217 .into_iter()
7218 .map(|(server_id, mut new_hints)| {
7219 new_hints.retain(|hint| {
7220 hint.position.is_valid(&buffer_snapshot)
7221 && range.start.is_valid(&buffer_snapshot)
7222 && range.end.is_valid(&buffer_snapshot)
7223 && hint.position.cmp(&range.start, &buffer_snapshot).is_ge()
7224 && hint.position.cmp(&range.end, &buffer_snapshot).is_lt()
7225 });
7226 (server_id, new_hints)
7227 })
7228 .collect())
7229 })
7230 }
7231 }
7232
7233 fn diagnostic_registration_exists(
7234 &self,
7235 server_id: LanguageServerId,
7236 registration_id: &Option<SharedString>,
7237 ) -> bool {
7238 let Some(local) = self.as_local() else {
7239 return false;
7240 };
7241 let Some(registrations) = local.language_server_dynamic_registrations.get(&server_id)
7242 else {
7243 return false;
7244 };
7245 let registration_key = registration_id.as_ref().map(|s| s.to_string());
7246 registrations.diagnostics.contains_key(®istration_key)
7247 }
7248
7249 pub fn pull_diagnostics_for_buffer(
7250 &mut self,
7251 buffer: Entity<Buffer>,
7252 cx: &mut Context<Self>,
7253 ) -> Task<anyhow::Result<()>> {
7254 let diagnostics = self.pull_diagnostics(buffer, cx);
7255 cx.spawn(async move |lsp_store, cx| {
7256 let Some(diagnostics) = diagnostics.await.context("pulling diagnostics")? else {
7257 return Ok(());
7258 };
7259 lsp_store.update(cx, |lsp_store, cx| {
7260 if lsp_store.as_local().is_none() {
7261 return;
7262 }
7263
7264 let mut unchanged_buffers = HashMap::default();
7265 let server_diagnostics_updates = diagnostics
7266 .into_iter()
7267 .filter_map(|diagnostics_set| match diagnostics_set {
7268 LspPullDiagnostics::Response {
7269 server_id,
7270 uri,
7271 diagnostics,
7272 registration_id,
7273 } => Some((server_id, uri, diagnostics, registration_id)),
7274 LspPullDiagnostics::Default => None,
7275 })
7276 .filter(|(server_id, _, _, registration_id)| {
7277 lsp_store.diagnostic_registration_exists(*server_id, registration_id)
7278 })
7279 .fold(
7280 HashMap::default(),
7281 |mut acc, (server_id, uri, diagnostics, new_registration_id)| {
7282 let (result_id, diagnostics) = match diagnostics {
7283 PulledDiagnostics::Unchanged { result_id } => {
7284 unchanged_buffers
7285 .entry(new_registration_id.clone())
7286 .or_insert_with(HashSet::default)
7287 .insert(uri.clone());
7288 (Some(result_id), Vec::new())
7289 }
7290 PulledDiagnostics::Changed {
7291 result_id,
7292 diagnostics,
7293 } => (result_id, diagnostics),
7294 };
7295 let disk_based_sources = Cow::Owned(
7296 lsp_store
7297 .language_server_adapter_for_id(server_id)
7298 .as_ref()
7299 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
7300 .unwrap_or(&[])
7301 .to_vec(),
7302 );
7303 acc.entry(server_id)
7304 .or_insert_with(HashMap::default)
7305 .entry(new_registration_id.clone())
7306 .or_insert_with(Vec::new)
7307 .push(DocumentDiagnosticsUpdate {
7308 server_id,
7309 diagnostics: lsp::PublishDiagnosticsParams {
7310 uri,
7311 diagnostics,
7312 version: None,
7313 },
7314 result_id: result_id.map(SharedString::new),
7315 disk_based_sources,
7316 registration_id: new_registration_id,
7317 });
7318 acc
7319 },
7320 );
7321
7322 for diagnostic_updates in server_diagnostics_updates.into_values() {
7323 for (registration_id, diagnostic_updates) in diagnostic_updates {
7324 lsp_store
7325 .merge_lsp_diagnostics(
7326 DiagnosticSourceKind::Pulled,
7327 diagnostic_updates,
7328 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
7329 DiagnosticSourceKind::Pulled => {
7330 old_diagnostic.registration_id != registration_id
7331 || unchanged_buffers
7332 .get(&old_diagnostic.registration_id)
7333 .is_some_and(|unchanged_buffers| {
7334 unchanged_buffers.contains(&document_uri)
7335 })
7336 }
7337 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => {
7338 true
7339 }
7340 },
7341 cx,
7342 )
7343 .log_err();
7344 }
7345 }
7346 })
7347 })
7348 }
7349
7350 pub fn signature_help<T: ToPointUtf16>(
7351 &mut self,
7352 buffer: &Entity<Buffer>,
7353 position: T,
7354 cx: &mut Context<Self>,
7355 ) -> Task<Option<Vec<SignatureHelp>>> {
7356 let position = position.to_point_utf16(buffer.read(cx));
7357
7358 if let Some((client, upstream_project_id)) = self.upstream_client() {
7359 let request = GetSignatureHelp { position };
7360 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7361 return Task::ready(None);
7362 }
7363 let request_timeout = ProjectSettings::get_global(cx)
7364 .global_lsp_settings
7365 .get_request_timeout();
7366 let request_task = client.request_lsp(
7367 upstream_project_id,
7368 None,
7369 request_timeout,
7370 cx.background_executor().clone(),
7371 request.to_proto(upstream_project_id, buffer.read(cx)),
7372 );
7373 let buffer = buffer.clone();
7374 cx.spawn(async move |weak_lsp_store, cx| {
7375 let lsp_store = weak_lsp_store.upgrade()?;
7376 let signatures = join_all(
7377 request_task
7378 .await
7379 .log_err()
7380 .flatten()
7381 .map(|response| response.payload)
7382 .unwrap_or_default()
7383 .into_iter()
7384 .map(|response| {
7385 let response = GetSignatureHelp { position }.response_from_proto(
7386 response.response,
7387 lsp_store.clone(),
7388 buffer.clone(),
7389 cx.clone(),
7390 );
7391 async move { response.await.log_err().flatten() }
7392 }),
7393 )
7394 .await
7395 .into_iter()
7396 .flatten()
7397 .collect();
7398 Some(signatures)
7399 })
7400 } else {
7401 let all_actions_task = self.request_multiple_lsp_locally(
7402 buffer,
7403 Some(position),
7404 GetSignatureHelp { position },
7405 cx,
7406 );
7407 cx.background_spawn(async move {
7408 Some(
7409 all_actions_task
7410 .await
7411 .into_iter()
7412 .flat_map(|(_, actions)| actions)
7413 .collect::<Vec<_>>(),
7414 )
7415 })
7416 }
7417 }
7418
7419 pub fn hover(
7420 &mut self,
7421 buffer: &Entity<Buffer>,
7422 position: PointUtf16,
7423 cx: &mut Context<Self>,
7424 ) -> Task<Option<Vec<Hover>>> {
7425 if let Some((client, upstream_project_id)) = self.upstream_client() {
7426 let request = GetHover { position };
7427 if !self.is_capable_for_proto_request(buffer, &request, cx) {
7428 return Task::ready(None);
7429 }
7430 let request_timeout = ProjectSettings::get_global(cx)
7431 .global_lsp_settings
7432 .get_request_timeout();
7433 let request_task = client.request_lsp(
7434 upstream_project_id,
7435 None,
7436 request_timeout,
7437 cx.background_executor().clone(),
7438 request.to_proto(upstream_project_id, buffer.read(cx)),
7439 );
7440 let buffer = buffer.clone();
7441 cx.spawn(async move |weak_lsp_store, cx| {
7442 let lsp_store = weak_lsp_store.upgrade()?;
7443 let hovers = join_all(
7444 request_task
7445 .await
7446 .log_err()
7447 .flatten()
7448 .map(|response| response.payload)
7449 .unwrap_or_default()
7450 .into_iter()
7451 .map(|response| {
7452 let response = GetHover { position }.response_from_proto(
7453 response.response,
7454 lsp_store.clone(),
7455 buffer.clone(),
7456 cx.clone(),
7457 );
7458 async move {
7459 response
7460 .await
7461 .log_err()
7462 .flatten()
7463 .and_then(remove_empty_hover_blocks)
7464 }
7465 }),
7466 )
7467 .await
7468 .into_iter()
7469 .flatten()
7470 .collect();
7471 Some(hovers)
7472 })
7473 } else {
7474 let all_actions_task = self.request_multiple_lsp_locally(
7475 buffer,
7476 Some(position),
7477 GetHover { position },
7478 cx,
7479 );
7480 cx.background_spawn(async move {
7481 Some(
7482 all_actions_task
7483 .await
7484 .into_iter()
7485 .filter_map(|(_, hover)| remove_empty_hover_blocks(hover?))
7486 .collect::<Vec<Hover>>(),
7487 )
7488 })
7489 }
7490 }
7491
7492 pub fn symbols(&self, query: &str, cx: &mut Context<Self>) -> Task<Result<Vec<Symbol>>> {
7493 let language_registry = self.languages.clone();
7494
7495 if let Some((upstream_client, project_id)) = self.upstream_client().as_ref() {
7496 let request = upstream_client.request(proto::GetProjectSymbols {
7497 project_id: *project_id,
7498 query: query.to_string(),
7499 });
7500 cx.foreground_executor().spawn(async move {
7501 let response = request.await?;
7502 let mut symbols = Vec::new();
7503 let core_symbols = response
7504 .symbols
7505 .into_iter()
7506 .filter_map(|symbol| Self::deserialize_symbol(symbol).log_err())
7507 .collect::<Vec<_>>();
7508 populate_labels_for_symbols(core_symbols, &language_registry, None, &mut symbols)
7509 .await;
7510 Ok(symbols)
7511 })
7512 } else if let Some(local) = self.as_local() {
7513 struct WorkspaceSymbolsResult {
7514 server_id: LanguageServerId,
7515 lsp_adapter: Arc<CachedLspAdapter>,
7516 worktree: WeakEntity<Worktree>,
7517 lsp_symbols: Vec<(String, SymbolKind, lsp::Location, Option<String>)>,
7518 }
7519
7520 let mut requests = Vec::new();
7521 let mut requested_servers = BTreeSet::new();
7522 let request_timeout = ProjectSettings::get_global(cx)
7523 .global_lsp_settings
7524 .get_request_timeout();
7525
7526 for (seed, state) in local.language_server_ids.iter() {
7527 let Some(worktree_handle) = self
7528 .worktree_store
7529 .read(cx)
7530 .worktree_for_id(seed.worktree_id, cx)
7531 else {
7532 continue;
7533 };
7534
7535 let worktree = worktree_handle.read(cx);
7536 if !worktree.is_visible() {
7537 continue;
7538 }
7539
7540 if !requested_servers.insert(state.id) {
7541 continue;
7542 }
7543
7544 let (lsp_adapter, server) = match local.language_servers.get(&state.id) {
7545 Some(LanguageServerState::Running {
7546 adapter, server, ..
7547 }) => (adapter.clone(), server),
7548
7549 _ => continue,
7550 };
7551
7552 let supports_workspace_symbol_request =
7553 match server.capabilities().workspace_symbol_provider {
7554 Some(OneOf::Left(supported)) => supported,
7555 Some(OneOf::Right(_)) => true,
7556 None => false,
7557 };
7558
7559 if !supports_workspace_symbol_request {
7560 continue;
7561 }
7562
7563 let worktree_handle = worktree_handle.clone();
7564 let server_id = server.server_id();
7565 requests.push(
7566 server
7567 .request::<lsp::request::WorkspaceSymbolRequest>(
7568 lsp::WorkspaceSymbolParams {
7569 query: query.to_string(),
7570 ..Default::default()
7571 },
7572 request_timeout,
7573 )
7574 .map(move |response| {
7575 let lsp_symbols = response
7576 .into_response()
7577 .context("workspace symbols request")
7578 .log_err()
7579 .flatten()
7580 .map(|symbol_response| match symbol_response {
7581 lsp::WorkspaceSymbolResponse::Flat(flat_responses) => {
7582 flat_responses
7583 .into_iter()
7584 .map(|lsp_symbol| {
7585 (
7586 lsp_symbol.name,
7587 lsp_symbol.kind,
7588 lsp_symbol.location,
7589 lsp_symbol.container_name,
7590 )
7591 })
7592 .collect::<Vec<_>>()
7593 }
7594 lsp::WorkspaceSymbolResponse::Nested(nested_responses) => {
7595 nested_responses
7596 .into_iter()
7597 .filter_map(|lsp_symbol| {
7598 let location = match lsp_symbol.location {
7599 OneOf::Left(location) => location,
7600 OneOf::Right(_) => {
7601 log::error!(
7602 "Unexpected: client capabilities \
7603 forbid symbol resolutions in \
7604 workspace.symbol.resolveSupport"
7605 );
7606 return None;
7607 }
7608 };
7609 Some((
7610 lsp_symbol.name,
7611 lsp_symbol.kind,
7612 location,
7613 lsp_symbol.container_name,
7614 ))
7615 })
7616 .collect::<Vec<_>>()
7617 }
7618 })
7619 .unwrap_or_default();
7620
7621 WorkspaceSymbolsResult {
7622 server_id,
7623 lsp_adapter,
7624 worktree: worktree_handle.downgrade(),
7625 lsp_symbols,
7626 }
7627 }),
7628 );
7629 }
7630
7631 cx.spawn(async move |this, cx| {
7632 let responses = futures::future::join_all(requests).await;
7633 let this = match this.upgrade() {
7634 Some(this) => this,
7635 None => return Ok(Vec::new()),
7636 };
7637
7638 let mut symbols = Vec::new();
7639 for result in responses {
7640 let core_symbols = this.update(cx, |this, cx| {
7641 result
7642 .lsp_symbols
7643 .into_iter()
7644 .filter_map(
7645 |(symbol_name, symbol_kind, symbol_location, container_name)| {
7646 let abs_path = symbol_location.uri.to_file_path().ok()?;
7647 let source_worktree = result.worktree.upgrade()?;
7648 let source_worktree_id = source_worktree.read(cx).id();
7649
7650 let path = if let Some((tree, rel_path)) =
7651 this.worktree_store.read(cx).find_worktree(&abs_path, cx)
7652 {
7653 let worktree_id = tree.read(cx).id();
7654 SymbolLocation::InProject(ProjectPath {
7655 worktree_id,
7656 path: rel_path,
7657 })
7658 } else {
7659 SymbolLocation::OutsideProject {
7660 signature: this.symbol_signature(&abs_path),
7661 abs_path: abs_path.into(),
7662 }
7663 };
7664
7665 Some(CoreSymbol {
7666 source_language_server_id: result.server_id,
7667 language_server_name: result.lsp_adapter.name.clone(),
7668 source_worktree_id,
7669 path,
7670 kind: symbol_kind,
7671 name: symbol_name,
7672 range: range_from_lsp(symbol_location.range),
7673 container_name,
7674 })
7675 },
7676 )
7677 .collect::<Vec<_>>()
7678 });
7679
7680 populate_labels_for_symbols(
7681 core_symbols,
7682 &language_registry,
7683 Some(result.lsp_adapter),
7684 &mut symbols,
7685 )
7686 .await;
7687 }
7688
7689 Ok(symbols)
7690 })
7691 } else {
7692 Task::ready(Err(anyhow!("No upstream client or local language server")))
7693 }
7694 }
7695
7696 pub fn diagnostic_summary(&self, include_ignored: bool, cx: &App) -> DiagnosticSummary {
7697 let mut summary = DiagnosticSummary::default();
7698 for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
7699 summary.error_count += path_summary.error_count;
7700 summary.warning_count += path_summary.warning_count;
7701 }
7702 summary
7703 }
7704
7705 /// Returns the diagnostic summary for a specific project path.
7706 pub fn diagnostic_summary_for_path(
7707 &self,
7708 project_path: &ProjectPath,
7709 _: &App,
7710 ) -> DiagnosticSummary {
7711 if let Some(summaries) = self
7712 .diagnostic_summaries
7713 .get(&project_path.worktree_id)
7714 .and_then(|map| map.get(&project_path.path))
7715 {
7716 let (error_count, warning_count) = summaries.iter().fold(
7717 (0, 0),
7718 |(error_count, warning_count), (_language_server_id, summary)| {
7719 (
7720 error_count + summary.error_count,
7721 warning_count + summary.warning_count,
7722 )
7723 },
7724 );
7725
7726 DiagnosticSummary {
7727 error_count,
7728 warning_count,
7729 }
7730 } else {
7731 DiagnosticSummary::default()
7732 }
7733 }
7734
7735 pub fn diagnostic_summaries<'a>(
7736 &'a self,
7737 include_ignored: bool,
7738 cx: &'a App,
7739 ) -> impl Iterator<Item = (ProjectPath, LanguageServerId, DiagnosticSummary)> + 'a {
7740 self.worktree_store
7741 .read(cx)
7742 .visible_worktrees(cx)
7743 .filter_map(|worktree| {
7744 let worktree = worktree.read(cx);
7745 Some((worktree, self.diagnostic_summaries.get(&worktree.id())?))
7746 })
7747 .flat_map(move |(worktree, summaries)| {
7748 let worktree_id = worktree.id();
7749 summaries
7750 .iter()
7751 .filter(move |(path, _)| {
7752 include_ignored
7753 || worktree
7754 .entry_for_path(path.as_ref())
7755 .is_some_and(|entry| !entry.is_ignored)
7756 })
7757 .flat_map(move |(path, summaries)| {
7758 summaries.iter().map(move |(server_id, summary)| {
7759 (
7760 ProjectPath {
7761 worktree_id,
7762 path: path.clone(),
7763 },
7764 *server_id,
7765 *summary,
7766 )
7767 })
7768 })
7769 })
7770 }
7771
7772 pub fn on_buffer_edited(
7773 &mut self,
7774 buffer: Entity<Buffer>,
7775 cx: &mut Context<Self>,
7776 ) -> Option<()> {
7777 let language_servers: Vec<_> = buffer.update(cx, |buffer, cx| {
7778 Some(
7779 self.as_local()?
7780 .language_servers_for_buffer(buffer, cx)
7781 .map(|i| i.1.clone())
7782 .collect(),
7783 )
7784 })?;
7785
7786 let buffer = buffer.read(cx);
7787 let file = File::from_dyn(buffer.file())?;
7788 let abs_path = file.as_local()?.abs_path(cx);
7789 let uri = lsp::Uri::from_file_path(&abs_path)
7790 .ok()
7791 .with_context(|| format!("Failed to convert path to URI: {}", abs_path.display()))
7792 .log_err()?;
7793 let next_snapshot = buffer.text_snapshot();
7794 for language_server in language_servers {
7795 let language_server = language_server.clone();
7796
7797 let buffer_snapshots = self
7798 .as_local_mut()?
7799 .buffer_snapshots
7800 .get_mut(&buffer.remote_id())
7801 .and_then(|m| m.get_mut(&language_server.server_id()))?;
7802 let previous_snapshot = buffer_snapshots.last()?;
7803
7804 let build_incremental_change = || {
7805 buffer
7806 .edits_since::<Dimensions<PointUtf16, usize>>(
7807 previous_snapshot.snapshot.version(),
7808 )
7809 .map(|edit| {
7810 let edit_start = edit.new.start.0;
7811 let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
7812 let new_text = next_snapshot
7813 .text_for_range(edit.new.start.1..edit.new.end.1)
7814 .collect();
7815 lsp::TextDocumentContentChangeEvent {
7816 range: Some(lsp::Range::new(
7817 point_to_lsp(edit_start),
7818 point_to_lsp(edit_end),
7819 )),
7820 range_length: None,
7821 text: new_text,
7822 }
7823 })
7824 .collect()
7825 };
7826
7827 let document_sync_kind = language_server
7828 .capabilities()
7829 .text_document_sync
7830 .as_ref()
7831 .and_then(|sync| match sync {
7832 lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
7833 lsp::TextDocumentSyncCapability::Options(options) => options.change,
7834 });
7835
7836 let content_changes: Vec<_> = match document_sync_kind {
7837 Some(lsp::TextDocumentSyncKind::FULL) => {
7838 vec![lsp::TextDocumentContentChangeEvent {
7839 range: None,
7840 range_length: None,
7841 text: next_snapshot.text(),
7842 }]
7843 }
7844 Some(lsp::TextDocumentSyncKind::INCREMENTAL) => build_incremental_change(),
7845 _ => {
7846 #[cfg(any(test, feature = "test-support"))]
7847 {
7848 build_incremental_change()
7849 }
7850
7851 #[cfg(not(any(test, feature = "test-support")))]
7852 {
7853 continue;
7854 }
7855 }
7856 };
7857
7858 let next_version = previous_snapshot.version + 1;
7859 buffer_snapshots.push(LspBufferSnapshot {
7860 version: next_version,
7861 snapshot: next_snapshot.clone(),
7862 });
7863
7864 language_server
7865 .notify::<lsp::notification::DidChangeTextDocument>(
7866 lsp::DidChangeTextDocumentParams {
7867 text_document: lsp::VersionedTextDocumentIdentifier::new(
7868 uri.clone(),
7869 next_version,
7870 ),
7871 content_changes,
7872 },
7873 )
7874 .ok();
7875 self.pull_workspace_diagnostics(language_server.server_id());
7876 }
7877
7878 None
7879 }
7880
7881 pub fn on_buffer_saved(
7882 &mut self,
7883 buffer: Entity<Buffer>,
7884 cx: &mut Context<Self>,
7885 ) -> Option<()> {
7886 let file = File::from_dyn(buffer.read(cx).file())?;
7887 let worktree_id = file.worktree_id(cx);
7888 let abs_path = file.as_local()?.abs_path(cx);
7889 let text_document = lsp::TextDocumentIdentifier {
7890 uri: file_path_to_lsp_url(&abs_path).log_err()?,
7891 };
7892 let local = self.as_local()?;
7893
7894 for server in local.language_servers_for_worktree(worktree_id) {
7895 if let Some(include_text) = include_text(server.as_ref()) {
7896 let text = if include_text {
7897 Some(buffer.read(cx).text())
7898 } else {
7899 None
7900 };
7901 server
7902 .notify::<lsp::notification::DidSaveTextDocument>(
7903 lsp::DidSaveTextDocumentParams {
7904 text_document: text_document.clone(),
7905 text,
7906 },
7907 )
7908 .ok();
7909 }
7910 }
7911
7912 let language_servers = buffer.update(cx, |buffer, cx| {
7913 local.language_server_ids_for_buffer(buffer, cx)
7914 });
7915 for language_server_id in language_servers {
7916 self.simulate_disk_based_diagnostics_events_if_needed(language_server_id, cx);
7917 }
7918
7919 None
7920 }
7921
7922 async fn refresh_workspace_configurations(lsp_store: &WeakEntity<Self>, cx: &mut AsyncApp) {
7923 maybe!(async move {
7924 let mut refreshed_servers = HashSet::default();
7925 let servers = lsp_store
7926 .update(cx, |lsp_store, cx| {
7927 let local = lsp_store.as_local()?;
7928
7929 let servers = local
7930 .language_server_ids
7931 .iter()
7932 .filter_map(|(seed, state)| {
7933 let worktree = lsp_store
7934 .worktree_store
7935 .read(cx)
7936 .worktree_for_id(seed.worktree_id, cx);
7937 let delegate: Arc<dyn LspAdapterDelegate> =
7938 worktree.map(|worktree| {
7939 LocalLspAdapterDelegate::new(
7940 local.languages.clone(),
7941 &local.environment,
7942 cx.weak_entity(),
7943 &worktree,
7944 local.http_client.clone(),
7945 local.fs.clone(),
7946 cx,
7947 )
7948 })?;
7949 let server_id = state.id;
7950
7951 let states = local.language_servers.get(&server_id)?;
7952
7953 match states {
7954 LanguageServerState::Starting { .. } => None,
7955 LanguageServerState::Running {
7956 adapter, server, ..
7957 } => {
7958 let adapter = adapter.clone();
7959 let server = server.clone();
7960 refreshed_servers.insert(server.name());
7961 let toolchain = seed.toolchain.clone();
7962 Some(cx.spawn(async move |_, cx| {
7963 let settings =
7964 LocalLspStore::workspace_configuration_for_adapter(
7965 adapter.adapter.clone(),
7966 &delegate,
7967 toolchain,
7968 None,
7969 cx,
7970 )
7971 .await
7972 .ok()?;
7973 server
7974 .notify::<lsp::notification::DidChangeConfiguration>(
7975 lsp::DidChangeConfigurationParams { settings },
7976 )
7977 .ok()?;
7978 Some(())
7979 }))
7980 }
7981 }
7982 })
7983 .collect::<Vec<_>>();
7984
7985 Some(servers)
7986 })
7987 .ok()
7988 .flatten()?;
7989
7990 log::debug!("Refreshing workspace configurations for servers {refreshed_servers:?}");
7991 // TODO this asynchronous job runs concurrently with extension (de)registration and may take enough time for a certain extension
7992 // to stop and unregister its language server wrapper.
7993 // This is racy : an extension might have already removed all `local.language_servers` state, but here we `.clone()` and hold onto it anyway.
7994 // This now causes errors in the logs, we should find a way to remove such servers from the processing everywhere.
7995 let _: Vec<Option<()>> = join_all(servers).await;
7996
7997 Some(())
7998 })
7999 .await;
8000 }
8001
8002 fn maintain_workspace_config(
8003 external_refresh_requests: watch::Receiver<()>,
8004 cx: &mut Context<Self>,
8005 ) -> Task<Result<()>> {
8006 let (mut settings_changed_tx, mut settings_changed_rx) = watch::channel();
8007 let _ = postage::stream::Stream::try_recv(&mut settings_changed_rx);
8008
8009 let settings_observation = cx.observe_global::<SettingsStore>(move |_, _| {
8010 *settings_changed_tx.borrow_mut() = ();
8011 });
8012
8013 let mut joint_future =
8014 futures::stream::select(settings_changed_rx, external_refresh_requests);
8015 // Multiple things can happen when a workspace environment (selected toolchain + settings) change:
8016 // - 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).
8017 // - 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.
8018 // - In the same vein, we might also decide to start a new language server if the workspace configuration *diverges* from the other.
8019 // - 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,
8020 // but it is still different to what we had before, we're gonna send out a workspace configuration update.
8021 cx.spawn(async move |this, cx| {
8022 while let Some(()) = joint_future.next().await {
8023 this.update(cx, |this, cx| {
8024 this.refresh_server_tree(cx);
8025 })
8026 .ok();
8027
8028 Self::refresh_workspace_configurations(&this, cx).await;
8029 }
8030
8031 drop(settings_observation);
8032 anyhow::Ok(())
8033 })
8034 }
8035
8036 pub fn running_language_servers_for_local_buffer<'a>(
8037 &'a self,
8038 buffer: &Buffer,
8039 cx: &mut App,
8040 ) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8041 let local = self.as_local();
8042 let language_server_ids = local
8043 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8044 .unwrap_or_default();
8045
8046 language_server_ids
8047 .into_iter()
8048 .filter_map(
8049 move |server_id| match local?.language_servers.get(&server_id)? {
8050 LanguageServerState::Running {
8051 adapter, server, ..
8052 } => Some((adapter, server)),
8053 _ => None,
8054 },
8055 )
8056 }
8057
8058 pub fn language_servers_for_local_buffer(
8059 &self,
8060 buffer: &Buffer,
8061 cx: &mut App,
8062 ) -> Vec<LanguageServerId> {
8063 let local = self.as_local();
8064 local
8065 .map(|local| local.language_server_ids_for_buffer(buffer, cx))
8066 .unwrap_or_default()
8067 }
8068
8069 pub fn language_server_for_local_buffer<'a>(
8070 &'a self,
8071 buffer: &'a Buffer,
8072 server_id: LanguageServerId,
8073 cx: &'a mut App,
8074 ) -> Option<(&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
8075 self.as_local()?
8076 .language_servers_for_buffer(buffer, cx)
8077 .find(|(_, s)| s.server_id() == server_id)
8078 }
8079
8080 fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut Context<Self>) {
8081 self.diagnostic_summaries.remove(&id_to_remove);
8082 if let Some(local) = self.as_local_mut() {
8083 let to_remove = local.remove_worktree(id_to_remove, cx);
8084 for server in to_remove {
8085 self.language_server_statuses.remove(&server);
8086 }
8087 }
8088 }
8089
8090 pub fn shared(
8091 &mut self,
8092 project_id: u64,
8093 downstream_client: AnyProtoClient,
8094 _: &mut Context<Self>,
8095 ) {
8096 self.downstream_client = Some((downstream_client.clone(), project_id));
8097
8098 for (server_id, status) in &self.language_server_statuses {
8099 if let Some(server) = self.language_server_for_id(*server_id) {
8100 downstream_client
8101 .send(proto::StartLanguageServer {
8102 project_id,
8103 server: Some(proto::LanguageServer {
8104 id: server_id.to_proto(),
8105 name: status.name.to_string(),
8106 worktree_id: status.worktree.map(|id| id.to_proto()),
8107 }),
8108 capabilities: serde_json::to_string(&server.capabilities())
8109 .expect("serializing server LSP capabilities"),
8110 })
8111 .log_err();
8112 }
8113 }
8114 }
8115
8116 pub fn disconnected_from_host(&mut self) {
8117 self.downstream_client.take();
8118 }
8119
8120 pub fn disconnected_from_ssh_remote(&mut self) {
8121 if let LspStoreMode::Remote(RemoteLspStore {
8122 upstream_client, ..
8123 }) = &mut self.mode
8124 {
8125 upstream_client.take();
8126 }
8127 }
8128
8129 pub(crate) fn set_language_server_statuses_from_proto(
8130 &mut self,
8131 project: WeakEntity<Project>,
8132 language_servers: Vec<proto::LanguageServer>,
8133 server_capabilities: Vec<String>,
8134 cx: &mut Context<Self>,
8135 ) {
8136 let lsp_logs = cx
8137 .try_global::<GlobalLogStore>()
8138 .map(|lsp_store| lsp_store.0.clone());
8139
8140 self.language_server_statuses = language_servers
8141 .into_iter()
8142 .zip(server_capabilities)
8143 .map(|(server, server_capabilities)| {
8144 let server_id = LanguageServerId(server.id as usize);
8145 if let Ok(server_capabilities) = serde_json::from_str(&server_capabilities) {
8146 self.lsp_server_capabilities
8147 .insert(server_id, server_capabilities);
8148 }
8149
8150 let name = LanguageServerName::from_proto(server.name);
8151 let worktree = server.worktree_id.map(WorktreeId::from_proto);
8152
8153 if let Some(lsp_logs) = &lsp_logs {
8154 lsp_logs.update(cx, |lsp_logs, cx| {
8155 lsp_logs.add_language_server(
8156 // Only remote clients get their language servers set from proto
8157 LanguageServerKind::Remote {
8158 project: project.clone(),
8159 },
8160 server_id,
8161 Some(name.clone()),
8162 worktree,
8163 None,
8164 cx,
8165 );
8166 });
8167 }
8168
8169 (
8170 server_id,
8171 LanguageServerStatus {
8172 name,
8173 server_version: None,
8174 pending_work: Default::default(),
8175 has_pending_diagnostic_updates: false,
8176 progress_tokens: Default::default(),
8177 worktree,
8178 binary: None,
8179 configuration: None,
8180 workspace_folders: BTreeSet::new(),
8181 process_id: None,
8182 },
8183 )
8184 })
8185 .collect();
8186 }
8187
8188 #[cfg(feature = "test-support")]
8189 pub fn update_diagnostic_entries(
8190 &mut self,
8191 server_id: LanguageServerId,
8192 abs_path: PathBuf,
8193 result_id: Option<SharedString>,
8194 version: Option<i32>,
8195 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8196 cx: &mut Context<Self>,
8197 ) -> anyhow::Result<()> {
8198 self.merge_diagnostic_entries(
8199 vec![DocumentDiagnosticsUpdate {
8200 diagnostics: DocumentDiagnostics {
8201 diagnostics,
8202 document_abs_path: abs_path,
8203 version,
8204 },
8205 result_id,
8206 server_id,
8207 disk_based_sources: Cow::Borrowed(&[]),
8208 registration_id: None,
8209 }],
8210 |_, _, _| false,
8211 cx,
8212 )?;
8213 Ok(())
8214 }
8215
8216 pub fn merge_diagnostic_entries<'a>(
8217 &mut self,
8218 diagnostic_updates: Vec<DocumentDiagnosticsUpdate<'a, DocumentDiagnostics>>,
8219 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
8220 cx: &mut Context<Self>,
8221 ) -> anyhow::Result<()> {
8222 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
8223 let mut updated_diagnostics_paths = HashMap::default();
8224 for mut update in diagnostic_updates {
8225 let abs_path = &update.diagnostics.document_abs_path;
8226 let server_id = update.server_id;
8227 let Some((worktree, relative_path)) =
8228 self.worktree_store.read(cx).find_worktree(abs_path, cx)
8229 else {
8230 log::warn!("skipping diagnostics update, no worktree found for path {abs_path:?}");
8231 return Ok(());
8232 };
8233
8234 let worktree_id = worktree.read(cx).id();
8235 let project_path = ProjectPath {
8236 worktree_id,
8237 path: relative_path,
8238 };
8239
8240 let document_uri = lsp::Uri::from_file_path(abs_path)
8241 .map_err(|()| anyhow!("Failed to convert buffer path {abs_path:?} to lsp Uri"))?;
8242 if let Some(buffer_handle) = self.buffer_store.read(cx).get_by_path(&project_path) {
8243 let snapshot = buffer_handle.read(cx).snapshot();
8244 let buffer = buffer_handle.read(cx);
8245 let reused_diagnostics = buffer
8246 .buffer_diagnostics(Some(server_id))
8247 .iter()
8248 .filter(|v| merge(&document_uri, &v.diagnostic, cx))
8249 .map(|v| {
8250 let start = Unclipped(v.range.start.to_point_utf16(&snapshot));
8251 let end = Unclipped(v.range.end.to_point_utf16(&snapshot));
8252 DiagnosticEntry {
8253 range: start..end,
8254 diagnostic: v.diagnostic.clone(),
8255 }
8256 })
8257 .collect::<Vec<_>>();
8258
8259 self.as_local_mut()
8260 .context("cannot merge diagnostics on a remote LspStore")?
8261 .update_buffer_diagnostics(
8262 &buffer_handle,
8263 server_id,
8264 Some(update.registration_id),
8265 update.result_id,
8266 update.diagnostics.version,
8267 update.diagnostics.diagnostics.clone(),
8268 reused_diagnostics.clone(),
8269 cx,
8270 )?;
8271
8272 update.diagnostics.diagnostics.extend(reused_diagnostics);
8273 } else if let Some(local) = self.as_local() {
8274 let reused_diagnostics = local
8275 .diagnostics
8276 .get(&worktree_id)
8277 .and_then(|diagnostics_for_tree| diagnostics_for_tree.get(&project_path.path))
8278 .and_then(|diagnostics_by_server_id| {
8279 diagnostics_by_server_id
8280 .binary_search_by_key(&server_id, |e| e.0)
8281 .ok()
8282 .map(|ix| &diagnostics_by_server_id[ix].1)
8283 })
8284 .into_iter()
8285 .flatten()
8286 .filter(|v| merge(&document_uri, &v.diagnostic, cx));
8287
8288 update
8289 .diagnostics
8290 .diagnostics
8291 .extend(reused_diagnostics.cloned());
8292 }
8293
8294 let updated = worktree.update(cx, |worktree, cx| {
8295 self.update_worktree_diagnostics(
8296 worktree.id(),
8297 server_id,
8298 project_path.path.clone(),
8299 update.diagnostics.diagnostics,
8300 cx,
8301 )
8302 })?;
8303 match updated {
8304 ControlFlow::Continue(new_summary) => {
8305 if let Some((project_id, new_summary)) = new_summary {
8306 match &mut diagnostics_summary {
8307 Some(diagnostics_summary) => {
8308 diagnostics_summary
8309 .more_summaries
8310 .push(proto::DiagnosticSummary {
8311 path: project_path.path.as_ref().to_proto(),
8312 language_server_id: server_id.0 as u64,
8313 error_count: new_summary.error_count,
8314 warning_count: new_summary.warning_count,
8315 })
8316 }
8317 None => {
8318 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
8319 project_id,
8320 worktree_id: worktree_id.to_proto(),
8321 summary: Some(proto::DiagnosticSummary {
8322 path: project_path.path.as_ref().to_proto(),
8323 language_server_id: server_id.0 as u64,
8324 error_count: new_summary.error_count,
8325 warning_count: new_summary.warning_count,
8326 }),
8327 more_summaries: Vec::new(),
8328 })
8329 }
8330 }
8331 }
8332 updated_diagnostics_paths
8333 .entry(server_id)
8334 .or_insert_with(Vec::new)
8335 .push(project_path);
8336 }
8337 ControlFlow::Break(()) => {}
8338 }
8339 }
8340
8341 if let Some((diagnostics_summary, (downstream_client, _))) =
8342 diagnostics_summary.zip(self.downstream_client.as_ref())
8343 {
8344 downstream_client.send(diagnostics_summary).log_err();
8345 }
8346 for (server_id, paths) in updated_diagnostics_paths {
8347 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
8348 }
8349 Ok(())
8350 }
8351
8352 fn update_worktree_diagnostics(
8353 &mut self,
8354 worktree_id: WorktreeId,
8355 server_id: LanguageServerId,
8356 path_in_worktree: Arc<RelPath>,
8357 diagnostics: Vec<DiagnosticEntry<Unclipped<PointUtf16>>>,
8358 _: &mut Context<Worktree>,
8359 ) -> Result<ControlFlow<(), Option<(u64, proto::DiagnosticSummary)>>> {
8360 let local = match &mut self.mode {
8361 LspStoreMode::Local(local_lsp_store) => local_lsp_store,
8362 _ => anyhow::bail!("update_worktree_diagnostics called on remote"),
8363 };
8364
8365 let summaries_for_tree = self.diagnostic_summaries.entry(worktree_id).or_default();
8366 let diagnostics_for_tree = local.diagnostics.entry(worktree_id).or_default();
8367 let summaries_by_server_id = summaries_for_tree
8368 .entry(path_in_worktree.clone())
8369 .or_default();
8370
8371 let old_summary = summaries_by_server_id
8372 .remove(&server_id)
8373 .unwrap_or_default();
8374
8375 let new_summary = DiagnosticSummary::new(&diagnostics);
8376 if diagnostics.is_empty() {
8377 if let Some(diagnostics_by_server_id) = diagnostics_for_tree.get_mut(&path_in_worktree)
8378 {
8379 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8380 diagnostics_by_server_id.remove(ix);
8381 }
8382 if diagnostics_by_server_id.is_empty() {
8383 diagnostics_for_tree.remove(&path_in_worktree);
8384 }
8385 }
8386 } else {
8387 summaries_by_server_id.insert(server_id, new_summary);
8388 let diagnostics_by_server_id = diagnostics_for_tree
8389 .entry(path_in_worktree.clone())
8390 .or_default();
8391 match diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
8392 Ok(ix) => {
8393 diagnostics_by_server_id[ix] = (server_id, diagnostics);
8394 }
8395 Err(ix) => {
8396 diagnostics_by_server_id.insert(ix, (server_id, diagnostics));
8397 }
8398 }
8399 }
8400
8401 if !old_summary.is_empty() || !new_summary.is_empty() {
8402 if let Some((_, project_id)) = &self.downstream_client {
8403 Ok(ControlFlow::Continue(Some((
8404 *project_id,
8405 proto::DiagnosticSummary {
8406 path: path_in_worktree.to_proto(),
8407 language_server_id: server_id.0 as u64,
8408 error_count: new_summary.error_count as u32,
8409 warning_count: new_summary.warning_count as u32,
8410 },
8411 ))))
8412 } else {
8413 Ok(ControlFlow::Continue(None))
8414 }
8415 } else {
8416 Ok(ControlFlow::Break(()))
8417 }
8418 }
8419
8420 pub fn open_buffer_for_symbol(
8421 &mut self,
8422 symbol: &Symbol,
8423 cx: &mut Context<Self>,
8424 ) -> Task<Result<Entity<Buffer>>> {
8425 if let Some((client, project_id)) = self.upstream_client() {
8426 let request = client.request(proto::OpenBufferForSymbol {
8427 project_id,
8428 symbol: Some(Self::serialize_symbol(symbol)),
8429 });
8430 cx.spawn(async move |this, cx| {
8431 let response = request.await?;
8432 let buffer_id = BufferId::new(response.buffer_id)?;
8433 this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))?
8434 .await
8435 })
8436 } else if let Some(local) = self.as_local() {
8437 let is_valid = local.language_server_ids.iter().any(|(seed, state)| {
8438 seed.worktree_id == symbol.source_worktree_id
8439 && state.id == symbol.source_language_server_id
8440 && symbol.language_server_name == seed.name
8441 });
8442 if !is_valid {
8443 return Task::ready(Err(anyhow!(
8444 "language server for worktree and language not found"
8445 )));
8446 };
8447
8448 let symbol_abs_path = match &symbol.path {
8449 SymbolLocation::InProject(project_path) => self
8450 .worktree_store
8451 .read(cx)
8452 .absolutize(&project_path, cx)
8453 .context("no such worktree"),
8454 SymbolLocation::OutsideProject {
8455 abs_path,
8456 signature: _,
8457 } => Ok(abs_path.to_path_buf()),
8458 };
8459 let symbol_abs_path = match symbol_abs_path {
8460 Ok(abs_path) => abs_path,
8461 Err(err) => return Task::ready(Err(err)),
8462 };
8463 let symbol_uri = if let Ok(uri) = lsp::Uri::from_file_path(symbol_abs_path) {
8464 uri
8465 } else {
8466 return Task::ready(Err(anyhow!("invalid symbol path")));
8467 };
8468
8469 self.open_local_buffer_via_lsp(symbol_uri, symbol.source_language_server_id, cx)
8470 } else {
8471 Task::ready(Err(anyhow!("no upstream client or local store")))
8472 }
8473 }
8474
8475 pub(crate) fn open_local_buffer_via_lsp(
8476 &mut self,
8477 abs_path: lsp::Uri,
8478 language_server_id: LanguageServerId,
8479 cx: &mut Context<Self>,
8480 ) -> Task<Result<Entity<Buffer>>> {
8481 let path_style = self.worktree_store.read(cx).path_style();
8482 cx.spawn(async move |lsp_store, cx| {
8483 // Escape percent-encoded string.
8484 let current_scheme = abs_path.scheme().to_owned();
8485 // Uri is immutable, so we can't modify the scheme
8486
8487 let abs_path = abs_path
8488 .to_file_path_ext(path_style)
8489 .map_err(|()| anyhow!("can't convert URI to path"))?;
8490 let p = abs_path.clone();
8491 let yarn_worktree = lsp_store
8492 .update(cx, move |lsp_store, cx| match lsp_store.as_local() {
8493 Some(local_lsp_store) => local_lsp_store.yarn.update(cx, |_, cx| {
8494 cx.spawn(async move |this, cx| {
8495 let t = this
8496 .update(cx, |this, cx| this.process_path(&p, ¤t_scheme, cx))
8497 .ok()?;
8498 t.await
8499 })
8500 }),
8501 None => Task::ready(None),
8502 })?
8503 .await;
8504 let (worktree_root_target, known_relative_path) =
8505 if let Some((zip_root, relative_path)) = yarn_worktree {
8506 (zip_root, Some(relative_path))
8507 } else {
8508 (Arc::<Path>::from(abs_path.as_path()), None)
8509 };
8510 let worktree = lsp_store.update(cx, |lsp_store, cx| {
8511 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8512 worktree_store.find_worktree(&worktree_root_target, cx)
8513 })
8514 })?;
8515 let (worktree, relative_path, source_ws) = if let Some(result) = worktree {
8516 let relative_path = known_relative_path.unwrap_or_else(|| result.1.clone());
8517 (result.0, relative_path, None)
8518 } else {
8519 let worktree = lsp_store
8520 .update(cx, |lsp_store, cx| {
8521 lsp_store.worktree_store.update(cx, |worktree_store, cx| {
8522 worktree_store.create_worktree(&worktree_root_target, false, cx)
8523 })
8524 })?
8525 .await?;
8526 let worktree_root = worktree.read_with(cx, |worktree, _| worktree.abs_path());
8527 let source_ws = if worktree.read_with(cx, |worktree, _| worktree.is_local()) {
8528 lsp_store
8529 .update(cx, |lsp_store, cx| {
8530 if let Some(local) = lsp_store.as_local_mut() {
8531 local.register_language_server_for_invisible_worktree(
8532 &worktree,
8533 language_server_id,
8534 cx,
8535 )
8536 }
8537 match lsp_store.language_server_statuses.get(&language_server_id) {
8538 Some(status) => status.worktree,
8539 None => None,
8540 }
8541 })
8542 .ok()
8543 .flatten()
8544 .zip(Some(worktree_root.clone()))
8545 } else {
8546 None
8547 };
8548 let relative_path = if let Some(known_path) = known_relative_path {
8549 known_path
8550 } else {
8551 RelPath::new(abs_path.strip_prefix(worktree_root)?, PathStyle::local())?
8552 .into_arc()
8553 };
8554 (worktree, relative_path, source_ws)
8555 };
8556 let project_path = ProjectPath {
8557 worktree_id: worktree.read_with(cx, |worktree, _| worktree.id()),
8558 path: relative_path,
8559 };
8560 let buffer = lsp_store
8561 .update(cx, |lsp_store, cx| {
8562 lsp_store.buffer_store().update(cx, |buffer_store, cx| {
8563 buffer_store.open_buffer(project_path, cx)
8564 })
8565 })?
8566 .await?;
8567 // we want to adhere to the read-only settings of the worktree we came from in case we opened an invisible one
8568 if let Some((source_ws, worktree_root)) = source_ws {
8569 buffer.update(cx, |buffer, cx| {
8570 let settings = WorktreeSettings::get(
8571 Some(
8572 (&ProjectPath {
8573 worktree_id: source_ws,
8574 path: Arc::from(RelPath::empty()),
8575 })
8576 .into(),
8577 ),
8578 cx,
8579 );
8580 let is_read_only = settings.is_std_path_read_only(&worktree_root);
8581 if is_read_only {
8582 buffer.set_capability(Capability::ReadOnly, cx);
8583 }
8584 });
8585 }
8586 Ok(buffer)
8587 })
8588 }
8589
8590 fn local_lsp_servers_for_buffer(
8591 &self,
8592 buffer: &Entity<Buffer>,
8593 cx: &mut Context<Self>,
8594 ) -> Vec<LanguageServerId> {
8595 let Some(local) = self.as_local() else {
8596 return Vec::new();
8597 };
8598
8599 let snapshot = buffer.read(cx).snapshot();
8600
8601 buffer.update(cx, |buffer, cx| {
8602 local
8603 .language_servers_for_buffer(buffer, cx)
8604 .map(|(_, server)| server.server_id())
8605 .filter(|server_id| {
8606 self.as_local().is_none_or(|local| {
8607 local
8608 .buffers_opened_in_servers
8609 .get(&snapshot.remote_id())
8610 .is_some_and(|servers| servers.contains(server_id))
8611 })
8612 })
8613 .collect()
8614 })
8615 }
8616
8617 fn request_multiple_lsp_locally<P, R>(
8618 &mut self,
8619 buffer: &Entity<Buffer>,
8620 position: Option<P>,
8621 request: R,
8622 cx: &mut Context<Self>,
8623 ) -> Task<Vec<(LanguageServerId, R::Response)>>
8624 where
8625 P: ToOffset,
8626 R: LspCommand + Clone,
8627 <R::LspRequest as lsp::request::Request>::Result: Send,
8628 <R::LspRequest as lsp::request::Request>::Params: Send,
8629 {
8630 let Some(local) = self.as_local() else {
8631 return Task::ready(Vec::new());
8632 };
8633
8634 let snapshot = buffer.read(cx).snapshot();
8635 let scope = position.and_then(|position| snapshot.language_scope_at(position));
8636
8637 let server_ids = buffer.update(cx, |buffer, cx| {
8638 local
8639 .language_servers_for_buffer(buffer, cx)
8640 .filter(|(adapter, _)| {
8641 scope
8642 .as_ref()
8643 .map(|scope| scope.language_allowed(&adapter.name))
8644 .unwrap_or(true)
8645 })
8646 .map(|(_, server)| server.server_id())
8647 .filter(|server_id| {
8648 self.as_local().is_none_or(|local| {
8649 local
8650 .buffers_opened_in_servers
8651 .get(&snapshot.remote_id())
8652 .is_some_and(|servers| servers.contains(server_id))
8653 })
8654 })
8655 .collect::<Vec<_>>()
8656 });
8657
8658 let mut response_results = server_ids
8659 .into_iter()
8660 .map(|server_id| {
8661 let task = self.request_lsp(
8662 buffer.clone(),
8663 LanguageServerToQuery::Other(server_id),
8664 request.clone(),
8665 cx,
8666 );
8667 async move { (server_id, task.await) }
8668 })
8669 .collect::<FuturesUnordered<_>>();
8670
8671 cx.background_spawn(async move {
8672 let mut responses = Vec::with_capacity(response_results.len());
8673 while let Some((server_id, response_result)) = response_results.next().await {
8674 match response_result {
8675 Ok(response) => responses.push((server_id, response)),
8676 // rust-analyzer likes to error with this when its still loading up
8677 Err(e) if format!("{e:#}").ends_with("content modified") => (),
8678 Err(e) => log::error!("Error handling response for request {request:?}: {e:#}"),
8679 }
8680 }
8681 responses
8682 })
8683 }
8684
8685 async fn handle_lsp_get_completions(
8686 this: Entity<Self>,
8687 envelope: TypedEnvelope<proto::GetCompletions>,
8688 mut cx: AsyncApp,
8689 ) -> Result<proto::GetCompletionsResponse> {
8690 let sender_id = envelope.original_sender_id().unwrap_or_default();
8691
8692 let buffer_id = GetCompletions::buffer_id_from_proto(&envelope.payload)?;
8693 let buffer_handle = this.update(&mut cx, |this, cx| {
8694 this.buffer_store.read(cx).get_existing(buffer_id)
8695 })?;
8696 let request = GetCompletions::from_proto(
8697 envelope.payload,
8698 this.clone(),
8699 buffer_handle.clone(),
8700 cx.clone(),
8701 )
8702 .await?;
8703
8704 let server_to_query = match request.server_id {
8705 Some(server_id) => LanguageServerToQuery::Other(server_id),
8706 None => LanguageServerToQuery::FirstCapable,
8707 };
8708
8709 let response = this
8710 .update(&mut cx, |this, cx| {
8711 this.request_lsp(buffer_handle.clone(), server_to_query, request, cx)
8712 })
8713 .await?;
8714 this.update(&mut cx, |this, cx| {
8715 Ok(GetCompletions::response_to_proto(
8716 response,
8717 this,
8718 sender_id,
8719 &buffer_handle.read(cx).version(),
8720 cx,
8721 ))
8722 })
8723 }
8724
8725 async fn handle_lsp_command<T: LspCommand>(
8726 this: Entity<Self>,
8727 envelope: TypedEnvelope<T::ProtoRequest>,
8728 mut cx: AsyncApp,
8729 ) -> Result<<T::ProtoRequest as proto::RequestMessage>::Response>
8730 where
8731 <T::LspRequest as lsp::request::Request>::Params: Send,
8732 <T::LspRequest as lsp::request::Request>::Result: Send,
8733 {
8734 let sender_id = envelope.original_sender_id().unwrap_or_default();
8735 let buffer_id = T::buffer_id_from_proto(&envelope.payload)?;
8736 let buffer_handle = this.update(&mut cx, |this, cx| {
8737 this.buffer_store.read(cx).get_existing(buffer_id)
8738 })?;
8739 let request = T::from_proto(
8740 envelope.payload,
8741 this.clone(),
8742 buffer_handle.clone(),
8743 cx.clone(),
8744 )
8745 .await?;
8746 let response = this
8747 .update(&mut cx, |this, cx| {
8748 this.request_lsp(
8749 buffer_handle.clone(),
8750 LanguageServerToQuery::FirstCapable,
8751 request,
8752 cx,
8753 )
8754 })
8755 .await?;
8756 this.update(&mut cx, |this, cx| {
8757 Ok(T::response_to_proto(
8758 response,
8759 this,
8760 sender_id,
8761 &buffer_handle.read(cx).version(),
8762 cx,
8763 ))
8764 })
8765 }
8766
8767 async fn handle_lsp_query(
8768 lsp_store: Entity<Self>,
8769 envelope: TypedEnvelope<proto::LspQuery>,
8770 mut cx: AsyncApp,
8771 ) -> Result<proto::Ack> {
8772 use proto::lsp_query::Request;
8773 let sender_id = envelope.original_sender_id().unwrap_or_default();
8774 let lsp_query = envelope.payload;
8775 let lsp_request_id = LspRequestId(lsp_query.lsp_request_id);
8776 let server_id = lsp_query.server_id.map(LanguageServerId::from_proto);
8777 match lsp_query.request.context("invalid LSP query request")? {
8778 Request::GetReferences(get_references) => {
8779 let position = get_references.position.clone().and_then(deserialize_anchor);
8780 Self::query_lsp_locally::<GetReferences>(
8781 lsp_store,
8782 server_id,
8783 sender_id,
8784 lsp_request_id,
8785 get_references,
8786 position,
8787 &mut cx,
8788 )
8789 .await?;
8790 }
8791 Request::GetDocumentColor(get_document_color) => {
8792 Self::query_lsp_locally::<GetDocumentColor>(
8793 lsp_store,
8794 server_id,
8795 sender_id,
8796 lsp_request_id,
8797 get_document_color,
8798 None,
8799 &mut cx,
8800 )
8801 .await?;
8802 }
8803 Request::GetFoldingRanges(get_folding_ranges) => {
8804 Self::query_lsp_locally::<GetFoldingRanges>(
8805 lsp_store,
8806 server_id,
8807 sender_id,
8808 lsp_request_id,
8809 get_folding_ranges,
8810 None,
8811 &mut cx,
8812 )
8813 .await?;
8814 }
8815 Request::GetDocumentSymbols(get_document_symbols) => {
8816 Self::query_lsp_locally::<GetDocumentSymbols>(
8817 lsp_store,
8818 server_id,
8819 sender_id,
8820 lsp_request_id,
8821 get_document_symbols,
8822 None,
8823 &mut cx,
8824 )
8825 .await?;
8826 }
8827 Request::GetHover(get_hover) => {
8828 let position = get_hover.position.clone().and_then(deserialize_anchor);
8829 Self::query_lsp_locally::<GetHover>(
8830 lsp_store,
8831 server_id,
8832 sender_id,
8833 lsp_request_id,
8834 get_hover,
8835 position,
8836 &mut cx,
8837 )
8838 .await?;
8839 }
8840 Request::GetCodeActions(get_code_actions) => {
8841 Self::query_lsp_locally::<GetCodeActions>(
8842 lsp_store,
8843 server_id,
8844 sender_id,
8845 lsp_request_id,
8846 get_code_actions,
8847 None,
8848 &mut cx,
8849 )
8850 .await?;
8851 }
8852 Request::GetSignatureHelp(get_signature_help) => {
8853 let position = get_signature_help
8854 .position
8855 .clone()
8856 .and_then(deserialize_anchor);
8857 Self::query_lsp_locally::<GetSignatureHelp>(
8858 lsp_store,
8859 server_id,
8860 sender_id,
8861 lsp_request_id,
8862 get_signature_help,
8863 position,
8864 &mut cx,
8865 )
8866 .await?;
8867 }
8868 Request::GetCodeLens(get_code_lens) => {
8869 Self::query_lsp_locally::<GetCodeLens>(
8870 lsp_store,
8871 server_id,
8872 sender_id,
8873 lsp_request_id,
8874 get_code_lens,
8875 None,
8876 &mut cx,
8877 )
8878 .await?;
8879 }
8880 Request::GetDefinition(get_definition) => {
8881 let position = get_definition.position.clone().and_then(deserialize_anchor);
8882 Self::query_lsp_locally::<GetDefinitions>(
8883 lsp_store,
8884 server_id,
8885 sender_id,
8886 lsp_request_id,
8887 get_definition,
8888 position,
8889 &mut cx,
8890 )
8891 .await?;
8892 }
8893 Request::GetDeclaration(get_declaration) => {
8894 let position = get_declaration
8895 .position
8896 .clone()
8897 .and_then(deserialize_anchor);
8898 Self::query_lsp_locally::<GetDeclarations>(
8899 lsp_store,
8900 server_id,
8901 sender_id,
8902 lsp_request_id,
8903 get_declaration,
8904 position,
8905 &mut cx,
8906 )
8907 .await?;
8908 }
8909 Request::GetTypeDefinition(get_type_definition) => {
8910 let position = get_type_definition
8911 .position
8912 .clone()
8913 .and_then(deserialize_anchor);
8914 Self::query_lsp_locally::<GetTypeDefinitions>(
8915 lsp_store,
8916 server_id,
8917 sender_id,
8918 lsp_request_id,
8919 get_type_definition,
8920 position,
8921 &mut cx,
8922 )
8923 .await?;
8924 }
8925 Request::GetImplementation(get_implementation) => {
8926 let position = get_implementation
8927 .position
8928 .clone()
8929 .and_then(deserialize_anchor);
8930 Self::query_lsp_locally::<GetImplementations>(
8931 lsp_store,
8932 server_id,
8933 sender_id,
8934 lsp_request_id,
8935 get_implementation,
8936 position,
8937 &mut cx,
8938 )
8939 .await?;
8940 }
8941 Request::InlayHints(inlay_hints) => {
8942 let query_start = inlay_hints
8943 .start
8944 .clone()
8945 .and_then(deserialize_anchor)
8946 .context("invalid inlay hints range start")?;
8947 let query_end = inlay_hints
8948 .end
8949 .clone()
8950 .and_then(deserialize_anchor)
8951 .context("invalid inlay hints range end")?;
8952 Self::deduplicate_range_based_lsp_requests::<InlayHints>(
8953 &lsp_store,
8954 server_id,
8955 lsp_request_id,
8956 &inlay_hints,
8957 query_start..query_end,
8958 &mut cx,
8959 )
8960 .await
8961 .context("preparing inlay hints request")?;
8962 Self::query_lsp_locally::<InlayHints>(
8963 lsp_store,
8964 server_id,
8965 sender_id,
8966 lsp_request_id,
8967 inlay_hints,
8968 None,
8969 &mut cx,
8970 )
8971 .await
8972 .context("querying for inlay hints")?
8973 }
8974 //////////////////////////////
8975 // Below are LSP queries that need to fetch more data,
8976 // hence cannot just proxy the request to language server with `query_lsp_locally`.
8977 Request::GetDocumentDiagnostics(get_document_diagnostics) => {
8978 let (_, buffer) = Self::wait_for_buffer_version::<GetDocumentDiagnostics>(
8979 &lsp_store,
8980 &get_document_diagnostics,
8981 &mut cx,
8982 )
8983 .await?;
8984 lsp_store.update(&mut cx, |lsp_store, cx| {
8985 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
8986 let key = LspKey {
8987 request_type: TypeId::of::<GetDocumentDiagnostics>(),
8988 server_queried: server_id,
8989 };
8990 if <GetDocumentDiagnostics as LspCommand>::ProtoRequest::stop_previous_requests(
8991 ) {
8992 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
8993 lsp_requests.clear();
8994 };
8995 }
8996
8997 lsp_data.lsp_requests.entry(key).or_default().insert(
8998 lsp_request_id,
8999 cx.spawn(async move |lsp_store, cx| {
9000 let diagnostics_pull = lsp_store
9001 .update(cx, |lsp_store, cx| {
9002 lsp_store.pull_diagnostics_for_buffer(buffer, cx)
9003 })
9004 .ok();
9005 if let Some(diagnostics_pull) = diagnostics_pull {
9006 match diagnostics_pull.await {
9007 Ok(()) => {}
9008 Err(e) => log::error!("Failed to pull diagnostics: {e:#}"),
9009 };
9010 }
9011 }),
9012 );
9013 });
9014 }
9015 Request::SemanticTokens(semantic_tokens) => {
9016 let (buffer_version, buffer) = Self::wait_for_buffer_version::<SemanticTokensFull>(
9017 &lsp_store,
9018 &semantic_tokens,
9019 &mut cx,
9020 )
9021 .await?;
9022 let for_server = semantic_tokens.for_server.map(LanguageServerId::from_proto);
9023 lsp_store.update(&mut cx, |lsp_store, cx| {
9024 if let Some((client, project_id)) = lsp_store.downstream_client.clone() {
9025 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
9026 let key = LspKey {
9027 request_type: TypeId::of::<SemanticTokensFull>(),
9028 server_queried: server_id,
9029 };
9030 if <SemanticTokensFull as LspCommand>::ProtoRequest::stop_previous_requests() {
9031 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
9032 lsp_requests.clear();
9033 };
9034 }
9035
9036 lsp_data.lsp_requests.entry(key).or_default().insert(
9037 lsp_request_id,
9038 cx.spawn(async move |lsp_store, cx| {
9039 let tokens_fetch = lsp_store
9040 .update(cx, |lsp_store, cx| {
9041 lsp_store
9042 .fetch_semantic_tokens_for_buffer(&buffer, for_server, cx)
9043 })
9044 .ok();
9045 if let Some(tokens_fetch) = tokens_fetch {
9046 let new_tokens = tokens_fetch.await;
9047 if let Some(new_tokens) = new_tokens {
9048 lsp_store
9049 .update(cx, |lsp_store, cx| {
9050 let response = new_tokens
9051 .into_iter()
9052 .map(|(server_id, response)| {
9053 (
9054 server_id.to_proto(),
9055 SemanticTokensFull::response_to_proto(
9056 response,
9057 lsp_store,
9058 sender_id,
9059 &buffer_version,
9060 cx,
9061 ),
9062 )
9063 })
9064 .collect::<HashMap<_, _>>();
9065 match client.send_lsp_response::<<SemanticTokensFull as LspCommand>::ProtoRequest>(
9066 project_id,
9067 lsp_request_id,
9068 response,
9069 ) {
9070 Ok(()) => {}
9071 Err(e) => {
9072 log::error!(
9073 "Failed to send semantic tokens LSP response: {e:#}",
9074 )
9075 }
9076 }
9077 })
9078 .ok();
9079 }
9080 }
9081 }),
9082 );
9083 }
9084 });
9085 }
9086 }
9087 Ok(proto::Ack {})
9088 }
9089
9090 async fn handle_lsp_query_response(
9091 lsp_store: Entity<Self>,
9092 envelope: TypedEnvelope<proto::LspQueryResponse>,
9093 cx: AsyncApp,
9094 ) -> Result<()> {
9095 lsp_store.read_with(&cx, |lsp_store, _| {
9096 if let Some((upstream_client, _)) = lsp_store.upstream_client() {
9097 upstream_client.handle_lsp_response(envelope.clone());
9098 }
9099 });
9100 Ok(())
9101 }
9102
9103 async fn handle_apply_code_action(
9104 this: Entity<Self>,
9105 envelope: TypedEnvelope<proto::ApplyCodeAction>,
9106 mut cx: AsyncApp,
9107 ) -> Result<proto::ApplyCodeActionResponse> {
9108 let sender_id = envelope.original_sender_id().unwrap_or_default();
9109 let action =
9110 Self::deserialize_code_action(envelope.payload.action.context("invalid action")?)?;
9111 let apply_code_action = this.update(&mut cx, |this, cx| {
9112 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9113 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
9114 anyhow::Ok(this.apply_code_action(buffer, action, false, cx))
9115 })?;
9116
9117 let project_transaction = apply_code_action.await?;
9118 let project_transaction = this.update(&mut cx, |this, cx| {
9119 this.buffer_store.update(cx, |buffer_store, cx| {
9120 buffer_store.serialize_project_transaction_for_peer(
9121 project_transaction,
9122 sender_id,
9123 cx,
9124 )
9125 })
9126 });
9127 Ok(proto::ApplyCodeActionResponse {
9128 transaction: Some(project_transaction),
9129 })
9130 }
9131
9132 async fn handle_register_buffer_with_language_servers(
9133 this: Entity<Self>,
9134 envelope: TypedEnvelope<proto::RegisterBufferWithLanguageServers>,
9135 mut cx: AsyncApp,
9136 ) -> Result<proto::Ack> {
9137 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
9138 let peer_id = envelope.original_sender_id.unwrap_or(envelope.sender_id);
9139 this.update(&mut cx, |this, cx| {
9140 if let Some((upstream_client, upstream_project_id)) = this.upstream_client() {
9141 return upstream_client.send(proto::RegisterBufferWithLanguageServers {
9142 project_id: upstream_project_id,
9143 buffer_id: buffer_id.to_proto(),
9144 only_servers: envelope.payload.only_servers,
9145 });
9146 }
9147
9148 let Some(buffer) = this.buffer_store().read(cx).get(buffer_id) else {
9149 anyhow::bail!("buffer is not open");
9150 };
9151
9152 let handle = this.register_buffer_with_language_servers(
9153 &buffer,
9154 envelope
9155 .payload
9156 .only_servers
9157 .into_iter()
9158 .filter_map(|selector| {
9159 Some(match selector.selector? {
9160 proto::language_server_selector::Selector::ServerId(server_id) => {
9161 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
9162 }
9163 proto::language_server_selector::Selector::Name(name) => {
9164 LanguageServerSelector::Name(LanguageServerName(
9165 SharedString::from(name),
9166 ))
9167 }
9168 })
9169 })
9170 .collect(),
9171 false,
9172 cx,
9173 );
9174 // Pull diagnostics for the buffer even if it was already registered.
9175 // This is needed to make test_streamed_lsp_pull_diagnostics pass,
9176 // but it's unclear if we need it.
9177 this.pull_diagnostics_for_buffer(buffer.clone(), cx)
9178 .detach();
9179 this.buffer_store().update(cx, |buffer_store, _| {
9180 buffer_store.register_shared_lsp_handle(peer_id, buffer_id, handle);
9181 });
9182
9183 Ok(())
9184 })?;
9185 Ok(proto::Ack {})
9186 }
9187
9188 async fn handle_rename_project_entry(
9189 this: Entity<Self>,
9190 envelope: TypedEnvelope<proto::RenameProjectEntry>,
9191 mut cx: AsyncApp,
9192 ) -> Result<proto::ProjectEntryResponse> {
9193 let entry_id = ProjectEntryId::from_proto(envelope.payload.entry_id);
9194 let new_worktree_id = WorktreeId::from_proto(envelope.payload.new_worktree_id);
9195 let new_path =
9196 RelPath::from_proto(&envelope.payload.new_path).context("invalid relative path")?;
9197
9198 let (worktree_store, old_worktree, new_worktree, old_entry) = this
9199 .update(&mut cx, |this, cx| {
9200 let (worktree, entry) = this
9201 .worktree_store
9202 .read(cx)
9203 .worktree_and_entry_for_id(entry_id, cx)?;
9204 let new_worktree = this
9205 .worktree_store
9206 .read(cx)
9207 .worktree_for_id(new_worktree_id, cx)?;
9208 Some((
9209 this.worktree_store.clone(),
9210 worktree,
9211 new_worktree,
9212 entry.clone(),
9213 ))
9214 })
9215 .context("worktree not found")?;
9216 let (old_abs_path, old_worktree_id) = old_worktree.read_with(&cx, |worktree, _| {
9217 (worktree.absolutize(&old_entry.path), worktree.id())
9218 });
9219 let new_abs_path =
9220 new_worktree.read_with(&cx, |worktree, _| worktree.absolutize(&new_path));
9221
9222 let _transaction = Self::will_rename_entry(
9223 this.downgrade(),
9224 old_worktree_id,
9225 &old_abs_path,
9226 &new_abs_path,
9227 old_entry.is_dir(),
9228 cx.clone(),
9229 )
9230 .await;
9231 let response = WorktreeStore::handle_rename_project_entry(
9232 worktree_store,
9233 envelope.payload,
9234 cx.clone(),
9235 )
9236 .await;
9237 this.read_with(&cx, |this, _| {
9238 this.did_rename_entry(
9239 old_worktree_id,
9240 &old_abs_path,
9241 &new_abs_path,
9242 old_entry.is_dir(),
9243 );
9244 });
9245 response
9246 }
9247
9248 async fn handle_update_diagnostic_summary(
9249 this: Entity<Self>,
9250 envelope: TypedEnvelope<proto::UpdateDiagnosticSummary>,
9251 mut cx: AsyncApp,
9252 ) -> Result<()> {
9253 this.update(&mut cx, |lsp_store, cx| {
9254 let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
9255 let mut updated_diagnostics_paths = HashMap::default();
9256 let mut diagnostics_summary = None::<proto::UpdateDiagnosticSummary>;
9257 for message_summary in envelope
9258 .payload
9259 .summary
9260 .into_iter()
9261 .chain(envelope.payload.more_summaries)
9262 {
9263 let project_path = ProjectPath {
9264 worktree_id,
9265 path: RelPath::from_proto(&message_summary.path).context("invalid path")?,
9266 };
9267 let path = project_path.path.clone();
9268 let server_id = LanguageServerId(message_summary.language_server_id as usize);
9269 let summary = DiagnosticSummary {
9270 error_count: message_summary.error_count as usize,
9271 warning_count: message_summary.warning_count as usize,
9272 };
9273
9274 if summary.is_empty() {
9275 if let Some(worktree_summaries) =
9276 lsp_store.diagnostic_summaries.get_mut(&worktree_id)
9277 && let Some(summaries) = worktree_summaries.get_mut(&path)
9278 {
9279 summaries.remove(&server_id);
9280 if summaries.is_empty() {
9281 worktree_summaries.remove(&path);
9282 }
9283 }
9284 } else {
9285 lsp_store
9286 .diagnostic_summaries
9287 .entry(worktree_id)
9288 .or_default()
9289 .entry(path)
9290 .or_default()
9291 .insert(server_id, summary);
9292 }
9293
9294 if let Some((_, project_id)) = &lsp_store.downstream_client {
9295 match &mut diagnostics_summary {
9296 Some(diagnostics_summary) => {
9297 diagnostics_summary
9298 .more_summaries
9299 .push(proto::DiagnosticSummary {
9300 path: project_path.path.as_ref().to_proto(),
9301 language_server_id: server_id.0 as u64,
9302 error_count: summary.error_count as u32,
9303 warning_count: summary.warning_count as u32,
9304 })
9305 }
9306 None => {
9307 diagnostics_summary = Some(proto::UpdateDiagnosticSummary {
9308 project_id: *project_id,
9309 worktree_id: worktree_id.to_proto(),
9310 summary: Some(proto::DiagnosticSummary {
9311 path: project_path.path.as_ref().to_proto(),
9312 language_server_id: server_id.0 as u64,
9313 error_count: summary.error_count as u32,
9314 warning_count: summary.warning_count as u32,
9315 }),
9316 more_summaries: Vec::new(),
9317 })
9318 }
9319 }
9320 }
9321 updated_diagnostics_paths
9322 .entry(server_id)
9323 .or_insert_with(Vec::new)
9324 .push(project_path);
9325 }
9326
9327 if let Some((diagnostics_summary, (downstream_client, _))) =
9328 diagnostics_summary.zip(lsp_store.downstream_client.as_ref())
9329 {
9330 downstream_client.send(diagnostics_summary).log_err();
9331 }
9332 for (server_id, paths) in updated_diagnostics_paths {
9333 cx.emit(LspStoreEvent::DiagnosticsUpdated { server_id, paths });
9334 }
9335 Ok(())
9336 })
9337 }
9338
9339 async fn handle_start_language_server(
9340 lsp_store: Entity<Self>,
9341 envelope: TypedEnvelope<proto::StartLanguageServer>,
9342 mut cx: AsyncApp,
9343 ) -> Result<()> {
9344 let server = envelope.payload.server.context("invalid server")?;
9345 let server_capabilities =
9346 serde_json::from_str::<lsp::ServerCapabilities>(&envelope.payload.capabilities)
9347 .with_context(|| {
9348 format!(
9349 "incorrect server capabilities {}",
9350 envelope.payload.capabilities
9351 )
9352 })?;
9353 lsp_store.update(&mut cx, |lsp_store, cx| {
9354 let server_id = LanguageServerId(server.id as usize);
9355 let server_name = LanguageServerName::from_proto(server.name.clone());
9356 lsp_store
9357 .lsp_server_capabilities
9358 .insert(server_id, server_capabilities);
9359 lsp_store.language_server_statuses.insert(
9360 server_id,
9361 LanguageServerStatus {
9362 name: server_name.clone(),
9363 server_version: None,
9364 pending_work: Default::default(),
9365 has_pending_diagnostic_updates: false,
9366 progress_tokens: Default::default(),
9367 worktree: server.worktree_id.map(WorktreeId::from_proto),
9368 binary: None,
9369 configuration: None,
9370 workspace_folders: BTreeSet::new(),
9371 process_id: None,
9372 },
9373 );
9374 cx.emit(LspStoreEvent::LanguageServerAdded(
9375 server_id,
9376 server_name,
9377 server.worktree_id.map(WorktreeId::from_proto),
9378 ));
9379 cx.notify();
9380 });
9381 Ok(())
9382 }
9383
9384 async fn handle_update_language_server(
9385 lsp_store: Entity<Self>,
9386 envelope: TypedEnvelope<proto::UpdateLanguageServer>,
9387 mut cx: AsyncApp,
9388 ) -> Result<()> {
9389 lsp_store.update(&mut cx, |lsp_store, cx| {
9390 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9391
9392 match envelope.payload.variant.context("invalid variant")? {
9393 proto::update_language_server::Variant::WorkStart(payload) => {
9394 lsp_store.on_lsp_work_start(
9395 language_server_id,
9396 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9397 .context("invalid progress token value")?,
9398 LanguageServerProgress {
9399 title: payload.title,
9400 is_disk_based_diagnostics_progress: false,
9401 is_cancellable: payload.is_cancellable.unwrap_or(false),
9402 message: payload.message,
9403 percentage: payload.percentage.map(|p| p as usize),
9404 last_update_at: cx.background_executor().now(),
9405 },
9406 cx,
9407 );
9408 }
9409 proto::update_language_server::Variant::WorkProgress(payload) => {
9410 lsp_store.on_lsp_work_progress(
9411 language_server_id,
9412 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9413 .context("invalid progress token value")?,
9414 LanguageServerProgress {
9415 title: None,
9416 is_disk_based_diagnostics_progress: false,
9417 is_cancellable: payload.is_cancellable.unwrap_or(false),
9418 message: payload.message,
9419 percentage: payload.percentage.map(|p| p as usize),
9420 last_update_at: cx.background_executor().now(),
9421 },
9422 cx,
9423 );
9424 }
9425
9426 proto::update_language_server::Variant::WorkEnd(payload) => {
9427 lsp_store.on_lsp_work_end(
9428 language_server_id,
9429 ProgressToken::from_proto(payload.token.context("missing progress token")?)
9430 .context("invalid progress token value")?,
9431 cx,
9432 );
9433 }
9434
9435 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(_) => {
9436 lsp_store.disk_based_diagnostics_started(language_server_id, cx);
9437 }
9438
9439 proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(_) => {
9440 lsp_store.disk_based_diagnostics_finished(language_server_id, cx)
9441 }
9442
9443 non_lsp @ proto::update_language_server::Variant::StatusUpdate(_)
9444 | non_lsp @ proto::update_language_server::Variant::RegisteredForBuffer(_)
9445 | non_lsp @ proto::update_language_server::Variant::MetadataUpdated(_) => {
9446 cx.emit(LspStoreEvent::LanguageServerUpdate {
9447 language_server_id,
9448 name: envelope
9449 .payload
9450 .server_name
9451 .map(SharedString::new)
9452 .map(LanguageServerName),
9453 message: non_lsp,
9454 });
9455 }
9456 }
9457
9458 Ok(())
9459 })
9460 }
9461
9462 async fn handle_language_server_log(
9463 this: Entity<Self>,
9464 envelope: TypedEnvelope<proto::LanguageServerLog>,
9465 mut cx: AsyncApp,
9466 ) -> Result<()> {
9467 let language_server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9468 let log_type = envelope
9469 .payload
9470 .log_type
9471 .map(LanguageServerLogType::from_proto)
9472 .context("invalid language server log type")?;
9473
9474 let message = envelope.payload.message;
9475
9476 this.update(&mut cx, |_, cx| {
9477 cx.emit(LspStoreEvent::LanguageServerLog(
9478 language_server_id,
9479 log_type,
9480 message,
9481 ));
9482 });
9483 Ok(())
9484 }
9485
9486 async fn handle_lsp_ext_cancel_flycheck(
9487 lsp_store: Entity<Self>,
9488 envelope: TypedEnvelope<proto::LspExtCancelFlycheck>,
9489 cx: AsyncApp,
9490 ) -> Result<proto::Ack> {
9491 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9492 let task = lsp_store.read_with(&cx, |lsp_store, _| {
9493 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9494 Some(server.notify::<lsp_store::lsp_ext_command::LspExtCancelFlycheck>(()))
9495 } else {
9496 None
9497 }
9498 });
9499 if let Some(task) = task {
9500 task.context("handling lsp ext cancel flycheck")?;
9501 }
9502
9503 Ok(proto::Ack {})
9504 }
9505
9506 async fn handle_lsp_ext_run_flycheck(
9507 lsp_store: Entity<Self>,
9508 envelope: TypedEnvelope<proto::LspExtRunFlycheck>,
9509 mut cx: AsyncApp,
9510 ) -> Result<proto::Ack> {
9511 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9512 lsp_store.update(&mut cx, |lsp_store, cx| {
9513 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9514 let text_document = if envelope.payload.current_file_only {
9515 let buffer_id = envelope
9516 .payload
9517 .buffer_id
9518 .map(|id| BufferId::new(id))
9519 .transpose()?;
9520 buffer_id
9521 .and_then(|buffer_id| {
9522 lsp_store
9523 .buffer_store()
9524 .read(cx)
9525 .get(buffer_id)
9526 .and_then(|buffer| {
9527 Some(buffer.read(cx).file()?.as_local()?.abs_path(cx))
9528 })
9529 .map(|path| make_text_document_identifier(&path))
9530 })
9531 .transpose()?
9532 } else {
9533 None
9534 };
9535 server.notify::<lsp_store::lsp_ext_command::LspExtRunFlycheck>(
9536 lsp_store::lsp_ext_command::RunFlycheckParams { text_document },
9537 )?;
9538 }
9539 anyhow::Ok(())
9540 })?;
9541
9542 Ok(proto::Ack {})
9543 }
9544
9545 async fn handle_lsp_ext_clear_flycheck(
9546 lsp_store: Entity<Self>,
9547 envelope: TypedEnvelope<proto::LspExtClearFlycheck>,
9548 cx: AsyncApp,
9549 ) -> Result<proto::Ack> {
9550 let server_id = LanguageServerId(envelope.payload.language_server_id as usize);
9551 lsp_store.read_with(&cx, |lsp_store, _| {
9552 if let Some(server) = lsp_store.language_server_for_id(server_id) {
9553 Some(server.notify::<lsp_store::lsp_ext_command::LspExtClearFlycheck>(()))
9554 } else {
9555 None
9556 }
9557 });
9558
9559 Ok(proto::Ack {})
9560 }
9561
9562 pub fn disk_based_diagnostics_started(
9563 &mut self,
9564 language_server_id: LanguageServerId,
9565 cx: &mut Context<Self>,
9566 ) {
9567 if let Some(language_server_status) =
9568 self.language_server_statuses.get_mut(&language_server_id)
9569 {
9570 language_server_status.has_pending_diagnostic_updates = true;
9571 }
9572
9573 cx.emit(LspStoreEvent::DiskBasedDiagnosticsStarted { language_server_id });
9574 cx.emit(LspStoreEvent::LanguageServerUpdate {
9575 language_server_id,
9576 name: self
9577 .language_server_adapter_for_id(language_server_id)
9578 .map(|adapter| adapter.name()),
9579 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdating(
9580 Default::default(),
9581 ),
9582 })
9583 }
9584
9585 pub fn disk_based_diagnostics_finished(
9586 &mut self,
9587 language_server_id: LanguageServerId,
9588 cx: &mut Context<Self>,
9589 ) {
9590 if let Some(language_server_status) =
9591 self.language_server_statuses.get_mut(&language_server_id)
9592 {
9593 language_server_status.has_pending_diagnostic_updates = false;
9594 }
9595
9596 cx.emit(LspStoreEvent::DiskBasedDiagnosticsFinished { language_server_id });
9597 cx.emit(LspStoreEvent::LanguageServerUpdate {
9598 language_server_id,
9599 name: self
9600 .language_server_adapter_for_id(language_server_id)
9601 .map(|adapter| adapter.name()),
9602 message: proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
9603 Default::default(),
9604 ),
9605 })
9606 }
9607
9608 // After saving a buffer using a language server that doesn't provide a disk-based progress token,
9609 // kick off a timer that will reset every time the buffer is saved. If the timer eventually fires,
9610 // simulate disk-based diagnostics being finished so that other pieces of UI (e.g., project
9611 // diagnostics view, diagnostic status bar) can update. We don't emit an event right away because
9612 // the language server might take some time to publish diagnostics.
9613 fn simulate_disk_based_diagnostics_events_if_needed(
9614 &mut self,
9615 language_server_id: LanguageServerId,
9616 cx: &mut Context<Self>,
9617 ) {
9618 const DISK_BASED_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_secs(1);
9619
9620 let Some(LanguageServerState::Running {
9621 simulate_disk_based_diagnostics_completion,
9622 adapter,
9623 ..
9624 }) = self
9625 .as_local_mut()
9626 .and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
9627 else {
9628 return;
9629 };
9630
9631 if adapter.disk_based_diagnostics_progress_token.is_some() {
9632 return;
9633 }
9634
9635 let prev_task =
9636 simulate_disk_based_diagnostics_completion.replace(cx.spawn(async move |this, cx| {
9637 cx.background_executor()
9638 .timer(DISK_BASED_DIAGNOSTICS_DEBOUNCE)
9639 .await;
9640
9641 this.update(cx, |this, cx| {
9642 this.disk_based_diagnostics_finished(language_server_id, cx);
9643
9644 if let Some(LanguageServerState::Running {
9645 simulate_disk_based_diagnostics_completion,
9646 ..
9647 }) = this.as_local_mut().and_then(|local_store| {
9648 local_store.language_servers.get_mut(&language_server_id)
9649 }) {
9650 *simulate_disk_based_diagnostics_completion = None;
9651 }
9652 })
9653 .ok();
9654 }));
9655
9656 if prev_task.is_none() {
9657 self.disk_based_diagnostics_started(language_server_id, cx);
9658 }
9659 }
9660
9661 pub fn language_server_statuses(
9662 &self,
9663 ) -> impl DoubleEndedIterator<Item = (LanguageServerId, &LanguageServerStatus)> {
9664 self.language_server_statuses
9665 .iter()
9666 .map(|(key, value)| (*key, value))
9667 }
9668
9669 pub(super) fn did_rename_entry(
9670 &self,
9671 worktree_id: WorktreeId,
9672 old_path: &Path,
9673 new_path: &Path,
9674 is_dir: bool,
9675 ) {
9676 maybe!({
9677 let local_store = self.as_local()?;
9678
9679 let old_uri = lsp::Uri::from_file_path(old_path)
9680 .ok()
9681 .map(|uri| uri.to_string())?;
9682 let new_uri = lsp::Uri::from_file_path(new_path)
9683 .ok()
9684 .map(|uri| uri.to_string())?;
9685
9686 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9687 let Some(filter) = local_store
9688 .language_server_paths_watched_for_rename
9689 .get(&language_server.server_id())
9690 else {
9691 continue;
9692 };
9693
9694 if filter.should_send_did_rename(&old_uri, is_dir) {
9695 language_server
9696 .notify::<DidRenameFiles>(RenameFilesParams {
9697 files: vec![FileRename {
9698 old_uri: old_uri.clone(),
9699 new_uri: new_uri.clone(),
9700 }],
9701 })
9702 .ok();
9703 }
9704 }
9705 Some(())
9706 });
9707 }
9708
9709 pub(super) fn will_rename_entry(
9710 this: WeakEntity<Self>,
9711 worktree_id: WorktreeId,
9712 old_path: &Path,
9713 new_path: &Path,
9714 is_dir: bool,
9715 cx: AsyncApp,
9716 ) -> Task<ProjectTransaction> {
9717 let old_uri = lsp::Uri::from_file_path(old_path)
9718 .ok()
9719 .map(|uri| uri.to_string());
9720 let new_uri = lsp::Uri::from_file_path(new_path)
9721 .ok()
9722 .map(|uri| uri.to_string());
9723 cx.spawn(async move |cx| {
9724 let mut tasks = vec![];
9725 this.update(cx, |this, cx| {
9726 let local_store = this.as_local()?;
9727 let old_uri = old_uri?;
9728 let new_uri = new_uri?;
9729 for language_server in local_store.language_servers_for_worktree(worktree_id) {
9730 let Some(filter) = local_store
9731 .language_server_paths_watched_for_rename
9732 .get(&language_server.server_id())
9733 else {
9734 continue;
9735 };
9736
9737 if !filter.should_send_will_rename(&old_uri, is_dir) {
9738 continue;
9739 }
9740 let request_timeout = ProjectSettings::get_global(cx)
9741 .global_lsp_settings
9742 .get_request_timeout();
9743
9744 let apply_edit = cx.spawn({
9745 let old_uri = old_uri.clone();
9746 let new_uri = new_uri.clone();
9747 let language_server = language_server.clone();
9748 async move |this, cx| {
9749 let edit = language_server
9750 .request::<WillRenameFiles>(
9751 RenameFilesParams {
9752 files: vec![FileRename { old_uri, new_uri }],
9753 },
9754 request_timeout,
9755 )
9756 .await
9757 .into_response()
9758 .context("will rename files")
9759 .log_err()
9760 .flatten()?;
9761
9762 LocalLspStore::deserialize_workspace_edit(
9763 this.upgrade()?,
9764 edit,
9765 false,
9766 language_server.clone(),
9767 cx,
9768 )
9769 .await
9770 .ok()
9771 }
9772 });
9773 tasks.push(apply_edit);
9774 }
9775 Some(())
9776 })
9777 .ok()
9778 .flatten();
9779 let mut merged_transaction = ProjectTransaction::default();
9780 for task in tasks {
9781 // Await on tasks sequentially so that the order of application of edits is deterministic
9782 // (at least with regards to the order of registration of language servers)
9783 if let Some(transaction) = task.await {
9784 for (buffer, buffer_transaction) in transaction.0 {
9785 merged_transaction.0.insert(buffer, buffer_transaction);
9786 }
9787 }
9788 }
9789 merged_transaction
9790 })
9791 }
9792
9793 fn lsp_notify_abs_paths_changed(
9794 &mut self,
9795 server_id: LanguageServerId,
9796 changes: Vec<PathEvent>,
9797 ) {
9798 maybe!({
9799 let server = self.language_server_for_id(server_id)?;
9800 let changes = changes
9801 .into_iter()
9802 .filter_map(|event| {
9803 let typ = match event.kind? {
9804 PathEventKind::Created => lsp::FileChangeType::CREATED,
9805 PathEventKind::Removed => lsp::FileChangeType::DELETED,
9806 PathEventKind::Changed => lsp::FileChangeType::CHANGED,
9807 };
9808 Some(lsp::FileEvent {
9809 uri: file_path_to_lsp_url(&event.path).log_err()?,
9810 typ,
9811 })
9812 })
9813 .collect::<Vec<_>>();
9814 if !changes.is_empty() {
9815 server
9816 .notify::<lsp::notification::DidChangeWatchedFiles>(
9817 lsp::DidChangeWatchedFilesParams { changes },
9818 )
9819 .ok();
9820 }
9821 Some(())
9822 });
9823 }
9824
9825 pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
9826 self.as_local()?.language_server_for_id(id)
9827 }
9828
9829 fn on_lsp_progress(
9830 &mut self,
9831 progress_params: lsp::ProgressParams,
9832 language_server_id: LanguageServerId,
9833 disk_based_diagnostics_progress_token: Option<String>,
9834 cx: &mut Context<Self>,
9835 ) {
9836 match progress_params.value {
9837 lsp::ProgressParamsValue::WorkDone(progress) => {
9838 self.handle_work_done_progress(
9839 progress,
9840 language_server_id,
9841 disk_based_diagnostics_progress_token,
9842 ProgressToken::from_lsp(progress_params.token),
9843 cx,
9844 );
9845 }
9846 lsp::ProgressParamsValue::WorkspaceDiagnostic(report) => {
9847 let registration_id = match progress_params.token {
9848 lsp::NumberOrString::Number(_) => None,
9849 lsp::NumberOrString::String(token) => token
9850 .split_once(WORKSPACE_DIAGNOSTICS_TOKEN_START)
9851 .map(|(_, id)| id.to_owned()),
9852 };
9853 if let Some(LanguageServerState::Running {
9854 workspace_diagnostics_refresh_tasks,
9855 ..
9856 }) = self
9857 .as_local_mut()
9858 .and_then(|local| local.language_servers.get_mut(&language_server_id))
9859 && let Some(workspace_diagnostics) =
9860 workspace_diagnostics_refresh_tasks.get_mut(®istration_id)
9861 {
9862 workspace_diagnostics.progress_tx.try_send(()).ok();
9863 self.apply_workspace_diagnostic_report(
9864 language_server_id,
9865 report,
9866 registration_id.map(SharedString::from),
9867 cx,
9868 )
9869 }
9870 }
9871 }
9872 }
9873
9874 fn handle_work_done_progress(
9875 &mut self,
9876 progress: lsp::WorkDoneProgress,
9877 language_server_id: LanguageServerId,
9878 disk_based_diagnostics_progress_token: Option<String>,
9879 token: ProgressToken,
9880 cx: &mut Context<Self>,
9881 ) {
9882 let language_server_status =
9883 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9884 status
9885 } else {
9886 return;
9887 };
9888
9889 if !language_server_status.progress_tokens.contains(&token) {
9890 return;
9891 }
9892
9893 let is_disk_based_diagnostics_progress =
9894 if let (Some(disk_based_token), ProgressToken::String(token)) =
9895 (&disk_based_diagnostics_progress_token, &token)
9896 {
9897 token.starts_with(disk_based_token)
9898 } else {
9899 false
9900 };
9901
9902 match progress {
9903 lsp::WorkDoneProgress::Begin(report) => {
9904 if is_disk_based_diagnostics_progress {
9905 self.disk_based_diagnostics_started(language_server_id, cx);
9906 }
9907 self.on_lsp_work_start(
9908 language_server_id,
9909 token.clone(),
9910 LanguageServerProgress {
9911 title: Some(report.title),
9912 is_disk_based_diagnostics_progress,
9913 is_cancellable: report.cancellable.unwrap_or(false),
9914 message: report.message.clone(),
9915 percentage: report.percentage.map(|p| p as usize),
9916 last_update_at: cx.background_executor().now(),
9917 },
9918 cx,
9919 );
9920 }
9921 lsp::WorkDoneProgress::Report(report) => self.on_lsp_work_progress(
9922 language_server_id,
9923 token,
9924 LanguageServerProgress {
9925 title: None,
9926 is_disk_based_diagnostics_progress,
9927 is_cancellable: report.cancellable.unwrap_or(false),
9928 message: report.message,
9929 percentage: report.percentage.map(|p| p as usize),
9930 last_update_at: cx.background_executor().now(),
9931 },
9932 cx,
9933 ),
9934 lsp::WorkDoneProgress::End(_) => {
9935 language_server_status.progress_tokens.remove(&token);
9936 self.on_lsp_work_end(language_server_id, token.clone(), cx);
9937 if is_disk_based_diagnostics_progress {
9938 self.disk_based_diagnostics_finished(language_server_id, cx);
9939 }
9940 }
9941 }
9942 }
9943
9944 fn on_lsp_work_start(
9945 &mut self,
9946 language_server_id: LanguageServerId,
9947 token: ProgressToken,
9948 progress: LanguageServerProgress,
9949 cx: &mut Context<Self>,
9950 ) {
9951 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9952 status.pending_work.insert(token.clone(), progress.clone());
9953 cx.notify();
9954 }
9955 cx.emit(LspStoreEvent::LanguageServerUpdate {
9956 language_server_id,
9957 name: self
9958 .language_server_adapter_for_id(language_server_id)
9959 .map(|adapter| adapter.name()),
9960 message: proto::update_language_server::Variant::WorkStart(proto::LspWorkStart {
9961 token: Some(token.to_proto()),
9962 title: progress.title,
9963 message: progress.message,
9964 percentage: progress.percentage.map(|p| p as u32),
9965 is_cancellable: Some(progress.is_cancellable),
9966 }),
9967 })
9968 }
9969
9970 fn on_lsp_work_progress(
9971 &mut self,
9972 language_server_id: LanguageServerId,
9973 token: ProgressToken,
9974 progress: LanguageServerProgress,
9975 cx: &mut Context<Self>,
9976 ) {
9977 let mut did_update = false;
9978 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
9979 match status.pending_work.entry(token.clone()) {
9980 btree_map::Entry::Vacant(entry) => {
9981 entry.insert(progress.clone());
9982 did_update = true;
9983 }
9984 btree_map::Entry::Occupied(mut entry) => {
9985 let entry = entry.get_mut();
9986 if (progress.last_update_at - entry.last_update_at)
9987 >= SERVER_PROGRESS_THROTTLE_TIMEOUT
9988 {
9989 entry.last_update_at = progress.last_update_at;
9990 if progress.message.is_some() {
9991 entry.message = progress.message.clone();
9992 }
9993 if progress.percentage.is_some() {
9994 entry.percentage = progress.percentage;
9995 }
9996 if progress.is_cancellable != entry.is_cancellable {
9997 entry.is_cancellable = progress.is_cancellable;
9998 }
9999 did_update = true;
10000 }
10001 }
10002 }
10003 }
10004
10005 if did_update {
10006 cx.emit(LspStoreEvent::LanguageServerUpdate {
10007 language_server_id,
10008 name: self
10009 .language_server_adapter_for_id(language_server_id)
10010 .map(|adapter| adapter.name()),
10011 message: proto::update_language_server::Variant::WorkProgress(
10012 proto::LspWorkProgress {
10013 token: Some(token.to_proto()),
10014 message: progress.message,
10015 percentage: progress.percentage.map(|p| p as u32),
10016 is_cancellable: Some(progress.is_cancellable),
10017 },
10018 ),
10019 })
10020 }
10021 }
10022
10023 fn on_lsp_work_end(
10024 &mut self,
10025 language_server_id: LanguageServerId,
10026 token: ProgressToken,
10027 cx: &mut Context<Self>,
10028 ) {
10029 if let Some(status) = self.language_server_statuses.get_mut(&language_server_id) {
10030 if let Some(work) = status.pending_work.remove(&token)
10031 && !work.is_disk_based_diagnostics_progress
10032 {
10033 cx.emit(LspStoreEvent::RefreshInlayHints {
10034 server_id: language_server_id,
10035 request_id: None,
10036 });
10037 }
10038 cx.notify();
10039 }
10040
10041 cx.emit(LspStoreEvent::LanguageServerUpdate {
10042 language_server_id,
10043 name: self
10044 .language_server_adapter_for_id(language_server_id)
10045 .map(|adapter| adapter.name()),
10046 message: proto::update_language_server::Variant::WorkEnd(proto::LspWorkEnd {
10047 token: Some(token.to_proto()),
10048 }),
10049 })
10050 }
10051
10052 pub async fn handle_resolve_completion_documentation(
10053 this: Entity<Self>,
10054 envelope: TypedEnvelope<proto::ResolveCompletionDocumentation>,
10055 mut cx: AsyncApp,
10056 ) -> Result<proto::ResolveCompletionDocumentationResponse> {
10057 let lsp_completion = serde_json::from_slice(&envelope.payload.lsp_completion)?;
10058
10059 let completion = this
10060 .read_with(&cx, |this, cx| {
10061 let id = LanguageServerId(envelope.payload.language_server_id as usize);
10062 let server = this
10063 .language_server_for_id(id)
10064 .with_context(|| format!("No language server {id}"))?;
10065
10066 let request_timeout = ProjectSettings::get_global(cx)
10067 .global_lsp_settings
10068 .get_request_timeout();
10069
10070 anyhow::Ok(cx.background_spawn(async move {
10071 let can_resolve = server
10072 .capabilities()
10073 .completion_provider
10074 .as_ref()
10075 .and_then(|options| options.resolve_provider)
10076 .unwrap_or(false);
10077 if can_resolve {
10078 server
10079 .request::<lsp::request::ResolveCompletionItem>(
10080 lsp_completion,
10081 request_timeout,
10082 )
10083 .await
10084 .into_response()
10085 .context("resolve completion item")
10086 } else {
10087 anyhow::Ok(lsp_completion)
10088 }
10089 }))
10090 })?
10091 .await?;
10092
10093 let mut documentation_is_markdown = false;
10094 let lsp_completion = serde_json::to_string(&completion)?.into_bytes();
10095 let documentation = match completion.documentation {
10096 Some(lsp::Documentation::String(text)) => text,
10097
10098 Some(lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value })) => {
10099 documentation_is_markdown = kind == lsp::MarkupKind::Markdown;
10100 value
10101 }
10102
10103 _ => String::new(),
10104 };
10105
10106 // If we have a new buffer_id, that means we're talking to a new client
10107 // and want to check for new text_edits in the completion too.
10108 let mut old_replace_start = None;
10109 let mut old_replace_end = None;
10110 let mut old_insert_start = None;
10111 let mut old_insert_end = None;
10112 let mut new_text = String::default();
10113 if let Ok(buffer_id) = BufferId::new(envelope.payload.buffer_id) {
10114 let buffer_snapshot = this.update(&mut cx, |this, cx| {
10115 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10116 anyhow::Ok(buffer.read(cx).snapshot())
10117 })?;
10118
10119 if let Some(text_edit) = completion.text_edit.as_ref() {
10120 let edit = parse_completion_text_edit(text_edit, &buffer_snapshot);
10121
10122 if let Some(mut edit) = edit {
10123 LineEnding::normalize(&mut edit.new_text);
10124
10125 new_text = edit.new_text;
10126 old_replace_start = Some(serialize_anchor(&edit.replace_range.start));
10127 old_replace_end = Some(serialize_anchor(&edit.replace_range.end));
10128 if let Some(insert_range) = edit.insert_range {
10129 old_insert_start = Some(serialize_anchor(&insert_range.start));
10130 old_insert_end = Some(serialize_anchor(&insert_range.end));
10131 }
10132 }
10133 }
10134 }
10135
10136 Ok(proto::ResolveCompletionDocumentationResponse {
10137 documentation,
10138 documentation_is_markdown,
10139 old_replace_start,
10140 old_replace_end,
10141 new_text,
10142 lsp_completion,
10143 old_insert_start,
10144 old_insert_end,
10145 })
10146 }
10147
10148 async fn handle_on_type_formatting(
10149 this: Entity<Self>,
10150 envelope: TypedEnvelope<proto::OnTypeFormatting>,
10151 mut cx: AsyncApp,
10152 ) -> Result<proto::OnTypeFormattingResponse> {
10153 let on_type_formatting = this.update(&mut cx, |this, cx| {
10154 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10155 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10156 let position = envelope
10157 .payload
10158 .position
10159 .and_then(deserialize_anchor)
10160 .context("invalid position")?;
10161 anyhow::Ok(this.apply_on_type_formatting(
10162 buffer,
10163 position,
10164 envelope.payload.trigger.clone(),
10165 cx,
10166 ))
10167 })?;
10168
10169 let transaction = on_type_formatting
10170 .await?
10171 .as_ref()
10172 .map(language::proto::serialize_transaction);
10173 Ok(proto::OnTypeFormattingResponse { transaction })
10174 }
10175
10176 async fn handle_pull_workspace_diagnostics(
10177 lsp_store: Entity<Self>,
10178 envelope: TypedEnvelope<proto::PullWorkspaceDiagnostics>,
10179 mut cx: AsyncApp,
10180 ) -> Result<proto::Ack> {
10181 let server_id = LanguageServerId::from_proto(envelope.payload.server_id);
10182 lsp_store.update(&mut cx, |lsp_store, _| {
10183 lsp_store.pull_workspace_diagnostics(server_id);
10184 });
10185 Ok(proto::Ack {})
10186 }
10187
10188 async fn handle_open_buffer_for_symbol(
10189 this: Entity<Self>,
10190 envelope: TypedEnvelope<proto::OpenBufferForSymbol>,
10191 mut cx: AsyncApp,
10192 ) -> Result<proto::OpenBufferForSymbolResponse> {
10193 let peer_id = envelope.original_sender_id().unwrap_or_default();
10194 let symbol = envelope.payload.symbol.context("invalid symbol")?;
10195 let symbol = Self::deserialize_symbol(symbol)?;
10196 this.read_with(&cx, |this, _| {
10197 if let SymbolLocation::OutsideProject {
10198 abs_path,
10199 signature,
10200 } = &symbol.path
10201 {
10202 let new_signature = this.symbol_signature(&abs_path);
10203 anyhow::ensure!(&new_signature == signature, "invalid symbol signature");
10204 }
10205 Ok(())
10206 })?;
10207 let buffer = this
10208 .update(&mut cx, |this, cx| {
10209 this.open_buffer_for_symbol(
10210 &Symbol {
10211 language_server_name: symbol.language_server_name,
10212 source_worktree_id: symbol.source_worktree_id,
10213 source_language_server_id: symbol.source_language_server_id,
10214 path: symbol.path,
10215 name: symbol.name,
10216 kind: symbol.kind,
10217 range: symbol.range,
10218 label: CodeLabel::default(),
10219 container_name: symbol.container_name,
10220 },
10221 cx,
10222 )
10223 })
10224 .await?;
10225
10226 this.update(&mut cx, |this, cx| {
10227 let is_private = buffer
10228 .read(cx)
10229 .file()
10230 .map(|f| f.is_private())
10231 .unwrap_or_default();
10232 if is_private {
10233 Err(anyhow!(rpc::ErrorCode::UnsharedItem))
10234 } else {
10235 this.buffer_store
10236 .update(cx, |buffer_store, cx| {
10237 buffer_store.create_buffer_for_peer(&buffer, peer_id, cx)
10238 })
10239 .detach_and_log_err(cx);
10240 let buffer_id = buffer.read(cx).remote_id().to_proto();
10241 Ok(proto::OpenBufferForSymbolResponse { buffer_id })
10242 }
10243 })
10244 }
10245
10246 fn symbol_signature(&self, abs_path: &Path) -> [u8; 32] {
10247 let mut hasher = Sha256::new();
10248 hasher.update(abs_path.to_string_lossy().as_bytes());
10249 hasher.update(self.nonce.to_be_bytes());
10250 hasher.finalize().as_slice().try_into().unwrap()
10251 }
10252
10253 pub async fn handle_get_project_symbols(
10254 this: Entity<Self>,
10255 envelope: TypedEnvelope<proto::GetProjectSymbols>,
10256 mut cx: AsyncApp,
10257 ) -> Result<proto::GetProjectSymbolsResponse> {
10258 let symbols = this
10259 .update(&mut cx, |this, cx| {
10260 this.symbols(&envelope.payload.query, cx)
10261 })
10262 .await?;
10263
10264 Ok(proto::GetProjectSymbolsResponse {
10265 symbols: symbols.iter().map(Self::serialize_symbol).collect(),
10266 })
10267 }
10268
10269 pub async fn handle_restart_language_servers(
10270 this: Entity<Self>,
10271 envelope: TypedEnvelope<proto::RestartLanguageServers>,
10272 mut cx: AsyncApp,
10273 ) -> Result<proto::Ack> {
10274 this.update(&mut cx, |lsp_store, cx| {
10275 let buffers =
10276 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10277 lsp_store.restart_language_servers_for_buffers(
10278 buffers,
10279 envelope
10280 .payload
10281 .only_servers
10282 .into_iter()
10283 .filter_map(|selector| {
10284 Some(match selector.selector? {
10285 proto::language_server_selector::Selector::ServerId(server_id) => {
10286 LanguageServerSelector::Id(LanguageServerId::from_proto(server_id))
10287 }
10288 proto::language_server_selector::Selector::Name(name) => {
10289 LanguageServerSelector::Name(LanguageServerName(
10290 SharedString::from(name),
10291 ))
10292 }
10293 })
10294 })
10295 .collect(),
10296 cx,
10297 );
10298 });
10299
10300 Ok(proto::Ack {})
10301 }
10302
10303 pub async fn handle_stop_language_servers(
10304 lsp_store: Entity<Self>,
10305 envelope: TypedEnvelope<proto::StopLanguageServers>,
10306 mut cx: AsyncApp,
10307 ) -> Result<proto::Ack> {
10308 lsp_store.update(&mut cx, |lsp_store, cx| {
10309 if envelope.payload.all
10310 && envelope.payload.also_servers.is_empty()
10311 && envelope.payload.buffer_ids.is_empty()
10312 {
10313 lsp_store.stop_all_language_servers(cx);
10314 } else {
10315 let buffers =
10316 lsp_store.buffer_ids_to_buffers(envelope.payload.buffer_ids.into_iter(), cx);
10317 lsp_store
10318 .stop_language_servers_for_buffers(
10319 buffers,
10320 envelope
10321 .payload
10322 .also_servers
10323 .into_iter()
10324 .filter_map(|selector| {
10325 Some(match selector.selector? {
10326 proto::language_server_selector::Selector::ServerId(
10327 server_id,
10328 ) => LanguageServerSelector::Id(LanguageServerId::from_proto(
10329 server_id,
10330 )),
10331 proto::language_server_selector::Selector::Name(name) => {
10332 LanguageServerSelector::Name(LanguageServerName(
10333 SharedString::from(name),
10334 ))
10335 }
10336 })
10337 })
10338 .collect(),
10339 cx,
10340 )
10341 .detach_and_log_err(cx);
10342 }
10343 });
10344
10345 Ok(proto::Ack {})
10346 }
10347
10348 pub async fn handle_cancel_language_server_work(
10349 lsp_store: Entity<Self>,
10350 envelope: TypedEnvelope<proto::CancelLanguageServerWork>,
10351 mut cx: AsyncApp,
10352 ) -> Result<proto::Ack> {
10353 lsp_store.update(&mut cx, |lsp_store, cx| {
10354 if let Some(work) = envelope.payload.work {
10355 match work {
10356 proto::cancel_language_server_work::Work::Buffers(buffers) => {
10357 let buffers =
10358 lsp_store.buffer_ids_to_buffers(buffers.buffer_ids.into_iter(), cx);
10359 lsp_store.cancel_language_server_work_for_buffers(buffers, cx);
10360 }
10361 proto::cancel_language_server_work::Work::LanguageServerWork(work) => {
10362 let server_id = LanguageServerId::from_proto(work.language_server_id);
10363 let token = work
10364 .token
10365 .map(|token| {
10366 ProgressToken::from_proto(token)
10367 .context("invalid work progress token")
10368 })
10369 .transpose()?;
10370 lsp_store.cancel_language_server_work(server_id, token, cx);
10371 }
10372 }
10373 }
10374 anyhow::Ok(())
10375 })?;
10376
10377 Ok(proto::Ack {})
10378 }
10379
10380 fn buffer_ids_to_buffers(
10381 &mut self,
10382 buffer_ids: impl Iterator<Item = u64>,
10383 cx: &mut Context<Self>,
10384 ) -> Vec<Entity<Buffer>> {
10385 buffer_ids
10386 .into_iter()
10387 .flat_map(|buffer_id| {
10388 self.buffer_store
10389 .read(cx)
10390 .get(BufferId::new(buffer_id).log_err()?)
10391 })
10392 .collect::<Vec<_>>()
10393 }
10394
10395 async fn handle_apply_additional_edits_for_completion(
10396 this: Entity<Self>,
10397 envelope: TypedEnvelope<proto::ApplyCompletionAdditionalEdits>,
10398 mut cx: AsyncApp,
10399 ) -> Result<proto::ApplyCompletionAdditionalEditsResponse> {
10400 let (buffer, completion) = this.update(&mut cx, |this, cx| {
10401 let buffer_id = BufferId::new(envelope.payload.buffer_id)?;
10402 let buffer = this.buffer_store.read(cx).get_existing(buffer_id)?;
10403 let completion = Self::deserialize_completion(
10404 envelope.payload.completion.context("invalid completion")?,
10405 )?;
10406 anyhow::Ok((buffer, completion))
10407 })?;
10408
10409 let apply_additional_edits = this.update(&mut cx, |this, cx| {
10410 this.apply_additional_edits_for_completion(
10411 buffer,
10412 Rc::new(RefCell::new(Box::new([Completion {
10413 replace_range: completion.replace_range,
10414 new_text: completion.new_text,
10415 source: completion.source,
10416 documentation: None,
10417 label: CodeLabel::default(),
10418 match_start: None,
10419 snippet_deduplication_key: None,
10420 insert_text_mode: None,
10421 icon_path: None,
10422 confirm: None,
10423 }]))),
10424 0,
10425 false,
10426 cx,
10427 )
10428 });
10429
10430 Ok(proto::ApplyCompletionAdditionalEditsResponse {
10431 transaction: apply_additional_edits
10432 .await?
10433 .as_ref()
10434 .map(language::proto::serialize_transaction),
10435 })
10436 }
10437
10438 pub fn last_formatting_failure(&self) -> Option<&str> {
10439 self.last_formatting_failure.as_deref()
10440 }
10441
10442 pub fn reset_last_formatting_failure(&mut self) {
10443 self.last_formatting_failure = None;
10444 }
10445
10446 pub fn environment_for_buffer(
10447 &self,
10448 buffer: &Entity<Buffer>,
10449 cx: &mut Context<Self>,
10450 ) -> Shared<Task<Option<HashMap<String, String>>>> {
10451 if let Some(environment) = &self.as_local().map(|local| local.environment.clone()) {
10452 environment.update(cx, |env, cx| {
10453 env.buffer_environment(buffer, &self.worktree_store, cx)
10454 })
10455 } else {
10456 Task::ready(None).shared()
10457 }
10458 }
10459
10460 pub fn format(
10461 &mut self,
10462 buffers: HashSet<Entity<Buffer>>,
10463 target: LspFormatTarget,
10464 push_to_history: bool,
10465 trigger: FormatTrigger,
10466 cx: &mut Context<Self>,
10467 ) -> Task<anyhow::Result<ProjectTransaction>> {
10468 let logger = zlog::scoped!("format");
10469 if self.as_local().is_some() {
10470 zlog::trace!(logger => "Formatting locally");
10471 let logger = zlog::scoped!(logger => "local");
10472 let buffers = buffers
10473 .into_iter()
10474 .map(|buffer_handle| {
10475 let buffer = buffer_handle.read(cx);
10476 let buffer_abs_path = File::from_dyn(buffer.file())
10477 .and_then(|file| file.as_local().map(|f| f.abs_path(cx)));
10478
10479 (buffer_handle, buffer_abs_path, buffer.remote_id())
10480 })
10481 .collect::<Vec<_>>();
10482
10483 cx.spawn(async move |lsp_store, cx| {
10484 let mut formattable_buffers = Vec::with_capacity(buffers.len());
10485
10486 for (handle, abs_path, id) in buffers {
10487 let env = lsp_store
10488 .update(cx, |lsp_store, cx| {
10489 lsp_store.environment_for_buffer(&handle, cx)
10490 })?
10491 .await;
10492
10493 let ranges = match &target {
10494 LspFormatTarget::Buffers => None,
10495 LspFormatTarget::Ranges(ranges) => {
10496 Some(ranges.get(&id).context("No format ranges provided for buffer")?.clone())
10497 }
10498 };
10499
10500 formattable_buffers.push(FormattableBuffer {
10501 handle,
10502 abs_path,
10503 env,
10504 ranges,
10505 });
10506 }
10507 zlog::trace!(logger => "Formatting {:?} buffers", formattable_buffers.len());
10508
10509 let format_timer = zlog::time!(logger => "Formatting buffers");
10510 let result = LocalLspStore::format_locally(
10511 lsp_store.clone(),
10512 formattable_buffers,
10513 push_to_history,
10514 trigger,
10515 logger,
10516 cx,
10517 )
10518 .await;
10519 format_timer.end();
10520
10521 zlog::trace!(logger => "Formatting completed with result {:?}", result.as_ref().map(|_| "<project-transaction>"));
10522
10523 lsp_store.update(cx, |lsp_store, _| {
10524 lsp_store.update_last_formatting_failure(&result);
10525 })?;
10526
10527 result
10528 })
10529 } else if let Some((client, project_id)) = self.upstream_client() {
10530 zlog::trace!(logger => "Formatting remotely");
10531 let logger = zlog::scoped!(logger => "remote");
10532
10533 let buffer_ranges = match &target {
10534 LspFormatTarget::Buffers => Vec::new(),
10535 LspFormatTarget::Ranges(ranges) => ranges
10536 .iter()
10537 .map(|(buffer_id, ranges)| proto::BufferFormatRanges {
10538 buffer_id: buffer_id.to_proto(),
10539 ranges: ranges.iter().cloned().map(serialize_anchor_range).collect(),
10540 })
10541 .collect(),
10542 };
10543
10544 let buffer_store = self.buffer_store();
10545 cx.spawn(async move |lsp_store, cx| {
10546 zlog::trace!(logger => "Sending remote format request");
10547 let request_timer = zlog::time!(logger => "remote format request");
10548 let result = client
10549 .request(proto::FormatBuffers {
10550 project_id,
10551 trigger: trigger as i32,
10552 buffer_ids: buffers
10553 .iter()
10554 .map(|buffer| buffer.read_with(cx, |buffer, _| buffer.remote_id().to_proto()))
10555 .collect(),
10556 buffer_ranges,
10557 })
10558 .await
10559 .and_then(|result| result.transaction.context("missing transaction"));
10560 request_timer.end();
10561
10562 zlog::trace!(logger => "Remote format request resolved to {:?}", result.as_ref().map(|_| "<project_transaction>"));
10563
10564 lsp_store.update(cx, |lsp_store, _| {
10565 lsp_store.update_last_formatting_failure(&result);
10566 })?;
10567
10568 let transaction_response = result?;
10569 let _timer = zlog::time!(logger => "deserializing project transaction");
10570 buffer_store
10571 .update(cx, |buffer_store, cx| {
10572 buffer_store.deserialize_project_transaction(
10573 transaction_response,
10574 push_to_history,
10575 cx,
10576 )
10577 })
10578 .await
10579 })
10580 } else {
10581 zlog::trace!(logger => "Not formatting");
10582 Task::ready(Ok(ProjectTransaction::default()))
10583 }
10584 }
10585
10586 async fn handle_format_buffers(
10587 this: Entity<Self>,
10588 envelope: TypedEnvelope<proto::FormatBuffers>,
10589 mut cx: AsyncApp,
10590 ) -> Result<proto::FormatBuffersResponse> {
10591 let sender_id = envelope.original_sender_id().unwrap_or_default();
10592 let format = this.update(&mut cx, |this, cx| {
10593 let mut buffers = HashSet::default();
10594 for buffer_id in &envelope.payload.buffer_ids {
10595 let buffer_id = BufferId::new(*buffer_id)?;
10596 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10597 }
10598
10599 let target = if envelope.payload.buffer_ranges.is_empty() {
10600 LspFormatTarget::Buffers
10601 } else {
10602 let mut ranges_map = BTreeMap::new();
10603 for buffer_range in &envelope.payload.buffer_ranges {
10604 let buffer_id = BufferId::new(buffer_range.buffer_id)?;
10605 let ranges: Result<Vec<_>> = buffer_range
10606 .ranges
10607 .iter()
10608 .map(|range| {
10609 deserialize_anchor_range(range.clone()).context("invalid anchor range")
10610 })
10611 .collect();
10612 ranges_map.insert(buffer_id, ranges?);
10613 }
10614 LspFormatTarget::Ranges(ranges_map)
10615 };
10616
10617 let trigger = FormatTrigger::from_proto(envelope.payload.trigger);
10618 anyhow::Ok(this.format(buffers, target, false, trigger, cx))
10619 })?;
10620
10621 let project_transaction = format.await?;
10622 let project_transaction = this.update(&mut cx, |this, cx| {
10623 this.buffer_store.update(cx, |buffer_store, cx| {
10624 buffer_store.serialize_project_transaction_for_peer(
10625 project_transaction,
10626 sender_id,
10627 cx,
10628 )
10629 })
10630 });
10631 Ok(proto::FormatBuffersResponse {
10632 transaction: Some(project_transaction),
10633 })
10634 }
10635
10636 async fn handle_apply_code_action_kind(
10637 this: Entity<Self>,
10638 envelope: TypedEnvelope<proto::ApplyCodeActionKind>,
10639 mut cx: AsyncApp,
10640 ) -> Result<proto::ApplyCodeActionKindResponse> {
10641 let sender_id = envelope.original_sender_id().unwrap_or_default();
10642 let format = this.update(&mut cx, |this, cx| {
10643 let mut buffers = HashSet::default();
10644 for buffer_id in &envelope.payload.buffer_ids {
10645 let buffer_id = BufferId::new(*buffer_id)?;
10646 buffers.insert(this.buffer_store.read(cx).get_existing(buffer_id)?);
10647 }
10648 let kind = match envelope.payload.kind.as_str() {
10649 "" => CodeActionKind::EMPTY,
10650 "quickfix" => CodeActionKind::QUICKFIX,
10651 "refactor" => CodeActionKind::REFACTOR,
10652 "refactor.extract" => CodeActionKind::REFACTOR_EXTRACT,
10653 "refactor.inline" => CodeActionKind::REFACTOR_INLINE,
10654 "refactor.rewrite" => CodeActionKind::REFACTOR_REWRITE,
10655 "source" => CodeActionKind::SOURCE,
10656 "source.organizeImports" => CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
10657 "source.fixAll" => CodeActionKind::SOURCE_FIX_ALL,
10658 _ => anyhow::bail!(
10659 "Invalid code action kind {}",
10660 envelope.payload.kind.as_str()
10661 ),
10662 };
10663 anyhow::Ok(this.apply_code_action_kind(buffers, kind, false, cx))
10664 })?;
10665
10666 let project_transaction = format.await?;
10667 let project_transaction = this.update(&mut cx, |this, cx| {
10668 this.buffer_store.update(cx, |buffer_store, cx| {
10669 buffer_store.serialize_project_transaction_for_peer(
10670 project_transaction,
10671 sender_id,
10672 cx,
10673 )
10674 })
10675 });
10676 Ok(proto::ApplyCodeActionKindResponse {
10677 transaction: Some(project_transaction),
10678 })
10679 }
10680
10681 async fn shutdown_language_server(
10682 server_state: Option<LanguageServerState>,
10683 name: LanguageServerName,
10684 cx: &mut AsyncApp,
10685 ) {
10686 let server = match server_state {
10687 Some(LanguageServerState::Starting { startup, .. }) => {
10688 let mut timer = cx
10689 .background_executor()
10690 .timer(SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT)
10691 .fuse();
10692
10693 select! {
10694 server = startup.fuse() => server,
10695 () = timer => {
10696 log::info!("timeout waiting for language server {name} to finish launching before stopping");
10697 None
10698 },
10699 }
10700 }
10701
10702 Some(LanguageServerState::Running { server, .. }) => Some(server),
10703
10704 None => None,
10705 };
10706
10707 let Some(server) = server else { return };
10708 if let Some(shutdown) = server.shutdown() {
10709 shutdown.await;
10710 }
10711 }
10712
10713 // Returns a list of all of the worktrees which no longer have a language server and the root path
10714 // for the stopped server
10715 fn stop_local_language_server(
10716 &mut self,
10717 server_id: LanguageServerId,
10718 cx: &mut Context<Self>,
10719 ) -> Task<()> {
10720 let local = match &mut self.mode {
10721 LspStoreMode::Local(local) => local,
10722 _ => {
10723 return Task::ready(());
10724 }
10725 };
10726
10727 // Remove this server ID from all entries in the given worktree.
10728 local
10729 .language_server_ids
10730 .retain(|_, state| state.id != server_id);
10731 self.buffer_store.update(cx, |buffer_store, cx| {
10732 for buffer in buffer_store.buffers() {
10733 buffer.update(cx, |buffer, cx| {
10734 buffer.update_diagnostics(server_id, DiagnosticSet::new([], buffer), cx);
10735 buffer.set_completion_triggers(server_id, Default::default(), cx);
10736 });
10737 }
10738 });
10739
10740 for (worktree_id, summaries) in self.diagnostic_summaries.iter_mut() {
10741 summaries.retain(|path, summaries_by_server_id| {
10742 if summaries_by_server_id.remove(&server_id).is_some() {
10743 if let Some((client, project_id)) = self.downstream_client.clone() {
10744 client
10745 .send(proto::UpdateDiagnosticSummary {
10746 project_id,
10747 worktree_id: worktree_id.to_proto(),
10748 summary: Some(proto::DiagnosticSummary {
10749 path: path.as_ref().to_proto(),
10750 language_server_id: server_id.0 as u64,
10751 error_count: 0,
10752 warning_count: 0,
10753 }),
10754 more_summaries: Vec::new(),
10755 })
10756 .log_err();
10757 }
10758 !summaries_by_server_id.is_empty()
10759 } else {
10760 true
10761 }
10762 });
10763 }
10764
10765 let local = self.as_local_mut().unwrap();
10766 for diagnostics in local.diagnostics.values_mut() {
10767 diagnostics.retain(|_, diagnostics_by_server_id| {
10768 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
10769 diagnostics_by_server_id.remove(ix);
10770 !diagnostics_by_server_id.is_empty()
10771 } else {
10772 true
10773 }
10774 });
10775 }
10776 local.language_server_watched_paths.remove(&server_id);
10777
10778 let server_state = local.language_servers.remove(&server_id);
10779 self.cleanup_lsp_data(server_id);
10780 let name = self
10781 .language_server_statuses
10782 .remove(&server_id)
10783 .map(|status| status.name)
10784 .or_else(|| {
10785 if let Some(LanguageServerState::Running { adapter, .. }) = server_state.as_ref() {
10786 Some(adapter.name())
10787 } else {
10788 None
10789 }
10790 });
10791
10792 if let Some(name) = name {
10793 log::info!("stopping language server {name}");
10794 self.languages
10795 .update_lsp_binary_status(name.clone(), BinaryStatus::Stopping);
10796 cx.notify();
10797
10798 return cx.spawn(async move |lsp_store, cx| {
10799 Self::shutdown_language_server(server_state, name.clone(), cx).await;
10800 lsp_store
10801 .update(cx, |lsp_store, cx| {
10802 lsp_store
10803 .languages
10804 .update_lsp_binary_status(name, BinaryStatus::Stopped);
10805 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10806 cx.notify();
10807 })
10808 .ok();
10809 });
10810 }
10811
10812 if server_state.is_some() {
10813 cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
10814 }
10815 Task::ready(())
10816 }
10817
10818 pub fn stop_all_language_servers(&mut self, cx: &mut Context<Self>) {
10819 self.shutdown_all_language_servers(cx).detach();
10820 }
10821
10822 pub fn shutdown_all_language_servers(&mut self, cx: &mut Context<Self>) -> Task<()> {
10823 if let Some((client, project_id)) = self.upstream_client() {
10824 let request = client.request(proto::StopLanguageServers {
10825 project_id,
10826 buffer_ids: Vec::new(),
10827 also_servers: Vec::new(),
10828 all: true,
10829 });
10830 cx.background_spawn(async move {
10831 request.await.ok();
10832 })
10833 } else {
10834 let Some(local) = self.as_local_mut() else {
10835 return Task::ready(());
10836 };
10837 let language_servers_to_stop = local
10838 .language_server_ids
10839 .values()
10840 .map(|state| state.id)
10841 .collect();
10842 local.lsp_tree.remove_nodes(&language_servers_to_stop);
10843 let tasks = language_servers_to_stop
10844 .into_iter()
10845 .map(|server| self.stop_local_language_server(server, cx))
10846 .collect::<Vec<_>>();
10847 cx.background_spawn(async move {
10848 futures::future::join_all(tasks).await;
10849 })
10850 }
10851 }
10852
10853 pub fn restart_all_language_servers(&mut self, cx: &mut Context<Self>) {
10854 let buffers = self.buffer_store.read(cx).buffers().collect();
10855 self.restart_language_servers_for_buffers(buffers, HashSet::default(), cx);
10856 }
10857
10858 pub fn restart_language_servers_for_buffers(
10859 &mut self,
10860 buffers: Vec<Entity<Buffer>>,
10861 only_restart_servers: HashSet<LanguageServerSelector>,
10862 cx: &mut Context<Self>,
10863 ) {
10864 if let Some((client, project_id)) = self.upstream_client() {
10865 let request = client.request(proto::RestartLanguageServers {
10866 project_id,
10867 buffer_ids: buffers
10868 .into_iter()
10869 .map(|b| b.read(cx).remote_id().to_proto())
10870 .collect(),
10871 only_servers: only_restart_servers
10872 .into_iter()
10873 .map(|selector| {
10874 let selector = match selector {
10875 LanguageServerSelector::Id(language_server_id) => {
10876 proto::language_server_selector::Selector::ServerId(
10877 language_server_id.to_proto(),
10878 )
10879 }
10880 LanguageServerSelector::Name(language_server_name) => {
10881 proto::language_server_selector::Selector::Name(
10882 language_server_name.to_string(),
10883 )
10884 }
10885 };
10886 proto::LanguageServerSelector {
10887 selector: Some(selector),
10888 }
10889 })
10890 .collect(),
10891 all: false,
10892 });
10893 cx.background_spawn(request).detach_and_log_err(cx);
10894 } else {
10895 let stop_task = if only_restart_servers.is_empty() {
10896 self.stop_local_language_servers_for_buffers(&buffers, HashSet::default(), cx)
10897 } else {
10898 self.stop_local_language_servers_for_buffers(&[], only_restart_servers.clone(), cx)
10899 };
10900 cx.spawn(async move |lsp_store, cx| {
10901 stop_task.await;
10902 lsp_store.update(cx, |lsp_store, cx| {
10903 for buffer in buffers {
10904 lsp_store.register_buffer_with_language_servers(
10905 &buffer,
10906 only_restart_servers.clone(),
10907 true,
10908 cx,
10909 );
10910 }
10911 })
10912 })
10913 .detach();
10914 }
10915 }
10916
10917 pub fn stop_language_servers_for_buffers(
10918 &mut self,
10919 buffers: Vec<Entity<Buffer>>,
10920 also_stop_servers: HashSet<LanguageServerSelector>,
10921 cx: &mut Context<Self>,
10922 ) -> Task<Result<()>> {
10923 if let Some((client, project_id)) = self.upstream_client() {
10924 let request = client.request(proto::StopLanguageServers {
10925 project_id,
10926 buffer_ids: buffers
10927 .into_iter()
10928 .map(|b| b.read(cx).remote_id().to_proto())
10929 .collect(),
10930 also_servers: also_stop_servers
10931 .into_iter()
10932 .map(|selector| {
10933 let selector = match selector {
10934 LanguageServerSelector::Id(language_server_id) => {
10935 proto::language_server_selector::Selector::ServerId(
10936 language_server_id.to_proto(),
10937 )
10938 }
10939 LanguageServerSelector::Name(language_server_name) => {
10940 proto::language_server_selector::Selector::Name(
10941 language_server_name.to_string(),
10942 )
10943 }
10944 };
10945 proto::LanguageServerSelector {
10946 selector: Some(selector),
10947 }
10948 })
10949 .collect(),
10950 all: false,
10951 });
10952 cx.background_spawn(async move {
10953 let _ = request.await?;
10954 Ok(())
10955 })
10956 } else {
10957 let task =
10958 self.stop_local_language_servers_for_buffers(&buffers, also_stop_servers, cx);
10959 cx.background_spawn(async move {
10960 task.await;
10961 Ok(())
10962 })
10963 }
10964 }
10965
10966 fn stop_local_language_servers_for_buffers(
10967 &mut self,
10968 buffers: &[Entity<Buffer>],
10969 also_stop_servers: HashSet<LanguageServerSelector>,
10970 cx: &mut Context<Self>,
10971 ) -> Task<()> {
10972 let Some(local) = self.as_local_mut() else {
10973 return Task::ready(());
10974 };
10975 let mut language_server_names_to_stop = BTreeSet::default();
10976 let mut language_servers_to_stop = also_stop_servers
10977 .into_iter()
10978 .flat_map(|selector| match selector {
10979 LanguageServerSelector::Id(id) => Some(id),
10980 LanguageServerSelector::Name(name) => {
10981 language_server_names_to_stop.insert(name);
10982 None
10983 }
10984 })
10985 .collect::<BTreeSet<_>>();
10986
10987 let mut covered_worktrees = HashSet::default();
10988 for buffer in buffers {
10989 buffer.update(cx, |buffer, cx| {
10990 language_servers_to_stop.extend(local.language_server_ids_for_buffer(buffer, cx));
10991 if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx))
10992 && covered_worktrees.insert(worktree_id)
10993 {
10994 language_server_names_to_stop.retain(|name| {
10995 let old_ids_count = language_servers_to_stop.len();
10996 let all_language_servers_with_this_name = local
10997 .language_server_ids
10998 .iter()
10999 .filter_map(|(seed, state)| seed.name.eq(name).then(|| state.id));
11000 language_servers_to_stop.extend(all_language_servers_with_this_name);
11001 old_ids_count == language_servers_to_stop.len()
11002 });
11003 }
11004 });
11005 }
11006 for name in language_server_names_to_stop {
11007 language_servers_to_stop.extend(
11008 local
11009 .language_server_ids
11010 .iter()
11011 .filter_map(|(seed, v)| seed.name.eq(&name).then(|| v.id)),
11012 );
11013 }
11014
11015 local.lsp_tree.remove_nodes(&language_servers_to_stop);
11016 let tasks = language_servers_to_stop
11017 .into_iter()
11018 .map(|server| self.stop_local_language_server(server, cx))
11019 .collect::<Vec<_>>();
11020
11021 cx.background_spawn(futures::future::join_all(tasks).map(|_| ()))
11022 }
11023
11024 fn get_buffer<'a>(&self, abs_path: &Path, cx: &'a App) -> Option<&'a Buffer> {
11025 let (worktree, relative_path) =
11026 self.worktree_store.read(cx).find_worktree(&abs_path, cx)?;
11027
11028 let project_path = ProjectPath {
11029 worktree_id: worktree.read(cx).id(),
11030 path: relative_path,
11031 };
11032
11033 Some(
11034 self.buffer_store()
11035 .read(cx)
11036 .get_by_path(&project_path)?
11037 .read(cx),
11038 )
11039 }
11040
11041 #[cfg(any(test, feature = "test-support"))]
11042 pub fn update_diagnostics(
11043 &mut self,
11044 server_id: LanguageServerId,
11045 diagnostics: lsp::PublishDiagnosticsParams,
11046 result_id: Option<SharedString>,
11047 source_kind: DiagnosticSourceKind,
11048 disk_based_sources: &[String],
11049 cx: &mut Context<Self>,
11050 ) -> Result<()> {
11051 self.merge_lsp_diagnostics(
11052 source_kind,
11053 vec![DocumentDiagnosticsUpdate {
11054 diagnostics,
11055 result_id,
11056 server_id,
11057 disk_based_sources: Cow::Borrowed(disk_based_sources),
11058 registration_id: None,
11059 }],
11060 |_, _, _| false,
11061 cx,
11062 )
11063 }
11064
11065 pub fn merge_lsp_diagnostics(
11066 &mut self,
11067 source_kind: DiagnosticSourceKind,
11068 lsp_diagnostics: Vec<DocumentDiagnosticsUpdate<lsp::PublishDiagnosticsParams>>,
11069 merge: impl Fn(&lsp::Uri, &Diagnostic, &App) -> bool + Clone,
11070 cx: &mut Context<Self>,
11071 ) -> Result<()> {
11072 anyhow::ensure!(self.mode.is_local(), "called update_diagnostics on remote");
11073 let updates = lsp_diagnostics
11074 .into_iter()
11075 .filter_map(|update| {
11076 let abs_path = update.diagnostics.uri.to_file_path().ok()?;
11077 Some(DocumentDiagnosticsUpdate {
11078 diagnostics: self.lsp_to_document_diagnostics(
11079 abs_path,
11080 source_kind,
11081 update.server_id,
11082 update.diagnostics,
11083 &update.disk_based_sources,
11084 update.registration_id.clone(),
11085 ),
11086 result_id: update.result_id,
11087 server_id: update.server_id,
11088 disk_based_sources: update.disk_based_sources,
11089 registration_id: update.registration_id,
11090 })
11091 })
11092 .collect();
11093 self.merge_diagnostic_entries(updates, merge, cx)?;
11094 Ok(())
11095 }
11096
11097 fn lsp_to_document_diagnostics(
11098 &mut self,
11099 document_abs_path: PathBuf,
11100 source_kind: DiagnosticSourceKind,
11101 server_id: LanguageServerId,
11102 mut lsp_diagnostics: lsp::PublishDiagnosticsParams,
11103 disk_based_sources: &[String],
11104 registration_id: Option<SharedString>,
11105 ) -> DocumentDiagnostics {
11106 let mut diagnostics = Vec::default();
11107 let mut primary_diagnostic_group_ids = HashMap::default();
11108 let mut sources_by_group_id = HashMap::default();
11109 let mut supporting_diagnostics = HashMap::default();
11110
11111 let adapter = self.language_server_adapter_for_id(server_id);
11112
11113 // Ensure that primary diagnostics are always the most severe
11114 lsp_diagnostics
11115 .diagnostics
11116 .sort_by_key(|item| item.severity);
11117
11118 for diagnostic in &lsp_diagnostics.diagnostics {
11119 let source = diagnostic.source.as_ref();
11120 let range = range_from_lsp(diagnostic.range);
11121 let is_supporting = diagnostic
11122 .related_information
11123 .as_ref()
11124 .is_some_and(|infos| {
11125 infos.iter().any(|info| {
11126 primary_diagnostic_group_ids.contains_key(&(
11127 source,
11128 diagnostic.code.clone(),
11129 range_from_lsp(info.location.range),
11130 ))
11131 })
11132 });
11133
11134 let is_unnecessary = diagnostic
11135 .tags
11136 .as_ref()
11137 .is_some_and(|tags| tags.contains(&DiagnosticTag::UNNECESSARY));
11138
11139 let underline = self
11140 .language_server_adapter_for_id(server_id)
11141 .is_none_or(|adapter| adapter.underline_diagnostic(diagnostic));
11142
11143 if is_supporting {
11144 supporting_diagnostics.insert(
11145 (source, diagnostic.code.clone(), range),
11146 (diagnostic.severity, is_unnecessary),
11147 );
11148 } else {
11149 let group_id = post_inc(&mut self.as_local_mut().unwrap().next_diagnostic_group_id);
11150 let is_disk_based =
11151 source.is_some_and(|source| disk_based_sources.contains(source));
11152
11153 sources_by_group_id.insert(group_id, source);
11154 primary_diagnostic_group_ids
11155 .insert((source, diagnostic.code.clone(), range.clone()), group_id);
11156
11157 diagnostics.push(DiagnosticEntry {
11158 range,
11159 diagnostic: Diagnostic {
11160 source: diagnostic.source.clone(),
11161 source_kind,
11162 code: diagnostic.code.clone(),
11163 code_description: diagnostic
11164 .code_description
11165 .as_ref()
11166 .and_then(|d| d.href.clone()),
11167 severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
11168 markdown: adapter.as_ref().and_then(|adapter| {
11169 adapter.diagnostic_message_to_markdown(&diagnostic.message)
11170 }),
11171 message: diagnostic.message.trim().to_string(),
11172 group_id,
11173 is_primary: true,
11174 is_disk_based,
11175 is_unnecessary,
11176 underline,
11177 data: diagnostic.data.clone(),
11178 registration_id: registration_id.clone(),
11179 },
11180 });
11181 if let Some(infos) = &diagnostic.related_information {
11182 for info in infos {
11183 if info.location.uri == lsp_diagnostics.uri && !info.message.is_empty() {
11184 let range = range_from_lsp(info.location.range);
11185 diagnostics.push(DiagnosticEntry {
11186 range,
11187 diagnostic: Diagnostic {
11188 source: diagnostic.source.clone(),
11189 source_kind,
11190 code: diagnostic.code.clone(),
11191 code_description: diagnostic
11192 .code_description
11193 .as_ref()
11194 .and_then(|d| d.href.clone()),
11195 severity: DiagnosticSeverity::INFORMATION,
11196 markdown: adapter.as_ref().and_then(|adapter| {
11197 adapter.diagnostic_message_to_markdown(&info.message)
11198 }),
11199 message: info.message.trim().to_string(),
11200 group_id,
11201 is_primary: false,
11202 is_disk_based,
11203 is_unnecessary: false,
11204 underline,
11205 data: diagnostic.data.clone(),
11206 registration_id: registration_id.clone(),
11207 },
11208 });
11209 }
11210 }
11211 }
11212 }
11213 }
11214
11215 for entry in &mut diagnostics {
11216 let diagnostic = &mut entry.diagnostic;
11217 if !diagnostic.is_primary {
11218 let source = *sources_by_group_id.get(&diagnostic.group_id).unwrap();
11219 if let Some(&(severity, is_unnecessary)) = supporting_diagnostics.get(&(
11220 source,
11221 diagnostic.code.clone(),
11222 entry.range.clone(),
11223 )) {
11224 if let Some(severity) = severity {
11225 diagnostic.severity = severity;
11226 }
11227 diagnostic.is_unnecessary = is_unnecessary;
11228 }
11229 }
11230 }
11231
11232 DocumentDiagnostics {
11233 diagnostics,
11234 document_abs_path,
11235 version: lsp_diagnostics.version,
11236 }
11237 }
11238
11239 fn insert_newly_running_language_server(
11240 &mut self,
11241 adapter: Arc<CachedLspAdapter>,
11242 language_server: Arc<LanguageServer>,
11243 server_id: LanguageServerId,
11244 key: LanguageServerSeed,
11245 workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
11246 cx: &mut Context<Self>,
11247 ) {
11248 let Some(local) = self.as_local_mut() else {
11249 return;
11250 };
11251 // If the language server for this key doesn't match the server id, don't store the
11252 // server. Which will cause it to be dropped, killing the process
11253 if local
11254 .language_server_ids
11255 .get(&key)
11256 .map(|state| state.id != server_id)
11257 .unwrap_or(false)
11258 {
11259 return;
11260 }
11261
11262 // Update language_servers collection with Running variant of LanguageServerState
11263 // indicating that the server is up and running and ready
11264 let workspace_folders = workspace_folders.lock().clone();
11265 language_server.set_workspace_folders(workspace_folders);
11266
11267 let workspace_diagnostics_refresh_tasks = language_server
11268 .capabilities()
11269 .diagnostic_provider
11270 .and_then(|provider| {
11271 local
11272 .language_server_dynamic_registrations
11273 .entry(server_id)
11274 .or_default()
11275 .diagnostics
11276 .entry(None)
11277 .or_insert(provider.clone());
11278 let workspace_refresher =
11279 lsp_workspace_diagnostics_refresh(None, provider, language_server.clone(), cx)?;
11280
11281 Some((None, workspace_refresher))
11282 })
11283 .into_iter()
11284 .collect();
11285 local.language_servers.insert(
11286 server_id,
11287 LanguageServerState::Running {
11288 workspace_diagnostics_refresh_tasks,
11289 adapter: adapter.clone(),
11290 server: language_server.clone(),
11291 simulate_disk_based_diagnostics_completion: None,
11292 },
11293 );
11294 local
11295 .languages
11296 .update_lsp_binary_status(adapter.name(), BinaryStatus::None);
11297 if let Some(file_ops_caps) = language_server
11298 .capabilities()
11299 .workspace
11300 .as_ref()
11301 .and_then(|ws| ws.file_operations.as_ref())
11302 {
11303 let did_rename_caps = file_ops_caps.did_rename.as_ref();
11304 let will_rename_caps = file_ops_caps.will_rename.as_ref();
11305 if did_rename_caps.or(will_rename_caps).is_some() {
11306 let watcher = RenamePathsWatchedForServer::default()
11307 .with_did_rename_patterns(did_rename_caps)
11308 .with_will_rename_patterns(will_rename_caps);
11309 local
11310 .language_server_paths_watched_for_rename
11311 .insert(server_id, watcher);
11312 }
11313 }
11314
11315 self.language_server_statuses.insert(
11316 server_id,
11317 LanguageServerStatus {
11318 name: language_server.name(),
11319 server_version: language_server.version(),
11320 pending_work: Default::default(),
11321 has_pending_diagnostic_updates: false,
11322 progress_tokens: Default::default(),
11323 worktree: Some(key.worktree_id),
11324 binary: Some(language_server.binary().clone()),
11325 configuration: Some(language_server.configuration().clone()),
11326 workspace_folders: language_server.workspace_folders(),
11327 process_id: language_server.process_id(),
11328 },
11329 );
11330
11331 cx.emit(LspStoreEvent::LanguageServerAdded(
11332 server_id,
11333 language_server.name(),
11334 Some(key.worktree_id),
11335 ));
11336
11337 let server_capabilities = language_server.capabilities();
11338 if let Some((downstream_client, project_id)) = self.downstream_client.as_ref() {
11339 downstream_client
11340 .send(proto::StartLanguageServer {
11341 project_id: *project_id,
11342 server: Some(proto::LanguageServer {
11343 id: server_id.to_proto(),
11344 name: language_server.name().to_string(),
11345 worktree_id: Some(key.worktree_id.to_proto()),
11346 }),
11347 capabilities: serde_json::to_string(&server_capabilities)
11348 .expect("serializing server LSP capabilities"),
11349 })
11350 .log_err();
11351 }
11352 self.lsp_server_capabilities
11353 .insert(server_id, server_capabilities);
11354
11355 // Tell the language server about every open buffer in the worktree that matches the language.
11356 // Also check for buffers in worktrees that reused this server
11357 let mut worktrees_using_server = vec![key.worktree_id];
11358 if let Some(local) = self.as_local() {
11359 // Find all worktrees that have this server in their language server tree
11360 for (worktree_id, servers) in &local.lsp_tree.instances {
11361 if *worktree_id != key.worktree_id {
11362 for server_map in servers.roots.values() {
11363 if server_map
11364 .values()
11365 .any(|(node, _)| node.id() == Some(server_id))
11366 {
11367 worktrees_using_server.push(*worktree_id);
11368 }
11369 }
11370 }
11371 }
11372 }
11373
11374 let mut buffer_paths_registered = Vec::new();
11375 self.buffer_store.clone().update(cx, |buffer_store, cx| {
11376 let mut lsp_adapters = HashMap::default();
11377 for buffer_handle in buffer_store.buffers() {
11378 let buffer = buffer_handle.read(cx);
11379 let file = match File::from_dyn(buffer.file()) {
11380 Some(file) => file,
11381 None => continue,
11382 };
11383 let language = match buffer.language() {
11384 Some(language) => language,
11385 None => continue,
11386 };
11387
11388 if !worktrees_using_server.contains(&file.worktree.read(cx).id())
11389 || !lsp_adapters
11390 .entry(language.name())
11391 .or_insert_with(|| self.languages.lsp_adapters(&language.name()))
11392 .iter()
11393 .any(|a| a.name == key.name)
11394 {
11395 continue;
11396 }
11397 // didOpen
11398 let file = match file.as_local() {
11399 Some(file) => file,
11400 None => continue,
11401 };
11402
11403 let local = self.as_local_mut().unwrap();
11404
11405 let buffer_id = buffer.remote_id();
11406 if local.registered_buffers.contains_key(&buffer_id) {
11407 let versions = local
11408 .buffer_snapshots
11409 .entry(buffer_id)
11410 .or_default()
11411 .entry(server_id)
11412 .and_modify(|_| {
11413 assert!(
11414 false,
11415 "There should not be an existing snapshot for a newly inserted buffer"
11416 )
11417 })
11418 .or_insert_with(|| {
11419 vec![LspBufferSnapshot {
11420 version: 0,
11421 snapshot: buffer.text_snapshot(),
11422 }]
11423 });
11424
11425 let snapshot = versions.last().unwrap();
11426 let version = snapshot.version;
11427 let initial_snapshot = &snapshot.snapshot;
11428 let uri = lsp::Uri::from_file_path(file.abs_path(cx)).unwrap();
11429 language_server.register_buffer(
11430 uri,
11431 adapter.language_id(&language.name()),
11432 version,
11433 initial_snapshot.text(),
11434 );
11435 buffer_paths_registered.push((buffer_id, file.abs_path(cx)));
11436 local
11437 .buffers_opened_in_servers
11438 .entry(buffer_id)
11439 .or_default()
11440 .insert(server_id);
11441 }
11442 buffer_handle.update(cx, |buffer, cx| {
11443 buffer.set_completion_triggers(
11444 server_id,
11445 language_server
11446 .capabilities()
11447 .completion_provider
11448 .as_ref()
11449 .and_then(|provider| {
11450 provider
11451 .trigger_characters
11452 .as_ref()
11453 .map(|characters| characters.iter().cloned().collect())
11454 })
11455 .unwrap_or_default(),
11456 cx,
11457 )
11458 });
11459 }
11460 });
11461
11462 for (buffer_id, abs_path) in buffer_paths_registered {
11463 cx.emit(LspStoreEvent::LanguageServerUpdate {
11464 language_server_id: server_id,
11465 name: Some(adapter.name()),
11466 message: proto::update_language_server::Variant::RegisteredForBuffer(
11467 proto::RegisteredForBuffer {
11468 buffer_abs_path: abs_path.to_string_lossy().into_owned(),
11469 buffer_id: buffer_id.to_proto(),
11470 },
11471 ),
11472 });
11473 }
11474
11475 cx.notify();
11476 }
11477
11478 pub fn language_servers_running_disk_based_diagnostics(
11479 &self,
11480 ) -> impl Iterator<Item = LanguageServerId> + '_ {
11481 self.language_server_statuses
11482 .iter()
11483 .filter_map(|(id, status)| {
11484 if status.has_pending_diagnostic_updates {
11485 Some(*id)
11486 } else {
11487 None
11488 }
11489 })
11490 }
11491
11492 pub(crate) fn cancel_language_server_work_for_buffers(
11493 &mut self,
11494 buffers: impl IntoIterator<Item = Entity<Buffer>>,
11495 cx: &mut Context<Self>,
11496 ) {
11497 if let Some((client, project_id)) = self.upstream_client() {
11498 let request = client.request(proto::CancelLanguageServerWork {
11499 project_id,
11500 work: Some(proto::cancel_language_server_work::Work::Buffers(
11501 proto::cancel_language_server_work::Buffers {
11502 buffer_ids: buffers
11503 .into_iter()
11504 .map(|b| b.read(cx).remote_id().to_proto())
11505 .collect(),
11506 },
11507 )),
11508 });
11509 cx.background_spawn(request).detach_and_log_err(cx);
11510 } else if let Some(local) = self.as_local() {
11511 let servers = buffers
11512 .into_iter()
11513 .flat_map(|buffer| {
11514 buffer.update(cx, |buffer, cx| {
11515 local.language_server_ids_for_buffer(buffer, cx).into_iter()
11516 })
11517 })
11518 .collect::<HashSet<_>>();
11519 for server_id in servers {
11520 self.cancel_language_server_work(server_id, None, cx);
11521 }
11522 }
11523 }
11524
11525 pub(crate) fn cancel_language_server_work(
11526 &mut self,
11527 server_id: LanguageServerId,
11528 token_to_cancel: Option<ProgressToken>,
11529 cx: &mut Context<Self>,
11530 ) {
11531 if let Some(local) = self.as_local() {
11532 let status = self.language_server_statuses.get(&server_id);
11533 let server = local.language_servers.get(&server_id);
11534 if let Some((LanguageServerState::Running { server, .. }, status)) = server.zip(status)
11535 {
11536 for (token, progress) in &status.pending_work {
11537 if let Some(token_to_cancel) = token_to_cancel.as_ref()
11538 && token != token_to_cancel
11539 {
11540 continue;
11541 }
11542 if progress.is_cancellable {
11543 server
11544 .notify::<lsp::notification::WorkDoneProgressCancel>(
11545 WorkDoneProgressCancelParams {
11546 token: token.to_lsp(),
11547 },
11548 )
11549 .ok();
11550 }
11551 }
11552 }
11553 } else if let Some((client, project_id)) = self.upstream_client() {
11554 let request = client.request(proto::CancelLanguageServerWork {
11555 project_id,
11556 work: Some(
11557 proto::cancel_language_server_work::Work::LanguageServerWork(
11558 proto::cancel_language_server_work::LanguageServerWork {
11559 language_server_id: server_id.to_proto(),
11560 token: token_to_cancel.map(|token| token.to_proto()),
11561 },
11562 ),
11563 ),
11564 });
11565 cx.background_spawn(request).detach_and_log_err(cx);
11566 }
11567 }
11568
11569 fn register_supplementary_language_server(
11570 &mut self,
11571 id: LanguageServerId,
11572 name: LanguageServerName,
11573 server: Arc<LanguageServer>,
11574 cx: &mut Context<Self>,
11575 ) {
11576 if let Some(local) = self.as_local_mut() {
11577 local
11578 .supplementary_language_servers
11579 .insert(id, (name.clone(), server));
11580 cx.emit(LspStoreEvent::LanguageServerAdded(id, name, None));
11581 }
11582 }
11583
11584 fn unregister_supplementary_language_server(
11585 &mut self,
11586 id: LanguageServerId,
11587 cx: &mut Context<Self>,
11588 ) {
11589 if let Some(local) = self.as_local_mut() {
11590 local.supplementary_language_servers.remove(&id);
11591 cx.emit(LspStoreEvent::LanguageServerRemoved(id));
11592 }
11593 }
11594
11595 pub(crate) fn supplementary_language_servers(
11596 &self,
11597 ) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
11598 self.as_local().into_iter().flat_map(|local| {
11599 local
11600 .supplementary_language_servers
11601 .iter()
11602 .map(|(id, (name, _))| (*id, name.clone()))
11603 })
11604 }
11605
11606 pub fn language_server_adapter_for_id(
11607 &self,
11608 id: LanguageServerId,
11609 ) -> Option<Arc<CachedLspAdapter>> {
11610 self.as_local()
11611 .and_then(|local| local.language_servers.get(&id))
11612 .and_then(|language_server_state| match language_server_state {
11613 LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
11614 _ => None,
11615 })
11616 }
11617
11618 pub(super) fn update_local_worktree_language_servers(
11619 &mut self,
11620 worktree_handle: &Entity<Worktree>,
11621 changes: &[(Arc<RelPath>, ProjectEntryId, PathChange)],
11622 cx: &mut Context<Self>,
11623 ) {
11624 if changes.is_empty() {
11625 return;
11626 }
11627
11628 let Some(local) = self.as_local() else { return };
11629
11630 local.prettier_store.update(cx, |prettier_store, cx| {
11631 prettier_store.update_prettier_settings(worktree_handle, changes, cx)
11632 });
11633
11634 let worktree_id = worktree_handle.read(cx).id();
11635 let mut language_server_ids = local
11636 .language_server_ids
11637 .iter()
11638 .filter_map(|(seed, v)| seed.worktree_id.eq(&worktree_id).then(|| v.id))
11639 .collect::<Vec<_>>();
11640 language_server_ids.sort();
11641 language_server_ids.dedup();
11642
11643 // let abs_path = worktree_handle.read(cx).abs_path();
11644 for server_id in &language_server_ids {
11645 if let Some(LanguageServerState::Running { server, .. }) =
11646 local.language_servers.get(server_id)
11647 && let Some(watched_paths) = local
11648 .language_server_watched_paths
11649 .get(server_id)
11650 .and_then(|paths| paths.worktree_paths.get(&worktree_id))
11651 {
11652 let params = lsp::DidChangeWatchedFilesParams {
11653 changes: changes
11654 .iter()
11655 .filter_map(|(path, _, change)| {
11656 if !watched_paths.is_match(path.as_std_path()) {
11657 return None;
11658 }
11659 let typ = match change {
11660 PathChange::Loaded => return None,
11661 PathChange::Added => lsp::FileChangeType::CREATED,
11662 PathChange::Removed => lsp::FileChangeType::DELETED,
11663 PathChange::Updated => lsp::FileChangeType::CHANGED,
11664 PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
11665 };
11666 let uri = lsp::Uri::from_file_path(
11667 worktree_handle.read(cx).absolutize(&path),
11668 )
11669 .ok()?;
11670 Some(lsp::FileEvent { uri, typ })
11671 })
11672 .collect(),
11673 };
11674 if !params.changes.is_empty() {
11675 server
11676 .notify::<lsp::notification::DidChangeWatchedFiles>(params)
11677 .ok();
11678 }
11679 }
11680 }
11681 for (path, _, _) in changes {
11682 if let Some(file_name) = path.file_name()
11683 && local.watched_manifest_filenames.contains(file_name)
11684 {
11685 self.request_workspace_config_refresh();
11686 break;
11687 }
11688 }
11689 }
11690
11691 pub fn wait_for_remote_buffer(
11692 &mut self,
11693 id: BufferId,
11694 cx: &mut Context<Self>,
11695 ) -> Task<Result<Entity<Buffer>>> {
11696 self.buffer_store.update(cx, |buffer_store, cx| {
11697 buffer_store.wait_for_remote_buffer(id, cx)
11698 })
11699 }
11700
11701 fn serialize_symbol(symbol: &Symbol) -> proto::Symbol {
11702 let mut result = proto::Symbol {
11703 language_server_name: symbol.language_server_name.0.to_string(),
11704 source_worktree_id: symbol.source_worktree_id.to_proto(),
11705 language_server_id: symbol.source_language_server_id.to_proto(),
11706 name: symbol.name.clone(),
11707 kind: unsafe { mem::transmute::<lsp::SymbolKind, i32>(symbol.kind) },
11708 start: Some(proto::PointUtf16 {
11709 row: symbol.range.start.0.row,
11710 column: symbol.range.start.0.column,
11711 }),
11712 end: Some(proto::PointUtf16 {
11713 row: symbol.range.end.0.row,
11714 column: symbol.range.end.0.column,
11715 }),
11716 worktree_id: Default::default(),
11717 path: Default::default(),
11718 signature: Default::default(),
11719 container_name: symbol.container_name.clone(),
11720 };
11721 match &symbol.path {
11722 SymbolLocation::InProject(path) => {
11723 result.worktree_id = path.worktree_id.to_proto();
11724 result.path = path.path.to_proto();
11725 }
11726 SymbolLocation::OutsideProject {
11727 abs_path,
11728 signature,
11729 } => {
11730 result.path = abs_path.to_string_lossy().into_owned();
11731 result.signature = signature.to_vec();
11732 }
11733 }
11734 result
11735 }
11736
11737 fn deserialize_symbol(serialized_symbol: proto::Symbol) -> Result<CoreSymbol> {
11738 let source_worktree_id = WorktreeId::from_proto(serialized_symbol.source_worktree_id);
11739 let worktree_id = WorktreeId::from_proto(serialized_symbol.worktree_id);
11740 let kind = unsafe { mem::transmute::<i32, lsp::SymbolKind>(serialized_symbol.kind) };
11741
11742 let path = if serialized_symbol.signature.is_empty() {
11743 SymbolLocation::InProject(ProjectPath {
11744 worktree_id,
11745 path: RelPath::from_proto(&serialized_symbol.path)
11746 .context("invalid symbol path")?,
11747 })
11748 } else {
11749 SymbolLocation::OutsideProject {
11750 abs_path: Path::new(&serialized_symbol.path).into(),
11751 signature: serialized_symbol
11752 .signature
11753 .try_into()
11754 .map_err(|_| anyhow!("invalid signature"))?,
11755 }
11756 };
11757
11758 let start = serialized_symbol.start.context("invalid start")?;
11759 let end = serialized_symbol.end.context("invalid end")?;
11760 Ok(CoreSymbol {
11761 language_server_name: LanguageServerName(serialized_symbol.language_server_name.into()),
11762 source_worktree_id,
11763 source_language_server_id: LanguageServerId::from_proto(
11764 serialized_symbol.language_server_id,
11765 ),
11766 path,
11767 name: serialized_symbol.name,
11768 range: Unclipped(PointUtf16::new(start.row, start.column))
11769 ..Unclipped(PointUtf16::new(end.row, end.column)),
11770 kind,
11771 container_name: serialized_symbol.container_name,
11772 })
11773 }
11774
11775 pub(crate) fn serialize_completion(completion: &CoreCompletion) -> proto::Completion {
11776 let mut serialized_completion = proto::Completion {
11777 old_replace_start: Some(serialize_anchor(&completion.replace_range.start)),
11778 old_replace_end: Some(serialize_anchor(&completion.replace_range.end)),
11779 new_text: completion.new_text.clone(),
11780 ..proto::Completion::default()
11781 };
11782 match &completion.source {
11783 CompletionSource::Lsp {
11784 insert_range,
11785 server_id,
11786 lsp_completion,
11787 lsp_defaults,
11788 resolved,
11789 } => {
11790 let (old_insert_start, old_insert_end) = insert_range
11791 .as_ref()
11792 .map(|range| (serialize_anchor(&range.start), serialize_anchor(&range.end)))
11793 .unzip();
11794
11795 serialized_completion.old_insert_start = old_insert_start;
11796 serialized_completion.old_insert_end = old_insert_end;
11797 serialized_completion.source = proto::completion::Source::Lsp as i32;
11798 serialized_completion.server_id = server_id.0 as u64;
11799 serialized_completion.lsp_completion = serde_json::to_vec(lsp_completion).unwrap();
11800 serialized_completion.lsp_defaults = lsp_defaults
11801 .as_deref()
11802 .map(|lsp_defaults| serde_json::to_vec(lsp_defaults).unwrap());
11803 serialized_completion.resolved = *resolved;
11804 }
11805 CompletionSource::BufferWord {
11806 word_range,
11807 resolved,
11808 } => {
11809 serialized_completion.source = proto::completion::Source::BufferWord as i32;
11810 serialized_completion.buffer_word_start = Some(serialize_anchor(&word_range.start));
11811 serialized_completion.buffer_word_end = Some(serialize_anchor(&word_range.end));
11812 serialized_completion.resolved = *resolved;
11813 }
11814 CompletionSource::Custom => {
11815 serialized_completion.source = proto::completion::Source::Custom as i32;
11816 serialized_completion.resolved = true;
11817 }
11818 CompletionSource::Dap { sort_text } => {
11819 serialized_completion.source = proto::completion::Source::Dap as i32;
11820 serialized_completion.sort_text = Some(sort_text.clone());
11821 }
11822 }
11823
11824 serialized_completion
11825 }
11826
11827 pub(crate) fn deserialize_completion(completion: proto::Completion) -> Result<CoreCompletion> {
11828 let old_replace_start = completion
11829 .old_replace_start
11830 .and_then(deserialize_anchor)
11831 .context("invalid old start")?;
11832 let old_replace_end = completion
11833 .old_replace_end
11834 .and_then(deserialize_anchor)
11835 .context("invalid old end")?;
11836 let insert_range = {
11837 match completion.old_insert_start.zip(completion.old_insert_end) {
11838 Some((start, end)) => {
11839 let start = deserialize_anchor(start).context("invalid insert old start")?;
11840 let end = deserialize_anchor(end).context("invalid insert old end")?;
11841 Some(start..end)
11842 }
11843 None => None,
11844 }
11845 };
11846 Ok(CoreCompletion {
11847 replace_range: old_replace_start..old_replace_end,
11848 new_text: completion.new_text,
11849 source: match proto::completion::Source::from_i32(completion.source) {
11850 Some(proto::completion::Source::Custom) => CompletionSource::Custom,
11851 Some(proto::completion::Source::Lsp) => CompletionSource::Lsp {
11852 insert_range,
11853 server_id: LanguageServerId::from_proto(completion.server_id),
11854 lsp_completion: serde_json::from_slice(&completion.lsp_completion)?,
11855 lsp_defaults: completion
11856 .lsp_defaults
11857 .as_deref()
11858 .map(serde_json::from_slice)
11859 .transpose()?,
11860 resolved: completion.resolved,
11861 },
11862 Some(proto::completion::Source::BufferWord) => {
11863 let word_range = completion
11864 .buffer_word_start
11865 .and_then(deserialize_anchor)
11866 .context("invalid buffer word start")?
11867 ..completion
11868 .buffer_word_end
11869 .and_then(deserialize_anchor)
11870 .context("invalid buffer word end")?;
11871 CompletionSource::BufferWord {
11872 word_range,
11873 resolved: completion.resolved,
11874 }
11875 }
11876 Some(proto::completion::Source::Dap) => CompletionSource::Dap {
11877 sort_text: completion
11878 .sort_text
11879 .context("expected sort text to exist")?,
11880 },
11881 _ => anyhow::bail!("Unexpected completion source {}", completion.source),
11882 },
11883 })
11884 }
11885
11886 pub(crate) fn serialize_code_action(action: &CodeAction) -> proto::CodeAction {
11887 let (kind, lsp_action) = match &action.lsp_action {
11888 LspAction::Action(code_action) => (
11889 proto::code_action::Kind::Action as i32,
11890 serde_json::to_vec(code_action).unwrap(),
11891 ),
11892 LspAction::Command(command) => (
11893 proto::code_action::Kind::Command as i32,
11894 serde_json::to_vec(command).unwrap(),
11895 ),
11896 LspAction::CodeLens(code_lens) => (
11897 proto::code_action::Kind::CodeLens as i32,
11898 serde_json::to_vec(code_lens).unwrap(),
11899 ),
11900 };
11901
11902 proto::CodeAction {
11903 server_id: action.server_id.0 as u64,
11904 start: Some(serialize_anchor(&action.range.start)),
11905 end: Some(serialize_anchor(&action.range.end)),
11906 lsp_action,
11907 kind,
11908 resolved: action.resolved,
11909 }
11910 }
11911
11912 pub(crate) fn deserialize_code_action(action: proto::CodeAction) -> Result<CodeAction> {
11913 let start = action
11914 .start
11915 .and_then(deserialize_anchor)
11916 .context("invalid start")?;
11917 let end = action
11918 .end
11919 .and_then(deserialize_anchor)
11920 .context("invalid end")?;
11921 let lsp_action = match proto::code_action::Kind::from_i32(action.kind) {
11922 Some(proto::code_action::Kind::Action) => {
11923 LspAction::Action(serde_json::from_slice(&action.lsp_action)?)
11924 }
11925 Some(proto::code_action::Kind::Command) => {
11926 LspAction::Command(serde_json::from_slice(&action.lsp_action)?)
11927 }
11928 Some(proto::code_action::Kind::CodeLens) => {
11929 LspAction::CodeLens(serde_json::from_slice(&action.lsp_action)?)
11930 }
11931 None => anyhow::bail!("Unknown action kind {}", action.kind),
11932 };
11933 Ok(CodeAction {
11934 server_id: LanguageServerId(action.server_id as usize),
11935 range: start..end,
11936 resolved: action.resolved,
11937 lsp_action,
11938 })
11939 }
11940
11941 fn update_last_formatting_failure<T>(&mut self, formatting_result: &anyhow::Result<T>) {
11942 match &formatting_result {
11943 Ok(_) => self.last_formatting_failure = None,
11944 Err(error) => {
11945 let error_string = format!("{error:#}");
11946 log::error!("Formatting failed: {error_string}");
11947 self.last_formatting_failure
11948 .replace(error_string.lines().join(" "));
11949 }
11950 }
11951 }
11952
11953 fn cleanup_lsp_data(&mut self, for_server: LanguageServerId) {
11954 self.lsp_server_capabilities.remove(&for_server);
11955 self.semantic_token_config.remove_server_data(for_server);
11956 for lsp_data in self.lsp_data.values_mut() {
11957 lsp_data.remove_server_data(for_server);
11958 }
11959 if let Some(local) = self.as_local_mut() {
11960 local.buffer_pull_diagnostics_result_ids.remove(&for_server);
11961 local
11962 .workspace_pull_diagnostics_result_ids
11963 .remove(&for_server);
11964 for buffer_servers in local.buffers_opened_in_servers.values_mut() {
11965 buffer_servers.remove(&for_server);
11966 }
11967 }
11968 }
11969
11970 pub fn result_id_for_buffer_pull(
11971 &self,
11972 server_id: LanguageServerId,
11973 buffer_id: BufferId,
11974 registration_id: &Option<SharedString>,
11975 cx: &App,
11976 ) -> Option<SharedString> {
11977 let abs_path = self
11978 .buffer_store
11979 .read(cx)
11980 .get(buffer_id)
11981 .and_then(|b| File::from_dyn(b.read(cx).file()))
11982 .map(|f| f.abs_path(cx))?;
11983 self.as_local()?
11984 .buffer_pull_diagnostics_result_ids
11985 .get(&server_id)?
11986 .get(registration_id)?
11987 .get(&abs_path)?
11988 .clone()
11989 }
11990
11991 /// Gets all result_ids for a workspace diagnostics pull request.
11992 /// 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.
11993 /// The latter is supposed to be of lower priority as we keep on pulling diagnostics for open buffers eagerly.
11994 pub fn result_ids_for_workspace_refresh(
11995 &self,
11996 server_id: LanguageServerId,
11997 registration_id: &Option<SharedString>,
11998 ) -> HashMap<PathBuf, SharedString> {
11999 let Some(local) = self.as_local() else {
12000 return HashMap::default();
12001 };
12002 local
12003 .workspace_pull_diagnostics_result_ids
12004 .get(&server_id)
12005 .into_iter()
12006 .filter_map(|diagnostics| diagnostics.get(registration_id))
12007 .flatten()
12008 .filter_map(|(abs_path, result_id)| {
12009 let result_id = local
12010 .buffer_pull_diagnostics_result_ids
12011 .get(&server_id)
12012 .and_then(|buffer_ids_result_ids| {
12013 buffer_ids_result_ids.get(registration_id)?.get(abs_path)
12014 })
12015 .cloned()
12016 .flatten()
12017 .or_else(|| result_id.clone())?;
12018 Some((abs_path.clone(), result_id))
12019 })
12020 .collect()
12021 }
12022
12023 pub fn pull_workspace_diagnostics(&mut self, server_id: LanguageServerId) {
12024 if let Some(LanguageServerState::Running {
12025 workspace_diagnostics_refresh_tasks,
12026 ..
12027 }) = self
12028 .as_local_mut()
12029 .and_then(|local| local.language_servers.get_mut(&server_id))
12030 {
12031 for diagnostics in workspace_diagnostics_refresh_tasks.values_mut() {
12032 diagnostics.refresh_tx.try_send(()).ok();
12033 }
12034 }
12035 }
12036
12037 /// Refreshes `textDocument/diagnostic` for all open buffers associated with the given server.
12038 /// This is called in response to `workspace/diagnostic/refresh` to comply with the LSP spec,
12039 /// which requires refreshing both workspace and document diagnostics.
12040 pub fn pull_document_diagnostics_for_server(
12041 &mut self,
12042 server_id: LanguageServerId,
12043 source_buffer_id: Option<BufferId>,
12044 cx: &mut Context<Self>,
12045 ) -> Shared<Task<()>> {
12046 let Some(local) = self.as_local_mut() else {
12047 return Task::ready(()).shared();
12048 };
12049 let mut buffers_to_refresh = HashSet::default();
12050 for (buffer_id, server_ids) in &local.buffers_opened_in_servers {
12051 if server_ids.contains(&server_id) && Some(buffer_id) != source_buffer_id.as_ref() {
12052 buffers_to_refresh.insert(*buffer_id);
12053 }
12054 }
12055
12056 self.refresh_background_diagnostics_for_buffers(buffers_to_refresh, cx)
12057 }
12058
12059 pub fn pull_document_diagnostics_for_buffer_edit(
12060 &mut self,
12061 buffer_id: BufferId,
12062 cx: &mut Context<Self>,
12063 ) {
12064 let Some(local) = self.as_local_mut() else {
12065 return;
12066 };
12067 let Some(languages_servers) = local.buffers_opened_in_servers.get(&buffer_id).cloned()
12068 else {
12069 return;
12070 };
12071 for server_id in languages_servers {
12072 let _ = self.pull_document_diagnostics_for_server(server_id, Some(buffer_id), cx);
12073 }
12074 }
12075
12076 fn apply_workspace_diagnostic_report(
12077 &mut self,
12078 server_id: LanguageServerId,
12079 report: lsp::WorkspaceDiagnosticReportResult,
12080 registration_id: Option<SharedString>,
12081 cx: &mut Context<Self>,
12082 ) {
12083 let mut workspace_diagnostics =
12084 GetDocumentDiagnostics::deserialize_workspace_diagnostics_report(
12085 report,
12086 server_id,
12087 registration_id,
12088 );
12089 workspace_diagnostics.retain(|d| match &d.diagnostics {
12090 LspPullDiagnostics::Response {
12091 server_id,
12092 registration_id,
12093 ..
12094 } => self.diagnostic_registration_exists(*server_id, registration_id),
12095 LspPullDiagnostics::Default => false,
12096 });
12097 let mut unchanged_buffers = HashMap::default();
12098 let workspace_diagnostics_updates = workspace_diagnostics
12099 .into_iter()
12100 .filter_map(
12101 |workspace_diagnostics| match workspace_diagnostics.diagnostics {
12102 LspPullDiagnostics::Response {
12103 server_id,
12104 uri,
12105 diagnostics,
12106 registration_id,
12107 } => Some((
12108 server_id,
12109 uri,
12110 diagnostics,
12111 workspace_diagnostics.version,
12112 registration_id,
12113 )),
12114 LspPullDiagnostics::Default => None,
12115 },
12116 )
12117 .fold(
12118 HashMap::default(),
12119 |mut acc, (server_id, uri, diagnostics, version, new_registration_id)| {
12120 let (result_id, diagnostics) = match diagnostics {
12121 PulledDiagnostics::Unchanged { result_id } => {
12122 unchanged_buffers
12123 .entry(new_registration_id.clone())
12124 .or_insert_with(HashSet::default)
12125 .insert(uri.clone());
12126 (Some(result_id), Vec::new())
12127 }
12128 PulledDiagnostics::Changed {
12129 result_id,
12130 diagnostics,
12131 } => (result_id, diagnostics),
12132 };
12133 let disk_based_sources = Cow::Owned(
12134 self.language_server_adapter_for_id(server_id)
12135 .as_ref()
12136 .map(|adapter| adapter.disk_based_diagnostic_sources.as_slice())
12137 .unwrap_or(&[])
12138 .to_vec(),
12139 );
12140
12141 let Some(abs_path) = uri.to_file_path().ok() else {
12142 return acc;
12143 };
12144 let Some((worktree, relative_path)) =
12145 self.worktree_store.read(cx).find_worktree(abs_path.clone(), cx)
12146 else {
12147 log::warn!("skipping workspace diagnostics update, no worktree found for path {abs_path:?}");
12148 return acc;
12149 };
12150 let worktree_id = worktree.read(cx).id();
12151 let project_path = ProjectPath {
12152 worktree_id,
12153 path: relative_path,
12154 };
12155 if let Some(local_lsp_store) = self.as_local_mut() {
12156 local_lsp_store.workspace_pull_diagnostics_result_ids.entry(server_id)
12157 .or_default().entry(new_registration_id.clone()).or_default().insert(abs_path, result_id.clone());
12158 }
12159 // The LSP spec recommends that "diagnostics from a document pull should win over diagnostics from a workspace pull."
12160 // Since we actively pull diagnostics for documents with open buffers, we ignore contents of workspace pulls for these documents.
12161 if self.buffer_store.read(cx).get_by_path(&project_path).is_none() {
12162 acc.entry(server_id)
12163 .or_insert_with(HashMap::default)
12164 .entry(new_registration_id.clone())
12165 .or_insert_with(Vec::new)
12166 .push(DocumentDiagnosticsUpdate {
12167 server_id,
12168 diagnostics: lsp::PublishDiagnosticsParams {
12169 uri,
12170 diagnostics,
12171 version,
12172 },
12173 result_id: result_id.map(SharedString::new),
12174 disk_based_sources,
12175 registration_id: new_registration_id,
12176 });
12177 }
12178 acc
12179 },
12180 );
12181
12182 for diagnostic_updates in workspace_diagnostics_updates.into_values() {
12183 for (registration_id, diagnostic_updates) in diagnostic_updates {
12184 self.merge_lsp_diagnostics(
12185 DiagnosticSourceKind::Pulled,
12186 diagnostic_updates,
12187 |document_uri, old_diagnostic, _| match old_diagnostic.source_kind {
12188 DiagnosticSourceKind::Pulled => {
12189 old_diagnostic.registration_id != registration_id
12190 || unchanged_buffers
12191 .get(&old_diagnostic.registration_id)
12192 .is_some_and(|unchanged_buffers| {
12193 unchanged_buffers.contains(&document_uri)
12194 })
12195 }
12196 DiagnosticSourceKind::Other | DiagnosticSourceKind::Pushed => true,
12197 },
12198 cx,
12199 )
12200 .log_err();
12201 }
12202 }
12203 }
12204
12205 fn register_server_capabilities(
12206 &mut self,
12207 server_id: LanguageServerId,
12208 params: lsp::RegistrationParams,
12209 cx: &mut Context<Self>,
12210 ) -> anyhow::Result<()> {
12211 let server = self
12212 .language_server_for_id(server_id)
12213 .with_context(|| format!("no server {server_id} found"))?;
12214 for reg in params.registrations {
12215 match reg.method.as_str() {
12216 "workspace/didChangeWatchedFiles" => {
12217 if let Some(options) = reg.register_options {
12218 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12219 let caps = serde_json::from_value(options)?;
12220 local_lsp_store
12221 .on_lsp_did_change_watched_files(server_id, ®.id, caps, cx);
12222 true
12223 } else {
12224 false
12225 };
12226 if notify {
12227 notify_server_capabilities_updated(&server, cx);
12228 }
12229 }
12230 }
12231 "workspace/didChangeConfiguration" => {
12232 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12233 }
12234 "workspace/didChangeWorkspaceFolders" => {
12235 // In this case register options is an empty object, we can ignore it
12236 let caps = lsp::WorkspaceFoldersServerCapabilities {
12237 supported: Some(true),
12238 change_notifications: Some(OneOf::Right(reg.id)),
12239 };
12240 server.update_capabilities(|capabilities| {
12241 capabilities
12242 .workspace
12243 .get_or_insert_default()
12244 .workspace_folders = Some(caps);
12245 });
12246 notify_server_capabilities_updated(&server, cx);
12247 }
12248 "workspace/symbol" => {
12249 let options = parse_register_capabilities(reg)?;
12250 server.update_capabilities(|capabilities| {
12251 capabilities.workspace_symbol_provider = Some(options);
12252 });
12253 notify_server_capabilities_updated(&server, cx);
12254 }
12255 "workspace/fileOperations" => {
12256 if let Some(options) = reg.register_options {
12257 let caps = serde_json::from_value(options)?;
12258 server.update_capabilities(|capabilities| {
12259 capabilities
12260 .workspace
12261 .get_or_insert_default()
12262 .file_operations = Some(caps);
12263 });
12264 notify_server_capabilities_updated(&server, cx);
12265 }
12266 }
12267 "workspace/executeCommand" => {
12268 if let Some(options) = reg.register_options {
12269 let options = serde_json::from_value(options)?;
12270 server.update_capabilities(|capabilities| {
12271 capabilities.execute_command_provider = Some(options);
12272 });
12273 notify_server_capabilities_updated(&server, cx);
12274 }
12275 }
12276 "textDocument/rangeFormatting" => {
12277 let options = parse_register_capabilities(reg)?;
12278 server.update_capabilities(|capabilities| {
12279 capabilities.document_range_formatting_provider = Some(options);
12280 });
12281 notify_server_capabilities_updated(&server, cx);
12282 }
12283 "textDocument/onTypeFormatting" => {
12284 if let Some(options) = reg
12285 .register_options
12286 .map(serde_json::from_value)
12287 .transpose()?
12288 {
12289 server.update_capabilities(|capabilities| {
12290 capabilities.document_on_type_formatting_provider = Some(options);
12291 });
12292 notify_server_capabilities_updated(&server, cx);
12293 }
12294 }
12295 "textDocument/formatting" => {
12296 let options = parse_register_capabilities(reg)?;
12297 server.update_capabilities(|capabilities| {
12298 capabilities.document_formatting_provider = Some(options);
12299 });
12300 notify_server_capabilities_updated(&server, cx);
12301 }
12302 "textDocument/rename" => {
12303 let options = parse_register_capabilities(reg)?;
12304 server.update_capabilities(|capabilities| {
12305 capabilities.rename_provider = Some(options);
12306 });
12307 notify_server_capabilities_updated(&server, cx);
12308 }
12309 "textDocument/inlayHint" => {
12310 let options = parse_register_capabilities(reg)?;
12311 server.update_capabilities(|capabilities| {
12312 capabilities.inlay_hint_provider = Some(options);
12313 });
12314 notify_server_capabilities_updated(&server, cx);
12315 }
12316 "textDocument/documentSymbol" => {
12317 let options = parse_register_capabilities(reg)?;
12318 server.update_capabilities(|capabilities| {
12319 capabilities.document_symbol_provider = Some(options);
12320 });
12321 notify_server_capabilities_updated(&server, cx);
12322 }
12323 "textDocument/codeAction" => {
12324 let options = parse_register_capabilities(reg)?;
12325 let provider = match options {
12326 OneOf::Left(value) => lsp::CodeActionProviderCapability::Simple(value),
12327 OneOf::Right(caps) => caps,
12328 };
12329 server.update_capabilities(|capabilities| {
12330 capabilities.code_action_provider = Some(provider);
12331 });
12332 notify_server_capabilities_updated(&server, cx);
12333 }
12334 "textDocument/definition" => {
12335 let options = parse_register_capabilities(reg)?;
12336 server.update_capabilities(|capabilities| {
12337 capabilities.definition_provider = Some(options);
12338 });
12339 notify_server_capabilities_updated(&server, cx);
12340 }
12341 "textDocument/completion" => {
12342 if let Some(caps) = reg
12343 .register_options
12344 .map(serde_json::from_value::<CompletionOptions>)
12345 .transpose()?
12346 {
12347 server.update_capabilities(|capabilities| {
12348 capabilities.completion_provider = Some(caps.clone());
12349 });
12350
12351 if let Some(local) = self.as_local() {
12352 let mut buffers_with_language_server = Vec::new();
12353 for handle in self.buffer_store.read(cx).buffers() {
12354 let buffer_id = handle.read(cx).remote_id();
12355 if local
12356 .buffers_opened_in_servers
12357 .get(&buffer_id)
12358 .filter(|s| s.contains(&server_id))
12359 .is_some()
12360 {
12361 buffers_with_language_server.push(handle);
12362 }
12363 }
12364 let triggers = caps
12365 .trigger_characters
12366 .unwrap_or_default()
12367 .into_iter()
12368 .collect::<BTreeSet<_>>();
12369 for handle in buffers_with_language_server {
12370 let triggers = triggers.clone();
12371 let _ = handle.update(cx, move |buffer, cx| {
12372 buffer.set_completion_triggers(server_id, triggers, cx);
12373 });
12374 }
12375 }
12376 notify_server_capabilities_updated(&server, cx);
12377 }
12378 }
12379 "textDocument/hover" => {
12380 let options = parse_register_capabilities(reg)?;
12381 let provider = match options {
12382 OneOf::Left(value) => lsp::HoverProviderCapability::Simple(value),
12383 OneOf::Right(caps) => caps,
12384 };
12385 server.update_capabilities(|capabilities| {
12386 capabilities.hover_provider = Some(provider);
12387 });
12388 notify_server_capabilities_updated(&server, cx);
12389 }
12390 "textDocument/signatureHelp" => {
12391 if let Some(caps) = reg
12392 .register_options
12393 .map(serde_json::from_value)
12394 .transpose()?
12395 {
12396 server.update_capabilities(|capabilities| {
12397 capabilities.signature_help_provider = Some(caps);
12398 });
12399 notify_server_capabilities_updated(&server, cx);
12400 }
12401 }
12402 "textDocument/didChange" => {
12403 if let Some(sync_kind) = reg
12404 .register_options
12405 .and_then(|opts| opts.get("syncKind").cloned())
12406 .map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
12407 .transpose()?
12408 {
12409 server.update_capabilities(|capabilities| {
12410 let mut sync_options =
12411 Self::take_text_document_sync_options(capabilities);
12412 sync_options.change = Some(sync_kind);
12413 capabilities.text_document_sync =
12414 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12415 });
12416 notify_server_capabilities_updated(&server, cx);
12417 }
12418 }
12419 "textDocument/didSave" => {
12420 if let Some(include_text) = reg
12421 .register_options
12422 .map(|opts| {
12423 let transpose = opts
12424 .get("includeText")
12425 .cloned()
12426 .map(serde_json::from_value::<Option<bool>>)
12427 .transpose();
12428 match transpose {
12429 Ok(value) => Ok(value.flatten()),
12430 Err(e) => Err(e),
12431 }
12432 })
12433 .transpose()?
12434 {
12435 server.update_capabilities(|capabilities| {
12436 let mut sync_options =
12437 Self::take_text_document_sync_options(capabilities);
12438 sync_options.save =
12439 Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
12440 include_text,
12441 }));
12442 capabilities.text_document_sync =
12443 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12444 });
12445 notify_server_capabilities_updated(&server, cx);
12446 }
12447 }
12448 "textDocument/codeLens" => {
12449 if let Some(caps) = reg
12450 .register_options
12451 .map(serde_json::from_value)
12452 .transpose()?
12453 {
12454 server.update_capabilities(|capabilities| {
12455 capabilities.code_lens_provider = Some(caps);
12456 });
12457 notify_server_capabilities_updated(&server, cx);
12458 }
12459 }
12460 "textDocument/diagnostic" => {
12461 if let Some(caps) = reg
12462 .register_options
12463 .map(serde_json::from_value::<DiagnosticServerCapabilities>)
12464 .transpose()?
12465 {
12466 let local = self
12467 .as_local_mut()
12468 .context("Expected LSP Store to be local")?;
12469 let state = local
12470 .language_servers
12471 .get_mut(&server_id)
12472 .context("Could not obtain Language Servers state")?;
12473 local
12474 .language_server_dynamic_registrations
12475 .entry(server_id)
12476 .or_default()
12477 .diagnostics
12478 .insert(Some(reg.id.clone()), caps.clone());
12479
12480 let supports_workspace_diagnostics =
12481 |capabilities: &DiagnosticServerCapabilities| match capabilities {
12482 DiagnosticServerCapabilities::Options(diagnostic_options) => {
12483 diagnostic_options.workspace_diagnostics
12484 }
12485 DiagnosticServerCapabilities::RegistrationOptions(
12486 diagnostic_registration_options,
12487 ) => {
12488 diagnostic_registration_options
12489 .diagnostic_options
12490 .workspace_diagnostics
12491 }
12492 };
12493
12494 if supports_workspace_diagnostics(&caps) {
12495 if let LanguageServerState::Running {
12496 workspace_diagnostics_refresh_tasks,
12497 ..
12498 } = state
12499 && let Some(task) = lsp_workspace_diagnostics_refresh(
12500 Some(reg.id.clone()),
12501 caps.clone(),
12502 server.clone(),
12503 cx,
12504 )
12505 {
12506 workspace_diagnostics_refresh_tasks.insert(Some(reg.id), task);
12507 }
12508 }
12509
12510 server.update_capabilities(|capabilities| {
12511 capabilities.diagnostic_provider = Some(caps);
12512 });
12513
12514 notify_server_capabilities_updated(&server, cx);
12515
12516 let _ = self.pull_document_diagnostics_for_server(server_id, None, cx);
12517 }
12518 }
12519 "textDocument/documentColor" => {
12520 let options = parse_register_capabilities(reg)?;
12521 let provider = match options {
12522 OneOf::Left(value) => lsp::ColorProviderCapability::Simple(value),
12523 OneOf::Right(caps) => caps,
12524 };
12525 server.update_capabilities(|capabilities| {
12526 capabilities.color_provider = Some(provider);
12527 });
12528 notify_server_capabilities_updated(&server, cx);
12529 }
12530 "textDocument/foldingRange" => {
12531 let options = parse_register_capabilities(reg)?;
12532 let provider = match options {
12533 OneOf::Left(value) => lsp::FoldingRangeProviderCapability::Simple(value),
12534 OneOf::Right(caps) => caps,
12535 };
12536 server.update_capabilities(|capabilities| {
12537 capabilities.folding_range_provider = Some(provider);
12538 });
12539 notify_server_capabilities_updated(&server, cx);
12540 }
12541 _ => log::warn!("unhandled capability registration: {reg:?}"),
12542 }
12543 }
12544
12545 Ok(())
12546 }
12547
12548 fn unregister_server_capabilities(
12549 &mut self,
12550 server_id: LanguageServerId,
12551 params: lsp::UnregistrationParams,
12552 cx: &mut Context<Self>,
12553 ) -> anyhow::Result<()> {
12554 let server = self
12555 .language_server_for_id(server_id)
12556 .with_context(|| format!("no server {server_id} found"))?;
12557 for unreg in params.unregisterations.iter() {
12558 match unreg.method.as_str() {
12559 "workspace/didChangeWatchedFiles" => {
12560 let notify = if let Some(local_lsp_store) = self.as_local_mut() {
12561 local_lsp_store
12562 .on_lsp_unregister_did_change_watched_files(server_id, &unreg.id, cx);
12563 true
12564 } else {
12565 false
12566 };
12567 if notify {
12568 notify_server_capabilities_updated(&server, cx);
12569 }
12570 }
12571 "workspace/didChangeConfiguration" => {
12572 // Ignore payload since we notify clients of setting changes unconditionally, relying on them pulling the latest settings.
12573 }
12574 "workspace/didChangeWorkspaceFolders" => {
12575 server.update_capabilities(|capabilities| {
12576 capabilities
12577 .workspace
12578 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12579 workspace_folders: None,
12580 file_operations: None,
12581 })
12582 .workspace_folders = None;
12583 });
12584 notify_server_capabilities_updated(&server, cx);
12585 }
12586 "workspace/symbol" => {
12587 server.update_capabilities(|capabilities| {
12588 capabilities.workspace_symbol_provider = None
12589 });
12590 notify_server_capabilities_updated(&server, cx);
12591 }
12592 "workspace/fileOperations" => {
12593 server.update_capabilities(|capabilities| {
12594 capabilities
12595 .workspace
12596 .get_or_insert_with(|| lsp::WorkspaceServerCapabilities {
12597 workspace_folders: None,
12598 file_operations: None,
12599 })
12600 .file_operations = None;
12601 });
12602 notify_server_capabilities_updated(&server, cx);
12603 }
12604 "workspace/executeCommand" => {
12605 server.update_capabilities(|capabilities| {
12606 capabilities.execute_command_provider = None;
12607 });
12608 notify_server_capabilities_updated(&server, cx);
12609 }
12610 "textDocument/rangeFormatting" => {
12611 server.update_capabilities(|capabilities| {
12612 capabilities.document_range_formatting_provider = None
12613 });
12614 notify_server_capabilities_updated(&server, cx);
12615 }
12616 "textDocument/onTypeFormatting" => {
12617 server.update_capabilities(|capabilities| {
12618 capabilities.document_on_type_formatting_provider = None;
12619 });
12620 notify_server_capabilities_updated(&server, cx);
12621 }
12622 "textDocument/formatting" => {
12623 server.update_capabilities(|capabilities| {
12624 capabilities.document_formatting_provider = None;
12625 });
12626 notify_server_capabilities_updated(&server, cx);
12627 }
12628 "textDocument/rename" => {
12629 server.update_capabilities(|capabilities| capabilities.rename_provider = None);
12630 notify_server_capabilities_updated(&server, cx);
12631 }
12632 "textDocument/codeAction" => {
12633 server.update_capabilities(|capabilities| {
12634 capabilities.code_action_provider = None;
12635 });
12636 notify_server_capabilities_updated(&server, cx);
12637 }
12638 "textDocument/definition" => {
12639 server.update_capabilities(|capabilities| {
12640 capabilities.definition_provider = None;
12641 });
12642 notify_server_capabilities_updated(&server, cx);
12643 }
12644 "textDocument/completion" => {
12645 server.update_capabilities(|capabilities| {
12646 capabilities.completion_provider = None;
12647 });
12648 notify_server_capabilities_updated(&server, cx);
12649 }
12650 "textDocument/hover" => {
12651 server.update_capabilities(|capabilities| {
12652 capabilities.hover_provider = None;
12653 });
12654 notify_server_capabilities_updated(&server, cx);
12655 }
12656 "textDocument/signatureHelp" => {
12657 server.update_capabilities(|capabilities| {
12658 capabilities.signature_help_provider = None;
12659 });
12660 notify_server_capabilities_updated(&server, cx);
12661 }
12662 "textDocument/didChange" => {
12663 server.update_capabilities(|capabilities| {
12664 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12665 sync_options.change = None;
12666 capabilities.text_document_sync =
12667 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12668 });
12669 notify_server_capabilities_updated(&server, cx);
12670 }
12671 "textDocument/didSave" => {
12672 server.update_capabilities(|capabilities| {
12673 let mut sync_options = Self::take_text_document_sync_options(capabilities);
12674 sync_options.save = None;
12675 capabilities.text_document_sync =
12676 Some(lsp::TextDocumentSyncCapability::Options(sync_options));
12677 });
12678 notify_server_capabilities_updated(&server, cx);
12679 }
12680 "textDocument/codeLens" => {
12681 server.update_capabilities(|capabilities| {
12682 capabilities.code_lens_provider = None;
12683 });
12684 notify_server_capabilities_updated(&server, cx);
12685 }
12686 "textDocument/diagnostic" => {
12687 let local = self
12688 .as_local_mut()
12689 .context("Expected LSP Store to be local")?;
12690
12691 let state = local
12692 .language_servers
12693 .get_mut(&server_id)
12694 .context("Could not obtain Language Servers state")?;
12695 let registrations = local
12696 .language_server_dynamic_registrations
12697 .get_mut(&server_id)
12698 .with_context(|| {
12699 format!("Expected dynamic registration to exist for server {server_id}")
12700 })?;
12701 registrations.diagnostics
12702 .remove(&Some(unreg.id.clone()))
12703 .with_context(|| format!(
12704 "Attempted to unregister non-existent diagnostic registration with ID {}",
12705 unreg.id)
12706 )?;
12707 let removed_last_diagnostic_provider = registrations.diagnostics.is_empty();
12708
12709 if let LanguageServerState::Running {
12710 workspace_diagnostics_refresh_tasks,
12711 ..
12712 } = state
12713 {
12714 workspace_diagnostics_refresh_tasks.remove(&Some(unreg.id.clone()));
12715 }
12716
12717 self.clear_unregistered_diagnostics(
12718 server_id,
12719 SharedString::from(unreg.id.clone()),
12720 cx,
12721 )?;
12722
12723 if removed_last_diagnostic_provider {
12724 server.update_capabilities(|capabilities| {
12725 debug_assert!(capabilities.diagnostic_provider.is_some());
12726 capabilities.diagnostic_provider = None;
12727 });
12728 }
12729
12730 notify_server_capabilities_updated(&server, cx);
12731 }
12732 "textDocument/documentColor" => {
12733 server.update_capabilities(|capabilities| {
12734 capabilities.color_provider = None;
12735 });
12736 notify_server_capabilities_updated(&server, cx);
12737 }
12738 "textDocument/foldingRange" => {
12739 server.update_capabilities(|capabilities| {
12740 capabilities.folding_range_provider = None;
12741 });
12742 notify_server_capabilities_updated(&server, cx);
12743 }
12744 _ => log::warn!("unhandled capability unregistration: {unreg:?}"),
12745 }
12746 }
12747
12748 Ok(())
12749 }
12750
12751 fn clear_unregistered_diagnostics(
12752 &mut self,
12753 server_id: LanguageServerId,
12754 cleared_registration_id: SharedString,
12755 cx: &mut Context<Self>,
12756 ) -> anyhow::Result<()> {
12757 let mut affected_abs_paths: HashSet<PathBuf> = HashSet::default();
12758
12759 self.buffer_store.update(cx, |buffer_store, cx| {
12760 for buffer_handle in buffer_store.buffers() {
12761 let buffer = buffer_handle.read(cx);
12762 let abs_path = File::from_dyn(buffer.file()).map(|f| f.abs_path(cx));
12763 let Some(abs_path) = abs_path else {
12764 continue;
12765 };
12766 affected_abs_paths.insert(abs_path);
12767 }
12768 });
12769
12770 let local = self.as_local().context("Expected LSP Store to be local")?;
12771 for (worktree_id, diagnostics_for_tree) in local.diagnostics.iter() {
12772 let Some(worktree) = self
12773 .worktree_store
12774 .read(cx)
12775 .worktree_for_id(*worktree_id, cx)
12776 else {
12777 continue;
12778 };
12779
12780 for (rel_path, diagnostics_by_server_id) in diagnostics_for_tree.iter() {
12781 if let Ok(ix) = diagnostics_by_server_id.binary_search_by_key(&server_id, |e| e.0) {
12782 let has_matching_registration =
12783 diagnostics_by_server_id[ix].1.iter().any(|entry| {
12784 entry.diagnostic.registration_id.as_ref()
12785 == Some(&cleared_registration_id)
12786 });
12787 if has_matching_registration {
12788 let abs_path = worktree.read(cx).absolutize(rel_path);
12789 affected_abs_paths.insert(abs_path);
12790 }
12791 }
12792 }
12793 }
12794
12795 if affected_abs_paths.is_empty() {
12796 return Ok(());
12797 }
12798
12799 // Send a fake diagnostic update which clears the state for the registration ID
12800 let clears: Vec<DocumentDiagnosticsUpdate<'static, DocumentDiagnostics>> =
12801 affected_abs_paths
12802 .into_iter()
12803 .map(|abs_path| DocumentDiagnosticsUpdate {
12804 diagnostics: DocumentDiagnostics {
12805 diagnostics: Vec::new(),
12806 document_abs_path: abs_path,
12807 version: None,
12808 },
12809 result_id: None,
12810 registration_id: Some(cleared_registration_id.clone()),
12811 server_id,
12812 disk_based_sources: Cow::Borrowed(&[]),
12813 })
12814 .collect();
12815
12816 let merge_registration_id = cleared_registration_id.clone();
12817 self.merge_diagnostic_entries(
12818 clears,
12819 move |_, diagnostic, _| {
12820 if diagnostic.source_kind == DiagnosticSourceKind::Pulled {
12821 diagnostic.registration_id != Some(merge_registration_id.clone())
12822 } else {
12823 true
12824 }
12825 },
12826 cx,
12827 )?;
12828
12829 Ok(())
12830 }
12831
12832 async fn deduplicate_range_based_lsp_requests<T>(
12833 lsp_store: &Entity<Self>,
12834 server_id: Option<LanguageServerId>,
12835 lsp_request_id: LspRequestId,
12836 proto_request: &T::ProtoRequest,
12837 range: Range<Anchor>,
12838 cx: &mut AsyncApp,
12839 ) -> Result<()>
12840 where
12841 T: LspCommand,
12842 T::ProtoRequest: proto::LspRequestMessage,
12843 {
12844 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12845 let version = deserialize_version(proto_request.buffer_version());
12846 let buffer = lsp_store.update(cx, |this, cx| {
12847 this.buffer_store.read(cx).get_existing(buffer_id)
12848 })?;
12849 buffer
12850 .update(cx, |buffer, _| buffer.wait_for_version(version))
12851 .await?;
12852 lsp_store.update(cx, |lsp_store, cx| {
12853 let buffer_snapshot = buffer.read(cx).snapshot();
12854 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12855 let chunks_queried_for = lsp_data
12856 .inlay_hints
12857 .applicable_chunks(&[range.to_point(&buffer_snapshot)])
12858 .collect::<Vec<_>>();
12859 match chunks_queried_for.as_slice() {
12860 &[chunk] => {
12861 let key = LspKey {
12862 request_type: TypeId::of::<T>(),
12863 server_queried: server_id,
12864 };
12865 let previous_request = lsp_data
12866 .chunk_lsp_requests
12867 .entry(key)
12868 .or_default()
12869 .insert(chunk, lsp_request_id);
12870 if let Some((previous_request, running_requests)) =
12871 previous_request.zip(lsp_data.lsp_requests.get_mut(&key))
12872 {
12873 running_requests.remove(&previous_request);
12874 }
12875 }
12876 _ambiguous_chunks => {
12877 // Have not found a unique chunk for the query range — be lenient and let the query to be spawned,
12878 // there, a buffer version-based check will be performed and outdated requests discarded.
12879 }
12880 }
12881 anyhow::Ok(())
12882 })?;
12883
12884 Ok(())
12885 }
12886
12887 async fn query_lsp_locally<T>(
12888 lsp_store: Entity<Self>,
12889 for_server_id: Option<LanguageServerId>,
12890 sender_id: proto::PeerId,
12891 lsp_request_id: LspRequestId,
12892 proto_request: T::ProtoRequest,
12893 position: Option<Anchor>,
12894 cx: &mut AsyncApp,
12895 ) -> Result<()>
12896 where
12897 T: LspCommand + Clone,
12898 T::ProtoRequest: proto::LspRequestMessage,
12899 <T::ProtoRequest as proto::RequestMessage>::Response:
12900 Into<<T::ProtoRequest as proto::LspRequestMessage>::Response>,
12901 {
12902 let (buffer_version, buffer) =
12903 Self::wait_for_buffer_version::<T>(&lsp_store, &proto_request, cx).await?;
12904 let request =
12905 T::from_proto(proto_request, lsp_store.clone(), buffer.clone(), cx.clone()).await?;
12906 let key = LspKey {
12907 request_type: TypeId::of::<T>(),
12908 server_queried: for_server_id,
12909 };
12910 lsp_store.update(cx, |lsp_store, cx| {
12911 let request_task = match for_server_id {
12912 Some(server_id) => {
12913 let server_task = lsp_store.request_lsp(
12914 buffer.clone(),
12915 LanguageServerToQuery::Other(server_id),
12916 request.clone(),
12917 cx,
12918 );
12919 cx.background_spawn(async move {
12920 let mut responses = Vec::new();
12921 match server_task.await {
12922 Ok(response) => responses.push((server_id, response)),
12923 // rust-analyzer likes to error with this when its still loading up
12924 Err(e) if format!("{e:#}").ends_with("content modified") => (),
12925 Err(e) => log::error!(
12926 "Error handling response for request {request:?}: {e:#}"
12927 ),
12928 }
12929 responses
12930 })
12931 }
12932 None => lsp_store.request_multiple_lsp_locally(&buffer, position, request, cx),
12933 };
12934 let lsp_data = lsp_store.latest_lsp_data(&buffer, cx);
12935 if T::ProtoRequest::stop_previous_requests() {
12936 if let Some(lsp_requests) = lsp_data.lsp_requests.get_mut(&key) {
12937 lsp_requests.clear();
12938 }
12939 }
12940 lsp_data.lsp_requests.entry(key).or_default().insert(
12941 lsp_request_id,
12942 cx.spawn(async move |lsp_store, cx| {
12943 let response = request_task.await;
12944 lsp_store
12945 .update(cx, |lsp_store, cx| {
12946 if let Some((client, project_id)) = lsp_store.downstream_client.clone()
12947 {
12948 let response = response
12949 .into_iter()
12950 .map(|(server_id, response)| {
12951 (
12952 server_id.to_proto(),
12953 T::response_to_proto(
12954 response,
12955 lsp_store,
12956 sender_id,
12957 &buffer_version,
12958 cx,
12959 )
12960 .into(),
12961 )
12962 })
12963 .collect::<HashMap<_, _>>();
12964 match client.send_lsp_response::<T::ProtoRequest>(
12965 project_id,
12966 lsp_request_id,
12967 response,
12968 ) {
12969 Ok(()) => {}
12970 Err(e) => {
12971 log::error!("Failed to send LSP response: {e:#}",)
12972 }
12973 }
12974 }
12975 })
12976 .ok();
12977 }),
12978 );
12979 });
12980 Ok(())
12981 }
12982
12983 async fn wait_for_buffer_version<T>(
12984 lsp_store: &Entity<Self>,
12985 proto_request: &T::ProtoRequest,
12986 cx: &mut AsyncApp,
12987 ) -> Result<(Global, Entity<Buffer>)>
12988 where
12989 T: LspCommand,
12990 T::ProtoRequest: proto::LspRequestMessage,
12991 {
12992 let buffer_id = BufferId::new(proto_request.buffer_id())?;
12993 let version = deserialize_version(proto_request.buffer_version());
12994 let buffer = lsp_store.update(cx, |this, cx| {
12995 this.buffer_store.read(cx).get_existing(buffer_id)
12996 })?;
12997 buffer
12998 .update(cx, |buffer, _| buffer.wait_for_version(version.clone()))
12999 .await?;
13000 let buffer_version = buffer.read_with(cx, |buffer, _| buffer.version());
13001 Ok((buffer_version, buffer))
13002 }
13003
13004 fn take_text_document_sync_options(
13005 capabilities: &mut lsp::ServerCapabilities,
13006 ) -> lsp::TextDocumentSyncOptions {
13007 match capabilities.text_document_sync.take() {
13008 Some(lsp::TextDocumentSyncCapability::Options(sync_options)) => sync_options,
13009 Some(lsp::TextDocumentSyncCapability::Kind(sync_kind)) => {
13010 let mut sync_options = lsp::TextDocumentSyncOptions::default();
13011 sync_options.change = Some(sync_kind);
13012 sync_options
13013 }
13014 None => lsp::TextDocumentSyncOptions::default(),
13015 }
13016 }
13017
13018 pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
13019 self.downstream_client.clone()
13020 }
13021
13022 pub fn worktree_store(&self) -> Entity<WorktreeStore> {
13023 self.worktree_store.clone()
13024 }
13025
13026 /// Gets what's stored in the LSP data for the given buffer.
13027 pub fn current_lsp_data(&mut self, buffer_id: BufferId) -> Option<&mut BufferLspData> {
13028 self.lsp_data.get_mut(&buffer_id)
13029 }
13030
13031 /// Gets the most recent LSP data for the given buffer: if the data is absent or out of date,
13032 /// new [`BufferLspData`] will be created to replace the previous state.
13033 pub fn latest_lsp_data(&mut self, buffer: &Entity<Buffer>, cx: &mut App) -> &mut BufferLspData {
13034 let (buffer_id, buffer_version) =
13035 buffer.read_with(cx, |buffer, _| (buffer.remote_id(), buffer.version()));
13036 let lsp_data = self
13037 .lsp_data
13038 .entry(buffer_id)
13039 .or_insert_with(|| BufferLspData::new(buffer, cx));
13040 if buffer_version.changed_since(&lsp_data.buffer_version) {
13041 // To send delta requests for semantic tokens, the previous tokens
13042 // need to be kept between buffer changes.
13043 let semantic_tokens = lsp_data.semantic_tokens.take();
13044 *lsp_data = BufferLspData::new(buffer, cx);
13045 lsp_data.semantic_tokens = semantic_tokens;
13046 }
13047 lsp_data
13048 }
13049}
13050
13051// Registration with registerOptions as null, should fallback to true.
13052// https://github.com/microsoft/vscode-languageserver-node/blob/d90a87f9557a0df9142cfb33e251cfa6fe27d970/client/src/common/client.ts#L2133
13053fn parse_register_capabilities<T: serde::de::DeserializeOwned>(
13054 reg: lsp::Registration,
13055) -> Result<OneOf<bool, T>> {
13056 Ok(match reg.register_options {
13057 Some(options) => OneOf::Right(serde_json::from_value::<T>(options)?),
13058 None => OneOf::Left(true),
13059 })
13060}
13061
13062fn subscribe_to_binary_statuses(
13063 languages: &Arc<LanguageRegistry>,
13064 cx: &mut Context<'_, LspStore>,
13065) -> Task<()> {
13066 let mut server_statuses = languages.language_server_binary_statuses();
13067 cx.spawn(async move |lsp_store, cx| {
13068 while let Some((server_name, binary_status)) = server_statuses.next().await {
13069 if lsp_store
13070 .update(cx, |_, cx| {
13071 let mut message = None;
13072 let binary_status = match binary_status {
13073 BinaryStatus::None => proto::ServerBinaryStatus::None,
13074 BinaryStatus::CheckingForUpdate => {
13075 proto::ServerBinaryStatus::CheckingForUpdate
13076 }
13077 BinaryStatus::Downloading => proto::ServerBinaryStatus::Downloading,
13078 BinaryStatus::Starting => proto::ServerBinaryStatus::Starting,
13079 BinaryStatus::Stopping => proto::ServerBinaryStatus::Stopping,
13080 BinaryStatus::Stopped => proto::ServerBinaryStatus::Stopped,
13081 BinaryStatus::Failed { error } => {
13082 message = Some(error);
13083 proto::ServerBinaryStatus::Failed
13084 }
13085 };
13086 cx.emit(LspStoreEvent::LanguageServerUpdate {
13087 // Binary updates are about the binary that might not have any language server id at that point.
13088 // Reuse `LanguageServerUpdate` for them and provide a fake id that won't be used on the receiver side.
13089 language_server_id: LanguageServerId(0),
13090 name: Some(server_name),
13091 message: proto::update_language_server::Variant::StatusUpdate(
13092 proto::StatusUpdate {
13093 message,
13094 status: Some(proto::status_update::Status::Binary(
13095 binary_status as i32,
13096 )),
13097 },
13098 ),
13099 });
13100 })
13101 .is_err()
13102 {
13103 break;
13104 }
13105 }
13106 })
13107}
13108
13109fn lsp_workspace_diagnostics_refresh(
13110 registration_id: Option<String>,
13111 options: DiagnosticServerCapabilities,
13112 server: Arc<LanguageServer>,
13113 cx: &mut Context<'_, LspStore>,
13114) -> Option<WorkspaceRefreshTask> {
13115 let identifier = workspace_diagnostic_identifier(&options)?;
13116 let registration_id_shared = registration_id.as_ref().map(SharedString::from);
13117
13118 let (progress_tx, mut progress_rx) = mpsc::channel(1);
13119 let (mut refresh_tx, mut refresh_rx) = mpsc::channel(1);
13120 refresh_tx.try_send(()).ok();
13121
13122 let request_timeout = ProjectSettings::get_global(cx)
13123 .global_lsp_settings
13124 .get_request_timeout();
13125
13126 // 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.
13127 // This allows users to increase the duration if need be
13128 let timeout = if request_timeout != Duration::ZERO {
13129 request_timeout.max(DEFAULT_LSP_REQUEST_TIMEOUT)
13130 } else {
13131 request_timeout
13132 };
13133
13134 let workspace_query_language_server = cx.spawn(async move |lsp_store, cx| {
13135 let mut attempts = 0;
13136 let max_attempts = 50;
13137 let mut requests = 0;
13138
13139 loop {
13140 let Some(()) = refresh_rx.recv().await else {
13141 return;
13142 };
13143
13144 'request: loop {
13145 requests += 1;
13146 if attempts > max_attempts {
13147 log::error!(
13148 "Failed to pull workspace diagnostics {max_attempts} times, aborting"
13149 );
13150 return;
13151 }
13152 let backoff_millis = (50 * (1 << attempts)).clamp(30, 1000);
13153 cx.background_executor()
13154 .timer(Duration::from_millis(backoff_millis))
13155 .await;
13156 attempts += 1;
13157
13158 let Ok(previous_result_ids) = lsp_store.update(cx, |lsp_store, _| {
13159 lsp_store
13160 .result_ids_for_workspace_refresh(server.server_id(), ®istration_id_shared)
13161 .into_iter()
13162 .filter_map(|(abs_path, result_id)| {
13163 let uri = file_path_to_lsp_url(&abs_path).ok()?;
13164 Some(lsp::PreviousResultId {
13165 uri,
13166 value: result_id.to_string(),
13167 })
13168 })
13169 .collect()
13170 }) else {
13171 return;
13172 };
13173
13174 let token = if let Some(registration_id) = ®istration_id {
13175 format!(
13176 "workspace/diagnostic/{}/{requests}/{WORKSPACE_DIAGNOSTICS_TOKEN_START}{registration_id}",
13177 server.server_id(),
13178 )
13179 } else {
13180 format!("workspace/diagnostic/{}/{requests}", server.server_id())
13181 };
13182
13183 progress_rx.try_recv().ok();
13184 let timer = server.request_timer(timeout).fuse();
13185 let progress = pin!(progress_rx.recv().fuse());
13186 let response_result = server
13187 .request_with_timer::<lsp::WorkspaceDiagnosticRequest, _>(
13188 lsp::WorkspaceDiagnosticParams {
13189 previous_result_ids,
13190 identifier: identifier.clone(),
13191 work_done_progress_params: Default::default(),
13192 partial_result_params: lsp::PartialResultParams {
13193 partial_result_token: Some(lsp::ProgressToken::String(token)),
13194 },
13195 },
13196 select(timer, progress).then(|either| match either {
13197 Either::Left((message, ..)) => ready(message).left_future(),
13198 Either::Right(..) => pending::<String>().right_future(),
13199 }),
13200 )
13201 .await;
13202
13203 // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh
13204 // > If a server closes a workspace diagnostic pull request the client should re-trigger the request.
13205 match response_result {
13206 ConnectionResult::Timeout => {
13207 log::error!("Timeout during workspace diagnostics pull");
13208 continue 'request;
13209 }
13210 ConnectionResult::ConnectionReset => {
13211 log::error!("Server closed a workspace diagnostics pull request");
13212 continue 'request;
13213 }
13214 ConnectionResult::Result(Err(e)) => {
13215 log::error!("Error during workspace diagnostics pull: {e:#}");
13216 break 'request;
13217 }
13218 ConnectionResult::Result(Ok(pulled_diagnostics)) => {
13219 attempts = 0;
13220 if lsp_store
13221 .update(cx, |lsp_store, cx| {
13222 lsp_store.apply_workspace_diagnostic_report(
13223 server.server_id(),
13224 pulled_diagnostics,
13225 registration_id_shared.clone(),
13226 cx,
13227 )
13228 })
13229 .is_err()
13230 {
13231 return;
13232 }
13233 break 'request;
13234 }
13235 }
13236 }
13237 }
13238 });
13239
13240 Some(WorkspaceRefreshTask {
13241 refresh_tx,
13242 progress_tx,
13243 task: workspace_query_language_server,
13244 })
13245}
13246
13247fn buffer_diagnostic_identifier(options: &DiagnosticServerCapabilities) -> Option<SharedString> {
13248 match &options {
13249 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => diagnostic_options
13250 .identifier
13251 .as_deref()
13252 .map(SharedString::new),
13253 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13254 let diagnostic_options = ®istration_options.diagnostic_options;
13255 diagnostic_options
13256 .identifier
13257 .as_deref()
13258 .map(SharedString::new)
13259 }
13260 }
13261}
13262
13263fn workspace_diagnostic_identifier(
13264 options: &DiagnosticServerCapabilities,
13265) -> Option<Option<String>> {
13266 match &options {
13267 lsp::DiagnosticServerCapabilities::Options(diagnostic_options) => {
13268 if !diagnostic_options.workspace_diagnostics {
13269 return None;
13270 }
13271 Some(diagnostic_options.identifier.clone())
13272 }
13273 lsp::DiagnosticServerCapabilities::RegistrationOptions(registration_options) => {
13274 let diagnostic_options = ®istration_options.diagnostic_options;
13275 if !diagnostic_options.workspace_diagnostics {
13276 return None;
13277 }
13278 Some(diagnostic_options.identifier.clone())
13279 }
13280 }
13281}
13282
13283fn resolve_word_completion(snapshot: &BufferSnapshot, completion: &mut Completion) {
13284 let CompletionSource::BufferWord {
13285 word_range,
13286 resolved,
13287 } = &mut completion.source
13288 else {
13289 return;
13290 };
13291 if *resolved {
13292 return;
13293 }
13294
13295 if completion.new_text
13296 != snapshot
13297 .text_for_range(word_range.clone())
13298 .collect::<String>()
13299 {
13300 return;
13301 }
13302
13303 let mut offset = 0;
13304 for chunk in snapshot.chunks(word_range.clone(), true) {
13305 let end_offset = offset + chunk.text.len();
13306 if let Some(highlight_id) = chunk.syntax_highlight_id {
13307 completion
13308 .label
13309 .runs
13310 .push((offset..end_offset, highlight_id));
13311 }
13312 offset = end_offset;
13313 }
13314 *resolved = true;
13315}
13316
13317impl EventEmitter<LspStoreEvent> for LspStore {}
13318
13319fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
13320 hover
13321 .contents
13322 .retain(|hover_block| !hover_block.text.trim().is_empty());
13323 if hover.contents.is_empty() {
13324 None
13325 } else {
13326 Some(hover)
13327 }
13328}
13329
13330async fn populate_labels_for_completions(
13331 new_completions: Vec<CoreCompletion>,
13332 language: Option<Arc<Language>>,
13333 lsp_adapter: Option<Arc<CachedLspAdapter>>,
13334) -> Vec<Completion> {
13335 let lsp_completions = new_completions
13336 .iter()
13337 .filter_map(|new_completion| {
13338 new_completion
13339 .source
13340 .lsp_completion(true)
13341 .map(|lsp_completion| lsp_completion.into_owned())
13342 })
13343 .collect::<Vec<_>>();
13344
13345 let mut labels = if let Some((language, lsp_adapter)) = language.as_ref().zip(lsp_adapter) {
13346 lsp_adapter
13347 .labels_for_completions(&lsp_completions, language)
13348 .await
13349 .log_err()
13350 .unwrap_or_default()
13351 } else {
13352 Vec::new()
13353 }
13354 .into_iter()
13355 .fuse();
13356
13357 let mut completions = Vec::new();
13358 for completion in new_completions {
13359 match completion.source.lsp_completion(true) {
13360 Some(lsp_completion) => {
13361 let documentation = lsp_completion.documentation.clone().map(|docs| docs.into());
13362
13363 let mut label = labels.next().flatten().unwrap_or_else(|| {
13364 CodeLabel::fallback_for_completion(&lsp_completion, language.as_deref())
13365 });
13366 ensure_uniform_list_compatible_label(&mut label);
13367 completions.push(Completion {
13368 label,
13369 documentation,
13370 replace_range: completion.replace_range,
13371 new_text: completion.new_text,
13372 insert_text_mode: lsp_completion.insert_text_mode,
13373 source: completion.source,
13374 icon_path: None,
13375 confirm: None,
13376 match_start: None,
13377 snippet_deduplication_key: None,
13378 });
13379 }
13380 None => {
13381 let mut label = CodeLabel::plain(completion.new_text.clone(), None);
13382 ensure_uniform_list_compatible_label(&mut label);
13383 completions.push(Completion {
13384 label,
13385 documentation: None,
13386 replace_range: completion.replace_range,
13387 new_text: completion.new_text,
13388 source: completion.source,
13389 insert_text_mode: None,
13390 icon_path: None,
13391 confirm: None,
13392 match_start: None,
13393 snippet_deduplication_key: None,
13394 });
13395 }
13396 }
13397 }
13398 completions
13399}
13400
13401#[derive(Debug)]
13402pub enum LanguageServerToQuery {
13403 /// Query language servers in order of users preference, up until one capable of handling the request is found.
13404 FirstCapable,
13405 /// Query a specific language server.
13406 Other(LanguageServerId),
13407}
13408
13409#[derive(Default)]
13410struct RenamePathsWatchedForServer {
13411 did_rename: Vec<RenameActionPredicate>,
13412 will_rename: Vec<RenameActionPredicate>,
13413}
13414
13415impl RenamePathsWatchedForServer {
13416 fn with_did_rename_patterns(
13417 mut self,
13418 did_rename: Option<&FileOperationRegistrationOptions>,
13419 ) -> Self {
13420 if let Some(did_rename) = did_rename {
13421 self.did_rename = did_rename
13422 .filters
13423 .iter()
13424 .filter_map(|filter| filter.try_into().log_err())
13425 .collect();
13426 }
13427 self
13428 }
13429 fn with_will_rename_patterns(
13430 mut self,
13431 will_rename: Option<&FileOperationRegistrationOptions>,
13432 ) -> Self {
13433 if let Some(will_rename) = will_rename {
13434 self.will_rename = will_rename
13435 .filters
13436 .iter()
13437 .filter_map(|filter| filter.try_into().log_err())
13438 .collect();
13439 }
13440 self
13441 }
13442
13443 fn should_send_did_rename(&self, path: &str, is_dir: bool) -> bool {
13444 self.did_rename.iter().any(|pred| pred.eval(path, is_dir))
13445 }
13446 fn should_send_will_rename(&self, path: &str, is_dir: bool) -> bool {
13447 self.will_rename.iter().any(|pred| pred.eval(path, is_dir))
13448 }
13449}
13450
13451impl TryFrom<&FileOperationFilter> for RenameActionPredicate {
13452 type Error = globset::Error;
13453 fn try_from(ops: &FileOperationFilter) -> Result<Self, globset::Error> {
13454 Ok(Self {
13455 kind: ops.pattern.matches.clone(),
13456 glob: GlobBuilder::new(&ops.pattern.glob)
13457 .case_insensitive(
13458 ops.pattern
13459 .options
13460 .as_ref()
13461 .is_some_and(|ops| ops.ignore_case.unwrap_or(false)),
13462 )
13463 .build()?
13464 .compile_matcher(),
13465 })
13466 }
13467}
13468struct RenameActionPredicate {
13469 glob: GlobMatcher,
13470 kind: Option<FileOperationPatternKind>,
13471}
13472
13473impl RenameActionPredicate {
13474 // Returns true if language server should be notified
13475 fn eval(&self, path: &str, is_dir: bool) -> bool {
13476 self.kind.as_ref().is_none_or(|kind| {
13477 let expected_kind = if is_dir {
13478 FileOperationPatternKind::Folder
13479 } else {
13480 FileOperationPatternKind::File
13481 };
13482 kind == &expected_kind
13483 }) && self.glob.is_match(path)
13484 }
13485}
13486
13487#[derive(Default)]
13488struct LanguageServerWatchedPaths {
13489 worktree_paths: HashMap<WorktreeId, GlobSet>,
13490 abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
13491}
13492
13493#[derive(Default)]
13494struct LanguageServerWatchedPathsBuilder {
13495 worktree_paths: HashMap<WorktreeId, GlobSet>,
13496 abs_paths: HashMap<Arc<Path>, GlobSet>,
13497}
13498
13499impl LanguageServerWatchedPathsBuilder {
13500 fn watch_worktree(&mut self, worktree_id: WorktreeId, glob_set: GlobSet) {
13501 self.worktree_paths.insert(worktree_id, glob_set);
13502 }
13503 fn watch_abs_path(&mut self, path: Arc<Path>, glob_set: GlobSet) {
13504 self.abs_paths.insert(path, glob_set);
13505 }
13506 fn build(
13507 self,
13508 fs: Arc<dyn Fs>,
13509 language_server_id: LanguageServerId,
13510 cx: &mut Context<LspStore>,
13511 ) -> LanguageServerWatchedPaths {
13512 let lsp_store = cx.weak_entity();
13513
13514 const LSP_ABS_PATH_OBSERVE: Duration = Duration::from_millis(100);
13515 let abs_paths = self
13516 .abs_paths
13517 .into_iter()
13518 .map(|(abs_path, globset)| {
13519 let task = cx.spawn({
13520 let abs_path = abs_path.clone();
13521 let fs = fs.clone();
13522
13523 let lsp_store = lsp_store.clone();
13524 async move |_, cx| {
13525 maybe!(async move {
13526 let mut push_updates = fs.watch(&abs_path, LSP_ABS_PATH_OBSERVE).await;
13527 while let Some(update) = push_updates.0.next().await {
13528 let action = lsp_store
13529 .update(cx, |this, _| {
13530 let Some(local) = this.as_local() else {
13531 return ControlFlow::Break(());
13532 };
13533 let Some(watcher) = local
13534 .language_server_watched_paths
13535 .get(&language_server_id)
13536 else {
13537 return ControlFlow::Break(());
13538 };
13539 let (globs, _) = watcher.abs_paths.get(&abs_path).expect(
13540 "Watched abs path is not registered with a watcher",
13541 );
13542 let matching_entries = update
13543 .into_iter()
13544 .filter(|event| globs.is_match(&event.path))
13545 .collect::<Vec<_>>();
13546 this.lsp_notify_abs_paths_changed(
13547 language_server_id,
13548 matching_entries,
13549 );
13550 ControlFlow::Continue(())
13551 })
13552 .ok()?;
13553
13554 if action.is_break() {
13555 break;
13556 }
13557 }
13558 Some(())
13559 })
13560 .await;
13561 }
13562 });
13563 (abs_path, (globset, task))
13564 })
13565 .collect();
13566 LanguageServerWatchedPaths {
13567 worktree_paths: self.worktree_paths,
13568 abs_paths,
13569 }
13570 }
13571}
13572
13573struct LspBufferSnapshot {
13574 version: i32,
13575 snapshot: TextBufferSnapshot,
13576}
13577
13578/// A prompt requested by LSP server.
13579#[derive(Clone, Debug)]
13580pub struct LanguageServerPromptRequest {
13581 pub id: usize,
13582 pub level: PromptLevel,
13583 pub message: String,
13584 pub actions: Vec<MessageActionItem>,
13585 pub lsp_name: String,
13586 pub(crate) response_channel: smol::channel::Sender<MessageActionItem>,
13587}
13588
13589impl LanguageServerPromptRequest {
13590 pub fn new(
13591 level: PromptLevel,
13592 message: String,
13593 actions: Vec<MessageActionItem>,
13594 lsp_name: String,
13595 response_channel: smol::channel::Sender<MessageActionItem>,
13596 ) -> Self {
13597 let id = NEXT_PROMPT_REQUEST_ID.fetch_add(1, atomic::Ordering::AcqRel);
13598 LanguageServerPromptRequest {
13599 id,
13600 level,
13601 message,
13602 actions,
13603 lsp_name,
13604 response_channel,
13605 }
13606 }
13607 pub async fn respond(self, index: usize) -> Option<()> {
13608 if let Some(response) = self.actions.into_iter().nth(index) {
13609 self.response_channel.send(response).await.ok()
13610 } else {
13611 None
13612 }
13613 }
13614
13615 #[cfg(any(test, feature = "test-support"))]
13616 pub fn test(
13617 level: PromptLevel,
13618 message: String,
13619 actions: Vec<MessageActionItem>,
13620 lsp_name: String,
13621 ) -> Self {
13622 let (tx, _rx) = smol::channel::unbounded();
13623 LanguageServerPromptRequest::new(level, message, actions, lsp_name, tx)
13624 }
13625}
13626impl PartialEq for LanguageServerPromptRequest {
13627 fn eq(&self, other: &Self) -> bool {
13628 self.message == other.message && self.actions == other.actions
13629 }
13630}
13631
13632#[derive(Clone, Debug, PartialEq)]
13633pub enum LanguageServerLogType {
13634 Log(MessageType),
13635 Trace { verbose_info: Option<String> },
13636 Rpc { received: bool },
13637}
13638
13639impl LanguageServerLogType {
13640 pub fn to_proto(&self) -> proto::language_server_log::LogType {
13641 match self {
13642 Self::Log(log_type) => {
13643 use proto::log_message::LogLevel;
13644 let level = match *log_type {
13645 MessageType::ERROR => LogLevel::Error,
13646 MessageType::WARNING => LogLevel::Warning,
13647 MessageType::INFO => LogLevel::Info,
13648 MessageType::LOG => LogLevel::Log,
13649 other => {
13650 log::warn!("Unknown lsp log message type: {other:?}");
13651 LogLevel::Log
13652 }
13653 };
13654 proto::language_server_log::LogType::Log(proto::LogMessage {
13655 level: level as i32,
13656 })
13657 }
13658 Self::Trace { verbose_info } => {
13659 proto::language_server_log::LogType::Trace(proto::TraceMessage {
13660 verbose_info: verbose_info.to_owned(),
13661 })
13662 }
13663 Self::Rpc { received } => {
13664 let kind = if *received {
13665 proto::rpc_message::Kind::Received
13666 } else {
13667 proto::rpc_message::Kind::Sent
13668 };
13669 let kind = kind as i32;
13670 proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
13671 }
13672 }
13673 }
13674
13675 pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
13676 use proto::log_message::LogLevel;
13677 use proto::rpc_message;
13678 match log_type {
13679 proto::language_server_log::LogType::Log(message_type) => Self::Log(
13680 match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
13681 LogLevel::Error => MessageType::ERROR,
13682 LogLevel::Warning => MessageType::WARNING,
13683 LogLevel::Info => MessageType::INFO,
13684 LogLevel::Log => MessageType::LOG,
13685 },
13686 ),
13687 proto::language_server_log::LogType::Trace(trace_message) => Self::Trace {
13688 verbose_info: trace_message.verbose_info,
13689 },
13690 proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
13691 received: match rpc_message::Kind::from_i32(message.kind)
13692 .unwrap_or(rpc_message::Kind::Received)
13693 {
13694 rpc_message::Kind::Received => true,
13695 rpc_message::Kind::Sent => false,
13696 },
13697 },
13698 }
13699 }
13700}
13701
13702pub struct WorkspaceRefreshTask {
13703 refresh_tx: mpsc::Sender<()>,
13704 progress_tx: mpsc::Sender<()>,
13705 #[allow(dead_code)]
13706 task: Task<()>,
13707}
13708
13709pub enum LanguageServerState {
13710 Starting {
13711 startup: Task<Option<Arc<LanguageServer>>>,
13712 /// List of language servers that will be added to the workspace once it's initialization completes.
13713 pending_workspace_folders: Arc<Mutex<BTreeSet<Uri>>>,
13714 },
13715
13716 Running {
13717 adapter: Arc<CachedLspAdapter>,
13718 server: Arc<LanguageServer>,
13719 simulate_disk_based_diagnostics_completion: Option<Task<()>>,
13720 workspace_diagnostics_refresh_tasks: HashMap<Option<String>, WorkspaceRefreshTask>,
13721 },
13722}
13723
13724impl LanguageServerState {
13725 fn add_workspace_folder(&self, uri: Uri) {
13726 match self {
13727 LanguageServerState::Starting {
13728 pending_workspace_folders,
13729 ..
13730 } => {
13731 pending_workspace_folders.lock().insert(uri);
13732 }
13733 LanguageServerState::Running { server, .. } => {
13734 server.add_workspace_folder(uri);
13735 }
13736 }
13737 }
13738 fn _remove_workspace_folder(&self, uri: Uri) {
13739 match self {
13740 LanguageServerState::Starting {
13741 pending_workspace_folders,
13742 ..
13743 } => {
13744 pending_workspace_folders.lock().remove(&uri);
13745 }
13746 LanguageServerState::Running { server, .. } => server.remove_workspace_folder(uri),
13747 }
13748 }
13749}
13750
13751impl std::fmt::Debug for LanguageServerState {
13752 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13753 match self {
13754 LanguageServerState::Starting { .. } => {
13755 f.debug_struct("LanguageServerState::Starting").finish()
13756 }
13757 LanguageServerState::Running { .. } => {
13758 f.debug_struct("LanguageServerState::Running").finish()
13759 }
13760 }
13761 }
13762}
13763
13764#[derive(Clone, Debug, Serialize)]
13765pub struct LanguageServerProgress {
13766 pub is_disk_based_diagnostics_progress: bool,
13767 pub is_cancellable: bool,
13768 pub title: Option<String>,
13769 pub message: Option<String>,
13770 pub percentage: Option<usize>,
13771 #[serde(skip_serializing)]
13772 pub last_update_at: Instant,
13773}
13774
13775#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize)]
13776pub struct DiagnosticSummary {
13777 pub error_count: usize,
13778 pub warning_count: usize,
13779}
13780
13781impl DiagnosticSummary {
13782 pub fn new<'a, T: 'a>(diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<T>>) -> Self {
13783 let mut this = Self {
13784 error_count: 0,
13785 warning_count: 0,
13786 };
13787
13788 for entry in diagnostics {
13789 if entry.diagnostic.is_primary {
13790 match entry.diagnostic.severity {
13791 DiagnosticSeverity::ERROR => this.error_count += 1,
13792 DiagnosticSeverity::WARNING => this.warning_count += 1,
13793 _ => {}
13794 }
13795 }
13796 }
13797
13798 this
13799 }
13800
13801 pub fn is_empty(&self) -> bool {
13802 self.error_count == 0 && self.warning_count == 0
13803 }
13804
13805 pub fn to_proto(
13806 self,
13807 language_server_id: LanguageServerId,
13808 path: &RelPath,
13809 ) -> proto::DiagnosticSummary {
13810 proto::DiagnosticSummary {
13811 path: path.to_proto(),
13812 language_server_id: language_server_id.0 as u64,
13813 error_count: self.error_count as u32,
13814 warning_count: self.warning_count as u32,
13815 }
13816 }
13817}
13818
13819#[derive(Clone, Debug)]
13820pub enum CompletionDocumentation {
13821 /// There is no documentation for this completion.
13822 Undocumented,
13823 /// A single line of documentation.
13824 SingleLine(SharedString),
13825 /// Multiple lines of plain text documentation.
13826 MultiLinePlainText(SharedString),
13827 /// Markdown documentation.
13828 MultiLineMarkdown(SharedString),
13829 /// Both single line and multiple lines of plain text documentation.
13830 SingleLineAndMultiLinePlainText {
13831 single_line: SharedString,
13832 plain_text: Option<SharedString>,
13833 },
13834}
13835
13836impl CompletionDocumentation {
13837 #[cfg(any(test, feature = "test-support"))]
13838 pub fn text(&self) -> SharedString {
13839 match self {
13840 CompletionDocumentation::Undocumented => "".into(),
13841 CompletionDocumentation::SingleLine(s) => s.clone(),
13842 CompletionDocumentation::MultiLinePlainText(s) => s.clone(),
13843 CompletionDocumentation::MultiLineMarkdown(s) => s.clone(),
13844 CompletionDocumentation::SingleLineAndMultiLinePlainText { single_line, .. } => {
13845 single_line.clone()
13846 }
13847 }
13848 }
13849}
13850
13851impl From<lsp::Documentation> for CompletionDocumentation {
13852 fn from(docs: lsp::Documentation) -> Self {
13853 match docs {
13854 lsp::Documentation::String(text) => {
13855 if text.lines().count() <= 1 {
13856 CompletionDocumentation::SingleLine(text.trim().to_string().into())
13857 } else {
13858 CompletionDocumentation::MultiLinePlainText(text.into())
13859 }
13860 }
13861
13862 lsp::Documentation::MarkupContent(lsp::MarkupContent { kind, value }) => match kind {
13863 lsp::MarkupKind::PlainText => {
13864 if value.lines().count() <= 1 {
13865 CompletionDocumentation::SingleLine(value.into())
13866 } else {
13867 CompletionDocumentation::MultiLinePlainText(value.into())
13868 }
13869 }
13870
13871 lsp::MarkupKind::Markdown => {
13872 CompletionDocumentation::MultiLineMarkdown(value.into())
13873 }
13874 },
13875 }
13876 }
13877}
13878
13879pub enum ResolvedHint {
13880 Resolved(InlayHint),
13881 Resolving(Shared<Task<()>>),
13882}
13883
13884pub fn glob_literal_prefix(glob: &Path) -> PathBuf {
13885 glob.components()
13886 .take_while(|component| match component {
13887 path::Component::Normal(part) => !part.to_string_lossy().contains(['*', '?', '{', '}']),
13888 _ => true,
13889 })
13890 .collect()
13891}
13892
13893pub struct SshLspAdapter {
13894 name: LanguageServerName,
13895 binary: LanguageServerBinary,
13896 initialization_options: Option<String>,
13897 code_action_kinds: Option<Vec<CodeActionKind>>,
13898}
13899
13900impl SshLspAdapter {
13901 pub fn new(
13902 name: LanguageServerName,
13903 binary: LanguageServerBinary,
13904 initialization_options: Option<String>,
13905 code_action_kinds: Option<String>,
13906 ) -> Self {
13907 Self {
13908 name,
13909 binary,
13910 initialization_options,
13911 code_action_kinds: code_action_kinds
13912 .as_ref()
13913 .and_then(|c| serde_json::from_str(c).ok()),
13914 }
13915 }
13916}
13917
13918impl LspInstaller for SshLspAdapter {
13919 type BinaryVersion = ();
13920 async fn check_if_user_installed(
13921 &self,
13922 _: &dyn LspAdapterDelegate,
13923 _: Option<Toolchain>,
13924 _: &AsyncApp,
13925 ) -> Option<LanguageServerBinary> {
13926 Some(self.binary.clone())
13927 }
13928
13929 async fn cached_server_binary(
13930 &self,
13931 _: PathBuf,
13932 _: &dyn LspAdapterDelegate,
13933 ) -> Option<LanguageServerBinary> {
13934 None
13935 }
13936
13937 async fn fetch_latest_server_version(
13938 &self,
13939 _: &dyn LspAdapterDelegate,
13940 _: bool,
13941 _: &mut AsyncApp,
13942 ) -> Result<()> {
13943 anyhow::bail!("SshLspAdapter does not support fetch_latest_server_version")
13944 }
13945
13946 async fn fetch_server_binary(
13947 &self,
13948 _: (),
13949 _: PathBuf,
13950 _: &dyn LspAdapterDelegate,
13951 ) -> Result<LanguageServerBinary> {
13952 anyhow::bail!("SshLspAdapter does not support fetch_server_binary")
13953 }
13954}
13955
13956#[async_trait(?Send)]
13957impl LspAdapter for SshLspAdapter {
13958 fn name(&self) -> LanguageServerName {
13959 self.name.clone()
13960 }
13961
13962 async fn initialization_options(
13963 self: Arc<Self>,
13964 _: &Arc<dyn LspAdapterDelegate>,
13965 ) -> Result<Option<serde_json::Value>> {
13966 let Some(options) = &self.initialization_options else {
13967 return Ok(None);
13968 };
13969 let result = serde_json::from_str(options)?;
13970 Ok(result)
13971 }
13972
13973 fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
13974 self.code_action_kinds.clone()
13975 }
13976}
13977
13978pub fn language_server_settings<'a>(
13979 delegate: &'a dyn LspAdapterDelegate,
13980 language: &LanguageServerName,
13981 cx: &'a App,
13982) -> Option<&'a LspSettings> {
13983 language_server_settings_for(
13984 SettingsLocation {
13985 worktree_id: delegate.worktree_id(),
13986 path: RelPath::empty(),
13987 },
13988 language,
13989 cx,
13990 )
13991}
13992
13993pub fn language_server_settings_for<'a>(
13994 location: SettingsLocation<'a>,
13995 language: &LanguageServerName,
13996 cx: &'a App,
13997) -> Option<&'a LspSettings> {
13998 ProjectSettings::get(Some(location), cx).lsp.get(language)
13999}
14000
14001pub struct LocalLspAdapterDelegate {
14002 lsp_store: WeakEntity<LspStore>,
14003 worktree: worktree::Snapshot,
14004 fs: Arc<dyn Fs>,
14005 http_client: Arc<dyn HttpClient>,
14006 language_registry: Arc<LanguageRegistry>,
14007 load_shell_env_task: Shared<Task<Option<HashMap<String, String>>>>,
14008}
14009
14010impl LocalLspAdapterDelegate {
14011 pub fn new(
14012 language_registry: Arc<LanguageRegistry>,
14013 environment: &Entity<ProjectEnvironment>,
14014 lsp_store: WeakEntity<LspStore>,
14015 worktree: &Entity<Worktree>,
14016 http_client: Arc<dyn HttpClient>,
14017 fs: Arc<dyn Fs>,
14018 cx: &mut App,
14019 ) -> Arc<Self> {
14020 let load_shell_env_task =
14021 environment.update(cx, |env, cx| env.worktree_environment(worktree.clone(), cx));
14022
14023 Arc::new(Self {
14024 lsp_store,
14025 worktree: worktree.read(cx).snapshot(),
14026 fs,
14027 http_client,
14028 language_registry,
14029 load_shell_env_task,
14030 })
14031 }
14032
14033 pub fn from_local_lsp(
14034 local: &LocalLspStore,
14035 worktree: &Entity<Worktree>,
14036 cx: &mut App,
14037 ) -> Arc<Self> {
14038 Self::new(
14039 local.languages.clone(),
14040 &local.environment,
14041 local.weak.clone(),
14042 worktree,
14043 local.http_client.clone(),
14044 local.fs.clone(),
14045 cx,
14046 )
14047 }
14048}
14049
14050#[async_trait]
14051impl LspAdapterDelegate for LocalLspAdapterDelegate {
14052 fn show_notification(&self, message: &str, cx: &mut App) {
14053 self.lsp_store
14054 .update(cx, |_, cx| {
14055 cx.emit(LspStoreEvent::Notification(message.to_owned()))
14056 })
14057 .ok();
14058 }
14059
14060 fn http_client(&self) -> Arc<dyn HttpClient> {
14061 self.http_client.clone()
14062 }
14063
14064 fn worktree_id(&self) -> WorktreeId {
14065 self.worktree.id()
14066 }
14067
14068 fn worktree_root_path(&self) -> &Path {
14069 self.worktree.abs_path().as_ref()
14070 }
14071
14072 fn resolve_relative_path(&self, path: PathBuf) -> PathBuf {
14073 self.worktree.resolve_relative_path(path)
14074 }
14075
14076 async fn shell_env(&self) -> HashMap<String, String> {
14077 let task = self.load_shell_env_task.clone();
14078 task.await.unwrap_or_default()
14079 }
14080
14081 async fn npm_package_installed_version(
14082 &self,
14083 package_name: &str,
14084 ) -> Result<Option<(PathBuf, Version)>> {
14085 let local_package_directory = self.worktree_root_path();
14086 let node_modules_directory = local_package_directory.join("node_modules");
14087
14088 if let Some(version) =
14089 read_package_installed_version(node_modules_directory.clone(), package_name).await?
14090 {
14091 return Ok(Some((node_modules_directory, version)));
14092 }
14093 let Some(npm) = self.which("npm".as_ref()).await else {
14094 log::warn!(
14095 "Failed to find npm executable for {:?}",
14096 local_package_directory
14097 );
14098 return Ok(None);
14099 };
14100
14101 let env = self.shell_env().await;
14102 let output = util::command::new_smol_command(&npm)
14103 .args(["root", "-g"])
14104 .envs(env)
14105 .current_dir(local_package_directory)
14106 .output()
14107 .await?;
14108 let global_node_modules =
14109 PathBuf::from(String::from_utf8_lossy(&output.stdout).to_string());
14110
14111 if let Some(version) =
14112 read_package_installed_version(global_node_modules.clone(), package_name).await?
14113 {
14114 return Ok(Some((global_node_modules, version)));
14115 }
14116 return Ok(None);
14117 }
14118
14119 async fn which(&self, command: &OsStr) -> Option<PathBuf> {
14120 let mut worktree_abs_path = self.worktree_root_path().to_path_buf();
14121 if self.fs.is_file(&worktree_abs_path).await {
14122 worktree_abs_path.pop();
14123 }
14124
14125 let env = self.shell_env().await;
14126
14127 let shell_path = env.get("PATH").cloned();
14128
14129 which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
14130 }
14131
14132 async fn try_exec(&self, command: LanguageServerBinary) -> Result<()> {
14133 let mut working_dir = self.worktree_root_path().to_path_buf();
14134 if self.fs.is_file(&working_dir).await {
14135 working_dir.pop();
14136 }
14137 let output = util::command::new_smol_command(&command.path)
14138 .args(command.arguments)
14139 .envs(command.env.clone().unwrap_or_default())
14140 .current_dir(working_dir)
14141 .output()
14142 .await?;
14143
14144 anyhow::ensure!(
14145 output.status.success(),
14146 "{}, stdout: {:?}, stderr: {:?}",
14147 output.status,
14148 String::from_utf8_lossy(&output.stdout),
14149 String::from_utf8_lossy(&output.stderr)
14150 );
14151 Ok(())
14152 }
14153
14154 fn update_status(&self, server_name: LanguageServerName, status: language::BinaryStatus) {
14155 self.language_registry
14156 .update_lsp_binary_status(server_name, status);
14157 }
14158
14159 fn registered_lsp_adapters(&self) -> Vec<Arc<dyn LspAdapter>> {
14160 self.language_registry
14161 .all_lsp_adapters()
14162 .into_iter()
14163 .map(|adapter| adapter.adapter.clone() as Arc<dyn LspAdapter>)
14164 .collect()
14165 }
14166
14167 async fn language_server_download_dir(&self, name: &LanguageServerName) -> Option<Arc<Path>> {
14168 let dir = self.language_registry.language_server_download_dir(name)?;
14169
14170 if !dir.exists() {
14171 smol::fs::create_dir_all(&dir)
14172 .await
14173 .context("failed to create container directory")
14174 .log_err()?;
14175 }
14176
14177 Some(dir)
14178 }
14179
14180 async fn read_text_file(&self, path: &RelPath) -> Result<String> {
14181 let entry = self
14182 .worktree
14183 .entry_for_path(path)
14184 .with_context(|| format!("no worktree entry for path {path:?}"))?;
14185 let abs_path = self.worktree.absolutize(&entry.path);
14186 self.fs.load(&abs_path).await
14187 }
14188}
14189
14190async fn populate_labels_for_symbols(
14191 symbols: Vec<CoreSymbol>,
14192 language_registry: &Arc<LanguageRegistry>,
14193 lsp_adapter: Option<Arc<CachedLspAdapter>>,
14194 output: &mut Vec<Symbol>,
14195) {
14196 #[allow(clippy::mutable_key_type)]
14197 let mut symbols_by_language = HashMap::<Option<Arc<Language>>, Vec<CoreSymbol>>::default();
14198
14199 let mut unknown_paths = BTreeSet::<Arc<str>>::new();
14200 for symbol in symbols {
14201 let Some(file_name) = symbol.path.file_name() else {
14202 continue;
14203 };
14204 let language = language_registry
14205 .load_language_for_file_path(Path::new(file_name))
14206 .await
14207 .ok()
14208 .or_else(|| {
14209 unknown_paths.insert(file_name.into());
14210 None
14211 });
14212 symbols_by_language
14213 .entry(language)
14214 .or_default()
14215 .push(symbol);
14216 }
14217
14218 for unknown_path in unknown_paths {
14219 log::info!("no language found for symbol in file {unknown_path:?}");
14220 }
14221
14222 let mut label_params = Vec::new();
14223 for (language, mut symbols) in symbols_by_language {
14224 label_params.clear();
14225 label_params.extend(symbols.iter_mut().map(|symbol| language::Symbol {
14226 name: mem::take(&mut symbol.name),
14227 kind: symbol.kind,
14228 container_name: symbol.container_name.take(),
14229 }));
14230
14231 let mut labels = Vec::new();
14232 if let Some(language) = language {
14233 let lsp_adapter = lsp_adapter.clone().or_else(|| {
14234 language_registry
14235 .lsp_adapters(&language.name())
14236 .first()
14237 .cloned()
14238 });
14239 if let Some(lsp_adapter) = lsp_adapter {
14240 labels = lsp_adapter
14241 .labels_for_symbols(&label_params, &language)
14242 .await
14243 .log_err()
14244 .unwrap_or_default();
14245 }
14246 }
14247
14248 for (
14249 (
14250 symbol,
14251 language::Symbol {
14252 name,
14253 container_name,
14254 ..
14255 },
14256 ),
14257 label,
14258 ) in symbols
14259 .into_iter()
14260 .zip(label_params.drain(..))
14261 .zip(labels.into_iter().chain(iter::repeat(None)))
14262 {
14263 output.push(Symbol {
14264 language_server_name: symbol.language_server_name,
14265 source_worktree_id: symbol.source_worktree_id,
14266 source_language_server_id: symbol.source_language_server_id,
14267 path: symbol.path,
14268 label: label.unwrap_or_else(|| CodeLabel::plain(name.clone(), None)),
14269 name,
14270 kind: symbol.kind,
14271 range: symbol.range,
14272 container_name,
14273 });
14274 }
14275 }
14276}
14277
14278fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
14279 match server.capabilities().text_document_sync.as_ref()? {
14280 lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
14281 // Server wants didSave but didn't specify includeText.
14282 lsp::TextDocumentSyncSaveOptions::Supported(true) => Some(false),
14283 // Server doesn't want didSave at all.
14284 lsp::TextDocumentSyncSaveOptions::Supported(false) => None,
14285 // Server provided SaveOptions.
14286 lsp::TextDocumentSyncSaveOptions::SaveOptions(save_options) => {
14287 Some(save_options.include_text.unwrap_or(false))
14288 }
14289 },
14290 // We do not have any save info. Kind affects didChange only.
14291 lsp::TextDocumentSyncCapability::Kind(_) => None,
14292 }
14293}
14294
14295/// Completion items are displayed in a `UniformList`.
14296/// Usually, those items are single-line strings, but in LSP responses,
14297/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
14298/// Many language plugins construct these items by joining these parts together, and we may use `CodeLabel::fallback_for_completion` that uses `label` at least.
14299/// 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,
14300/// breaking the completions menu presentation.
14301///
14302/// 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.
14303pub fn ensure_uniform_list_compatible_label(label: &mut CodeLabel) {
14304 let mut new_text = String::with_capacity(label.text.len());
14305 let mut offset_map = vec![0; label.text.len() + 1];
14306 let mut last_char_was_space = false;
14307 let mut new_idx = 0;
14308 let chars = label.text.char_indices().fuse();
14309 let mut newlines_removed = false;
14310
14311 for (idx, c) in chars {
14312 offset_map[idx] = new_idx;
14313
14314 match c {
14315 '\n' if last_char_was_space => {
14316 newlines_removed = true;
14317 }
14318 '\t' | ' ' if last_char_was_space => {}
14319 '\n' if !last_char_was_space => {
14320 new_text.push(' ');
14321 new_idx += 1;
14322 last_char_was_space = true;
14323 newlines_removed = true;
14324 }
14325 ' ' | '\t' => {
14326 new_text.push(' ');
14327 new_idx += 1;
14328 last_char_was_space = true;
14329 }
14330 _ => {
14331 new_text.push(c);
14332 new_idx += c.len_utf8();
14333 last_char_was_space = false;
14334 }
14335 }
14336 }
14337 offset_map[label.text.len()] = new_idx;
14338
14339 // Only modify the label if newlines were removed.
14340 if !newlines_removed {
14341 return;
14342 }
14343
14344 let last_index = new_idx;
14345 let mut run_ranges_errors = Vec::new();
14346 label.runs.retain_mut(|(range, _)| {
14347 match offset_map.get(range.start) {
14348 Some(&start) => range.start = start,
14349 None => {
14350 run_ranges_errors.push(range.clone());
14351 return false;
14352 }
14353 }
14354
14355 match offset_map.get(range.end) {
14356 Some(&end) => range.end = end,
14357 None => {
14358 run_ranges_errors.push(range.clone());
14359 range.end = last_index;
14360 }
14361 }
14362 true
14363 });
14364 if !run_ranges_errors.is_empty() {
14365 log::error!(
14366 "Completion label has errors in its run ranges: {run_ranges_errors:?}, label text: {}",
14367 label.text
14368 );
14369 }
14370
14371 let mut wrong_filter_range = None;
14372 if label.filter_range == (0..label.text.len()) {
14373 label.filter_range = 0..new_text.len();
14374 } else {
14375 let mut original_filter_range = Some(label.filter_range.clone());
14376 match offset_map.get(label.filter_range.start) {
14377 Some(&start) => label.filter_range.start = start,
14378 None => {
14379 wrong_filter_range = original_filter_range.take();
14380 label.filter_range.start = last_index;
14381 }
14382 }
14383
14384 match offset_map.get(label.filter_range.end) {
14385 Some(&end) => label.filter_range.end = end,
14386 None => {
14387 wrong_filter_range = original_filter_range.take();
14388 label.filter_range.end = last_index;
14389 }
14390 }
14391 }
14392 if let Some(wrong_filter_range) = wrong_filter_range {
14393 log::error!(
14394 "Completion label has an invalid filter range: {wrong_filter_range:?}, label text: {}",
14395 label.text
14396 );
14397 }
14398
14399 label.text = new_text;
14400}